blob: 9c34c3b95b83270b94646a5858c519e640c0f64f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2013 Formal Mind GmbH and University of Dusseldorf.
* 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:
* Michael Jastram - initial API and implementation
******************************************************************************/
package org.eclipse.rmf.reqif10.pror.editor.presentation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.ui.viewer.IViewerProvider;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.emf.edit.ui.action.CreateChildAction;
import org.eclipse.emf.edit.ui.action.CreateSiblingAction;
import org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.ControlContribution;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.SubContributionItem;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.rmf.reqif10.ReqIF10Factory;
import org.eclipse.rmf.reqif10.ReqIF10Package;
import org.eclipse.rmf.reqif10.ReqIFContent;
import org.eclipse.rmf.reqif10.SpecHierarchy;
import org.eclipse.rmf.reqif10.SpecObject;
import org.eclipse.rmf.reqif10.SpecRelation;
import org.eclipse.rmf.reqif10.SpecRelationType;
import org.eclipse.rmf.reqif10.SpecType;
import org.eclipse.rmf.reqif10.common.util.ReqIF10Util;
import org.eclipse.rmf.reqif10.pror.editor.ISpecificationEditor;
import org.eclipse.rmf.reqif10.pror.editor.agilegrid.AgileCellEditorActionHandler;
import org.eclipse.rmf.reqif10.pror.filter.ReqifFilter;
import org.eclipse.rmf.reqif10.pror.filter.SimpleStringFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;
/**
* This is the action bar contributor for the Reqif10 model editor.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public class Reqif10ActionBarContributor
extends EditingDomainActionBarContributor
implements ISelectionChangedListener {
/**
* This keeps track of the active editor.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected IEditorPart activeEditorPart;
/**
* This keeps track of the current selection provider.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected ISelectionProvider selectionProvider;
private AgileCellEditorActionHandler agileCellEditorActionHandler;
/**
* List of all SpecObjects (directly or indirectly via SpecHierarchy) in the
* current selection.
*/
private List<SpecObject> linkSelection = new ArrayList<SpecObject>();
/**
* SpecObjects for which linking has been initiated.
*/
private List<SpecObject> linkSource = new ArrayList<SpecObject>();
/**
* This action opens the Properties view.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected IAction showPropertiesViewAction =
new Action(Reqif10EditorPlugin.INSTANCE.getString("_UI_ShowPropertiesView_menu_item")) {
@Override
public void run() {
try {
getPage().showView("org.eclipse.ui.views.PropertySheet");
}
catch (PartInitException exception) {
Reqif10EditorPlugin.INSTANCE.log(exception);
}
}
};
/**
* This action refreshes the viewer of the current editor if the editor
* implements {@link org.eclipse.emf.common.ui.viewer.IViewerProvider}.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected IAction refreshViewerAction =
new Action(Reqif10EditorPlugin.INSTANCE.getString("_UI_RefreshViewer_menu_item")) {
@Override
public boolean isEnabled() {
return activeEditorPart instanceof IViewerProvider;
}
@Override
public void run() {
if (activeEditorPart instanceof IViewerProvider) {
Viewer viewer = ((IViewerProvider)activeEditorPart).getViewer();
if (viewer != null) {
viewer.refresh();
}
}
}
};
/**
* This will contain one {@link org.eclipse.emf.edit.ui.action.CreateChildAction} corresponding to each descriptor
* generated for the current selection by the item provider.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected Collection<IAction> createChildActions;
/**
* This is the menu manager into which menu contribution items should be added for CreateChild actions.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected IMenuManager createChildMenuManager;
/**
* This will contain one {@link org.eclipse.emf.edit.ui.action.CreateSiblingAction} corresponding to each descriptor
* generated for the current selection by the item provider.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected Collection<IAction> createSiblingActions;
/**
* This is the menu manager into which menu contribution items should be
* added for CreateSibling actions. <!-- begin-user-doc --> <!--
* end-user-doc -->
*
* @generated NOT
*/
protected IMenuManager createSiblingMenuManager;
private Text quicksearch;
/**
* This creates an instance of the contributor. <!-- begin-user-doc -->
* Assignments were out-commented to remove them from the menuManager
* (IMenuManager) <!-- end-user-doc -->
*
* @generated NOT
*/
public Reqif10ActionBarContributor() {
super(ADDITIONS_LAST_STYLE);
}
@Override
public void init(IActionBars actionBars) {
super.init(actionBars);
agileCellEditorActionHandler = new AgileCellEditorActionHandler(
actionBars);
agileCellEditorActionHandler.setDeleteAction(deleteAction);
// actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(),
// deleteAction);
agileCellEditorActionHandler.setCutAction(cutAction);
// actionBars.setGlobalActionHandler(ActionFactory.CUT.getId(),
// cutAction);
agileCellEditorActionHandler.setCopyAction(copyAction);
// actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(),
// copyAction);
agileCellEditorActionHandler.setPasteAction(pasteAction);
// actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(),
// pasteAction);
agileCellEditorActionHandler.setUndoAction(undoAction);
// actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(),
// undoAction);
agileCellEditorActionHandler.setRedoAction(redoAction);
// actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(),
// redoAction);
}
/**
* This adds Separators for editor additions to the tool bar.
* <!-- begin-user-doc -->
* Adding Quick Search Box
* <!-- end-user-doc -->
* @generated NOT
*/
@Override
public void contributeToToolBar(IToolBarManager toolBarManager) {
toolBarManager.add(new Separator("reqif10-settings"));
toolBarManager.add(new Separator("reqif10-additions"));
toolBarManager.add(createQuickSearchToolbar());
}
private IContributionItem createQuickSearchToolbar() {
return new ControlContribution("quicksearch") {
private int width = -1;
private final int FIELD_SIZE = 25; // characters
@Override
protected Control createControl(Composite parent) {
return createQuickSearchControl(parent);
}
@Override
protected int computeWidth(Control control) {
if (width == -1) {
GC gc = new GC(control);
FontMetrics fm = gc.getFontMetrics();
width = FIELD_SIZE * fm.getAverageCharWidth();
}
return width;
}
};
}
private Control createQuickSearchControl(Composite parent) {
quicksearch = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL
| SWT.ICON_SEARCH);
quicksearch.setSize(500, 0);
quicksearch.setEnabled(activeEditorPart instanceof ISpecificationEditor);
quicksearch.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (activeEditorPart instanceof ISpecificationEditor) {
quicksearch.setEnabled(true);
ISpecificationEditor specEditor = (ISpecificationEditor) activeEditor;
final String text = quicksearch.getText();
if (text == null || "".equals(text)) {
specEditor.setFilter(null);
} else {
ReqifFilter filter = new SimpleStringFilter(text);
specEditor.setFilter(filter);
}
} else {
quicksearch.setEnabled(false);
}
}
});
return quicksearch;
}
/**
* This adds to the menu bar a menu and some separators for editor additions,
* as well as the sub-menus for object creation items.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void contributeToMenu(IMenuManager menuManager) {
super.contributeToMenu(menuManager);
IMenuManager submenuManager = new MenuManager(Reqif10EditorPlugin.INSTANCE.getString("_UI_Reqif10Editor_menu"), "org.eclipse.rmf.reqif10MenuID");
menuManager.insertAfter("additions", submenuManager);
submenuManager.add(new Separator("settings"));
submenuManager.add(new Separator("actions"));
submenuManager.add(new Separator("additions"));
submenuManager.add(new Separator("additions-end"));
// Prepare for CreateChild item addition or removal.
//
createChildMenuManager = new MenuManager(Reqif10EditorPlugin.INSTANCE.getString("_UI_CreateChild_menu_item"));
submenuManager.insertBefore("additions", createChildMenuManager);
// Prepare for CreateSibling item addition or removal.
//
createSiblingMenuManager = new MenuManager(Reqif10EditorPlugin.INSTANCE.getString("_UI_CreateSibling_menu_item"));
submenuManager.insertBefore("additions", createSiblingMenuManager);
// Force an update because Eclipse hides empty menus now.
//
submenuManager.addMenuListener
(new IMenuListener() {
public void menuAboutToShow(IMenuManager menuManager) {
menuManager.updateAll(true);
}
});
addGlobalActions(submenuManager);
}
/**
* When the active editor changes, this remembers the change and registers with it as a selection provider.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setActiveEditor(IEditorPart part) {
super.setActiveEditor(part);
activeEditorPart = part;
// Clear Quicksearch on switching editor. We trigger a notification to clear the Filter.s
if (quicksearch != null && ! quicksearch.isDisposed()) {
quicksearch.setText("");
}
// Switch to the new selection provider.
//
if (selectionProvider != null) {
selectionProvider.removeSelectionChangedListener(this);
}
if (part == null) {
selectionProvider = null;
}
else {
selectionProvider = part.getSite().getSelectionProvider();
selectionProvider.addSelectionChangedListener(this);
// Fake a selection changed event to update the menus.
//
if (selectionProvider.getSelection() != null) {
selectionChanged(new SelectionChangedEvent(selectionProvider, selectionProvider.getSelection()));
}
}
}
/**
* This implements {@link org.eclipse.jface.viewers.ISelectionChangedListener},
* handling {@link org.eclipse.jface.viewers.SelectionChangedEvent}s by querying for the children and siblings
* that can be added to the selected object and updating the menus accordingly.
* <!-- begin-user-doc -->
* Added selection management for the linking process
* <!-- end-user-doc -->
* @generated NOT
*/
public void selectionChanged(SelectionChangedEvent event) {
// Remove any menu items for old selection.
//
if (createChildMenuManager != null) {
depopulateManager(createChildMenuManager, createChildActions);
}
if (createSiblingMenuManager != null) {
depopulateManager(createSiblingMenuManager, createSiblingActions);
}
// Query the new selection for appropriate new child/sibling descriptors
//
Collection<?> newChildDescriptors = null;
Collection<?> newSiblingDescriptors = null;
ISelection selection = event.getSelection();
if (selection instanceof IStructuredSelection && ((IStructuredSelection)selection).size() == 1) {
Object object = ((IStructuredSelection)selection).getFirstElement();
EditingDomain domain = ((IEditingDomainProvider)activeEditorPart).getEditingDomain();
newChildDescriptors = domain.getNewChildDescriptors(object, null);
newSiblingDescriptors = domain.getNewChildDescriptors(null, object);
}
// Generate actions for selection; populate and redraw the menus.
//
createChildActions = generateCreateChildActions(newChildDescriptors, selection);
createSiblingActions = generateCreateSiblingActions(newSiblingDescriptors, selection);
if (createChildMenuManager != null) {
populateManager(createChildMenuManager, createChildActions, null);
createChildMenuManager.update(true);
}
if (createSiblingMenuManager != null) {
populateManager(createSiblingMenuManager, createSiblingActions, null);
createSiblingMenuManager.update(true);
}
// Stores the selection that is needed for link management.
saveLinkingSelection(selection);
}
/**
* Updates linkSelection by extracting all directly or indirectly contained
* {@link SpecObject}s.
*/
private void saveLinkingSelection(ISelection selection) {
linkSelection.clear();
if (selection instanceof IStructuredSelection) {
Iterator<?> iterator = ((IStructuredSelection)selection).iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
if (obj instanceof SpecObject) linkSelection.add((SpecObject) obj);
if (obj instanceof SpecHierarchy) {
SpecObject specObject = ((SpecHierarchy)obj).getObject();
if (obj != null) linkSelection.add(specObject);
}
}
}
}
/**
* This generates a {@link org.eclipse.emf.edit.ui.action.CreateChildAction} for each object in <code>descriptors</code>,
* and returns the collection of these actions.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected Collection<IAction> generateCreateChildActions(Collection<?> descriptors, ISelection selection) {
Collection<IAction> actions = new ArrayList<IAction>();
if (descriptors != null) {
for (Object descriptor : descriptors) {
actions.add(new CreateChildAction(activeEditorPart, selection, descriptor));
}
}
return actions;
}
/**
* This generates a {@link org.eclipse.emf.edit.ui.action.CreateSiblingAction} for each object in <code>descriptors</code>,
* and returns the collection of these actions.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected Collection<IAction> generateCreateSiblingActions(Collection<?> descriptors, ISelection selection) {
Collection<IAction> actions = new ArrayList<IAction>();
if (descriptors != null) {
for (Object descriptor : descriptors) {
actions.add(new CreateSiblingAction(activeEditorPart, selection, descriptor));
}
}
return actions;
}
/**
* This populates the specified <code>manager</code> with {@link org.eclipse.jface.action.ActionContributionItem}s
* based on the {@link org.eclipse.jface.action.IAction}s contained in the <code>actions</code> collection,
* by inserting them before the specified contribution item <code>contributionID</code>.
* If <code>contributionID</code> is <code>null</code>, they are simply added.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected void populateManager(IContributionManager manager, Collection<? extends IAction> actions, String contributionID) {
if (actions != null) {
for (IAction action : actions) {
if (contributionID != null) {
manager.insertBefore(contributionID, action);
}
else {
manager.add(action);
}
}
}
}
/**
* This removes from the specified <code>manager</code> all {@link org.eclipse.jface.action.ActionContributionItem}s
* based on the {@link org.eclipse.jface.action.IAction}s contained in the <code>actions</code> collection.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected void depopulateManager(IContributionManager manager, Collection<? extends IAction> actions) {
if (actions != null) {
IContributionItem[] items = manager.getItems();
for (int i = 0; i < items.length; i++) {
// Look into SubContributionItems
//
IContributionItem contributionItem = items[i];
while (contributionItem instanceof SubContributionItem) {
contributionItem = ((SubContributionItem)contributionItem).getInnerItem();
}
// Delete the ActionContributionItems with matching action.
//
if (contributionItem instanceof ActionContributionItem) {
IAction action = ((ActionContributionItem)contributionItem).getAction();
if (actions.contains(action)) {
manager.remove(contributionItem);
}
}
}
}
}
/**
* This populates the pop-up menu before it appears.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
@Override
public void menuAboutToShow(IMenuManager menuManager) {
// This taken and modified from super.menuAboutToShow(menuManager);
menuManager.add(new Separator("additions"));
menuManager.add(new Separator("edit"));
menuManager.add(new ActionContributionItem(deleteAction));
menuManager.add(new Separator("additions-end"));
addGlobalActions(menuManager);
MenuManager submenuManager = null;
submenuManager = new MenuManager(Reqif10EditorPlugin.INSTANCE.getString("_UI_CreateChild_menu_item"));
populateManager(submenuManager, createChildActions, null);
menuManager.insertBefore("edit", submenuManager);
submenuManager = new MenuManager(Reqif10EditorPlugin.INSTANCE.getString("_UI_CreateSibling_menu_item"));
populateManager(submenuManager, createSiblingActions, null);
menuManager.insertBefore("edit", submenuManager);
// New Code for Link Management
buildLinkMenuEntries(menuManager);
}
/**
* Extends the context menu for link management. It is only active if the
* current selection contains at least one {@link SpecObject} or one
* {@link SpecHierarchy}.<p>
*
* There is always an action "Initiate Linking" which saves the current selection as a starting point.<p>
*
* If a selection has been initiated, there are two additional entries "link to" and "link from" that complete the link
* process with the previously initiated selection.
*
* @param menuManager
*/
private void buildLinkMenuEntries(IMenuManager menuManager) {
if (linkSelection.isEmpty()) return;
MenuManager submenuManager;
menuManager.insertAfter("edit", new Separator());
ImageDescriptor toIcon = ExtendedImageRegistry.INSTANCE.getImageDescriptor(Reqif10EditorPlugin.INSTANCE.getImage(
"full/obj16/SpecRelationTo.png"));
ImageDescriptor fromIcon = ExtendedImageRegistry.INSTANCE.getImageDescriptor(Reqif10EditorPlugin.INSTANCE.getImage(
"full/obj16/SpecRelationFrom.png"));
if (!linkSource.isEmpty()) {
submenuManager = new MenuManager(
Reqif10EditorPlugin.INSTANCE
.getString("_Action_Complete_Linking_From", new String[] { linkSource.size() + "" }),
fromIcon, "_Action_Complete_Linking_From");
populateLinkMenu(submenuManager, linkSelection, linkSource);
menuManager.insertAfter("edit", submenuManager);
submenuManager = new MenuManager(
Reqif10EditorPlugin.INSTANCE
.getString("_Action_Complete_Linking_To", new String[] { linkSource.size() + "" }),
toIcon, "_Action_Complete_Linking_To");
populateLinkMenu(submenuManager, linkSource, linkSelection);
menuManager.insertAfter("edit", submenuManager);
}
IAction action = new Action(
Reqif10EditorPlugin.INSTANCE
.getString("_Action_Initiate_Linking", new String[] { linkSelection.size() + "" })) {
@Override
public void run() {
linkSource.clear();
linkSource.addAll(linkSelection);
}
};
menuManager.insertAfter("edit", action);
}
private void populateLinkMenu(IContributionManager manager, List<SpecObject> source, List<SpecObject> target) {
final EditingDomain domain = ((IEditingDomainProvider)activeEditorPart).getEditingDomain();
ReqIFContent coreContent = ReqIF10Util.getReqIF(linkSource.get(0)).getCoreContent();
manager.add(createLinkCommand(source, target, domain,
coreContent, null));
for (SpecType type : coreContent.getSpecTypes()) {
if (type instanceof SpecRelationType) {
manager.add(createLinkCommand(source, target, domain,
coreContent, (SpecRelationType) type));
}
}
}
/**
* Builds a command that creates the links between source and target, using type.
*/
private IAction createLinkCommand(List<SpecObject> source,
List<SpecObject> target, final EditingDomain domain,
ReqIFContent coreContent, SpecRelationType type) {
String label;
if (type == null) {
label = Reqif10EditorPlugin.INSTANCE
.getString("_Action_SpecRelation_Untyped");
} else {
String typeName = type.getLongName();
if (typeName == null)
typeName = type.getIdentifier();
label = Reqif10EditorPlugin.INSTANCE
.getString("_Action_SpecRelation_Typed", new String[] { typeName });
}
final CompoundCommand cmd = new CompoundCommand(label);
for (SpecObject sourceObject : source) {
for (SpecObject targetObject : target) {
SpecRelation specRelation = ReqIF10Factory.eINSTANCE.createSpecRelation();
specRelation.setSource(sourceObject);
specRelation.setTarget(targetObject);
specRelation.setType(type);
cmd.append(AddCommand.create(domain, coreContent,
ReqIF10Package.Literals.REQ_IF_CONTENT__SPEC_RELATIONS,
specRelation));
}
}
return new Action(label) {
@Override
public void run() {
domain.getCommandStack().execute(cmd);
}
};
}
/**
* This inserts global actions before the "additions-end" separator.
* <!-- begin-user-doc -->
* We don't want Refresh and Properties View - redundant in our application
* <!-- end-user-doc -->
* @generated NOT
*/
@Override
protected void addGlobalActions(IMenuManager menuManager) {
menuManager.insertAfter("additions-end", new Separator("ui-actions"));
super.addGlobalActions(menuManager);
}
/**
* This ensures that a delete action will clean up all references to deleted objects.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected boolean removeAllReferencesOnDelete() {
return true;
}
public AgileCellEditorActionHandler getAgileCellEditorActionHandler() {
return agileCellEditorActionHandler;
}
}