Java tutorial
/* FeatureIDE - A Framework for Feature-Oriented Software Development * Copyright (C) 2005-2016 FeatureIDE team, University of Magdeburg, Germany * * This file is part of FeatureIDE. * * FeatureIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * FeatureIDE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with FeatureIDE. If not, see <http://www.gnu.org/licenses/>. * * See http://featureide.cs.ovgu.de/ for further information. */ package de.ovgu.featureide.fm.ui.editors.featuremodel.operations; import static de.ovgu.featureide.fm.core.localization.StringTable.DELETE; import static de.ovgu.featureide.fm.core.localization.StringTable.DELETE_ERROR; import static de.ovgu.featureide.fm.core.localization.StringTable.IT_CAN_NOT_BE_REPLACED_WITH_AN_EQUIVALENT_ONE_; import static de.ovgu.featureide.fm.core.localization.StringTable.SELECT_ONLY_ONE_FEATURE_IN_ORDER_TO_REPLACE_IT_WITH_AN_EQUIVALENT_ONE_; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.gef.EditPart; import org.eclipse.gef.ui.parts.GraphicalViewerImpl; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.widgets.Shell; import de.ovgu.featureide.fm.core.FeatureDependencies; import de.ovgu.featureide.fm.core.Features; import de.ovgu.featureide.fm.core.base.FeatureUtils; import de.ovgu.featureide.fm.core.base.IConstraint; import de.ovgu.featureide.fm.core.base.IFeature; import de.ovgu.featureide.fm.core.base.IFeatureModel; import de.ovgu.featureide.fm.core.base.impl.Constraint; import de.ovgu.featureide.fm.core.base.impl.Feature; import de.ovgu.featureide.fm.ui.editors.DeleteOperationAlternativeDialog; import de.ovgu.featureide.fm.ui.editors.FeatureModelEditor; import de.ovgu.featureide.fm.ui.editors.featuremodel.GUIDefaults; import de.ovgu.featureide.fm.ui.editors.featuremodel.editparts.ConstraintEditPart; import de.ovgu.featureide.fm.ui.editors.featuremodel.editparts.FeatureEditPart; import de.ovgu.featureide.fm.ui.views.outline.FmOutlinePage; /** * Operation with functionality to delete multiple elements from the {@link FeatureModelEditor} and the {@link FmOutlinePage}. Enables Undo/Redo. * * @author Fabian Benduhn * @author Marcus Pinnecke */ public class ElementDeleteOperation extends MultiFeatureModelOperation implements GUIDefaults { private Object viewer; public ElementDeleteOperation(Object viewer, IFeatureModel featureModel) { super(featureModel, DELETE); this.viewer = viewer; } /** * Executes the requested delete operation. */ public void createSingleOperations() { /** * The key of the Map is the feature which could be replaced by their equivalents given at the * corresponding List. */ Map<IFeature, List<IFeature>> removalMap = new HashMap<>(); List<IFeature> alreadyDeleted = new LinkedList<>(); List<IFeature> commonAncestorList = null; for (Object element : getSelection().toArray()) { if (removeConstraint(element)) { continue; } IFeature parent = removeFeature(element, removalMap, alreadyDeleted); commonAncestorList = Features.getCommonAncestor(commonAncestorList, parent); } removeContainedFeatures(removalMap, alreadyDeleted); if (viewer instanceof GraphicalViewerImpl) { final GraphicalViewerImpl viewer2 = (GraphicalViewerImpl) viewer; final IFeature parent = (commonAncestorList != null && !commonAncestorList.isEmpty()) ? commonAncestorList.get(commonAncestorList.size() - 1) : null; final Object editPart = viewer2.getEditPartRegistry() .get(parent != null ? parent : featureModel.getStructure().getRoot()); if (editPart instanceof FeatureEditPart) { viewer2.setSelection(new StructuredSelection(editPart)); viewer2.reveal((EditPart) editPart); } } } private IStructuredSelection getSelection() { if (viewer instanceof GraphicalViewerImpl) { return (IStructuredSelection) ((GraphicalViewerImpl) viewer).getSelection(); } else { return (IStructuredSelection) ((TreeViewer) viewer).getSelection(); } } /** * If the given element is a {@link Constraint} it will be removed instantly. * * @param element The constraint to remove. * @return <code>true</code> if the given element was a constraint. */ private boolean removeConstraint(Object element) { if (element instanceof ConstraintEditPart) { IConstraint constraint = ((ConstraintEditPart) element).getConstraintModel().getObject(); operations.add(new DeleteConstraintOperation(constraint, featureModel)); return true; } else if (element instanceof IConstraint) { IConstraint constraint = ((IConstraint) element); operations.add(new DeleteConstraintOperation(constraint, featureModel)); return true; } return false; } /** * Tries to remove the given {@link Feature} else there will be an dialog for exception handling. * * @param element The feature to remove. * @param removalMap A map with the features and their equivalents. * @param alreadyDeleted A List of features which are already deleted. */ private IFeature removeFeature(Object element, Map<IFeature, List<IFeature>> removalMap, List<IFeature> alreadyDeleted) { IFeature feature = null; if (element instanceof IFeature) { feature = ((IFeature) element); } else if (element instanceof FeatureEditPart) { feature = ((FeatureEditPart) element).getFeature().getObject(); } if (feature != null) { final IFeature parent = FeatureUtils.getParent(feature); if (FeatureUtils.getRelevantConstraints(feature).isEmpty()) { // feature can be removed because it has no relevant constraint operations.add(new DeleteFeatureOperation(featureModel, feature)); alreadyDeleted.add(feature); } else { // check for all equivalent features FeatureDependencies featureDependencies = new FeatureDependencies(featureModel, false); List<IFeature> equivalent = new LinkedList<IFeature>(); for (IFeature f2 : featureDependencies.getImpliedFeatures(feature)) { if (featureDependencies.isAlways(f2, feature)) { equivalent.add(f2); } } removalMap.put(feature, equivalent); } return parent; } return null; } /** * Exception handling if the {@link Feature} to remove is contained in {@link Constraint}s.<br> * If the feature could be removed a {@link DeleteOperationAlternativeDialog} will be opened to * select the features to replace with.<br> * If the feature has no equivalent an error message will be displayed. * * @param removalMap A map with the features and their equivalents. * @param alreadyDeleted A List of features which are already deleted. */ private void removeContainedFeatures(Map<IFeature, List<IFeature>> removalMap, List<IFeature> alreadyDeleted) { if (!removalMap.isEmpty()) { boolean hasDeletableFeature = false; List<IFeature> toBeDeleted = new ArrayList<IFeature>(removalMap.keySet()); List<IFeature> notDeletable = new LinkedList<IFeature>(); for (Entry<IFeature, List<IFeature>> entry : removalMap.entrySet()) { List<IFeature> featureList = entry.getValue(); featureList.removeAll(toBeDeleted); featureList.removeAll(alreadyDeleted); if (featureList.isEmpty()) { notDeletable.add(entry.getKey()); } else { hasDeletableFeature = true; } } if (hasDeletableFeature) { // case: features can be replaced with an equivalent feature new DeleteOperationAlternativeDialog(featureModel, removalMap, this); } else { // case: features can NOT be replaced with an equivalent feature openErrorDialog(notDeletable); } } } /** * Opens an error dialog displaying the {@link Feature}s which could not be replaced by alternatives. * * @param notDeletable The not deletable features */ private void openErrorDialog(List<IFeature> notDeletable) { String notDeletedFeatures = null; for (IFeature f : notDeletable) { if (notDeletedFeatures == null) { notDeletedFeatures = "\"" + f.getName() + "\""; } else { notDeletedFeatures += ", \"" + f.getName() + "\""; } } MessageDialog dialog = new MessageDialog(new Shell(), DELETE_ERROR, FEATURE_SYMBOL, ((notDeletable.size() != 1) ? "The following features are contained in constraints:" : "The following feature is contained in constraints:") + "\n" + notDeletedFeatures + "\n" + ((notDeletable.size() != 1) ? SELECT_ONLY_ONE_FEATURE_IN_ORDER_TO_REPLACE_IT_WITH_AN_EQUIVALENT_ONE_ : IT_CAN_NOT_BE_REPLACED_WITH_AN_EQUIVALENT_ONE_), MessageDialog.ERROR, new String[] { IDialogConstants.OK_LABEL }, 0); dialog.open(); } }