/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Max Weninger (max.weninger@windriver.com) - Bug 131895 [Edit] Undo in compare * Max Weninger (max.weninger@windriver.com) - Bug 72936 [Viewers] Show line numbers in comparision *******************************************************************************/ package org.eclipse.compare.internal; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ResourceBundle; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.core.commands.Command; import org.eclipse.core.commands.IHandler; import org.eclipse.core.commands.operations.IOperationHistory; import org.eclipse.core.commands.operations.IOperationHistoryListener; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.commands.operations.OperationHistoryEvent; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextListener; import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.IUndoManager; import org.eclipse.jface.text.IUndoManagerExtension; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextEvent; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.ISharedTextColors; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.LineNumberRulerColumn; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IPropertyListener; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.menus.CommandContributionItem; import org.eclipse.ui.menus.CommandContributionItemParameter; import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; import org.eclipse.ui.texteditor.ChangeEncodingAction; import org.eclipse.ui.texteditor.FindReplaceAction; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IElementStateListener; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.compare.ICompareContainer; /** * Wraps a JFace SourceViewer and add some convenience methods. */ public class MergeSourceViewer implements ISelectionChangedListener, ITextListener, IMenuListener, IOperationHistoryListener, IAdaptable { public static final String UNDO_ID= "undo"; //$NON-NLS-1$ public static final String REDO_ID= "redo"; //$NON-NLS-1$ public static final String CUT_ID= "cut"; //$NON-NLS-1$ public static final String COPY_ID= "copy"; //$NON-NLS-1$ public static final String PASTE_ID= "paste"; //$NON-NLS-1$ public static final String DELETE_ID= "delete"; //$NON-NLS-1$ public static final String SELECT_ALL_ID= "selectAll"; //$NON-NLS-1$ public static final String FIND_ID= "find"; //$NON-NLS-1$ public static final String GOTO_LINE_ID= "gotoLine"; //$NON-NLS-1$ public static final String CHANGE_ENCODING_ID= "changeEncoding"; //$NON-NLS-1$ class TextOperationAction extends MergeViewerAction { private int fOperationCode; TextOperationAction(int operationCode, boolean mutable, boolean selection, boolean content) { this(operationCode, null, mutable, selection, content); } public TextOperationAction(int operationCode, String actionDefinitionId, boolean mutable, boolean selection, boolean content) { super(mutable, selection, content); if (actionDefinitionId != null) setActionDefinitionId(actionDefinitionId); fOperationCode= operationCode; update(); } public void run() { if (isEnabled()) getSourceViewer().doOperation(fOperationCode); } public boolean isEnabled() { return fOperationCode != -1 && getSourceViewer().canDoOperation(fOperationCode); } public void update() { this.setEnabled(isEnabled()); } } /** * TODO: The only purpose of this class is to provide "Go to Line" action in * TextMergeViewer. The adapter should be removed as soon as we implement * embedded TextEditor in a similar way JDT has it done for Java compare. */ class TextEditorAdapter implements ITextEditor { public void close(boolean save) { // defining interface method } public void doRevertToSaved() { // defining interface method } public IAction getAction(String actionId) { // defining interface method return null; } public IDocumentProvider getDocumentProvider() { return new IDocumentProvider(){ public void aboutToChange(Object element) { // defining interface method } public void addElementStateListener( IElementStateListener listener) { // defining interface method } public boolean canSaveDocument(Object element) { // defining interface method return false; } public void changed(Object element) { // defining interface method } public void connect(Object element) throws CoreException { // defining interface method } public void disconnect(Object element) { // defining interface method } public IAnnotationModel getAnnotationModel(Object element) { // defining interface method return null; } public IDocument getDocument(Object element) { return MergeSourceViewer.this.getSourceViewer().getDocument(); } public long getModificationStamp(Object element) { // defining interface method return 0; } public long getSynchronizationStamp(Object element) { // defining interface method return 0; } public boolean isDeleted(Object element) { // defining interface method return false; } public boolean mustSaveDocument(Object element) { // defining interface method return false; } public void removeElementStateListener( IElementStateListener listener) { // defining interface method } public void resetDocument(Object element) throws CoreException { // defining interface method } public void saveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException { // defining interface method }}; } public IRegion getHighlightRange() { // defining interface method return null; } public ISelectionProvider getSelectionProvider() { return MergeSourceViewer.this.getSourceViewer().getSelectionProvider(); } public boolean isEditable() { // defining interface method return false; } public void removeActionActivationCode(String actionId) { // defining interface method } public void resetHighlightRange() { // defining interface method } public void selectAndReveal(int start, int length) { selectAndReveal(start, length, start, length); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#selectAndReveal(int, int, int, int) */ private void selectAndReveal(int selectionStart, int selectionLength, int revealStart, int revealLength) { ISelection selection = getSelectionProvider().getSelection(); if (selection instanceof ITextSelection) { ITextSelection textSelection = (ITextSelection) selection; if (textSelection.getOffset() != 0 || textSelection.getLength() != 0) markInNavigationHistory(); } StyledText widget= MergeSourceViewer.this.getSourceViewer().getTextWidget(); widget.setRedraw(false); { adjustHighlightRange(revealStart, revealLength); MergeSourceViewer.this.getSourceViewer().revealRange(revealStart, revealLength); MergeSourceViewer.this.getSourceViewer().setSelectedRange(selectionStart, selectionLength); markInNavigationHistory(); } widget.setRedraw(true); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#markInNavigationHistory() */ private void markInNavigationHistory() { getSite().getPage().getNavigationHistory().markLocation(this); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#adjustHighlightRange(int, int) */ private void adjustHighlightRange(int offset, int length) { if (MergeSourceViewer.this instanceof ITextViewerExtension5) { ITextViewerExtension5 extension= (ITextViewerExtension5) MergeSourceViewer.this; extension.exposeModelRange(new Region(offset, length)); } else if (!isVisible(MergeSourceViewer.this.getSourceViewer(), offset, length)) { MergeSourceViewer.this.getSourceViewer().resetVisibleRegion(); } } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#isVisible(ISourceViewer, int, int) */ private /*static*/ final boolean isVisible(ITextViewer viewer, int offset, int length) { if (viewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension= (ITextViewerExtension5) viewer; IRegion overlap= extension.modelRange2WidgetRange(new Region(offset, length)); return overlap != null; } return viewer.overlapsWithVisibleRegion(offset, length); } public void setAction(String actionID, IAction action) { // defining interface method } public void setActionActivationCode(String actionId, char activationCharacter, int activationKeyCode, int activationStateMask) { // defining interface method } public void setHighlightRange(int offset, int length, boolean moveCursor) { // defining interface method } public void showHighlightRangeOnly(boolean showHighlightRangeOnly) { // defining interface method } public boolean showsHighlightRangeOnly() { // defining interface method return false; } public IEditorInput getEditorInput() { if (MergeSourceViewer.this.fContainer.getWorkbenchPart() instanceof IEditorPart) return ((IEditorPart) MergeSourceViewer.this.fContainer.getWorkbenchPart()).getEditorInput(); return null; } public IEditorSite getEditorSite() { // defining interface method return null; } public void init(IEditorSite site, IEditorInput input) throws PartInitException { // defining interface method } public void addPropertyListener(IPropertyListener listener) { // defining interface method } public void createPartControl(Composite parent) { // defining interface method } public void dispose() { // defining interface method } public IWorkbenchPartSite getSite() { return MergeSourceViewer.this.fContainer.getWorkbenchPart().getSite(); } public String getTitle() { // defining interface method return null; } public Image getTitleImage() { // defining interface method return null; } public String getTitleToolTip() { // defining interface method return null; } public void removePropertyListener(IPropertyListener listener) { // defining interface method } public void setFocus() { // defining interface method } public Object getAdapter(Class adapter) { // defining interface method return null; } public void doSave(IProgressMonitor monitor) { // defining interface method } public void doSaveAs() { // defining interface method } public boolean isDirty() { // defining interface method return false; } public boolean isSaveAsAllowed() { // defining interface method return false; } public boolean isSaveOnCloseNeeded() { // defining interface method return false; } } private ResourceBundle fResourceBundle; private ICompareContainer fContainer; private SourceViewer fSourceViewer; private Position fRegion; private boolean fEnabled= true; private HashMap fActions= new HashMap(); private IDocument fRememberedDocument; private boolean fAddSaveAction= true; private boolean isConfigured = false; // line number ruler support private IPropertyChangeListener fPreferenceChangeListener; private boolean fShowLineNumber=false; private LineNumberRulerColumn fLineNumberColumn; private List textActions = new ArrayList(); private CommandContributionItem fSaveContributionItem; public MergeSourceViewer(SourceViewer sourceViewer, ResourceBundle bundle, ICompareContainer container) { Assert.isNotNull(sourceViewer); fSourceViewer= sourceViewer; fResourceBundle= bundle; fContainer = container; MenuManager menu= new MenuManager(); menu.setRemoveAllWhenShown(true); menu.addMenuListener(this); StyledText te= getSourceViewer().getTextWidget(); te.setMenu(menu.createContextMenu(te)); fContainer.registerContextMenu(menu, getSourceViewer()); // for listening to editor show/hide line number preference value fPreferenceChangeListener= new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { MergeSourceViewer.this.handlePropertyChangeEvent(event); } }; EditorsUI.getPreferenceStore().addPropertyChangeListener(fPreferenceChangeListener); fShowLineNumber= EditorsUI.getPreferenceStore().getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER); if(fShowLineNumber){ updateLineNumberRuler(); } IOperationHistory history = getHistory(); if (history != null) history.addOperationHistoryListener(this); // don't add save when in a dialog, IWorkbenchPart is null in dialog containers fAddSaveAction = fContainer.getWorkbenchPart() != null; } public void rememberDocument(IDocument doc) { // if (doc != null && fRememberedDocument != null) { // System.err.println("MergeSourceViewer.rememberDocument: fRememberedDocument != null: shouldn't happen"); //$NON-NLS-1$ // } fRememberedDocument= doc; } public IDocument getRememberedDocument() { return fRememberedDocument; } public void hideSaveAction() { fAddSaveAction= false; } public void setFont(Font font) { StyledText te= getSourceViewer().getTextWidget(); if (te != null) te.setFont(font); if (fLineNumberColumn != null) { fLineNumberColumn.setFont(font); layoutViewer(); } } public void setBackgroundColor(Color color) { StyledText te= getSourceViewer().getTextWidget(); if (te != null) te.setBackground(color); if (fLineNumberColumn != null) fLineNumberColumn.setBackground(color); } public void setForegroundColor(Color color) { StyledText te= getSourceViewer().getTextWidget(); if (te != null) te.setForeground(color); } public void setEnabled(boolean enabled) { if (enabled != fEnabled) { fEnabled= enabled; StyledText c= getSourceViewer().getTextWidget(); if (c != null) { c.setEnabled(enabled); Display d= c.getDisplay(); c.setBackground(enabled ? d.getSystemColor(SWT.COLOR_LIST_BACKGROUND) : null); } } } public boolean getEnabled() { return fEnabled; } public void setRegion(Position region) { fRegion= region; } public Position getRegion() { return fRegion; } public boolean isControlOkToUse() { StyledText t= getSourceViewer().getTextWidget(); return t != null && !t.isDisposed(); } public void setSelection(Position position) { if (position != null) getSourceViewer().setSelectedRange(position.getOffset(), position.getLength()); } public void setLineBackground(Position position, Color c) { StyledText t= getSourceViewer().getTextWidget(); if (t != null && !t.isDisposed()) { Point region= new Point(0, 0); getLineRange(position, region); region.x-= getDocumentRegionOffset(); try { t.setLineBackground(region.x, region.y, c); } catch (IllegalArgumentException ex) { // silently ignored } } } public void resetLineBackground() { StyledText t= getSourceViewer().getTextWidget(); if (t != null && !t.isDisposed()) { int lines= getLineCount(); t.setLineBackground(0, lines, null); } } /* * Returns number of lines in document region. */ public int getLineCount() { IRegion region= getSourceViewer().getVisibleRegion(); int length= region.getLength(); if (length == 0) return 0; IDocument doc= getSourceViewer().getDocument(); int startLine= 0; int endLine= 0; int start= region.getOffset(); try { startLine= doc.getLineOfOffset(start); } catch(BadLocationException ex) { // silently ignored } try { endLine= doc.getLineOfOffset(start+length); } catch(BadLocationException ex) { // silently ignored } return endLine-startLine+1; } public int getViewportLines() { StyledText te= getSourceViewer().getTextWidget(); Rectangle clArea= te.getClientArea(); if (!clArea.isEmpty()) return clArea.height / te.getLineHeight(); return 0; } public int getViewportHeight() { StyledText te= getSourceViewer().getTextWidget(); Rectangle clArea= te.getClientArea(); if (!clArea.isEmpty()) return clArea.height; return 0; } /* * Returns lines */ public int getDocumentRegionOffset() { int start= getSourceViewer().getVisibleRegion().getOffset(); IDocument doc= getSourceViewer().getDocument(); if (doc != null) { try { return doc.getLineOfOffset(start); } catch(BadLocationException ex) { // silently ignored } } return 0; } public int getVerticalScrollOffset() { StyledText st= getSourceViewer().getTextWidget(); int lineHeight= st.getLineHeight(); return getSourceViewer().getTopInset() - ((getDocumentRegionOffset()*lineHeight) + st.getTopPixel()); } /* * Returns the start line and the number of lines which correspond to the given position. * Starting line number is 0 based. */ public Point getLineRange(Position p, Point region) { IDocument doc= getSourceViewer().getDocument(); if (p == null || doc == null) { region.x= 0; region.y= 0; return region; } int start= p.getOffset(); int length= p.getLength(); int startLine= 0; try { startLine= doc.getLineOfOffset(start); } catch (BadLocationException e) { // silently ignored } int lineCount= 0; if (length == 0) { // // if range length is 0 and if range starts a new line // try { // if (start == doc.getLineStartOffset(startLine)) { // lines--; // } // } catch (BadLocationException e) { // lines--; // } } else { int endLine= 0; try { endLine= doc.getLineOfOffset(start + length - 1); // why -1? } catch (BadLocationException e) { // silently ignored } lineCount= endLine-startLine+1; } region.x= startLine; region.y= lineCount; return region; } /* * Scroll TextPart to the given line. */ public void vscroll(int line) { int srcViewSize= getLineCount(); int srcExtentSize= getViewportLines(); if (srcViewSize > srcExtentSize) { if (line < 0) line= 0; int cp= getSourceViewer().getTopIndex(); if (cp != line) getSourceViewer().setTopIndex(line + getDocumentRegionOffset()); } } public void addAction(String actionId, MergeViewerAction action) { fActions.put(actionId, action); } public IAction getAction(String actionId) { IAction action= (IAction) fActions.get(actionId); if (action == null) { action= createAction(actionId); if (action == null) return null; if (action instanceof MergeViewerAction) { MergeViewerAction mva = (MergeViewerAction) action; if (mva.isContentDependent()) getSourceViewer().addTextListener(this); if (mva.isSelectionDependent()) getSourceViewer().addSelectionChangedListener(this); Utilities.initAction(action, fResourceBundle, "action." + actionId + "."); //$NON-NLS-1$ //$NON-NLS-2$ } addAction(actionId, action); } if (action instanceof MergeViewerAction) { MergeViewerAction mva = (MergeViewerAction) action; if (mva.isEditableDependent() && !getSourceViewer().isEditable()) return null; } return action; } protected IAction createAction(String actionId) { if (UNDO_ID.equals(actionId)) return new TextOperationAction(ITextOperationTarget.UNDO, IWorkbenchCommandConstants.EDIT_UNDO, true, false, true); if (REDO_ID.equals(actionId)) return new TextOperationAction(ITextOperationTarget.REDO, IWorkbenchCommandConstants.EDIT_REDO, true, false, true); if (CUT_ID.equals(actionId)) return new TextOperationAction(ITextOperationTarget.CUT, IWorkbenchCommandConstants.EDIT_CUT, true, true, false); if (COPY_ID.equals(actionId)) return new TextOperationAction(ITextOperationTarget.COPY, IWorkbenchCommandConstants.EDIT_COPY, false, true, false); if (PASTE_ID.equals(actionId)) return new TextOperationAction(ITextOperationTarget.PASTE, IWorkbenchCommandConstants.EDIT_PASTE, true, false, false); if (DELETE_ID.equals(actionId)) return new TextOperationAction(ITextOperationTarget.DELETE, IWorkbenchCommandConstants.EDIT_DELETE, true, false, false); if (SELECT_ALL_ID.equals(actionId)) return new TextOperationAction(ITextOperationTarget.SELECT_ALL, IWorkbenchCommandConstants.EDIT_SELECT_ALL, false, false, false); return null; } public void selectionChanged(SelectionChangedEvent event) { Iterator e= fActions.values().iterator(); while (e.hasNext()) { Object next = e.next(); if (next instanceof MergeViewerAction) { MergeViewerAction action = (MergeViewerAction) next; if (action.isSelectionDependent()) action.update(); } } } public void textChanged(TextEvent event) { updateContentDependantActions(); } void updateContentDependantActions() { Iterator e= fActions.values().iterator(); while (e.hasNext()) { Object next = e.next(); if (next instanceof MergeViewerAction) { MergeViewerAction action = (MergeViewerAction) next; if (action.isContentDependent()) action.update(); } } } /* * Allows the viewer to add menus and/or tools to the context menu. */ public void menuAboutToShow(IMenuManager menu) { menu.add(new Separator("undo")); //$NON-NLS-1$ addMenu(menu, UNDO_ID); addMenu(menu, REDO_ID); menu.add(new GroupMarker("save")); //$NON-NLS-1$ if (fAddSaveAction) addSave(menu); menu.add(new Separator("file")); //$NON-NLS-1$ menu.add(new Separator("ccp")); //$NON-NLS-1$ addMenu(menu, CUT_ID); addMenu(menu, COPY_ID); addMenu(menu, PASTE_ID); addMenu(menu, DELETE_ID); addMenu(menu, SELECT_ALL_ID); menu.add(new Separator("edit")); //$NON-NLS-1$ addMenu(menu, CHANGE_ENCODING_ID); menu.add(new Separator("find")); //$NON-NLS-1$ addMenu(menu, FIND_ID); menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); menu.add(new Separator("text")); //$NON-NLS-1$ for (Iterator iterator = textActions.iterator(); iterator.hasNext();) { IAction action = (IAction) iterator.next(); menu.add(action); } menu.add(new Separator("rest")); //$NON-NLS-1$ // update all actions // to get undo redo right updateActions(); } private void addMenu(IMenuManager menu, String actionId) { IAction action= getAction(actionId); if (action != null) menu.add(action); } private void addSave(IMenuManager menu) { ICommandService commandService = (ICommandService) fContainer.getWorkbenchPart().getSite().getService(ICommandService.class); final Command command= commandService.getCommand(IWorkbenchCommandConstants.FILE_SAVE); final IHandler handler = command.getHandler(); if (handler != null) { if (fSaveContributionItem == null) { fSaveContributionItem = new CommandContributionItem( new CommandContributionItemParameter(fContainer .getWorkbenchPart().getSite(), null, command .getId(), CommandContributionItem.STYLE_PUSH)); } // save is an editable dependent action, ie add only when edit // is possible if (handler.isHandled() && getSourceViewer().isEditable()) menu.add(fSaveContributionItem); } } /** * The viewer is no longer part of the UI, it's a wrapper only. The disposal * doesn't take place while releasing the editor pane's children. The method * have to be called it manually. The wrapped viewer is disposed as a * regular viewer, while disposing the UI. */ public void dispose() { getSourceViewer().removeTextListener(this); getSourceViewer().removeSelectionChangedListener(this); EditorsUI.getPreferenceStore().removePropertyChangeListener(fPreferenceChangeListener); IOperationHistory history = getHistory(); if (history != null) history.removeOperationHistoryListener(this); } /** * update all actions independent of their type * */ public void updateActions() { Iterator e= fActions.values().iterator(); while (e.hasNext()) { Object next = e.next(); if (next instanceof MergeViewerAction) { MergeViewerAction action = (MergeViewerAction) next; action.update(); } else if (next instanceof FindReplaceAction) { FindReplaceAction action = (FindReplaceAction) next; action.update(); } else if (next instanceof ChangeEncodingAction) { ChangeEncodingAction action = (ChangeEncodingAction) next; action.update(); } } } public void configure(SourceViewerConfiguration configuration) { if (isConfigured ) getSourceViewer().unconfigure(); isConfigured = true; getSourceViewer().configure(configuration); } /** * specific implementation to support a vertical ruler * @param x * @param y * @param width * @param height */ public void setBounds (int x, int y, int width, int height) { if(getSourceViewer().getControl() instanceof Composite){ ((Composite)getSourceViewer().getControl()).setBounds(x, y, width, height); } else { getSourceViewer().getTextWidget().setBounds(x, y, width, height); } } /** * handle show/hide line numbers from editor preferences * @param event */ protected void handlePropertyChangeEvent(PropertyChangeEvent event) { String key= event.getProperty(); if(key.equals(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER)){ boolean b= EditorsUI.getPreferenceStore().getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER); if (b != fShowLineNumber){ toggleLineNumberRuler(); } } else if (key.equals(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR)) { updateLineNumberColumnPresentation(true); } } /** * Hides or shows line number ruler column based of preference setting */ private void updateLineNumberRuler() { IVerticalRuler v= getVerticalRuler(getSourceViewer()); if (v!=null && v instanceof CompositeRuler) { CompositeRuler c= (CompositeRuler) v; if(!fShowLineNumber){ if(fLineNumberColumn!=null){ c.removeDecorator(fLineNumberColumn); } } else { if(fLineNumberColumn==null){ fLineNumberColumn = new LineNumberRulerColumn(); updateLineNumberColumnPresentation(false); } c.addDecorator(0, fLineNumberColumn); } } } /** * Calls the <code>getVerticalRuler</code> method of the given viewer. * * TODO: don't use reflection * * @param viewer the viewer to call <code>getVerticalRuler</code> on */ private IVerticalRuler getVerticalRuler(SourceViewer viewer) { try { Method method= SourceViewer.class.getDeclaredMethod("getVerticalRuler", new Class[] {}); //$NON-NLS-1$ method.setAccessible(true); return (IVerticalRuler) method.invoke(viewer, new Object[] {}); } catch (Throwable e) { CompareUIPlugin.log(e); } return null; } private void updateLineNumberColumnPresentation(boolean refresh) { if (fLineNumberColumn == null) return; RGB rgb= getColorFromStore(EditorsUI.getPreferenceStore(), AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR); if (rgb == null) rgb= new RGB(0, 0, 0); ISharedTextColors sharedColors= getSharedColors(); fLineNumberColumn.setForeground(sharedColors.getColor(rgb)); if (refresh) { fLineNumberColumn.redraw(); } } private void layoutViewer() { Control parent= getSourceViewer().getControl(); if (parent instanceof Composite && !parent.isDisposed()) ((Composite) parent).layout(true); } private ISharedTextColors getSharedColors() { return EditorsUI.getSharedTextColors(); } private RGB getColorFromStore(IPreferenceStore store, String key) { RGB rgb= null; if (store.contains(key)) { if (store.isDefault(key)) rgb= PreferenceConverter.getDefaultColor(store, key); else rgb= PreferenceConverter.getColor(store, key); } return rgb; } /** * Toggles line number ruler column. */ private void toggleLineNumberRuler() { fShowLineNumber=!fShowLineNumber; updateLineNumberRuler(); } public void addTextAction(IAction textEditorPropertyAction) { textActions.add(textEditorPropertyAction); } public void addAction(String id, IAction action) { fActions.put(id, action); } private IOperationHistory getHistory() { if (PlatformUI.getWorkbench() == null) { return null; } return PlatformUI.getWorkbench().getOperationSupport() .getOperationHistory(); } public void historyNotification(OperationHistoryEvent event) { // This method updates the enablement of all content operations // when the undo history changes. It could be localized to UNDO and REDO. IUndoContext context = getUndoContext(); if (context != null && event.getOperation().hasContext(context)) { Display.getDefault().asyncExec(new Runnable() { public void run() { updateContentDependantActions(); } }); } } private IUndoContext getUndoContext() { IUndoManager undoManager = getSourceViewer().getUndoManager(); if (undoManager instanceof IUndoManagerExtension) return ((IUndoManagerExtension)undoManager).getUndoContext(); return null; } /** * @return the wrapped viewer */ public SourceViewer getSourceViewer() { return fSourceViewer; } public Object getAdapter(Class adapter) { if (adapter == ITextEditor.class) { return new TextEditorAdapter(); } return null; } }