package org.rubypeople.rdt.internal.ui.browsing;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.util.TransferDragSourceListener;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.jface.viewers.DecoratingLabelProvider;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.search.ui.IContextMenuConstants;
import org.eclipse.search.ui.ISearchResultView;
import org.eclipse.search.ui.ISearchResultViewPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.actions.ActionGroup;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.ResourceTransfer;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
import org.osgi.framework.Bundle;
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.internal.corext.util.Messages;
import org.rubypeople.rdt.internal.ui.RubyPlugin;
import org.rubypeople.rdt.internal.ui.actions.CompositeActionGroup;
import org.rubypeople.rdt.internal.ui.actions.NewWizardsActionGroup;
import org.rubypeople.rdt.internal.ui.dnd.DelegatingDropAdapter;
import org.rubypeople.rdt.internal.ui.dnd.RdtViewerDragAdapter;
import org.rubypeople.rdt.internal.ui.packageview.ResourceTransferDragAdapter;
import org.rubypeople.rdt.internal.ui.packageview.SelectionTransferDragAdapter;
import org.rubypeople.rdt.internal.ui.packageview.SelectionTransferDropAdapter;
import org.rubypeople.rdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
import org.rubypeople.rdt.internal.ui.viewsupport.DecoratingRubyLabelProvider;
import org.rubypeople.rdt.internal.ui.viewsupport.ProblemTableViewer;
import org.rubypeople.rdt.internal.ui.viewsupport.RubyElementImageProvider;
import org.rubypeople.rdt.internal.ui.viewsupport.RubyUILabelProvider;
import org.rubypeople.rdt.internal.ui.viewsupport.StatusBarUpdater;
import org.rubypeople.rdt.internal.ui.workingsets.WorkingSetFilterActionGroup;
import org.rubypeople.rdt.ui.IWorkingCopyManager;
import org.rubypeople.rdt.ui.PreferenceConstants;
import org.rubypeople.rdt.ui.RubyElementLabelProvider;
import org.rubypeople.rdt.ui.RubyElementLabels;
import org.rubypeople.rdt.ui.RubyElementSorter;
import org.rubypeople.rdt.ui.StandardRubyElementContentProvider;
import org.rubypeople.rdt.ui.actions.BuildActionGroup;
import org.rubypeople.rdt.ui.actions.CCPActionGroup;
import org.rubypeople.rdt.ui.actions.CustomFiltersActionGroup;
import org.rubypeople.rdt.ui.actions.OpenEditorActionGroup;
import org.rubypeople.rdt.ui.actions.OpenViewActionGroup;
import org.rubypeople.rdt.ui.actions.RubySearchActionGroup;
abstract class RubyBrowsingPart extends ViewPart implements
ISelectionListener, IMenuListener {
private static final String TAG_SELECTED_ELEMENTS= "selectedElements"; //$NON-NLS-1$
private static final String TAG_SELECTED_ELEMENT= "selectedElement"; //$NON-NLS-1$
private static final String TAG_SELECTED_ELEMENT_PATH= "selectedElementPath"; //$NON-NLS-1$
private StructuredViewer fViewer;
private IMemento fMemento;
private RubyUILabelProvider fLabelProvider;
protected IWorkbenchPart fPreviousSelectionProvider;
protected Object fPreviousSelectedElement;
private ILabelProvider fTitleProvider;
// Actions
private WorkingSetFilterActionGroup fWorkingSetFilterActionGroup;
private boolean fHasWorkingSetFilter= true;
private boolean fHasCustomFilter= true;
private OpenEditorActionGroup fOpenEditorGroup;
protected CompositeActionGroup fActionGroups;
private ToggleLinkingAction fToggleLinkingAction;
// Filters
private CustomFiltersActionGroup fCustomFiltersActionGroup;
// Linking
private boolean fLinkingEnabled;
/*
* Ensure selection changed events being processed only if initiated by user
* interaction with this part.
*/
private boolean fProcessSelectionEvents = true;
private RubyElementTypeComparator fTypeComparator;
private IPartListener2 fPartListener = new IPartListener2() {
public void partActivated(IWorkbenchPartReference ref) {
}
public void partBroughtToTop(IWorkbenchPartReference ref) {
}
public void partInputChanged(IWorkbenchPartReference ref) {
}
public void partClosed(IWorkbenchPartReference ref) {
}
public void partDeactivated(IWorkbenchPartReference ref) {
}
public void partOpened(IWorkbenchPartReference ref) {
}
public void partVisible(IWorkbenchPartReference ref) {
if (ref != null && ref.getId() == getSite().getId()) {
fProcessSelectionEvents = true;
IWorkbenchPage page = getSite().getWorkbenchWindow()
.getActivePage();
if (page != null)
selectionChanged(page.getActivePart(), page.getSelection());
}
}
public void partHidden(IWorkbenchPartReference ref) {
if (ref != null && ref.getId() == getSite().getId())
fProcessSelectionEvents = false;
}
};
private CCPActionGroup fCCPActionGroup;
private BuildActionGroup fBuildActionGroup;
public RubyBrowsingPart() {
super();
initLinkingEnabled();
}
protected void createActions() {
fActionGroups= new CompositeActionGroup(new ActionGroup[] {
new NewWizardsActionGroup(this.getSite()),
fOpenEditorGroup= new OpenEditorActionGroup(this),
new OpenViewActionGroup(this),
fCCPActionGroup= new CCPActionGroup(this),
// new GenerateActionGroup(this),
// new RefactorActionGroup(this),
// new ImportActionGroup(this),
fBuildActionGroup= new BuildActionGroup(this),
new RubySearchActionGroup(this)});
if (fHasWorkingSetFilter) {
String viewId= getConfigurationElement().getAttribute("id"); //$NON-NLS-1$
Assert.isNotNull(viewId);
IPropertyChangeListener workingSetListener= new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
doWorkingSetChanged(event);
}
};
fWorkingSetFilterActionGroup= new WorkingSetFilterActionGroup(getSite(), workingSetListener);
fViewer.addFilter(fWorkingSetFilterActionGroup.getWorkingSetFilter());
}
// Custom filter group
if (fHasCustomFilter)
fCustomFiltersActionGroup= new CustomFiltersActionGroup(this, fViewer);
fToggleLinkingAction= new ToggleLinkingAction(this);
}
/**
* Adds filters the viewer of this part.
*/
protected void addFilters() {
// default is to have no filters
}
/**
* Adds the KeyListener
*/
protected void addKeyListener() {
fViewer.getControl().addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent event) {
handleKeyReleased(event);
}
});
}
protected void handleKeyReleased(KeyEvent event) {
if (event.stateMask != 0)
return;
int key= event.keyCode;
if (key == SWT.F5) {
IAction action= fBuildActionGroup.getRefreshAction();
if (action.isEnabled())
action.run();
}
}
protected void initDragAndDrop() {
int ops= DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
// drop
Transfer[] dropTransfers= new Transfer[] {
LocalSelectionTransfer.getInstance()
};
TransferDropTargetListener[] dropListeners= new TransferDropTargetListener[] {
new SelectionTransferDropAdapter(fViewer)
};
fViewer.addDropSupport(ops | DND.DROP_DEFAULT, dropTransfers, new DelegatingDropAdapter(dropListeners));
// Drag
Transfer[] dragTransfers= new Transfer[] {
LocalSelectionTransfer.getInstance(),
ResourceTransfer.getInstance()};
TransferDragSourceListener[] dragListeners= new TransferDragSourceListener[] {
new SelectionTransferDragAdapter(fViewer),
new ResourceTransferDragAdapter(fViewer)
};
fViewer.addDragSupport(ops, dragTransfers, new RdtViewerDragAdapter(fViewer, dragListeners));
}
protected void createContextMenu() {
MenuManager menuManager= new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuManager.setRemoveAllWhenShown(true);
menuManager.addMenuListener(this);
Menu contextMenu= menuManager.createContextMenu(fViewer.getControl());
fViewer.getControl().setMenu(contextMenu);
getSite().registerContextMenu(menuManager, fViewer);
}
private void doWorkingSetChanged(PropertyChangeEvent event) {
String property= event.getProperty();
if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE.equals(property))
updateTitle();
else if (IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE.equals(property)) {
updateTitle();
fViewer.getControl().setRedraw(false);
fViewer.refresh();
fViewer.getControl().setRedraw(true);
}
}
/**
* Adds additional listeners to this view.
* This method can be overridden but should
* call super.
*/
protected void hookViewerListeners() {
fViewer.addOpenListener(new IOpenListener() {
public void open(OpenEvent event) {
IAction open= fOpenEditorGroup.getOpenAction();
if (open.isEnabled()) {
open.run();
restoreSelection();
}
}
});
}
void setHasCustomSetFilter(boolean state) {
fHasCustomFilter= state;
}
protected boolean hasCustomFilter() {
return fHasCustomFilter;
}
protected void setCustomFiltersActionGroup(CustomFiltersActionGroup customFiltersActionGroup) {
fCustomFiltersActionGroup= customFiltersActionGroup;
}
void restoreSelection() {
// Default is to do nothing
}
protected void setOpenEditorGroup(OpenEditorActionGroup openEditorGroup) {
fOpenEditorGroup= openEditorGroup;
}
protected OpenEditorActionGroup getOpenEditorGroup() {
return fOpenEditorGroup;
}
public void createPartControl(Composite parent) {
Assert.isTrue(fViewer == null);
fViewer = createViewer(parent);
fTypeComparator = new RubyElementTypeComparator();
fLabelProvider = createLabelProvider();
fViewer
.setLabelProvider(createDecoratingLabelProvider(fLabelProvider));
fViewer.setSorter(createRubyElementSorter());
fViewer.setUseHashlookup(true);
fTitleProvider= createTitleProvider();
getSite().setSelectionProvider(fViewer);
if (fMemento != null) { // initialize linking state before creating the actions
restoreLinkingEnabled(fMemento);
}
createActions(); // call before registering for selection changes
if (fMemento != null)
restoreState(fMemento);
getSite().setSelectionProvider(fViewer);
hookViewerListeners();
fViewer.setContentProvider(createContentProvider());
setInitialInput();
// Initialize selection
// TODO Use selection from editor, etc
setInitialSelection();
// Listen to page changes
getViewSite().getPage().addPostSelectionListener(this);
getViewSite().getPage().addPartListener(fPartListener);
fillActionBars(getViewSite().getActionBars());
}
protected StatusBarUpdater createStatusBarUpdater(IStatusLineManager slManager) {
return new StatusBarUpdater(slManager);
}
protected ILabelProvider createTitleProvider() {
return new RubyElementLabelProvider(RubyElementLabelProvider.SHOW_BASICS | RubyElementLabelProvider.SHOW_SMALL_ICONS);
}
/*
* Implements method from IViewPart.
*/
public void init(IViewSite site, IMemento memento) throws PartInitException {
super.init(site, memento);
fMemento= memento;
}
private void restoreLinkingEnabled(IMemento memento) {
Integer val= memento.getInteger(getLinkToEditorKey());
if (val != null) {
fLinkingEnabled= val.intValue() != 0;
}
}
private void saveSelectionState(IMemento memento) {
Object elements[]= ((IStructuredSelection) fViewer.getSelection()).toArray();
if (elements.length > 0) {
IMemento selectionMem= memento.createChild(TAG_SELECTED_ELEMENTS);
for (int i= 0; i < elements.length; i++) {
IMemento elementMem= selectionMem.createChild(TAG_SELECTED_ELEMENT);
Object o= elements[i];
if (o instanceof IRubyElement)
elementMem.putString(TAG_SELECTED_ELEMENT_PATH, ((IRubyElement) elements[i]).getHandleIdentifier());
}
}
}
protected void restoreState(IMemento memento) {
if (fHasWorkingSetFilter)
fWorkingSetFilterActionGroup.restoreState(memento);
if (fHasCustomFilter)
fCustomFiltersActionGroup.restoreState(memento);
if (fHasCustomFilter /*|| fHasWorkingSetFilter*/) {
fViewer.getControl().setRedraw(false);
fViewer.refresh();
fViewer.getControl().setRedraw(true);
}
}
protected StructuredViewer createViewer(Composite parent) {
return new ProblemTableViewer(parent);
}
protected void fillActionBars(IActionBars actionBars) {
IToolBarManager toolBar= actionBars.getToolBarManager();
fillToolBar(toolBar);
if (fHasWorkingSetFilter)
fWorkingSetFilterActionGroup.fillActionBars(getViewSite().getActionBars());
actionBars.updateActionBars();
fActionGroups.fillActionBars(actionBars);
if (fHasCustomFilter)
fCustomFiltersActionGroup.fillActionBars(actionBars);
IMenuManager menu= actionBars.getMenuManager();
menu.add(fToggleLinkingAction);
}
protected boolean hasWorkingSetFilter() {
return fHasWorkingSetFilter;
}
protected void fillToolBar(IToolBarManager tbm) {
}
/**
* Creates the the content provider of this part.
*/
protected IContentProvider createContentProvider() {
return new RubyBrowsingContentProvider(true, this);
}
protected final StructuredViewer getViewer() {
return fViewer;
}
protected void setInitialInput() {
// Use the selection, if any
ISelection selection = getSite().getPage().getSelection();
Object input = getSingleElementFromSelection(selection);
if (!(input instanceof IRubyElement)) {
// Use the input of the page
input = getSite().getPage().getInput();
if (!(input instanceof IRubyElement) && input instanceof IAdaptable)
input = ((IAdaptable) input).getAdapter(IRubyElement.class);
}
setInput(findInputForRubyElement((IRubyElement) input));
}
protected RubyUILabelProvider createLabelProvider() {
return new AppearanceAwareLabelProvider(
AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS,
AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS
| RubyElementImageProvider.SMALL_ICONS);
}
protected void setInput(Object input) {
setViewerInput(input);
updateTitle();
}
void updateTitle() {
setTitleToolTip(getToolTipText(fViewer.getInput()));
}
/**
* Returns the tool tip text for the given element.
*/
String getToolTipText(Object element) {
String result;
if (!(element instanceof IResource)) {
result= RubyElementLabels.getTextLabel(element, AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS);
} else {
IPath path= ((IResource) element).getFullPath();
if (path.isRoot()) {
result= getConfigurationElement().getAttribute("name"); //$NON-NLS-1$
} else {
result= path.makeRelative().toString();
}
}
if (fWorkingSetFilterActionGroup == null || fWorkingSetFilterActionGroup.getWorkingSet() == null)
return result;
IWorkingSet ws= fWorkingSetFilterActionGroup.getWorkingSet();
String wsstr= Messages.format(RubyBrowsingMessages.RubyBrowsingPart_toolTip, new String[] { ws.getLabel() });
if (result.length() == 0)
return wsstr;
return Messages.format(RubyBrowsingMessages.RubyBrowsingPart_toolTip2, new String[] { result, ws.getLabel() });
}
protected final void setViewer(StructuredViewer viewer){
fViewer= viewer;
}
private void setViewerInput(Object input) {
fProcessSelectionEvents = false;
fViewer.setInput(input);
fProcessSelectionEvents = true;
}
private boolean isSearchResultView(IWorkbenchPart part) {
return isSearchPlugInActivated()
&& (part instanceof ISearchResultView || part instanceof ISearchResultViewPart);
}
// FIXME Move this to a ruby SearchUtil class
public static boolean isSearchPlugInActivated() {
return Platform.getBundle("org.eclipse.search").getState() == Bundle.ACTIVE; //$NON-NLS-1$
}
protected boolean needsToProcessSelectionChanged(IWorkbenchPart part,
ISelection selection) {
if (!fProcessSelectionEvents || part == this
|| isSearchResultView(part)) {
if (part == this)
fPreviousSelectionProvider = part;
return false;
}
return true;
}
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (!needsToProcessSelectionChanged(part, selection))
return;
if (fToggleLinkingAction.isChecked() && (part instanceof ITextEditor)) {
setSelectionFromEditor(part, selection);
return;
}
if (!(selection instanceof IStructuredSelection))
return;
// Set selection
Object selectedElement = getSingleElementFromSelection(selection);
if (selectedElement != null
&& (part == null || part.equals(fPreviousSelectionProvider))
&& selectedElement.equals(fPreviousSelectedElement))
return;
fPreviousSelectedElement = selectedElement;
Object currentInput = getViewer().getInput();
if (selectedElement != null && selectedElement.equals(currentInput)) {
IRubyElement elementToSelect = findElementToSelect(selectedElement);
if (elementToSelect != null
&& getTypeComparator().compare(selectedElement,
elementToSelect) < 0)
setSelection(new StructuredSelection(elementToSelect), true);
else if (elementToSelect == null && (this instanceof MembersView)) {
setSelection(StructuredSelection.EMPTY, true);
fPreviousSelectedElement = StructuredSelection.EMPTY;
}
fPreviousSelectionProvider = part;
return;
}
// Clear input if needed
if (part != fPreviousSelectionProvider && selectedElement != null
&& !selectedElement.equals(currentInput)
&& isInputResetBy(selectedElement, currentInput, part)) {
if (!isAncestorOf(selectedElement, currentInput))
setInput(null);
fPreviousSelectionProvider = part;
return;
} else if (selection.isEmpty() && !isInputResetBy(part)) {
fPreviousSelectionProvider = part;
return;
} else if (selectedElement == null
&& part == fPreviousSelectionProvider) {
setInput(null);
fPreviousSelectionProvider = part;
return;
}
fPreviousSelectionProvider = part;
// Adjust input and set selection and
adjustInputAndSetSelection(selectedElement);
}
void setSelection(ISelection selection, boolean reveal) {
if (selection != null && selection.equals(fViewer.getSelection()))
return;
fProcessSelectionEvents = false;
fViewer.setSelection(selection, reveal);
fProcessSelectionEvents = true;
}
protected Object getInput() {
return fViewer.getInput();
}
public void setFocus() {
fViewer.getControl().setFocus();
}
/**
* Answer the property defined by key.
*/
public Object getAdapter(Class key) {
if (key == IShowInSource.class) {
return getShowInSource();
}
// TODO Uncomment when we have RubyUIHelp
// if (key == IContextProvider.class)
// return RubyUIHelp.getHelpContextProvider(this, getHelpContextId());
return super.getAdapter(key);
}
/**
* Returns the <code>IShowInSource</code> for this view.
*/
protected IShowInSource getShowInSource() {
return new IShowInSource() {
public ShowInContext getShowInContext() {
return new ShowInContext(null, getSite().getSelectionProvider()
.getSelection());
}
};
}
void adjustInputAndSetSelection(Object o) {
if (!(o instanceof IRubyElement)) {
if (o == null)
setInput(null);
setSelection(StructuredSelection.EMPTY, true);
return;
}
IRubyElement je = (IRubyElement) o;
IRubyElement elementToSelect = getSuitableRubyElement(findElementToSelect(je));
IRubyElement newInput = findInputForRubyElement(je);
IRubyElement oldInput = null;
if (getInput() instanceof IRubyElement)
oldInput = (IRubyElement) getInput();
if (elementToSelect == null && !isValidInput(newInput)
&& (newInput == null && !isAncestorOf(je, oldInput)))
// Clear input
setInput(null);
else if (mustSetNewInput(elementToSelect, oldInput, newInput)) {
// Adjust input to selection
setInput(newInput);
// Recompute suitable element since it depends on the viewer's input
elementToSelect = getSuitableRubyElement(elementToSelect);
}
if (elementToSelect != null && elementToSelect.exists())
setSelection(new StructuredSelection(elementToSelect), true);
else
setSelection(StructuredSelection.EMPTY, true);
}
/**
* Converts the given Ruby element to one which is suitable for this view.
* It takes into account whether the view shows working copies or not.
*
* @param obj
* the Ruby element to be converted
* @return an element suitable for this view
*/
IRubyElement getSuitableRubyElement(Object obj) {
if (!(obj instanceof IRubyElement))
return null;
IRubyElement element = (IRubyElement) obj;
if (fTypeComparator.compare(element, IRubyElement.SCRIPT) > 0)
return element;
if (isInputAWorkingCopy()) {
IRubyElement wc = getWorkingCopy(element);
if (wc != null)
element = wc;
return element;
} else {
return element.getPrimaryElement();
}
}
boolean isInputAWorkingCopy() {
return ((StandardRubyElementContentProvider) getViewer()
.getContentProvider()).getProvideWorkingCopy();
}
/**
* Tries to find the given element in a workingcopy.
*/
protected static IRubyElement getWorkingCopy(IRubyElement input) {
// MA: with new working copy story original == working copy
return input;
}
/**
* Compute if a new input must be set.
*
* @return <code>true</code> if the input has to be set
* @since 3.0
*/
private boolean mustSetNewInput(IRubyElement elementToSelect,
IRubyElement oldInput, IRubyElement newInput) {
return (newInput == null || !newInput.equals(oldInput))
&& (elementToSelect == null || oldInput == null || (!(false && (elementToSelect
.getParent().equals(oldInput.getParent())) && (!isAncestorOf(
getViewPartInput(), elementToSelect)))));
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
*/
public Object getViewPartInput() {
if (fViewer != null) {
return fViewer.getInput();
}
return null;
}
/**
* Gets the typeComparator.
*
* @return Returns a RubyElementTypeComparator
*/
protected Comparator getTypeComparator() {
return fTypeComparator;
}
private boolean isInputResetBy(Object newInput, Object input,
IWorkbenchPart part) {
if (newInput == null)
return part == fPreviousSelectionProvider;
if (input instanceof IRubyElement && newInput instanceof IRubyElement)
return getTypeComparator().compare(newInput, input) > 0;
else
return false;
}
private boolean isInputResetBy(IWorkbenchPart part) {
if (!(part instanceof RubyBrowsingPart))
return true;
Object thisInput = getViewer().getInput();
Object partInput = ((RubyBrowsingPart) part).getViewer().getInput();
if (thisInput instanceof Collection)
thisInput = ((Collection) thisInput).iterator().next();
if (partInput instanceof Collection)
partInput = ((Collection) partInput).iterator().next();
if (thisInput instanceof IRubyElement
&& partInput instanceof IRubyElement)
return getTypeComparator().compare(partInput, thisInput) > 0;
else
return true;
}
protected boolean isAncestorOf(Object ancestor, Object element) {
if (element instanceof IRubyElement && ancestor instanceof IRubyElement)
return !element.equals(ancestor)
&& internalIsAncestorOf((IRubyElement) ancestor,
(IRubyElement) element);
return false;
}
private boolean internalIsAncestorOf(IRubyElement ancestor,
IRubyElement element) {
if (element != null)
return element.equals(ancestor)
|| internalIsAncestorOf(ancestor, element.getParent());
else
return false;
}
protected final IRubyElement findElementToSelect(Object obj) {
if (obj instanceof IRubyElement)
return findElementToSelect((IRubyElement) obj);
return null;
}
/**
* Finds the element which has to be selected in this part.
*
* @param je
* the Ruby element which has the focus
*/
abstract protected IRubyElement findElementToSelect(IRubyElement je);
protected final Object getSingleElementFromSelection(ISelection selection) {
if (!(selection instanceof StructuredSelection) || selection.isEmpty())
return null;
Iterator iter = ((StructuredSelection) selection).iterator();
Object firstElement = iter.next();
if (!(firstElement instanceof IRubyElement)) {
if (firstElement instanceof IMarker)
firstElement = ((IMarker) firstElement).getResource();
if (firstElement instanceof IAdaptable) {
IRubyElement je = (IRubyElement) ((IAdaptable) firstElement)
.getAdapter(IRubyElement.class);
if (je == null && firstElement instanceof IFile) {
IContainer parent = ((IFile) firstElement).getParent();
if (parent != null)
return (IRubyElement) parent
.getAdapter(IRubyElement.class);
else
return null;
} else
return je;
} else
return firstElement;
}
Object currentInput = getViewer().getInput();
if (currentInput == null
|| !currentInput
.equals(findInputForRubyElement((IRubyElement) firstElement)))
if (iter.hasNext())
// multi-selection and view is empty
return null;
else
// OK: single selection and view is empty
return firstElement;
// be nice to multi-selection
while (iter.hasNext()) {
Object element = iter.next();
if (!(element instanceof IRubyElement))
return null;
if (!currentInput
.equals(findInputForRubyElement((IRubyElement) element)))
return null;
}
return firstElement;
}
/**
* Finds the closest Ruby element which can be used as input for this part
* and has the given Ruby element as child
*
* @param je
* the Ruby element for which to search the closest input
* @return the closest Ruby element used as input for this part
*/
protected IRubyElement findInputForRubyElement(IRubyElement je) {
if (je == null || !je.exists())
return null;
if (isValidInput(je))
return je;
return findInputForRubyElement(je.getParent());
}
protected RubyElementSorter createRubyElementSorter() {
return new RubyElementSorter() {
@Override
protected String getElementName(Object element) {
if (element instanceof IType) {
IType type = (IType) element;
return type.getFullyQualifiedName();
}
return super.getElementName(element);
}
};
}
/**
* Returns the shell to use for opening dialogs.
* Used in this class, and in the actions.
*/
Shell getShell() {
return fViewer.getControl().getShell();
}
protected final Display getDisplay() {
return fViewer.getControl().getDisplay();
}
/**
* Returns the selection provider.
*/
ISelectionProvider getSelectionProvider() {
return fViewer;
}
/**
* Answers if the given <code>element</code> is a valid input for this
* part.
*
* @param element
* the object to test
* @return <code>true</code> if the given element is a valid input
*/
abstract protected boolean isValidInput(Object element);
/**
* Answers if the given <code>element</code> is a valid element for this
* part.
*
* @param element
* the object to test
* @return <code>true</code> if the given element is a valid element
*/
protected boolean isValidElement(Object element) {
if (element == null)
return false;
element = getSuitableRubyElement(element);
if (element == null)
return false;
Object input = getViewer().getInput();
if (input == null)
return false;
if (input instanceof Collection)
return ((Collection) input).contains(element);
else
return input.equals(element);
}
protected DecoratingLabelProvider createDecoratingLabelProvider(RubyUILabelProvider provider) {
// XXX: Work in progress for problem decorator being a workbench decorator//
// return new ExcludingDecoratingLabelProvider(provider, decorationMgr, "org.eclipse.jdt.ui.problem.decorator"); //$NON-NLS-1$
return new DecoratingRubyLabelProvider(provider);
}
protected IType getTypeForRubyScript(IRubyScript script) {
script = (IRubyScript) getSuitableRubyElement(script);
// Use primary type if possible
IType primaryType = script.findPrimaryType();
if (primaryType != null)
return primaryType;
// Use first top-level type
try {
IType[] types = script.getTypes();
if (types.length > 0)
return types[0];
else
return null;
} catch (RubyModelException ex) {
return null;
}
}
public void dispose() {
if (fViewer != null) {
getViewSite().getPage().removePostSelectionListener(this);
getViewSite().getPage().removePartListener(fPartListener);
fViewer = null;
}
if (fActionGroups != null)
fActionGroups.dispose();
super.dispose();
}
void setProcessSelectionEvents(boolean state) {
fProcessSelectionEvents = state;
}
/**
* Called when the context menu is about to open.
* Override to add your own context dependent menu contributions.
*/
public void menuAboutToShow(IMenuManager menu) {
RubyPlugin.createStandardGroups(menu);
IStructuredSelection selection= (IStructuredSelection) fViewer.getSelection();
int size= selection.size();
Object element= selection.getFirstElement();
if (size == 1)
addOpenNewWindowAction(menu, element);
fActionGroups.setContext(new ActionContext(selection));
fActionGroups.fillContextMenu(menu);
fActionGroups.setContext(null);
}
private void addOpenNewWindowAction(IMenuManager menu, Object element) {
if (element instanceof IRubyElement) {
element= ((IRubyElement)element).getResource();
}
if (!(element instanceof IContainer))
return;
menu.appendToGroup(
IContextMenuConstants.GROUP_OPEN,
new PatchedOpenInNewWindowAction(getSite().getWorkbenchWindow(), (IContainer)element));
}
/*
* Implements method from IViewPart.
*/
public void saveState(IMemento memento) {
if (fViewer == null) {
// part has not been created
if (fMemento != null) //Keep the old state;
memento.putMemento(fMemento);
return;
}
if (fHasWorkingSetFilter)
fWorkingSetFilterActionGroup.saveState(memento);
if (fHasCustomFilter)
fCustomFiltersActionGroup.saveState(memento);
saveSelectionState(memento);
saveLinkingEnabled(memento);
}
void setHasWorkingSetFilter(boolean state) {
fHasWorkingSetFilter= state;
}
private void saveLinkingEnabled(IMemento memento) {
memento.putInteger(getLinkToEditorKey(), fLinkingEnabled ? 1 : 0);
}
protected void setInitialSelection() {
// Use the selection, if any
Object input;
IWorkbenchPage page= getSite().getPage();
ISelection selection= null;
if (page != null)
selection= page.getSelection();
if (selection instanceof ITextSelection) {
Object part= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart();
if (part instanceof IEditorPart) {
setSelectionFromEditor((IEditorPart)part);
if (fViewer.getSelection() != null)
return;
}
}
// Use saved selection from memento
if (selection == null || selection.isEmpty())
selection= restoreSelectionState(fMemento);
if (selection == null || selection.isEmpty()) {
// Use the input of the page
input= getSite().getPage().getInput();
if (!(input instanceof IRubyElement)) {
if (input instanceof IAdaptable)
input= ((IAdaptable)input).getAdapter(IRubyElement.class);
else
return;
}
selection= new StructuredSelection(input);
}
selectionChanged(null, selection);
}
private ISelection restoreSelectionState(IMemento memento) {
if (memento == null)
return null;
IMemento childMem;
childMem= memento.getChild(TAG_SELECTED_ELEMENTS);
if (childMem != null) {
ArrayList list= new ArrayList();
IMemento[] elementMem= childMem.getChildren(TAG_SELECTED_ELEMENT);
for (int i= 0; i < elementMem.length; i++) {
String javaElementHandle= elementMem[i].getString(TAG_SELECTED_ELEMENT_PATH);
IRubyElement element= RubyCore.create(javaElementHandle);
if (element != null && element.exists())
list.add(element);
}
return new StructuredSelection(list);
}
return null;
}
boolean isLinkingEnabled() {
return fLinkingEnabled;
}
private void initLinkingEnabled() {
fLinkingEnabled= PreferenceConstants.getPreferenceStore().getBoolean(getLinkToEditorKey());
}
private boolean linkBrowsingViewSelectionToEditor() {
return isLinkingEnabled();
}
public void setLinkingEnabled(boolean enabled) {
fLinkingEnabled= enabled;
PreferenceConstants.getPreferenceStore().setValue(getLinkToEditorKey(), enabled);
if (enabled) {
IEditorPart editor = getSite().getPage().getActiveEditor();
if (editor != null) {
setSelectionFromEditor(editor);
}
}
}
protected final ILabelProvider getLabelProvider() {
return fLabelProvider;
}
protected final ILabelProvider getTitleProvider() {
return fTitleProvider;
}
/**
* Returns the preference key for the link to editor setting.
*
* @return the string used as key into the preference store
*/
abstract protected String getLinkToEditorKey();
void setSelectionFromEditor(IWorkbenchPart part) {
if (!fProcessSelectionEvents || !linkBrowsingViewSelectionToEditor() || !(part instanceof IEditorPart))
return;
IWorkbenchPartSite site= part.getSite();
if (site == null)
return;
ISelectionProvider provider= site.getSelectionProvider();
if (provider != null)
setSelectionFromEditor(part, provider.getSelection());
}
private void setSelectionFromEditor(IWorkbenchPart part, ISelection selection) {
if (part instanceof IEditorPart) {
IRubyElement element= null;
if (selection instanceof IStructuredSelection) {
Object obj= getSingleElementFromSelection(selection);
if (obj instanceof IRubyElement)
element= (IRubyElement)obj;
}
IEditorInput ei= ((IEditorPart)part).getEditorInput();
if (selection instanceof ITextSelection) {
int offset= ((ITextSelection)selection).getOffset();
element= getElementAt(ei, offset);
}
if (element != null) {
adjustInputAndSetSelection(element);
return;
}
if (ei instanceof IFileEditorInput) {
IFile file= ((IFileEditorInput)ei).getFile();
IRubyElement je= (IRubyElement)file.getAdapter(IRubyElement.class);
if (je == null) {
IContainer container= ((IFileEditorInput)ei).getFile().getParent();
if (container != null)
je= (IRubyElement)container.getAdapter(IRubyElement.class);
}
if (je == null) {
setSelection(null, false);
return;
}
adjustInputAndSetSelection(je);
}
}
}
/**
* @see org.rubypeople.rdt.internal.ui.rubyeditor.RubyEditor#getElementAt(int)
*/
protected IRubyElement getElementAt(IEditorInput input, int offset) {
IWorkingCopyManager manager= RubyPlugin.getDefault().getWorkingCopyManager();
IRubyScript unit= manager.getWorkingCopy(input);
if (unit != null)
try {
if (unit.isConsistent())
return unit.getElementAt(offset);
else {
/*
* XXX: We should set the selection later when the
* CU is reconciled.
* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=51290
*/
}
} catch (RubyModelException ex) {
// fall through
}
return null;
}
}