1 package org.simantics.scl.ui.editor2;
3 import java.text.CharacterIterator;
5 import org.eclipse.jface.action.IAction;
6 import org.eclipse.jface.resource.JFaceResources;
7 import org.eclipse.jface.resource.LocalResourceManager;
8 import org.eclipse.jface.resource.ResourceManager;
9 import org.eclipse.jface.text.BadLocationException;
10 import org.eclipse.jface.text.IDocument;
11 import org.eclipse.jface.text.link.LinkedModeModel;
12 import org.eclipse.jface.text.link.LinkedPosition;
13 import org.eclipse.jface.text.source.ISourceViewer;
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.custom.ST;
16 import org.eclipse.swt.custom.StyledText;
17 import org.eclipse.swt.graphics.Point;
18 import org.eclipse.swt.widgets.Composite;
19 import org.eclipse.ui.IEditorInput;
20 import org.eclipse.ui.IEditorSite;
21 import org.eclipse.ui.PartInitException;
22 import org.eclipse.ui.contexts.IContextService;
23 import org.eclipse.ui.editors.text.TextEditor;
24 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
25 import org.eclipse.ui.texteditor.IUpdate;
26 import org.eclipse.ui.texteditor.TextNavigationAction;
27 import org.simantics.scl.ui.editor.SCLSourceViewerConfigurationNew;
28 import org.simantics.scl.ui.editor.completion.SCLTextEditorEnvironment;
29 import org.simantics.scl.ui.editor2.iterator.DocumentCharacterIterator;
30 import org.simantics.scl.ui.editor2.iterator.JavaWordIterator;
32 import com.ibm.icu.text.BreakIterator;
34 public class SCLModuleEditor2 extends TextEditor {
35 private boolean disposed = false;
36 protected ResourceManager resourceManager;
38 public SCLModuleEditor2() {
40 resourceManager = new LocalResourceManager(JFaceResources.getResources());
41 SCLSourceViewerConfigurationNew sourceViewerConfiguration = new SCLSourceViewerConfigurationNew(resourceManager);
42 setDocumentProvider(new SCLModuleEditor2DocumentProvider(sourceViewerConfiguration));
43 setSourceViewerConfiguration(sourceViewerConfiguration);
47 public boolean isTabsToSpacesConversionEnabled() {
52 public void init(IEditorSite site, IEditorInput input)
53 throws PartInitException {
54 super.init(site, input);
58 public void createPartControl(Composite parent) {
59 super.createPartControl(parent);
60 getEditorSite().getService(IContextService.class).activateContext("org.simantics.scl.ui.editor");
65 protected void createNavigationActions() {
66 super.createNavigationActions();
68 // Taken from org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.createNavigationActions()
69 final StyledText textWidget= getSourceViewer().getTextWidget();
71 IAction action = new NavigatePreviousSubWordAction();
72 action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_PREVIOUS);
73 setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, action);
74 textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_LEFT, SWT.NULL);
76 action = new NavigateNextSubWordAction();
77 action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_NEXT);
78 setAction(ITextEditorActionDefinitionIds.WORD_NEXT, action);
79 textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_RIGHT, SWT.NULL);
81 action = new SelectPreviousSubWordAction();
82 action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS);
83 setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, action);
84 textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_LEFT, SWT.NULL);
86 action = new SelectNextSubWordAction();
87 action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT);
88 setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, action);
89 textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_RIGHT, SWT.NULL);
92 protected void updatePartName() {
93 setPartName(getEditorInput().getName());
97 public void dispose() {
100 resourceManager.dispose();
103 public boolean isDisposed() {
107 public SCLTextEditorEnvironment getSCLTextEditorEnvironment() {
108 return ((SCLSourceViewerConfigurationNew)getSourceViewerConfiguration())
109 .getSclTextEditorEnvironment();
112 public IDocument getDocument() {
113 return getSourceViewer().getDocument();
117 * Text navigation action to navigate to the next sub-word.
121 protected abstract class NextSubWordAction extends TextNavigationAction {
123 protected JavaWordIterator fIterator= new JavaWordIterator();
126 * Creates a new next sub-word action.
128 * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
130 protected NextSubWordAction(int code) {
131 super(getSourceViewer().getTextWidget(), code);
135 * @see org.eclipse.jface.action.IAction#run()
139 final ISourceViewer viewer= getSourceViewer();
140 final IDocument document= viewer.getDocument();
142 fIterator.setText((CharacterIterator)new DocumentCharacterIterator(document));
143 int position= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
147 int next= findNextPosition(position);
148 if (isBlockSelectionModeEnabled() && document.getLineOfOffset(next) != document.getLineOfOffset(position)) {
149 super.run(); // may navigate into virtual white space
150 } else if (next != BreakIterator.DONE) {
151 setCaretPosition(next);
152 getTextWidget().showSelection();
153 fireSelectionChanged();
155 } catch (BadLocationException x) {
161 * Finds the next position after the given position.
163 * @param position the current position
164 * @return the next position
166 protected int findNextPosition(int position) {
167 ISourceViewer viewer= getSourceViewer();
170 while (next != BreakIterator.DONE && widget == -1) { // XXX: optimize
171 next= fIterator.following(next);
172 if (next != BreakIterator.DONE)
173 widget= modelOffset2WidgetOffset(viewer, next);
176 IDocument document= viewer.getDocument();
177 LinkedModeModel model= LinkedModeModel.getModel(document, position);
178 if (model != null && next != BreakIterator.DONE) {
179 LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, position, 0));
180 if (linkedPosition != null) {
181 int linkedPositionEnd= linkedPosition.getOffset() + linkedPosition.getLength();
182 if (position != linkedPositionEnd && linkedPositionEnd < next)
183 next= linkedPositionEnd;
185 LinkedPosition nextLinkedPosition= model.findPosition(new LinkedPosition(document, next, 0));
186 if (nextLinkedPosition != null) {
187 int nextLinkedPositionOffset= nextLinkedPosition.getOffset();
188 if (position != nextLinkedPositionOffset && nextLinkedPositionOffset < next)
189 next= nextLinkedPositionOffset;
198 * Sets the caret position to the sub-word boundary given with <code>position</code>.
200 * @param position Position where the action should move the caret
202 protected abstract void setCaretPosition(int position);
206 * Text navigation action to navigate to the next sub-word.
210 protected class NavigateNextSubWordAction extends NextSubWordAction {
213 * Creates a new navigate next sub-word action.
215 public NavigateNextSubWordAction() {
220 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
223 protected void setCaretPosition(final int position) {
224 getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
229 * Text operation action to delete the next sub-word.
233 protected class DeleteNextSubWordAction extends NextSubWordAction implements IUpdate {
236 * Creates a new delete next sub-word action.
238 public DeleteNextSubWordAction() {
239 super(ST.DELETE_WORD_NEXT);
243 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
246 protected void setCaretPosition(final int position) {
247 if (!validateEditorInputState())
250 final ISourceViewer viewer= getSourceViewer();
251 StyledText text= viewer.getTextWidget();
252 Point widgetSelection= text.getSelection();
253 if (isBlockSelectionModeEnabled() && widgetSelection.y != widgetSelection.x) {
254 final int caret= text.getCaretOffset();
255 final int offset= modelOffset2WidgetOffset(viewer, position);
257 if (caret == widgetSelection.x)
258 text.setSelectionRange(widgetSelection.y, offset - widgetSelection.y);
260 text.setSelectionRange(widgetSelection.x, offset - widgetSelection.x);
261 text.invokeAction(ST.DELETE_NEXT);
263 Point selection= viewer.getSelectedRange();
264 final int caret, length;
265 if (selection.y != 0) {
269 caret= widgetOffset2ModelOffset(viewer, text.getCaretOffset());
270 length= position - caret;
274 viewer.getDocument().replace(caret, length, ""); //$NON-NLS-1$
275 } catch (BadLocationException exception) {
282 * @see org.eclipse.ui.texteditor.IUpdate#update()
284 public void update() {
285 setEnabled(isEditorInputModifiable());
290 * Text operation action to select the next sub-word.
294 protected class SelectNextSubWordAction extends NextSubWordAction {
297 * Creates a new select next sub-word action.
299 public SelectNextSubWordAction() {
300 super(ST.SELECT_WORD_NEXT);
304 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
307 protected void setCaretPosition(final int position) {
308 final ISourceViewer viewer= getSourceViewer();
310 final StyledText text= viewer.getTextWidget();
311 if (text != null && !text.isDisposed()) {
313 final Point selection= text.getSelection();
314 final int caret= text.getCaretOffset();
315 final int offset= modelOffset2WidgetOffset(viewer, position);
317 if (caret == selection.x)
318 text.setSelectionRange(selection.y, offset - selection.y);
320 text.setSelectionRange(selection.x, offset - selection.x);
326 * Text navigation action to navigate to the previous sub-word.
330 protected abstract class PreviousSubWordAction extends TextNavigationAction {
332 protected JavaWordIterator fIterator= new JavaWordIterator();
335 * Creates a new previous sub-word action.
337 * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
339 protected PreviousSubWordAction(final int code) {
340 super(getSourceViewer().getTextWidget(), code);
344 * @see org.eclipse.jface.action.IAction#run()
348 final ISourceViewer viewer= getSourceViewer();
349 final IDocument document= viewer.getDocument();
351 fIterator.setText((CharacterIterator)new DocumentCharacterIterator(document));
352 int position= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
356 int previous= findPreviousPosition(position);
357 if (isBlockSelectionModeEnabled() && document.getLineOfOffset(previous) != document.getLineOfOffset(position)) {
358 super.run(); // may navigate into virtual white space
359 } else if (previous != BreakIterator.DONE) {
360 setCaretPosition(previous);
361 getTextWidget().showSelection();
362 fireSelectionChanged();
364 } catch (BadLocationException x) {
365 // ignore - getLineOfOffset failed
371 * Finds the previous position before the given position.
373 * @param position the current position
374 * @return the previous position
376 protected int findPreviousPosition(int position) {
377 ISourceViewer viewer= getSourceViewer();
379 int previous= position;
380 while (previous != BreakIterator.DONE && widget == -1) { // XXX: optimize
381 previous= fIterator.preceding(previous);
382 if (previous != BreakIterator.DONE)
383 widget= modelOffset2WidgetOffset(viewer, previous);
386 IDocument document= viewer.getDocument();
387 LinkedModeModel model= LinkedModeModel.getModel(document, position);
388 if (model != null && previous != BreakIterator.DONE) {
389 LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, position, 0));
390 if (linkedPosition != null) {
391 int linkedPositionOffset= linkedPosition.getOffset();
392 if (position != linkedPositionOffset && previous < linkedPositionOffset)
393 previous= linkedPositionOffset;
395 LinkedPosition previousLinkedPosition= model.findPosition(new LinkedPosition(document, previous, 0));
396 if (previousLinkedPosition != null) {
397 int previousLinkedPositionEnd= previousLinkedPosition.getOffset() + previousLinkedPosition.getLength();
398 if (position != previousLinkedPositionEnd && previous < previousLinkedPositionEnd)
399 previous= previousLinkedPositionEnd;
408 * Sets the caret position to the sub-word boundary given with <code>position</code>.
410 * @param position Position where the action should move the caret
412 protected abstract void setCaretPosition(int position);
416 * Text navigation action to navigate to the previous sub-word.
420 protected class NavigatePreviousSubWordAction extends PreviousSubWordAction {
423 * Creates a new navigate previous sub-word action.
425 public NavigatePreviousSubWordAction() {
426 super(ST.WORD_PREVIOUS);
430 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
433 protected void setCaretPosition(final int position) {
434 getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
439 * Text operation action to delete the previous sub-word.
443 protected class DeletePreviousSubWordAction extends PreviousSubWordAction implements IUpdate {
446 * Creates a new delete previous sub-word action.
448 public DeletePreviousSubWordAction() {
449 super(ST.DELETE_WORD_PREVIOUS);
453 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
456 protected void setCaretPosition(int position) {
457 if (!validateEditorInputState())
461 final ISourceViewer viewer= getSourceViewer();
462 StyledText text= viewer.getTextWidget();
463 Point widgetSelection= text.getSelection();
464 if (isBlockSelectionModeEnabled() && widgetSelection.y != widgetSelection.x) {
465 final int caret= text.getCaretOffset();
466 final int offset= modelOffset2WidgetOffset(viewer, position);
468 if (caret == widgetSelection.x)
469 text.setSelectionRange(widgetSelection.y, offset - widgetSelection.y);
471 text.setSelectionRange(widgetSelection.x, offset - widgetSelection.x);
472 text.invokeAction(ST.DELETE_PREVIOUS);
474 Point selection= viewer.getSelectedRange();
475 if (selection.y != 0) {
476 position= selection.x;
479 length= widgetOffset2ModelOffset(viewer, text.getCaretOffset()) - position;
483 viewer.getDocument().replace(position, length, ""); //$NON-NLS-1$
484 } catch (BadLocationException exception) {
491 * @see org.eclipse.ui.texteditor.IUpdate#update()
493 public void update() {
494 setEnabled(isEditorInputModifiable());
499 * Text operation action to select the previous sub-word.
503 protected class SelectPreviousSubWordAction extends PreviousSubWordAction {
506 * Creates a new select previous sub-word action.
508 public SelectPreviousSubWordAction() {
509 super(ST.SELECT_WORD_PREVIOUS);
513 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
516 protected void setCaretPosition(final int position) {
517 final ISourceViewer viewer= getSourceViewer();
519 final StyledText text= viewer.getTextWidget();
520 if (text != null && !text.isDisposed()) {
522 final Point selection= text.getSelection();
523 final int caret= text.getCaretOffset();
524 final int offset= modelOffset2WidgetOffset(viewer, position);
526 if (caret == selection.x)
527 text.setSelectionRange(selection.y, offset - selection.y);
529 text.setSelectionRange(selection.x, offset - selection.x);