/***************************************************************************** * Copyright (c) 2009 CEA LIST & LIFL * * * 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: * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.infra.core.sasheditor.multipage.editor; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IAbstractPanelModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IComponentModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IEditorModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashPanelModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ITabFolderModel; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.MultiPageEditorPart; /** * A MultiPageEditor implementation accepting IMultiSashContentProvider as content provider. * This implementation extends the regular eclipse MultiPageEditorPart. * The refresh() method allows to refresh the tabs. * * The implementation do not listen on model change. This can be done by subclasses. * To add a new tab, one should add it as a model in the ContentProvider. The addPage() * methods should not be used for this purpose. * * This implementation is intended for debug and testing purpose : it can be used in place * of the AbstractMultiPageSashEditor. It takes the same arguments and ContentProvider, but * it only allows one folder and don't deal with multisashes. * Also, the implementation use the regular Eclipse EditorSite management. This allows to check for problems from this * site management. * * @author dumoulin */ public abstract class MultiPageEditor extends MultiPageEditorPart { /** Log object */ protected Logger log = Logger.getLogger(getClass().getName()); /** The pageProvider */ private ISashWindowsContentProvider pageProvider; /** * The tabfolder model providing the pages that must be shown. */ private ITabFolderModel tabFolderModel; /** Ordered set of currently shown diagrams */ protected List<IPageModel> currentTabs = new ArrayList<IPageModel>(); /** * Constructor. */ public MultiPageEditor() { super(); } /** * This method is called at the end of createPartControl(). * Just intercept the call in order to call activate(). * Create the part controls. {@inheritDoc} */ @Override protected void initializePageSwitching() { super.initializePageSwitching(); activate(); } /** * Method to activate the editor. * Called immediately after createPartControl() is complete. * To be implemented by subclasses. Default implementation do nothing. */ protected void activate() { } /** * Method to deactivate the editor. * Called when dispose() is called. * To be implemented by subclasses. Default implementation do nothing. */ protected void deactivate() { } /** * Dispose the Editor. Also dispose the sashsystem. * * @see org.eclipse.ui.part.WorkbenchPart#dispose() * */ @Override public void dispose() { deactivate(); super.dispose(); // sashContainer.dispose(); } @Override public Object getAdapter(Class adapter) { // Get the content provider if requested. if(ISashWindowsContentProvider.class == adapter) return getContentProvider(); return super.getAdapter(adapter); } /** * get the contentProvider. Create it if necessary. * * @return */ protected ISashWindowsContentProvider getContentProvider() { if(pageProvider == null) pageProvider = createPageProvider(); return pageProvider; } /** * @param pageProvider * the pageProvider to set */ protected void setContentProvider(ISashWindowsContentProvider pageProvider) { this.pageProvider = pageProvider; } /** * Add a page containing the Component described by the provided model. * * @param tabItem */ protected int addPage(IComponentModel tabItem) { Composite composite = tabItem.createPartControl(getContainer()); int index = addPage(composite); setPageText(index, tabItem.getTabTitle()); Image image = tabItem.getTabIcon(); if(image != null) setPageImage(index, image); return index; } /** * Add the editor corresponding to the model to the folder. * * @param editorModel */ protected int addPage(IEditorModel editorModel) { try { IEditorPart editor = editorModel.createIEditorPart(); int index = addPage(editor, getEditorInput()); setPageText(index, editorModel.getTabTitle()); Image image = editorModel.getTabIcon(); if(image != null) setPageImage(index, image); return index; } catch (PartInitException e) { ErrorDialog.openError( getSite().getShell(), "Error creating nested text editor", null, e.getStatus()); return -1; } } /** * Creates the pages of the multi-page editor. */ protected void createPages() { // get the page descriptions pageProvider = getContentProvider(); // Get the current tabFolder // tabFolderModel = lookupFolder(); refreshTabs(); // // iterate over pages to be show // for( Object rawPageModel : tabFolderModel.getChildren() ) // { // // Get the model interface // ITabItemModel tabItem = tabFolderModel.createChildSashModel( rawPageModel); // if(tabItem instanceof IEditorModel ) // { // addPage((IEditorModel)tabItem ); // } // else if(tabItem instanceof IComponentModel ) // { // addPage((IComponentModel)tabItem ); // } // else // { // System.err.println("Can't create page for model '" + tabItem + "'. Skipp it."); // } // } } /** * Lookup for a folder in the SashModel. Return the first folder found. * * @return */ private ITabFolderModel lookupFolder() { if(pageProvider == null) return null; Object rawModel = pageProvider.getRootModel(); IAbstractPanelModel panelModel = pageProvider.createChildSashModel(rawModel); return lookupFolder(panelModel); } /** * Recursively search in sash models for a FolderModel. * Return the first encountered folder. * * @param panelModel * @return */ private ITabFolderModel lookupFolder(IAbstractPanelModel panelModel) { if(panelModel instanceof ITabFolderModel) return (ITabFolderModel)panelModel; else { ISashPanelModel sashModel = (ISashPanelModel)panelModel; // Iterate on children for(Object child : sashModel.getChildren()) { IAbstractPanelModel childModel = pageProvider.createChildSashModel(child); ITabFolderModel res = lookupFolder(childModel); if(res != null) return res; } } // Not found return null; } /** * Create the provider. * Subclass must implements this method. It should return the provider used by the editor. * */ abstract protected ISashWindowsContentProvider createPageProvider(); /** * Refresh the tabs order. * This method should be called after the model list is modified. */ protected void refreshTabs() { // get list of diagrams to be displayed List<?> newModels = tabFolderModel.getChildren(); // Check if each model has an open pageEditor. If not, create the editor. Iterator<?> newIter = newModels.iterator(); while(newIter.hasNext()) { Object model = newIter.next(); if(!tabExistsFor(model)) { // create a new editor for the model IPageModel pageModel = tabFolderModel.createChildSashModel(model); if(pageModel != null) { addEditor(pageModel); } } } // If open editor count is the same has models count, // all models have an editor. So, end the refresh process. if(newModels.size() == getPageCount()) return; // There is some extra editors ! remove them. // remove extra editors : for each open editor, check if its model is in // the list of required models. List<IPageModel> toBeRemoved = new ArrayList<IPageModel>(); Iterator<IPageModel> currentIter = currentTabs.iterator(); while(currentIter.hasNext()) { IPageModel model = currentIter.next(); if(!newModels.contains(model.getRawModel())) { // remove editor toBeRemoved.add(model); } } // Remove editor from the editors displayed by the multi editor Iterator<IPageModel> removeIter = toBeRemoved.iterator(); while(removeIter.hasNext()) { IPageModel model = removeIter.next(); removeEditor(model); } } /** * Check if an editor exists for the specified model. * * @param model * the diagram (model) that should be displayed * @return <code>true</code> if the editor exists for this model */ private boolean tabExistsFor(Object model) { for(IPageModel tabItem : currentTabs) { if(tabItem.getRawModel() == model) return true; } return false; } /* * (non-Javadoc) * * @see org.eclipse.ui.part.MultiPageEditorPart#removePage(int) */ @Override public void removePage(int pageIndex) { super.removePage(pageIndex); // synchronize the list of currently shown models. currentTabs.remove(pageIndex); } /** * Removes the editor associated to the specified model. * * @param model * the diagram (model) displayed in the editor */ private void removeEditor(IPageModel model) { int index = currentTabs.indexOf(model); removePage(index); } /** * Add a new editor at the end of existing editors. * First, create the editor, then add it to the tabs. * * @param contentProvider * the diagram (model) to be displayed in the editor */ private void addEditor(IPageModel tabItem) { // Check if an editor already exists if(tabExistsFor(tabItem)) { if(log.isLoggable(Level.FINE)) log.fine("Editor already exists for '" + tabItem + "'"); return; } int editorIndex = -1; if(tabItem instanceof IEditorModel) { editorIndex = addPage((IEditorModel)tabItem); } else if(tabItem instanceof IComponentModel) { editorIndex = addPage((IComponentModel)tabItem); } else { System.err.println("Can't create page for model '" + tabItem + "'. Skipp it."); return; } // Add the model in the list of current tabs. currentTabs.add(tabItem); // set active page setActivePage(editorIndex); } }