Commit b5053888 authored by Simon Barner's avatar Simon Barner
Browse files

Working editor for 1:1, 1:n and n:1 allocations

TODO
 - Filter fake top-level elements (e.g., component architecture)
 - Update view on model change
 - Reflect model hierarchy (e.g., tree for rows, ?? for columns) to disambiguate duplicated names
 - More cleanup
refs 2950
parent e459dde0
......@@ -25,8 +25,8 @@ import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.fortiss.af3.allocation.model.AllocationTable;
/**
*
......@@ -37,93 +37,68 @@ import org.eclipse.swt.widgets.Table;
*/
public class AllocationTableEditorGUI extends Composite {
private Table table;
/** {@link TableViewer} used to edit {@link AllocationTable}. */
private TableViewer tableViewer;
private ComboViewer comboViewerSrc;
private ComboViewer comboViewerDst;
private Shell currentShell;
/** {@link ComboViewer} used to select source viewpoint. */
private ComboViewer comboViewerSource;
/** {@link ComboViewer} used to select target viewpoint. */
private ComboViewer comboViewerTarget;
/** Constructor. */
public AllocationTableEditorGUI(Composite parent, int style) {
super(parent, style);
setCurrentShell(parent.getShell());
setLayout(new GridLayout(2, false));
Label lblSrc = new Label(this, SWT.NONE);
lblSrc.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
lblSrc.setText("Src");
setComboViewerSrc(new ComboViewer(this, SWT.NONE));
Combo comboSrc = getComboViewerSrc().getCombo();
GridData gd_comboSrc = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
gd_comboSrc.widthHint = 265;
comboSrc.setLayoutData(gd_comboSrc);
Label lblDst = new Label(this, SWT.NONE);
lblDst.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
lblDst.setText("Dst");
setComboViewerDst(new ComboViewer(this, SWT.NONE));
Combo comboDst = getComboViewerDst().getCombo();
GridData gd_comboDst = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
gd_comboDst.widthHint = 270;
comboDst.setLayoutData(gd_comboDst);
Label labelSource = new Label(this, SWT.NONE);
labelSource.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
labelSource.setText("Source");
comboViewerSource = new ComboViewer(this, SWT.NONE);
Combo comboSource = getComboViewerSource().getCombo();
GridData gd_comboSource = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
gd_comboSource.widthHint = 265;
comboSource.setLayoutData(gd_comboSource);
Label labelTarget = new Label(this, SWT.NONE);
labelTarget.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
labelTarget.setText("Target");
comboViewerTarget = new ComboViewer(this, SWT.NONE);
Combo comboTarget = getComboViewerTarget().getCombo();
GridData gd_comboTarget = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
gd_comboTarget.widthHint = 270;
comboTarget.setLayoutData(gd_comboTarget);
new Label(this, SWT.NONE);
setTableViewer(new TableViewer(this, SWT.BORDER | SWT.FULL_SELECTION));
table = getTableViewer().getTable();
tableViewer = new TableViewer(this, SWT.BORDER | SWT.FULL_SELECTION);
Table table = getTableViewer().getTable();
table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
table.setLinesVisible(true);
table.setHeaderVisible(true);
}
/** Returns comboViewerSrc. */
public ComboViewer getComboViewerSrc() {
return comboViewerSrc;
}
/** Sets comboViewerSrc. */
public void setComboViewerSrc(ComboViewer comboViewerSrc) {
this.comboViewerSrc = comboViewerSrc;
}
/** Returns comboViewerDst. */
public ComboViewer getComboViewerDst() {
return comboViewerDst;
/** Returns {@link #comboViewerSource}. */
public ComboViewer getComboViewerSource() {
return comboViewerSource;
}
/** Sets comboViewerDst. */
public void setComboViewerDst(ComboViewer comboViewerDst) {
this.comboViewerDst = comboViewerDst;
/** Returns {@link #comboViewerTarget}. */
public ComboViewer getComboViewerTarget() {
return comboViewerTarget;
}
/** Returns tableViewer. */
/** Returns {@link #tableViewer}. */
public TableViewer getTableViewer() {
return tableViewer;
}
/** Sets tableViewer. */
public void setTableViewer(TableViewer tableViewer) {
this.tableViewer = tableViewer;
}
/** {@inheritDoc} */
@Override
public boolean setFocus() {
tableViewer.refresh();
return super.setFocus();
}
/** Returns currentShell. */
public Shell getCurrentShell() {
return currentShell;
}
/** Sets currentShell. */
public void setCurrentShell(Shell currentShell) {
this.currentShell = currentShell;
}
// /** {@inheritDoc} */
// @Override
// public boolean setFocus() {
// tableViewer.refresh();
// return super.setFocus();
// }
}
......@@ -34,13 +34,14 @@
<details key="body" value="return AllocationTableStaticImpl.getAllocationEntries(this, type);"/>
</eAnnotations>
<eGenericType eClassifier="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EEList">
<eTypeArguments eClassifier="#//AllocationEntry"/>
<eTypeArguments eTypeParameter="#//AllocationTable/getAllocationEntries.1/T"/>
</eGenericType>
<eTypeParameters name="T">
<eBounds eClassifier="#//AllocationEntry"/>
</eTypeParameters>
<eParameters name="type" lowerBound="1">
<eGenericType eClassifier="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EJavaClass">
<eTypeArguments>
<eUpperBound eClassifier="#//AllocationEntry"/>
</eTypeArguments>
<eTypeArguments eTypeParameter="#//AllocationTable/getAllocationEntries.1/T"/>
</eGenericType>
</eParameters>
</eOperations>
......
......@@ -19,6 +19,7 @@
<genOperations ecoreOperation="allocation.ecore#//AllocationTable/getAllocationEntries"/>
<genOperations ecoreOperation="allocation.ecore#//AllocationTable/getAllocationEntries.1">
<genParameters ecoreParameter="allocation.ecore#//AllocationTable/getAllocationEntries.1/type"/>
<genTypeParameters ecoreTypeParameter="allocation.ecore#//AllocationTable/getAllocationEntries.1/T"/>
</genOperations>
<genOperations ecoreOperation="allocation.ecore#//AllocationTable/getOneToOneAllocationEntries"/>
<genOperations ecoreOperation="allocation.ecore#//AllocationTable/getOneToManyAllocationEntries"/>
......
......@@ -17,7 +17,6 @@ $Id$
+--------------------------------------------------------------------------*/
package org.fortiss.af3.allocation.model.impl;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.generalizeList;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickInstanceOf;
import java.util.Set;
......@@ -67,11 +66,10 @@ public class AllocationTableStaticImpl {
*
* @return {@link AllocationEntry}s contained by the given {@link AllocationTable}.
*/
public static EList<AllocationEntry> getAllocationEntries(AllocationTable allocationTable,
Class<? extends AllocationEntry> type) {
public static <T extends AllocationEntry> EList<T> getAllocationEntries(
AllocationTable allocationTable, Class<T> type) {
return generalizeList(AllocationEntry.class,
pickInstanceOf(type, allocationTable.getContainedElements()));
return pickInstanceOf(type, allocationTable.getContainedElements());
}
/**
......
......@@ -17,8 +17,15 @@ $Id$
+--------------------------------------------------------------------------*/
package org.fortiss.af3.allocation.utils;
import static org.eclipse.emf.ecore.util.EcoreUtil.create;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.getEClassForClass;
import org.fortiss.af3.allocation.model.AF3AllocationFactory;
import org.fortiss.af3.allocation.model.AllocationEntry;
import org.fortiss.af3.allocation.model.AllocationTableCollection;
import org.fortiss.af3.allocation.model.ManyToOneAllocationEntry;
import org.fortiss.af3.allocation.model.OneToManyAllocationEntry;
import org.fortiss.af3.allocation.model.OneToOneAllocationEntry;
/**
* Model element factory for AF3 allocation.
......@@ -43,4 +50,19 @@ public class AllocationModelElementFactory {
allocationTableCollection.setName(name);
return allocationTableCollection;
}
/**
* Creates an {@link AllocationEntry} of the given {@code type}, where {@code represents} a
* concrete sub-class of {@link OneToOneAllocationEntry}, {@link OneToManyAllocationEntry}, or
* {@link ManyToOneAllocationEntry}.
*
* @param type
* {@link AllocationEntry} concretization to be created.
*
* @return {@link AllocationEntry} of the given {@code type}.
*/
@SuppressWarnings("unchecked")
public static <T extends AllocationEntry> T createAllocationEntry(Class<T> type) {
return (T)create(getEClassForClass(type));
}
}
/*--------------------------------------------------------------------------+
$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.utils;
import static org.fortiss.af3.allocation.utils.AllocationModelElementFactory.createAllocationEntry;
import static org.fortiss.tooling.kernel.utils.JavaUtils.isDirectlyDerived;
import org.fortiss.af3.allocation.model.AllocationEntry;
import org.fortiss.af3.allocation.model.AllocationTable;
import org.fortiss.af3.allocation.model.AllocationTableCollection;
import org.fortiss.af3.allocation.model.ManyToOneAllocationEntry;
import org.fortiss.af3.allocation.model.OneToManyAllocationEntry;
import org.fortiss.af3.allocation.model.OneToOneAllocationEntry;
import org.fortiss.tooling.base.model.element.IModelElement;
/**
* Utility methods for working with allocations ({@link AllocationTableCollection}s,
* {@link AllocationTable}s, {@link AllocationEntry}s, ...).
*
* @author barner
* @author $Author$
* @version $Rev$
* @ConQAT.Rating RED Hash:
*/
public class AllocationUtils {
/**
* Allocates a particular source and target {@link IModelElement} within a given
* {@link AllocationTable}. {@link ManyToOneAllocationEntry}s ({@link OneToOneAllocationEntry})
* are extended, in case they already exist for the given {@code targetElement} (
* {@code sourceElement}), but where the given {@code sourceElement} ({@code targetElement}) is
* still missing.
*
* @param allocationTable
* {@link AllocationTable} in which the given {@code sourceElement} /
* {@code targetElement}) should be allocated.
* @param entryType
* Type of {@link AllocationEntry}s to be considered
* @param sourceElement
* Source {@link IModelElement} to be allocated
* @param targetElement
* Target {@link IModelElement} to be allocated
*
* @return {@code true} iff the {@link AllocationTable} has been modified, i.e., the given
* {@code sourceElement} / {@code targetElement} has not already been allocated before.
*/
public static <T extends AllocationEntry> boolean addAllocationEntry(
AllocationTable allocationTable, Class<T> entryType, IModelElement sourceElement,
IModelElement targetElement) {
// Abort if the entry already exists, or in case of erroneous input parameters
if(isAllocated(allocationTable, entryType, sourceElement, targetElement) ||
sourceElement == null || targetElement == null) {
return false;
}
// Get or create the allocation entry to be extended with a (sourceElement, targetElement)
// allocation.
T allocationEntry =
getAllocationEntry(allocationTable, entryType, isManyToOne(entryType) ? null
: sourceElement, isOneToMany(entryType) ? null : targetElement);
boolean createdEntry = false;
if(allocationEntry == null) {
allocationEntry = createAllocationEntry(entryType);
createdEntry = true;
}
if(isOneToOne(entryType)) {
OneToOneAllocationEntry oneToOneAllocationEntry =
(OneToOneAllocationEntry)allocationEntry;
oneToOneAllocationEntry.setSourceElement(sourceElement);
oneToOneAllocationEntry.setTargetElement(targetElement);
} else if(isOneToMany(entryType)) {
OneToManyAllocationEntry oneToManyAllocationEntry =
(OneToManyAllocationEntry)allocationEntry;
oneToManyAllocationEntry.setSourceElement(sourceElement);
oneToManyAllocationEntry.getTargetElements().add(targetElement);
} else if(isManyToOne(entryType)) {
ManyToOneAllocationEntry manyToOneAllocationEntry =
(ManyToOneAllocationEntry)allocationEntry;
manyToOneAllocationEntry.getSourceElements().add(sourceElement);
manyToOneAllocationEntry.setTargetElement(targetElement);
}
if(createdEntry) {
// Add new AllocationEntry if needed
// CAVEAT: AllocationTable.getAllocationEntries() returns an unmodifiable list!
allocationTable.getContainedElements().add(allocationEntry);
}
return true;
}
/** Deletes either the whole {@link AllocationEntry} or only the corresponding target/source. */
public static <T extends AllocationEntry> boolean deleteAllocationEntry(
AllocationTable allocationTable, Class<T> entryType, IModelElement sourceElement,
IModelElement targetElement) {
// Get the allocation entry from which the given (sourceElement, targetElement)
// allocation should be removed
T allocationEntry =
getAllocationEntry(allocationTable, entryType, sourceElement, targetElement);
// Abort if such allocation does not exist
if(allocationEntry == null) {
return false;
}
if(isOneToMany(entryType)) {
OneToManyAllocationEntry oneToManyAllocationEntry =
(OneToManyAllocationEntry)allocationEntry;
if(oneToManyAllocationEntry.getTargetElements().size() > 1) {
oneToManyAllocationEntry.getTargetElements().remove(targetElement);
return true;
}
} else if(isManyToOne(entryType)) {
ManyToOneAllocationEntry manyToOneAllocationEntry =
(ManyToOneAllocationEntry)allocationEntry;
if(manyToOneAllocationEntry.getSourceElements().size() > 1) {
manyToOneAllocationEntry.getSourceElements().remove(sourceElement);
return true;
}
}
// Remove the entry altogether for a OneToOneAllocationEntry, in case the last target
// (source) element is to be removed from a OneToManyAllocationEntry
// (ManyToOneAllocationEntry).
//
// CAVEAT: AllocationTable.getAllocationEntries() returns an unmodifiable list!
allocationTable.getContainedElements().remove(allocationEntry);
return true;
}
/**
* Predicate whether an {@link AllocationEntry} for a given {@code sourceElement} and
* {@code targetElement} exists. Either of {@code sourceElement} and {@code targetElement} (but
* not both) may be {@code null}, meaning "don't care".
*
* @param allocationTable
* {@link AllocationTable} for which to check if a matching {@link AllocationEntry}
* exists.
* @param entryType
* Considered {@link AllocationEntry} type.
* @param sourceElement
* Queried source element.
* @param targetElement
* Queried target element.
*
* @return {@code true} iff an {@link AllocationEntry} that links the given
* {@code sourceElement} and {@code targetElement}.
*/
public static boolean isAllocated(AllocationTable allocationTable,
Class<? extends AllocationEntry> entryType, IModelElement sourceElement,
IModelElement targetElement) {
return getAllocationEntry(allocationTable, entryType, sourceElement, targetElement) != null;
}
/**
* Predicate if the given source-target {@link IModelElement} pair is modifiable. There exist
* two cases:
* <ul>
* <li>The pair already exists, and hence it can be removed.</li>
* <li>The pair does not exist yet, and the constraints imposed by the given
* {@link AllocationEntry} allow for its creation.</li>
* </ul>
*/
public static boolean isModifiableAllocationEntry(AllocationTable allocationTable,
Class<? extends AllocationEntry> entryType, IModelElement sourceElement,
IModelElement targetElement) {
// It is possible to remove a current allocation (sourceElement, targetElement)
if(isAllocated(allocationTable, entryType, sourceElement, targetElement)) {
return true;
}
// Remember in the following that the case (sourceElement, targetElement) has just been
// ruled out
if(isOneToOne(entryType)) {
return !(isAllocated(allocationTable, entryType, null, targetElement) || isAllocated(
allocationTable, entryType, sourceElement, null));
} else if(isOneToMany(entryType)) {
// For 1:n mappings, a particular target can only be referenced by one source.
return !isAllocated(allocationTable, entryType, null, targetElement);
} else if(isManyToOne(entryType)) {
// For n:1 mappings, a particular source cannot be mapped onto different targets.
return !isAllocated(allocationTable, entryType, sourceElement, null);
}
// Never here
return true;
}
/**
* Returns the {@link AllocationEntry} for a given {@code sourceElement} and
* {@code targetElement} if it exists, {@code null} otherwise. Either of {@code sourceElement}
* and {@code targetElement} (but not both) may be {@code null}, meaning "don't care".
*
* @param allocationTable
* {@link AllocationTable} for which to determine the matching
* {@link AllocationEntry}.
* @param entryType
* {@link AllocationEntry} type to be obtained from given {@link AllocationTable}.
* @param sourceElement
* Source element expected in returned {@link AllocationEntry}.
* @param targetElement
* Target element expected in returned {@link AllocationEntry}.
*
* @return {@link AllocationEntry} for a given {@code sourceElement} and {@code targetElement}
* if it exists. {@code null} in case no {@link AllocationEntry} could be found, or if
* both {@code sourceElement} and {@code targetElement} are {@code null}.
*/
@SuppressWarnings("unchecked")
private static <T extends AllocationEntry> T getAllocationEntry(
AllocationTable allocationTable, Class<T> entryType, IModelElement sourceElement,
IModelElement targetElement) {
if(sourceElement == null && targetElement == null) {
return null;
}
if(isOneToOne(entryType)) {
for(OneToOneAllocationEntry allocationEntry : allocationTable
.getAllocationEntries(OneToOneAllocationEntry.class)) {
if((allocationEntry.getSourceElement() == sourceElement || sourceElement == null) &&
(allocationEntry.getTargetElement() == targetElement || targetElement == null)) {
return (T)allocationEntry;
}
}
} else if(isOneToMany(entryType)) {
for(OneToManyAllocationEntry allocationEntry : allocationTable
.getAllocationEntries(OneToManyAllocationEntry.class)) {
if((allocationEntry.getSourceElement() == sourceElement || sourceElement == null) &&
(allocationEntry.getTargetElements().contains(targetElement) || targetElement == null)) {
return (T)allocationEntry;
}
}
} else if(isManyToOne(entryType)) {
for(ManyToOneAllocationEntry allocationEntry : allocationTable
.getAllocationEntries(ManyToOneAllocationEntry.class)) {
if((allocationEntry.getSourceElements().contains(sourceElement) || sourceElement == null) &&
(allocationEntry.getTargetElement() == targetElement || targetElement == null)) {
return (T)allocationEntry;
}
}
}
return null;
}
// Keep below methods private to encapsulate case-distinctions in this utility class!
/**
* Predicate whether an {@link AllocationEntry} type is 1:1.
*/
private static boolean isOneToOne(Class<? extends AllocationEntry> entryType) {
return isDirectlyDerived(entryType, OneToOneAllocationEntry.class);
}
/** Predicate whether an {@link AllocationEntry} type is 1:n. */
private static boolean isOneToMany(Class<? extends AllocationEntry> entryType) {
return isDirectlyDerived(entryType, OneToManyAllocationEntry.class);
}
/** Predicate whether an {@link AllocationEntry} type is n:1. */
private static boolean isManyToOne(Class<? extends AllocationEntry> entryType) {
return isDirectlyDerived(entryType, ManyToOneAllocationEntry.class);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment