/******************************************************************************* * Copyright (c) 2010-2015 Henshin developers. 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: * TU Berlin, University of Luxembourg, SES S.A. *******************************************************************************/ package de.tub.tfs.muvitor.ui; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.ecore.EObject; import org.eclipse.gef.GraphicalViewer; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.ISelectionService; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.part.IPage; import org.eclipse.ui.part.IPageBookViewPage; import org.eclipse.ui.part.MessagePage; import org.eclipse.ui.part.PageBook; import org.eclipse.ui.part.PageBookView; import de.tub.tfs.muvitor.ui.utils.MuvitorNotifierService; /** * This is a {@link PageBookView} for displaying some model {@link EObject} on * an {@link IPage}. It is merely a wrapper for the contained * {@link MuvitorPage} implementing {@link IPage}, as this is the only * possibility Eclipse offers to show a customized page in a workbench view. The * {@link GraphicalViewer}s for editing are hosted in this {@link MuvitorPage}. * * <p> * <b> The user has to implement {@link #createPageForModel(EObject)} to * instantiate a {@link MuvitorPage} that is able to display or even edit the * model. </b> * </p> * * <p> * The model to show is determined by the following mechanism: <br> * It is expected that this view is opened via a call * {@link MuvitorTreeEditor#showView(String, EObject)} where * <ul> * <li>the first string is the viewID to that this view has been registered with * in the plugin.xml. * <li>model is the model to be displayed. * </ul> * This call sets the EObject's unique ID for the model as secondary ID of this * view. So, the model to be shown can be determined by the secondary ID. * </p> * * <p> * The AbstractTreeEditor instance will hide this view when its model is being * deleted (for details see how {@link IDUtil#getIDForModel(EObject)} employs * the Muvitor's {@link MuvitorNotifierService}). * </p> * * <p> * Additionally this view registers itself an EMF adapter to the model * {@link EObject} that reacts on notifications of the EMF model. For this, * subclasses may override {#notifyChanged(Notification)}, especially to update * the name of this {@link IViewPart} according to the model. For this, * {@link #calculatePartName()} must be implemented to represent the model's * name as a string. * </p> * * <p> * This class is based roughly on ContentOutline but does not provide selections * e.g. to {@link ISelectionService}s. Selection are handled by the * {@link MuvitorPage}s. * </p> * * @author Tony Modica */ public abstract class MuvitorPageBookView extends PageBookView { /** * The EMF adapter listening to the EObject shown in this view. */ final private Adapter adapter = new AdapterImpl() { @Override public void notifyChanged(final Notification msg) { MuvitorPageBookView.this.notifyChanged(msg); } }; private IEditorPart editor; /** * The model to be displayed in the view's page. */ private EObject model; /** * Not very elegant but I do not see another possibility to check whether * the page is shown */ private boolean pageShown = false; /** * @return */ final public IEditorPart getEditor() { /* * TODO try new getEditor() FIXED this better has to be stored lazily, * when disposing this view the model may already have been removed from * the model so that no host editor can be found */ if (editor == null) { // if model has been determined we can get the editor via the model if (model != null) { // final IWorkbenchPart editor = IDUtil.getHostEditor(model); // if (editor != null) // return editor; editor = IDUtil.getHostEditor(model); } // otherwise this view is going to be opened now, so just get the // active editor final IWorkbenchPage page = getSite().getPage(); if (page != null) { editor = page.getActiveEditor(); } } return editor; } /** * @return the model */ final public EObject getModel() { return model; } /* * (non-Javadoc) * @see * org.eclipse.ui.IPartListener#partBroughtToTop(org.eclipse.ui.IWorkbenchPart * ) */ @Override final public void partActivated(final IWorkbenchPart part) { // bring parent editor to top if (part == this) { getSite().getPage().bringToTop(getBootstrapPart()); } else { super.partActivated(part); } } /* * (non-Javadoc) * @seeorg.eclipse.ui.part.PageBookView#partBroughtToTop(org.eclipse.ui. * IWorkbenchPart) */ @Override final public void partBroughtToTop(final IWorkbenchPart part) { // react on editor brought to top; page book views just work this way super.partActivated(part); } @Override public void setFocus() { // FIXED avoid a strange SWTError that occurs only when closing an // editor after restoring it if (getPageBook() != null && !getPageBook().isDisposed()) { super.setFocus(); } } /** * @return The name this part should be set to, e.g. the name of the shown * model accessible via {@link #getModel()}. */ abstract protected String calculatePartName(); /* * (non-Javadoc) * @see * org.eclipse.ui.part.PageBookView#createDefaultPage(org.eclipse.ui.part * .PageBook) */ @Override final protected IPage createDefaultPage(final PageBook book) { final MessagePage defaultPage = new MessagePage(); initPage(defaultPage); defaultPage.createControl(book); defaultPage.setMessage("The Editor did not return a model for ID: " + getViewSite().getSecondaryId() + " or some other nasty error has occured!"); return defaultPage; } /** * Subclasses must implement this method to create a {@link IPage} that * displays the model. It may be advisable to ensure the model being an * instance of the intended class(es) here. * * @param forModel * The model to be displayed in the page. * @return An {@link IPage} displaying the passed model. */ abstract protected IPage createPageForModel(EObject forModel); /** * Subclasses may override but must call super. * {@link #doCreatePage(IWorkbenchPart)}. Note that this method returns a * PageRec only once and <code>null</code> afterwards!. * * @return A PageRec with a new Page for the model determined by the * secondaryID which is being resolved via {@link IDUtil}. * * @see #createPageForModel(Object) */ /* * (non-Javadoc) * @see * org.eclipse.ui.part.PageBookView#doCreatePage(org.eclipse.ui.IWorkbenchPart * ) */ @Override protected PageRec doCreatePage(final IWorkbenchPart editor) { if (pageShown) { // we already have a page shown (which will not be replaced) return null; } final String secondaryID = getViewSite().getSecondaryId(); if (secondaryID == null) return null; model = IDUtil.getModelForID(secondaryID); // show default error page if no model is returned by the editor if (null == model) { return null; } // register for listening for notifications on the model model.eAdapters().add(adapter); // create page for the model final IPage page = createPageForModel(model); initPage((IPageBookViewPage) page); page.createControl(getPageBook()); // set the part's name for the first time setPartName(calculatePartName()); return new PageRec(editor, page); } /** * Subclasses may override but must call super. * {@link #doDestroyPage(IWorkbenchPart, PageRec)}. */ /* * (non-Javadoc) * @see * org.eclipse.ui.part.PageBookView#doDestroyPage(org.eclipse.ui.IWorkbenchPart * , org.eclipse.ui.part.PageBookView.PageRec) */ @Override protected void doDestroyPage(final IWorkbenchPart part, final PageRec rec) { model.eAdapters().remove(adapter); final IPage page = rec.page; page.dispose(); rec.dispose(); /* * This prevents the page to be layouted causing an SWTError on its * disposed FlyoutComposite. We won't need the page book anyway after * this. */ getPageBook().dispose(); } /* * (non-Javadoc) * @see org.eclipse.ui.part.PageBookView#getBootstrapPart() */ @Override final protected IWorkbenchPart getBootstrapPart() { return getEditor(); } /* * (non-Javadoc) * @see * org.eclipse.ui.part.PageBookView#isImportant(org.eclipse.ui.IWorkbenchPart * ) */ @Override final protected boolean isImportant(final IWorkbenchPart part) { // could just return true, but this optimizes memory footprint a bit return part instanceof MuvitorTreeEditor; } /** * By default, {@link #notifyChanged(Notification)} calls * <code>setPartName(calculatePartName())</code>. * <p> * Subclasses may override but must call super. * {@link #notifyChanged(Notification)} if they do not handle changing the * part name themselves. */ protected void notifyChanged(final Notification msg) { setPartName(calculatePartName()); } /* * (non-Javadoc) * @see * org.eclipse.ui.part.PageBookView#showPageRec(org.eclipse.ui.part.PageBookView * .PageRec) */ @Override final protected void showPageRec(final PageRec pageRec) { // change the active page just once for the first page if (model != null && !pageShown) { pageShown = true; super.showPageRec(pageRec); } } }