/***************************************************************************** * Copyright (c) 2010 CEA LIST. * * 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: * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.common.service.palette; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.EditPart; import org.eclipse.gef.palette.PaletteEntry; import org.eclipse.gef.palette.ToolEntry; import org.eclipse.gmf.runtime.common.core.command.CompositeCommand; import org.eclipse.gmf.runtime.common.core.command.ICommand; import org.eclipse.gmf.runtime.common.ui.util.DisplayUtils; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.CheckboxCellEditor; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ComboBoxCellEditor; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.ITreeSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.papyrus.commands.wrappers.EMFtoGMFCommandWrapper; import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper; import org.eclipse.papyrus.uml.diagram.common.Activator; import org.eclipse.papyrus.uml.diagram.common.Messages; import org.eclipse.papyrus.uml.diagram.common.part.PaletteUtil; import org.eclipse.papyrus.uml.diagram.common.service.ApplyStereotypeRequest; import org.eclipse.papyrus.uml.diagram.common.ui.dialogs.PropertyEditors; import org.eclipse.papyrus.uml.diagram.common.util.Util; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; 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.Shell; import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog; import org.eclipse.uml2.uml.Class; import org.eclipse.uml2.uml.DataType; import org.eclipse.uml2.uml.PrimitiveType; import org.eclipse.uml2.uml.Profile; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.Stereotype; import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.UMLPackage; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * Aspect action that applies stereotypes on the edit part newly created * * /!\ WARNING use the setters and getters for manipulating the {@link #propertiesToUpdate} and {@link #valuesToProperties} * * */ public class StereotypePostAction extends ModelPostAction { /* * the icons paths */ /** up icon path */ protected static final String ICONS_UP = "/icons/arrow_up.gif"; //$NON-NLS-1$ /** down icon path */ protected static final String ICONS_DOWN = "/icons/arrow_down.gif"; //$NON-NLS-1$ /** add icon path */ protected static final String ICONS_ADD = "/icons/obj16/Add_16x16.gif"; //$NON-NLS-1$ /** remove icon path */ protected static final String ICONS_REMOVE = "/icons/delete.gif"; //$NON-NLS-1$ /** stereotype icon path */ protected static final String ICON_STEREOTYPE = "/icons/stereotype.gif"; //$NON-NLS-1$ /** profile icon path */ protected static final String ICON_PROFILE = "/icons/profile.gif"; //$NON-NLS-1$ /** property icon path */ protected static final String ICON_PROPERTY = "/icons/property.gif"; //$NON-NLS-1$ /** metaclass icon path */ protected static final String ICON_METACLASS = "/icons/Metaclass.gif"; //$NON-NLS-1$ /** boolean icon path */ protected static final String ICON_LITERALBOOLEAN = "/icons/LiteralBoolean.gif"; //$NON-NLS-1$ /** integer icon path */ protected static final String ICON_LITERALINTEGER = "/icons/LiteralInteger.gif"; //$NON-NLS-1$ /** string icon path */ protected static final String ICON_LITERALSTRING = "/icons/LiteralString.gif"; //$NON-NLS-1$ /** unlimited natural icon path */ protected static final String ICON_LITERALUNLIMITEDNATURAL = "/icons/LiteralUnlimitedNatural.gif"; //$NON-NLS-1$ /** unknown icon path */ protected static final String ICON_UNKNOWN = "/icons/Clause.gif"; //$NON-NLS-1$ /** enumeration icon path */ protected static final String ICON_ENUMERATION = "/icons/Enumeration.gif"; //$NON-NLS-1$ /** datatype icon path */ protected static final String ICON_DATATYPE = "/icons/DataType.gif"; //$NON-NLS-1$ /** the configuration for the palette element */ protected Configuration config; /** * Separator for displaying the different values owned by a multi-valued * property */ protected static final String SEPARATOR = ", "; //$NON-NLS-1$ /** viewer to display stereotypes to apply */ protected TreeViewer stereotypesViewer; /** entry proxy "parent" of this action when configuring the action */ protected IPaletteEntryProxy entryProxy; /** editor label provider */ protected EditorLabelProvider editorLabelProvider = new EditorLabelProvider(); /** editor content provider */ protected StereotypeContentProvider stereotypeContentProvider = new StereotypeContentProvider(); /* * the buttons */ /** remove button */ protected Button removeButton; /** add button */ protected Button addButton; /** up button */ protected Button upButton; /** down button */ protected Button downButton; /** string used with the upButton */ public static final String MOVE_DOWN = "move down"; //$NON-NLS-1$ /** string used with the downButton */ public static final String MOVE_UP = "move up"; //$NON-NLS-1$ /** contains the expanded nodes */ private Object[] expandedElements = null; /** constant to identify the type of a Boolean property */ final static public String UMLPrimitiveTypes_BOOLEAN = "UMLPrimitiveTypes::Boolean"; //$NON-NLS-1$ /** constant to identify the type of an Integer property */ final static public String UMLPrimitiveTypes_INTEGER = "UMLPrimitiveTypes::Integer"; //$NON-NLS-1$ /** constant to identify the type of a String property */ final static public String UMLPrimitiveTypes_STRING = "UMLPrimitiveTypes::String"; //$NON-NLS-1$ /** constant to identify the type of an Unlimited Natural property */ final static public String UMLPrimitiveTypes_UNLIMITED_NATURAL = "UMLPrimitiveTypes::UnlimitedNatural"; //$NON-NLS-1$ /** path to the checked box image */ protected final static String ICON_CHECKED = "/icons/complete_tsk.gif"; //$NON-NLS-1$ /** path to the unchecked box image */ protected final static String ICON_UNCHECKED = "/icons/incomplete_tsk.gif"; //$NON-NLS-1$ /** the column for the stereotypes */ private TreeViewerColumn stereotypeColumn = null; /** the column with the checkboxes for the runtime properties */ private TreeViewerColumn runtimeColumn = null; private ArrayList<Value> savedValues; /** * Constructor. */ public StereotypePostAction() { } /** * {@inheritDoc} */ @Override public IStatus checkPostCondition() { return Status.OK_STATUS; } /** * {@inheritDoc} */ @Override public IStatus checkPreCondition() { return Status.OK_STATUS; } /** * * @see org.eclipse.papyrus.uml.diagram.common.service.palette.ModelPostAction#init(org.w3c.dom.Node, * org.eclipse.papyrus.uml.diagram.common.service.palette.IAspectActionProvider) * * @param configurationNode * @param factory */ @Override public void init(Node configurationNode, IAspectActionProvider factory) { super.init(configurationNode, factory); config = new Configuration(configurationNode); } /** * @{inheritDoc */ public void save(Node parentNode) { if(parentNode instanceof Element) { config.save(parentNode); } else { Activator.log.error("parent node is not an Element", null); //$NON-NLS-1$ } } /** * {@inheritDoc} */ @Override @SuppressWarnings("unchecked") public void run(final EditPart editPart) { // so, we doesn't need to save the default values which can be modified // during the runtime config = new Configuration(config.getConfigurationNode()); // Apply the required stereotypes ApplyStereotypeRequest request = new ApplyStereotypeRequest(config.getStereotypesToApplyQN()); request.getExtendedData().put(ApplyStereotypeRequest.NEW_EDIT_PART_NAME, "NEW"); //$NON-NLS-1$ editPart.performRequest(request); /* * Looks like updateValue in ValueTreeObject and CompositeProperty to * apply the values properties to the elements */ // element where are the properties final EObject objectToEdit = ((View)editPart.getModel()).getElement(); if(!(objectToEdit instanceof org.eclipse.uml2.uml.NamedElement)) { // TODO for the Element which are not NamedElement return; } // we search the container for the object org.eclipse.uml2.uml.Element packageContainerTmp = ((org.eclipse.uml2.uml.Element)objectToEdit); do { packageContainerTmp = packageContainerTmp.getOwner(); } while(!(packageContainerTmp instanceof org.eclipse.uml2.uml.Package)); final org.eclipse.uml2.uml.Element packageContainer = packageContainerTmp; config.setAppliedProfiles(((org.eclipse.uml2.uml.Package)packageContainer).getAllAppliedProfiles()); if(config.hasRuntimeProperties()) { defineRuntimeProperties(config); } final TransactionalEditingDomain editingDomain = org.eclipse.papyrus.infra.core.utils.EditorUtils.getTransactionalEditingDomain(); // -----------------create a composite command CompositeCommand cmd = new CompositeCommand("Apply values for properties"); ArrayList<StereotypeRepresentation> stereotypes = config.getStereotypesRepresentations(); for(StereotypeRepresentation stereotype : stereotypes) { final Stereotype stereotypeToEdit = stereotype.getUMLStereotype(); ArrayList<PropertyRepresentation> properties = stereotype.getPropertiesWithValues(); for(PropertyRepresentation property : properties) { if(property.hasValues()) { Type type = property.getType(); final String propertyName = property.getUMLProperty().getName(); if(type != null && propertyName != null) { final Object newValue; if(type instanceof PrimitiveType) { newValue = Util.getValueFromString(property.getUMLProperty(), property.getStringValue()); } else if(Util.isMetaclass(type)) { newValue = Util.retrievesMetaclassElementFromString(property.getUMLProperty(), property.getStringValue(), packageContainer); // property is an Enumeration } else if(type instanceof org.eclipse.uml2.uml.Enumeration) { newValue = Util.retrievesEnumerationLiteralFromString(property.getUMLProperty(), property.getStringValue(), packageContainer); // property is a DataType } else if(type instanceof org.eclipse.uml2.uml.DataType) { newValue = Util.getValueFromString(property.getUMLProperty(), property.getStringValue()); // property is a Stereotype } else if(type instanceof Stereotype) { newValue = Util.retrievesStereotypedElementFromString(property.getUMLProperty(), property.getStringValue(), packageContainer); // property is a composite class } else if((type instanceof org.eclipse.uml2.uml.Class) && !(type instanceof Stereotype) && property.getUMLProperty().isMultivalued()) { // TODO newValue = null; } else { Activator.log.error("impossible to find a correct editor for the property" + property, null); //$NON-NLS-1$ return; } // we create and execute the recording command RecordingCommand command = null; if(newValue != null) { command = new RecordingCommand(editingDomain) { @Override protected void doExecute() { ((org.eclipse.uml2.uml.Element)objectToEdit).setValue(stereotypeToEdit, propertyName, newValue); } }; } if(command != null) { cmd.add(new EMFtoGMFCommandWrapper(command)); } } } } } final ICommand iCmd = cmd.reduce(); try { if(iCmd.canExecute()) { // execute the command editingDomain.runExclusive(new Runnable() { // public void run() { Display.getCurrent().asyncExec(new Runnable() { public void run() { editingDomain.getCommandStack().execute(new GMFtoEMFCommandWrapper(iCmd)); } }); } }); } } catch (InterruptedException e) { e.printStackTrace(); } } private void saveValues() { savedValues = new ArrayList<Value>(); for(StereotypeRepresentation steRep : config.getStereotypesRepresentations()) { if(steRep.hasRuntimeProperties()) { for(PropertyRepresentation propRep : steRep.getRuntimeProperties()) { for(Value value : propRep.getValues()) { Value newVal = new Value(value); newVal.setPropertyRepresentation(propRep); savedValues.add(newVal); } } } } } private void restoreValues() { for(Value val : savedValues) { } } /** * @{inheritDoc */ public Control createConfigurationComposite(Composite parent, IPaletteEntryProxy entryProxy, List<Profile> appliedProfiles) { config.setAppliedProfiles(appliedProfiles); this.entryProxy = entryProxy; Composite mainComposite = new Composite(parent, SWT.BORDER); GridLayout layout = new GridLayout(5, false); mainComposite.setLayout(layout); Label titleLabel = new Label(mainComposite, SWT.NONE); titleLabel.setText("Stereotypes to Apply"); //$NON-NLS-1$ GridData data = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); titleLabel.setLayoutData(data); addButton = new Button(mainComposite, SWT.NONE); addButton.setImage(Activator.getPluginIconImage(Activator.ID, ICONS_ADD)); addButton.addMouseListener(new MouseListener() { /** * @{inheritDoc */ public void mouseUp(MouseEvent e) { performAddButtonPressed(stereotypesViewer); selectionHasChange(); } /** * @{inheritDoc */ public void mouseDown(MouseEvent e) { } /** * @{inheritDoc */ public void mouseDoubleClick(MouseEvent e) { } }); removeButton = new Button(mainComposite, SWT.NONE); removeButton.setImage(Activator.getPluginIconImage(Activator.ID, ICONS_REMOVE)); removeButton.addMouseListener(new MouseListener() { /** * @{inheritDoc */ public void mouseUp(MouseEvent e) { performRemoveAction(stereotypesViewer); } /** * @{inheritDoc */ public void mouseDown(MouseEvent e) { } /** * @{inheritDoc */ public void mouseDoubleClick(MouseEvent e) { } }); removeButton.setEnabled(false); upButton = new Button(mainComposite, SWT.NONE); upButton.setImage(Activator.getPluginIconImage(Activator.ID, ICONS_UP)); upButton.addMouseListener(new MouseListener() { /** * @{inheritDoc */ public void mouseUp(MouseEvent e) { moveElement(MOVE_UP, stereotypesViewer); selectionHasChange(); } /** * @{inheritDoc */ public void mouseDown(MouseEvent e) { } /** * @{inheritDoc */ public void mouseDoubleClick(MouseEvent e) { } }); upButton.setEnabled(false); downButton = new Button(mainComposite, SWT.NONE); downButton.setImage(Activator.getPluginIconImage(Activator.ID, ICONS_DOWN)); downButton.addMouseListener(new MouseListener() { /** * @{inheritDoc */ public void mouseUp(MouseEvent e) { moveElement(MOVE_DOWN, stereotypesViewer); selectionHasChange(); } /** * @{inheritDoc */ public void mouseDown(MouseEvent e) { } /** * @{inheritDoc */ public void mouseDoubleClick(MouseEvent e) { } }); downButton.setEnabled(false); // stereotype viewer creation stereotypesViewer = new TreeViewer(mainComposite, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); data = new GridData(SWT.FILL, SWT.FILL, true, true); data.horizontalSpan = 5; stereotypesViewer.getControl().setLayoutData(data); stereotypesViewer.setContentProvider(stereotypeContentProvider); stereotypesViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { performSelectionChange(event); } }); stereotypesViewer.getControl().addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { } public void keyPressed(KeyEvent e) { if(e.keyCode == SWT.F2) { performF2Action(stereotypesViewer); } else if(e.character == SWT.DEL) { performRemoveAction(stereotypesViewer); } else if(e.stateMask == SWT.CTRL && e.keyCode == 110) {// e.character=='N' // doesn't // work performCTRL_N_Action(e, stereotypesViewer); } selectionHasChange(); } }); /* * we can't do : stereotypesViewer.addDoubleClickListener, because we * can't know on which column we are to make something or nothing! */ stereotypesViewer.getControl().addMouseListener(new MouseListener() { public void mouseUp(MouseEvent e) { } public void mouseDown(MouseEvent e) { } public void mouseDoubleClick(MouseEvent e) { if(stereotypeColumn != null) { if(e.x < stereotypeColumn.getColumn().getWidth()) {// we // are // on // the // stereotype // column performDoubleClickAction(stereotypesViewer); } else {// change the property value ViewerCell cell = runtimeColumn.getViewer().getCell(new Point(e.x, e.y)); if(cell != null) { Object element = ((TreeSelection)stereotypesViewer.getSelection()).getFirstElement(); stereotypesViewer.editElement(element, 1); } } } } }); createColumn(stereotypesViewer); updateStereotypeViewer(); return mainComposite; } /** * Create the necessary columns to have CellEditor in the tree * * @param viewer * the viewer owning the columns */ protected void createColumn(TreeViewer viewer) { stereotypeColumn = new TreeViewerColumn(viewer, SWT.FILL); stereotypeColumn.getColumn().setResizable(true); stereotypeColumn.getColumn().setWidth(300); stereotypeColumn.setLabelProvider(editorLabelProvider); stereotypeColumn.setEditingSupport(new AttributeEditingSupport(viewer)); runtimeColumn = new TreeViewerColumn(viewer, SWT.CENTER); runtimeColumn.getColumn().setText("Runtime"); //$NON-NLS-1$ runtimeColumn.getColumn().setResizable(true); runtimeColumn.getColumn().setWidth(80); runtimeColumn.setLabelProvider(new RuntimeLabelProvider()); runtimeColumn.setEditingSupport(new RuntimeEditingSupport(viewer)); viewer.getTree().setLinesVisible(true); viewer.getTree().setHeaderVisible(true); } /** * updates the stereotype viewer set the expandedNode refresh the status * button this method is called by * <ul> * <li> * {@link #createConfigurationComposite(Composite, PaletteEntryProxy, List)}</li> * <li> {@link #performAddButtonPressed(TreeViewer)} when we add or remove stereotypes</li> * </ul> */ protected void updateStereotypeViewer() { if(stereotypesViewer != null) { saveExpandedNode(); stereotypesViewer.setInput(config.getStereotypesRepresentations()); restoreExpandedNode(); } } /** * used to force the buttons update */ protected void selectionHasChange() { performSelectionChange(new SelectionChangedEvent(stereotypesViewer, stereotypesViewer.getSelection())); } /** * Action done when the add button is pressed * * @param tree * */ protected void performAddButtonPressed(TreeViewer tree) { TreeSelection selection = (TreeSelection)tree.getSelection(); Object selectedElement = selection.getFirstElement(); if(selection != null && selection.size() == 1 && !(selectedElement instanceof StereotypeRepresentation)) { if(selectedElement instanceof PropertyRepresentation) { // We want add a value to a multi-valued property or edit a // value to a mono-valued property PropertyRepresentation prop = (PropertyRepresentation)selectedElement; if(prop.getUpperMultiplicity() != 1) { editMe(prop, null);// we add a value } else if(!prop.getValues().isEmpty()) { // mono-valued // property and the // valu exists editMe(prop, prop.getValues().get(0)); } else {// monovalued property, the value doesn't exist editMe(prop, null); } tree.refresh(selectedElement); } return; } // pops-up a dialog window where users can select the additionnal // stereotypes to apply // it needs the metaclass information... // for this, entry Proxy should be a Palette entry proxy if(!(entryProxy instanceof IPaletteAspectToolEntryProxy)) { return; } PaletteEntry entry = ((IPaletteAspectToolEntryProxy)entryProxy).getEntry(); if(!(entry instanceof ToolEntry)) { return; } // this is a PaletteAspectToolEntryProxy // try to find the metaclass on which the element is working EClass metaClass = PaletteUtil.getToolMetaclass((ToolEntry)entry); if(metaClass == null) { Activator.log.error("Impossible to find metaclass", null); //$NON-NLS-1$ return; } // retrieve the original stereotype list from the qualified names List<Stereotype> stereotypeList = config.getUMLStereotypes();// retrieveStereotypesFromQualifiedNames(); // we have all applied profiles, the list of already applied // stereotypes, the metaclass of the created element... // just have to open a selection dialog final CheckedTreeSelectionDialog selectionDialog = new CheckedTreeSelectionDialog(DisplayUtils.getDisplay().getActiveShell(), editorLabelProvider, new ProfileContentProvider(metaClass)); selectionDialog.setTitle(Messages.StereotypePostAction_StereotypeSelectionTitle); selectionDialog.setMessage(Messages.StereotypePostAction_StereotypeSelectionMessage); selectionDialog.setContainerMode(true); selectionDialog.setInitialElementSelections(stereotypeList); selectionDialog.setInput(config.getAppliedProfiles()); selectionDialog.setExpandedElements(config.getAppliedProfiles().toArray()); ViewerComparator comparator = new ViewerComparator(); selectionDialog.setComparator(comparator); if(CheckedTreeSelectionDialog.OK == selectionDialog.open()) { // update the list of stereotype to apply Object[] result = selectionDialog.getResult(); ArrayList<String> stereotypesToApply = new ArrayList<String>(); for(int i = 0; i < result.length; i++) { if(result[i] instanceof Stereotype) { stereotypesToApply.add(((Stereotype)result[i]).getQualifiedName()); } } config.setStereotypesRepresentations(stereotypesToApply); // it's not possible to use refresh or update here! updateStereotypeViewer(); } } /** * Action done when the remove button is pressed * * @param viewer * the viewer on which the remove action is applied */ protected void performRemoveAction(TreeViewer viewer) { ITreeSelection selection = (ITreeSelection)viewer.getSelection(); if(selection != null) { List<?> selectedElements = ((TreeSelection)selection).toList(); if(sameLevelForFullSelection(selection)) { // all the element have the same type if(selection.getFirstElement() instanceof StereotypeRepresentation) { for(Object object : selectedElements) { if(object instanceof StereotypeRepresentation) { config.removeStereotype((StereotypeRepresentation)object); } } } else if(selection.getFirstElement() instanceof PropertyRepresentation) { // we delete the value for mono-valued property for(Object object : selectedElements) { if(object instanceof PropertyRepresentation) { if(!((PropertyRepresentation)object).getUMLProperty().isMultivalued()) { ((PropertyRepresentation)object).getValues().remove(0); } } } } else if(selection.getFirstElement() instanceof Value) { // we remove value from a multivalued property for(Object object : selectedElements) { if(object instanceof Value) { ((Value)object).getPropertyRepresentation().removeValue((Value)object); } } } viewer.refresh(); } } } /** * Action to do when the F2 key is pressed * <ul> * <li>open a CellEditor for the PrimitiveType and DataType</li> * <li>open a popup editor for others types</li> * </ul> * * @param viewer * the viewer on which the F2 action is applied */ protected void performF2Action(TreeViewer viewer) { TreeSelection selection = (TreeSelection)viewer.getSelection(); if((selection != null) && (selection.size() == 1)) { Object objectToEdit = selection.getFirstElement(); if(objectToEdit instanceof PropertyRepresentation) { Property prop = ((PropertyRepresentation)objectToEdit).getUMLProperty(); if(prop.isMultivalued() == false) { if((prop.getType() instanceof PrimitiveType) || (prop.getType() instanceof DataType)) { viewer.editElement(prop, 0); } else { // TODO } } } else if(objectToEdit instanceof Value) { PropertyRepresentation propRep = ((Value)objectToEdit).getPropertyRepresentation(); Type type = propRep.getType(); if(type != null) { if(type instanceof PrimitiveType || type instanceof DataType) { viewer.editElement(objectToEdit, 0); // the refresh is do by the cellEditor! (if the resfresh // is do here, there is a bug!) // viewer.refresh(property); } else {// popupEditor editMe(propRep, (Value)objectToEdit); viewer.refresh(propRep); } } } } } /** * Action done when a DoubleClick is received by the tree * * @param viewer * the viewer on which the DoubleClick action is applied */ protected void performDoubleClickAction(TreeViewer viewer) { TreeSelection selection = (TreeSelection)viewer.getSelection(); if(selection != null && selection.size() == 1) { Object selectedObject = selection.getFirstElement(); if(selectedObject instanceof StereotypeRepresentation) { // we expand or collapse the node viewer.setExpandedState(selectedObject, !viewer.getExpandedState(selectedObject)); } else if(selectedObject instanceof PropertyRepresentation) { Property prop = ((PropertyRepresentation)selectedObject).getUMLProperty(); if(prop.isMultivalued()) { // we expand or collapse the node viewer.setExpandedState(selectedObject, !viewer.getExpandedState(selectedObject)); } else { // we edit a value if(((PropertyRepresentation)selectedObject).getValues().isEmpty()) { editMe((PropertyRepresentation)selectedObject, null); } else { editMe((PropertyRepresentation)selectedObject, ((PropertyRepresentation)selectedObject).getValues().get(0)); } viewer.update(selectedObject, null); } } else if(selectedObject instanceof Value) { editMe(((Value)selectedObject).getPropertyRepresentation(), (Value)selectedObject); viewer.refresh(selectedObject); } } } /** * Action done when the user does a CTRL^N on the tree * * @param e * the KeyEvent * @param viewer * the TreeViewer in which we add something */ protected void performCTRL_N_Action(KeyEvent e, TreeViewer viewer) { TreeSelection selection = (TreeSelection)viewer.getSelection(); if(selection != null && selection.size() == 1) { Object selectedObject = selection.getFirstElement(); if(selectedObject != null) { if(selectedObject instanceof PropertyRepresentation) { Property property = ((PropertyRepresentation)selectedObject).getUMLProperty(); if(property.isMultivalued()) { // can we add a new value? int upperMultiplicity = property.getUpper(); ArrayList<Value> values = ((PropertyRepresentation)selectedObject).getValues(); if(upperMultiplicity == -1 || values.size() < upperMultiplicity) { editMe((PropertyRepresentation)selectedObject, null); } else if(values.size() == 0) { editMe((PropertyRepresentation)selectedObject, null); } viewer.refresh(selectedObject); } } } } } /** * Set the {@link Button#setEnabled(boolean)} parameter to true or false for * the buttons following the selected element in the {@link StereotypePostAction#stereotypeViewer} * <ul> * <li> {@link StereotypePostAction#addButton}</li> * <li> {@link StereotypePostAction#removeButton}</li> * <li> {@link StereotypePostAction#upButton}</li> * <li> {@link StereotypePostAction#downButton}</li> * </ul> * * @param event * the SelectionChangeEvent */ protected void performSelectionChange(SelectionChangedEvent event) { ITreeSelection selection = (ITreeSelection)event.getSelection(); int selectionSize = selection.size(); if((selectionSize == 0) || !(sameLevelForFullSelection(selection))) { addButton.setEnabled(true); removeButton.setEnabled(false); upButton.setEnabled(false); downButton.setEnabled(false); } else if(selectionSize == 1) { Object selectedElement = selection.getFirstElement(); // removeButton state if(selectedElement instanceof StereotypeRepresentation) { removeButton.setEnabled(true); } else if(selectedElement instanceof PropertyRepresentation) { if(((PropertyRepresentation)selectedElement).getUpperMultiplicity() == 1) { removeButton.setEnabled(true); } else { removeButton.setEnabled(false); } } else if(selectedElement instanceof Value) { removeButton.setEnabled(true); } // addButton state if(selectedElement instanceof StereotypeRepresentation) { addButton.setEnabled(true); } else if(selectedElement instanceof PropertyRepresentation) { ArrayList<Value> values = ((PropertyRepresentation)selectedElement).getValues(); Property prop = ((PropertyRepresentation)selectedElement).getUMLProperty(); if(!prop.isMultivalued()) { if(values.size() == 0) { addButton.setEnabled(true); } else { addButton.setEnabled(false); } } else {// multi-valued property} int upper = prop.getUpper(); if(upper == -1) { addButton.setEnabled(true); } else if(values.size() < upper) { addButton.setEnabled(true); } else { addButton.setEnabled(false); } } } else if(selectedElement instanceof Value) { addButton.setEnabled(false); } // upButton and downButton states if(selectedElement instanceof StereotypeRepresentation) { int index = config.getStereotypesRepresentations().indexOf(selectedElement); if(config.getStereotypesRepresentations().size() == 1) { downButton.setEnabled(false); upButton.setEnabled(false); } else if(index == 0) { downButton.setEnabled(true); upButton.setEnabled(false); } else if(index == config.getStereotypesRepresentations().size() - 1) { downButton.setEnabled(false); upButton.setEnabled(true); } else { downButton.setEnabled(true); upButton.setEnabled(true); } } else if(selectedElement instanceof PropertyRepresentation) { downButton.setEnabled(false); upButton.setEnabled(false); } else if(selectedElement instanceof Value) { ArrayList<Value> valuesList = ((Value)selectedElement).getPropertyRepresentation().getValues(); int index = valuesList.indexOf(selectedElement); if(valuesList.size() == 1) { upButton.setEnabled(false); downButton.setEnabled(false); } else if(index == 0) { upButton.setEnabled(false); downButton.setEnabled(true); } else if(index == valuesList.size() - 1) { upButton.setEnabled(true); downButton.setEnabled(false); } else { upButton.setEnabled(true); downButton.setEnabled(true); } } } else {// all the elements are from the same level List<?> selectedElements = ((TreeSelection)selection).toList(); if(selection.getFirstElement() instanceof StereotypeRepresentation) { removeButton.setEnabled(true); upButton.setEnabled(false); downButton.setEnabled(false); addButton.setEnabled(true); } else if(selection.getFirstElement() instanceof Value) { removeButton.setEnabled(true); upButton.setEnabled(false); downButton.setEnabled(false); addButton.setEnabled(false); } } } /** * move the selected element in stereotypeViewer following shiftValue * * * * @param shiftValue * shiftValue can take the values : * <ul> * <li>{@link StereotypePostAction#MOVE_UP}</li> * <li>{@link StereotypePostAction#MOVE_DOWN}</li> * </ul> * @param viewer * the TreeViewer in which we move elements * */ protected void moveElement(String shiftValue, TreeViewer viewer) { TreeSelection selection = (TreeSelection)viewer.getSelection(); if(selection != null && selection.size() == 1) { Object selectedElement = selection.getFirstElement(); if(selectedElement instanceof Value) { /** it's a property value */ exchangeTwoValues(((Value)selectedElement).getPropertyRepresentation().getValues(), selectedElement, shiftValue); viewer.refresh(((Value)selectedElement).getPropertyRepresentation()); } else if(selectedElement instanceof StereotypeRepresentation) { /** it's a stereotype */ exchangeTwoValues(config.getStereotypesRepresentations(), selectedElement, shiftValue); viewer.refresh(); } } } /** * Exchange the selectedElement with its neighbor, in arrayList, up or down * following shiftValue * * * @param arrayList * the ArrayList containing the elements to move * @param selectedElement * the element to move * @param shiftValue * shiftValue can take the values : * <ul> * <li>{@link StereotypePostAction#MOVE_UP}</li> * <li>{@link StereotypePostAction#MOVE_DOWN}</li> * </ul> */ @SuppressWarnings({ "rawtypes", "unchecked" }) protected void exchangeTwoValues(ArrayList arrayList, Object selectedElement, String shiftValue) { int index = getIndexOf(arrayList, selectedElement); /** * is it possible to move the objects ? */ if(arrayList == null || arrayList.size() < 2) { // the list is to small return; } if((shiftValue.equals(MOVE_UP) && index == 0) || (shiftValue.equals(MOVE_DOWN) && arrayList.size() == (index + 1))) { // the selected element is already the first or the last return; } if(shiftValue.equals(MOVE_DOWN)) { arrayList.set(index, arrayList.get(index + 1)); arrayList.set(index + 1, selectedElement); } else if(shiftValue.equals(MOVE_UP)) { arrayList.set(index, arrayList.get(index - 1)); arrayList.set(index - 1, selectedElement); } } /** * test if all the selected element in the selection are fron the same level * * @param selection * @return <ul> * <li>{@code true} if all the element are from the same level in the tree</li> * <li>{@code false if not}</li> * </ul> * */ protected boolean sameLevelForFullSelection(ITreeSelection selection) { // ITreeSelection selection = // (ITreeSelection)stereotypesViewer.getSelection(); // we do the delete action, only if all the elements have the same level List<?> selectedElements = ((TreeSelection)selection).toList(); if(!selectedElements.isEmpty()) { TreePath[] path = selection.getPathsFor(selectedElements.get(0)); if(path != null) { // the level for the first selected Element int level = path[0].getSegmentCount(); for(Object object : selectedElements) { path = selection.getPathsFor(object); if(level != path[0].getSegmentCount()) { /** * the selection is a mixed between different types of * elements */ return false; } } return true; } } return false; } /** * Returns the list of stereotypes applied by this action * * @return the list of stereotypes applied by this action */ public List<String> getStereotypesToApply() { return config.getStereotypesToApplyQN(); } /** * This class provides the methods for displaying the stereotypeViewer's * column. This class gives the correct Label and it's {@link Image} to * display for each element * * */ protected class EditorLabelProvider extends CellLabelProvider implements ILabelProvider { /** * @see org.eclipse.jface.viewers.CellLabelProvider#update(org.eclipse.jface.viewers.ViewerCell) * * @param cell */ @Override public void update(ViewerCell cell) { cell.setText(getText(cell.getElement())); cell.setImage(getImage(cell.getElement())); } /** * @{inheritDoc */ public String getText(Object element) { if(element instanceof Profile) { return ((Profile)element).getLabel(); } else if(element instanceof Stereotype) { return ((Stereotype)element).getLabel(); } else if(element instanceof StereotypeRepresentation) { return ((StereotypeRepresentation)element).getStereotypeQualifiedName(); } else if(element instanceof Value) { return ((Value)element).getValue(); } else if(element instanceof PropertyRepresentation) { return ((PropertyRepresentation)element).getLabel(); } return element.toString(); } /** * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object) * * @param element * @return */ public Image getImage(Object element) { if(element instanceof StereotypeRepresentation) { return Activator.getPluginIconImage(Activator.ID, ICON_STEREOTYPE); } else if(element instanceof PropertyRepresentation) { return Activator.getPluginIconImage(Activator.ID, ICON_PROPERTY); } else if(element instanceof Value) { Property property = ((Value)element).getPropertyRepresentation().getUMLProperty(); Type type = property.getType(); if(type != null) { if(type instanceof PrimitiveType) { String typeName = type.getQualifiedName(); // property is a boolean property if(UMLPrimitiveTypes_BOOLEAN.equals(typeName)) { return Activator.getPluginIconImage(Activator.ID, ICON_LITERALBOOLEAN); // property is a String } else if(UMLPrimitiveTypes_STRING.equals(typeName)) { return Activator.getPluginIconImage(Activator.ID, ICON_LITERALSTRING); // property is an Integer } else if(UMLPrimitiveTypes_INTEGER.equals(typeName)) { return Activator.getPluginIconImage(Activator.ID, ICON_LITERALINTEGER); // property is an unlimitedNatural } else if(UMLPrimitiveTypes_UNLIMITED_NATURAL.equals(typeName)) { return Activator.getPluginIconImage(Activator.ID, ICON_LITERALUNLIMITEDNATURAL); // property is a user primitive Type } else { // never used! // newVTO = new // UserPrimitiveTypeValueTreeObject(parent, // newValue, domain); } // property is a Metaclass property } else if(Util.isMetaclass(type)) { return Activator.getPluginIconImage(Activator.ID, ICON_METACLASS); // property is an Enumeration } else if(type instanceof org.eclipse.uml2.uml.Enumeration) { return Activator.getPluginIconImage(Activator.ID, ICON_ENUMERATION); // property is a DataType } else if(type instanceof org.eclipse.uml2.uml.DataType) { return Activator.getPluginIconImage(Activator.ID, ICON_DATATYPE); // property is a Stereotype } else if(type instanceof Stereotype) { return Activator.getPluginIconImage(Activator.ID, ICON_STEREOTYPE); // property is a composite class } else if((type instanceof org.eclipse.uml2.uml.Class) && !(type instanceof Stereotype) && property.isMultivalued()) { // TODO } } } else if(element instanceof Profile) { return Activator.getPluginIconImage(Activator.ID, ICON_PROFILE); } else if(element instanceof Stereotype) {// it's a stereotype return Activator.getPluginIconImage(Activator.ID, ICON_STEREOTYPE); } return Activator.getPluginIconImage(Activator.ID, ICON_UNKNOWN); } } /** * Content provider for the stereotype viewer */ protected class StereotypeContentProvider implements ITreeContentProvider { /** * @{inheritDoc */ public Object[] getChildren(Object parentElement) { if(parentElement instanceof List<?>) { return ((List<?>)parentElement).toArray(); } else if(parentElement instanceof StereotypeRepresentation) { return ((StereotypeRepresentation)parentElement).getPropertyRepresentations().toArray(); } else if(parentElement instanceof PropertyRepresentation) { if(((PropertyRepresentation)parentElement).getUpperMultiplicity() != 1 && ((PropertyRepresentation)parentElement).getValues().size() != 0) { return ((PropertyRepresentation)parentElement).getValues().toArray(); } } return new Object[0]; } /** * @{inheritDoc */ public Object getParent(Object element) { if(element instanceof Value) { return ((Value)element).getPropertyRepresentation(); } else if(element instanceof PropertyRepresentation) { return ((PropertyRepresentation)element).getStereotypeRepresentation(); } return null; } /** * @{inheritDoc */ public boolean hasChildren(Object element) { return getChildren(element) != null && (getChildren(element).length > 0); } /** * @{inheritDoc */ public Object[] getElements(Object inputElement) { return getChildren(inputElement); } /** * @{inheritDoc */ public void dispose() { } /** * @{inheritDoc */ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } /** * Content provider for the selection dialog */ protected class ProfileContentProvider implements ITreeContentProvider { /** metaclass of the element created by the tool */ final protected EClass metaclass; /** * Constructor. * * @param metaclass * the metaclass on which stereotypes can be applied */ public ProfileContentProvider(EClass metaclass) { this.metaclass = metaclass; } /** * @{inheritDoc */ public Object[] getChildren(Object parentElement) { List<org.eclipse.uml2.uml.Element> children = new ArrayList<org.eclipse.uml2.uml.Element>(); if(parentElement instanceof Profile) { for(Stereotype stereotype : ((Profile)parentElement).getOwnedStereotypes()) { // check applicability boolean isValid = false; List<Class> metaclasses = stereotype.getAllExtendedMetaclasses(); for(Class stMetaclass : metaclasses) { java.lang.Class<? extends Class> metaclassClass = stMetaclass.getClass(); if(metaclassClass != null) { EClassifier metaClassifier = UMLPackage.eINSTANCE.getEClassifier(stMetaclass.getName()); if(((EClass)metaClassifier).isSuperTypeOf(metaclass)) { isValid = true; } } } if(isValid) { children.add(stereotype); } } } return children.toArray(); } /** * @{inheritDoc */ public Object getParent(Object element) { if(element instanceof Profile) { return ((Profile)element).getOwner(); } else if(element instanceof Stereotype) { return ((Stereotype)element).getProfile(); } return null; } /** * @{inheritDoc */ public boolean hasChildren(Object element) { return (element instanceof Profile); } /** * @{inheritDoc */ public Object[] getElements(Object inputElement) { if(inputElement instanceof List<?>) { return ((List<?>)inputElement).toArray(); } return new Object[0]; } /** * @{inheritDoc */ public void dispose() { } /** * @{inheritDoc */ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } /** * Give the correct editor to a property following the property type. Fill * the hashmaps with the new value * <ul> * <li>if {@code value==null}, we add a value to a multi-valued property</li> * <li>if {@code value!=null}, we modify a value</li> * </ul> * * @param property * @param value */ public void editMe(PropertyRepresentation propRepresentation, Value valueToEdit) { Type type = propRepresentation.getType(); Property property = propRepresentation.getUMLProperty(); String value = null; // property is a a primitive type if(type instanceof PrimitiveType) { String typeName = type.getQualifiedName(); // property is a boolean property if(UMLPrimitiveTypes_BOOLEAN.equals(typeName)) { value = PropertyEditors.BooleanEditor(property, valueToEdit); // property is a String } else if(UMLPrimitiveTypes_STRING.equals(typeName)) { value = PropertyEditors.StringEditor(property, valueToEdit); // property is an Integer } else if(UMLPrimitiveTypes_INTEGER.equals(typeName)) { value = PropertyEditors.IntegerEditor(property, valueToEdit); // property is an unlimitedNatural } else if(UMLPrimitiveTypes_UNLIMITED_NATURAL.equals(typeName)) { value = PropertyEditors.UnlimitedNaturalEditor(property, valueToEdit); /** property is a user primitive Type */ } else { // never used! // newVTO = new UserPrimitiveTypeValueTreeObject(parent, // newValue, domain); } // property is a Metaclass property } else if(Util.isMetaclass(type)) { value = PropertyEditors.MetaclassEditor(property, valueToEdit, config.getAppliedProfiles()); // property is an Enumeration } else if(type instanceof org.eclipse.uml2.uml.Enumeration) { value = PropertyEditors.EnumerationEditor(property, valueToEdit); // property is a DataType } else if(type instanceof org.eclipse.uml2.uml.DataType) { value = PropertyEditors.DataTypeEditor(property, valueToEdit); // property is a Stereotype } else if(type instanceof Stereotype) { value = PropertyEditors.StereotypeEditor(property, valueToEdit, config.getAppliedProfiles()); // property is a composite class } else if((type instanceof org.eclipse.uml2.uml.Class) && !(type instanceof Stereotype) && property.isMultivalued()) { value = PropertyEditors.CompositeClassEditor(property, valueToEdit); } else { Activator.log.error("Impossible to find a correct editor for the property" + property, null); //$NON-NLS-1$ return; } if(value == null && valueToEdit == null) { // nothing to do return; } else if(value == null && valueToEdit != null) { // we delete a value valueToEdit.getPropertyRepresentation().getValues().remove(valueToEdit); } else if(value != null && valueToEdit == null) { // we add a value propRepresentation.addValue(new Value(value)); } else if(value != null && valueToEdit != null) { // we change a value valueToEdit.setValue(value); } } /** * search the object in the ArrayList list, using == and not the equals * method * * @param list * @param obj * @return return the index of the object or -1 if it doesn't exist in the * list */ public int getIndexOf(ArrayList<?> list, Object obj) { int index = -1; for(int i = 0; i < list.size(); i++) { if(list.get(i) == obj) { index = i; } } return index; } /** * save the expanded Nodes */ protected void saveExpandedNode() { expandedElements = stereotypesViewer.getExpandedElements(); } /** * restore the expanded nodes */ protected void restoreExpandedNode() { if(expandedElements != null) { stereotypesViewer.setExpandedElements(expandedElements); expandedElements = null; } } /** * Class giving cell editors for the {@link stereotypesViewer} and for the {@link RuntimePropertiesDialog#tree} */ public class AttributeEditingSupport extends EditingSupport { /** proposals for boolean */ protected final String[] booleanProposals = new String[]{ "", "true", "false" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ protected TreeViewer treeViewer = null; /** * Constructor. * * @param viewer * viewer in which editors will open */ public AttributeEditingSupport(ColumnViewer viewer) { super(viewer); this.treeViewer = (TreeViewer)viewer; } /** * @{inheritDoc */ @Override protected boolean canEdit(Object element) { return true; } /** * @{inheritDoc */ @Override protected CellEditor getCellEditor(Object element) { Type type = null; CellEditor editor = null; if(element instanceof Value) { type = ((Value)element).getPropertyRepresentation().getType(); } if(type != null) { if(type instanceof PrimitiveType) { String typeName = type.getQualifiedName(); // property is a boolean property if(UMLPrimitiveTypes_BOOLEAN.equals(typeName)) { editor = createBooleanEditor(treeViewer.getTree()); // property is a String } else if(UMLPrimitiveTypes_STRING.equals(typeName)) { editor = new TextCellEditor(treeViewer.getTree()); // property is an Integer } else if(UMLPrimitiveTypes_INTEGER.equals(typeName)) { editor = new TextCellEditor(treeViewer.getTree()); // property is an unlimitedNatural } else if(UMLPrimitiveTypes_UNLIMITED_NATURAL.equals(typeName)) { editor = new TextCellEditor(treeViewer.getTree()); // property is a user primitive Type } else { // never used! // newVTO = new UserPrimitiveTypeValueTreeObject(parent, // newValue, domain); } } } return editor; } /** * Creates and return a combobox cell editor for a boolean type * * @param feature * the feature to edit * @return the newly created combo box cell editor */ protected CellEditor createBooleanEditor(Composite parent) { return new ComboBoxCellEditor(parent, booleanProposals, SWT.READ_ONLY); } /** * @{inheritDoc */ @Override protected Object getValue(Object element) { if(element instanceof Value) { Property prop = ((Value)element).getPropertyRepresentation().getUMLProperty(); if(prop.getType() != null) { if(prop.getType().getQualifiedName().equals(UMLPrimitiveTypes_BOOLEAN)) { for(int index = 0; index < booleanProposals.length; index++) { if(booleanProposals[index].equals(element.toString())) { return index; } } return 0; } } } return element.toString(); } /** * we use the Cell Editor only to replace a value. */ @Override protected void setValue(Object oldValue, Object newValue) { // property can't be null, because, we change a value, we never // create a new value if(!"".equals(newValue)) { //$NON-NLS-1$ if(oldValue instanceof Value) { Property property = ((Value)oldValue).getPropertyRepresentation().getUMLProperty(); if(property.getType() != null) { if(property.getType() instanceof PrimitiveType) { String typeName = property.getType().getQualifiedName(); if(UMLPrimitiveTypes_BOOLEAN.equals(typeName)) { setBooleanValue(oldValue, newValue); } else { ((Value)oldValue).setValue((String)newValue); } } else { ((Value)oldValue).setValue((String)newValue); } } treeViewer.refresh(oldValue); } } } /** * Sets the new boolean value on the given element. * * @param element * the model element * @param value * the new value */ protected void setBooleanValue(Object oldValue, Object newValue) { if(newValue == null || newValue.equals(0)) { ((Value)oldValue).getPropertyRepresentation().getValues().remove(oldValue); } else if(newValue.equals(1)) { ((Value)oldValue).setValue(booleanProposals[1]); } else if(newValue.equals(2)) { ((Value)oldValue).setValue(booleanProposals[2]); } else { Activator.log.error("Impossible to set boolean value " + newValue, null); //$NON-NLS-1$ } } } /** * This class provides a {@link CheckboxCellEditor} for the {@link StereotypePostAction#runtimeColumn} * * */ protected class RuntimeEditingSupport extends EditingSupport { /** editor */ private final CellEditor editor; /** * * Constructor. * * @param viewer * viewer in which editors will open */ public RuntimeEditingSupport(ColumnViewer viewer) { super(viewer); editor = new CheckboxCellEditor(null, SWT.NONE); } /** * * @see org.eclipse.jface.viewers.EditingSupport#getCellEditor(java.lang.Object) * * @param element * @return */ @Override protected CellEditor getCellEditor(Object element) { return editor; } /** * * @see org.eclipse.jface.viewers.EditingSupport#canEdit(java.lang.Object) * * @param element * @return */ @Override protected boolean canEdit(Object element) { if(element instanceof PropertyRepresentation) { return true; } return false; } /** * * @see org.eclipse.jface.viewers.EditingSupport#getValue(java.lang.Object) * * @param element * @return */ @Override protected Object getValue(Object element) { if(element instanceof PropertyRepresentation) { return ((PropertyRepresentation)element).isRuntime(); } return null; } /** * * @see org.eclipse.jface.viewers.EditingSupport#setValue(java.lang.Object, java.lang.Object) * * @param element * @param value */ @Override protected void setValue(Object element, Object value) { if(element instanceof PropertyRepresentation) { ((PropertyRepresentation)element).setRuntime((Boolean)value); stereotypesViewer.update(element, null); } } } /** * This class provides the methods for displaying the stereotypeViewer's * column. This class gives the correct Label and it's {@link Image} to * display for each element * */ protected class RuntimeLabelProvider extends CellLabelProvider implements ILabelProvider { /** * @see org.eclipse.jface.viewers.CellLabelProvider#update(org.eclipse.jface.viewers.ViewerCell) * * @param cell */ @Override public void update(ViewerCell cell) { cell.setText(getText(cell.getElement())); cell.setImage(getImage(cell.getElement())); } /** * @{inheritDoc */ public String getText(Object element) { return ""; //$NON-NLS-1$ } /** * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object) * * @param element * @return the image corresponding to the status (define or not at * runtime) */ public Image getImage(Object element) { if(element instanceof PropertyRepresentation) { if(((PropertyRepresentation)element).isRuntime()) { return Activator.getPluginIconImage(Activator.ID, ICON_CHECKED); } return Activator.getPluginIconImage(Activator.ID, ICON_UNCHECKED); } return null; } } /** * This method does the action to define the properties defined at runtime, * that's to say, open a dialog to propose editing the properties defined * during the palette customisation * * @param config * the configuration which contains all the applied stereotypes * with properties and values * @param editPart * the edit */ protected void defineRuntimeProperties(Configuration config) { /* * we copy the stereotype with runtime properties we copy the runtime * properties (note that the values aren't not copied) * * so steWithPropToEdit contains only stereotypes with only their * runtime properties. */ List<StereotypeRepresentation> steWithPropToEdit = new ArrayList<StereotypeRepresentation>(); for(StereotypeRepresentation ste : config.getStereotypesRepresentations()) { if(ste.hasRuntimeProperties()) { StereotypeRepresentation newSte = new StereotypeRepresentation(ste); for(PropertyRepresentation propRep : ste.getRuntimeProperties()) { PropertyRepresentation prop = new PropertyRepresentation(propRep); newSte.addProperty(prop); } steWithPropToEdit.add(newSte); } } RuntimePropertiesDialog dialog = new RuntimePropertiesDialog(new Shell(), steWithPropToEdit); dialog.open(); } /** * * This class provides a Dialog to define the properties values during the * element creation * */ protected class RuntimePropertiesDialog extends Dialog { /** the dialog title */ private String title = null; /** the dialog message */ private String message = null; /** the viewer */ private TreeViewer tree = null; /** * the list containing the {@link StereotypeRepresentation} with the * runtime roperties */ private List<StereotypeRepresentation> stereotypesRep; /** * * Constructor. * * @param parent * @param stereotypesList */ public RuntimePropertiesDialog(Shell parent, List<StereotypeRepresentation> steWithPropToEdit) { super(parent); this.title = Messages.StereotypePostAction_EditRuntimePropertiesTitle; this.message = Messages.StereotypePostAction_EditRuntimePropertiesMessage; this.stereotypesRep = steWithPropToEdit; } /** * * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) * * @param shell */ @Override protected void configureShell(Shell shell) { super.configureShell(shell); if(title != null) { shell.setText(title); } } /** * * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) * we remove the CANCEL Button * @param parent */ @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); } /** * * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) * * @param parent * @return */ @Override protected Control createDialogArea(Composite parent) { // create composite Composite composite = (Composite)super.createDialogArea(parent); GridLayout layout = new GridLayout(5, false); composite.setLayout(layout); if(message != null) { Label titleLabel = new Label(composite, SWT.WRAP); titleLabel.setText(message); GridData data = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); titleLabel.setLayoutData(data); } downButton = new Button(composite, SWT.NONE); downButton.setImage(Activator.getPluginIconImage(Activator.ID, ICONS_DOWN)); downButton.setEnabled(false); downButton.addMouseListener(new MouseListener() { public void mouseUp(MouseEvent e) { moveElement(MOVE_DOWN, tree); runtimeSelectionHasChange(); } public void mouseDown(MouseEvent e) { } public void mouseDoubleClick(MouseEvent e) { } }); upButton = new Button(composite, SWT.NONE); upButton.setImage(Activator.getPluginIconImage(Activator.ID, ICONS_UP)); upButton.setEnabled(false); upButton.addMouseListener(new MouseListener() { public void mouseUp(MouseEvent e) { moveElement(MOVE_UP, tree); runtimeSelectionHasChange(); } public void mouseDown(MouseEvent e) { } public void mouseDoubleClick(MouseEvent e) { } }); addButton = new Button(composite, SWT.NONE); addButton.setImage(Activator.getPluginIconImage(Activator.ID, ICONS_ADD)); addButton.setEnabled(false); addButton.addMouseListener(new MouseListener() { public void mouseUp(MouseEvent e) { // performedAddButtonRuntime(e); performAddButtonPressed(tree); tree.refresh(); runtimeSelectionHasChange(); } public void mouseDown(MouseEvent e) { } public void mouseDoubleClick(MouseEvent e) { } }); removeButton = new Button(composite, SWT.NONE); removeButton.setImage(Activator.getPluginIconImage(Activator.ID, ICONS_REMOVE)); removeButton.setEnabled(false); removeButton.addMouseListener(new MouseListener() { public void mouseUp(MouseEvent e) { performRemoveAction(tree); runtimeSelectionHasChange(); } public void mouseDown(MouseEvent e) { } public void mouseDoubleClick(MouseEvent e) { } }); // create the tree tree = new TreeViewer(parent, SWT.BORDER | SWT.MULTI); // tree.setContentProvider(new // RuntimePropertiesStereotypeContentProvider()); tree.setContentProvider(new StereotypeContentProvider()); tree.getControl().setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); createColumn(tree); tree.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { performSelectionChangeRuntime(event); } }); tree.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { performDoubleClickAction(tree); runtimeSelectionHasChange(); } }); tree.getControl().addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { } public void keyPressed(KeyEvent e) { if(e.keyCode == SWT.F2) { performF2Action(tree); } else if(e.character == SWT.DEL) { performRemoveAction(tree); } else if(e.stateMask == SWT.CTRL && e.keyCode == 110) {// e.character=='N' // doesn't // work // on // my // computer performCTRL_N_Action(e, tree); } runtimeSelectionHasChange(); } }); updateTreeViewer(); tree.expandAll(); return composite; } /** * create the column for the given * * @param viewer */ protected void createColumn(TreeViewer viewer) { final TreeViewerColumn stereotypeColumn = new TreeViewerColumn(viewer, SWT.FILL); stereotypeColumn.getColumn().setResizable(true); stereotypeColumn.getColumn().setWidth(400); stereotypeColumn.setLabelProvider(editorLabelProvider); stereotypeColumn.setEditingSupport(new AttributeEditingSupport(viewer)); } /** * update the TreevViewer */ private void updateTreeViewer() { tree.setInput(stereotypesRep); runtimeSelectionHasChange(); } /** * use to force the buttons's update */ private void runtimeSelectionHasChange() { performSelectionChangeRuntime(new SelectionChangedEvent(this.tree, tree.getSelection())); } /** * this function updates the buttons status * * @param event */ protected void performSelectionChangeRuntime(SelectionChangedEvent event) { ITreeSelection selection = (ITreeSelection)event.getSelection(); int selectionSize = selection.size(); if((selectionSize == 0) || !(sameLevelForFullSelection(selection))) { addButton.setEnabled(true); removeButton.setEnabled(false); upButton.setEnabled(false); downButton.setEnabled(false); } else if(selectionSize == 1) { Object selectedElement = selection.getFirstElement(); // removeButton state if(selectedElement instanceof StereotypeRepresentation) { removeButton.setEnabled(false); } else if(selectedElement instanceof PropertyRepresentation) { if(((PropertyRepresentation)selectedElement).getUpperMultiplicity() == 1) { removeButton.setEnabled(true); } else { removeButton.setEnabled(false); } } else if(selectedElement instanceof Value) { removeButton.setEnabled(true); } // addButton state if(selectedElement instanceof StereotypeRepresentation) { addButton.setEnabled(false); } else if(selectedElement instanceof PropertyRepresentation) { ArrayList<Value> values = ((PropertyRepresentation)selectedElement).getValues(); Property prop = ((PropertyRepresentation)selectedElement).getUMLProperty(); if(!prop.isMultivalued()) { if(values.size() == 0) { addButton.setEnabled(true); } else { addButton.setEnabled(false); } } else {// multi-valued property} int upper = prop.getUpper(); if(upper == -1) { addButton.setEnabled(true); } else if(values.size() < upper) { addButton.setEnabled(true); } else { addButton.setEnabled(false); } } } else if(selectedElement instanceof Value) { addButton.setEnabled(false); } // upButton and downButton states if(selectedElement instanceof StereotypeRepresentation) { int index = stereotypesRep.indexOf(selectedElement); if(config.getStereotypesRepresentations().size() == 1) { downButton.setEnabled(false); upButton.setEnabled(false); } else if(index == 0) { downButton.setEnabled(true); upButton.setEnabled(false); } else if(index == stereotypesRep.indexOf(selectedElement) - 1) { downButton.setEnabled(false); upButton.setEnabled(true); } else { downButton.setEnabled(true); upButton.setEnabled(true); } } else if(selectedElement instanceof PropertyRepresentation) { downButton.setEnabled(false); upButton.setEnabled(false); } else if(selectedElement instanceof Value) { ArrayList<Value> valuesList = ((Value)selectedElement).getPropertyRepresentation().getValues(); int index = valuesList.indexOf(selectedElement); if(valuesList.size() == 1) { upButton.setEnabled(false); downButton.setEnabled(false); } else if(index == 0) { upButton.setEnabled(false); downButton.setEnabled(true); } else if(index == valuesList.size() - 1) { upButton.setEnabled(true); downButton.setEnabled(false); } else { upButton.setEnabled(true); downButton.setEnabled(true); } } } else {// all the elements are from the same level if(selection.getFirstElement() instanceof StereotypeRepresentation) { removeButton.setEnabled(true); upButton.setEnabled(false); downButton.setEnabled(false); addButton.setEnabled(true); } else if(selection.getFirstElement() instanceof Value) { removeButton.setEnabled(true); upButton.setEnabled(false); downButton.setEnabled(false); addButton.setEnabled(false); } } } } }