/*****************************************************************************
* Copyright (c) 2008 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:
* Chokri Mraidha (CEA LIST) Chokri.Mraidha@cea.fr - Initial API and implementation
* Patrick Tessier (CEA LIST) Patrick.Tessier@cea.fr - modification
*
*****************************************************************************/
package org.eclipse.papyrus.uml.properties.profile.ui.compositesformodel;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.NotificationImpl;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.papyrus.infra.core.utils.EditorUtils;
import org.eclipse.papyrus.uml.profile.Activator;
import org.eclipse.papyrus.uml.profile.preference.ProfilePreferenceConstants;
import org.eclipse.papyrus.uml.profile.tree.ProfileElementContentProvider;
import org.eclipse.papyrus.uml.profile.tree.ProfileElementLabelProvider;
import org.eclipse.papyrus.uml.profile.tree.ProfileElementTreeViewerFilter;
import org.eclipse.papyrus.uml.profile.tree.objects.AppliedStereotypePropertyTreeObject;
import org.eclipse.papyrus.uml.profile.tree.objects.AppliedStereotypeTreeObject;
import org.eclipse.papyrus.uml.profile.tree.objects.StereotypedElementTreeObject;
import org.eclipse.papyrus.uml.profile.utils.Util;
import org.eclipse.papyrus.uml.properties.profile.ui.dialogs.ChooseSetStereotypeDialog;
import org.eclipse.papyrus.uml.properties.profile.ui.panels.AppliedStereotypePanel;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Stereotype;
// TODO: Auto-generated Javadoc
/**
* This composite is used to display applied stereotype in the model. It allows applying or desapply a stereotype
*/
public class AppliedStereotypeCompositeOnModel extends DecoratedTreeComposite implements ISelectionChangedListener {
/**
* Gets the domain.
*
* @return the domain
*/
public TransactionalEditingDomain getDomain() {
return EditorUtils.getTransactionalEditingDomain();
}
/** The panel that display applied stereotypes. */
private AppliedStereotypePanel appliedStereotypePanel;
/** The label. */
protected CLabel label;
/**
* The default constructor.
*
* @param parent
* the parent Composite for this panel
*/
public AppliedStereotypeCompositeOnModel(AppliedStereotypePanel parent) {
super(parent, SWT.NONE, "Applied stereotypes", true);
appliedStereotypePanel = parent;
}
/**
* create a composite applied stereotype on model.
*
* @param parent
* the parent composite
*/
public AppliedStereotypeCompositeOnModel(Composite parent) {
super(parent, SWT.NONE, "Applied stereotypes", true);
}
/**
* apply a stereotype on current selected element.
*/
protected void addAppliedStereotype() {
// Open stereotype selection (may add or remove)
ChooseSetStereotypeDialog dialog = new ChooseSetStereotypeDialog(this.getShell(), getElement());
int result = dialog.open();
if(result == ChooseSetStereotypeDialog.OK) {
// Retrieve selected element
Element element = getElement();
// compare the 2 lists (present list and future list
EList<Stereotype> oldStereotypeList = element.getAppliedStereotypes();
ArrayList<Stereotype> newStereotypeList = dialog.getSelectedElements();
// Keep newStereotype order (will be used at the end of the method)
EList<Stereotype> newOrderList = new BasicEList<Stereotype>();
newOrderList.addAll(newStereotypeList);
// If the 2 lists differ, apply the new list of stereotypes
if(!(newStereotypeList.equals(oldStereotypeList))) {
// Parse old list :
// if stereotype is in the new list : it is already applied
// --> don't unapply it
// --> remove it from new list
Iterator<Stereotype> it = oldStereotypeList.iterator();
while(it.hasNext()) {
Stereotype currentStOld = it.next();
if(newStereotypeList.contains(currentStOld)) {
newStereotypeList.remove(currentStOld);
} else {
unapplyStereotype(element, currentStOld);
}
}
// Already applied stereotype should have been removed
// apply others
Iterator<Stereotype> newApplyStereotypes = newStereotypeList.iterator();
while(newApplyStereotypes.hasNext()) {
Stereotype currentStereotype = newApplyStereotypes.next();
applyStereotype(element, currentStereotype);
}
// Update Stereotype order
// this.reorderStereotypeApplications(element, newOrderList);
// checkSelection(null);
selectionChanged(null);
if(appliedStereotypePanel != null) {
appliedStereotypePanel.refresh();
}
}
}
}
/**
* Button action : open a selection dialog box that allow the user to choose stereotypes to apply (or unapply).
*/
@Override
public void addButtonPressed() {
addAppliedStereotype();
}
/**
*
* {@inheritDoc}
*/
@Override
public Composite createContent(Composite parent, TabbedPropertySheetWidgetFactory factory) {
super.createContent(parent, factory);
createStereotypesTree();
removeButton.setToolTipText("Remove stereotype");
addButton.setToolTipText("Apply stereotype");
return this;
}
/**
* Creates the stereotypes tree.
*
* @return the tree of applied stereotypes and properties
*/
private void createStereotypesTree() {
// Tree viewer shows applied stereotypes
treeViewer.setContentProvider(new ProfileElementContentProvider());
treeViewer.setLabelProvider(new ProfileElementLabelProvider());
treeViewer.addFilter(new ProfileElementTreeViewerFilter());
treeViewer.addSelectionChangedListener(this);
}
/**
* Button action : modify display order of stereotypes (selected elements are pushed down in the list).
*/
@Override
public void downButtonPressed() {
int nbrOfSelection = getTree().getSelectionCount();
if(nbrOfSelection < 1) {
return;
}
TreeItem[] items = getTree().getSelection();
int indexLast = getTree().indexOf(items[items.length - 1]);
if(indexLast + 1 >= getElement().getAppliedStereotypes().size()) {
// do nothing
return;
}
for(int i = 0; i < nbrOfSelection; i++) {
TreeItem item = items[nbrOfSelection - 1 - i];
if(item.getData() instanceof AppliedStereotypeTreeObject) {
AppliedStereotypeTreeObject sTO = (AppliedStereotypeTreeObject)item.getData();
EList stereotypes = new BasicEList();
stereotypes.addAll(element.getAppliedStereotypes());
int index = stereotypes.indexOf(sTO.getStereotype());
if((index == -1) || (index >= stereotypes.size() - 1)) {
// Not found of already on top...
return;
}
stereotypes.move(index + 1, sTO.getStereotype());
this.reorderStereotypeApplications(element, stereotypes);
}
}
}
/**
* Edits the item.
*
* @param item
* the item
*/
@Override
public void editItem(TreeItem item) {
// do nothing
}
/**
* Gets the selected.
*
* @return Returns the selected element.
*/
public Element getSelected() {
return appliedStereotypePanel.getSelected();
}
/**
* Gets the tree.
*
* @return the tree
*/
public Tree getTree() {
return treeViewer.getTree();
}
/**
* Checks if is in stereotype display.
*
* @param st
* the stereotype
*
* @return true, if checks if is in stereotype display
*/
protected Boolean isInStereotypeDisplay(Stereotype st) {
return false;
}
/**
* Redraw the treeViewer while preserving selections and non-collapsed tree elements
* It is not sufficient to redraw only selected elements as an optimization, since
* derived stereotype attributes (that are not selected) might change in response to
* changing other attributes.
*
* @param propertyView
*/
public void refreshTreeViewer () {
treeViewer.refresh ();
}
/**
* Refresh the content of applied the applied stereotype tree.
*/
@Override
public void refresh() {
if(treeViewer.getTree() != null && !(treeViewer.getTree().isDisposed())) {
treeViewer.setInput(null);
treeViewer.refresh();
if(element != null) {
treeViewer.setInput(new StereotypedElementTreeObject(element));
}
StereotypedElementTreeObject rTO = (StereotypedElementTreeObject)treeViewer.getInput();
if(rTO == null) {
return;
}
// If the property is Multivalued show Up - Down
if((rTO.getChildren() != null) && (rTO.getChildren().length > 1)) {
upButton.setEnabled(true);
downButton.setEnabled(true);
} else {
upButton.setEnabled(false);
downButton.setEnabled(false);
}
if((rTO.getChildren() != null) && (rTO.getChildren().length == 0)) {
removeButton.setEnabled(false);
} else {
removeButton.setEnabled(true);
}
}
}
/**
* Button action : unapply the stereotypes selected by the user in the stereotype tree.
*/
@Override
public void removeButtonPressed() {
unapplyStereotype();
}
/**
* Selection changed.
*
* @param event
* the event
*/
public void selectionChanged(SelectionChangedEvent event) {
if(appliedStereotypePanel != null) {
if(event == null) {
appliedStereotypePanel.setSelectedProperty(null);
return;
}
IStructuredSelection structSelection = (IStructuredSelection)event.getSelection();
Object selection = structSelection.getFirstElement();
if(selection instanceof AppliedStereotypePropertyTreeObject) {
appliedStereotypePanel.setSelectedProperty((AppliedStereotypePropertyTreeObject)selection);
} else {
appliedStereotypePanel.setSelectedProperty(null);
}
}
}
/**
* Sets the input.
*
* @param element
* the element
*/
public void setInput(StereotypedElementTreeObject element) {
treeViewer.setInput(element);
if(Activator.getDefault().getPreferenceStore().getBoolean(ProfilePreferenceConstants.EXPAND_STEREOTYPES_TREE)) {
treeViewer.expandAll();
}
}
/**
* unapply stereotype on current selected element.
*/
protected void unapplyStereotype() {
int nbrOfSelection = getTree().getSelectionCount();
if(nbrOfSelection == 0) {
return;
}
for(int i = 0; i < nbrOfSelection; i++) {
TreeItem item = getTree().getSelection()[i];
if(item.getData() instanceof AppliedStereotypeTreeObject) {
AppliedStereotypeTreeObject sTO = (AppliedStereotypeTreeObject)item.getData();
unapplyStereotype(element, sTO.getStereotype());
sTO.removeMe();
}
}
if(appliedStereotypePanel != null) {
appliedStereotypePanel.refresh();
} else {
refresh();
}
}
/**
* Button action : modify display order of stereotypes (selected elements are pushed up in the list).
*/
@Override
public void upButtonPressed() {
int nbrOfSelection = getTree().getSelectionCount();
if(nbrOfSelection < 1) {
return;
}
TreeItem[] items = getTree().getSelection();
int indexFirst = getTree().indexOf(items[0]);
if(indexFirst == 0) {
// do nothing
return;
}
for(int i = 0; i < nbrOfSelection; i++) {
TreeItem item = items[i];
if(item.getData() instanceof AppliedStereotypeTreeObject) {
AppliedStereotypeTreeObject sTO = (AppliedStereotypeTreeObject)item.getData();
EList stereotypes = new BasicEList();
stereotypes.addAll(element.getAppliedStereotypes());
int index = stereotypes.indexOf(sTO.getStereotype());
if(index < 1) {
return;
}
stereotypes.move(index - 1, sTO.getStereotype());
this.reorderStereotypeApplications(element, stereotypes);
}
}
if(appliedStereotypePanel != null) {
appliedStereotypePanel.refresh();
} else {
refresh();
}
}
/**
* Apply stereotype.
*
* @param elt
* the elt
* @param st
* the st
*/
public void applyStereotype(final Element elt, final Stereotype st) {
try {
getDomain().runExclusive(new Runnable() {
public void run() {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
getDomain().getCommandStack().execute(new RecordingCommand(getDomain()) {
@Override
protected void doExecute() {
elt.applyStereotype(st);
refresh();
}
});
}
});
}
});
} catch (Exception e) {
System.err.println(e);
}
}
/**
* Unapply stereotype.
*
* @param elt
* the uml element
* @param st
* the stereotype to unapply
*/
protected void unapplyStereotype(final Element elt, final Stereotype st) {
// bugfix: a selected element is not necessary a diagram element (ex: selection in the outline)
try {
getDomain().runExclusive(new Runnable() {
public void run() {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
getDomain().getCommandStack().execute(new RecordingCommand(getDomain()) {
@Override
protected void doExecute() {
elt.unapplyStereotype(st);
elt.eNotify(new NotificationImpl(Notification.SET, true, true, true));
refresh();
}
});
}
});
}
});
} catch (Exception e) {
System.err.println(e);
}
}
/**
* change the order of applied stereotype
*
* @param element
* the UML element where stereotypes are applied
* @param stereotypes
* the lis of applied stereotypes with the wanted order
*/
public void reorderStereotypeApplications(final Element element, final EList stereotypes) {
try {
getDomain().runExclusive(new Runnable() {
public void run() {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
getDomain().getCommandStack().execute(new RecordingCommand(getDomain()) {
@Override
protected void doExecute() {
Util.reorderStereotypeApplications(element, stereotypes);
refresh();
}
});
}
});
}
});
} catch (Exception e) {
System.err.println(e);
}
}
}