Commit 4c7c52c8 authored by Simon Barner's avatar Simon Barner
Browse files

- AllocationTableEditor reacts on addition/removal of new models or entities

  Introduced ModelListenerEditorBase that might be reused for other editors, too
- General cleanup and improvements
refs 2950
parent 3b986730
......@@ -6,7 +6,8 @@ Bundle-Version: 2.11.0.qualifier
Bundle-Activator: org.fortiss.af3.allocation.ui.AF3AllocationUIActivator
Require-Bundle: org.eclipse.ui.ide;visibility:=reexport,
org.fortiss.af3.allocation,
org.fortiss.tooling.base.ui
org.fortiss.tooling.base.ui,
org.fortiss.af3.project
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Vendor: fortiss GmbH
......
......@@ -17,6 +17,8 @@ $Id$
+--------------------------------------------------------------------------*/
package org.fortiss.af3.allocation.ui.editor;
import static java.util.Collections.emptyList;
import static org.conqat.lib.commons.reflect.ReflectionUtils.isInstanceOfAny;
import static org.fortiss.af3.allocation.utils.AllocationUtils.addAllocationEntry;
import static org.fortiss.af3.allocation.utils.AllocationUtils.deleteAllocationEntry;
import static org.fortiss.af3.allocation.utils.AllocationUtils.isAllocated;
......@@ -32,6 +34,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ComboViewer;
......@@ -41,19 +44,24 @@ import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.fortiss.af3.allocation.model.AllocationEntry;
import org.fortiss.af3.allocation.model.AllocationTable;
import org.fortiss.tooling.base.model.element.IHierarchicElement;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.base.ui.editor.GEFEditorBase;
import org.fortiss.tooling.base.ui.tablecell.CheckBoxEditingSupport;
import org.fortiss.tooling.base.ui.tablecell.CheckBoxLabelProvider;
import org.fortiss.tooling.kernel.model.INamedElement;
import org.fortiss.tooling.kernel.model.IProjectRootElement;
import org.fortiss.tooling.kernel.ui.extension.IModelElementHandler;
import org.fortiss.tooling.kernel.ui.service.IModelElementHandlerService;
import org.fortiss.tooling.kernel.utils.KernelModelElementUtils;
/**
......@@ -65,7 +73,8 @@ import org.fortiss.tooling.kernel.utils.KernelModelElementUtils;
* @version $Rev$
* @ConQAT.Rating RED Hash:
*/
public abstract class AllocationTableEditor<T extends AllocationTable> extends GEFEditorBase<T> {
public abstract class AllocationTableEditor<T extends AllocationTable> extends
ModelListenerEditorBase<T> {
/** {@link AllocationEntry} type to be edited in this {@link AllocationTableEditor}. */
private Class<? extends AllocationEntry> allocationEntryType;
......@@ -118,48 +127,144 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends G
this.targetViewElementFilter = targetViewElementFilter;
}
/**
* Returns the {@link List} of models (i.e., {@link IProjectRootElement}s) of the given type;
*/
@SuppressWarnings("unchecked")
private List<IProjectRootElement> getModels(Class<? extends IProjectRootElement> type) {
List<? extends IProjectRootElement> models =
KernelModelElementUtils.getRootElements(getEditedObject(), type);
return (List<IProjectRootElement>)models;
/********************* Implementation of ModelListenerEditorBase *********************/
/** {@inheritDoc} */
@Override
protected boolean isEditedModel(Object object) {
return isInstanceOfAny(object, sourceModelType, targetModelType);
}
/** {@inheritDoc} */
@Override
protected void addModel(IProjectRootElement model) {
if(sourceModelType.isAssignableFrom(model.getClass())) {
addModel(gui.getComboViewerSource(), model);
} else if(targetModelType.isAssignableFrom(model.getClass())) {
addModel(gui.getComboViewerTarget(), model);
}
}
/** {@inheritDoc} */
@Override
protected void removeModel(IProjectRootElement model) {
if(sourceModelType.isAssignableFrom(model.getClass())) {
removeModel(gui.getComboViewerSource(), model);
} else if(targetModelType.isAssignableFrom(model.getClass())) {
removeModel(gui.getComboViewerTarget(), model);
}
}
/** {@inheritDoc} */
@Override
protected void refresh(IProjectRootElement model) {
if(sourceModelType.isAssignableFrom(model.getClass())) {
gui.getComboViewerSource().refresh();
} else if(targetModelType.isAssignableFrom(model.getClass())) {
gui.getComboViewerTarget().refresh();
}
gui.getTableViewer().refresh();
}
/** {@inheritDoc} */
@Override
protected boolean isEditedEntity(Object object) {
return isInstanceOfAny(object, sourceEntityType, targetEntityType);
}
/** {@inheritDoc} */
@Override
protected void modelSelectionChanged(IProjectRootElement model,
Consumer<IHierarchicElement> modelSetter, Supplier<IHierarchicElement> modelGetter) {
super.modelSelectionChanged(model, modelSetter, modelGetter);
// For now update the entire table
updateTableViewer();
}
/** {@inheritDoc} */
@Override
protected void addEntity(IModelElement entity) {
// For now update the entire table
updateTableViewer();
}
/** {@inheritDoc} */
@Override
protected void removeEntity(IModelElement entity) {
// For now update the entire table
updateTableViewer();
}
/********************* Implementation of IWorkbenchPart *********************/
/** {@inheritDoc} */
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
gui = new AllocationTableEditorGUI(parent, SWT.NONE);
ISelectionChangedListener sourceSelectionChangedListener = new ISelectionChangedListener() {
setupViewPointSelectionComboBox(gui.getComboViewerSource(), getModels(sourceModelType),
editedObject.getSourceView(), editedObject::setSourceView,
editedObject::getSourceView);
/** {@inheritDoc} */
@Override
public void selectionChanged(SelectionChangedEvent event) {
setViewFromSelection(event.getSelection(), editedObject::setSourceView,
editedObject::getSourceView);
setupViewPointSelectionComboBox(gui.getComboViewerTarget(), getModels(targetModelType),
editedObject.getTargetView(), editedObject::setTargetView,
editedObject::getTargetView);
}
createNewTable();
}
};
setupViewPointSelectionComboBox(gui.getComboViewerSource(), getModels(sourceModelType),
editedObject.getSourceView(), sourceSelectionChangedListener);
/********************* Model selection ComboBoxes *********************/
ISelectionChangedListener targetSelectionChangedListener = new ISelectionChangedListener() {
/** {@inheritDoc} */
@Override
public void selectionChanged(SelectionChangedEvent event) {
// Saves the target selection from the {@link ComboViewer}s into the model.
setViewFromSelection(event.getSelection(), editedObject::setTargetView,
editedObject::getTargetView);
/** {@link ISelectionChangedListener} for model view selection {@link ComboViewer}s. */
private class ModelViewComboBoxSelectionListener implements ISelectionChangedListener {
/** Method used to store the extracted view into the model. */
private Consumer<IHierarchicElement> modelSetter;
createNewTable();
/** Method used to extract the view that is currently set in the model. */
private Supplier<IHierarchicElement> modelGetter;
/** Constructor. */
public ModelViewComboBoxSelectionListener(Consumer<IHierarchicElement> modelSetter,
Supplier<IHierarchicElement> modelGetter) {
this.modelSetter = modelSetter;
this.modelGetter = modelGetter;
}
/** {@inheritDoc} */
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
setViewFromSelection(selection, modelSetter, modelGetter);
if(selection instanceof IStructuredSelection && !selection.isEmpty()) {
Object model = ((IStructuredSelection)selection).getFirstElement();
if(model instanceof IProjectRootElement) {
modelSelectionChanged((IProjectRootElement)model, modelSetter, modelGetter);
}
}
};
setupViewPointSelectionComboBox(gui.getComboViewerTarget(), getModels(targetModelType),
editedObject.getTargetView(), targetSelectionChangedListener);
}
/**
* Stores the source/target model referenced by the given {@code selection} to the
* {@link AllocationTable}.
*
* @param selection
* Selection depicting source/target model to be set.
* @param modelSetter
* Method used to store the extracted model into the model.
* @param modelGetter
* Method used to extract the view that is currently set in the model.
*/
private void setViewFromSelection(ISelection selection,
Consumer<IHierarchicElement> modelSetter, Supplier<IHierarchicElement> modelGetter) {
if(selection instanceof IStructuredSelection && !selection.isEmpty()) {
Object newModel = ((IStructuredSelection)selection).getFirstElement();
if(newModel instanceof IHierarchicElement && newModel != modelGetter.get()) {
runAsCommand(editedObject, () -> {
modelSetter.accept((IHierarchicElement)newModel);
});
}
}
}
}
/**
......@@ -172,23 +277,25 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends G
* Available models to be shown in {@code comboViewer}.
* @param selectedModel
* Initially selected model.
* @param selectionChangedListener
* {@link ISelectionChangedListener} used to react on selection changes in the given
* {@code comboViewer}.
* @param modelSetter
* Method used to store the extracted view into the model.
* @param modelGetter
* Method used to extract the view that is currently set in the model.
*/
private void setupViewPointSelectionComboBox(ComboViewer comboViewer,
List<IProjectRootElement> models, IHierarchicElement selectedModel,
ISelectionChangedListener selectionChangedListener) {
Consumer<IHierarchicElement> modelSetter, Supplier<IHierarchicElement> modelGetter) {
comboViewer.setContentProvider(new ArrayContentProvider());
comboViewer.setLabelProvider(new LabelProvider() {
/** {@inheritDoc} */
@Override
public String getText(Object element) {
return ((INamedElement)element).getName();
return getName(element);
}
});
comboViewer.addSelectionChangedListener(selectionChangedListener);
comboViewer.addSelectionChangedListener(new ModelViewComboBoxSelectionListener(modelSetter,
modelGetter));
comboViewer.setInput(models);
if(selectedModel != null) {
......@@ -197,61 +304,87 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends G
}
/**
* Stores the source/target view referenced by the given {@code selection} to the model.
*
* @param selection
* Selection depicting view to be stored in model.
* @param modelSetter
* Method used to store the extracted view into the model.
* @param modelGetter
* Method used to extract the view that is currently set in the model.
* <p>
* Adds the given {@code model} to the {@code comboViewer}. If in the {@link ComboViewer} no
* model is currently selected, the method sets the selection of a {@link ComboViewer} to the
* given element.
* </p>
* <p>
* This is done by iterating over the list of Items and finding the specific index. Then the
* selection is set using this index in order to circumvent the creation of
* {@link SelectionChangedEvent}s that would distort the UI. This is possibly inefficient but
* safer and still cleaner than directly storing indices.
* </p>
*/
private void setViewFromSelection(ISelection selection,
Consumer<IHierarchicElement> modelSetter, Supplier<IHierarchicElement> modelGetter) {
if(selection instanceof IStructuredSelection && !selection.isEmpty()) {
Object view = ((IStructuredSelection)selection).getFirstElement();
if(view instanceof IHierarchicElement && view != modelGetter.get()) {
runAsCommand(editedObject, () -> {
modelSetter.accept((IHierarchicElement)view);
});
private void addModel(ComboViewer comboViewer, IProjectRootElement element) {
comboViewer.add(element);
Combo combo = comboViewer.getCombo();
if(combo.getSelectionIndex() == -1) {
for(int i = 0; i < combo.getItems().length; i++) {
if(comboViewer.getElementAt(i) == element) {
combo.select(i);
return;
}
}
}
}
/** Creates the TableViewer and adds the first (source) column to it. */
private void createNewTable() {
// dispose old table
for(TableColumn column : gui.getTableViewer().getTable().getColumns()) {
/** Removes a model from a {@link ComboViewer}. */
private void removeModel(ComboViewer comboViewer, IProjectRootElement model) {
comboViewer.remove(model);
Combo combo = comboViewer.getCombo();
if(combo.getItemCount() == 0) {
combo.deselectAll();
return;
}
}
/********************* Table Viewer *********************/
/**
* Updates (or creates) the {@link TableViewer} with the edited source/target entities and adds
* the first (source) column to it.
*/
protected void updateTableViewer() {
// Dispose old table. NOOP if it does not exist.
TableViewer tableViewer = gui.getTableViewer();
Table table = tableViewer.getTable();
table.setRedraw(false);
for(TableColumn column : table.getColumns()) {
column.dispose();
}
List<? extends IModelElement> sourceModelElements = getSourceViewModelElements();
gui.getTableViewer().setContentProvider(new ArrayContentProvider());
tableViewer.setContentProvider(new ArrayContentProvider());
TableViewerColumn firstColumn = new TableViewerColumn(gui.getTableViewer(), SWT.NONE);
TableViewerColumn firstColumn = new TableViewerColumn(tableViewer, SWT.NONE);
TableColumn tblclmnSrc = firstColumn.getColumn();
tblclmnSrc.setWidth(100);
tblclmnSrc.setText("\u2193 Src. | Tgt. \u2192"); // Down and right unicode arrow
firstColumn.setLabelProvider(new ColumnLabelProvider() {
/** {@inheritDoc} */
@Override
public Image getImage(Object element) {
return AllocationTableEditor.getImage(element);
}
/** {@inheritDoc} */
@Override
public String getText(Object element) {
INamedElement t = (INamedElement)element;
return t.getName();
return getName(element);
}
});
gui.getTableViewer().setInput(sourceModelElements);
tableViewer.setInput(sourceModelElements);
List<? extends IModelElement> targetModelElements = getTargetViewModelElements();
for(IModelElement targetElement : targetModelElements) {
TableViewerColumn tableViewerColumn =
new TableViewerColumn(gui.getTableViewer(), SWT.NONE);
TableViewerColumn tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
TableColumn tableColumn = tableViewerColumn.getColumn();
tableColumn.setWidth(100);
tableColumn.setText(((INamedElement)targetElement).getName());
tableColumn.setText(getName(targetElement));
tableColumn.setImage(getImage(targetElement));
CheckBoxLabelProvider checkBoxlabelProvider = new CheckBoxLabelProvider() {
@Override
......@@ -261,7 +394,6 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends G
return isAllocated(editedObject, allocationEntryType, sourceElement,
targetElement);
}
return false;
}
......@@ -269,7 +401,6 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends G
protected boolean isEnabled(Object element) {
if(element instanceof IModelElement) {
IModelElement sourceElement = (IModelElement)element;
return isModifiableAllocationEntry(editedObject, allocationEntryType,
sourceElement, targetElement);
}
......@@ -277,7 +408,7 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends G
}
};
tableViewerColumn.setLabelProvider(checkBoxlabelProvider);
tableViewerColumn.setEditingSupport(new CheckBoxEditingSupport(gui.getTableViewer()) {
tableViewerColumn.setEditingSupport(new CheckBoxEditingSupport(tableViewer) {
/** {@inheritDoc} */
@Override
......@@ -328,27 +459,29 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends G
}
});
}
gui.getTableViewer().refresh();
tableViewer.refresh();
table.setRedraw(true);
}
// TODO Move to LambdaUtils after release
/** Converts an {@link Iterator} to a (sequential) {@link Stream}. */
private static <T> Stream<T> asStream(Iterator<T> iterator) {
Iterable<T> iterable = new Iterable<T>() {
/** {@inheritDoc} */
@Override
public Iterator<T> iterator() {
return iterator;
}
};
/********************* Binding to underlying model *********************/
return StreamSupport.stream(iterable.spliterator(), false);
/**
* Returns the {@link List} of models (i.e., {@link IProjectRootElement}s) of the given type;
*/
@SuppressWarnings("unchecked")
private List<IProjectRootElement> getModels(Class<? extends IProjectRootElement> type) {
List<? extends IProjectRootElement> models =
KernelModelElementUtils.getRootElements(getEditedObject(), type);
return (List<IProjectRootElement>)models;
}
/** Determines the list of model elements offered for a given {@code modelView}. */
private List<? extends IModelElement> getModelViewElements(IHierarchicElement modelView,
Class<? extends IModelElement> entityType, ViewElementFilter elementFilter) {
if(modelView == null) {
return emptyList();
}
Stream<IModelElement> modelElements =
asStream(modelView.eAllContents()).filter(entityType::isInstance).map(
entityType::cast);
......@@ -370,4 +503,58 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends G
return getModelViewElements(editedObject.getTargetView(), targetEntityType,
targetViewElementFilter);
}
/********************* Utility Methods *********************/
// TODO Move to a utility class after the release
/**
* Returns a UI name for the given {@code element}, or {@code null} in case it cannot be
* determined.
*/
private static String getName(Object element) {
if(!(element instanceof EObject)) {
return null;
}
EObject eObject = (EObject)element;
IModelElementHandler<EObject> modelElementHandler =
IModelElementHandlerService.getInstance().getModelElementHandler(eObject);
if(modelElementHandler != null) {
return modelElementHandler.getName(eObject);
} else if(element instanceof INamedElement) {
return ((INamedElement)element).getName();
}
return null;
}
// TODO Move to a utility class after the release
/**
* Returns an {@link Image} for the given {@code element}, or {@code null} in case it cannot be
* determined.
*/
private static Image getImage(Object element) {
if(element instanceof EObject) {
EObject eObj = (EObject)element;
IModelElementHandler<EObject> modelElementHandler =
IModelElementHandlerService.getInstance().getModelElementHandler(eObj);
if(modelElementHandler != null) {
return modelElementHandler.getIcon(eObj);
}
}
return null;
}
// TODO Move to LambdaUtils after release
/** Converts an {@link Iterator} to a (sequential) {@link Stream}. */
private static <T> Stream<T> asStream(Iterator<T> iterator) {
Iterable<T> iterable = new Iterable<T>() {
/** {@inheritDoc} */
@Override
public Iterator<T> iterator() {
return iterator;
}
};
return StreamSupport.stream(iterable.spliterator(), false);
}
}
/*--------------------------------------------------------------------------+
$Id$
| |
| Copyright 2017 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.af3.allocation.ui.editor;
import static org.eclipse.emf.common.notify.Notification.ADD;
import static org.eclipse.emf.common.notify.Notification.REMOVE;
import static org.eclipse.emf.common.notify.Notification.REMOVING_ADAPTER;
import static org.eclipse.emf.common.notify.Notification.SET;
import static org.fortiss.af3.project.utils.ProjectUtils.getFileProject;
import static org.fortiss.tooling.kernel.model.FortissToolingKernelPackage.Literals.INAMED_ELEMENT__NAME;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.getParentElement;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.runAsCommand;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.fortiss.af3.project.model.FileProject;
import org.fortiss.tooling.base.model.element.IHierarchicElement;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.base.ui.editor.GEFEditorBase;
import org.fortiss.tooling.kernel.model.IProjectRootElement;
/**
* Base class for model editors that listen for changes in other parts of the model.
*
* @author barner
* @author $Author$
* @version $Rev$
* @ConQAT.Rating RED Hash: