View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics and Informatics, Comenius
3    * University, Bratislava. This file is protected by the Mozilla Public License
4    * version 1.1 (the License); you may not use this file except in compliance
5    * with the License. You may obtain a copy of the License at
6    * http://euromath2.sourceforge.net/license.html Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is
8    * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9    * KIND, either express or implied. See the License for the specific language
10   * governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.editor;
13  
14  import java.lang.reflect.InvocationTargetException;
15  import java.lang.reflect.Method;
16  import java.util.ArrayList;
17  import java.util.List;
18  
19  import org.eclipse.core.runtime.IPath;
20  import org.eclipse.core.runtime.IProgressMonitor;
21  import org.eclipse.core.runtime.IStatus;
22  import org.eclipse.jface.dialogs.MessageDialog;
23  import org.eclipse.swt.SWT;
24  import org.eclipse.swt.events.SelectionAdapter;
25  import org.eclipse.swt.events.SelectionEvent;
26  import org.eclipse.swt.widgets.Menu;
27  import org.eclipse.swt.widgets.MenuItem;
28  import org.eclipse.ui.IEditorInput;
29  import org.eclipse.ui.IEditorSite;
30  import org.eclipse.ui.PartInitException;
31  import org.eclipse.ui.part.MultiPageEditorPart;
32  import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
33  
34  import sk.baka.ikslibs.interval.DOMIntervalSet;
35  import sk.uniba.euromath.EuroMath;
36  import sk.uniba.euromath.document.XMLAccess;
37  import sk.uniba.euromath.editor.lang.ErrorMessages;
38  import sk.uniba.euromath.editor.lang.Messages;
39  import sk.uniba.euromath.plugin.views.outline.XMLOutlinePage;
40  
41  /***
42   * <h6>Is an IEditorPart suporting views</h6>
43   * <p>
44   * For every opening file = IEditorInput new instance is created by workbench
45   * (or by us, somewhere in rcp, openfilewizard) and view for file is added.
46   * </p>
47   * <p>
48   * For opened file new view can be opened by invoking ViewPopupMenu. Navigation
49   * between views is provided by pages localized at left-bottom of editor
50   * control, there can be also invoked ViewPopupMenu.
51   * </p>
52   * <h6>View is presented by EditorSite located on page within this editor.</h6>
53   * <p>
54   * View is defined by selecting XSLT transformation, stylesheet. So views
55   * differs by XSLT transformation used on common input with other views - edited
56   * document. View implements IEditorPart, is a true compound editor and must be
57   * EditorSite or extended.
58   * </p>
59   * 
60   * @author Tomáš Studva 31.7.2005
61   */
62  public class MultiViewXMLEditor extends MultiPageEditorPart {
63  
64      /***
65       * Holds IViewListeners.
66       */
67      private final List<IViewListener> listeners = new ArrayList<IViewListener>();
68  
69      /***
70       * Holds resource manipulator.
71       */
72      private XMLResourceManipulator resourceManipulator;
73  
74      /***
75       * With this id is registered as IEditorPart.
76       */
77      public static final String ID = "sk.uniba.euromath.editor.MultiViewXMLEditor"; //$NON-NLS-1$
78  
79      /***
80       * Adds new EditorSite as new view and activate it.
81       */
82      private void addNewView() {
83          try {
84              EditorSite view = new EditorSite(this);
85              int pageIndex = addPage(view, getEditorInput());
86              setActivePage(pageIndex);
87              setPageText(pageIndex, Messages
88                      .getString("MultiViewXMLEditor.ViewCaption") + pageIndex); //$NON-NLS-1$
89              fireViewAdded(view);
90          } catch (PartInitException e) {
91              EuroMath.log(IStatus.ERROR, 0,
92                      "Error during creation of inner editor", e); //$NON-NLS-1$
93              MessageDialog
94                      .openError(
95                              getEditorSite().getWorkbenchWindow().getShell(),
96                              ErrorMessages.getString("Error"), Messages.getString("MultiViewXMLEditor.EditorInitializationError") //$NON-NLS-1$ //$NON-NLS-2$ 
97                                      + e.getLocalizedMessage());
98              return;
99          }
100     }
101 
102     /***
103      * Fires viewAdded event to listeners.
104      * 
105      * @param view
106      *            which was added
107      */
108     private void fireViewAdded(EditorSite view) {
109         for (IViewListener listener : this.listeners) {
110             listener.viewAdded(view);
111         }
112     }
113 
114     /***
115      * Constructor.
116      */
117     public MultiViewXMLEditor() {
118         super();
119     }
120 
121     @Override
122     public Object getAdapter(Class adapter) {
123         if (adapter.equals(IContentOutlinePage.class))
124             return getContentOutlinePage();
125 
126         return super.getAdapter(adapter);
127     }
128 
129     /***
130      * Returns content outline.
131      * 
132      * @return content outline
133      */
134     private XMLOutlinePage getContentOutlinePage() {
135         if (getActiveView() != null)
136             return getActiveView().getOutlinePage();
137         return null;
138     }
139 
140     /***
141      * Tests if outline is created/ready.
142      * 
143      * @return true, if outline is avalaible
144      */
145     public boolean outlineAvailable() {
146         return (getContentOutlinePage() != null);
147     }
148 
149 @Override
150     public void init(IEditorSite site, IEditorInput input)
151             throws PartInitException {
152         super.init(site, input);
153         // load document
154         if (getEditorInput() == null) {
155             throw new PartInitException("null input"); //$NON-NLS-1$
156         }
157         this.resourceManipulator = new XMLResourceManipulator(getEditorInput());
158         try {
159             getResourceManipulator().load();
160         } catch (Exception ex) {
161             PartInitException e = new PartInitException(
162                     "Data loading failed.", ex); //$NON-NLS-1$
163             EuroMath
164                     .log(
165                             IStatus.ERROR,
166                             0,
167                             "Error loading document. Opening file is probably not xml valid/wellformed file.", e); //$NON-NLS-1$
168             MessageDialog.openError(getEditorSite().getShell(), Messages
169                     .getString("ERROR"), //$NON-NLS-1$
170                     Messages.getString("MultiViewXMLEditor.LoadingDocumentError") //$NON-NLS-1$
171                             + ex.getLocalizedMessage());
172         }
173     }    /***
174              * Creates one view = page for document which was just opened or
175              * created.
176              */
177     @Override
178     protected void createPages() {
179         addNewView();
180         setPartName(getEditorInput().getName());
181         setContentDescription(getEditorInput().getToolTipText());
182         getContainer().setMenu(createViewPopupMenu());
183     }
184 
185     /***
186      * Checks if input is correct.
187      */
188     @Override
189     protected void setInput(IEditorInput input) {
190         // ensure that the input is LocalFilesystemEditorInput or
191         // NewDocumentEditorInput
192         if ((input instanceof LocalFilesystemEditorInput)
193                 || (input instanceof NewDocumentEditorInput)) {
194             super.setInput(input);
195             return;
196         }
197         // it is probably IFileEditorInput, however we don't have ui.ide plugin
198         // linked. Try to use reflection and retrieve the result of getFile()
199         // function.
200         Object ifile;
201         try {
202             final Method m = input.getClass().getDeclaredMethod("getFile", //$NON-NLS-1$
203                     new Class[] {});
204             ifile = m.invoke(input, (Object[]) null);
205             if (ifile == null)
206                 throw new NullPointerException("file is null"); //$NON-NLS-1$
207         } catch (NoSuchMethodException ex) {
208             throw new IllegalArgumentException(
209                     "input does not define getFile() method", ex); //$NON-NLS-1$
210         } catch (InvocationTargetException ex) {
211             throw new RuntimeException("getFile() has thrown an exception", ex); //$NON-NLS-1$
212         } catch (IllegalAccessException ex) {
213             throw new IllegalArgumentException(ex);
214         }
215         // convert this IFile to IPath using getFullPath function (or
216         // getRawLocation() function on eclipse 3.1.1)
217         try {
218             Method m;
219             try {
220                 m = ifile.getClass()
221                         .getMethod("getRawLocation", new Class[] {}); //$NON-NLS-1$
222             } catch (NoSuchMethodException ex) {
223                 m = ifile.getClass().getMethod("getFullPath", //$NON-NLS-1$
224                         new Class[] {});
225             }
226             final IPath path = (IPath) m.invoke(ifile, (Object[]) null);
227             if (path == null)
228                 throw new NullPointerException("path is null"); //$NON-NLS-1$
229             super.setInput(new LocalFilesystemEditorInput(path, input));
230         } catch (NoSuchMethodException ex) {
231             throw new IllegalArgumentException(
232                     "IFile does not define getFullPath() nor getRawLocation() method", ex); //$NON-NLS-1$
233         } catch (InvocationTargetException ex) {
234             throw new RuntimeException(
235                     "getFullPath() has thrown an exception", ex); //$NON-NLS-1$
236         } catch (IllegalAccessException ex) {
237             throw new IllegalArgumentException(ex);
238         }
239     }
240 
241     /***
242      * Creates popup menu for opening new view and closing opened.
243      * 
244      * @return menu with open and close view actions.
245      */
246     private Menu createViewPopupMenu() {
247         Menu result = new Menu(getContainer());
248 
249         MenuItem item;
250         // NEW Presentation page:
251         item = new MenuItem(result, SWT.NONE);
252         item.setText(Messages
253                 .getString("MultiViewXMLEditor.OpenPresentationActionText")); //$NON-NLS-1$
254         item.setAccelerator(SWT.CONTROL | SWT.ALT | 'N');
255         item.addSelectionListener(new SelectionAdapter() {
256             @Override
257             public void widgetSelected(SelectionEvent e) {
258                 addNewView();
259             }
260         });
261         // CLOSE active page:
262         item = new MenuItem(result, SWT.NONE);
263         item.setText(Messages
264                 .getString("MultiViewXMLEditor.ClosePresentationActionText")); //$NON-NLS-1$
265         item.setAccelerator(SWT.CONTROL | SWT.ALT | SWT.F4);
266         item.addSelectionListener(new SelectionAdapter() {
267             @Override
268             public void widgetSelected(SelectionEvent e) {
269                 closeActiveView();
270             }
271         });
272         return result;
273     }
274 
275     /***
276      * Closes active view.
277      * 
278      */
279     public void closeActiveView() {
280         if (getPageCount() == 1)
281             return;
282         if (getActiveView() != null) {
283             removePage(getActivePage());
284         }
285     }
286 
287     /***
288      * Return active view.
289      * 
290      * @return EditorSite
291      */
292     public EditorSite getActiveView() {
293         return (EditorSite) getActiveEditor();
294     }
295 
296     /***
297      * Returns the document instance.
298      * 
299      * @return the document instance.
300      */
301     public final XMLAccess getXMLAccess() {
302         return getResourceManipulator().getXmlAccess();
303     }
304 
305     /***
306      * When view is activated, selection is synchronized with outline.
307      */
308     @Override
309     protected void pageChange(int newPageIndex) {
310         super.pageChange(newPageIndex);
311         if (outlineAvailable()) {
312             DOMIntervalSet sel = getContentOutlinePage().getDOMSelection();
313             getActiveView().setSelection(sel);
314         }
315     }
316 
317     @Override
318     public void doSave(IProgressMonitor monitor) {
319         if (getPageCount() > 0)
320             getActiveView().doSave(monitor);
321     }
322 
323     @Override
324     public void doSaveAs() {
325         if (getPageCount() > 0)
326             getActiveView().doSaveAs();
327     }
328 
329     @Override
330     public boolean isSaveAsAllowed() {
331         return (getPageCount() > 0) && getActiveView().isSaveAsAllowed();
332     }
333 
334     /***
335      * Adds view listener.
336      * 
337      * @param listener
338      *            to add
339      */
340     public void addViewListener(IViewListener listener) {
341         this.listeners.add(listener);
342     }
343 
344     /***
345      * Removes view listener.
346      * 
347      * @param listener
348      *            to remove
349      */
350     public void removeViewListener(IViewListener listener) {
351         this.listeners.remove(listener);
352     }
353 
354     // protected List<IViewListener> getListeners() {
355     // return this.listeners;
356     // }
357     // TODO Studva> Moto: dal som prec tento getter, pretoze EventManager v
358     // e3.2m4 obsahuje final getListeners(). Mozno by
359     // nebolo zle pozriet na jeho funkcionalitu.
360     // >> Nebolo by to zle, ale rad by som si podrzal spatnu kompatibilitu s e3.1 pokym nevyjde plna e3.2
361     // >> takze plz pozri sa na to, ale zatial to nechaj ako to bolo predtym.
362 
363     /***
364      * @return Returns the resourceManipulator.
365      */
366     public XMLResourceManipulator getResourceManipulator() {
367         return this.resourceManipulator;
368     }
369 
370 }