blob: 292a4ad284bcb76bcbb5541255cb6f7b5690ff21 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2017 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.tcl.internal.ui.navigation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.DLTKLanguageManager;
import org.eclipse.dltk.core.ElementChangedEvent;
import org.eclipse.dltk.core.IDLTKLanguageToolkit;
import org.eclipse.dltk.core.IElementChangedListener;
import org.eclipse.dltk.core.IExternalSourceModule;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelElementDelta;
import org.eclipse.dltk.core.IParent;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.internal.core.ExternalScriptFolder;
import org.eclipse.dltk.internal.ui.editor.EditorUtility;
import org.eclipse.dltk.internal.ui.filters.IFilterElementNameProvider;
import org.eclipse.dltk.tcl.core.TclLanguageToolkit;
import org.eclipse.dltk.tcl.core.TclNature;
import org.eclipse.dltk.tcl.internal.ui.TclUI;
import org.eclipse.dltk.ui.DLTKPluginImages;
import org.eclipse.dltk.ui.ModelElementSorter;
import org.eclipse.dltk.ui.actions.CustomFiltersActionGroup;
import org.eclipse.dltk.ui.viewsupport.ScriptUILabelProvider;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
public abstract class ElementsView extends ViewPart {
private ElementsTreeViewer treeViewer;
protected ElementsContentProvider provider;
protected abstract String getPreferencesId();
private CustomFiltersActionGroup fCustomFiltersActionGroup;
private boolean lookIntoExternal;
protected IPreferenceStore getStore() {
return TclUI.getDefault().getPreferenceStore();
}
private class ElementsTreeViewer extends TreeViewer
implements IFilterElementNameProvider {
public ElementsTreeViewer(Composite container, int border) {
super(container, border);
}
@Override
public String getElementName(Object element) {
return labelProvider.getText(element);
}
}
class ToggleExternalAction extends Action {
public ToggleExternalAction() {
super();
setText("Show external elements");
// DLTKPluginImages.setLocalImageDescriptors(this,
// "package_obj.gif"); //$NON-NLS-1$
setImageDescriptor(DLTKPluginImages
.getDescriptor(DLTKPluginImages.IMG_OBJS_PACKAGE));
boolean checked = getStore().getBoolean(
getPreferencesId() + "ToggleExternalAction.isChecked"); //$NON-NLS-1$
valueChanged(checked, false);
}
@Override
public void run() {
valueChanged(isChecked(), true);
}
private void valueChanged(final boolean on, boolean store) {
setChecked(on);
if (store)
getStore().setValue(
getPreferencesId() + "ToggleExternalAction.isChecked", //$NON-NLS-1$
on);
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(),
() -> {
lookIntoExternal = on;
provider.clear();
runAsync();
});
}
}
class LexicalSortingAction extends Action {
private ModelElementSorter fSorter = new ModelElementSorter() {
@Override
protected String getElementName(Object element) {
return labelProvider.getText(element);
}
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
Object o1 = e1;
Object o2 = e2;
if (e1 != null && e1 instanceof ElementList) {
o1 = ((ElementList) e1).getFirstElement();
}
if (e2 != null && e2 instanceof ElementList) {
o2 = ((ElementList) e2).getFirstElement();
}
return super.compare(viewer, o1, o2);
}
};
public LexicalSortingAction() {
super();
if (DLTKCore.DEBUG) {
System.err.println(
"LexicalSortingAction: Need to set correct info here.");
}
// PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
// IDLTKHelpContextIds.LEXICAL_SORTING_OUTLINE_ACTION);
setText("Alphabetical Sort");
DLTKPluginImages.setLocalImageDescriptors(this,
"alphab_sort_co.gif"); //$NON-NLS-1$
boolean checked = getStore().getBoolean(
getPreferencesId() + "LexicalSortingAction.isChecked"); //$NON-NLS-1$
valueChanged(checked, false);
}
@Override
public void run() {
valueChanged(isChecked(), true);
}
private void valueChanged(final boolean on, boolean store) {
setChecked(on);
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(),
() -> treeViewer.setComparator(on ? fSorter : null));
if (store)
getStore().setValue(
getPreferencesId() + "LexicalSortingAction.isChecked", //$NON-NLS-1$
on);
}
}
protected ElementsViewLabelProvider labelProvider;
class ElementList implements IAdaptable {
private String name;
private List childs;
ElementList(String name, List childs) {
this.name = name;
this.childs = childs;
}
Object getFirstElement() {
if (childs != null && childs.size() > 0) {
return childs.get(0);
}
return null;
}
@Override
public String toString() {
return this.name;
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ElementList other = (ElementList) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public List getElements() {
return this.childs;
}
@SuppressWarnings("unchecked")
@Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter == IModelElement.class) {
return (T) getFirstElement();
}
if (adapter == List.class) {
return (T) childs;
}
return null;
}
}
private class ElementsContentProvider implements ITreeContentProvider {
private Object[] NO_ELEMENT = new Object[0];
private Map elements = new HashMap();
public ElementsContentProvider() {
DLTKCore.addElementChangedListener(new IElementChangedListener() {
@Override
public void elementChanged(ElementChangedEvent event) {
IModelElementDelta delta = event.getDelta();
processChildren(delta);
asyncRefresh();
}
private void processChildren(IModelElementDelta delta) {
IModelElement element = delta.getElement();
if (delta.getKind() == IModelElementDelta.ADDED) {
addElementsJob(element);
}
if (delta.getKind() == IModelElementDelta.REMOVED) {
removeTypesJob(element);
}
if ((delta.getFlags()
& IModelElementDelta.F_ADDED_TO_BUILDPATH) != 0) {
addElementsJob(element);
}
if ((delta.getFlags()
& IModelElementDelta.F_REMOVED_FROM_BUILDPATH) != 0) {
synchronized (elements) {
elements.clear();
}
runAsync();
}
if ((delta.getFlags()
& IModelElementDelta.F_CHILDREN) != 0) {
IModelElementDelta[] affectedChildren = delta
.getAffectedChildren();
for (int i = 0; i < affectedChildren.length; i++) {
IModelElementDelta child = affectedChildren[i];
processChildren(child);
}
}
}
});
}
@Override
public synchronized Object[] getChildren(Object parentElement) {
if (parentElement instanceof IWorkspaceRoot) {
List result = new ArrayList();
Set keys = elements.keySet();
Iterator i = keys.iterator();
while (i.hasNext()) {
Object e = i.next();
Object o = elements.get(e);
if (o instanceof IModelElement) {
if (!result.contains(o)) {
result.add(o);
}
} else if (o instanceof List) {
ElementList el = new ElementList((String) e, (List) o);
if (!result.contains(o)) {
result.add(el);
}
}
}
return result.toArray();
}
return NO_ELEMENT;
}
@Override
public Object getParent(Object element) {
if (element instanceof IModelElement) {
return ResourcesPlugin.getWorkspace().getRoot();
}
return NO_ELEMENT;
}
@Override
public boolean hasChildren(Object element) {
if (element instanceof IWorkspaceRoot) {
return true;
}
return false;
}
@Override
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput,
Object newInput) {
}
synchronized public void addElement(IModelElement element) {
IDLTKLanguageToolkit languageToolkit = DLTKLanguageManager
.getLanguageToolkit(element);
if (!languageToolkit.getNatureId()
.equals(TclLanguageToolkit.getDefault().getNatureId())) {
return;
}
String name = labelProvider.getText(element);
if (elements.containsKey(name)) {
Object o = elements.get(name);
if (o instanceof IModelElement) {
List els = new ArrayList();
els.add(o);
if (!els.contains(element)) {
els.add(element);
}
elements.put(name, els);
} else if (o instanceof List) {
List els = (List) o;
if (!els.contains(o)) {
els.add(element);
}
}
} else {
elements.put(name, element);
}
}
synchronized public void clear() {
elements.clear();
}
synchronized public void removeElement(IModelElement element) {
String name = labelProvider.getText(element);
if (elements.containsKey(name)) {
Object o = elements.get(name);
if (o instanceof IModelElement && o.equals(element)) {
elements.remove(name);
} else if (o instanceof List) {
List els = (List) o;
els.remove(element);
if (els.size() == 0) {
elements.remove(name);
}
}
}
}
}
public abstract String getElementName(Object o);
public class ElementsViewLabelProvider extends ScriptUILabelProvider {
@Override
public Image getImage(Object element) {
if (element instanceof ElementList) {
return getImage(((ElementList) element).getFirstElement());
}
/*
* if( element instanceof IType ) { IType type = (IType)element; int
* flags = 0; try { flags = type.getFlags(); } catch (ModelException
* e) { // TODO Auto-generated catch block e.printStackTrace(); } if
* ((flags & Modifiers.AccNameSpace) == 0) return
* DLTKPluginImages.DESC_OBJS_CLASS.createImage(); return
* DLTKPluginImages.DESC_OBJS_NAMESPACE.createImage(); }
*/
return super.getImage(element);
}
public String getOriginalText(Object element) {
return super.getText(element);
}
@Override
public String getText(Object element) {
String text = getElementName(element);
if (text != null) {
return text;
}
if (element instanceof ElementList) {
return ((ElementList) element).toString();
}
return super.getText(element);
}
}
public abstract boolean isElement(IModelElement e);
public abstract boolean needProcessChildren(IModelElement e);
private void addElements(final IModelElement element,
IProgressMonitor monitor) {
if (monitor.isCanceled())
return;
monitor.worked(1);
if (isElement(element)) {
provider.addElement(element);
}
if (element instanceof ISourceModule)
asyncRefresh();
boolean bad = !lookIntoExternal
&& (element instanceof ExternalScriptFolder
|| element instanceof IExternalSourceModule);
if (element instanceof IParent && !bad) {
IModelElement[] children = null;
try {
children = ((IParent) element).getChildren();
} catch (ModelException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
return;
}
if (children != null) {
for (int j = 0; j < children.length; ++j) {
addElements(children[j], monitor);
}
}
}
// asyncRefresh();
monitor.done();
}
public abstract String getJobTitle();
private void addElementsJob(final IModelElement element) {
Job job = new Job(getTitle()) {
@Override
protected IStatus run(IProgressMonitor monitor) {
addElements(element, monitor);
monitor.done();
return Status.OK_STATUS;
}
};
job.schedule();
}
private void removeElements(IModelElement element) {
IDLTKLanguageToolkit languageToolkit = DLTKLanguageManager
.getLanguageToolkit(element);
if (languageToolkit != null && !languageToolkit.getNatureId()
.equals(TclLanguageToolkit.getDefault().getNatureId())) {
return;
}
if (isElement(element)) {
provider.removeElement(element);
asyncRefresh();
}
if (element instanceof IParent) {
IModelElement[] children = null;
try {
children = ((IParent) element).getChildren();
} catch (ModelException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
return;
}
if (children != null) {
for (int j = 0; j < children.length; ++j) {
removeElements(children[j]);
}
}
}
}
private void removeTypesJob(final IModelElement element) {
Job job = new Job(getTitle()) {
@Override
protected IStatus run(IProgressMonitor monitor) {
removeElements(element);
monitor.done();
return Status.OK_STATUS;
}
};
job.schedule();
}
private void asyncRefresh() {
Display.getDefault().asyncExec(() -> {
if (treeViewer != null && !treeViewer.getTree().isDisposed()) {
treeViewer.refresh(true);
}
});
}
private Job currentJob;
protected void runAsync() {
if (currentJob != null && currentJob.getResult() == null) {
currentJob.cancel();
provider.clear();
currentJob = null;
}
Job job = new Job(getJobTitle()) {
@Override
protected IStatus run(IProgressMonitor monitor) {
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
.getProjects();
// monitor.beginTask(getTitle(), projects.length);
for (int i = 0; i < projects.length; ++i) {
if (monitor.isCanceled())
return Status.OK_STATUS;
try {
if (projects[i].isAccessible()
&& projects[i].hasNature(TclNature.NATURE_ID)) {
IScriptProject project = DLTKCore
.create(projects[i]);
if (project != null) {
addElements(project, monitor);
}
}
} catch (CoreException e) {
e.printStackTrace();
}
monitor.worked(1);
}
asyncRefresh();
monitor.done();
return Status.OK_STATUS;
}
};
job.schedule();
currentJob = job;
}
@Override
public void createPartControl(Composite parent) {
Composite container = new Composite(parent, SWT.NONE);
container.setLayout(new FillLayout());
treeViewer = new ElementsTreeViewer(container, SWT.BORDER);
provider = new ElementsContentProvider();
labelProvider = new ElementsViewLabelProvider();
treeViewer.setLabelProvider(labelProvider);
treeViewer.setContentProvider(provider);
treeViewer.setInput(ResourcesPlugin.getWorkspace().getRoot());
treeViewer.addDoubleClickListener(event -> {
ITreeSelection selection = (ITreeSelection) (event.getSelection());
Object source = selection.getFirstElement();
if (source == null)
return;
try {
if (source instanceof IModelElement) {
IEditorPart editor1 = EditorUtility.openInEditor(source);
EditorUtility.revealInEditor(editor1,
(IModelElement) source);
} else if (source instanceof ElementList) {
ElementList el = (ElementList) source;
List elements = el.getElements();
if (elements != null) {
for (int i = 0; i < elements.size(); ++i) {
Object element = elements.get(i);
if (element instanceof IModelElement) {
IEditorPart editor2 = EditorUtility
.openInEditor(element);
EditorUtility.revealInEditor(editor2,
(IModelElement) element);
} else
EditorUtility.openInEditor(element);
}
}
}
} catch (PartInitException e1) {
e1.printStackTrace();
} catch (ModelException e2) {
e2.printStackTrace();
}
});
IViewSite site = (IViewSite) this.getSite();
IActionBars bars = site.getActionBars();
registerToolbarActions(bars);
runAsync();
}
private void registerToolbarActions(IActionBars actionBars) {
IToolBarManager toolBarManager = actionBars.getToolBarManager();
if (toolBarManager != null) {
toolBarManager.add(new LexicalSortingAction());
toolBarManager.add(new ToggleExternalAction());
}
// registerSpecialToolbarActions(actionBars);
// Custom filter group
fCustomFiltersActionGroup = new CustomFiltersActionGroup(this,
treeViewer) {
};
fCustomFiltersActionGroup.fillActionBars(actionBars);
/*
* actionBars.getMenuManager().add( new PackageFilterAction(this,
* treeViewer));
*/
IMenuManager viewMenuManager = actionBars.getMenuManager();
viewMenuManager.add(new Separator("EndFilterGroup")); //$NON-NLS-1$
// fToggleLinkingAction= new ToggleLinkingAction(this);
// viewMenuManager.add(fToggleLinkingAction);
}
@Override
public void dispose() {
if (fCustomFiltersActionGroup != null) {
fCustomFiltersActionGroup.dispose();
fCustomFiltersActionGroup = null;
}
super.dispose();
}
@Override
public void setFocus() {
}
public String getOriginalElementText(Object o) {
return labelProvider.getOriginalText(o);
}
}