/** * This file Copyright (c) 2005-2008 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain other free and open source software ("FOSS") code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.editors.unified; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Vector; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.help.IContextProvider; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.preference.PreferenceStore; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension3; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ISynchronizable; import org.eclipse.jface.text.ITextListener; import org.eclipse.jface.text.ITextViewerExtension2; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextEvent; import org.eclipse.jface.text.TextPresentation; import org.eclipse.jface.text.WhitespaceCharacterPainter; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.AnnotationRulerColumn; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IAnnotationModelExtension; import org.eclipse.jface.text.source.IOverviewRuler; import org.eclipse.jface.text.source.ISharedTextColors; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.IVerticalRulerColumn; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.text.source.UnifiedLineNumberChangeRulerColumn; import org.eclipse.jface.text.source.UnifiedOverviewRuler; import org.eclipse.jface.text.source.projection.ProjectionAnnotation; import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel; import org.eclipse.jface.text.source.projection.ProjectionViewer; import org.eclipse.jface.text.source.projection.UnifiedProjectionSupport; import org.eclipse.jface.text.source.projection.UnifiedRulerColumn; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.IPostSelectionProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.LineStyleEvent; import org.eclipse.swt.custom.LineStyleListener; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.custom.TextChangeListener; import org.eclipse.swt.custom.TextChangedEvent; import org.eclipse.swt.custom.TextChangingEvent; import org.eclipse.swt.custom.VerifyKeyListener; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.events.TraverseEvent; import org.eclipse.swt.events.TraverseListener; import org.eclipse.swt.events.VerifyEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Caret; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.ScrollBar; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IPathEditorInput; import org.eclipse.ui.IURIEditorInput; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.editors.text.EditorsPlugin; import org.eclipse.ui.internal.editors.text.NonExistingFileEditorInput; import org.eclipse.ui.navigator.CommonNavigator; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.progress.UIJob; import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; import org.eclipse.ui.texteditor.AbstractTextEditor; import org.eclipse.ui.texteditor.AnnotationPreference; import org.eclipse.ui.texteditor.BookmarkRulerAction; import org.eclipse.ui.texteditor.ChainedPreferenceStore; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; import org.eclipse.ui.texteditor.TaskRulerAction; import org.eclipse.ui.texteditor.TextOperationAction; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import com.aptana.ide.core.IdeLog; import com.aptana.ide.core.StringUtils; import com.aptana.ide.core.ui.CoreUIUtils; import com.aptana.ide.core.ui.editors.ISaveAsEvent; import com.aptana.ide.core.ui.editors.ISaveEvent; import com.aptana.ide.editors.UnifiedEditorsPlugin; import com.aptana.ide.editors.actions.OpenDeclarationAction; import com.aptana.ide.editors.formatting.UnifiedBracketInserterManager; import com.aptana.ide.editors.managers.FileContextManager; import com.aptana.ide.editors.preferences.IPreferenceConstants; import com.aptana.ide.editors.unified.actions.CodeFormatAction; import com.aptana.ide.editors.unified.actions.GotoMatchingBracketAction; import com.aptana.ide.editors.unified.actions.UnifiedActionContributor; import com.aptana.ide.editors.unified.colorizer.LanguageColorizer; import com.aptana.ide.editors.unified.colorizer.UnifiedCursorLinePainter; import com.aptana.ide.editors.unified.contentassist.ContentAssistAction; import com.aptana.ide.editors.unified.context.ContextItem; import com.aptana.ide.editors.unified.context.IContextAwareness; import com.aptana.ide.editors.unified.errors.ExternalFileErrorListener; import com.aptana.ide.editors.unified.errors.FileErrorListener; import com.aptana.ide.editors.unified.errors.ProjectFileErrorListener; import com.aptana.ide.editors.unified.folding.FoldingExtensionPointLoader; import com.aptana.ide.editors.unified.folding.LanguageProjectAnnotation; import com.aptana.ide.editors.unified.help.LexemeUIHelp; import com.aptana.ide.editors.unified.messaging.UnifiedMessages; import com.aptana.ide.editors.untitled.BaseTextEditor; import com.aptana.ide.lexer.IRange; import com.aptana.ide.lexer.Lexeme; import com.aptana.ide.lexer.LexemeList; import com.aptana.ide.lexer.TokenCategories; import com.aptana.ide.parsing.IParseState; import com.aptana.ide.views.outline.UnifiedOutlinePage; import com.aptana.ide.views.outline.UnifiedQuickOutlinePage; /** * UnifiedEditor */ public abstract class UnifiedEditor extends BaseTextEditor implements IUnifiedEditor, IPropertyChangeListener, ISelectionChangedListener, IRedrawRangeListener { /** * ADD_BOOKMARK */ public static final String ADD_BOOKMARK = "AddBookmark"; //$NON-NLS-1$ /** * ADD_TASK */ public static final String ADD_TASK = "AddTask"; //$NON-NLS-1$ /** * ctrlDown */ public static boolean ctrlDown; /** * outlinePage */ protected UnifiedOutlinePage outlinePage; /** * Auto activate for code assist, used for ContentAssistant AutoActivation listener */ protected boolean autoActivateCodeAssist = true; /** * File service change listeners */ protected ListenerList fileServiceChangeListeners = new ListenerList(); private UnifiedColorizer _colorizer; private IUnifiedEditorContributor _baseContributor; private FileErrorListener _errorListener; private WhitespaceCharacterPainter _whitespacePainter; private EditorFileContext _fileContextWrapper; // private UnifiedBracketMatcher bracketMatcher; private ArrayList<ISaveAsEvent> _saveAsListeners; private ArrayList<ISaveEvent> _saveListeners; private CommonNavigator _fileExplorerView; // private TextColorer textColorer; private IPreferenceStore _prefStore; private IPartListener _partListener; private UnifiedProjectionSupport _projectionSupport; private Listener _keyUpListener; private VerifyKeyListener _verifyKeyListener; private UnifiedViewer _viewer; private IContextAwareness _contextAwareness; private boolean _isDisposing = false; private boolean _hasKeyBeenPressed = false; private LineStyleListener _lineStyleListener; private TextChangeListener _textChangeListener; private PairMatcher _pairMatcher; private Image _caretImage; private UnifiedCursorLinePainter _painter; private int _maxColorizingColumns; private boolean _extendedStylesEnabled; private SelectionAdapter _selectionListener; private FocusAdapter _focusListener; private ITextListener _textListener; private IPreferenceStore _runtimeStore = new PreferenceStore(); private UnifiedBracketInserterManager _bracketInserterManager; private CodeFormatAction _formatAction; /** * UnifiedEditor */ public UnifiedEditor() { super(); addPluginToPreferenceStore(UnifiedEditorsPlugin.getDefault()); this._saveListeners = new ArrayList<ISaveEvent>(); this._saveAsListeners = new ArrayList<ISaveAsEvent>(); // bracketMatcher = new UnifiedBracketMatcher(); /** * See UnifiedEditor.init for comments regarding the movement of object creation/abstract method calling from * this constructor to that method. */ } /** * @see org.eclipse.ui.texteditor.AbstractTextEditor#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput) */ public void init(IEditorSite site, IEditorInput input) throws PartInitException { /** * The following lines of code were moved from the default constructor to allow anonymous UnifiedEditors to be * created from the GenericTextEditor. This code was moved to this specific method since the calling of this * method signifies the beginning of the editors life-cycle and it called following the call to the constructor. * See comments for AbstractTextEditor.init for more details about the timing of this method call. */ this._baseContributor = createLocalContributor(); this._colorizer = UnifiedColorizer.getInstance(); setSourceViewerConfiguration(new UnifiedConfiguration(this, getPreferenceStore())); // Keeping in, as it may have side effects getFileServiceFactory(); this._prefStore = UnifiedEditorsPlugin.getDefault().getPreferenceStore(); this._prefStore = (this._prefStore == null) ? null : this._prefStore; // make compiler happy // TODO: Actuate change // setDocumentProvider(UnifiedDocumentProvider.getInstance()); setDocumentProvider(createDocumentProvider()); this._fileContextWrapper = new EditorFileContext(); // Update the base contributor with the file context this._baseContributor.setFileContext(this._fileContextWrapper); /** * This marks the end of the moved lines from the default UnifiedEditor constructor */ syncFoldingPreferenceStore(); super.init(site, input); setEditorContextMenuId(getSite().getId() + "#UnifiedEditorContext"); //$NON-NLS-1$ setRulerContextMenuId(getSite().getId() + "#UnifiedRulerContext"); //$NON-NLS-1$ IPreferenceStore localPreferenceStore = this.getPreferenceStore(); if (localPreferenceStore != null) { autoActivateCodeAssist = localPreferenceStore.getBoolean(IPreferenceConstants.CODE_ASSIST_AUTO_ACTIVATION); } IUnifiedEditorContributor[] contributors = this._baseContributor.getChildContributors(); // Process children for auto activate code assist if the parent is not // already requesting it if (contributors != null && !autoActivateCodeAssist) { for (int i = 0; i < contributors.length; i++) { autoActivateCodeAssist = autoActivateCodeAssist || contributors[i].isAutoActivateContentAssist(); // Once we find a language that wants it we just break and it // will be setup to listen if (autoActivateCodeAssist) { break; } } } } /** * This method circumvents that the line change ruler on AbstractDecoratedTextEditor is private. A placeholder pref * store is used to sync our colorization values with the Eclipse values that this ruler pulls from. */ private void syncFoldingPreferenceStore() { if (this._baseContributor != null) { String language = this._baseContributor.getLocalContentType(); LanguageColorizer colorizer = LanguageRegistry.getLanguageColorizer(language); if (colorizer != null && colorizer.getFoldingBg() != null) { this._runtimeStore.setDefault(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT, true); this._runtimeStore.setValue(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT, false); PreferenceConverter.setValue(this._runtimeStore, PREFERENCE_COLOR_BACKGROUND, colorizer.getFoldingBg() .getRGB()); } } } /** * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#rulerContextMenuAboutToShow(org.eclipse.jface.action.IMenuManager) */ protected void rulerContextMenuAboutToShow(IMenuManager menu) { menu.add(getAction(ADD_BOOKMARK)); menu.add(getAction(ADD_TASK)); menu.add(new Separator("source"));// TODO: add this constant //$NON-NLS-1$ menu.add(_formatAction); _formatAction.setActiveEditor(null, this); menu.add(new Separator()); super.rulerContextMenuAboutToShow(menu); FoldingExtensionPointLoader.fillRulerContextMenu(this, menu); } /** * @see org.eclipse.ui.texteditor.AbstractTextEditor#editorContextMenuAboutToShow(org.eclipse.jface.action.IMenuManager) */ protected void editorContextMenuAboutToShow(IMenuManager menu) { menu.add(new Separator("debug")); // TODO: find where this constant is defined //$NON-NLS-1$ super.editorContextMenuAboutToShow(menu); IUnifiedEditorContributor contributor = getBaseContributor(); if (contributor != null) { String mimeType = contributor.getLocalContentType(); if (mimeType != null && LanguageRegistry.getCodeFormatter(mimeType) != null) { menu.add(new Separator("source")); // TODO: add this constant //$NON-NLS-1$ menu.add(_formatAction); _formatAction.setActiveEditor(null, this); } OpenDeclarationAction openDelcaration = new OpenDeclarationAction(); openDelcaration.setActiveEditor(this, this.getFileContext().getLanguageService(mimeType)); menu.add(openDelcaration); } } /** * Adds the specified plugin to the list of plugin stores to check when searching for preference * * @param plugin * The plugin to add */ protected void addPluginToPreferenceStore(AbstractUIPlugin plugin) { setPreferenceStore(new ChainedPreferenceStore(new IPreferenceStore[] { this._runtimeStore, getPreferenceStore(), plugin.getPreferenceStore() })); } /** * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) */ public void createPartControl(Composite parent) { super.createPartControl(parent); ProjectionViewer viewer = (ProjectionViewer) getSourceViewer(); if (viewer.canDoOperation(ProjectionViewer.TOGGLE)) { viewer.doOperation(ProjectionViewer.TOGGLE); } // TODO refactor to new colorizer system this._maxColorizingColumns = getPreferenceStore().getInt(IPreferenceConstants.COLORIZER_MAXCOLUMNS); linkColorer(); linkPairMatcher(); // Keyword/variable highlight this._extendedStylesEnabled = getPreferenceStore().getBoolean( IPreferenceConstants.COLORIZER_TEXT_HIGHLIGHT_ENABLED); if (this._extendedStylesEnabled) { installTextOccurrenceHighlightSupport(); } // Overridden here, as this matches what JavaEditor does. Can be done at // any point after // text widget is created. LexemeUIHelp.setHelp(this, this.getViewer().getTextWidget(), getFileContext()); // Add support for custom colors for background, selection, line // highlight, and caret setEditorOptions(); } private void setEditorOptions() { // Check in case init hasn't been called yet or creating the contributor // failed if (getBaseContributor() == null || this.getViewer() == null || this.getViewer().getTextWidget() == null) { return; } String language = getBaseContributor().getLocalContentType(); LanguageColorizer colorizer = LanguageRegistry.getLanguageColorizer(language); if (colorizer != null && colorizer.getLineHighlightColor() != null && colorizer.getCaretColor() != null && colorizer.getBackground() != null && colorizer.getSelectionForeground() != null && colorizer.getSelectionBackground() != null) { if (this.getViewer() instanceof ITextViewerExtension2) { ITextViewerExtension2 highlightEditor = (ITextViewerExtension2) this.getViewer(); if (this.getViewer().getTextWidget() != null) { if (this._painter != null) { highlightEditor.removePainter(this._painter); } this._painter = new UnifiedCursorLinePainter(this, this.getViewer()); this._painter.setHighlightColor(colorizer.getLineHighlightColor()); highlightEditor.addPainter(this._painter); if (this._selectionListener != null) { this.getViewer().getTextWidget().removeSelectionListener(this._selectionListener); } if (this._focusListener != null) { this.getViewer().getTextWidget().removeFocusListener(this._focusListener); } if (this._textListener != null) { this.getViewer().removeTextListener(this._textListener); } this._selectionListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { StyledText text = getViewer().getTextWidget(); if (_painter != null && text != null && !text.isDisposed()) { Point p = text.getSelectionRange(); if (p.y == 0) { _painter.paintLines(0, text.getLineCount()); text.redraw(); text.update(); } } } }; this._focusListener = new FocusAdapter() { public void focusGained(FocusEvent e) { StyledText text = getViewer().getTextWidget(); if (_painter != null && text != null && !text.isDisposed()) { Point p = text.getSelectionRange(); if (p.y > 0) { _painter.paintLines(0, text.getLineCount()); } } } }; this._textListener = new ITextListener() { public void textChanged(TextEvent event) { StyledText text = getViewer().getTextWidget(); if (_painter != null && text != null && !text.isDisposed()) { Point p = text.getSelectionRange(); if (p.y > 0) { _painter.paintLines(0, text.getLineCount()); } } } }; this.getViewer().addTextListener(this._textListener); this.getViewer().getTextWidget().addFocusListener(this._focusListener); this.getViewer().getTextWidget().addSelectionListener(this._selectionListener); if (isWordWrapEnabled()) { this.getViewer().getTextWidget().setWordWrap(true); this.getViewer().getTextWidget().addControlListener(new ControlAdapter() { public void controlResized(ControlEvent e) { if (_projectionSupport != null) { UnifiedRulerColumn column = _projectionSupport.getRulerColumn(); if (column != null) { column.redraw(); } } IVerticalRuler ruler = getVerticalRuler(); if (ruler instanceof CompositeRuler) { Iterator columnIter = ((CompositeRuler) ruler).getDecoratorIterator(); while (columnIter.hasNext()) { Object column = columnIter.next(); if (column instanceof AnnotationRulerColumn) { ((AnnotationRulerColumn) column).redraw(); } } } if (fLineNumberRulerColumn != null) { fLineNumberRulerColumn.redraw(); } IOverviewRuler overviewRuler = getOverviewRuler(); if (overviewRuler != null) { overviewRuler.update(); } } }); } } } // Apply the folding background and forground colors setFoldingColors(colorizer); // Removing caret support on Carbon since it causes lag if (!Platform.getWS().equals(Platform.WS_CARBON)) { if (this.getViewer().getTextWidget() != null) { Caret caret = this.getViewer().getTextWidget().getCaret(); // Correct cursor color accordining to line highlight color RGB converted = new RGB(0, 0, 0); converted.red = Math.abs(colorizer.getCaretColor().getRed() - colorizer.getLineHighlightColor().getRed()); converted.blue = Math.abs(colorizer.getCaretColor().getBlue() - colorizer.getLineHighlightColor().getBlue()); converted.green = Math.abs(colorizer.getCaretColor().getGreen() - colorizer.getLineHighlightColor().getGreen()); PaletteData data = new PaletteData(new RGB[] { converted }); int x = caret.getSize().x; int y = caret.getSize().y; // Apparently the current caret may have invalid sizings // that will cause errors when an attempt to // change the color is made. So perform the check and catch // errors and exceptions so caret coloring // doesn't affect opening the editor. if (x > 0 && y > 0) { try { ImageData iData = new ImageData(x, y, 1, data); caret.setImage(null); if (this._caretImage != null) { this._caretImage.dispose(); this._caretImage = null; } this._caretImage = new Image(caret.getDisplay(), iData); caret.setImage(this._caretImage); } catch (Error e) { } catch (Exception e) { } } } } Color bg = colorizer.getBackground(); Color deadSpace = createDeadSpaceColor(bg); if (deadSpace != null && !deadSpace.isDisposed()) { this.getViewer().getTextWidget().setBackground(deadSpace); } else { this.getViewer().getTextWidget().setBackground(bg); } this.getViewer().getTextWidget().setSelectionBackground(colorizer.getSelectionBackground()); this.getViewer().getTextWidget().setSelectionForeground(colorizer.getSelectionForeground()); } else { IPreferenceStore store = EditorsPlugin.getDefault().getPreferenceStore(); RGB background = PreferenceConverter.getColor(store, AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND); RGB selectionFg = PreferenceConverter.getColor(store, AbstractTextEditor.PREFERENCE_COLOR_SELECTION_FOREGROUND); RGB selectionBg = PreferenceConverter.getColor(store, AbstractTextEditor.PREFERENCE_COLOR_SELECTION_BACKGROUND); Color eclipseBackgroundColor = UnifiedColorManager.getInstance().getColor(background); if (store.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) { eclipseBackgroundColor = null; } Color eclipseSelectionFgColor = UnifiedColorManager.getInstance().getColor(selectionFg); if (store.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_SELECTION_FOREGROUND_SYSTEM_DEFAULT)) { eclipseSelectionFgColor = null; } Color eclipseSelectionBgColor = UnifiedColorManager.getInstance().getColor(selectionBg); if (store.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_SELECTION_BACKGROUND_SYSTEM_DEFAULT)) { eclipseSelectionBgColor = null; } Color deadSpace = createDeadSpaceColor(eclipseBackgroundColor); if (deadSpace != null) { this.getViewer().getTextWidget().setBackground(deadSpace); } else { this.getViewer().getTextWidget().setBackground(eclipseBackgroundColor); } this.getViewer().getTextWidget().setSelectionBackground(eclipseSelectionBgColor); this.getViewer().getTextWidget().setSelectionForeground(eclipseSelectionFgColor); Caret caret = this.getViewer().getTextWidget().getCaret(); caret.setImage(null); if (this._caretImage != null) { this._caretImage.dispose(); this._caretImage = null; } if (this.getViewer() instanceof ITextViewerExtension2) { ITextViewerExtension2 highlightEditor = (ITextViewerExtension2) this.getViewer(); if (this._painter != null) { highlightEditor.removePainter(this._painter); } } } } /** * Apply the forground and the background colors of the folding markers and bar. * * @param colorizer */ protected void setFoldingColors(LanguageColorizer colorizer) { if (colorizer.getFoldingFg() != null) { SourceViewerConfiguration config = this.getSourceViewerConfiguration(); if (config instanceof UnifiedConfiguration) { UnifiedReconcilingStrategy strategy = ((UnifiedConfiguration) config).getStrategy(); if (strategy != null) { strategy.setFoldingAnnotationHoverColor(colorizer.getFoldingFg()); } } } if (colorizer.getFoldingBg() != null) { if (this._projectionSupport != null) { UnifiedRulerColumn column = this._projectionSupport.getRulerColumn(); if (column != null) { column.setBackground(colorizer.getFoldingBg()); } } if (fLineNumberRulerColumn != null && fLineNumberRulerColumn.getControl() != null && !fLineNumberRulerColumn.getControl().isDisposed()) { if (fLineNumberRulerColumn instanceof UnifiedLineNumberChangeRulerColumn) { ((UnifiedLineNumberChangeRulerColumn) fLineNumberRulerColumn).setTextWidget(getViewer() .getTextWidget()); ((UnifiedLineNumberChangeRulerColumn) fLineNumberRulerColumn).setSourceViewer(getViewer()); } fLineNumberRulerColumn.setBackground(colorizer.getFoldingBg()); fLineNumberRulerColumn.redraw(); } } } private boolean isWordWrapEnabled() { return UnifiedEditorsPlugin.getDefault().getPreferenceStore().getBoolean(IPreferenceConstants.ENABLE_WORD_WRAP); } /** * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createLineNumberRulerColumn() */ protected IVerticalRulerColumn createLineNumberRulerColumn() { if (isWordWrapEnabled()) { if (isPrefQuickDiffAlwaysOn()) { UnifiedLineNumberChangeRulerColumn column = new UnifiedLineNumberChangeRulerColumn(getSharedColors()); if (getViewer() != null) { column.setSourceViewer(getViewer()); column.setTextWidget(getViewer().getTextWidget()); } column.setHover(createChangeHover()); // initializeChangeRulerColumn(column); fLineNumberRulerColumn = column; } else { fLineNumberRulerColumn = new UnifiedLineNumberChangeRulerColumn(getSharedColors()); if (getViewer() != null) { ((UnifiedLineNumberChangeRulerColumn) fLineNumberRulerColumn).setSourceViewer(getViewer()); ((UnifiedLineNumberChangeRulerColumn) fLineNumberRulerColumn).setTextWidget(getViewer() .getTextWidget()); } } initializeLineNumberRulerColumn(fLineNumberRulerColumn); return fLineNumberRulerColumn; } else { return super.createLineNumberRulerColumn(); } } /** * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createOverviewRuler(org.eclipse.jface.text.source.ISharedTextColors) */ protected IOverviewRuler createOverviewRuler(ISharedTextColors sharedColors) { if (isWordWrapEnabled()) { IOverviewRuler ruler = new UnifiedOverviewRuler(getAnnotationAccess(), VERTICAL_RULER_WIDTH, sharedColors); Iterator e = EditorsPlugin.getDefault().getMarkerAnnotationPreferences().getAnnotationPreferences() .iterator(); while (e.hasNext()) { AnnotationPreference preference = (AnnotationPreference) e.next(); if (preference.contributesToHeader()) ruler.addHeaderAnnotationType(preference.getAnnotationType()); } return ruler; } else { return super.createOverviewRuler(sharedColors); } } private Color createDeadSpaceColor(Color bg) { if (bg != null) { int factor = 4; boolean canGoDarker = bg.getRed() - factor > 0 || bg.getGreen() - factor > 0 || bg.getBlue() - factor > 0; boolean canGoLighter = bg.getRed() + factor > 0 || bg.getGreen() + factor > 0 || bg.getBlue() + factor > 0; int red = 0; int green = 0; int blue = 0; if (canGoDarker) { red = bg.getRed() - factor > 0 ? (int) (bg.getRed() - factor) : bg.getRed(); green = bg.getGreen() - factor > 0 ? (int) (bg.getGreen() - factor) : bg.getGreen(); blue = bg.getBlue() - factor > 0 ? (int) (bg.getBlue() - factor) : bg.getBlue(); } else if (canGoLighter) { red = bg.getRed() + factor > 0 ? (int) (bg.getRed() + factor) : bg.getRed(); green = bg.getGreen() + factor > 0 ? (int) (bg.getGreen() + factor) : bg.getGreen(); blue = bg.getBlue() + factor > 0 ? (int) (bg.getBlue() + factor) : bg.getBlue(); } if (canGoDarker || canGoLighter) { Color deadSpace = UnifiedColorManager.getInstance().getColor(new RGB(red, green, blue)); return deadSpace; } } return null; } private void installTextOccurrenceHighlightSupport() { ISelectionProvider selectionProvider = getSelectionProvider(); if (selectionProvider instanceof IPostSelectionProvider) { IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider; provider.addPostSelectionChangedListener(this); } else { selectionProvider.addSelectionChangedListener(this); } this._extendedStylesEnabled = true; } private void uninstallTextOccurrenceHighlightSupport() { ISelectionProvider selectionProvider = getSelectionProvider(); if (selectionProvider != null) { if (selectionProvider instanceof IPostSelectionProvider) { IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider; provider.removePostSelectionChangedListener(this); } else { selectionProvider.removeSelectionChangedListener(this); } } removeMarkedOccurrences(); this._extendedStylesEnabled = false; } private IRange underLine; private Annotation[] fOccurrenceAnnotations; /** * removing given range from underlined state * * @param range */ void removeUnderlinedRange(IRange range) { underLine = range; StyledText textWidget = getViewer().getTextWidget(); try { textWidget.redrawRange(range.getStartingOffset(), range.getLength(), true); } catch (IllegalArgumentException e) { // Do nothing if the range being invalid causes an exception } } /** * @see com.aptana.ide.editors.unified.IRedrawRangeListener#redrawRange(com.aptana.ide.lexer.IRange) */ public void redrawRange(final IRange range) { if (range != null) { final StyledText textWidget = getViewer().getTextWidget(); Display display = textWidget.getDisplay(); display.asyncExec(new Runnable() { public void run() { try { textWidget.redrawRange(range.getStartingOffset(), range.getLength(), true); } catch (IllegalArgumentException e) { // Do nothing if the range being invalid causes an exception } } }); } } /** * sets current range to be underlined * * @param range */ void setUnderlinedRange(IRange range) { if (range != null) { underLine = null; StyledText textWidget = getViewer().getTextWidget(); try { textWidget.redrawRange(range.getStartingOffset(), range.getLength(), true); } catch (IllegalArgumentException e) { // Do nothing if the range being invalid causes an exception } } } private void linkColorer() { if (this._lineStyleListener == null) { this._lineStyleListener = new LineStyleListener() { /** * @see org.eclipse.swt.custom.LineStyleListener#lineGetStyle(org.eclipse.swt.custom.LineStyleEvent) */ public void lineGetStyle(LineStyleEvent e) { EditorFileContext fileContext = getFileContext(); // wrapper could be non-null, but interior is. if (fileContext == null || fileContext.getFileContext() == null) { return; } IParseState parseState = fileContext.getParseState(); if (parseState == null) { return; } LexemeList lexemeList = parseState.getLexemeList(); if (lexemeList == null) { IdeLog.logError(UnifiedEditorsPlugin.getDefault(), Messages.UnifiedEditor_LexemeListIsNull); return; } int orgOffset = e.lineOffset; int offset = orgOffset; int extra = 0; int lineLength = e.lineText.length(); // need to get actual offset values in the doc, // as widget offsets do not include potentially folded code if (_viewer instanceof ITextViewerExtension5) { ITextViewerExtension5 v5 = (ITextViewerExtension5) _viewer; offset = v5.widgetOffset2ModelOffset(e.lineOffset); extra = offset - e.lineOffset; } int maxLineLength = !isWordWrapEnabled() && lineLength > _maxColorizingColumns ? _maxColorizingColumns : lineLength; Lexeme[] lexemes = null; synchronized (lexemeList) { int startingIndex = lexemeList.getLexemeCeilingIndex(offset); int endingIndex = lexemeList.getLexemeFloorIndex(offset + maxLineLength); if (startingIndex == -1 && endingIndex != -1) { startingIndex = endingIndex; } if (endingIndex == -1 && startingIndex != -1) { endingIndex = startingIndex; } if (startingIndex != -1 && endingIndex != -1) { lexemes = lexemeList.cloneRange(startingIndex, endingIndex); } } if (lexemes != null) { Vector<StyleRange> styles = new Vector<StyleRange>(); _colorizer.createStyles(parseState, styles, lexemes, _extendedStylesEnabled); StyleRange[] styleResults = styles.toArray(new StyleRange[] {}); // move styles back to actual widget offsets in case of // folding if (extra > 0) { for (int i = 0; i < styleResults.length; i++) { StyleRange range = styleResults[i]; range.start -= extra; } } if (underLine != null) { for (int a = 0; a < styleResults.length; a++) { StyleRange styleRange = styleResults[a]; if (styleRange.start == underLine.getStartingOffset() && (styleRange.start + styleRange.length) == underLine.getEndingOffset()) { styleRange.underline = true; } } } else { for (int a = 0; a < styleResults.length; a++) { StyleRange styleRange = styleResults[a]; styleRange.underline = false; } } e.styles = styleResults; } UnifiedViewer rr = (UnifiedViewer) getViewer(); TextPresentation textPresentation = rr.getTextPresentation(); if (textPresentation != null) { TextPresentation ps = new TextPresentation(); if (e.styles != null) { ps.replaceStyleRanges(e.styles); } Iterator<?> nonDefaultStyleRangeIterator = textPresentation.getNonDefaultStyleRangeIterator(); while (nonDefaultStyleRangeIterator.hasNext()) { // Make sure that the StyleRange is at a visible location in case we have folded blocks in // the code. StyleRange clone = (StyleRange) ((StyleRange) nonDefaultStyleRangeIterator.next()).clone(); IRegion region = new Region(clone.start, clone.length); region = rr.modelRange2WidgetRange(region); if (region != null) { clone.start = region.getOffset(); clone.length = region.getLength(); ps.mergeStyleRange(clone); } } Iterator<?> nonDefaultStyleRangeIterator2 = ps.getNonDefaultStyleRangeIterator(); ArrayList<StyleRange> rs = new ArrayList<StyleRange>(); while (nonDefaultStyleRangeIterator2.hasNext()) { StyleRange next = (StyleRange) nonDefaultStyleRangeIterator2.next(); rs.add(next); } e.styles = rs.toArray(new StyleRange[rs.size()]); } } }; } // Repaint lines if the user is making changes if (this._textChangeListener == null) { this._textChangeListener = new TextChangeListener() { public void textChanging(TextChangingEvent event) { } public void textChanged(TextChangedEvent event) { StyledText text = getViewer().getTextWidget(); redrawFrom(text, text.getLineAtOffset(text.getCaretOffset())); } // Used with complex text change events (tabbing, replacement, // etc.) public void textSet(TextChangedEvent event) { StyledText text = getViewer().getTextWidget(); redrawFrom(text, 0); } private void redrawFrom(StyledText text, int lno) { if (lno < 0 || lno >= text.getLineCount()) { return; } int height = text.getClientArea().height; int width = text.getClientArea().width + text.getHorizontalPixel(); try { text.redraw(0, 0, width, height, true); } catch (Exception e) { // Catch errors in redraw as they may be intermittent // and the subsequent redraw will complete // successfully } } }; } getViewer().getTextWidget().addLineStyleListener(this._lineStyleListener); getViewer().getTextWidget().getContent().addTextChangeListener(this._textChangeListener); } private void linkPairMatcher() { if (this._pairMatcher == null) { this._pairMatcher = new PairMatcher(); StyledText text = getViewer().getTextWidget(); text.addPaintListener(this._pairMatcher); text.addKeyListener(this._pairMatcher); text.addTraverseListener(this._pairMatcher); text.addMouseListener(this._pairMatcher); text.addSelectionListener(this._pairMatcher); ScrollBar sb = text.getVerticalBar(); if (sb != null) { sb.addSelectionListener(this._pairMatcher); } } } private void unlinkPairMatcher() { if (this._pairMatcher != null) { if (getViewer() == null) { return; } StyledText text = getViewer().getTextWidget(); if (text == null || text.isDisposed() == true) { return; } text.removePaintListener(this._pairMatcher); text.removeKeyListener(this._pairMatcher); text.removeTraverseListener(this._pairMatcher); text.removeMouseListener(this._pairMatcher); text.removeSelectionListener(this._pairMatcher); ScrollBar sb = text.getVerticalBar(); if (sb != null) { sb.removeSelectionListener(this._pairMatcher); } } } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#getPairMatch(int) */ public PairMatch getPairMatch(int offset) { IParseState parseState = this.getFileContext().getParseState(); if (parseState == null) { return null; } LexemeList lexemeList = parseState.getLexemeList(); Lexeme cursorLexeme = lexemeList.getLexemeFromOffset(offset); if (cursorLexeme == null && offset > 0) { cursorLexeme = lexemeList.getLexemeFromOffset(offset - 1); } if (cursorLexeme == null) { return null; } String language = cursorLexeme.getLanguage(); IPairFinder finder = LanguageRegistry.getPairFinder(language); PairMatch match = null; if (finder != null && !finder.doNotDisplay()) { if (finder instanceof AbstractPairFinder) { // NOTE: [KEL] loop count relates to each pair finder // implementation and should not be passed in // as an argument int loopCount = 2; match = ((AbstractPairFinder) finder).findPairMatch(offset, parseState, cursorLexeme, loopCount); } else { match = finder.findPairMatch(offset, parseState); } } if (match != null) { match.setColor(finder.getPairFinderColor()); match.setDisplayOnlyMatch(finder.displayOnlyMatch()); match.offset = offset; if (match instanceof IPairMatchExt) { List<PairMatch> subsequentMatches = ((IPairMatchExt) match).getSubsequentMatches(); for (PairMatch subMatch : subsequentMatches) { subMatch.setColor(finder.getPairFinderColor()); subMatch.setDisplayOnlyMatch(finder.displayOnlyMatch()); subMatch.offset = offset; } } // NOTE: [KEL] The following is subjective and therefore should // become a preference. Turning off for now // since this breaks the case where the matched pair on the right // touches but the matcher pair to the left // does not. In that scenario, we show no matching when we should // show the pair to the left // // This check is for the case when the pair match will border // each other which present a cluttered UI // with // // the match and the cursor // if (match.beginEnd == match.endStart || match.endEnd == // match.beginStart) // { // match = null; // } } return match; } /** * findBalancingLexeme * * @param startIndex * @param language * @param startType * @param endType * @param direction * @return Lexeme */ protected Lexeme findBalancingLexeme(int startIndex, String language, int startType, int endType, int direction) { LexemeList lexemeList = this.getFileContext().getParseState().getLexemeList(); return findBalancingLexeme(lexemeList, startIndex, language, startType, endType, direction); } /** * @param lexemeList * @param startIndex * @param language * @param startType * @param endType * @param direction * @return Lexeme */ public static Lexeme findBalancingLexeme(LexemeList lexemeList, int startIndex, String language, int startType, int endType, int direction) { Lexeme result = null; int count = 0; while (0 <= startIndex && startIndex < lexemeList.size()) { result = lexemeList.get(startIndex); if (result.getLanguage().equals(language)) { if (result.typeIndex == endType) { count--; if (count == 0) { break; } } else if (result.typeIndex == startType) { count++; } } startIndex += direction; } if (count != 0) { result = null; } return result; } /** * @author Paul Colton */ class PairMatcher implements SelectionListener, MouseListener, KeyListener, PaintListener, TraverseListener { private PairMatch _currentPair; /** * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) */ public void mouseDoubleClick(MouseEvent e) { } /** * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) */ public void mouseDown(MouseEvent e) { stateChanged(); } /** * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) */ public void mouseUp(MouseEvent e) { } /** * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) */ public void keyPressed(KeyEvent e) { stateChanged(); } /** * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) */ public void keyReleased(KeyEvent e) { } /** * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent) */ public void paintControl(PaintEvent e) { stateChanged(); pairsDraw(e.gc, this._currentPair); } /** * @see org.eclipse.swt.events.TraverseListener#keyTraversed(org.eclipse.swt.events.TraverseEvent) */ public void keyTraversed(TraverseEvent e) { stateChanged(); } /** * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetSelected(SelectionEvent e) { stateChanged(); } /** * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetDefaultSelected(SelectionEvent e) { } void stateChanged() { StyledText text = getViewer().getTextWidget(); if (text != null) { int offset = text.getCaretOffset(); if (getViewer() instanceof ITextViewerExtension5) { int resolved = ((ITextViewerExtension5) getViewer()).widgetOffset2ModelOffset(offset); if (resolved > -1) { offset = resolved; } } PairMatch newmatch = getPairMatch(offset); if ((newmatch == null && this._currentPair != null) || (newmatch != null && !newmatch.equals(this._currentPair))) { pairsDraw(null, this._currentPair); pairsDraw(null, newmatch); } this._currentPair = newmatch; } } void pairsDraw(GC gc, PairMatch pm) { if (pm == null) { return; } pairsDrawSingle(gc, pm); if (pm instanceof IPairMatchExt) { List<PairMatch> subsequentMatches = ((IPairMatchExt) pm).getSubsequentMatches(); if (subsequentMatches != null && subsequentMatches.size() > 0) { for (PairMatch subsequentMatch : subsequentMatches) { pairsDrawSingle(gc, subsequentMatch); } } } } void pairsDrawSingle(GC gc, PairMatch pm) { if (pm == null) { return; } StyledText text = getViewer().getTextWidget(); if (text != null) { int cursor = text.getCaretOffset(); if (pm.displayOnlyMatch() && gc != null) { if (cursor >= pm.beginStart && cursor <= pm.beginEnd) { pairDraw(gc, pm.endStart, pm.endEnd, pm.getColor()); } else if (cursor >= pm.endStart && cursor <= pm.endEnd) { pairDraw(gc, pm.beginStart, pm.beginEnd, pm.getColor()); } } else { pairDraw(gc, pm.beginStart, pm.beginEnd, pm.getColor()); pairDraw(gc, pm.endStart, pm.endEnd, pm.getColor()); } } } void pairDraw(GC gc, int start, int end, Color color) { StyledText text = getViewer().getTextWidget(); if (getViewer() instanceof ITextViewerExtension5) { ITextViewerExtension5 v5 = (ITextViewerExtension5) getViewer(); start = v5.modelOffset2WidgetOffset(start); end = v5.modelOffset2WidgetOffset(end); } if (start < 0 || end < 0 || start > text.getCharCount() || end > text.getCharCount()) { return; } if (gc != null) { try { Point left = text.getLocationAtOffset(start); Point right = text.getLocationAtOffset(end); gc.setForeground(color); gc.setLineWidth(1); gc.drawRectangle(left.x + 1, left.y + 1, right.x - left.x - 2, gc.getFontMetrics().getHeight() - 2); } catch (Exception e) { IdeLog.logError(UnifiedEditorsPlugin.getDefault(), StringUtils.format( Messages.UnifiedEditor_PairDraw, e.getMessage())); } } else { text.redrawRange(start, end - start, true); } } } /** * getDefaultFileExtension * * @return String */ public abstract String getDefaultFileExtension(); /** * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent e) { // if (textColorer == null) // return; // // if (e == null || // e.getProperty().equals(ColorizerPreferencePage.USE_BACK) || // e.getProperty().equals(ColorizerPreferencePage.HRD_SET)) // { // textColorer.setRegionMapper( // prefStore.getString(ColorizerPreferencePage.HRD_SET), // prefStore.getBoolean(ColorizerPreferencePage.USE_BACK)); // } // if (e == null || // e.getProperty().equals(ColorizerPreferencePage.FULL_BACK)){ // textColorer.setFullBackground(prefStore.getBoolean(ColorizerPreferencePage.FULL_BACK)); // } // if (e == null || // e.getProperty().equals(ColorizerPreferencePage.HORZ_CROSS) || // e.getProperty().equals(ColorizerPreferencePage.VERT_CROSS)) // { // textColorer.setCross( // prefStore.getBoolean(ColorizerPreferencePage.HORZ_CROSS), // prefStore.getBoolean(ColorizerPreferencePage.VERT_CROSS)); // } // // if (e == null || // e.getProperty().equals(ColorizerPreferencePage.PAIRS_MATCH)) { // String pairs = // prefStore.getString(ColorizerPreferencePage.PAIRS_MATCH); // int pmode = TextColorer.HLS_XOR; // if (pairs.equals("PAIRS_OUTLINE")) // pmode = TextColorer.HLS_OUTLINE; // if (pairs.equals("PAIRS_OUTLINE2")) // pmode = TextColorer.HLS_OUTLINE2; // textColorer.setPairsPainter(!pairs.equals("PAIRS_NO"), pmode); // } // if (e == null || // e.getProperty().equals(ColorizerPreferencePage.TEXT_FONT)){ // Font textFont = // JFaceResources.getFont(ColorizerPreferencePage.TEXT_FONT); // getViewer().getTextWidget().setFont(textFont); // } } /** * Are we currently the active editor? * * @return boolean */ public boolean isActiveEditor() { IEditorPart part = getEditorSite().getPage().getActiveEditor(); if (part == null) { return false; } else if (part instanceof IUnifiedEditor) { IUnifiedEditor editor = (IUnifiedEditor) part; return editor.getEditor() == this; } else { return part == this; } } /** * onKeyPressed * * @param event */ private void onKeyPressed(VerifyEvent event) { char c = event.character; StyledText styledText = (StyledText) event.widget; int keyCode = event.keyCode; // when undoing a template, the caret is not reset at this point ITypedRegion reg = this._fileContextWrapper.getPartitionAtOffset(styledText.getCaretOffset()); if (reg == null) { return; } final String contentType = reg.getType(); IUnifiedEditorContributor contributor = this._baseContributor.findChildContributor(contentType); if (contributor != null && contributor.isAutoActivateContentAssist() && contributor.isValidIdentifier(c, keyCode) && isLeftCharacterWhitespace(contributor, styledText, c, keyCode)) { getViewer().getTextWidget().setData(IContentAssistConstants.ASSIST_FORCE_ACTIVATION, true); showContentAssist(); } } /** * isLeftCharacterWhitespace * * @param styledText * @param c * @param keyCode * @return boolean */ private boolean isLeftCharacterWhitespace(IUnifiedEditorContributor contributor, StyledText styledText, char c, int keyCode) { int offset = styledText.getCaretOffset(); // Are we at beginning of file? if (offset == 0) { return true; } String line = styledText.getText(offset - 1, offset - 1); if (line.length() > 0) { return contributor.isValidActivationCharacter(line.charAt(0), keyCode); } else { return false; } } /** * showContentAssist */ private void showContentAssist() { final IWorkbench workbench = PlatformUI.getWorkbench(); final Display display = workbench.getDisplay(); display.asyncExec(new Runnable() { public void run() { try { final SourceViewer sv = (SourceViewer) getSourceViewer(); if (sv == null) { return; // guard against already closed editor } // In case you switched away Control c = display.getFocusControl(); if (c == null || c != sv.getTextWidget()) { return; } // Check if source viewer is able to perform operation if (sv.canDoOperation(SourceViewer.CONTENTASSIST_PROPOSALS)) { // Perform operation sv.doOperation(SourceViewer.CONTENTASSIST_PROPOSALS); } } catch (Exception e) { IdeLog.logError(UnifiedEditorsPlugin.getDefault(), Messages.UnifiedEditor_ErrorContentProposals, e); } } }); } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#showWhitespace(boolean) */ public void showWhitespace(boolean state) { ISourceViewer fSourceViewer = this.getSourceViewer(); if (state) { if (this._whitespacePainter == null) { if (fSourceViewer instanceof ITextViewerExtension2) { this._whitespacePainter = new WhitespaceCharacterPainter(fSourceViewer); ITextViewerExtension2 extension = (ITextViewerExtension2) fSourceViewer; extension.addPainter(this._whitespacePainter); } } } else { if (this._whitespacePainter != null) { if (fSourceViewer instanceof ITextViewerExtension2) { ITextViewerExtension2 extension = (ITextViewerExtension2) fSourceViewer; extension.removePainter(this._whitespacePainter); this._whitespacePainter.deactivate(true); this._whitespacePainter.dispose(); this._whitespacePainter = null; // this.getFileContext().removeLongDelayedFileListener(fWhitespacePainter); } } } } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#showPianoKeys(boolean) */ public void showPianoKeys(boolean state) { if (this._painter != null) { StyledText text = getViewer().getTextWidget(); this._painter.paintLines(0, text.getLineCount()); } } /** * Updates the folding structure * * @param annotations */ public void updateFoldingStructure(Map annotations) { List<Annotation> deletions = new ArrayList<Annotation>(); Collection additions = annotations.values(); ProjectionAnnotationModel currentModel = getProjectionAnnotationModel(); if (currentModel == null) { return; } for (Iterator iter = currentModel.getAnnotationIterator(); iter.hasNext();) { Object annotation = iter.next(); if (annotation instanceof ProjectionAnnotation) { Position position = currentModel.getPosition((Annotation) annotation); if (additions.contains(position)) { additions.remove(position); } else { deletions.add((Annotation) annotation); } } } if (annotations.size() != 0 || deletions.size() != 0) { currentModel.modifyAnnotations(deletions.toArray(new Annotation[deletions.size()]), annotations, null); } } /** * @see org.eclipse.ui.texteditor.AbstractTextEditor#createSourceViewer(org.eclipse.swt.widgets.Composite, * org.eclipse.jface.text.source.IVerticalRuler, int) */ protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) { // **** NOTE **** // we are not using Projection Viewer in order to get shift left working // (to shift until no // whitespace) // if this is problematic or 3.2 exposes that in a more intelligent way // (or fixes that // issue) // we can get rid of UnifiedViewer, and revert this one line of code // here (move back to // using // projectionViewer). // ISourceViewer viewer = new ProjectionViewer(parent, ruler, // getOverviewRuler(), // isOverviewRulerVisible(), // styles); this._viewer = new UnifiedViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles); // ensure decoration support has been created and configured. getSourceViewerDecorationSupport(this._viewer); this._projectionSupport = new UnifiedProjectionSupport(this._viewer, getAnnotationAccess(), getSharedColors()); this._projectionSupport.install(); SourceViewer sv = this._viewer; Display d = this.getSite().getShell().getDisplay(); this._keyUpListener = new Listener() { public void handleEvent(Event e) { UnifiedEditor.ctrlDown = false; } }; d.addFilter(SWT.KeyUp, this._keyUpListener); this._verifyKeyListener = new VerifyKeyListener() { public void verifyKey(VerifyEvent event) { _hasKeyBeenPressed = true; onKeyPressed(event); // Check for Ctrl // note: state mask doesn't work for some reason if (event.keyCode == SWT.CTRL) { UnifiedEditor.ctrlDown = true; } else { UnifiedEditor.ctrlDown = false; } } }; sv.prependVerifyKeyListener(this._verifyKeyListener); SourceViewerConfiguration svc = this.getSourceViewerConfiguration(); if (svc instanceof UnifiedConfiguration) { UnifiedConfiguration uc = (UnifiedConfiguration) svc; this._bracketInserterManager = uc.getBracketInserterManager(sv); sv.prependVerifyKeyListener(this._bracketInserterManager); } return this._viewer; } // private IPreferenceStore fPreferenceStore; /** * @see org.eclipse.ui.texteditor.AbstractTextEditor#doSetInput(org.eclipse.ui.IEditorInput) */ protected void doSetInput(IEditorInput input) throws CoreException { // After Save As, we are getting a new IEditorInput each time // implicitly enters it into the hash of the document provider, using // input as the key super.doSetInput(input); try { // Get the document provider (which is a singleton) IDocumentProvider dp = getDocumentProvider(); if (dp == null) { throw new Exception(Messages.UnifiedEditor_DocumentProviderNull); } // Get document from input IDocument document = dp.getDocument(input); // TODO: Actuate change // UnifiedFileInfo cuInfo = (UnifiedFileInfo) // dp.getFileInfoPublic(input); // // if (cuInfo == null) // { // throw new Exception(Messages.UnifiedEditor_CuInfoIsNull); // } DocumentSourceProvider provider = new DocumentSourceProvider(document, input); if (provider == null) { throw new Exception(Messages.UnifiedEditor_ProviderIsNull); } // TODO: Actuate change // boolean isNewInput = (cuInfo.sourceProvider == null || // cuInfo.sourceProvider.equals(provider) == false); boolean isNewInput = isNewInput(input); // update various stuffs and more :-) // TODO: Actuate changes // updateFileInfo(input, provider, cuInfo, document, isNewInput); updateFileInfo(input, provider, document); // Commented out for now, as this code now lives in // UnifiedDocumentProvider // updateAnnotationModel(cuInfo); // TODO: Actuate changes // updatePartitioner(provider, cuInfo, document, isNewInput); updatePartitioner(provider, document, isNewInput); // Set the actual file context onto the wrapper this._fileContextWrapper.setFileContext(FileContextManager.get(provider.getSourceURI())); // Set up error listeners based on the the input file type setErrorListeners(input); fireNewFileServiceEvent(); // Refresh colorization if (this.getViewer() != null && this.getViewer().getTextWidget() != null) { this.getViewer().getTextWidget().redraw(); this.getViewer().getTextWidget().update(); } } catch (Exception e) { IdeLog.logError(UnifiedEditorsPlugin.getDefault(), "Unable to set input in UnifiedEditor: " //$NON-NLS-1$ + e.getMessage(), e); IStatus status = new Status(IStatus.ERROR, UnifiedEditorsPlugin.ID, IStatus.OK, "Unable to set input in Unified Editor", e);//$NON-NLS-1$ throw new CoreException(status); } } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#addFileServiceChangeListener(com.aptana.ide.editors.unified.IFileServiceChangeListener) */ public void addFileServiceChangeListener(IFileServiceChangeListener listener) { fileServiceChangeListeners.add(listener); } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#removeFileServiceChangeListener(com.aptana.ide.editors.unified.IFileServiceChangeListener) */ public void removeFileServiceChangeListener(IFileServiceChangeListener listener) { fileServiceChangeListeners.remove(listener); } /** * Updates the file service listeners with the new service */ private void fireNewFileServiceEvent() { if (this._fileContextWrapper != null && this._fileContextWrapper.getFileContext() != null) { final IFileService newService = this._fileContextWrapper.getFileContext(); // Notify file service listeners Object[] listeners = fileServiceChangeListeners.getListeners(); for (int i = 0; i < listeners.length; ++i) { final IFileServiceChangeListener l = (IFileServiceChangeListener) listeners[i]; SafeRunnable.run(new SafeRunnable() { public void run() { l.fileServiceChanged(newService); } }); } } } private void setErrorListeners(IEditorInput input) { // Project file if (input instanceof IFileEditorInput) { IFileEditorInput fileInput = (IFileEditorInput) input; IFile file = fileInput.getFile(); this._errorListener = new ProjectFileErrorListener(file); } // External file or Untitled file (not saved) else if (input instanceof IPathEditorInput || input instanceof IURIEditorInput || input instanceof NonExistingFileEditorInput) { IDocument doc = this.getDocumentProvider().getDocument(input); IAnnotationModel ann = this.getDocumentProvider().getAnnotationModel(input); this._errorListener = new ExternalFileErrorListener(ann, doc); } if (this._errorListener != null) { getFileContext().addErrorListener(this._errorListener); } } /** * updateFileInfo * * @param input * @param provider * @param document */ protected void updateFileInfo(IEditorInput input, DocumentSourceProvider provider, IDocument document) { if (isNewInput(input)) { // TODO: Actuate change // save reference to provider // cuInfo.sourceProvider = provider; IFileServiceFactory fileServiceFactory = this.getFileServiceFactory(); if (fileServiceFactory != null) { FileService context = fileServiceFactory.createFileService(provider, false); FileContextManager.add(provider.getSourceURI(), context); context.setRedrawRangeListener(this); } FileContextManager.connectSourceProvider(provider.getSourceURI(), provider); } } // private void updateAnnotationModel(UnifiedFileInfo cuInfo) // { // // Provide a simple annotation model if none has been provided // // fixes bug 156 - line numbers are not displayed for external files // // PC: not needed? cuInfo.fModel = new AnnotationModel(); // // if (cuInfo.fTextFileBuffer.getAnnotationModel() == null) // { // // when editing external files, there will not be an annotation model // attached, so we // // attach a simple one. // // This is necessary so that the source viewer's annotation bar (which // displays line // // numbers, etc) will be displayed // IUniformResource uniformResource = null; // // if (cuInfo.fElement instanceof IAdaptable) // { // uniformResource = (IUniformResource) ((IAdaptable) // cuInfo.fElement).getAdapter(IUniformResource.class); // } // // if (uniformResource != null) // { // cuInfo.fModel = new // UniformResourceMarkerAnnotationModel(uniformResource); // } // else // { // cuInfo.fModel = new AnnotationModel(); // } // } // else // { // cuInfo.fModel = cuInfo.fTextFileBuffer.getAnnotationModel(); // } // } private void updatePartitioner(DocumentSourceProvider provider, IDocument document, boolean isNewInput) { if (isNewInput) { UnifiedDocumentPartitioner partitioner = new UnifiedDocumentPartitioner(provider.getSourceURI()); // NOTE: The content types (and other stuff) will change when a user // does a Save As to another file type (i.e. JS to HTML) partitioner.setLegalContentTypes(this._baseContributor.getContentTypes()); partitioner.setPartitions(); if (document instanceof IDocumentExtension3) { // this should always be the once called ((IDocumentExtension3) document).setDocumentPartitioner(UnifiedConfiguration.UNIFIED_PARTITIONING, partitioner); } else { // document.setDocumentPartitioner(partitioner); throw new IllegalStateException(Messages.UnifiedEditor_DocumentMustBe); } } } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#getFileContext() */ public EditorFileContext getFileContext() { return this._fileContextWrapper; } /** * createLocalContributor * * @return IUnifiedEditorContributor */ protected abstract IUnifiedEditorContributor createLocalContributor(); /** * @see org.eclipse.ui.IWorkbenchPart#dispose() */ public void dispose() { if (this._isDisposing) { return; } this._isDisposing = true; if (this._lineStyleListener != null) { if (getViewer().getTextWidget() != null && getViewer().getTextWidget().isDisposed() == false) { getViewer().getTextWidget().removeLineStyleListener(this._lineStyleListener); } } if (this._textChangeListener != null) { if (getViewer().getTextWidget() != null && getViewer().getTextWidget().isDisposed() == false) { getViewer().getTextWidget().getContent().removeTextChangeListener(this._textChangeListener); } } unlinkPairMatcher(); if (this._errorListener != null) { getFileContext().removeErrorListener(this._errorListener); } if (this._partListener != null) { this.getEditorSite().getPage().removePartListener(this._partListener); this._partListener = null; } if (this._keyUpListener != null) { Display d = this.getSite().getShell().getDisplay(); d.removeFilter(SWT.KeyUp, this._keyUpListener); this._keyUpListener = null; } if (_verifyKeyListener != null) { ((SourceViewer) this._viewer).removeVerifyKeyListener(this._verifyKeyListener); this._verifyKeyListener = null; } if (this._bracketInserterManager != null) { ((SourceViewer) this._viewer).removeVerifyKeyListener(this._bracketInserterManager); this._bracketInserterManager = null; } SourceViewerConfiguration svc = this.getConfiguration(); if (svc instanceof UnifiedConfiguration) { ((UnifiedConfiguration) svc).dispose(); } if (outlinePage != null) { outlinePage.dispose(); outlinePage = null; } showWhitespace(false); if (this._whitespacePainter != null) { this._whitespacePainter.dispose(); } this._saveListeners.clear(); this._saveAsListeners.clear(); this._lineStyleListener = null; outlinePage = null; if (this._baseContributor != null) { this._baseContributor.setParentConfiguration(null); this._baseContributor = null; } this._errorListener = null; this._whitespacePainter = null; this._fileExplorerView = null; this._prefStore = null; this._contextAwareness = null; this.disposeDocumentProvider(); if (this._fileContextWrapper != null) { this._fileContextWrapper.deactivateForEditing(); // The following was commented out since: // it disconnects regardless if another file is using the file // context (two editors around same document) // Looking at this.disposeDocumentProvider() shows the proper checks // before disconnecting and so the // following line was redundant as well since the document provider // handles it correctly and so calling it // here will just ruin any other open editors using the file context // being disposed // fileContextWrapper.disconnectSourceProvider(null); } if (this._extendedStylesEnabled) { uninstallTextOccurrenceHighlightSupport(); } if (this._caretImage != null) { this._caretImage.dispose(); this._caretImage = null; } super.dispose(); } /** * getFileServiceFactory * * @return IFileServiceFactory */ public abstract IFileServiceFactory getFileServiceFactory(); /** * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) */ public Object getAdapter(Class adapter) { // Context is just plugin ID + name of class. Matches contexts.xml file if (adapter == IContextProvider.class) { return LexemeUIHelp.getHelpContextProvider(this, getFileContext()); } // Return our adapter for the content outline page if (IContentOutlinePage.class.equals(adapter)) { return getOutlinePage(); } return super.getAdapter(adapter); } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#getViewer() */ public ISourceViewer getViewer() { return this.getSourceViewer(); } /** * // exposing this as public for scripting access * * @see com.aptana.ide.editors.unified.IUnifiedEditor#getConfiguration() */ public SourceViewerConfiguration getConfiguration() { return this.getSourceViewerConfiguration(); } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#getContextAwareness() */ public IContextAwareness getContextAwareness() { // For editors that don't have/need a ContextAwareness service if (this._contextAwareness == null) { this._contextAwareness = new IContextAwareness() { public void update(IFileService fileService) { } public ContextItem getFileContext() { return new ContextItem(); } }; } return this._contextAwareness; } /** * Returns the content outline page adapter * * @return Returns the content outline page adapter. */ public UnifiedOutlinePage getOutlinePage() { if (this.outlinePage == null || (this.outlinePage.getControl() != null && this.outlinePage.getControl().isDisposed())) { this.outlinePage = new UnifiedOutlinePage(this); } return outlinePage; } /** * {@inheritDoc} */ public UnifiedQuickOutlinePage createQuickOutlinePage() { return new UnifiedQuickOutlinePage(this); } /** * @see org.eclipse.ui.texteditor.AbstractTextEditor#handlePreferenceStoreChanged(org.eclipse.jface.util.PropertyChangeEvent) */ protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { try { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) { return; } String property = event.getProperty(); if (IPreferenceConstants.COLORIZER_MAXCOLUMNS.equals(property)) { this._maxColorizingColumns = getPreferenceStore().getInt(IPreferenceConstants.COLORIZER_MAXCOLUMNS); } else if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH.equals(property) || IPreferenceConstants.INSERT_SPACES_FOR_TABS.equals(property)) { IPreferenceStore store = getPreferenceStore(); if (store == null) { throw new Exception(Messages.UnifiedEditor_UnableToRetrievePreferenceStore); } int prefs = store.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); SourceViewerConfiguration sv = getSourceViewerConfiguration(); boolean tabsOrSpaces = store.getBoolean(IPreferenceConstants.INSERT_SPACES_FOR_TABS); if (sv != null && sv instanceof UnifiedConfiguration) { UnifiedConfiguration uc = (UnifiedConfiguration) sv; uc.setTabWidth(prefs, tabsOrSpaces, sourceViewer); } else { IdeLog.logInfo(UnifiedEditorsPlugin.getDefault(), Messages.UnifiedEditor_ErrorUpdateTabWidth); } } else if (IPreferenceConstants.COLORIZER_TEXT_HIGHLIGHT_ENABLED.equals(property)) { boolean textHighlightEnabled = getPreferenceStore().getBoolean( IPreferenceConstants.COLORIZER_TEXT_HIGHLIGHT_ENABLED); if (textHighlightEnabled) { installTextOccurrenceHighlightSupport(); } else { uninstallTextOccurrenceHighlightSupport(); // remove highlights } } else if (property != null && property.startsWith(IPreferenceConstants.EDITOR_FOLDING_ENABLED)) { String language = property.substring(IPreferenceConstants.EDITOR_FOLDING_ENABLED.length() + 1, property .length()); if (this.getViewer() != null && this.getViewer() instanceof ProjectionViewer) { ProjectionViewer viewer = (ProjectionViewer) this.getViewer(); if (UnifiedEditorsPlugin.getDefault().getPreferenceStore().getBoolean(property)) { if (this.getConfiguration() instanceof UnifiedConfiguration) { UnifiedReconcilingStrategy reconciler = ((UnifiedConfiguration) this.getConfiguration()) .getStrategy(); if (reconciler != null) { reconciler.initialReconcile(); } } } else if (viewer.getProjectionAnnotationModel() != null) { List<Annotation> mods = new ArrayList<Annotation>(); Iterator annotationIterator = viewer.getProjectionAnnotationModel().getAnnotationIterator(); if (annotationIterator != null) { while (annotationIterator.hasNext()) { Annotation annotation = (Annotation) annotationIterator.next(); if (annotation instanceof LanguageProjectAnnotation) { LanguageProjectAnnotation lpa = (LanguageProjectAnnotation) annotation; if (language.equals(lpa.getLanguage())) { lpa.markDeleted(true); mods.add(lpa); } } } viewer.getProjectionAnnotationModel().modifyAnnotations( mods.toArray(new Annotation[mods.size()]), null, null); } } } } // This updates the folding icons when the colorization changes else if (property != null && property.startsWith("Colorization")) //$NON-NLS-1$ { syncFoldingPreferenceStore(); if (this.getConfiguration() instanceof UnifiedConfiguration) { UnifiedReconcilingStrategy reconciler = ((UnifiedConfiguration) this.getConfiguration()) .getStrategy(); ProjectionAnnotationModel currentModel = getProjectionAnnotationModel(); if (reconciler != null && currentModel != null) { currentModel.removeAllAnnotations(); reconciler.initialReconcile(); } } } // boolean wordWrap = // getPreferenceStore().getBoolean(IPreferenceConstants.ENABLE_WORD_WRAP); // this.getViewer().getTextWidget().setWordWrap(wordWrap); // this can be null (? either when closing or when sourceViewer is // UndefinedViewer) StyledText viewer = sourceViewer.getTextWidget(); if (viewer != null) { sourceViewer.getTextWidget().redraw(); } } catch (Exception ex) { IdeLog .logError(UnifiedEditorsPlugin.getDefault(), Messages.UnifiedEditor_ErrorHandlingPreferenceChange, ex); } finally { super.handlePreferenceStoreChanged(event); // Editor options must be changed after super is called so that the // Eclipse editor prefs don't affect the // Aptana color prefs if the Eclipse prefs are overriden by the // language editor // Refresh editor options in case changed // Always run in UI thread! Display display = Display.getCurrent(); if (display == null) display = Display.getDefault(); display.asyncExec(new Runnable() { public void run() { setEditorOptions(); } }); } } /** * Gets the projection annotation model ( folding annotations stored here) * * @return - model or null if the viewer or model is null */ private ProjectionAnnotationModel getProjectionAnnotationModel() { ProjectionViewer viewer = (ProjectionViewer) getSourceViewer(); if (viewer != null) { return viewer.getProjectionAnnotationModel(); } return null; } /** * @see org.eclipse.ui.texteditor.AbstractTextEditor#handleCursorPositionChanged() */ protected void handleCursorPositionChanged() { // update current lexeme and index based on new cursor position StyledText styledText = getSourceViewer().getTextWidget(); int offset = styledText.getCaretOffset(); try { if (getSourceViewer() instanceof ITextViewerExtension5) { offset = ((ITextViewerExtension5) getSourceViewer()).widgetOffset2ModelOffset(offset); } } catch (Exception e) { // If can't convert offset then use caret offset uncoverted } catch (Error e) { // If can't convert offset then use caret offset uncoverted } IFileService fs = this.getFileContext(); if (fs != null) { // RD: must always account for whitespace in lexemelist LexemeList list = fs.getLexemeList(); if (list == null) { return; } int index = list.getLexemeFloorIndex(offset); if (index == -1) { index = list.getLexemeCeilingIndex(offset); if (index == -1) { return; } } Lexeme l = list.get(index); if (l != null) { IFileLanguageService ls = fs.getLanguageService(l.getLanguage()); if (ls != null && ls.getOffsetMapper() != null) { ls.getOffsetMapper().calculateCurrentLexeme(offset); } } } super.handleCursorPositionChanged(); } /** * Retrieves the current IEditorPart * * @return The current EditorPart */ public IEditorPart getEditor() { return this; } /** * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#initializeKeyBindingScopes() */ protected void initializeKeyBindingScopes() { setKeyBindingScopes(new String[] { "com.aptana.ide.editors.UnifiedEditorsScope" }); //$NON-NLS-1$ } /** * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#configureSourceViewerDecorationSupport(org.eclipse.ui.texteditor.SourceViewerDecorationSupport) */ protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) { // support.setCharacterPairMatcher(bracketMatcher); // support.setMatchingCharacterPainterPreferenceKeys("matchBrackets", // "matchBracketsColor"); super.configureSourceViewerDecorationSupport(support); } // public void addBracketMatchListener(IUnifiedBracketMatcherListener obj) // { // bracketMatcher.addBracketMatchListener(obj); // } // // public void removeBracketMatchListener(IUnifiedBracketMatcherListener // obj) // { // bracketMatcher.removeBracketMatchListener(obj); // } /** * */ protected void onSaveComplete() { ISaveEvent[] listeners = null; synchronized (this._saveListeners) { listeners = this._saveListeners.toArray(new ISaveEvent[this._saveListeners.size()]); } for (int i = 0; i < listeners.length; i++) { ISaveEvent element = listeners[i]; element.onSave(this.getEditor()); } } /** * @see com.aptana.ide.editors.untitled.BaseTextEditor#onSaveAsComplete(java.io.File, java.io.File) */ protected void onSaveAsComplete(File oldFile, File newFile) { ISaveAsEvent[] listeners = null; synchronized (this._saveAsListeners) { listeners = this._saveAsListeners.toArray(new ISaveAsEvent[this._saveAsListeners.size()]); } for (int i = 0; i < listeners.length; i++) { ISaveAsEvent element = listeners[i]; element.onSaveAs(this.getEditor(), oldFile, newFile); } updateFileExplorer(); } private void updateFileExplorer() { if (this._fileExplorerView == null) { this._fileExplorerView = (CommonNavigator) CoreUIUtils.getViewInternal( "com.aptana.ide.ui.io.fileExplorerView", null); //$NON-NLS-1$ } if (this._fileExplorerView == null) { return; } Display.getDefault().asyncExec(new Runnable() { public void run() { _fileExplorerView.getCommonViewer().refresh(); } }); } /** * @param listener */ public void addSaveListener(ISaveEvent listener) { this._saveListeners.add(listener); } /** * @param listener */ public void removeSaveListener(ISaveEvent listener) { if (this._saveListeners.contains(listener)) { this._saveListeners.remove(listener); } } /** * @param listener */ public void addSaveAsListener(ISaveAsEvent listener) { this._saveAsListeners.add(listener); } /** * @param listener */ public void removeSaveAsListener(ISaveAsEvent listener) { if (this._saveAsListeners.contains(listener)) { this._saveAsListeners.remove(listener); } } void showPairError() { MessageDialog.openInformation(null, Messages.UnifiedEditor_MatchingPairError, Messages.UnifiedEditor_MatchingPairErrorMessage); } /** * isHasKeyBeenPressed * * @return boolean */ public boolean isHasKeyBeenPressed() { return this._hasKeyBeenPressed; } /** * setHasKeyBeenPressed * * @param hasKeyBeenPressed */ public void setHasKeyBeenPressed(boolean hasKeyBeenPressed) { this._hasKeyBeenPressed = hasKeyBeenPressed; } /** * @see org.eclipse.ui.editors.text.TextEditor#createActions() */ protected void createActions() { super.createActions(); // Add bookmark action final BookmarkRulerAction bra = new BookmarkRulerAction(); Action bookmarkAction = new Action() { public void run() { bra.run(this); } }; bra.setActiveEditor(bookmarkAction, this); setAction(ADD_BOOKMARK, bookmarkAction); // Add task action final TaskRulerAction tra = new TaskRulerAction(); Action taskAction = new Action() { public void run() { tra.run(this); } }; tra.setActiveEditor(taskAction, this); setAction(ADD_TASK, taskAction); Action action = new ContentAssistAction(UnifiedMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$ String id = ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS; action.setActionDefinitionId(id); setAction("ContentAssistProposal", action); //$NON-NLS-1$ markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$ action = new GotoMatchingBracketAction(this); action.setActionDefinitionId(UnifiedActionContributor.GOTO_MATCHING_BRACKET_ID); setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action); Action actionContext = new TextOperationAction(UnifiedMessages.getResourceBundle(), "ContentAssistContextInformation.", this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); //$NON-NLS-1$ actionContext.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION); setAction("ContentAssistContextInformation", actionContext); //$NON-NLS-1$ markAsStateDependentAction("ContentAssistContextInformation", true); //$NON-NLS-1$ // PlatformUI.getWorkbench().getHelpSystem().setHelp(action, // IJavaHelpContextIds.PARAMETER_HINTS_ACTION); FoldingExtensionPointLoader.createFoldingActions(this); _formatAction = new CodeFormatAction(); } /** * @see com.aptana.ide.editors.unified.IUnifiedEditor#getBaseContributor() */ public IUnifiedEditorContributor getBaseContributor() { return this._baseContributor; } /** * isNewInput * * @param input * @return boolean */ protected boolean isNewInput(IEditorInput input) { return true; } /** * @param event */ public void selectionChanged(SelectionChangedEvent event) { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) { return; } StyledText styledText = sourceViewer.getTextWidget(); if (styledText == null) { return; } int offset = -1; // If there is a selection, we consider selection range instead of caret // position. Point selectionRange = sourceViewer.getSelectedRange(); if (selectionRange.x > -1 && selectionRange.y > 0) { offset = selectionRange.x; } if (offset < 0) { if (sourceViewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer; offset = extension.widgetOffset2ModelOffset(styledText.getCaretOffset()); } else { offset = sourceViewer.getVisibleRegion().getOffset(); offset += styledText.getCaretOffset(); } } if (offset < 0) { return; } LexemeList lexemeList = getLexemeList(); if (lexemeList == null) { IdeLog.logError(UnifiedEditorsPlugin.getDefault(), Messages.UnifiedEditor_LexemeListIsNull); return; } Lexeme selectedLexeme = lexemeList.getLexemeFromOffset(offset); if (selectedLexeme == null) { return; } if (!canMarkOccurrences(selectedLexeme)) { return; } String selectedText = selectedLexeme.getText(); if (selectedText == null || selectedText.length() == 0) { return; } markOccurences(lexemeList, selectedLexeme); Job job = new UIJob("Redraw") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { // TODO: Measure time to see if a precisely calculated redraw area yields significant savings getSourceViewer().getTextWidget().redraw(); return Status.OK_STATUS; } }; job.setPriority(Job.INTERACTIVE); job.setSystem(true); job.schedule(); } /** * Mark matching lexemes in the lexeme list * * @param lexemeList * @param selectedLexeme */ protected void markOccurences(LexemeList lexemeList, Lexeme selectedLexeme) { String selectedText = selectedLexeme.getText(); IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput()); Map<Annotation, Position> toAdd = new HashMap<Annotation, Position>(); for (int i = 0; i < lexemeList.size(); i++) { Lexeme lexeme = lexemeList.get(i); if (lexeme != null) { if (lexeme.isHighlighted()) { lexeme.setHighlighted(false); } if (lexeme.length == selectedLexeme.length && selectedText.equals(lexeme.getText())) { lexeme.setHighlighted(true); if (model != null) { Position pos = new Position(lexeme.offset, lexeme.length); Annotation occurence = new Annotation("com.aptana.ide.annotation.occurence", false, lexeme //$NON-NLS-1$ .getText()); toAdd.put(occurence, pos); } } } } synchronized (getLockObject(model)) { if (model instanceof IAnnotationModelExtension) { ((IAnnotationModelExtension)model).replaceAnnotations(fOccurrenceAnnotations, toAdd); } else { removeOccurrenceAnnotations(); Iterator iter= toAdd.entrySet().iterator(); while (iter.hasNext()) { Map.Entry mapEntry= (Map.Entry)iter.next(); model.addAnnotation((Annotation)mapEntry.getKey(), (Position)mapEntry.getValue()); } } fOccurrenceAnnotations= (Annotation[])toAdd.keySet().toArray(new Annotation[toAdd.keySet().size()]); } } /** * Gets the lexeme list for this editor * * @return - lexeme list */ protected LexemeList getLexemeList() { EditorFileContext fileContext = getFileContext(); // wrapper could be non-null, but interior is. if (fileContext == null || fileContext.getFileContext() == null) { return null; } IParseState parseState = fileContext.getParseState(); if (parseState == null) { return null; } LexemeList lexemeList = parseState.getLexemeList(); return lexemeList; } /** * Returns language MIME type for offset position * * @param offset * @return - language */ public String getLanguageAtOffset(int offset) { LexemeList lexemeList = getLexemeList(); if (lexemeList == null) { return null; } Lexeme lexemeAtOffset = lexemeList.getCeilingLexeme(offset); if (lexemeAtOffset == null) { return null; } return lexemeAtOffset.getLanguage(); } private void removeOccurrenceAnnotations() { 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; } /** * * */ public void removeMarkedOccurrences() { removeOccurrenceAnnotations(); LexemeList lexemeList = getLexemeList(); if (lexemeList == null) { return; } for (int i = 0; i < lexemeList.size(); i++) { Lexeme lexeme = lexemeList.get(i); if (lexeme != null && lexeme.isHighlighted()) { lexeme.setHighlighted(false); } } } /** * @param lexeme * @return - true if occurrence should be marked */ public boolean canMarkOccurrences(Lexeme lexeme) { if (lexeme.getCategoryIndex() == TokenCategories.WHITESPACE) { return false; } if (lexeme.getCategoryIndex() == TokenCategories.PUNCTUATOR) { return false; } return true; } /** * Creates the docment provider * * @return IDocumentProvider */ public abstract IDocumentProvider createDocumentProvider(); /** * Is code assist available for auto-activation * * @return - true if activating, false otherwise */ public boolean autoActivateCodeAssist() { return autoActivateCodeAssist; } public void gotoMatchingBracket() { ISourceViewer sourceViewer = getSourceViewer(); IDocument document = sourceViewer.getDocument(); if (document == null) return; Point selectedPoint = sourceViewer.getSelectedRange(); IRegion selection = new Region(selectedPoint.x, selectedPoint.y); int selectionLength = Math.abs(selection.getLength()); if (selectionLength > 1) { setStatusLineErrorMessage(com.aptana.ide.editors.unified.actions.Messages.GotoMatchingBracket_error_invalidSelection); sourceViewer.getTextWidget().getDisplay().beep(); return; } int sourceCaretOffset = selection.getOffset() + selection.getLength(); PairMatch pair = getPairMatch(sourceCaretOffset); if (pair == null) { setStatusLineErrorMessage(com.aptana.ide.editors.unified.actions.Messages.GotoMatchingBracket_error_noMatchingBracket); sourceViewer.getTextWidget().getDisplay().beep(); return; } int start = 0; int end = 0; if (sourceCaretOffset <= pair.beginEnd && sourceCaretOffset >= pair.beginStart) { start = pair.endStart; end = pair.endEnd; } else { start = pair.beginStart; end = pair.beginEnd; } int length = end - start; sourceViewer.setSelectedRange(start, length); sourceViewer.revealRange(start, length); } }