Commit 1c7c499c authored by Simon Barner's avatar Simon Barner
Browse files

- Allocation Metamodel: Make source and target view IProjectRootElements

- AllocationService: Add setInternalAllocationTable() and isAllocationTableInternal()
- AllocationTableEditor
 - Enable to embed AllocationTableEditor into other editors by means of a constructor that can be used to set the edited object
 - Don't crash with 'null' edited object
- ModelListenerEditorBase
  - add valueSet() callback that is triggered when a configurable feature is changed
  - Move ModelViewComboBoxSelectionListener, setupModelSelectionComboBox(), and updateModelSelectionComboBox() here
- AllocationTableCollectionHandler: hide internal AllocationTables

- Task Metamodel: Add TaskWcetTable reference to TaskArchitecture
- TaskToExecutionUnitAllocationTableCollectionCompositor: Automatically delete TaskWcetTable along with TaskToExecutionUnitAllocationTables
- Add TaskArchitectureTimingEditor, an editor for user-provided temporal properties
 - Enables to select underlying allocation that provides a TaskToExecutionUnitAllocationTable. The editor ensures that a TaskWcetTable is created. 
 - TODO:
   - Integrate Periods and allocation-independent WCETs
   - Inline editing of allocation-specific WCETs

refs 2950,2562
parent fdef2e8d
AllocationTableEditor.java fd25e3200630aaa92bc59136cc8ddc3e560685a4 YELLOW
AllocationTableEditor.java bb235a83d392d788b82bdc1552e9926d0b44f4f1 YELLOW
AllocationTableEditorUtils.java 3f53fc3ce279be40ca18d6d63f3f7f830ec4eb86 RED
ModelListenerEditorBase.java 622ed9ea90668f665f73f99fb4eec215ba10105d YELLOW
ModelListenerEditorBase.java ad5ecd0c353234b76bb81dad72fb259ff961607f YELLOW
......@@ -25,6 +25,7 @@ import static org.fortiss.tooling.common.util.LambdaUtils.asStream;
import static org.fortiss.tooling.kernel.ui.util.SelectionUtils.checkAndPickFirst;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstChildWithType;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.getParentElement;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.getRootElements;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.runAsCommand;
import java.util.Collection;
......@@ -37,7 +38,6 @@ import java.util.stream.Stream;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
......@@ -53,10 +53,8 @@ import org.fortiss.af3.allocation.IAllocationService;
import org.fortiss.af3.allocation.model.AllocationEntry;
import org.fortiss.af3.allocation.model.AllocationTable;
import org.fortiss.af3.allocation.ui.editor.treeviewer.TreeViewerManager;
import org.fortiss.tooling.base.model.element.IHierarchicElement;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.kernel.model.IProjectRootElement;
import org.fortiss.tooling.kernel.utils.KernelModelElementUtils;
/**
* Generic {@link AllocationTable} editor.
......@@ -122,6 +120,10 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
private void checkConfiguration() {
checkAllocationEntryType(allocationEntryType);
if(getEditedObject() == null) {
return;
}
final IAllocationService as = IAllocationService.getInstance();
if(getSourceModelType() == null) {
throw new RuntimeException("Source model type must be set.");
......@@ -200,30 +202,38 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
/** Performs a refresh for the given root element. */
protected void refresh(IProjectRootElement model) {
Class<? extends IProjectRootElement> sourceModelType = getSourceModelType();
Class<? extends IProjectRootElement> targetModelType = getTargetModelType();
if(sourceModelType.isAssignableFrom(model.getClass())) {
updateViewPointSelectionComboBox(gui.getComboViewerSource(),
getModels(sourceModelType), getEditedObject().getSourceView());
// Update available source entity types (that might have changed when selecting a
// different source model)
Collection<Class<? extends IModelElement>> sourceEntityTypes =
IAllocationService.getInstance().getSourceEntityTypes(allocationEntryType);
updateEntityTypeComboBox(gui.getComboViewerSourceEntityType(), sourceEntityTypes,
getEditedObject().getSourceView(), this::setSourceEntityType);
} else if(targetModelType.isAssignableFrom(model.getClass())) {
updateViewPointSelectionComboBox(gui.getComboViewerTarget(),
getModels(targetModelType), getEditedObject().getTargetView());
// Update available target entity types (that might have changed when selecting a
// different target model)
Collection<Class<? extends IModelElement>> targetEntityTypes =
IAllocationService.getInstance().getTargetEntityTypes(allocationEntryType);
updateEntityTypeComboBox(gui.getComboViewerTargetEntityType(), targetEntityTypes,
getEditedObject().getTargetView(), this::setTargetEntityType);
if(model != null) {
Class<? extends IProjectRootElement> sourceModelType = getSourceModelType();
Class<? extends IProjectRootElement> targetModelType = getTargetModelType();
if(sourceModelType.isAssignableFrom(model.getClass())) {
updateModelSelectionComboBox(gui.getComboViewerSource(),
getModels(sourceModelType), getEditedObject().getSourceView());
// Update available source entity types (that might have changed when selecting a
// different source model)
Collection<Class<? extends IModelElement>> sourceEntityTypes =
IAllocationService.getInstance().getSourceEntityTypes(allocationEntryType);
updateEntityTypeComboBox(gui.getComboViewerSourceEntityType(), sourceEntityTypes,
getEditedObject().getSourceView(), this::setSourceEntityType);
} else if(targetModelType.isAssignableFrom(model.getClass())) {
updateModelSelectionComboBox(gui.getComboViewerTarget(),
getModels(targetModelType), getEditedObject().getTargetView());
// Update available target entity types (that might have changed when selecting a
// different target model)
Collection<Class<? extends IModelElement>> targetEntityTypes =
IAllocationService.getInstance().getTargetEntityTypes(allocationEntryType);
updateEntityTypeComboBox(gui.getComboViewerTargetEntityType(), targetEntityTypes,
getEditedObject().getTargetView(), this::setTargetEntityType);
}
} else {
updateModelSelectionComboBox(gui.getComboViewerSource(), emptyList(), null);
updateEntityTypeComboBox(gui.getComboViewerSourceEntityType(), emptyList(), null,
this::setSourceEntityType);
updateModelSelectionComboBox(gui.getComboViewerTarget(), emptyList(), null);
updateEntityTypeComboBox(gui.getComboViewerTargetEntityType(), emptyList(), null,
this::setTargetEntityType);
}
treeViewerManager.updateTreeViewer();
......@@ -236,13 +246,13 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
Class<? extends IProjectRootElement> targetModelType = getTargetModelType();
if(sourceModelType.isAssignableFrom(model.getClass())) {
updateViewPointSelectionComboBox(gui.getComboViewerSource(),
getModels(sourceModelType), getEditedObject().getSourceView());
updateModelSelectionComboBox(gui.getComboViewerSource(), getModels(sourceModelType),
getEditedObject().getSourceView());
gui.getComboViewerSource().refresh();
} else if(targetModelType.isAssignableFrom(model.getClass())) {
updateViewPointSelectionComboBox(gui.getComboViewerTarget(),
getModels(targetModelType), getEditedObject().getTargetView());
updateModelSelectionComboBox(gui.getComboViewerTarget(), getModels(targetModelType),
getEditedObject().getTargetView());
gui.getComboViewerTarget().refresh();
}
}
......@@ -276,7 +286,7 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
/** {@inheritDoc} */
@Override
protected void modelSelectionChanged(IProjectRootElement model,
Consumer<IHierarchicElement> modelSetter, Supplier<IHierarchicElement> modelGetter) {
Consumer<IProjectRootElement> modelSetter, Supplier<IProjectRootElement> modelGetter) {
boolean changeSelection = true;
if(!getEditedObject().getAllocationEntries().isEmpty()) {
......@@ -347,40 +357,48 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
@Override
public void createPartControl(Composite parent) {
checkConfiguration();
super.createPartControl(parent);
gui = new AllocationTableEditorGUI(parent, SWT.NONE);
treeViewerManager = new TreeViewerManager<>(this, gui.getTreeViewer());
final IAllocationService as = IAllocationService.getInstance();
IProjectRootElement sourceView = null;
IProjectRootElement targetView = null;
List<IProjectRootElement> sourceModels = emptyList();
List<IProjectRootElement> targetModels = emptyList();
if(getEditedObject() != null) {
sourceView = getEditedObject().getSourceView();
targetView = getEditedObject().getTargetView();
sourceModels = getModels(getSourceModelType());
targetModels = getModels(getTargetModelType());
}
Collection<Class<? extends IModelElement>> sourceEntityTypes =
as.getSourceEntityTypes(allocationEntryType);
setupEntityTypeComboBox(gui.getComboViewerSourceEntityType(), this::setSourceEntityType);
updateEntityTypeComboBox(gui.getComboViewerSourceEntityType(), sourceEntityTypes,
getEditedObject().getSourceView(), this::setSourceEntityType);
sourceView, this::setSourceEntityType);
Collection<Class<? extends IModelElement>> targetEntityTypes =
as.getTargetEntityTypes(allocationEntryType);
setupEntityTypeComboBox(gui.getComboViewerTargetEntityType(), this::setTargetEntityType);
updateEntityTypeComboBox(gui.getComboViewerTargetEntityType(), targetEntityTypes,
getEditedObject().getTargetView(), this::setTargetEntityType);
targetView, this::setTargetEntityType);
setupViewPointSelectionComboBox(gui.getComboViewerSource(),
getEditedObject()::setSourceView, getEditedObject()::getSourceView);
updateViewPointSelectionComboBox(gui.getComboViewerSource(),
getModels(getSourceModelType()), getEditedObject().getSourceView());
setupModelSelectionComboBox(gui.getComboViewerSource(), getEditedObject()::setSourceView,
getEditedObject()::getSourceView);
updateModelSelectionComboBox(gui.getComboViewerSource(), sourceModels, sourceView);
setupViewPointSelectionComboBox(gui.getComboViewerTarget(),
getEditedObject()::setTargetView, getEditedObject()::getTargetView);
updateViewPointSelectionComboBox(gui.getComboViewerTarget(),
getModels(getTargetModelType()), getEditedObject().getTargetView());
setupModelSelectionComboBox(gui.getComboViewerTarget(), getEditedObject()::setTargetView,
getEditedObject()::getTargetView);
updateModelSelectionComboBox(gui.getComboViewerTarget(), targetModels, targetView);
gui.getCheckboxShowSourceModelHierarchy().addSelectionListener(
new SourceModelHierarchyCheckBoxSelectionListener());
super.createPartControl(parent);
}
/** Selection listener to update how the {@link TreeViewer} displays the model's hierarchy. */
......@@ -414,117 +432,6 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
}
}
/********************* Model selection ComboBoxes *********************/
/** {@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;
/** 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);
IProjectRootElement rootElement =
checkAndPickFirst(selection, IProjectRootElement.class);
if(rootElement != null) {
modelSelectionChanged(rootElement, modelSetter, modelGetter);
}
}
/**
* 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) {
IHierarchicElement newModel = checkAndPickFirst(selection, IHierarchicElement.class);
if(newModel != null && newModel != modelGetter.get()) {
runAsCommand(getEditedObject(), () -> {
modelSetter.accept(newModel);
});
}
}
}
/**
* Initializes a {@link ComboViewer} used to select the source or target viewpoint of the edited
* {@link AllocationTable}.
*
* @param comboViewer
* {@link ComboViewer} to be initialized.
* @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,
Consumer<IHierarchicElement> modelSetter, Supplier<IHierarchicElement> modelGetter) {
comboViewer.setContentProvider(new ArrayContentProvider());
comboViewer.setLabelProvider(new LabelProvider() {
/** {@inheritDoc} */
@Override
public String getText(Object element) {
return AllocationTableEditorUtils.getName(element);
}
});
comboViewer.addSelectionChangedListener(new ModelViewComboBoxSelectionListener(modelSetter,
modelGetter));
}
/**
* Updates {@link ComboViewer} to display the given set of {@code models} and to select the
* {@code selectedElement}.
*
* @param comboViewer
* {@link ComboViewer} to be initialized.
* @param models
* Available models to be shown in {@code comboViewer}.
* @param selectedModel
* Initially selected model.
*/
private void updateViewPointSelectionComboBox(ComboViewer comboViewer,
List<IProjectRootElement> models, IHierarchicElement selectedModel) {
comboViewer.setInput(models);
Combo combo = comboViewer.getCombo();
if(combo.getItemCount() == 0) {
combo.deselectAll();
} else if(combo.getSelectionIndex() == -1) {
// In contrast to comboViewer.setSelection(), this approach to set the selection does
// not trigger {@link SelectionChangedEvent}s that would result into an infinite
// recursion modelSelectionChanged()->refresh()->updateViewPointSelectionComboBox().
for(int i = 0; i < combo.getItems().length; i++) {
if(comboViewer.getElementAt(i) == selectedModel) {
combo.select(i);
break;
}
}
}
}
/********************* Miscellaneous options *********************/
/** Predicate if this {@link AllocationTableEditor} should visualize the model's hierarchy. */
public boolean isShowModelHierarchy() {
......@@ -566,7 +473,7 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
/** Updates the given entity type selection {@link ComboViewer}. */
private void updateEntityTypeComboBox(ComboViewer comboViewer,
Collection<Class<? extends IModelElement>> entityTypes, IHierarchicElement model,
Collection<Class<? extends IModelElement>> entityTypes, IProjectRootElement model,
Consumer<Class<? extends IModelElement>> setter) {
List<Class<? extends IModelElement>> usedEntityTypes;
......@@ -603,13 +510,12 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
*/
@SuppressWarnings("unchecked")
private List<IProjectRootElement> getModels(Class<? extends IProjectRootElement> type) {
List<? extends IProjectRootElement> models =
KernelModelElementUtils.getRootElements(getEditedObject(), type);
List<? extends IProjectRootElement> models = 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,
private List<? extends IModelElement> getModelViewElements(IProjectRootElement modelView,
Class<? extends IModelElement> entityType, ViewElementFilter elementFilter) {
if(modelView == null || entityType == null) {
......@@ -636,4 +542,9 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
return getModelViewElements(getEditedObject().getTargetView(), getTargetEntityType(),
targetViewElementFilter);
}
/** Getter for {@link #gui}. */
public AllocationTableEditorGUI getGUI() {
return gui;
}
}
......@@ -63,6 +63,7 @@ public class AllocationTableEditorGUI extends Composite {
Label labelSource = new Label(this, SWT.NONE);
GridData gd_labelSource = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1);
gd_labelSource.widthHint = 60;
gd_labelSource.verticalIndent = 2;
labelSource.setLayoutData(gd_labelSource);
labelSource.setText("Source");
......
......@@ -15,25 +15,36 @@
+--------------------------------------------------------------------------*/
package org.fortiss.af3.allocation.ui.editor;
import static java.util.Collections.emptyList;
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.ui.util.SelectionUtils.checkAndPickFirst;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.runAsCommand;
import java.util.List;
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.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.fortiss.af3.allocation.model.AllocationTable;
import org.fortiss.af3.project.model.FileProject;
import org.fortiss.tooling.base.model.element.IHierarchicElement;
import org.fortiss.af3.project.utils.ProjectUtils;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.base.ui.editor.GEFEditorBase;
import org.fortiss.tooling.kernel.model.IProjectRootElement;
......@@ -51,11 +62,15 @@ public abstract class ModelListenerEditorBase<T extends EObject> extends GEFEdit
*/
private FileProject fileProject;
/** Features in models and model entities to be observed. */
private List<EStructuralFeature> observedFeatures = emptyList();
/**
* Adapter to watch a {@link FileProject} for added / removed / renamed
* {@link IProjectRootElement}s and added / removed / renamed entities.
*/
private Adapter fileProjectListener = new EContentAdapter() {
/** {@inheritDoc} */
@Override
public void notifyChanged(Notification notification) {
......@@ -66,37 +81,55 @@ public abstract class ModelListenerEditorBase<T extends EObject> extends GEFEdit
return;
}
if(getEditedObject() == null) {
return;
}
final Display display = Display.getDefault();
if(eventType == ADD) {
Object newValue = notification.getNewValue();
if(isEditedModel(newValue)) {
IProjectRootElement model = (IProjectRootElement)newValue;
Display.getDefault().syncExec(() -> addModel(model));
display.syncExec(() -> addModel(model));
} else if(isEditedEntity(newValue)) {
IModelElement entity = (IModelElement)newValue;
Display.getDefault().syncExec(() -> addEntity(entity));
display.syncExec(() -> addEntity(entity));
}
} else if(eventType == REMOVE) {
Object oldValue = notification.getOldValue();
if(isEditedModel(oldValue)) {
IProjectRootElement model = (IProjectRootElement)oldValue;
Display.getDefault().syncExec(() -> removeModel(model));
display.syncExec(() -> removeModel(model));
} else if(isEditedEntity(oldValue)) {
IModelElement entity = (IModelElement)oldValue;
Display.getDefault().syncExec(() -> removeEntity(entity));
display.syncExec(() -> removeEntity(entity));
}
} else if(eventType == SET && notification.getFeature() == INAMED_ELEMENT__NAME) {
} else if(eventType == SET) {
Object changedValue = notification.getNotifier();
if(changedValue instanceof IProjectRootElement) {
Display.getDefault().syncExec(
() -> renameModel((IProjectRootElement)changedValue));
} else if(changedValue instanceof IModelElement) {
Display.getDefault().syncExec(() -> renameEntity((IModelElement)changedValue));
if(notification.getFeature() == INAMED_ELEMENT__NAME) {
if(changedValue instanceof IProjectRootElement) {
display.syncExec(() -> renameModel((IProjectRootElement)changedValue));
} else if(changedValue instanceof IModelElement) {
display.syncExec(() -> renameEntity((IModelElement)changedValue));
}
} else if(observedFeatures.contains(notification.getFeature())) {
if(changedValue instanceof EObject) {
display.syncExec(() -> valueSet((EObject)changedValue));
}
}
}
}
};
/** Constructor. */
public ModelListenerEditorBase() {
}
/** Constructor. */
public ModelListenerEditorBase(List<EStructuralFeature> observedFeatures) {
this.observedFeatures = observedFeatures;
}
/**
* Predicate if the given {@code object} represents an edited model (typically: the root
* element).
......@@ -135,6 +168,128 @@ public abstract class ModelListenerEditorBase<T extends EObject> extends GEFEdit
*/
protected abstract void renameEntity(IModelElement entity);
/**
* Generic hook to react on setting of values (see {@link #observedFeatures}).
*
* @param eObject
* {@link EObject} in which model has been set.
*/
protected void valueSet(EObject eObject) {
// Do nothing
}
/********************* Model selection ComboBoxes *********************/
/** {@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<IProjectRootElement> modelSetter;
/** Method used to extract the view that is currently set in the model. */
private Supplier<IProjectRootElement> modelGetter;
/** Constructor. */
public ModelViewComboBoxSelectionListener(Consumer<IProjectRootElement> modelSetter,
Supplier<IProjectRootElement> modelGetter) {
this.modelSetter = modelSetter;
this.modelGetter = modelGetter;
}
/** {@inheritDoc} */
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
setViewFromSelection(selection, modelSetter, modelGetter);
IProjectRootElement rootElement =
checkAndPickFirst(selection, IProjectRootElement.class);
if(rootElement != null) {
modelSelectionChanged(rootElement, modelSetter, modelGetter);
}
}
/**
* 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<IProjectRootElement> modelSetter,
Supplier<IProjectRootElement> modelGetter) {
IProjectRootElement newModel = checkAndPickFirst(selection, IProjectRootElement.class);
if(newModel != null && newModel != modelGetter.get()) {
runAsCommand(getEditedObject(), () -> {
modelSetter.accept(newModel);
});
}
}
}
/**
* Initializes a {@link ComboViewer} used to select the edited models.
*
* @param comboViewer
* {@link ComboViewer} to be initialized.