Java tutorial
/******************************************************************************* * Copyright (c) 2011-2013 EclipseSource Muenchen GmbH 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: * Anas Chakfeh - initial API and implementation * Eugen Neufeld - Refactoring * Alexandra Buzila - Refactoring * Johannes Faltermeier - integration with validation service ******************************************************************************/ package org.eclipse.emf.ecp.view.spi.treemasterdetail.ui.swt; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; import org.eclipse.emf.ecp.common.spi.ChildrenDescriptorCollector; import org.eclipse.emf.ecp.edit.internal.swt.util.OverlayImageDescriptor; import org.eclipse.emf.ecp.edit.spi.DeleteService; import org.eclipse.emf.ecp.edit.spi.EMFDeleteServiceImpl; import org.eclipse.emf.ecp.edit.spi.ReferenceService; import org.eclipse.emf.ecp.edit.spi.swt.util.SWTValidationHelper; import org.eclipse.emf.ecp.ui.view.ECPRendererException; import org.eclipse.emf.ecp.ui.view.swt.DefaultReferenceService; import org.eclipse.emf.ecp.ui.view.swt.ECPSWTViewRenderer; import org.eclipse.emf.ecp.view.internal.swt.ContextMenuViewModelService; import org.eclipse.emf.ecp.view.internal.treemasterdetail.ui.swt.Activator; import org.eclipse.emf.ecp.view.model.common.edit.provider.CustomReflectiveItemProviderAdapterFactory; import org.eclipse.emf.ecp.view.spi.context.ViewModelContext; import org.eclipse.emf.ecp.view.spi.model.ModelChangeListener; import org.eclipse.emf.ecp.view.spi.model.ModelChangeNotification; import org.eclipse.emf.ecp.view.spi.model.VDiagnostic; import org.eclipse.emf.ecp.view.spi.model.VElement; import org.eclipse.emf.ecp.view.spi.model.VView; import org.eclipse.emf.ecp.view.spi.model.VViewModelProperties; import org.eclipse.emf.ecp.view.spi.model.reporting.StatusReport; import org.eclipse.emf.ecp.view.spi.model.util.ViewModelPropertiesHelper; import org.eclipse.emf.ecp.view.spi.provider.ViewProviderHelper; import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption; import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException; import org.eclipse.emf.ecp.view.treemasterdetail.model.VTreeMasterDetail; import org.eclipse.emf.ecp.view.treemasterdetail.ui.swt.internal.RootObject; import org.eclipse.emf.ecp.view.treemasterdetail.ui.swt.internal.TreeMasterDetailSelectionManipulatorHelper; import org.eclipse.emf.edit.command.AddCommand; import org.eclipse.emf.edit.command.CommandParameter; import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.ui.action.ecp.CreateChildAction; import org.eclipse.emf.edit.ui.dnd.EditingDomainViewerDropAdapter; import org.eclipse.emf.edit.ui.dnd.LocalTransfer; import org.eclipse.emf.edit.ui.dnd.ViewerDragAdapter; import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider; import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; import org.eclipse.emfforms.spi.common.report.ReportService; import org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer; import org.eclipse.emfforms.spi.swt.core.layout.GridDescriptionFactory; import org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell; import org.eclipse.emfforms.spi.swt.core.layout.SWTGridDescription; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.action.ToolBarManager; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.ToolBar; import org.osgi.framework.FrameworkUtil; /** * SWT Renderer for a {@link VTreeMasterDetail} element. * * @author Anas Chakfeh * @author Eugen Neufeld * @since 1.5 * */ public class TreeMasterDetailSWTRenderer extends AbstractSWTRenderer<VTreeMasterDetail> { /** * Default Constructor. * * @param vElement the view element to be rendered * @param viewContext The view model context * @param reportService the ReportService to use * @since 1.6 */ public TreeMasterDetailSWTRenderer(final VTreeMasterDetail vElement, final ViewModelContext viewContext, ReportService reportService) { super(vElement, viewContext, reportService); } /** * The detail key passed to the view model context. */ public static final String DETAIL_KEY = "detail"; //$NON-NLS-1$ /** * Context key for the root. */ public static final String ROOT_KEY = "root"; //$NON-NLS-1$ private SWTGridDescription rendererGridDescription; private Font detailsFont; private Color titleColor; private Font titleFont; private Color headerBgColor; private TreeViewer treeViewer; /** * Static string. * */ public static final String GLOBAL_ADDITIONS = "global_additions"; //$NON-NLS-1$ private ScrolledComposite rightPanel; private Composite container; private Composite rightPanelContainerComposite; private ModelChangeListener domainModelListener; /** * @author jfaltermeier * */ private final class MasterTreeContextMenuListener implements IMenuListener { private final EditingDomain editingDomain; private final TreeViewer treeViewer; private final ChildrenDescriptorCollector childrenDescriptorCollector; private final List<MasterDetailAction> menuActions; /** * @param editingDomain * @param treeViewer * @param childrenDescriptorCollector * @param menuActions */ private MasterTreeContextMenuListener(EditingDomain editingDomain, TreeViewer treeViewer, ChildrenDescriptorCollector childrenDescriptorCollector, List<MasterDetailAction> menuActions) { this.editingDomain = editingDomain; this.treeViewer = treeViewer; this.childrenDescriptorCollector = childrenDescriptorCollector; this.menuActions = menuActions; } @Override public void menuAboutToShow(IMenuManager manager) { if (treeViewer.getSelection().isEmpty()) { return; } final EObject root = ((RootObject) treeViewer.getInput()).getRoot(); if (treeViewer.getSelection() instanceof IStructuredSelection) { final IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection(); if (selection.size() == 1 && EObject.class.isInstance(selection.getFirstElement())) { final EObject eObject = (EObject) selection.getFirstElement(); final EditingDomain domain = AdapterFactoryEditingDomain.getEditingDomainFor(eObject); if (domain == null) { return; } final Collection<?> descriptors = childrenDescriptorCollector.getDescriptors(eObject); fillContextMenu(manager, descriptors, editingDomain, eObject); } if (!selection.toList().contains(root)) { manager.add(new Separator(GLOBAL_ADDITIONS)); addDeleteActionToContextMenu(editingDomain, manager, selection); } manager.add(new Separator()); if (selection.getFirstElement() != null && EObject.class.isInstance(selection.getFirstElement())) { final EObject selectedObject = (EObject) selection.getFirstElement(); for (final MasterDetailAction menuAction : menuActions) { if (menuAction.shouldShow(selectedObject)) { final Action newAction = new Action() { @Override public void run() { super.run(); menuAction.execute(selectedObject); } }; newAction.setImageDescriptor(ImageDescriptor.createFromURL(FrameworkUtil .getBundle(menuAction.getClass()).getResource(menuAction.getImagePath()))); newAction.setText(menuAction.getLabel()); manager.add(newAction); } } } } } } /** * {@inheritDoc} * * @see org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer#dispose() */ @Override protected void dispose() { rendererGridDescription = null; if (getViewModelContext() != null && domainModelListener != null) { getViewModelContext().unregisterDomainChangeListener(domainModelListener); } super.dispose(); } /** * {@inheritDoc} * * @see org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer#getGridDescription(SWTGridDescription) */ @Override public SWTGridDescription getGridDescription(SWTGridDescription gridDescription) { if (rendererGridDescription == null) { rendererGridDescription = GridDescriptionFactory.INSTANCE.createSimpleGrid(1, 1, this); } return rendererGridDescription; } /** * {@inheritDoc} * * @see org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer#renderControl(org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell, * org.eclipse.swt.widgets.Composite) */ @Override protected Control renderControl(SWTGridCell cell, Composite parent) throws NoRendererFoundException, NoPropertyDescriptorFoundExeption { /* The tree's composites */ final Composite form = createMasterDetailForm(parent); createHeader(form); final SashForm sash = createSash(form); final Composite masterPanel = createMasterPanel(sash); createRightPanelContent(sash); sash.setWeights(new int[] { 1, 3 }); createMasterTree(masterPanel); if (hasContextMenu()) { registerControlAsContextMenuReceiver(); } form.layout(true); return form; } private void registerControlAsContextMenuReceiver() { if (!getViewModelContext().hasService(ContextMenuViewModelService.class)) { return; } final ContextMenuViewModelService service = getViewModelContext() .getService(ContextMenuViewModelService.class); if (service != null) { service.setParentControl(treeViewer.getTree()); service.registerContextMenu(); } } /** * Creates the sashform for the master detail colums. * * @param parent the parent * @return the sash */ protected SashForm createSash(Composite parent) { /* THe contents of the composite */ final Composite sashComposite = new Composite(parent, SWT.FILL); final GridLayout sashLayout = GridLayoutFactory.fillDefaults().create(); sashLayout.marginWidth = 5; sashComposite.setLayout(sashLayout); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(sashComposite); final SashForm sash = new SashForm(sashComposite, SWT.HORIZONTAL); sash.setBackground(parent.getBackground()); GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).applyTo(sash); GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(sash); sash.setSashWidth(5); return sash; } /** * Create the parent of the master detail form. * * @param parent the parent * @return the composite */ protected Composite createMasterDetailForm(Composite parent) { final Composite form = new Composite(parent, SWT.BORDER); final GridLayout layout = GridLayoutFactory.fillDefaults().create(); form.setLayout(layout); form.setBackgroundMode(SWT.INHERIT_FORCE); // form.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE)); return form; } /** * Creates the tree viewer for the master. * * @param masterPanel the parent * @return the tree viewer */ protected TreeViewer createMasterTree(final Composite masterPanel) { final EObject modelElement = getViewModelContext().getDomainModel(); final EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(modelElement); final ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory( new AdapterFactory[] { new CustomReflectiveItemProviderAdapterFactory(), new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) }); final AdapterFactoryContentProvider adapterFactoryContentProvider = new AdapterFactoryContentProvider( adapterFactory) { @Override public Object[] getElements(Object object) { return new Object[] { ((RootObject) object).getRoot() }; } }; final AdapterFactoryLabelProvider labelProvider = new TreeMasterDetailLabelProvider(adapterFactory); treeViewer = new TreeViewer(masterPanel); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).hint(100, SWT.DEFAULT) .applyTo(treeViewer.getTree()); treeViewer.setContentProvider(adapterFactoryContentProvider); treeViewer.setLabelProvider(getLabelProvider(labelProvider)); treeViewer.setAutoExpandLevel(2); // top level element is expanded, but not the children treeViewer.setInput(new RootObject(modelElement)); // workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=27480 // the treeviewer doesn't autoexpand on refresh domainModelListener = new ModelChangeListener() { @Override public void notifyChange(ModelChangeNotification notification) { // expand the tree if elements are added to the tree and the root isn't already expanded if (notification.getRawNotification().getEventType() == Notification.ADD || notification.getRawNotification().getEventType() == Notification.ADD_MANY) { final EObject notifier = notification.getNotifier(); treeViewer.expandToLevel(notifier, 1); } } }; getViewModelContext().registerDomainChangeListener(domainModelListener); // Drag and Drop if (hasDnDSupport()) { addDragAndDropSupport(modelElement, treeViewer, editingDomain); } // Selection Listener treeViewer.addSelectionChangedListener(new TreeMasterViewSelectionListener()); treeViewer.setSelection(new StructuredSelection(modelElement)); if (hasContextMenu()) { fillContextMenu(treeViewer, editingDomain); } treeViewer.getTree().addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent event) { adapterFactoryContentProvider.dispose(); labelProvider.dispose(); adapterFactory.dispose(); if (titleFont != null) { titleFont.dispose(); } if (detailsFont != null) { detailsFont.dispose(); } if (titleColor != null) { titleColor.dispose(); } if (headerBgColor != null) { headerBgColor.dispose(); } } }); return treeViewer; } /** * Return true if a context menu should be shown in the tree. * * @return true if a context menu should be shown, false otherwise */ protected boolean hasContextMenu() { return true; } /** * Return true if the tree should support DnD. * * @return true if DnD should be supported , false otherwise */ protected boolean hasDnDSupport() { return true; } /** * Returns the label provider. * * @param adapterFactoryLabelProvider the adaper factory label provider * @return the label provider to use for the tree */ protected ILabelProvider getLabelProvider(final AdapterFactoryLabelProvider adapterFactoryLabelProvider) { return adapterFactoryLabelProvider; } /** * Creates the composite for the master panel. * * @param sash the parent * @return the composite */ protected Composite createMasterPanel(final SashForm sash) { final Composite leftPanel = new Composite(sash, SWT.NONE); leftPanel.setLayout(GridLayoutFactory.fillDefaults().create()); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(leftPanel); // leftPanel.setBackground(sash.getBackground()); leftPanel.setBackgroundMode(SWT.INHERIT_FORCE); return leftPanel; } /** * Adds the header to a parent composite. * * @param parent the parent */ protected void createHeader(Composite parent) { final Composite headerComposite = new Composite(parent, SWT.NONE); final GridLayout headerLayout = GridLayoutFactory.fillDefaults().create(); headerComposite.setLayout(headerLayout); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(headerComposite); headerBgColor = new Color(parent.getDisplay(), new RGB(220, 240, 247)); headerComposite.setBackground(headerBgColor); final EObject modelElement = getViewModelContext().getDomainModel(); final EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(modelElement); /* The header of the composite */ if (modelElement.eContainer() == null && !DynamicEObjectImpl.class.isInstance(modelElement)) { final Composite header = getPageHeader(headerComposite); final List<Action> actions = readToolbarActions(modelElement, editingDomain); final ToolBar toolBar = new ToolBar(header, SWT.FLAT | SWT.RIGHT); final FormData formData = new FormData(); formData.right = new FormAttachment(100, 0); toolBar.setLayoutData(formData); toolBar.layout(); final ToolBarManager toolBarManager = new ToolBarManager(toolBar); /* Add actions to header */ for (final Action action : actions) { toolBarManager.add(action); } toolBarManager.update(true); header.layout(); } } /** * @param form2 */ private Composite getPageHeader(Composite parent) { final Composite header = new Composite(parent, SWT.FILL); final FormLayout layout = new FormLayout(); layout.marginHeight = 5; layout.marginWidth = 5; header.setLayout(layout); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(header); header.setBackground(parent.getBackground()); final Label titleImage = new Label(header, SWT.FILL); final ImageDescriptor imageDescriptor = ImageDescriptor .createFromURL(Activator.getDefault().getBundle().getResource("icons/view.png")); //$NON-NLS-1$ titleImage.setImage(new Image(parent.getDisplay(), imageDescriptor.getImageData())); final FormData titleImageData = new FormData(); final int imageOffset = -titleImage.computeSize(SWT.DEFAULT, SWT.DEFAULT).y / 2; titleImageData.top = new FormAttachment(50, imageOffset); titleImageData.left = new FormAttachment(0, 10); titleImage.setLayoutData(titleImageData); final Label title = new Label(header, SWT.WRAP); title.setText("View Editor"); //$NON-NLS-1$ titleFont = new Font(title.getDisplay(), getDefaultFontName(title), 12, SWT.BOLD); title.setFont(titleFont); title.setForeground(getTitleColor(parent)); final FormData titleData = new FormData(); title.setLayoutData(titleData); titleData.left = new FormAttachment(titleImage, 5, SWT.DEFAULT); return header; } /** * @return */ private Color getTitleColor(Composite parent) { if (titleColor == null) { titleColor = new Color(parent.getDisplay(), new RGB(25, 76, 127)); } return titleColor; } /** * Creates the composite holding the details. * * @param parent the parent * @return the right panel/detail composite */ protected ScrolledComposite createRightPanelContent(Composite parent) { rightPanel = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL); rightPanel.setShowFocusedControl(true); rightPanel.setExpandVertical(true); rightPanel.setExpandHorizontal(true); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(rightPanel); rightPanel.setLayout(GridLayoutFactory.fillDefaults().create()); rightPanel.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE)); container = new Composite(rightPanel, SWT.FILL); container.setLayout(GridLayoutFactory.fillDefaults().create()); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(container); container.setBackground(rightPanel.getBackground()); /* The header */ final Composite header = new Composite(container, SWT.FILL); final GridLayout headerLayout = GridLayoutFactory.fillDefaults().create(); headerLayout.marginWidth = 5; header.setLayout(headerLayout); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(header); header.setBackground(rightPanel.getBackground()); final Label label = new Label(header, SWT.WRAP); label.setText("Details"); //$NON-NLS-1$ detailsFont = new Font(label.getDisplay(), getDefaultFontName(label), 10, SWT.BOLD); label.setFont(detailsFont); label.setForeground(getTitleColor(parent)); label.setBackground(header.getBackground()); rightPanelContainerComposite = new Composite(container, SWT.FILL); rightPanelContainerComposite.setLayout(GridLayoutFactory.fillDefaults().create()); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true) .applyTo(rightPanelContainerComposite); rightPanelContainerComposite.setBackground(rightPanel.getBackground()); rightPanel.setContent(container); rightPanel.layout(); container.layout(); final Point point = container.computeSize(SWT.DEFAULT, SWT.DEFAULT); rightPanel.setMinSize(point); return rightPanel; } @Override protected String getDefaultFontName(Control control) { return control.getDisplay().getSystemFont().getFontData()[0].getName(); } /** * */ private List<Action> readToolbarActions(EObject modelElement, final EditingDomain editingDomain) { final List<Action> actions = new ArrayList<Action>(); final IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); if (extensionRegistry == null) { return actions; } if (!VView.class.isInstance(modelElement)) { return actions; } final VView view = (VView) modelElement; final IConfigurationElement[] controls = extensionRegistry.getConfigurationElementsFor( "org.eclipse.emf.ecp.view.treemasterdetail.ui.swt.masterDetailActions"); //$NON-NLS-1$ for (final IConfigurationElement e : controls) { try { final String location = e.getAttribute("location"); //$NON-NLS-1$ if (!location.equals("toolbar")) { //$NON-NLS-1$ continue; } final String label = e.getAttribute("label"); //$NON-NLS-1$ final String imagePath = e.getAttribute("imagePath"); //$NON-NLS-1$ final MasterDetailAction command = (MasterDetailAction) e.createExecutableExtension("command"); //$NON-NLS-1$ final Action newAction = new Action() { @Override public void run() { super.run(); command.execute(view); } }; newAction.setImageDescriptor(ImageDescriptor .createFromURL(FrameworkUtil.getBundle(command.getClass()).getResource(imagePath))); newAction.setText(label); actions.add(newAction); } catch (final CoreException e1) { e1.printStackTrace(); } } return actions; } private void addDragAndDropSupport(final EObject modelElement, final TreeViewer treeViewer, EditingDomain editingDomain) { final int dndOperations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK; final Transfer[] transfers = new Transfer[] { LocalTransfer.getInstance() }; treeViewer.addDragSupport(dndOperations, transfers, new ViewerDragAdapter(treeViewer)); final EditingDomainViewerDropAdapter editingDomainViewerDropAdapter = new EditingDomainViewerDropAdapter( editingDomain, treeViewer); treeViewer.addDropSupport(dndOperations, transfers, editingDomainViewerDropAdapter); } /** * @param treeViewer * @param editingDomain */ private void fillContextMenu(final TreeViewer treeViewer, final EditingDomain editingDomain) { final ChildrenDescriptorCollector childrenDescriptorCollector = new ChildrenDescriptorCollector(); final List<MasterDetailAction> menuActions = readMasterDetailActions(); final MenuManager menuMgr = new MenuManager(); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new MasterTreeContextMenuListener(editingDomain, treeViewer, childrenDescriptorCollector, menuActions)); final Menu menu = menuMgr.createContextMenu(treeViewer.getControl()); treeViewer.getControl().setMenu(menu); } /** * Returns a list of all {@link MasterDetailAction MasterDetailActions} which shall be displayed in the context menu * of the master treeviewer. * * @return the actions */ protected List<MasterDetailAction> readMasterDetailActions() { final List<MasterDetailAction> commands = new ArrayList<MasterDetailAction>(); final IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); if (extensionRegistry == null) { return commands; } final IConfigurationElement[] controls = extensionRegistry.getConfigurationElementsFor( "org.eclipse.emf.ecp.view.treemasterdetail.ui.swt.masterDetailActions"); //$NON-NLS-1$ for (final IConfigurationElement e : controls) { try { final String location = e.getAttribute("location"); //$NON-NLS-1$ if (!location.equals("menu")) { //$NON-NLS-1$ continue; } final String label = e.getAttribute("label"); //$NON-NLS-1$ final String imagePath = e.getAttribute("imagePath"); //$NON-NLS-1$ final MasterDetailAction command = (MasterDetailAction) e.createExecutableExtension("command"); //$NON-NLS-1$ command.setLabel(label); command.setImagePath(imagePath); command.setTreeViewer(treeViewer); commands.add(command); } catch (final CoreException ex) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), ex.getMessage(), ex)); } } return commands; } /** * @param manager The menu manager responsible for the context menu * @param descriptors The menu items to be added * @param domain The editing domain of the current EObject * @param eObject The model element */ private void fillContextMenu(IMenuManager manager, Collection<?> descriptors, final EditingDomain domain, final EObject eObject) { for (final Object descriptor : descriptors) { final CommandParameter cp = (CommandParameter) descriptor; if (!CommandParameter.class.isInstance(descriptor)) { continue; } if (cp.getEReference() == null) { continue; } if (!cp.getEReference().isMany() && eObject.eIsSet(cp.getEStructuralFeature())) { continue; } else if (cp.getEReference().isMany() && cp.getEReference().getUpperBound() != -1 && cp.getEReference().getUpperBound() <= ((List<?>) eObject.eGet(cp.getEReference())).size()) { continue; } manager.add(new CreateChildAction(domain, new StructuredSelection(eObject), descriptor) { @Override public void run() { super.run(); final EReference reference = ((CommandParameter) descriptor).getEReference(); // if (!reference.isContainment()) { // domain.getCommandStack().execute( // AddCommand.create(domain, eObject.eContainer(), null, cp.getEValue())); // } domain.getCommandStack().execute(AddCommand.create(domain, eObject, reference, cp.getEValue())); } }); } } /** * @param editingDomain * @param manager * @param selection */ private void addDeleteActionToContextMenu(final EditingDomain editingDomain, final IMenuManager manager, final IStructuredSelection selection) { final Action deleteAction = new Action() { @Override public void run() { super.run(); DeleteService deleteService = getViewModelContext().getService(DeleteService.class); if (deleteService == null) { /* * #getService(Class<?>) will report to the reportservice if it could not be found * Use Default */ deleteService = new EMFDeleteServiceImpl(); } for (final Object obj : selection.toList()) { deleteService.deleteElement(obj); } treeViewer.setSelection(new StructuredSelection(getViewModelContext().getDomainModel())); } }; final String deleteImagePath = "icons/delete.png";//$NON-NLS-1$ deleteAction.setImageDescriptor( ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource(deleteImagePath))); deleteAction.setText("Delete"); //$NON-NLS-1$ manager.add(deleteAction); } /** * Allows to manipulate the view context for the selected element that is about to be rendered. * * @param viewContext the view context. */ protected void manipulateViewContext(ViewModelContext viewContext) { // do nothing } /** * * @author Anas Chakfeh * This class is responsible for handling selection changed events which happen on the tree * */ private class TreeMasterViewSelectionListener implements ISelectionChangedListener { private Composite childComposite; private ReferenceService referenceService; public TreeMasterViewSelectionListener() { // TODO refactor if (getViewModelContext().hasService(ReferenceService.class)) { referenceService = getViewModelContext().getService(ReferenceService.class); } else { referenceService = new DefaultReferenceService(); } } @Override public void selectionChanged(SelectionChangedEvent event) { final Object treeSelected = ((IStructuredSelection) event.getSelection()).getFirstElement(); final Object selected = treeSelected == null ? treeSelected : manipulateSelection(treeSelected); if (selected instanceof EObject) { try { if (childComposite != null) { childComposite.dispose(); cleanCustomOnSelectionChange(); } childComposite = createComposite(); final Object root = manipulateSelection( ((RootObject) ((TreeViewer) event.getSource()).getInput()).getRoot()); final VElement viewModel = getViewModelContext().getViewModel(); final VViewModelProperties properties = ViewModelPropertiesHelper .getInhertitedPropertiesOrEmpty(viewModel); properties.addNonInheritableProperty(DETAIL_KEY, true); final boolean rootSelected = selected.equals(root); if (rootSelected) { properties.addNonInheritableProperty(ROOT_KEY, true); } VView view = null; if (rootSelected) { view = getVElement().getDetailView(); } if (view == null || view.getChildren().isEmpty()) { view = ViewProviderHelper.getView((EObject) selected, properties); } final ReferenceService referenceService = getViewModelContext() .getService(ReferenceService.class); final ViewModelContext childContext = getViewModelContext().getChildContext((EObject) selected, getVElement(), view, new TreeMasterDetailReferenceService(referenceService)); manipulateViewContext(childContext); ECPSWTViewRenderer.INSTANCE.render(childComposite, childContext); relayoutDetail(); } catch (final ECPRendererException e) { Activator.getDefault().getReportService().report(new StatusReport(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), e.getMessage(), e))); } } } private Composite createComposite() { final Composite parent = getDetailContainer(); final Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getBackground()); final GridLayout gridLayout = GridLayoutFactory.fillDefaults().create(); // gridLayout.marginTop = 7; // gridLayout.marginLeft = 5; composite.setLayout(gridLayout); GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(composite); // .indent(10, 10) composite.layout(true, true); return composite; } } /** * Returns the composite for the detail. * * @return the composite */ protected Composite getDetailContainer() { return rightPanelContainerComposite; } /** * Allows to manipulate the selection by returning a specific child. * * @param treeSelected the selected element in the tree * @return the object that should be used as a selection */ protected Object manipulateSelection(Object treeSelected) { return TreeMasterDetailSelectionManipulatorHelper.manipulateSelection(treeSelected); } /** * Gets called after a detail composite was disposed. Allows for further cleanup. */ protected void cleanCustomOnSelectionChange() { // do nothing } /** * Relayouts the detail composite. */ protected void relayoutDetail() { rightPanelContainerComposite.layout(); final Point point = container.computeSize(SWT.DEFAULT, SWT.DEFAULT); rightPanel.setMinSize(point); } /** * The label provider used for the detail tree. * * @author jfaltermeier * */ private class TreeMasterDetailLabelProvider extends AdapterFactoryLabelProvider { public TreeMasterDetailLabelProvider(AdapterFactory adapterFactory) { super(adapterFactory); } @Override public Image getImage(Object object) { final Image image = super.getImage(object); if (!EObject.class.isInstance(object)) { return image; } return getValidationOverlay(image, (EObject) object); } protected Image getValidationOverlay(Image image, final EObject object) { // final Integer severity = validationResultCacheTree.getCachedValue(object); final VDiagnostic vDiagnostic = getVElement().getDiagnostic(); int highestSeverity = Diagnostic.OK; if (vDiagnostic != null) { for (final Diagnostic diagnostic : vDiagnostic.getDiagnostics(object)) { if (diagnostic.getSeverity() > highestSeverity) { highestSeverity = diagnostic.getSeverity(); } } } final ImageDescriptor overlay = SWTValidationHelper.INSTANCE .getValidationOverlayDescriptor(highestSeverity); if (overlay == null) { return image; } final OverlayImageDescriptor imageDescriptor = new OverlayImageDescriptor(image, overlay, OverlayImageDescriptor.LOWER_RIGHT); final Image resultImage = imageDescriptor.createImage(); return resultImage; } } /** * {@inheritDoc} * * @see org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer#applyValidation() */ @Override protected void applyValidation() { super.applyValidation(); if (treeViewer == null) { return; } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (treeViewer.getTree().isDisposed()) { return; } treeViewer.refresh(); } }); } private class TreeMasterDetailReferenceService implements ReferenceService { private final ReferenceService delegate; public TreeMasterDetailReferenceService(ReferenceService delegate) { this.delegate = delegate; } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.view.spi.context.ViewModelService#instantiate(org.eclipse.emf.ecp.view.spi.context.ViewModelContext) */ @Override public void instantiate(ViewModelContext context) { // no op } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.view.spi.context.ViewModelService#dispose() */ @Override public void dispose() { // no op } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.view.spi.context.ViewModelService#getPriority() */ @Override public int getPriority() { if (delegate == null) { return 0; } return delegate.getPriority() - 1; } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.edit.spi.ReferenceService#addNewModelElements(org.eclipse.emf.ecore.EObject, * org.eclipse.emf.ecore.EReference) */ @Override public void addNewModelElements(EObject eObject, EReference eReference) { if (delegate == null) { return; } delegate.addNewModelElements(eObject, eReference); } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.edit.spi.ReferenceService#addExistingModelElements(org.eclipse.emf.ecore.EObject, * org.eclipse.emf.ecore.EReference) */ @Override public void addExistingModelElements(EObject eObject, EReference eReference) { if (delegate == null) { return; } delegate.addExistingModelElements(eObject, eReference); } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.edit.spi.ReferenceService#openInNewContext(org.eclipse.emf.ecore.EObject) */ @Override public void openInNewContext(EObject eObject) { treeViewer.setSelection(new StructuredSelection(eObject), true); final ISelection selection = treeViewer.getSelection(); if (!selection.isEmpty()) { return; } if (delegate == null) { return; } delegate.openInNewContext(eObject); } } }