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             MessageDialog.openError(getEditorSite().getShell(), Messages
162                     .getString("ERROR"), //$NON-NLS-1$
163                     Messages.getString("MultiViewXMLEditor.LoadingDocumentError") //$NON-NLS-1$
164                             + ex.getLocalizedMessage());
165             PartInitException e = new PartInitException(
166                             "Data loading failed. Opening file is probably not xml valid/wellformed file.", ex); //$NON-NLS-1$
167             throw e;
168         }
169     }    /***
170              * Creates one view = page for document which was just opened or
171              * created.
172              */
173     @Override
174     protected void createPages() {
175         addNewView();
176         setPartName(getEditorInput().getName());
177         setContentDescription(getEditorInput().getToolTipText());
178         getContainer().setMenu(createViewPopupMenu());
179     }
180 
181     /***
182      * Checks if input is correct.
183      */
184     @Override
185     protected void setInput(IEditorInput input) {
186         // ensure that the input is LocalFilesystemEditorInput or
187         // NewDocumentEditorInput
188         if ((input instanceof LocalFilesystemEditorInput)
189                 || (input instanceof NewDocumentEditorInput)) {
190             super.setInput(input);
191             return;
192         }
193         // it is probably IFileEditorInput, however we don't have ui.ide plugin
194         // linked. Try to use reflection and retrieve the result of getFile()
195         // function.
196         Object ifile;
197         try {
198             final Method m = input.getClass().getDeclaredMethod("getFile", //$NON-NLS-1$
199                     new Class[] {});
200             ifile = m.invoke(input, (Object[]) null);
201             if (ifile == null)
202                 throw new NullPointerException("file is null"); //$NON-NLS-1$
203         } catch (NoSuchMethodException ex) {
204             throw new IllegalArgumentException(
205                     "input does not define getFile() method", ex); //$NON-NLS-1$
206         } catch (InvocationTargetException ex) {
207             throw new RuntimeException("getFile() has thrown an exception", ex); //$NON-NLS-1$
208         } catch (IllegalAccessException ex) {
209             throw new IllegalArgumentException(ex);
210         }
211         // convert this IFile to IPath using getFullPath function (or
212         // getRawLocation() function on eclipse 3.1.1)
213         try {
214             Method m;
215             try {
216                 m = ifile.getClass()
217                         .getMethod("getRawLocation", new Class[] {}); //$NON-NLS-1$
218             } catch (NoSuchMethodException ex) {
219                 m = ifile.getClass().getMethod("getFullPath", //$NON-NLS-1$
220                         new Class[] {});
221             }
222             final IPath path = (IPath) m.invoke(ifile, (Object[]) null);
223             if (path == null)
224                 throw new NullPointerException("path is null"); //$NON-NLS-1$
225             super.setInput(new LocalFilesystemEditorInput(path, input));
226         } catch (NoSuchMethodException ex) {
227             throw new IllegalArgumentException(
228                     "IFile does not define getFullPath() nor getRawLocation() method", ex); //$NON-NLS-1$
229         } catch (InvocationTargetException ex) {
230             throw new RuntimeException(
231                     "getFullPath() has thrown an exception", ex); //$NON-NLS-1$
232         } catch (IllegalAccessException ex) {
233             throw new IllegalArgumentException(ex);
234         }
235     }
236 
237     /***
238      * Creates popup menu for opening new view and closing opened.
239      * 
240      * @return menu with open and close view actions.
241      */
242     private Menu createViewPopupMenu() {
243         Menu result = new Menu(getContainer());
244 
245         MenuItem item;
246         // NEW Presentation page:
247         item = new MenuItem(result, SWT.NONE);
248         item.setText(Messages
249                 .getString("MultiViewXMLEditor.OpenPresentationActionText")); //$NON-NLS-1$
250         item.setAccelerator(SWT.CONTROL | SWT.ALT | 'N');
251         item.addSelectionListener(new SelectionAdapter() {
252             @Override
253             public void widgetSelected(SelectionEvent e) {
254                 addNewView();
255             }
256         });
257         // CLOSE active page:
258         item = new MenuItem(result, SWT.NONE);
259         item.setText(Messages
260                 .getString("MultiViewXMLEditor.ClosePresentationActionText")); //$NON-NLS-1$
261         item.setAccelerator(SWT.CONTROL | SWT.ALT | SWT.F4);
262         item.addSelectionListener(new SelectionAdapter() {
263             @Override
264             public void widgetSelected(SelectionEvent e) {
265                 closeActiveView();
266             }
267         });
268         return result;
269     }
270 
271     /***
272      * Closes active view.
273      * 
274      */
275     public void closeActiveView() {
276         if (getPageCount() == 1)
277             return;
278         if (getActiveView() != null) {
279             removePage(getActivePage());
280         }
281     }
282 
283     /***
284      * Return active view.
285      * 
286      * @return EditorSite
287      */
288     public EditorSite getActiveView() {
289         return (EditorSite) getActiveEditor();
290     }
291 
292     /***
293      * Returns the document instance.
294      * 
295      * @return the document instance.
296      */
297     public final XMLAccess getXMLAccess() {
298         return getResourceManipulator().getXmlAccess();
299     }
300 
301     /***
302      * When view is activated, selection is synchronized with outline.
303      */
304     @Override
305     protected void pageChange(int newPageIndex) {
306         super.pageChange(newPageIndex);
307         if (outlineAvailable()) {
308             DOMIntervalSet sel = getContentOutlinePage().getDOMSelection();
309             getActiveView().setSelection(sel);
310         }
311     }
312 
313     @Override
314     public void doSave(IProgressMonitor monitor) {
315         if (getPageCount() > 0)
316             getActiveView().doSave(monitor);
317     }
318 
319     @Override
320     public void doSaveAs() {
321         if (getPageCount() > 0)
322             getActiveView().doSaveAs();
323     }
324 
325     @Override
326     public boolean isSaveAsAllowed() {
327         return (getPageCount() > 0) && getActiveView().isSaveAsAllowed();
328     }
329 
330     /***
331      * Adds view listener.
332      * 
333      * @param listener
334      *            to add
335      */
336     public void addViewListener(IViewListener listener) {
337         this.listeners.add(listener);
338     }
339 
340     /***
341      * Removes view listener.
342      * 
343      * @param listener
344      *            to remove
345      */
346     public void removeViewListener(IViewListener listener) {
347         this.listeners.remove(listener);
348     }
349 
350     // protected List<IViewListener> getListeners() {
351     // return this.listeners;
352     // }
353     // TODO Studva> Moto: dal som prec tento getter, pretoze EventManager v
354     // e3.2m4 obsahuje final getListeners(). Mozno by
355     // nebolo zle pozriet na jeho funkcionalitu.
356     // >> Nebolo by to zle, ale rad by som si podrzal spatnu kompatibilitu s e3.1 pokym nevyjde plna e3.2
357     // >> takze plz pozri sa na to, ale zatial to nechaj ako to bolo predtym.
358 
359     /***
360      * @return Returns the resourceManipulator.
361      */
362     public XMLResourceManipulator getResourceManipulator() {
363         return this.resourceManipulator;
364     }
365 
366 }