|
From: <jas...@us...> - 2006-07-19 05:47:34
|
Revision: 1521 Author: jasonpmorrison Date: 2006-07-18 22:47:24 -0700 (Tue, 18 Jul 2006) ViewCVS: http://svn.sourceforge.net/rubyeclipse/?rev=1521&view=rev Log Message: ----------- Glued up the Mark Occurrence code so it is actually invoked! Modified Paths: -------------- branches/type_inferrence/trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java Modified: branches/type_inferrence/trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java =================================================================== --- branches/type_inferrence/trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java 2006-07-19 05:42:24 UTC (rev 1520) +++ branches/type_inferrence/trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java 2006-07-19 05:47:24 UTC (rev 1521) @@ -2,7 +2,10 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.HashMap; import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Stack; import org.eclipse.core.resources.IMarker; @@ -11,9 +14,13 @@ import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Preferences; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; @@ -25,12 +32,17 @@ import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension; +import org.eclipse.jface.text.IDocumentExtension4; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.ILineTracker; import org.eclipse.jface.text.IPositionUpdater; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ISelectionValidator; +import org.eclipse.jface.text.ISynchronizable; +import org.eclipse.jface.text.ITextInputListener; import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.ITextViewerExtension; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.ITypedRegion; @@ -46,6 +58,7 @@ import org.eclipse.jface.text.link.LinkedModeUI.IExitPolicy; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IAnnotationModelExtension; import org.eclipse.jface.text.source.ICharacterPairMatcher; import org.eclipse.jface.text.source.IOverviewRuler; import org.eclipse.jface.text.source.ISourceViewer; @@ -54,9 +67,12 @@ import org.eclipse.jface.text.source.projection.ProjectionSupport; import org.eclipse.jface.text.source.projection.ProjectionViewer; import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.viewers.IPostSelectionProvider; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.custom.VerifyKeyListener; @@ -67,9 +83,12 @@ import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWindowListener; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; import org.eclipse.ui.SelectionEnabler; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.actions.ActionGroup; @@ -77,6 +96,7 @@ import org.eclipse.ui.help.WorkbenchHelp; import org.eclipse.ui.texteditor.AnnotationPreference; import org.eclipse.ui.texteditor.ContentAssistAction; +import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.MarkerAnnotation; @@ -87,6 +107,8 @@ import org.rubypeople.rdt.core.IRubyScript; import org.rubypeople.rdt.core.RubyModelException; import org.rubypeople.rdt.internal.corext.util.RubyModelUtil; +import org.rubypeople.rdt.internal.ti.DefaultOccurrencesFinder; +import org.rubypeople.rdt.internal.ti.IOccurrencesFinder; import org.rubypeople.rdt.internal.ui.IRubyHelpContextIds; import org.rubypeople.rdt.internal.ui.RubyPlugin; import org.rubypeople.rdt.internal.ui.RubyUIMessages; @@ -159,7 +181,108 @@ private FoldingActionGroup fFoldingGroup; private BracketInserter fBracketInserter = new BracketInserter(); + + /** + * Holds the current occurrence annotations. + * @since 3.0 + */ + private Annotation[] fOccurrenceAnnotations= null; + /** + * Tells whether all occurrences of the element at the + * current caret location are automatically marked in + * this editor. + * @since 3.0 + */ + private boolean fMarkOccurrenceAnnotations; + /** + * Tells whether the occurrence annotations are sticky + * i.e. whether they stay even if there's no valid Java + * element at the current caret position. + * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. + * @since 3.0 + */ + private boolean fStickyOccurrenceAnnotations; +// /** +// * Tells whether to mark type occurrences in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.0 +// */ +// private boolean fMarkTypeOccurrences; +// /** +// * Tells whether to mark method occurrences in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.0 +// */ +// private boolean fMarkMethodOccurrences; +// /** +// * Tells whether to mark constant occurrences in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.0 +// */ +// private boolean fMarkConstantOccurrences; +// /** +// * Tells whether to mark field occurrences in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.0 +// */ +// private boolean fMarkFieldOccurrences; +// /** +// * Tells whether to mark local variable occurrences in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.0 +// */ +// private boolean fMarkLocalVariableypeOccurrences; +// /** +// * Tells whether to mark exception occurrences in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.0 +// */ +// private boolean fMarkExceptions; +// /** +// * Tells whether to mark method exits in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.0 +// */ +// private boolean fMarkMethodExitPoints; +// +// /** +// * Tells whether to mark targets of <code>break</code> and <code>continue</code> statements in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.2 +// */ +// private boolean fMarkBreakContinueTargets; +// +// /** +// * Tells whether to mark implementors in this editor. +// * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. +// * @since 3.1 +// */ +// private boolean fMarkImplementors; + /** + * The selection used when forcing occurrence marking + * through code. + * @since 3.0 + */ + private ISelection fForcedMarkOccurrencesSelection; + /** + * The document modification stamp at the time when the last + * occurrence marking took place. + * @since 3.1 + */ + //TODO: Do I need to use this? + private long fMarkOccurrenceModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; + /** + * The internal shell activation listener for updating occurrences. + */ + private ActivationListener fActivationListener= new ActivationListener(); + private ISelectionChangedListener fPostSelectionListener; + private OccurrencesFinderJob fOccurrencesFinderJob; + /** The occurrences finder job canceler */ + private OccurrencesFinderJobCanceler fOccurrencesFinderJobCanceler; + private IOccurrencesFinder fOccurrencesFinder; + + public RubyEditor() { super(); setDocumentProvider(RubyPlugin.getDefault().getRubyDocumentProvider()); @@ -289,7 +412,31 @@ fBracketInserter.setCloseBracesEnabled(closeBraces); fBracketInserter.setCloseStringsEnabled(closeStrings); ((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(fBracketInserter); + + //TODO: Pull these from prefs rather than hardcoded true values + fMarkOccurrenceAnnotations = true; + fStickyOccurrenceAnnotations = false; +// setPreferenceStore(store); +// JavaTextTools textTools= JavaPlugin.getDefault().getJavaTextTools(); +// setSourceViewerConfiguration(new JavaSourceViewerConfiguration(textTools.getColorManager(), store, this, IJavaPartitions.JAVA_PARTITIONING)); +// fMarkOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES); +// fStickyOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_STICKY_OCCURRENCES); +// fMarkTypeOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_TYPE_OCCURRENCES); +// fMarkMethodOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_OCCURRENCES); +// fMarkConstantOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_CONSTANT_OCCURRENCES); +// fMarkFieldOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_FIELD_OCCURRENCES); +// fMarkLocalVariableypeOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_LOCAL_VARIABLE_OCCURRENCES); +// fMarkExceptions= store.getBoolean(PreferenceConstants.EDITOR_MARK_EXCEPTION_OCCURRENCES); +// fMarkImplementors= store.getBoolean(PreferenceConstants.EDITOR_MARK_IMPLEMENTORS); +// fMarkMethodExitPoints= store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_EXIT_POINTS); +// fMarkBreakContinueTargets= store.getBoolean(PreferenceConstants.EDITOR_MARK_BREAK_CONTINUE_TARGETS); } + + + if (fMarkOccurrenceAnnotations) + installOccurrencesFinder(false); + + PlatformUI.getWorkbench().addWindowListener(fActivationListener); } /** @@ -606,6 +753,16 @@ fProjectionSupport.dispose(); fProjectionSupport = null; } + + // cancel possible running computation + fMarkOccurrenceAnnotations= false; + uninstallOccurrencesFinder(); + + if (fActivationListener != null) { + PlatformUI.getWorkbench().removeWindowListener(fActivationListener); + fActivationListener= null; + } + super.dispose(); } @@ -1558,4 +1715,390 @@ public FoldingActionGroup getFoldingActionGroup() { return fFoldingGroup; } + + /** + * Internal activation listener. + * @since 3.0 + */ + private class ActivationListener implements IWindowListener { + + /* + * @see org.eclipse.ui.IWindowListener#windowActivated(org.eclipse.ui.IWorkbenchWindow) + * @since 3.1 + */ + public void windowActivated(IWorkbenchWindow window) { + if (window == getEditorSite().getWorkbenchWindow() && fMarkOccurrenceAnnotations && isActivePart()) { + fForcedMarkOccurrencesSelection= getSelectionProvider().getSelection(); + updateOccurrenceAnnotations((ITextSelection)fForcedMarkOccurrencesSelection); + } + } + + /* + * @see org.eclipse.ui.IWindowListener#windowDeactivated(org.eclipse.ui.IWorkbenchWindow) + * @since 3.1 + */ + public void windowDeactivated(IWorkbenchWindow window) { + if (window == getEditorSite().getWorkbenchWindow() && fMarkOccurrenceAnnotations && isActivePart()) + removeOccurrenceAnnotations(); + } + + /* + * @see org.eclipse.ui.IWindowListener#windowClosed(org.eclipse.ui.IWorkbenchWindow) + * @since 3.1 + */ + public void windowClosed(IWorkbenchWindow window) { + } + + /* + * @see org.eclipse.ui.IWindowListener#windowOpened(org.eclipse.ui.IWorkbenchWindow) + * @since 3.1 + */ + public void windowOpened(IWorkbenchWindow window) { + } + } + + /** + * Cancels the occurrences finder job upon document changes. + * + * @since 3.0 + */ + class OccurrencesFinderJobCanceler implements IDocumentListener, ITextInputListener { + + public void install() { + ISourceViewer sourceViewer= getSourceViewer(); + if (sourceViewer == null) + return; + + StyledText text= sourceViewer.getTextWidget(); + if (text == null || text.isDisposed()) + return; + + sourceViewer.addTextInputListener(this); + + IDocument document= sourceViewer.getDocument(); + if (document != null) + document.addDocumentListener(this); + } + + public void uninstall() { + ISourceViewer sourceViewer= getSourceViewer(); + if (sourceViewer != null) + sourceViewer.removeTextInputListener(this); + + IDocumentProvider documentProvider= getDocumentProvider(); + if (documentProvider != null) { + IDocument document= documentProvider.getDocument(getEditorInput()); + if (document != null) + document.removeDocumentListener(this); + } + } + + + /* + * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentAboutToBeChanged(DocumentEvent event) { + if (fOccurrencesFinderJob != null) + fOccurrencesFinderJob.doCancel(); + } + + /* + * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentChanged(DocumentEvent event) { + } + + /* + * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) + */ + public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { + if (oldInput == null) + return; + + oldInput.removeDocumentListener(this); + } + + /* + * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) + */ + public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { + if (newInput == null) + return; + newInput.addDocumentListener(this); + } + } + + /** + * Finds and marks occurrence annotations. + * + * @since 3.0 + */ + class OccurrencesFinderJob extends Job { + + private IDocument fDocument; + private ISelection fSelection; + private ISelectionValidator fPostSelectionValidator; + private boolean fCanceled= false; + private IProgressMonitor fProgressMonitor; + private Position[] fPositions; + + public OccurrencesFinderJob(IDocument document, Position[] positions, ISelection selection) { + //TODO: Refactor job name to resource string somewhere + super("OccurrencesFinderJob"); + fDocument= document; + fSelection= selection; + fPositions= positions; + + if (getSelectionProvider() instanceof ISelectionValidator) + fPostSelectionValidator= (ISelectionValidator)getSelectionProvider(); + } + + // cannot use cancel() because it is declared final + void doCancel() { + fCanceled= true; + cancel(); + } + + private boolean isCanceled() { + return fCanceled || fProgressMonitor.isCanceled() + || fPostSelectionValidator != null && !(fPostSelectionValidator.isValid(fSelection) || fForcedMarkOccurrencesSelection == fSelection) + || LinkedModeModel.hasInstalledModel(fDocument); + } + + /* + * @see Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + public IStatus run(IProgressMonitor progressMonitor) { + + fProgressMonitor= progressMonitor; + + if (isCanceled()) + return Status.CANCEL_STATUS; + + ITextViewer textViewer= getViewer(); + if (textViewer == null) + return Status.CANCEL_STATUS; + + IDocument document= textViewer.getDocument(); + if (document == null) + return Status.CANCEL_STATUS; + + IDocumentProvider documentProvider= getDocumentProvider(); + if (documentProvider == null) + return Status.CANCEL_STATUS; + + IAnnotationModel annotationModel= documentProvider.getAnnotationModel(getEditorInput()); + if (annotationModel == null) + return Status.CANCEL_STATUS; + + // Add occurrence annotations + int length= fPositions.length; + Map annotationMap= new HashMap(length); + for (int i= 0; i < length; i++) { + + if (isCanceled()) + return Status.CANCEL_STATUS; + + String message; + Position position= fPositions[i]; + + // Create & add annotation + try { + message= document.get(position.offset, position.length); + } catch (BadLocationException ex) { + // Skip this match + continue; + } + annotationMap.put( + new Annotation("org.eclipse.jdt.ui.occurrences", false, message), //$NON-NLS-1$ + position); + } + + if (isCanceled()) + return Status.CANCEL_STATUS; + + synchronized (getLockObject(annotationModel)) { + if (annotationModel instanceof IAnnotationModelExtension) { + ((IAnnotationModelExtension)annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap); + } else { + removeOccurrenceAnnotations(); + Iterator iter= annotationMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry mapEntry= (Map.Entry)iter.next(); + annotationModel.addAnnotation((Annotation)mapEntry.getKey(), (Position)mapEntry.getValue()); + } + } + fOccurrenceAnnotations= (Annotation[])annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]); + } + + return Status.OK_STATUS; + } + } + + /** + * Updates the occurrences annotations based + * on the current selection. + * + * @param selection the text selection + */ + protected void updateOccurrenceAnnotations(ITextSelection selection) { + + if (fOccurrencesFinderJob != null) + fOccurrencesFinderJob.cancel(); + + if (!fMarkOccurrenceAnnotations) + return; + + if (selection == null) + return; + + IDocument document= getDocumentProvider().getDocument(getEditorInput()); + String source = document.get(); + + // Search for occurrences + fOccurrencesFinder.initialize(source, selection.getOffset(), selection.getLength()); + List<Position> matches = fOccurrencesFinder.perform(); + + if (matches.isEmpty()) { + if (!fStickyOccurrenceAnnotations) { + removeOccurrenceAnnotations(); + } + return; + } else { + // Convert to array + //TODO: Update IOccurrencesFinder interface to return an array of Position + Position[] positions = new Position[matches.size()]; + int i = 0; + for (Position match : matches) { + positions[i++] = match; + } + + // Mark occurrences + fOccurrencesFinderJob= new OccurrencesFinderJob(document, positions, selection); + //fOccurrencesFinderJob.setPriority(Job.DECORATE); + //fOccurrencesFinderJob.setSystem(true); + //fOccurrencesFinderJob.schedule(); + fOccurrencesFinderJob.run(new NullProgressMonitor()); + } + } + + protected void installOccurrencesFinder(boolean forceUpdate) { + fMarkOccurrenceAnnotations= true; + + fOccurrencesFinder = new DefaultOccurrencesFinder(); + + fPostSelectionListener = new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + updateOccurrenceAnnotations((ITextSelection)event.getSelection()); + } + }; + + IPostSelectionProvider postSelectionProvider = (IPostSelectionProvider)getSourceViewer().getSelectionProvider(); + postSelectionProvider.addPostSelectionChangedListener(fPostSelectionListener); + + if (forceUpdate && getSelectionProvider() != null) { + fForcedMarkOccurrencesSelection= getSelectionProvider().getSelection(); + updateOccurrenceAnnotations((ITextSelection)fForcedMarkOccurrencesSelection); + } + + if (fOccurrencesFinderJobCanceler == null) { + fOccurrencesFinderJobCanceler= new OccurrencesFinderJobCanceler(); + fOccurrencesFinderJobCanceler.install(); + } + } + + protected void uninstallOccurrencesFinder() { + fMarkOccurrenceAnnotations= false; + + if (fOccurrencesFinderJob != null) { + fOccurrencesFinderJob.cancel(); + fOccurrencesFinderJob= null; + } + + if (fOccurrencesFinderJobCanceler != null) { + fOccurrencesFinderJobCanceler.uninstall(); + fOccurrencesFinderJobCanceler= null; + } + + if (fPostSelectionListener != null) { + IPostSelectionProvider postSelectionProvider = (IPostSelectionProvider)getSourceViewer().getSelectionProvider(); + postSelectionProvider.removePostSelectionChangedListener(fPostSelectionListener); + fPostSelectionListener = null; + } + + removeOccurrenceAnnotations(); + } + + protected boolean isMarkingOccurrences() { + return fMarkOccurrenceAnnotations; + } + +// boolean markOccurrencesOfType(IBinding binding) { +// +// if (binding == null) +// return false; +// +// int kind= binding.getKind(); +// +// if (fMarkTypeOccurrences && kind == IBinding.TYPE) +// return true; +// +// if (fMarkMethodOccurrences && kind == IBinding.METHOD) +// return true; +// +// if (kind == IBinding.VARIABLE) { +// IVariableBinding variableBinding= (IVariableBinding)binding; +// if (variableBinding.isField()) { +// int constantModifier= IModifierConstants.ACC_STATIC | IModifierConstants.ACC_FINAL; +// boolean isConstant= (variableBinding.getModifiers() & constantModifier) == constantModifier; +// if (isConstant) +// return fMarkConstantOccurrences; +// else +// return fMarkFieldOccurrences; +// } +// +// return fMarkLocalVariableypeOccurrences; +// } +// +// return false; +// } + + void removeOccurrenceAnnotations() { + fMarkOccurrenceModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; + + IDocumentProvider documentProvider= getDocumentProvider(); + if (documentProvider == null) + return; + + IAnnotationModel annotationModel= documentProvider.getAnnotationModel(getEditorInput()); + if (annotationModel == null || fOccurrenceAnnotations == null) + return; + + synchronized (getLockObject(annotationModel)) { + if (annotationModel instanceof IAnnotationModelExtension) { + ((IAnnotationModelExtension)annotationModel).replaceAnnotations(fOccurrenceAnnotations, null); + } else { + for (int i= 0, length= fOccurrenceAnnotations.length; i < length; i++) + annotationModel.removeAnnotation(fOccurrenceAnnotations[i]); + } + fOccurrenceAnnotations= null; + } + } + + /** + * Returns the lock object for the given annotation model. + * + * @param annotationModel the annotation model + * @return the annotation model's lock object + * @since 3.0 + */ + private Object getLockObject(IAnnotationModel annotationModel) { + if (annotationModel instanceof ISynchronizable) { + Object lock= ((ISynchronizable)annotationModel).getLockObject(); + if (lock != null) + return lock; + } + return annotationModel; + } + } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |