/***************************************************************************** * 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 * Emilien Perico (Atos Origin) - fix bug on refresh * *****************************************************************************/ package org.eclipse.papyrus.uml.properties.profile.ui.compositesformodel; import java.util.ArrayList; import java.util.Iterator; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.papyrus.infra.core.utils.EditorUtils; import org.eclipse.papyrus.uml.profile.Activator; import org.eclipse.papyrus.uml.profile.ImageManager; import org.eclipse.papyrus.uml.profile.ui.dialogs.ProfileTreeSelectionDialog; import org.eclipse.papyrus.uml.properties.profile.ui.dialogs.FileSelectionFilter; import org.eclipse.papyrus.uml.properties.profile.ui.dialogs.Message; import org.eclipse.papyrus.uml.properties.profile.ui.dialogs.RegisteredProfileSelectionDialog; import org.eclipse.papyrus.uml.properties.profile.ui.panels.AppliedProfilePanel; import org.eclipse.papyrus.uml.tools.utils.PackageUtil; import org.eclipse.papyrus.uml.tools.utils.UMLUtil; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.List; import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; import org.eclipse.ui.model.WorkbenchContentProvider; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertyConstants; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.PackageImport; import org.eclipse.uml2.uml.Profile; /** * The Class ProfileComposite. */ public class AppliedProfileCompositeOnModel extends Composite { public final static String TAG_PROFILE_CHANGED = " (has changed, consider re-applying profile)"; /** * The add registered button. */ private Button addButton, removeButton, addRegisteredButton; /** * Listeners *. */ private MouseListener addButtonListener, removeButtonListener, addRegisteredButtonListener; /** * The applied label. */ private CLabel appliedLabel; private TransactionalEditingDomain domain; /** * the factory to create elements */ protected TabbedPropertySheetWidgetFactory factory; /** * The profiles. */ private List profiles; /** * profile listener */ private SelectionListener profilesListener; public Profile profiletoApply; /** * The selected element of the edior : an edit part or element in the outline for example. */ protected ISelection selectedElement; /** * The default constructor. * * @param style * the style of this panel * @param parent * the parent Composite for this panel */ public AppliedProfileCompositeOnModel(AppliedProfilePanel parent) { super(parent, SWT.NONE); this.setLayout(new FormLayout()); } /** * * * @param factory * @param parent */ public AppliedProfileCompositeOnModel(Composite parent, TabbedPropertySheetWidgetFactory factory) { super(parent, SWT.NONE); this.setLayout(new FormLayout()); this.factory = factory; } /** * apply profile done in asynchronous thread * * @param thepackage * the package where the profile will be applied * @param profile * to apply * @param withSubProfiles * yes if we want to apply all contained subprofiles */ protected void applyProfile(final Package thepackage, final Profile profile, final boolean withSubProfiles) { try { getDomain().runExclusive(new Runnable() { public void run() { Display.getCurrent().asyncExec(new Runnable() { public void run() { getDomain().getCommandStack().execute(new RecordingCommand(domain) { @Override protected void doExecute() { PackageUtil.applyProfile(thepackage, profile, withSubProfiles); refresh(); } }); } }); } }); } catch (Exception e) { Activator.logException(e, "Unable to apply selected profile."); } } /** * Button action : open a selection dialog box that allow the user to choose profiles to apply. */ protected void applyProfileButtonPressed() { // Create and open the dialog box // ResourceSelectionDialog dialog = // new ResourceSelectionDialog(getShell(), ResourcesPlugin.getWorkspace().getRoot(), "Apply Profiles"); ILabelProvider lp = new WorkbenchLabelProvider(); ITreeContentProvider cp = new WorkbenchContentProvider(); ArrayList<String> filetypes = new ArrayList<String>(); filetypes.add("uml"); ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), lp, cp); dialog.setTitle("Apply Profiles..."); dialog.setMessage("Choose profiles to apply"); dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); dialog.addFilter(new FileSelectionFilter(filetypes)); dialog.setValidator(new org.eclipse.papyrus.uml.properties.profile.ui.dialogs.FileSelectionValidator()); dialog.setDoubleClickSelects(true); dialog.setHelpAvailable(false); dialog.setAllowMultiple(true); dialog.open(); // If nothing is selected : abort if((dialog.getResult() == null) || (dialog.getResult().length < 1)) { return; } ArrayList<Package> importedModels = new ArrayList<Package>(); Package package_ = getSelectedPackage(); for(int i = 0; i < dialog.getResult().length; i++) { IFile selectedFile = (IFile)dialog.getResult()[i]; URI profileUri = URI.createURI("platform:/resource" + selectedFile.getFullPath().toString()); ResourceSet resourceSet = package_.eResource().getResourceSet(); Resource profileResource = resourceSet.getResource(profileUri, true); if(profileResource.getContents().get(0) instanceof Package) { Package importedModel = (Package)profileResource.getContents().get(0); importedModels.add(importedModel); } } if(importedModels.size() > 0) { ProfileTreeSelectionDialog profileDialog = new ProfileTreeSelectionDialog(getShell(), importedModels); profileDialog.open(); ArrayList<Profile> profilestoApply = profileDialog.getResult(); Message message = new Message("Profile application", "Applying profile..."); message.open(); Iterator<Profile> iterator = profilestoApply.iterator(); while(iterator.hasNext()) { applyProfile(package_, iterator.next(), false); } message.close(); } } /** * Creates the button that applies new profiles on selected package. */ private void createApplyProfileButton() { FormData data = new FormData(); // Button creation addButton = factory.createButton(this, "", SWT.PUSH); addButton.setImage(ImageManager.IMG_ADD); addButton.setToolTipText("Apply profile..."); addButton.setVisible(true); // Button placement data.right = new FormAttachment(addRegisteredButton, -ITabbedPropertyConstants.HSPACE); data.top = new FormAttachment(0, ITabbedPropertyConstants.VSPACE); addButton.setLayoutData(data); // Button listeners addButton.addMouseListener(addButtonListener = new MouseListener() { public void mouseDoubleClick(MouseEvent e) { } public void mouseDown(MouseEvent e) { } public void mouseUp(MouseEvent e) { applyProfileButtonPressed(); } }); } /** * */ public void createContent() { createLabel(); createUnapplyProfileButton(); createRegiteredProfileButton(); createApplyProfileButton(); profiles = createProfilesList(); profiles.setVisible(true); } /** * Create a label. */ private void createLabel() { FormData data = new FormData(); // Label creation appliedLabel = factory.createCLabel(this, "Applied profiles:", SWT.NONE); // Label placement data.left = new FormAttachment(0, ITabbedPropertyConstants.HSPACE); data.top = new FormAttachment(0, ITabbedPropertyConstants.VSPACE); appliedLabel.setLayoutData(data); } /** * Creates the profiles list. * * @return the list of applied profiles */ private List createProfilesList() { FormData data = new FormData(); // List of applied profiles List profiles = new List(this, SWT.V_SCROLL | SWT.MULTI | SWT.BORDER); // List placement data.left = new FormAttachment(0, ITabbedPropertyConstants.HSPACE); data.right = new FormAttachment(100, -ITabbedPropertyConstants.HSPACE); data.top = new FormAttachment(addButton, ITabbedPropertyConstants.VSPACE); data.bottom = new FormAttachment(100, -ITabbedPropertyConstants.VSPACE); profiles.setLayoutData(data); // List listeners profiles.addSelectionListener(profilesListener = new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { } public void widgetSelected(SelectionEvent e) { } }); return profiles; } /** * Creates the button used to apply a registered (= plugin enclosed) profile to the selected package. */ private void createRegiteredProfileButton() { FormData data = new FormData(); // Button creation addRegisteredButton = factory.createButton(this, "", SWT.PUSH); addRegisteredButton.setImage(ImageManager.IMG_ADDREG); addRegisteredButton.setToolTipText("Apply registered profile..."); addRegisteredButton.setVisible(true); // Button placement data.right = new FormAttachment(removeButton, -ITabbedPropertyConstants.HSPACE); data.top = new FormAttachment(0, ITabbedPropertyConstants.VSPACE); addRegisteredButton.setLayoutData(data); // Button listeners addRegisteredButton.addMouseListener(addRegisteredButtonListener = new MouseListener() { public void mouseDoubleClick(MouseEvent e) { } public void mouseDown(MouseEvent e) { } public void mouseUp(MouseEvent e) { registeredProfileButtonPressed(); } }); } /** * Creates a button used to unapply a profile from the selected package. */ private void createUnapplyProfileButton() { FormData data = new FormData(); // Button creation removeButton = factory.createButton(this, "", SWT.PUSH); removeButton.setImage(ImageManager.IMG_DELETE); removeButton.setToolTipText("Unapply profiles..."); removeButton.setVisible(true); // Button placement data.right = new FormAttachment(100, -ITabbedPropertyConstants.HSPACE); data.top = new FormAttachment(0, ITabbedPropertyConstants.VSPACE); removeButton.setLayoutData(data); // Button listeners removeButton.addMouseListener(removeButtonListener = new MouseListener() { public void mouseDoubleClick(MouseEvent e) { } public void mouseDown(MouseEvent e) { } public void mouseUp(MouseEvent e) { unapplyProfileButtonPressed(); } }); } /** * Dispose listeners. */ public void disposeListeners() { if(addButton != null && !addButton.isDisposed()) { addButton.removeMouseListener(addButtonListener); } if(removeButton != null && !removeButton.isDisposed()) { removeButton.removeMouseListener(removeButtonListener); } if(addRegisteredButton != null && !addRegisteredButton.isDisposed()) { addRegisteredButton.removeMouseListener(addRegisteredButtonListener); } if(profiles != null && !profiles.isDisposed()) { profiles.removeSelectionListener(profilesListener); } } public TransactionalEditingDomain getDomain() { return EditorUtils.getTransactionalEditingDomain(); } /** * * * @return */ protected List getProfiles() { return profiles; } /** * Gets the selected package. * * @return the selected package or null */ public Package getSelectedPackage() { Package selectedPackage = null; Object input = ((IStructuredSelection)selectedElement).getFirstElement(); Element element =UMLUtil.resolveUMLElement(input); if(element!=null && element instanceof Package ) { selectedPackage = (Package)element; } return selectedPackage; } /** * Checks if the profile applied has been changed since last application (definition does not match. * * @param _package * on which the profile is applied * @param _profile * the applied profile * @return true if the profile has changed */ private boolean isDirty(Package _package, Profile _profile) { boolean isDirty = false; // Retrieve model resourceSet ResourceSet pkge_resourceSet = _package.eResource().getResourceSet(); // Retrieve profile resource URI prof_URI = _profile.eResource().getURI(); Resource modelResource = pkge_resourceSet.getResource(prof_URI, true); if(modelResource.getContents().get(0) instanceof Profile) { // ckeck applied profile application definition vs profile definition referenced in file Profile profileInFile = (Profile)(modelResource.getContents().get(0)); if(_package.getProfileApplication(_profile) != null) { EPackage appliedProfileDefinition = _package.getProfileApplication(_profile).getAppliedDefinition(); EPackage fileProfileDefinition = null; // Check profiles qualified names to ensure the correct profiles are compared String appliedProfileName = _profile.getQualifiedName(); String fileProfileName = profileInFile.getQualifiedName(); if(!appliedProfileName.equals(fileProfileName)) { // The profile must be a subprofile Iterator<Profile> it = PackageUtil.getSubProfiles(profileInFile).iterator(); while(it.hasNext()) { Profile current = it.next(); fileProfileName = current.getQualifiedName(); if(fileProfileName.equals(appliedProfileName)) { profileInFile = current; } } } fileProfileDefinition = profileInFile.getDefinition(); if(appliedProfileDefinition != fileProfileDefinition) { isDirty = true; } } } return isDirty; } /** * refresh the composite */ public void refresh() { Package currentPackage = getSelectedPackage(); if(currentPackage != null && !profiles.isDisposed()) { profiles.removeAll(); EList<Profile> appliedProfiles = currentPackage.getAllAppliedProfiles(); for(int i = 0; i < appliedProfiles.size(); i++) { Profile currentProfile = appliedProfiles.get(i); String currentName = currentProfile.getQualifiedName(); if(currentName == null) { Activator.getDefault().getLog().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Warning a profile applied on " + currentPackage.getName() + " could not be found : \n\t" + currentProfile.toString())); } else if(isDirty(currentPackage, currentProfile)) { profiles.add(currentName + TAG_PROFILE_CHANGED); profiles.setData(currentName, currentProfile); } else { profiles.add(currentName); profiles.setData(currentName, currentProfile); } } } } /** * Button action : open the dialog box for registered profile selection. */ protected void registeredProfileButtonPressed() { RegisteredProfileSelectionDialog profileSelectionDialog = new RegisteredProfileSelectionDialog(getShell(), getSelectedPackage()); java.util.List<Profile> profilestoApply = profileSelectionDialog.run(); Iterator<Profile> iterator = profilestoApply.iterator(); while(iterator.hasNext()) { if(getSelectedPackage() != null) { this.applyProfile(getSelectedPackage(), iterator.next(), false); } } } public void setDomain(TransactionalEditingDomain domain) { this.domain = domain; } /** * Sets the selection. * * @param selection * the selection */ public void setSelection(ISelection selection) { this.selectedElement = selection; } /** * unApply profile done in asynchronous thread * * @param thepackage * the package where the profile will be unapplied * @param profile * to unapply */ protected void unApplyProfile(final Package thepackage, final Profile profile) { try { getDomain().runExclusive(new Runnable() { public void run() { Display.getCurrent().asyncExec(new Runnable() { public void run() { getDomain().getCommandStack().execute(new RecordingCommand(domain) { @Override protected void doExecute() { thepackage.unapplyProfile(profile); refresh(); } }); } }); } }); } catch (Exception e) { Activator.logException(e); } } /** * Button action : unaply the profiles selected by the user. */ protected void unapplyProfileButtonPressed() { // Retrieve indices of selected profiles to unapply int[] selectionIndices = profiles.getSelectionIndices(); if((selectionIndices == null) || (selectionIndices.length == 0)) { return; } // Parse selection for(int i = 0; i < selectionIndices.length; i++) { int currentIndex = selectionIndices[i]; // Remove TAG_PROFILE_CHANGED when it exists String itemName = profiles.getItem(currentIndex).replace(TAG_PROFILE_CHANGED, ""); Profile profileToUnapply = (Profile)profiles.getData(itemName); if(profileToUnapply == null) { return; } // Allow removal if profile is applied on current package // Not if it is applied from owner package EList appliedProfiles = getSelectedPackage().getAppliedProfiles(); if(appliedProfiles.contains(profileToUnapply)) { /**********************************************************************/ /** delete imported model libraries and types related to that profile */ // model libraries handling EList importedPackages = getSelectedPackage().getPackageImports(); Iterator<PackageImport> iterPI = importedPackages.iterator(); ArrayList importedPackagesToRemove = new ArrayList(); while(iterPI.hasNext()) { PackageImport pi = iterPI.next(); if(pi.getImportedPackage().getOwner() != null) { if(pi.getImportedPackage().getOwner().equals(profileToUnapply)) { importedPackagesToRemove.add(pi); } } } // remove model librairies // this has been done here to avoid concurrent modification of importedPackages for(int j = 0; j < importedPackagesToRemove.size(); j++) { importedPackages.remove(importedPackagesToRemove.get(j)); } } unApplyProfile(getSelectedPackage(), profileToUnapply); } } /** * Resolve semantic element * * @param object * the object to resolve * @return <code>null</code> or the semantic element associated to the specified object */ private EObject resolveSemanticObject(Object object) { if(object instanceof EObject) { return (EObject)object; } else if(object instanceof IAdaptable) { IAdaptable adaptable = (IAdaptable)object; if(adaptable.getAdapter(EObject.class) != null) { return (EObject)adaptable.getAdapter(EObject.class); } } return null; } }