/******************************************************************************* * Copyright (c) 2004, 2006 Sybase, Inc. and others. * * 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: * Sybase, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.jst.jsf.facesconfig.ui; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EventObject; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.command.BasicCommandStack; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.domain.IEditingDomainProvider; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory; import org.eclipse.gef.commands.CommandStack; import org.eclipse.gef.commands.CommandStackListener; import org.eclipse.gef.editparts.ZoomManager; import org.eclipse.gef.ui.actions.ActionRegistry; import org.eclipse.gef.ui.actions.EditorPartAction; import org.eclipse.gef.ui.actions.SaveAction; import org.eclipse.gef.ui.actions.UpdateAction; import org.eclipse.gef.ui.views.palette.PaletteView; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jst.jsf.common.ui.internal.actions.IOpenPage; import org.eclipse.jst.jsf.core.IJSFCoreConstants; import org.eclipse.jst.jsf.facesconfig.edit.provider.FacesConfigItemProviderAdapterFactory; import org.eclipse.jst.jsf.facesconfig.emf.FacesConfigType; import org.eclipse.jst.jsf.facesconfig.ui.page.ComponentsPage; import org.eclipse.jst.jsf.facesconfig.ui.page.IntroductionPage; import org.eclipse.jst.jsf.facesconfig.ui.page.ManagedBeanPage; import org.eclipse.jst.jsf.facesconfig.ui.page.OthersPage; import org.eclipse.jst.jsf.facesconfig.ui.page.OverviewPage; import org.eclipse.jst.jsf.facesconfig.ui.page.WaitForLoadPage; import org.eclipse.jst.jsf.facesconfig.ui.pageflow.DelegatingZoomManager; import org.eclipse.jst.jsf.facesconfig.ui.pageflow.PageflowEditor; import org.eclipse.jst.jsf.facesconfig.ui.pageflow.command.DelegatingCommandStack; import org.eclipse.jst.jsf.facesconfig.ui.pageflow.command.EMFCommandStackGEFAdapter; import org.eclipse.jst.jsf.facesconfig.ui.pageflow.layout.PageflowLayoutManager; import org.eclipse.jst.jsf.facesconfig.ui.preference.GEMPreferences; import org.eclipse.jst.jsf.facesconfig.util.FacesConfigArtifactEdit; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorActionBarContributor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.contexts.IContextService; import org.eclipse.ui.dialogs.SaveAsDialog; import org.eclipse.ui.forms.editor.FormEditor; import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.ide.IGotoMarker; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; import org.eclipse.wst.common.project.facet.core.IFacetedProject; import org.eclipse.wst.common.project.facet.core.IProjectFacet; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; import org.eclipse.wst.sse.ui.StructuredTextEditor; /** * This is the main editor for the faces-config file. Note that the model * load can involve long-running socket operations (shouldn't but can), * so the editor UI is load asynchronously. This is means that any * operations that need to be executed on editor open should be run * using AddPagesTask.pageSafeExecute() to ensure that they occur * after all editor pages have finished loading. * * @author sfshi * */ public class FacesConfigEditor extends FormEditor implements IEditingDomainProvider, ISelectionProvider { /** * This editor's ID. TODO: this should prob be in plugin.properties? */ public static final String EDITOR_ID = "org.eclipse.jst.jsf.facesconfig.ui.FacesConfigEditor"; //$NON-NLS-1$ /** * Page id for Source page. Used for testing only. */ public static final String SOURCE_PAGE_ID = "SourcePageId"; //$NON-NLS-1$ /** * editing domain that is used to track all changes to the model */ private AdapterFactoryEditingDomain editingDomain; /** * adapter factory used for providing views of the model */ private ComposedAdapterFactory adapterFactory; private int overviewPageID; /** id of the pageflowPage */ private int pageflowPageID; private int managedBeanPageID; private int componentsPageID; private int othersPageID; private int sourcePageId; private PageflowEditor pageflowPage; private OverviewPage overviewPage; /** The source text editor. */ private StructuredTextEditor sourcePage; private Collection selectionChangedListeners = new ArrayList(); private ISelection editorSelection = StructuredSelection.EMPTY; private IContentOutlinePage outlinePage; private IProject currentProject; private boolean isWebProject; private ModelLoader _modelLoader; /** * only true once dispose() has been called * used to signal that the editor was disposed. */ private boolean _isDisposed; // = false; /** * Used to load editor pages when the model is loaded */ private final AddPagesTask _addPagesTask = new AddPagesTask(); /** * Default constructor */ public FacesConfigEditor() { initializeEMF(); } /** * This listens for workspace changes. <!-- begin-user-doc --> <!-- * end-user-doc --> * * @generated */ protected IResourceChangeListener resourceChangeListener = new IResourceChangeListener() { public void resourceChanged(IResourceChangeEvent event) { // Only listening to these. // if (event.getType() == IResourceDelta.POST_CHANGE) { IResourceDelta delta = event.getDelta(); try { class ResourceDeltaVisitor implements IResourceDeltaVisitor { protected ResourceSet resourceSet = editingDomain .getResourceSet(); @SuppressWarnings("hiding") protected Collection changedResources = new ArrayList(); @SuppressWarnings("hiding") protected Collection removedResources = new ArrayList(); public boolean visit(IResourceDelta delta_) { if (delta_.getFlags() != IResourceDelta.MARKERS && delta_.getResource().getType() == IResource.FILE) { if ((delta_.getKind() & (IResourceDelta.CHANGED | IResourceDelta.REMOVED)) != 0) { Resource resource = resourceSet .getResource(URI.createURI(delta_ .getFullPath().toString()), false); if (resource != null) { if ((delta_.getKind() & IResourceDelta.REMOVED) != 0) { removedResources.add(resource); } else { changedResources.add(resource); } } } } return true; } public Collection getChangedResources() { return changedResources; } public Collection getRemovedResources() { return removedResources; } } ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(); delta.accept(visitor); if (!visitor.getRemovedResources().isEmpty()) { removedResources.addAll(visitor.getRemovedResources()); if (!isDirty()) { getSite().getShell().getDisplay().asyncExec( new Runnable() { public void run() { getSite().getPage().closeEditor( FacesConfigEditor.this, false); FacesConfigEditor.this.dispose(); } }); } } if (!visitor.getChangedResources().isEmpty()) { changedResources.addAll(visitor.getChangedResources()); } } catch (CoreException exception) { // log it. EditorPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, EditorPlugin .getPluginId(), IStatus.OK, exception .getMessage() == null ? "" : exception //$NON-NLS-1$ .getMessage(), exception)); } } } }; /** * Resources that have been removed since last activation. * * @generated */ Collection removedResources = new ArrayList(); /** * Resources that have been changed since last activation. * * @generated */ Collection changedResources = new ArrayList(); /** * Resources that have been saved. * * @generated */ Collection savedResources = new ArrayList(); /** * Initializes the EMF support. */ private void initializeEMF() { // create an adapter factory that yields item providers List factories = new ArrayList(); factories.add(new ResourceItemProviderAdapterFactory()); factories.add(new FacesConfigItemProviderAdapterFactory()); factories.add(new ReflectiveItemProviderAdapterFactory()); adapterFactory = new ComposedAdapterFactory(factories); // create the command stack that will notify this editor as commands are // executed BasicCommandStack commandStack = new BasicCommandStack(); commandStack .addCommandStackListener(new org.eclipse.emf.common.command.CommandStackListener() { public void commandStackChanged(final EventObject event) { getContainer().getShell().getDisplay().asyncExec( new Runnable() { public void run() { editorDirtyStateChanged(); getActionBarContributor() .updateActionBars(); } }); } }); // commandStack.addCommandStackListener(this); // create the editing domain with a special command stack editingDomain = new AdapterFactoryEditingDomain(adapterFactory, commandStack, new HashMap()); } /* * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite, * org.eclipse.ui.IEditorInput) */ public void init(IEditorSite site, IEditorInput input) throws PartInitException { try { super.init(site, input); } catch (Exception e) { MessageDialog.openError(null, EditorMessages.FacesConfigEditor_Error_OpenModel_Title, EditorMessages.FacesConfigEditor_Error_OpenModel); throw new PartInitException( EditorMessages.FacesConfigEditor_Error_OpenModel); } setPartName(input.getName()); if (!isValidInput(input)) { PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getActivePage().openEditor(input, "org.eclipse.ui.DefaultTextEditor"); //$NON-NLS-1$ close(false); return; } //Bug 291054 - faces-config should be checked out if the user tries to modify it if (input instanceof IFileEditorInput) { IFile file = ((IFileEditorInput)input).getFile(); if (file.isReadOnly()) { file.getWorkspace().validateEdit(new IFile[]{file}, site != null ? site.getShell() : null); } } //Bug 191494 - Unable to switch pages in faces config editor without mouse // Activate plugin context IContextService contextService = (IContextService) getSite() .getService(IContextService.class); contextService .activateContext("org.eclipse.jst.jsf.facesconfig.editorContext"); //$NON-NLS-1$ createActions(); ResourcesPlugin.getWorkspace().addResourceChangeListener( resourceChangeListener, IResourceChangeEvent.POST_CHANGE); } /* * @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput) */ protected void setInput(IEditorInput input) { isWebProject = matches(input); super.setInput(input); IFile inputFile = (IFile) input.getAdapter(IFile.class); if (inputFile != null) { final IProject project = inputFile.getProject(); final IPath inputPath = inputFile.getFullPath(); _modelLoader = new ModelLoader(); _modelLoader.load(project, inputPath, isWebProject, _addPagesTask); } } protected void addPages() { // try loading wait page // if we get to here before model load completes, // then wait page will give the user the indication // that something is happening in the background before // the editor full loads. // if the model is already loaded, this call should do nothing _addPagesTask.maybeAddWaitPage(); } /** * This runnable is used to used to manage the loading of the * editor pages for editor in a deferred fashion. Because the model * loading for this editor can be noticably long and (unfortunately) * may involve socket calls that block, loadModel(), runs this on a * separate thread. This class is intended to be used in two ways: * * 1) by the model loading code to signal it is finished by executing * the run() via a display.asyncExec(). * * 2) by the addPages() call back on the the main editor as a way to * load a "Please wait for loading" page if the loading is still running * by the time the editor is ready to visualize itself. * * Note that in both cases methods of this class *must* be running on the * main display thread. * * @author cbateman * */ private class AddPagesTask extends ModelLoader.ModelLoaderComplete { private final AtomicBoolean _arePagesLoaded = new AtomicBoolean(false); // set to true when the regular editor pages are loaded private FormPage _waitPage; private List<Runnable> _deferredRunnables = new ArrayList<Runnable>(); /** * If the editor pages are loaded, runnable.run() is invoked immediately * If the editor pages are not loaded yet, runnable is queued and will be * executed in the order they are added immediately after the pages are loaded * * @param runnable */ public synchronized void pageSafeExecute(Runnable runnable) { if (!_isDisposed) { if (!_arePagesLoaded.get()) { _deferredRunnables.add(runnable); } else { runnable.run(); } } } /** * @return true if the pages are loaded */ public synchronized boolean getArePagesLoaded() { return _arePagesLoaded.get(); } /** * Remove the wait page if present. */ public synchronized void removeWaitPage() { if (_waitPage != null && !_waitPage.getPartControl().isDisposed()) { int index = _waitPage.getIndex(); if (index >= 0) { removePage(index); } } } /** * Add the wait page if the main pages aren't already loaded */ public synchronized void maybeAddWaitPage() { // only load the wait page if the other pages haven't been loaded if (!getArePagesLoaded()) { _waitPage = new WaitForLoadPage(FacesConfigEditor.this, "WaitForLoad", EditorMessages.FacesConfigEditor_WaitForLoad_EditorTabTitle); //$NON-NLS-1$ try { addPage(0,_waitPage); } catch(PartInitException pie) { _waitPage =null; EditorPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, EditorPlugin.getPluginId(), IStatus.OK, pie.getMessage() == null ? "" : pie //$NON-NLS-1$ .getMessage(), pie)); } } } /** * Must be run on the UI thread */ public void doRun(FacesConfigArtifactEdit edit) { synchronized(this) { // ensure wait page gets removed removeWaitPage(); if (!getArePagesLoaded() && !_isDisposed) // NOTE: we assume that access to variable does not need to // to be synchronous since this method must // be run on the UI thread. The only way // that isDisposed should be true is if model loading took a long // time and the user closed the editor before it completed (trigger dispose to be called) { try { if (isWebProject && edit != null && edit.getFacesConfig() != null) { // only add the intro editor if the preference // is set to do so. if (GEMPreferences.getShowIntroEditor()) { IntroductionPage page1 = new IntroductionPage(FacesConfigEditor.this); addPage(page1, FacesConfigEditor.this.getEditorInput()); } overviewPage = new OverviewPage(FacesConfigEditor.this); overviewPageID = addPage(overviewPage, FacesConfigEditor.this.getEditorInput()); // Page flow createAndAddPageflowPage(); // pages IFormPage managedBeanPage = new ManagedBeanPage(FacesConfigEditor.this); managedBeanPageID = addPage(managedBeanPage, FacesConfigEditor.this.getEditorInput()); IFormPage componentsPage = new ComponentsPage(FacesConfigEditor.this); componentsPageID = addPage(componentsPage, FacesConfigEditor.this.getEditorInput()); IFormPage othersPage = new OthersPage(FacesConfigEditor.this); othersPageID = addPage(othersPage, FacesConfigEditor.this.getEditorInput()); } sourcePage = new StructuredTextEditor(); sourcePage.setEditorPart(FacesConfigEditor.this); sourcePageId = addPage(sourcePage, FacesConfigEditor.this.getEditorInput()); setPageText(sourcePageId, EditorMessages.FacesConfigEditor_Source_TabName); sourcePage.update(); /* * Bug 335276 - compile errors with near M5 platform * * Code previously added to address Bug 263806 relied on internal classes * that have since been removed. Bug 263806 no longer requires the code that * was added in order to function correctly, and so the old fix for Bug * 263806 has simply been removed. */ // default active page to 0 setActivePage(0); // execute deferred runnables for (Runnable runnable : _deferredRunnables) { runnable.run(); } // flag the fact that the regular editor pages have been added _arePagesLoaded.set(true); } catch (PartInitException e) { EditorPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, EditorPlugin.getPluginId(), IStatus.OK, e.getMessage() == null ? "" : e //$NON-NLS-1$ .getMessage(), e)); } } } } } /** * Creates the pageflow page of the multi-page editor. * @throws PartInitException */ protected void createAndAddPageflowPage() throws PartInitException { pageflowPage = new PageflowEditor(this); pageflowPageID = addPage(pageflowPage, getEditorInput()); setPageText(pageflowPageID, EditorMessages.FacesConfigEditor_Pageflow_TabName); addPageActionRegistry(pageflowPage); pageflowPage.getModelsTransform().setFacesConfig(getFacesConfig()); pageflowPage.getModelsTransform().setPageflow( pageflowPage.getPageflow()); boolean fornew = pageflowPage.getModelsTransform() .updatePageflowModelFromEMF(); pageflowPage.setGraphicalViewerContents(pageflowPage.getPageflow()); if (fornew) { PageflowLayoutManager.getInstance().layoutPageflow( pageflowPage.getPageflow()); } pageflowPage.getModelsTransform().setListenToNotify(true); } /** * TODO: this is used only for testing * @return the page flow editor */ public PageflowEditor getPageflowPage() { return pageflowPage; } /** * get the action's registry of sub pages. * @param page * */ protected void addPageActionRegistry(IEditorPart page) { if (page != null) { ActionRegistry pageActionRegisty = (ActionRegistry) page .getAdapter(ActionRegistry.class); if (pageActionRegisty != null) { for (Iterator iter = pageActionRegisty.getActions(); iter .hasNext();) { getActionRegistry().registerAction((IAction) iter.next()); } } } } /** the editor's action registry */ private ActionRegistry actionRegistry = null; /** * Returns the action registry of this editor. * * @return - the action registry */ protected ActionRegistry getActionRegistry() { if (null == actionRegistry) actionRegistry = new ActionRegistry(); return actionRegistry; } /** * Returns the root object of the configuration model. * * @return the root object. Should not, but may return null. */ public FacesConfigType getFacesConfig() { FacesConfigArtifactEdit edit = _modelLoader.getEdit(); if (edit != null) { return edit.getFacesConfig(); } return null; } /* * @see org.eclipse.ui.ISaveablePart#isDirty() */ public boolean isDirty() { return ((BasicCommandStack) editingDomain.getCommandStack()) .isSaveNeeded() || super.isDirty(); } /** * This class listens for command stack changes of the pages contained in * this editor and decides if the editor is dirty or not. */ private class MultiPageCommandStackListener implements CommandStackListener { /** the observed command stacks */ private List commandStacks = new ArrayList(2); /** to get the editorpart from command stack */ private HashMap mapEditorCommandStack = new HashMap(); private boolean saveLocation = false; /** * Adds a <code>CommandStack</code> to observe. * * @param commandStack * @param editor */ public void addCommandStack(CommandStack commandStack, IEditorPart editor) { if (commandStack == null) return; if (mapEditorCommandStack.get(commandStack) == editor) return; commandStacks.add(commandStack); commandStack.addCommandStackListener(this); mapEditorCommandStack.put(commandStack, editor); } /** * set the dirty status for the models of different editor * * @param editor - * editor, e.g., pageflow or databinding page. * @param dirty - * true or false */ private void setEditorDirty(IEditorPart editor, boolean dirty) { // do nothing } /** the list of action ids that are to CommandStack actions */ private List stackActionIDs = new ArrayList(); /** * Updates the specified actions. * * @param actionIds - * the list of ids of actions to update */ private void updateActions(List actionIds) { for (Iterator ids = actionIds.iterator(); ids.hasNext();) { IAction action = getActionRegistry().getAction(ids.next()); if (null != action && action instanceof UpdateAction) { ((UpdateAction) action).update(); } } } /* * (non-Javadoc) * * @see CommandStackListener#commandStackChanged(java.util.EventObject) */ public void commandStackChanged(EventObject event) { // enable or disable the actions updateActions(stackActionIDs); if (((CommandStack) event.getSource()).isDirty()) { // set the editor's model dirty status setEditorDirty((IEditorPart) mapEditorCommandStack .get(event.getSource()), true); // at least one command stack is dirty, // so the multi page editor is dirty too setDirty(true); } else { // set the editor's model dirty status, if it is from not save // location. if (!saveLocation) { setEditorDirty((IEditorPart) mapEditorCommandStack .get(event.getSource()), true); setDirty(true); } else { setDirty(false); } } } /** the pageflow page editor's dirty state */ private boolean isDirty = false; /** * Changes the dirty state. * * @param dirty - * dirty state */ public void setDirty(boolean dirty) { if (isDirty != dirty) { isDirty = dirty; firePropertyChange(IEditorPart.PROP_DIRTY); } } /** * Disposed the listener */ public void dispose() { for (Iterator stacks = commandStacks.iterator(); stacks.hasNext();) { ((CommandStack) stacks.next()).removeCommandStackListener(this); } commandStacks.clear(); } /** * Marks every observed command stack beeing saved. This method should * be called whenever the editor/model was saved. */ public void markSaveLocations() { saveLocation = true; for (Iterator stacks = commandStacks.iterator(); stacks.hasNext();) { CommandStack stack = (CommandStack) stacks.next(); stack.markSaveLocation(); } saveLocation = false; } /** * Flushes every observed command stack and resets the save location to * zero. */ // public void flush() { // for (Iterator stacks = commandStacks.iterator(); stacks.hasNext();) { // CommandStack stack = (CommandStack) stacks.next(); // stack.flush(); // } // } } /** the <code>CommandStackListener</code> */ private MultiPageCommandStackListener multiPageCommandStackListener = null; /** * Returns the global command stack listener. * * @return the <code>CommandStackListener</code> */ protected MultiPageCommandStackListener getMultiPageCommandStackListener() { if (null == multiPageCommandStackListener) multiPageCommandStackListener = new MultiPageCommandStackListener(); return multiPageCommandStackListener; } /* * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor) */ public void doSave(IProgressMonitor monitor) { // do the work within an operation because this is a long running // activity that modifies the workbench WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { public void execute(IProgressMonitor monitor_) { try { if (isWebProject && _modelLoader.getEdit() != null) { // modelResource.save(Collections.EMPTY_MAP); Resource deploymentDescriptorResource = _modelLoader.getEdit() .getDeploymentDescriptorResource(); if (deploymentDescriptorResource != null) { deploymentDescriptorResource.save( Collections.EMPTY_MAP); } IFile file = ((IFileEditorInput) getEditorInput()) .getFile(); pageflowPage.doSave(file, monitor_); } sourcePage.doSave(monitor_); getMultiPageCommandStackListener().markSaveLocations(); } catch (Exception e) { EditorPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, EditorPlugin .getPluginId(), IStatus.OK, e.getMessage() == null ? "" : e //$NON-NLS-1$ .getMessage(), e)); } } }; try { // commit all pending changes in form pages for (Iterator iter = pages.iterator(); iter.hasNext();) { Object obj = iter.next(); if (obj instanceof FormPage) { ((FormPage) obj).doSave(monitor); } // else if (obj instanceof PageflowEditor) { // ((PageflowEditor) obj).doSave(monitor); // } } operation.run(null);// .run(true, false, // operation; // runs the operation, and shows progress // new ProgressMonitorDialog(); // refresh the necessary state ((BasicCommandStack) editingDomain.getCommandStack()).saveIsDone(); editorDirtyStateChanged(); } catch (Exception e) { EditorPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, EditorPlugin.getPluginId(), IStatus.OK, e.getMessage(), e)); } } public void doSaveAs() { SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell()); saveAsDialog.open(); IPath path = saveAsDialog.getResult(); if (path != null) { IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); if (file != null) { doSaveAs(URI.createPlatformResourceURI(file.getFullPath() .toString(), false), new FileEditorInput(file)); } } } /** * @param uri * @param editorInput */ protected void doSaveAs(URI uri, IEditorInput editorInput) { editingDomain.getResourceSet().getResources().get(0) .setURI(uri); setInputWithNotify(editorInput); setPartName(editorInput.getName()); IProgressMonitor progressMonitor = getActionBars() .getStatusLineManager() != null ? getActionBars() .getStatusLineManager().getProgressMonitor() : new NullProgressMonitor(); doSave(progressMonitor); } public boolean isSaveAsAllowed() { return true; } /** * Returns the <code>TabbedPropertySheetPage</code> for this editor. * * @return - the <code>TabbedPropertySheetPage</code> */ protected IPropertySheetPage getPropertySheetPage() { return new TabbedPropertySheetPage( new ITabbedPropertySheetPageContributor() { public String getContributorId() { return EDITOR_ID; } }); } /** the delegating ZoomManager */ private DelegatingZoomManager delegatingZoomManager = null; /** * check whether the input is related with IFile. * * @param input * @return */ private boolean isValidInput(IEditorInput input) { if (input != null) { IFile file = (IFile) input.getAdapter(IResource.class); if (file != null) { return true; } } return false; } /** * Returns the <code>DelegatingZoomManager</code> for this editor. * * @return - the <code>DelegatingZoomManager</code> */ protected DelegatingZoomManager getDelegatingZoomManager() { if ( !isValidInput(getEditorInput()) || !isWebProject || _addPagesTask == null || !_addPagesTask.getArePagesLoaded() || pageflowPage == null) { return null; } if (null == delegatingZoomManager) { delegatingZoomManager = new DelegatingZoomManager(); delegatingZoomManager .setCurrentZoomManager((ZoomManager) pageflowPage .getAdapter(ZoomManager.class)); } return delegatingZoomManager; } /** the delegating CommandStack */ private DelegatingCommandStack delegatingCommandStack = null; /** * Returns the <code>CommandStack</code> for this editor. * * @return - the <code>CommandStack</code> */ public DelegatingCommandStack getDelegatingCommandStack() { if (null == delegatingCommandStack) { delegatingCommandStack = new DelegatingCommandStack(); } return delegatingCommandStack; } /* * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) */ public Object getAdapter(Class adapter) { if (adapter == IEditingDomainProvider.class) { return new IEditingDomainProvider() { public EditingDomain getEditingDomain() { return editingDomain; } }; } if (adapter == EditingDomain.class) { return editingDomain; } if (adapter == AdapterFactory.class) { return adapterFactory; } if (adapter == IEditorPart.class) { return getActiveEditor(); } if (adapter == CommandStack.class) { return getDelegatingCommandStack(); } if (adapter == ZoomManager.class) { return getDelegatingZoomManager(); } if (adapter == ActionRegistry.class) { return getActionRegistry(); } if (adapter == IGotoMarker.class) { return new IGotoMarker() { public void gotoMarker(final IMarker marker) { // this may be called on an editor open (i.e. double-click the Problems view) // so ensure it runs safely with respect to the page load _addPagesTask.pageSafeExecute(new Runnable() { public void run() { FacesConfigEditor.this.gotoMarker(marker); } }); } }; } if (adapter == StructuredTextEditor.class) { return sourcePage; } if (adapter == IContentOutlinePage.class) { return getOutlinePage(); } if (adapter == IPropertySheetPage.class) { return getPropertySheetPage(); } if (adapter == IProject.class) { return getProject(); } if (adapter == CTabFolder.class) { return getContainer(); } if (adapter == IOpenPage.class) { return new IOpenPage() { public void setActiveEditorPage(String pageID) { FacesConfigEditor.this.setActiveEditorPage(pageID); } }; } return super.getAdapter(adapter); } private EMFCommandStackGEFAdapter sourceCommandStack; /** * get or create the source page's GEF command stack based on its EMF * command stack. * * @return */ private CommandStack getSourcePageCommandStack() { if (sourceCommandStack == null) { IDocument doc = sourcePage.getDocumentProvider().getDocument(getEditorInput()); if (doc instanceof IStructuredDocument) { sourceCommandStack = new EMFCommandStackGEFAdapter(doc); } else { EditorPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, EditorPlugin.getPluginId(), 0, "Error getting undo stack for Faces Config editor. Undo may be disabled", //$NON-NLS-1$ new Throwable())); } } return sourceCommandStack; } /** the list of action ids that are to CommandStack actions */ // private List stackActionIDs = new ArrayList(); /** the list of action ids that are editor actions */ private List editorActionIDs = new ArrayList(); /** * Adds an editor action to this editor. * <p> * Editor actions are actions that depend and work on the editor. * * @param action - * the editor action */ protected void addEditorAction(EditorPartAction action) { getActionRegistry().registerAction(action); editorActionIDs.add(action.getId()); } /** * Creates different kinds of actions and registers them to the * ActionRegistry. */ protected void createActions() { // register save action addEditorAction(new SaveAction(this)); } /** * Indicates that the current page has changed. * <p> * We update the DelegatingCommandStack, OutlineViewer and other things * here. // */ protected void currentPageChanged() { IEditorPart activeEditor = getActiveEditor(); if (activeEditor == null) { return; } // update command stack CommandStack cmdStack = null; if (activeEditor == pageflowPage) { cmdStack = (CommandStack) activeEditor .getAdapter(CommandStack.class); } else if (activeEditor == sourcePage)// other page will delegate the // GEF command stack to source // page's. { cmdStack = this.getSourcePageCommandStack(); } // Add command stacks getMultiPageCommandStackListener().addCommandStack(cmdStack, activeEditor); getDelegatingCommandStack().setCurrentCommandStack(cmdStack); // enable or disable the actions // updateActions(stackActionIDs); // update zoom actions ZoomManager zoomManager = null; zoomManager = (ZoomManager) activeEditor.getAdapter(ZoomManager.class); if (zoomManager != null) { getDelegatingZoomManager().setCurrentZoomManager(zoomManager); } IEditorActionBarContributor contributor = getEditorSite() .getActionBarContributor(); if (contributor != null && contributor instanceof FacesConfigActionBarContributor) { ((FacesConfigActionBarContributor) contributor) .setActivePage(activeEditor); PaletteView paletteView = (PaletteView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(PaletteView.ID); if(paletteView != null) { paletteView.partActivated(activeEditor); } } } /* * (non-Javadoc) * * @see MultiPageEditorPart#pageChange(int) */ protected void pageChange(int newPageIndex) { super.pageChange(newPageIndex); // getActionBarContributor().setActivePage(getActiveEditor()); // refresh content depending on current page currentPageChanged(); //Bug 367899 - Navigation Information doesn't get synchronized with "From Outcome" updates if (newPageIndex == overviewPageID) { if (overviewPage != null) { overviewPage.refreshAll(); } } } public void dispose() { // signal that we have been disposed // do this before anything else _isDisposed = true; _modelLoader.dispose(); ResourcesPlugin.getWorkspace().removeResourceChangeListener( resourceChangeListener); adapterFactory.dispose(); if (this.outlinePage != null) outlinePage.dispose(); if (sourcePage != null) sourcePage.dispose(); if (sourceCommandStack != null) sourceCommandStack.dispose(); if (pageflowPage != null) pageflowPage.dispose(); if (multiPageCommandStackListener != null) multiPageCommandStackListener.dispose(); //do not call dispose on delegatingCommandStack. source and multiPage are already disposed super.dispose(); } /** * get the project of the faces config file that the editor is working on. * * @return IProject */ public IProject getProject() { if (currentProject == null) { if (_modelLoader.getEdit() != null) { IFile file = _modelLoader.getEdit().getFile(); if (file != null) currentProject = file.getProject(); } } return currentProject; } public EditingDomain getEditingDomain() { return editingDomain; } /** * Returns the <code>IContentOutlinePage</code> for this editor. * * @return - the <code>IContentOutlinePage</code> */ protected IContentOutlinePage getOutlinePage() { if (null == outlinePage) { outlinePage = new MultiPageEditorOutlinePage(); } return outlinePage; } public void addSelectionChangedListener(ISelectionChangedListener listener) { selectionChangedListeners.add(listener); } public ISelection getSelection() { return editorSelection; } public void removeSelectionChangedListener( ISelectionChangedListener listener) { selectionChangedListeners.remove(listener); } public void setSelection(ISelection selection) { editorSelection = selection; for (Iterator listeners = selectionChangedListeners.iterator(); listeners .hasNext();) { ISelectionChangedListener listener = (ISelectionChangedListener) listeners .next(); listener .selectionChanged(new SelectionChangedEvent(this, selection)); } } private void gotoMarker(IMarker marker) { setActivePage(sourcePageId); IDE.gotoMarker(this.sourcePage, marker); } /** * FIXME: this is used only for testing. Should isolate better * @return the action bar */ public FacesConfigActionBarContributor getActionBarContributor() { return (FacesConfigActionBarContributor) getEditorSite() .getActionBarContributor(); } private IActionBars getActionBars() { return getActionBarContributor().getActionBars(); } public Object getSelectedPage() { IFormPage page = getActivePageInstance(); if (page != null) return page; if (getActiveEditor() instanceof PageflowEditor) return getActiveEditor(); return null; } /** * Shows a dialog that asks if conflicting changes should be discarded. * @return the user's response. */ protected boolean handleDirtyConflict() { return MessageDialog .openQuestion( getSite().getShell(), EditorMessages.FacesConfigEditor_ErrorHandlingUndoConflicts_DialogTitle, EditorMessages.FacesConfigEditor_ErrorHandlingUndoConflicts_DialogMessage); } /** * Handles what to do with changed resources on activation. * * @generated */ protected void handleChangedResources() { if (!changedResources.isEmpty() && (!isDirty() || handleDirtyConflict())) { editingDomain.getCommandStack().flush(); for (Iterator i = changedResources.iterator(); i.hasNext();) { Resource resource = (Resource) i.next(); if (resource.isLoaded()) { resource.unload(); try { resource.load(Collections.EMPTY_MAP); } catch (IOException exception) { EditorPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, EditorPlugin .getPluginId(), IStatus.OK, exception .getMessage() == null ? "" : exception //$NON-NLS-1$ .getMessage(), exception)); } } } } } /** * TODO this is used only for testing. Should be able to remove if we * go to true automated UI testing * @param pageID */ public void setActiveEditorPage(String pageID) { if (pageID.equals(PageflowEditor.PAGE_ID)) { setActivePage(pageflowPageID); } else if (pageID.equals(ManagedBeanPage.PAGE_ID)) { setActivePage(managedBeanPageID); } else if (pageID.equals(ComponentsPage.PAGE_ID)) { setActivePage(componentsPageID); } else if (pageID.equals(OthersPage.PAGE_ID)) { setActivePage(othersPageID); } else if (pageID.equals(SOURCE_PAGE_ID)) { setActivePage(sourcePageId); } } private boolean matches(IEditorInput input) { final IResource file = (IResource) input.getAdapter(IResource.class); boolean hasWebFacet = false; boolean hasJSFFacet = false; if (file != null) { final IProject project = file.getProject(); if (project != null) { try { final IFacetedProject facetedProject = ProjectFacetsManager .create(project); if (facetedProject != null) { final Set facets = facetedProject.getProjectFacets(); for (final Iterator it = facets.iterator(); it .hasNext();) { final IProjectFacetVersion version = (IProjectFacetVersion) it .next(); IProjectFacet facet = version.getProjectFacet(); if (IJSFCoreConstants.JSF_CORE_FACET_ID.equals(facet.getId())) { hasJSFFacet = true; } else if ("jst.web".equals(facet.getId())) { //$NON-NLS-1$ hasWebFacet = true; } } } } catch (CoreException ex) { EditorPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, EditorPlugin .getPluginId(), IStatus.OK, ex.getMessage() == null ? "" : ex //$NON-NLS-1$ .getMessage(), ex)); } } } return hasWebFacet && hasJSFFacet; } /** * DANGER! This call is for testing only! Should not be used, * even internally, by production code. * @param timeoutMs the time to wait in milliseconds * @throws InterruptedException */ public void doPageLoad(long timeoutMs) throws InterruptedException { _modelLoader.waitForLoad(timeoutMs); _addPagesTask.doRun(_modelLoader.getEdit()); } }