View Javadoc

1   /*
2    * $Id: OWLSourceEditor.java,v 1.42 2005/07/08 18:20:03 jlerner Exp $
3    *
4    * Copyright (c) 1999-2004, BBN Technologies, LLC.
5    * All rights reserved.
6    * http://www.daml.org/legal/opensource/bbn_license.html
7    */
8   
9   package com.bbn.swede.editor;
10  
11  import org.eclipse.core.runtime.CoreException;
12  import org.eclipse.core.runtime.IProgressMonitor;
13  import org.eclipse.jface.action.IAction;
14  import org.eclipse.jface.text.BadLocationException;
15  import org.eclipse.jface.text.IDocument;
16  import org.eclipse.jface.text.IRegion;
17  import org.eclipse.jface.text.source.SourceViewer;
18  import org.eclipse.jface.viewers.ISelection;
19  import org.eclipse.jface.viewers.ISelectionChangedListener;
20  import org.eclipse.jface.viewers.ISelectionProvider;
21  import org.eclipse.jface.viewers.StructuredSelection;
22  import org.eclipse.swt.SWT;
23  import org.eclipse.swt.widgets.Composite;
24  import org.eclipse.ui.IEditorPart;
25  import org.eclipse.ui.IWorkbenchPage;
26  import org.eclipse.ui.editors.text.FileDocumentProvider;
27  import org.eclipse.ui.editors.text.TextEditor;
28  import org.eclipse.ui.part.MultiPageEditorSite;
29  import org.eclipse.ui.texteditor.DefaultRangeIndicator;
30  import org.eclipse.ui.texteditor.TextOperationAction;
31  
32  import com.bbn.swede.core.dom.AttributeNode;
33  import com.bbn.swede.core.dom.OAST;
34  import com.bbn.swede.core.dom.OASTNode;
35  
36  /***
37   * The text editor that appears as "Source" tab in OWLEditor.
38   * @author jlerner
39   */
40  public class OWLSourceEditor extends TextEditor implements ISelectionProvider
41  {
42     /*
43      *  (non-Javadoc)
44      * @see org.eclipse.ui.texteditor.ITextEditor#close(boolean)
45      */
46     public void close(boolean save)
47     {
48        //No need to call the superclass close() method.  It will always fail
49        //since the text editor is in a MultiPageEditorSite, not a PartSite.
50        MultiPageEditorSite site = (MultiPageEditorSite)getSite();
51        IEditorPart part = site.getMultiPageEditor();
52        IWorkbenchPage page = part.getSite().getPage();
53        page.closeEditor(part, save);
54     }
55     
56     /***
57      * Creates documents that use OWLDocumentPartitioner as their document
58      * partitioner.
59      * @author jlerner
60      */
61     protected class OWLDocumentProvider extends FileDocumentProvider
62     {
63        /***
64         * The OWL abstract syntax tree for the provided document.
65         */
66        protected OAST _tree;
67        /***
68         * The document partitioner for the provided document.
69         */
70        protected OWLDocumentPartitioner _partitioner;
71  
72        /***
73         * Creates an OWL document provider for a specified OAST.
74         * @param tree The OAST.
75         */
76        public OWLDocumentProvider(OAST tree)
77        {
78           super();
79           _tree = tree;
80        }
81  
82        /*
83         *  (non-Javadoc)
84         * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#createDocument(java.lang.Object)
85         */
86        protected IDocument createDocument(Object element) throws CoreException
87        {
88           IDocument document = super.createDocument(element);
89           if (document != null)
90           {
91              _partitioner = new OWLDocumentPartitioner(_tree);
92              _partitioner.connect(document);
93              document.setDocumentPartitioner(_partitioner);
94           }
95           return document;
96        }
97  
98        /***
99         * Sets the source editor reference in the document partitioner.
100        * The document must already have been created before setting the source
101        * viewer reference.
102        * @param editor The OWL source editor for the document
103        * @param viewer The editor's source viewer control
104        */
105       protected void setEditor(OWLSourceEditor editor, SourceViewer viewer)
106       {
107          if (_partitioner != null)
108          {
109             _partitioner.setEditor(editor, viewer);
110          }
111       }
112 
113    }
114 
115    /***
116     * Creates a new OWLSourceEditor associated with an OAST.  The OAST will
117     * be updated automatically as the document is changed and, if there are
118     * unsaved changes when the editor is closed, reverted to reflect the
119     * state of the file on disk.
120     * @param tree The OAST to connect to the editor
121     */
122    public OWLSourceEditor(OAST tree)
123    {
124       super();
125 
126       setDocumentProvider(new OWLDocumentProvider(tree));
127       setRangeIndicator(new DefaultRangeIndicator());
128       setSourceViewerConfiguration(new OWLSourceViewerConfiguration(tree));
129    }
130 
131    private OWLEditorContentOutlinePage _outline;
132    /***
133     * Retrives the content outline page representing this editor's OAST,
134     * creating it first if necessary.
135     * @param editor The enclosing multi-page OWL editor
136     * @return A content outline page representing the editor's document's OAST
137     */
138    public OWLEditorContentOutlinePage getContentOutline(OWLEditor editor)
139    {
140       if (_outline == null)
141       {
142          _outline =
143             new OWLEditorContentOutlinePage(editor,
144                ((OWLEditorInput) getEditorInput()).getOAST());
145       }
146       return _outline;
147    }
148 
149    /***
150     * Selects the full text of a node and scrolls the editor to display it.
151     * If <code>node</code> is not attached to the OAST of the document being
152     * edited, nothing happens.
153     * @param node The OASTNode to select and display
154     */
155    public void selectNode(OASTNode node)
156    {
157       OWLEditorInput oei = (OWLEditorInput)getEditorInput();
158       if (oei.getOAST().equals(node.getOWLAbstractSyntaxTree()))
159       {
160          int iStart = node.getOffset();
161          int iLength = node.getLength();
162          selectAndReveal(iStart, iLength);
163          setHighlightRange(iStart, iLength, false);
164       }
165    }
166 
167    /***
168     * Selects the text of a node's QName and scrolls the editor to display
169     * it.  If <code>node</code> has no QName or <code>node</code> is not
170     * attached to the OAST of the document being edited, nothing happens.
171     * @param node The node to select
172     */
173    public void selectQName(OASTNode node)
174    {
175       OWLEditorInput oei = (OWLEditorInput)getEditorInput();
176       if (oei.getOAST().equals(node.getOWLAbstractSyntaxTree()))
177       {
178          int iStart = node.getOffset();
179          int iLength = node.getLength();
180          this.setHighlightRange(iStart, iLength, false);
181          if (!(node instanceof AttributeNode))
182          {
183             iStart++;
184          }
185          String sQName = node.getQName();
186          if (sQName == null)
187          {
188             return;
189          }
190          selectAndReveal(iStart, sQName.length());
191       }
192    }
193 
194    private static final String CONTENTASSIST_PROPOSAL_ID =
195       "com.bbn.OWLeditor.ContentAssistProposal";
196 
197    /* (non-Javadoc)
198     * @see org.eclipse.ui.texteditor.AbstractTextEditor#createActions()
199     */
200    protected void createActions()
201    {
202       super.createActions();
203       // This action will fire a CONTENTASSIST_PROPOSALS operation
204       // when executed
205 
206       IAction action =
207          new TextOperationAction(
208             EditorPlugin.getPlugin().getResourceBundle(),
209             "ContentAssistProposal",
210             this,
211             SourceViewer.CONTENTASSIST_PROPOSALS);
212       action.setActionDefinitionId(CONTENTASSIST_PROPOSAL_ID);
213       // Tell the editor about this new action
214       setAction(CONTENTASSIST_PROPOSAL_ID, action);
215       // Tell the editor to execute this action 
216       // when Ctrl+Spacebar is pressed
217       setActionActivationCode(CONTENTASSIST_PROPOSAL_ID, ' ', -1, SWT.CTRL);
218    }
219 
220    /***
221     * Insert a manually constructed node into the document's syntax tree.
222     * @param parent Parent node for the new node
223     * @param node The new node.  It will be placed relative to either the
224     *             existing attributes or existing nested tags of the parent
225     *             node, depending on whether or not it is an instance of
226     *             AttributeNode
227     * @param bBefore true to insert the new node before the parent's existing
228     *                children, false to insert after them.
229     * @deprecated As of SWeDE 2.0.0, use the OAST API instead.
230     * @throws BadLocationException if text for <code>parent</code> cannot be
231     *         retrieved for a partial reparse.
232     */
233    public void insertNode(OASTNode parent, OASTNode node, boolean bBefore)
234       throws BadLocationException
235    {
236       OASTNode[] children = parent.getChildren();
237       IDocument doc = this.getSourceViewer().getDocument();
238       int insertPos;
239       StringBuffer sbText = new StringBuffer();
240       IRegion[] regions = parent.simplePartitioning();
241 
242       if (node instanceof AttributeNode && bBefore)
243       {
244          if (children.length > 0
245             && children[0] instanceof AttributeNode)
246          {
247             insertPos = children[0].getOffset();
248          }
249          else
250          {
251             String sBegin =
252                doc.get(regions[0].getOffset(), regions[0].getLength());
253             int i;
254             for (i = 0; i < sBegin.length(); i++)
255             {
256                if (Character.isWhitespace(sBegin.charAt(i))
257                   || sBegin.charAt(i) == '/'
258                   || sBegin.charAt(i) == '>')
259                {
260                   break;
261                }
262             }
263             insertPos = regions[0].getOffset() + i;
264             sbText.append(" ");
265          }
266       }
267       else if (node instanceof AttributeNode)
268       {
269          String sBegin =
270             doc.get(regions[0].getOffset(), regions[0].getLength());
271          int i;
272          for (i = sBegin.length() - 1; i >= 0; i--)
273          {
274             if (sBegin.charAt(i) != '>' && sBegin.charAt(i) != '/')
275             {
276                break;
277             }
278          }
279          insertPos = regions[0].getOffset() + i + 1;
280          if (!Character.isWhitespace(sBegin.charAt(i)))
281          {
282             sbText.append(" ");
283          }
284       }
285       else if (bBefore)
286       {
287          //this doesn't handle cases that require splitting a singleton into 
288          //begin/end tags, but it's deprecated, so...meh.
289          insertPos = regions[1].getOffset();
290          sbText.append("\n");
291       }
292       else
293       {
294          //this doesn't handle cases that require splitting a singleton into 
295          //begin/end tags, but it's deprecated, so...meh.
296          insertPos = regions[regions.length - 1].getOffset();
297          sbText.append("\n");
298       }
299       sbText.append(node.generateNodeText());
300       getSourceViewer().setSelectedRange(insertPos, 0);
301       getSourceViewer().getTextWidget().replaceTextRange(insertPos, 0, sbText.toString());
302       int iLength = getSourceViewer().getSelectedRange().x - insertPos;
303       selectAndReveal(insertPos, iLength);
304    }
305 
306    /*
307     *  (non-Javadoc)
308     * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
309     */
310    public void doSave(IProgressMonitor monitor)
311    {
312       super.doSave(monitor);
313       ((OWLDocumentPartitioner)getSourceViewer().getDocument().getDocumentPartitioner()).updateOAST();
314       OWLEditorInput oei = (OWLEditorInput) getEditorInput();
315       oei.getOAST().persistUnparseability();
316    }
317 
318    /*
319     *  (non-Javadoc)
320     * @see org.eclipse.ui.ISaveablePart#doSaveAs()
321     */
322    public void doSaveAs()
323    {
324       super.doSaveAs();
325       ((OWLDocumentPartitioner)getSourceViewer().getDocument().getDocumentPartitioner()).updateOAST();
326       OWLEditorInput oei = (OWLEditorInput) getEditorInput();
327       oei.getOAST().persistUnparseability();
328    }
329 
330    /*
331     *  (non-Javadoc)
332     * @see org.eclipse.ui.IWorkbenchPart#dispose()
333     */
334    public void dispose()
335    {
336       OWLEditorInput oei = (OWLEditorInput) getEditorInput();
337       if (oei != null)
338       {
339          //If the file was deleted, just let the editor close.  This prevents
340          //the error log from filling up with warnings due to the Eclipse 3.0
341          //bug where text editors don't auto-close if their document is dirty
342          if (!oei.getFile().exists())
343          {
344             return;
345          }
346       }
347       //Eliminate any unsaved changes from the syntax tree by reloading it
348       //from disk
349       if (isDirty())
350       {
351          oei.getOAST().reload();
352       }
353 
354       super.dispose();
355    }
356 
357    /* (non-Javadoc)
358     * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(
359     *       org.eclipse.jface.viewers.ISelectionChangedListener)
360     */
361    public void addSelectionChangedListener(ISelectionChangedListener listener)
362    { 
363    }
364   
365    /* (non-Javadoc)
366     * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(
367     *       org.eclipse.jface.viewers.ISelectionChangedListener)
368     */
369    public void removeSelectionChangedListener(ISelectionChangedListener listener)
370    {      
371    }
372 
373    /* (non-Javadoc)
374     * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection)
375     */
376    public void setSelection(ISelection selection)
377    {
378    }
379 
380    /***
381     * This function is an accessor that runs a sanity check on the file system.
382     * @param input The editor input to check.
383     */
384    public void editorSyncCheck(OWLEditorInput input)
385    {
386       safelySanityCheckState(input); 
387    }
388    
389    /* (non-Javadoc)
390     * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
391     */   
392    public ISelection getSelection()
393    {
394       //return istructuredselection, get from owleditor    
395       OWLEditorInput input = (OWLEditorInput)getEditorInput();      
396       StructuredSelection selection = null;
397             
398       if(input != null)
399       {
400          selection = new StructuredSelection(input.getDocument());
401       }
402 
403       editorSyncCheck(input);
404       
405       return selection;
406    }
407    /*
408     *  (non-Javadoc)
409     * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
410     */
411    public void createPartControl(Composite parent)
412    {
413       super.createPartControl(parent);
414       //Don't need to set the selection provider here since setFocus does it
415       ((OWLDocumentProvider)getDocumentProvider()).setEditor(this, (SourceViewer)getSourceViewer());
416       this.getSourceViewer().getTextWidget().setTabs(EditorPlugin.getTabWidth());
417    }
418    /*
419     *  (non-Javadoc)
420     * @see org.eclipse.ui.IWorkbenchPart#setFocus()
421     */
422    public void setFocus()
423    {
424       super.setFocus();
425       getSite().setSelectionProvider(this);
426    }
427 }