Java tutorial
/****************************************************************************** * Copyright (c) 2009-2013, Linagora * * 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: * Linagora - initial API and implementation *******************************************************************************/ package com.ebmwebsourcing.petals.common.internal.formeditor; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.EventObject; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; 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.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.common.command.BasicCommandStack; import org.eclipse.emf.common.command.CommandStack; import org.eclipse.emf.common.command.CommandStackListener; 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.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.part.EditorPart; import org.eclipse.ui.part.FileEditorInput; import com.ebmwebsourcing.petals.common.internal.PetalsCommonPlugin; import com.ebmwebsourcing.petals.common.internal.provisional.formeditor.AbstractJbiEditorPersonality; import com.ebmwebsourcing.petals.common.internal.provisional.formeditor.ISharedEdition; import com.ebmwebsourcing.petals.common.internal.provisional.utils.PetalsConstants; import com.ebmwebsourcing.petals.common.internal.provisional.utils.StringUtils; import com.sun.java.xml.ns.jbi.DocumentRoot; import com.sun.java.xml.ns.jbi.Jbi; /** * The Petals form editor for JBI descriptors. */ public class JbiFormEditor extends EditorPart implements IEditorPart, ISelectionProvider, ISharedEdition { private static final String EXTENSION_POINT = "com.ebmwebsourcing.petals.common.formeditor"; private DataBindingContext dbc; private Jbi jbiModel; private TransactionalEditingDomain editDomain; private FormToolkit toolkit; private IFile editedFile; private IResourceChangeListener workspaceListener; private AbstractJbiEditorPersonality personality; private Image editorImage; private ScrolledForm mainForm; private final Set<ISelectionChangedListener> selectionListeners = new HashSet<ISelectionChangedListener>(); private ISelection selection; /** * @return the editor personality */ private AbstractJbiEditorPersonality getPersonality() { if (this.personality == null && this.editedFile != null) { // Look into the extensions IExtensionRegistry reg = Platform.getExtensionRegistry(); List<AbstractJbiEditorPersonality> personalities = new ArrayList<AbstractJbiEditorPersonality>(); IConfigurationElement[] extensions = reg.getConfigurationElementsFor(EXTENSION_POINT); for (IConfigurationElement elt : extensions) { String className = elt.getAttribute("class"); if (StringUtils.isEmpty(className)) { PetalsCommonPlugin.log("No personality was found for " + elt.getContributor().getName(), IStatus.ERROR); continue; } try { AbstractJbiEditorPersonality pers = (AbstractJbiEditorPersonality) elt .createExecutableExtension("class"); personalities.add(pers); } catch (CoreException e) { PetalsCommonPlugin.log("A JBI personality could not be instantiated - " + className, IStatus.ERROR); } } for (AbstractJbiEditorPersonality pers : personalities) { if (pers.matchesPersonality(this.jbiModel, this.editedFile)) { this.personality = pers; break; } } if (this.personality == null) this.personality = new JbiDefaultPersonality(); } return this.personality; } /** * Loads the DOM model. * <p> * If this model was already loaded, we reuse it. Otherwise, we make it loaded. * </p> */ private void loadSharedModel() throws IOException { try { // Get the edited file if (getEditorInput() instanceof IFileEditorInput) { this.editedFile = ((IFileEditorInput) getEditorInput()).getFile(); if (!this.editedFile.exists()) throw new FileNotFoundException(this.editedFile.getLocation() + " does not exist."); if (!this.editedFile.isSynchronized(IResource.DEPTH_ONE)) this.editedFile.refreshLocal(IResource.DEPTH_ONE, null); } else { // Don't load anything return; } ResourceSet resourceSet = new ResourceSetImpl(); this.editDomain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(resourceSet); URI resourceUri = URI.createPlatformResourceURI(this.editedFile.getFullPath().toString(), true); Resource resource = resourceSet.getResource(resourceUri, true); resource.load(resourceSet.getLoadOptions()); this.jbiModel = ((DocumentRoot) resource.getContents().get(0)).getJbi(); this.editDomain.getCommandStack().addCommandStackListener(new CommandStackListener() { @Override public void commandStackChanged(final EventObject event) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { firePropertyChange(IEditorPart.PROP_DIRTY); } }); } }); } catch (CoreException e) { PetalsCommonPlugin.log(e, IStatus.WARNING); } } /** * Initializes the resource listener to check markers. */ private void initializeResourceListener() { // No need to monitor changes if the file is not in the workspace if (this.editedFile == null) return; // The resource delta visitor final IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() { @Override public boolean visit(final IResourceDelta delta) throws CoreException { // Check for changes. if (delta.getResource().equals(JbiFormEditor.this.editedFile)) { // Deleted or renamed if (delta.getKind() == IResourceDelta.REMOVED) { if (delta.getMovedToPath() == null) { // Deleted getSite().getShell().getDisplay().asyncExec(new Runnable() { @Override public void run() { getSite().getPage().closeEditor(JbiFormEditor.this, false); } }); } else { // Renamed? if (delta.getMovedToPath() != null) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { setPartName(delta.getMovedToPath().lastSegment()); } }); } } } // Marker changes else if ((delta.getFlags() & IResourceDelta.MARKERS) != 0) refreshMarkers(); return false; } // Keep on checking on, only if the resource is an ancestor of the edited file. return delta.getResource().getFullPath().isPrefixOf(JbiFormEditor.this.editedFile.getFullPath()); } }; // The resource change listener this.workspaceListener = new IResourceChangeListener() { @Override public void resourceChanged(IResourceChangeEvent event) { try { event.getDelta().accept(visitor); } catch (CoreException e) { PetalsCommonPlugin.log(e, IStatus.ERROR); } } }; // Register it ResourcesPlugin.getWorkspace().addResourceChangeListener(this.workspaceListener, IResourceChangeEvent.POST_BUILD); } /** * Refreshes the markers * @param markerDeltas */ private void refreshMarkers() { if (this.editedFile == null || !this.editedFile.exists()) return; try { // Prepare the messages final Set<String> warningMessages = new HashSet<String>(); final Set<String> errorMessages = new HashSet<String>(); IMarker[] markers = this.editedFile.findMarkers(PetalsConstants.MARKER_ID_JBI_XML, true, IResource.DEPTH_ZERO); if (markers != null) { for (IMarker marker : markers) { int severity = marker.getAttribute(IMarker.SEVERITY, -1); if (severity == IMarker.SEVERITY_ERROR) errorMessages.add(marker.getAttribute(IMarker.MESSAGE, "")); else if (severity == IMarker.SEVERITY_WARNING) warningMessages.add(marker.getAttribute(IMarker.MESSAGE, "")); } } // Update the message manager Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (JbiFormEditor.this.mainForm.isDisposed()) return; JbiFormEditor.this.mainForm.getMessageManager().removeAllMessages(); int i = 0; for (String msg : errorMessages) JbiFormEditor.this.mainForm.getMessageManager().addMessage("error" + i++, msg, null, IMessageProvider.ERROR); for (String msg : warningMessages) JbiFormEditor.this.mainForm.getMessageManager().addMessage("warning" + i++, msg, null, IMessageProvider.WARNING); } }); } catch (CoreException e) { PetalsCommonPlugin.log(e, IStatus.ERROR); } } /** * This is called during startup. */ @Override public void init(IEditorSite site, IEditorInput editorInput) { setSite(site); setInputWithNotify(editorInput); if (editorInput instanceof FileEditorInput) setPartName(((FileEditorInput) editorInput).getFile().getProject().getName()); else setPartName(editorInput.getName()); site.setSelectionProvider(this); try { loadSharedModel(); initializeResourceListener(); this.dbc = new DataBindingContext(); } catch (Exception ex) { PetalsCommonPlugin.log(ex, IStatus.ERROR); } } /* * (non-Javadoc) * @see org.eclipse.ui.part.EditorPart * #doSave(org.eclipse.core.runtime.IProgressMonitor) */ @Override 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() { @Override public void execute(IProgressMonitor monitor) { // Delegate the save part to the personality handler getPersonality().saveModel(JbiFormEditor.this.jbiModel, JbiFormEditor.this.editedFile, JbiFormEditor.this.editDomain); } }; try { new ProgressMonitorDialog(getSite().getShell()).run(true, false, operation); ((BasicCommandStack) getEditingDomain().getCommandStack()).saveIsDone(); firePropertyChange(IEditorPart.PROP_DIRTY); } catch (Exception exception) { PetalsCommonPlugin.log(exception, IStatus.ERROR); } } /* * (non-Javadoc) * @see org.eclipse.ui.part.EditorPart * #doSaveAs() */ @Override public void doSaveAs() { // Not supported } /* * (non-Javadoc) * @see org.eclipse.ui.part.EditorPart * #isSaveAsAllowed() */ @Override public boolean isSaveAsAllowed() { return false; } /* * (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider * #addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ @Override public void addSelectionChangedListener(ISelectionChangedListener listener) { this.selectionListeners.add(listener); } /* * (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider * #getSelection() */ @Override public ISelection getSelection() { return this.selection; } /* * (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider * #removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ @Override public void removeSelectionChangedListener(ISelectionChangedListener listener) { this.selectionListeners.remove(listener); } /* * (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider * #setSelection(org.eclipse.jface.viewers.ISelection) */ @Override public void setSelection(ISelection selection) { // Update the selection this.selection = selection; for (ISelectionChangedListener listener : this.selectionListeners) { listener.selectionChanged(new SelectionChangedEvent(this, selection)); } // Update the status line try { IStatusLineManager manager = getEditorSite().getActionBars().getStatusLineManager(); if (selection instanceof IStructuredSelection) { IStructuredSelection sse = (IStructuredSelection) selection; switch (sse.size()) { case 0: manager.setMessage(""); break; case 1: ILabelProvider lp = getStatusLineLabelProvider(); if (lp != null) { String msg = lp.getText(sse.getFirstElement()); Image img = lp.getImage(sse.getFirstElement()); manager.setMessage(img, msg); } break; default: manager.setMessage(sse.size() + " selected elements"); break; } } } catch (Exception e) { PetalsCommonPlugin.log(e, IStatus.WARNING); } } /** * @return a label provider for the status line manager */ public ILabelProvider getStatusLineLabelProvider() { AbstractJbiEditorPersonality pers = getPersonality(); return pers != null ? pers.getStatusLineLabelProvider() : null; } /** * @return */ public EditingDomainActionBarContributor getActionBarContributor() { return (EditingDomainActionBarContributor) getEditorSite().getActionBarContributor(); } /* * (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart * #dispose() */ @Override public void dispose() { if (this.editDomain != null) this.editDomain.dispose(); if (this.dbc != null) this.dbc.dispose(); if (this.toolkit != null) this.toolkit.dispose(); if (this.editorImage != null && !this.editorImage.isDisposed()) this.editorImage.dispose(); ResourcesPlugin.getWorkspace().removeResourceChangeListener(this.workspaceListener); super.dispose(); } /* * (non-Javadoc) * @see org.eclipse.ui.part.EditorPart * #isDirty() */ @Override public boolean isDirty() { CommandStack commandStack = getEditingDomain().getCommandStack(); return commandStack != null ? ((BasicCommandStack) commandStack).isSaveNeeded() : false; } /* * (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart * #createPartControl(org.eclipse.swt.widgets.Composite) */ @Override public void createPartControl(Composite parent) { AbstractJbiEditorPersonality pers = getPersonality(); this.toolkit = new FormToolkit(getSite().getShell().getDisplay()); this.mainForm = this.toolkit.createScrolledForm(parent); this.mainForm.setText(pers != null ? pers.getTitle() : "Title"); this.editorImage = pers != null ? pers.getTitleImage() : null; this.mainForm.setImage(this.editorImage); this.toolkit.decorateFormHeading(this.mainForm.getForm()); this.toolkit.paintBordersFor(this.mainForm.getBody()); GridLayout layout = new GridLayout(); layout.marginBottom = 4; this.mainForm.getBody().setLayout(layout); this.mainForm.setLayoutData(new GridData(GridData.FILL_BOTH)); if (pers != null) pers.createControl(this.mainForm.getBody(), this); refreshMarkers(); } /* * (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart * #setFocus() */ @Override public void setFocus() { // nothing } /* * (non-Javadoc) * @see org.eclipse.emf.edit.domain.IEditingDomainProvider * #getEditingDomain() */ @Override public EditingDomain getEditingDomain() { return this.editDomain; } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.jbi.editor.ISharedEdition * #getFormToolkit() */ @Override public FormToolkit getFormToolkit() { return this.toolkit; } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.jbi.editor.ISharedEdition * #getDataBindingContext() */ @Override public DataBindingContext getDataBindingContext() { return this.dbc; } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.jbi.editor.ISharedEdition * #getJbiModel() */ @Override public Jbi getJbiModel() { return this.jbiModel; } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.jbi.editor.ISharedEdition * #getEditedFile() */ @Override public IFile getEditedFile() { return this.editedFile; } }