blob: c9e9be48137b5f8983c618597bce59c0138f7367 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.uima.taeconfigurator.editors.ui;
/*
* Created on 15.07.2003
*
* Redesign Feb 7 2005 Redesign Feb 9 2005 Changed Description to hover style Feb 27
*
* Add <Not in any group> Two case: primitive and aggregate Primitive: allow groups to be defined,
* including <Not in any group> <Common> Allow multi def of parmnames (with same decls) as long as
* they're in different groups. Same name not allowed in both <Common> and named group but are
* allowed in both <Common> and <Not in any group>
*
* A parm name declared in different groups which don't overlap can have a different declaration.
*
* Parm names are unique within a within the group-set formed by the union of all groups where the
* parm is defined. This means that a parm name P1 in group g1, g2 must match the definition of a
* parm name P1 in group g2, g3.
*
* Two parm names with the same name, in different non-intersecting groups, are distinct.
*
* Two parm names with the same name, in different delegates, even if in the same group, are
* distinct. They can have different definitions. They can be seperately overridden in each
* delegate. This allows separate development of primitives, with future combining.
*
* Two parm names with the same name in the same primitive that is used twice in the delegates list
* are distinct. They can be separately overridden, with different values. In this case, though, the
* definitions (type, multi-value, mandatory) are the same.
*
* Aggregate: groups are the union of immediate delegate groups, except <Common> Common at lower
* level defines parms that are in all named groups at that level.
*
* Treatment of <Common>: <Common> in a delegate is translated into G1, G2, ... Gn (all groups
* defined in that delegate).
*
* Common at aggregate level defines parms that are in all named groups at aggregate level. This is
* a bigger set of group names than exist at any lower delegate level. Note: Cannot add or remove
* groups at aggregate level: the groups are pre-defined based on the delegates
*
* Check of the model done at first refresh to validate it. If model has extra groups (not in
* delegates) - these are removed. If model is missing groups (in delegates) - these are added.
*
* 2 panel design for aggregate. Right panel is tree, delegate-keys, groups, parms Left panel is
* like primitive panel.
*
* Operations: Adding an override: double click on right panel element. click on delegate: add all
* parms all groups click on group: add group and all parms click on parm: add parm
*
* On left panel: add override - adds additional override. Edit - applies to override - change the
* override. Remove - applies to override, to param, to group
*
* When adding overriding parm for a delegate, use as a default the same name as the name being
* overridden. Change name if there exists parm in the groups with same name but different def
* Change name if there exists parm but group membership is not equal.
*
* User may change the name in any case. If user does this, check for name collision as above. This
* is useful, for instance, when more than one delegate defines that parameter name - to allow each
* delegate to have a different override.
*
* Adding a parm under a group: set default, allow overtyping - auto fill in type, mandatory, and
* multivalue from picked parm name setting override: based on what was clicked
*
* OK ToDo: When adding a parm, if it is an aggregate, include <overrides> OK ToDo; When adding a
* parm, have custom dialog, set multivalued, mandatory, and 1st override OK ToDo: add button add
* override (for case: aggregate) OK ToDo: make remove work for override, and edit too Later: ToDo:
* For overrides: lookup key names, lookup parm names in delegates. If delegate is another
* aggregate, do additional key All this done as optional - in case sub things not yet defined. What
* about a "browse" like file system? for descending thru aggr to parm?
*
* Todos: MaybeNot 1) make model for all parmDefs following other models MaybeNot 2) make model for
* all parmSettings following other models 2a) Have all changes (add, edit, and remove) affect
* ParameterSettingsSection 2aa) For Edit of each kind including changing name consider effect on
* settings OK 3) Checking: if change type - what to do about existing setting? Message it will be
* deleted OK 4) Checking: if change MultiV - same as above. OK 5) Checking: overrides: only show
* parm names which match on type and mv and mandatory < override OK 6) Model for editing overrides:
* using same dialog, plus combo to select which override, autoselected when dbl-clicking / edit
* existing , or adding new. Make base parm info read-only to avoid accidents NO 7) detail window:
* for groups: has list of group names; line per name, editable. for parm: has description; editable
* for overrides: has override string; line per segment, editable. OK 8) Checking: overrides: last
* level must have parm style match. 9) add value fixups and change awareness; use change awareness
* to trigger model updates OK 10) add name character-set checking OK 11) Fix shash for borders, for
* initial ratio, move to HeaderSection. Note: not appropriate for things with centered import box
* on bottom.
*
* March 24 2005 - finish impl of overrides for aggregates: Disallow editing of parameters or adding
* parameters (parameters only to be created via the double-click on the delegate parameter).
*
* Have the double-click on the deletage handle Common properly by setting up a special group with
* all the groups for that delegate.
*
* Allow adding additional overrides. Do in pickOverrides dialog.
*
*
*/
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.uima.analysis_engine.metadata.FlowControllerDeclaration;
import org.apache.uima.resource.metadata.ConfigurationGroup;
import org.apache.uima.resource.metadata.ConfigurationParameter;
import org.apache.uima.resource.metadata.ConfigurationParameterDeclarations;
import org.apache.uima.resource.metadata.ConfigurationParameterSettings;
import org.apache.uima.resource.metadata.impl.ConfigurationGroup_impl;
import org.apache.uima.resource.metadata.impl.ConfigurationParameter_impl;
import org.apache.uima.taeconfigurator.InternalErrorCDE;
import org.apache.uima.taeconfigurator.editors.MultiPageEditor;
import org.apache.uima.taeconfigurator.editors.ui.dialogs.AddParameterDialog;
import org.apache.uima.taeconfigurator.editors.ui.dialogs.CommonInputDialog;
import org.apache.uima.taeconfigurator.files.PickOverrideKeysAndParmName;
import org.apache.uima.taeconfigurator.model.ConfigGroup;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.forms.IManagedForm;
public class ParameterSection extends AbstractSectionParm {
public final static int NEW_OVERRIDE = -1;
public final static boolean REMOVE_FROM_GUI = true;
public final static boolean GIVE_WARNING_MESSAGE = true;
private Text defaultGroup;
private CCombo searchStrategy;
private Button addButton;
private Button addGroupButton;
private Button editButton;
private Button removeButton;
private Button usingGroupsButton;
private Composite groupingControl;
private boolean firstTime = true;
/**
* Creates a section to show a list of all parameters
*
* @param editor
* backpointer to the main multipage editor
* @param parent
* the Composite where this section lives
*/
public ParameterSection(MultiPageEditor editor, Composite parent) {
super(editor, parent, "Configuration Parameters",
"This section shows all configuration parameters defined for this engine.");
}
// This page shows the configuration parameters
// Organization: top section for switching between simple and groups, and
// for groups: default Group name, + search strat (combo)
// Main body: a tree, 2 hierarchies:
// 1) for groups
// 2) for aggregates: overrides
// Tree is one of 3 entries:
// parm entry: multi/single, req/opt, boolean/string/int/float, name
// group entry: <Group> , , , names
// (aggregates) <Overrides> key/key/.../key/parmname
//
// Checking: parmNames are unique for primitive and each aggr level
// overrides: lookup valid keys and parmnames
// names: well-formed with proper char sets, like java pkg names
//
// Editing: via double click, or edit button + select.
// using same dialog as for create
//
// Tree and corresponding tree (if created) in ParameterSettings are
// both incrementally updated, so rebuild is not needed. This preserves
// user-specified expansion of nodes.
public void initialize(IManagedForm form) {
super.initialize(form);
Composite sectionClient = newComposite(getSection());
usingGroupsButton = newCheckBox(sectionClient, "Use Parameter Groups",
"Check this box if Groups are being used with Parameters");
groupingControl = new2ColumnComposite(sectionClient);
((GridData) groupingControl.getLayoutData()).grabExcessVerticalSpace = false;
enableBorders(groupingControl);
toolkit.paintBordersFor(groupingControl);
defaultGroup = newLabeledTextField(groupingControl, "Default Group",
"Specify the name of the default group.");
newLabelWithData(groupingControl, "SearchStrategy");
searchStrategy = newCComboWithTip(groupingControl, "SearchStrategyToolTip");
searchStrategy.add("language_fallback");
searchStrategy.add("default_fallback");
searchStrategy.add("none");
// main table + buttons on left
Composite tableContainer = new2ColumnComposite(sectionClient);
enableBorders(tableContainer);
toolkit.paintBordersFor(tableContainer);
// SWT.SINGLE to support deselecting
// SWT.FULL_SELECTION to select whole row
parameterSectionTree = tree = newTree(tableContainer);
// Buttons
Composite buttonContainer = newButtonContainer(tableContainer);
addButton = newPushButton(buttonContainer, S_ADD, "Click here to add a new parameter");
addGroupButton = newPushButton(buttonContainer, "AddGroup",
"Click here to add a group specification. A group specification names one or more group names.");
editButton = newPushButton(buttonContainer, S_EDIT, S_EDIT_TIP);
removeButton = newPushButton(buttonContainer, S_REMOVE, S_REMOVE_TIP);
tree.addListener(SWT.MouseDoubleClick, this); // for Editing
tree.addListener(SWT.MouseHover, this); // for Description
}
/*
* refresh() called when UI is stale with respect to the model. Updates the UI to be in sync with
* the model Not called when model updated thru UI interaction. Called initially, and called when
* switching from sourcePage because user may have arbitrarilly changed things. (non-Javadoc)
*
* @see org.eclipse.ui.forms.IFormPart#refresh()
*/
public void refresh() {
super.refresh(); // clears stale and dirty bits in AbstractFormPart
// superclass
cpd = getAnalysisEngineMetaData().getConfigurationParameterDeclarations();
if ((firstTime && isParmGroup()) || isAggregate()
|| (!firstTime && usingGroupsButton.getSelection())) {
usingGroupsButton.setSelection(true);
groupingControl.setVisible(true);
defaultGroup.setText(convertNull(cpd.getDefaultGroupName()));
if (null == cpd.getSearchStrategy())
cpd.setSearchStrategy("language_fallback");
searchStrategy.setText(cpd.getSearchStrategy());
} else {
groupingControl.setVisible(false);
usingGroupsButton.setSelection(false);
}
firstTime = false;
showOverrides = true;
splitGroupNames = false;
clearAndRefillTree(usingGroupsButton.getSelection());
tree.setSelection(new TreeItem[] { tree.getItems()[0] });
enable();
// sync settings page to catch use case of switching from sourceEditor
// to this page after having shown settings page - may be out of date
ParameterSettingsSection settingsSection = editor.getSettingsPage()
.getParameterSettingsSection();
if (null != settingsSection) {
setSettings(settingsSection);
settings.refresh();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
*/
public void handleEvent(Event event) {
cpd = getAnalysisEngineMetaData().getConfigurationParameterDeclarations();
if (event.type == SWT.MouseHover) {
showDescriptionAsToolTip(event);
} else if (event.widget == usingGroupsButton) {
if (usingGroupsButton.getSelection()) {
} else {
if (Window.CANCEL == Utility
.popOkCancel(
"Confirm Remove Groups",
"This action will delete any group information that may be present in this descriptor. Proceed?",
MessageDialog.WARNING)) {
usingGroupsButton.setSelection(true);
return;
}
// remove all top level items (groups) except the 1st one,
// which is NOT_IN_ANY_GROUP
TreeItem[] items = tree.getItems();
TreeItem[] removeItems = new TreeItem[items.length - 1];
System.arraycopy(items, 1, removeItems, 0, removeItems.length);
removeItems(removeItems, !GIVE_WARNING_MESSAGE);
cpd.setCommonParameters(AbstractSection.configurationParameterArray0);
cpd.setConfigurationGroups(AbstractSection.configurationGroupArray0);
}
setFileDirty(); // maybe slightly overkill
refresh();
} else if (event.widget == searchStrategy) {
valueChanged = false;
cpd.setSearchStrategy(setValueChanged(searchStrategy.getText(), cpd.getSearchStrategy()));
if (valueChanged)
setFileDirty();
} else if (event.widget == defaultGroup) {
valueChanged = false;
cpd.setDefaultGroupName(setValueChanged(defaultGroup.getText(), cpd.getDefaultGroupName()));
if (valueChanged)
setFileDirty();
} else if (event.widget == addGroupButton) {
CommonInputDialog dialog = new CommonInputDialog(
this,
"Add Group",
"Specify one or more unique group names, separated by 1 space character, and press OK",
CommonInputDialog.GROUP_NAMES);
for (;;) { // stay in loop until get "true" return from add below
// used for looping while group name set is duplicate
if (dialog.open() == Window.CANCEL)
return;
if (addNewOrEditExistingGroup(dialog.getValue(), null))
break;
}
commonActionFinish();
} else if (event.widget == addButton) { // add parameter or add override action
boolean valid = tree.getSelectionCount() == 1;
if (isPrimitive())
valid = valid && (isGroupSelection() || isParmSelection());
else
valid = valid && (isParmSelection() || isOverrideSelection());
if (!valid) {
if (isPrimitive())
Utility.popMessage("Wrong item selected",
"Please first select the group under which to add a parameter",
MessageDialog.ERROR);
else
Utility.popMessage("Wrong item selected",
"Please first select the parameter under which to add an override",
MessageDialog.ERROR);
return;
}
if (isPrimitive()) { // adding a parameter
TreeItem parentGroup = tree.getSelection()[0];
if (isParmSelection())
parentGroup = parentGroup.getParentItem();
AddParameterDialog dialog = new AddParameterDialog(this);
if (dialog.open() == Window.CANCEL)
return;
addNewConfigurationParameter(dialog, parentGroup);
if (null != parentGroup)
parentGroup.setExpanded(true);
commonActionFinish();
} else { // is aggregate - add an override
TreeItem parentParm = tree.getSelection()[0];
if (isOverride(parentParm))
parentParm = parentParm.getParentItem();
addOrEditOverride(parentParm, -1);
}
} else if ((event.widget == editButton) || (event.type == SWT.MouseDoubleClick)) {
TreeItem editItem = tree.getSelection()[0];
if (isParameter(editItem) && isPrimitive()) {
AddParameterDialog dialog = new AddParameterDialog(this,
getCorrespondingModelParm(editItem));
if (dialog.open() == Window.CANCEL)
return;
// update the existing item
alterExistingConfigurationParameter(dialog, editItem);
// TODO consequences of changes in rest of model?
commonActionFinishDirtyIfChange();
} else if (isParameter(editItem) && isAggregate()) {
// can edit name and description, but not Type (set from override)
ConfigurationParameter existingCP = getCorrespondingModelParm(editItem);
AddParameterDialog dialog = new AddParameterDialog(this, existingCP);
if (dialog.open() == Window.CANCEL)
return;
alterExistingConfigurationParameter(dialog, editItem);
// TODO consequences of changes in rest of model?
commonActionFinishDirtyIfChange();
} else if (isOverride(editItem)) {
TreeItem parent = editItem.getParentItem();
int overrideIndex = getItemIndex(parent, editItem);
addOrEditOverride(parent, overrideIndex);
} else if (isGroup(editItem)) {
String groupNames = getName(editItem.getText());
if (groupNames.equals(COMMON_GROUP) || groupNames.equals(NOT_IN_ANY_GROUP))
return; // can't change the name of these groups
CommonInputDialog dialog = new CommonInputDialog(
this,
"Edit group",
"Specify one or more unique group names, separated by 1 space character, and press OK",
CommonInputDialog.GROUP_NAMES, groupNames);
for (;;) {
if (dialog.open() == Window.CANCEL)
return;
if (addNewOrEditExistingGroup(dialog.getValue(), editItem))
break;
}
commonActionFinishDirtyIfChange();
}
} else if ((event.widget == removeButton)
|| (event.widget == tree && event.type == SWT.KeyUp && event.character == SWT.DEL)) {
// handle remove - of all selected items
// if a group is selected, removing the group also removes all the parms in the group
// Because this is dangerous, we issue an "are you sure?" prompt.
// Other side effects: Any parameter settings for the removed
// parameters are also removed.
valueChanged = removeItems(tree.getSelection(), GIVE_WARNING_MESSAGE);
commonActionFinishDirtyIfChange();
// TODO remove settings for any parameters removed
} // end of remove action
// handle selection changes
else if (event.widget == tree && event.type == SWT.Selection) {
}
enable();
}
private void addOrEditOverride(TreeItem parent, int overrideIndex) {
ConfigurationParameter cp = getCorrespondingModelParm(parent);
Map delegateMap1 = editor.getResolvedDelegates();
Map delegateMap = null;
if (null != delegateMap1) {
delegateMap = new HashMap(delegateMap1.size());
delegateMap.putAll(delegateMap1);
FlowControllerDeclaration fcd = editor.getResolvedFlowControllerDeclaration();
if (null != fcd) {
delegateMap.put(fcd.getKey(), fcd.getSpecifier());
}
}
// only picks one override key - but code is from earlier design where multiple keys were
// possible
PickOverrideKeysAndParmName dialog = new PickOverrideKeysAndParmName(this, delegateMap,
"Override Keys and Parameter Name Selection", cp, cpd, overrideIndex == -1);
dialog.setTitle("Delegate Keys and Parameter Name Selection");
dialog
.setMessage("Select the override key path from the left panel, and the overridden parameter from the right panel.\nOnly valid parameters will be shown.");
if (dialog.open() == Window.CANCEL)
return;
String delegateKeyName = dialog.delegateKeyName;
String delegateParameterName = dialog.delegateParameterName;
// update the existing item
// have to do a 3 step update because the getOverrides returns a
// cloned array
valueChanged = false;
String overrideSpec = delegateKeyName + '/' + delegateParameterName;
// updateOneOverride(cp, overrideIndex, dialog.overrideSpec);
if (overrideIndex < 0) {
addOverride(cp, overrideSpec);
valueChanged = true;
} else {
String[] overrides = cp.getOverrides();
overrides[overrideIndex] = setValueChanged(overrideSpec, overrides[overrideIndex]);
cp.setOverrides(overrides);
parent.getItems()[overrideIndex].setText(OVERRIDE_HEADER + overrideSpec);
}
// TODO consequences of changes in rest of model?
commonActionFinishDirtyIfChange();
}
private boolean removeItems(TreeItem[] itemsToRemove, boolean giveWarningMsg) {
String[] namesToRemove = new String[itemsToRemove.length];
boolean[] isGroup = new boolean[itemsToRemove.length];
StringBuffer msgGroup = new StringBuffer();
StringBuffer msg = new StringBuffer();
StringBuffer oMsg = new StringBuffer();
for (int i = 0; i < itemsToRemove.length; i++) {
namesToRemove[i] = getName(itemsToRemove[i].getText());
isGroup[i] = isGroup(itemsToRemove[i]);
if (isGroup[i]) {
if (NOT_IN_ANY_GROUP.equals(namesToRemove[i]))
msgGroup
.append("\nThis action removes all parameter descriptions in the <Not in any group> section.");
else {
if (i > 0)
msgGroup.append(", ");
else if (COMMON_GROUP.equals(namesToRemove[i]))
msgGroup
.append("\nThis action removes all parameter descriptions in the <Common> section.");
else
msgGroup
.append("\nGroups being removed, together with their parameter definitions defined here: \n");
if (!COMMON_GROUP.equals(namesToRemove[i]))
msgGroup.append(namesToRemove[i]);
}
} else if (isParameter(itemsToRemove[i])) {
if (i > 0)
msg.append(", ");
else
msg.append("\nParameters being removed: \n");
msg.append(namesToRemove[i]);
} else if (isOverride(itemsToRemove[i])) {
if (i > 0)
oMsg.append(", ");
else
oMsg.append("\nOverride being removed: \n");
oMsg.append(namesToRemove[i]);
} else
throw new InternalErrorCDE("invalid state");
}
if (giveWarningMsg
&& Window.CANCEL == Utility.popOkCancel("Confirm Remove",
"Please confirm remove, or Cancel.\n" + msgGroup.toString() + msg.toString()
+ oMsg.toString(), MessageDialog.WARNING))
return false;
// loop thru all things being removed, and remove them
for (int i = 0; i < itemsToRemove.length; i++) {
if (isGroup[i]) {
removeGroup(itemsToRemove[i], namesToRemove[i]);
} else if (isParameter(itemsToRemove[i])) { // just a plain parameter being
// removed
removeParameter(itemsToRemove[i], namesToRemove[i]);
} else if (isOverride(itemsToRemove[i])) {
TreeItem parentItem = itemsToRemove[i].getParentItem();
ConfigurationParameter cp = getCorrespondingModelParm(parentItem);
cp.setOverrides(removeOverride(cp, getItemIndex(parentItem, itemsToRemove[i])));
itemsToRemove[i].dispose();
if (cp.getOverrides().length == 0) {
removeParameter(parentItem, getName(parentItem));
}
} else
throw new InternalErrorCDE("Invalid state");
}
return true;
}
private void removeParameter(TreeItem itemToRemove, String nameToRemove) {
TreeItem parentItem = itemToRemove.getParentItem();
ConfigurationGroup cg = null;
String parentGroupName = getName(parentItem.getText());
if (parentGroupName.equals(NOT_IN_ANY_GROUP))
cpd.setConfigurationParameters(removeConfigurationParameter(cpd.getConfigurationParameters(),
nameToRemove));
else if (parentGroupName.equals(COMMON_GROUP))
cpd.setCommonParameters(commonParms = removeConfigurationParameter(cpd.getCommonParameters(),
nameToRemove));
else {
cg = getConfigurationGroup(parentGroupName);
cg.setConfigurationParameters(removeConfigurationParameter(cg.getConfigurationParameters(),
nameToRemove));
}
removeParmSettingFromMultipleGroups(itemToRemove, REMOVE_FROM_GUI);
itemToRemove.dispose();
if (null != cg && cg.getConfigurationParameters().length == 0) {
removeGroup(parentItem, getName(parentItem));
}
}
private void removeGroup(TreeItem itemToRemove, String nameToRemove) {
if (nameToRemove.equals(COMMON_GROUP)) {
removeCommonParmSettingsFromMultipleGroups();
cpd.setCommonParameters(configurationParameterArray0);
commonParms = configurationParameterArray0;
// can't really remove the <Common> group so remove all the parms
disposeAllChildItems(itemToRemove);
} else if (nameToRemove.equals(NOT_IN_ANY_GROUP)) {
// remove settings for all non-group parm definitions
removeIncludedParmSettingsFromSingleGroup(NOT_IN_ANY_GROUP, null);
cpd.setConfigurationParameters(configurationParameterArray0);
// remove all non-group parm definitions
disposeAllChildItems(itemToRemove);
} else {
ConfigurationGroup cg = getConfigurationGroup(nameToRemove);
// remove settings for all parms in the group too
// also updates the settings GUI if the GUI is initialized
removeIncludedParmSettingsFromMultipleGroups(cg.getNames(), cg.getConfigurationParameters());
// remove group
cpd.setConfigurationGroups(removeConfigurationGroup(cpd.getConfigurationGroups(), cg));
itemToRemove.dispose(); // also disposes children of group in
// GUI
}
}
public void addParm(String name, ConfigurationParameter modelParm, ConfigGroup group,
String override) {
TreeItem parentGroup = getTreeItemGroup(group);
AddParameterDialog dialog = new AddParameterDialog(this);
dialog.parmName = name;
dialog.description = modelParm.getDescription();
dialog.mandatory = modelParm.isMandatory();
dialog.multiValue = modelParm.isMultiValued();
dialog.parmType = modelParm.getType();
// dialog.overrideSpec = override;
ConfigurationParameter parmInGroup = addNewConfigurationParameter(dialog, parentGroup);
addOverride(parmInGroup, override);
parentGroup.setExpanded(true);
commonActionFinish();
}
private ConfigurationGroup getConfigurationGroup(String groupName) {
if (groupName.equals(COMMON_GROUP))
throw new InternalErrorCDE("invalid call");
ConfigurationGroup[] groups = cpd.getConfigurationGroups();
for (int i = 0; i < groups.length; i++) {
if (groupName.equals(groupNameArrayToString(groups[i].getNames())))
return groups[i];
}
throw new InternalErrorCDE("invalid state");
}
private ConfigurationGroup[] removeConfigurationGroup(ConfigurationGroup[] groups,
ConfigurationGroup cg) {
return (ConfigurationGroup[]) Utility.removeElementFromArray(groups, cg,
ConfigurationGroup.class);
}
private ConfigurationParameter[] removeConfigurationParameter(ConfigurationParameter[] parms,
String nameToRemove) {
ConfigurationParameter[] newParms = new ConfigurationParameter[parms.length - 1];
for (int i = 0, j = 0; i < newParms.length; i++, j++) {
if (parms[j].getName().equals(nameToRemove))
j++;
newParms[i] = parms[j];
}
return newParms;
}
private String[] removeOverride(ConfigurationParameter cp, int i) {
String[] oldOverrides = cp.getOverrides();
String[] newOverrides = new String[oldOverrides.length - 1];
if (i > 0)
System.arraycopy(oldOverrides, 0, newOverrides, 0, i);
if (oldOverrides.length - 1 - i > 0)
System.arraycopy(oldOverrides, i + 1, newOverrides, i, oldOverrides.length - 1 - i);
return newOverrides;
}
/**
* Called to add group to aggregate parm decl based on delegate group
*
* @param group
* the delegate group needing to be added to the aggregate
*/
public ConfigGroup addGroup(ConfigGroup group) {
String groupName = group.getName();
String[] groupNameArray = group.getNameArray();
if (group.getKind() == ConfigGroup.COMMON) {
groupNameArray = getAllGroupNames(group.getCPD());
groupName = groupNameArrayToString(groupNameArray);
}
ConfigurationGroup cg = new ConfigurationGroup_impl();
cg.setConfigurationParameters(configurationParameterArray0);
TreeItem item = addGroupToGUI(groupName, cg);
// fill(commonParms, item); // don't add common parsm, they're added by definition
addGroupToModel(cg);
cg.setNames(groupNameArray);
tree.setSelection(new TreeItem[] { item });
return new ConfigGroup(cpd, cg);
}
// existing, if not null, doesn't point to <Common> which can't be edited
/**
* @param names -
* a sequence of group names separated by blanks
* @param existing -
* null or an existing tree item being edited
*/
private boolean addNewOrEditExistingGroup(String names, TreeItem existing) {
valueChanged = true; // preset
ConfigGroup mcg = null;
String[] oldGroupNames = stringArray0;
String[] newGroupNames = groupNamesToArray(names);
String[] groupNamesToAdd;
String[] groupNamesToDrop = stringArray0;
if (null != existing) {
mcg = getCorrespondingModelGroup(existing);
oldGroupNames = mcg.getNameArray();
groupNamesToDrop = setDiff(oldGroupNames, newGroupNames);
groupNamesToAdd = setDiff(newGroupNames, oldGroupNames);
} else {
groupNamesToAdd = newGroupNames;
}
// it is legal to define a group name more than once, but the same set of group names
// shouldn't be defined more than once
if (groupNameAlreadyDefined(newGroupNames)) {
Utility.popMessage("Group Already Defined",
"This set of group names has already been defined." + "\n\nGroup: " + names,
MessageDialog.ERROR);
return false;
}
TreeItem item;
if (existing == null) {
ConfigurationGroup cg = new ConfigurationGroup_impl();
cg.setConfigurationParameters(configurationParameterArray0);
cg.setNames(groupNamesToArray(names));
item = addGroupToGUI(names, cg);
addGroupToModel(cg);
} else { // editing existing group
valueChanged = groupNamesToDrop.length != 0 || groupNamesToAdd.length != 0;
item = existing;
setGroupText(item, names);
for (int i = 0; i < groupNamesToDrop.length; i++) {
removeIncludedParmSettingsFromSingleGroup(groupNamesToDrop[i], mcg.getConfigParms());
}
mcg.setNameArray(groupNamesToArray(names));
if (null != settings) {
for (int i = 0; i < groupNamesToAdd.length; i++) {
TreeItem settingsItem = getSettingsTreeGroup(groupNamesToAdd[i]);
if (null == settingsItem) {
settingsItem = new TreeItem(settingsTree, SWT.NONE);
setGroupText(settingsItem, groupNamesToAdd[i]);
settingsItem.setData(null);
fill(mcg.getConfigParms(), settingsItem);
fill(commonParms, settingsItem);
} else {
fillInFrontOfCommon(mcg.getConfigParms(), settingsItem);
}
}
}
}
tree.setSelection(new TreeItem[] { item });
return true;
}
private void fillInFrontOfCommon(ConfigurationParameter[] parms, TreeItem settingsTreeGroup) {
if (parms != null) {
for (int i = parms.length - 1; i >= 0; i--) {
fillParmItem(new TreeItem(settingsTreeGroup, SWT.NONE, 0), parms[i]);
}
}
}
/**
* Calculate s1 - s2 set
*
* @param s1
* @param s2
* @return
*/
private String[] setDiff(String[] s1, String[] s2) {
Set result = new TreeSet();
for (int i = 0; i < s1.length; i++)
result.add(s1[i]);
for (int i = 0; i < s2.length; i++)
result.remove(s2[i]);
return (String[]) result.toArray(stringArray0);
}
private boolean setEqual(String[] s1, String[] s2) {
if (null == s1 && null == s2)
return true;
if (null == s1 || null == s2)
return false;
if (s1.length != s2.length)
return false;
if (setDiff(s1, s2).length == 0)
return true;
return false;
}
/**
* Called from ParameterDelegatesSection to add an override
*
* @param parmInGroup
* @param override
*/
public void addOverride(ConfigurationParameter parmInGroup, String override) {
addOverride(override, getTreeItemParm(parmInGroup), parmInGroup);
}
/**
* add an override item
*
* @param parent
* @param override
*/
private void addOverrideToGUI(TreeItem parent, String override) {
// addOverride(dialog.overrideSpec, parent, cp);
TreeItem item = new TreeItem(parent, SWT.NONE);
item.setText(OVERRIDE_HEADER + override);
}
/**
* Called by addNewConfigurationParameter, and fill (via refresh) to add overrides to the tree
* list
*
* @param parent
* @param modelCP
*/
protected void fillOverrides(TreeItem parent, ConfigurationParameter modelCP) {
if (isAggregate()) {
String[] overrides = modelCP.getOverrides();
if (overrides != null) {
for (int i = 0; i < overrides.length; i++) {
addOverrideToGUI(parent, overrides[i]);
}
parent.setExpanded(true); // show added overrides
}
}
}
/**
* called from add Override action
*
* @param dialog
* @param parent
* @param cp
*/
private void addOverride(String override, TreeItem parent, ConfigurationParameter cp) {
cp.setOverrides(addOverrideToArray(cp.getOverrides(), override));
addOverrideToGUI(parent, override);
parent.setExpanded(true);
commonActionFinish();
}
private void alterExistingConfigurationParameter(AddParameterDialog dialog,
TreeItem existingTreeItem) {
ConfigurationParameter existingCP = getCorrespondingModelParm(existingTreeItem);
ConfigurationParameter previousCP = existingCP;
previousCP = (ConfigurationParameter) previousCP.clone();
fillModelParm(dialog, existingCP);
fillParmItem(existingTreeItem, existingCP);
// the following may have changed in an existing param spec, that could
// affect the setting:
// 1) the name, 2) the type, 3) the multi-value aspect
// Description or mandatory changes have no effect on the settings
// If the multi-value aspect changes, drop all the settings
// If the type changes, drop all the settings
// If the name changes, change existing settings for that parm name in all groups
if ((!previousCP.getType().equals(existingCP.getType()))
|| (previousCP.isMultiValued() != existingCP.isMultiValued())) {
removeParmSettingFromMultipleGroups(existingTreeItem, !REMOVE_FROM_GUI);
}
commonParmUpdate(existingTreeItem, existingCP, previousCP.getName());
}
private void commonParmUpdate(TreeItem existingTreeItem, ConfigurationParameter existingCP,
String prevName) {
updateParmInSettingsGUI(existingCP, existingTreeItem, prevName);
String newName = existingCP.getName();
if (!newName.equals(prevName)) {
// name changed; update the settings model
ConfigurationParameterSettings cps = getModelSettings();
String[] allGroupNames = new String[] { null };
if (usingGroupsButton.getSelection()) {
allGroupNames = (String[]) Utility
.addElementToArray(getAllGroupNames(), null, String.class);
}
Object value;
for (int i = 0; i < allGroupNames.length; i++) {
if (null != (value = cps.getParameterValue(allGroupNames[i], prevName))) {
cps.setParameterValue(allGroupNames[i], newName, value);
cps.setParameterValue(allGroupNames[i], prevName, null);
}
}
}
}
/**
* Fills in the model Configuration Parm from the Add/Edit dialog. called from
* addNewConfigurationParameter, and alterExistingConfigurationParameter
*
* @param dialog
* @param existingCP
*/
private void fillModelParm(AddParameterDialog dialog, ConfigurationParameter existingCP) {
valueChanged = false;
existingCP.setName(setValueChanged(dialog.parmName, existingCP.getName()));
existingCP.setDescription(setValueChanged(multiLineFix(dialog.description), existingCP
.getDescription()));
existingCP.setMandatory(setValueChangedBoolean(dialog.mandatory, existingCP.isMandatory()));
existingCP
.setMultiValued(setValueChangedBoolean(dialog.multiValue, existingCP.isMultiValued()));
existingCP.setType(setValueChanged(dialog.parmType, existingCP.getType()));
if (valueChanged)
setFileDirty();
}
/**
* Called from UI when adding a new Configuraton Parameter Called from refresh when filling params
* Called when adding override to new parm
*
* @param dialog
* @param group
* @return
*/
private ConfigurationParameter addNewConfigurationParameter(AddParameterDialog dialog,
TreeItem group) {
ConfigurationParameter newCP = new ConfigurationParameter_impl();
fillModelParm(dialog, newCP);
if (null != group) {
String groupName = getName(group.getText());
if (groupName.equals(COMMON_GROUP)) {
cpd.setCommonParameters(commonParms = addParmToArray(cpd.getCommonParameters(), newCP));
} else if (groupName.equals(NOT_IN_ANY_GROUP)) {
cpd.setConfigurationParameters(addParmToArray(cpd.getConfigurationParameters(), newCP));
} else {
ConfigurationGroup cg = getConfigurationGroup(groupName);
cg.setConfigurationParameters(addParmToArray(cg.getConfigurationParameters(), newCP));
}
} else { // no groups
throw new InternalErrorCDE("invalid state");
}
addNewConfigurationParameterToGUI(newCP, group);
return newCP;
}
private void addGroupToModel(ConfigurationGroup newCg) {
ConfigurationGroup[] oldCgs = cpd.getConfigurationGroups();
ConfigurationGroup[] newCgs;
if (null == oldCgs) {
newCgs = new ConfigurationGroup[1];
} else {
newCgs = new ConfigurationGroup[oldCgs.length + 1];
System.arraycopy(oldCgs, 0, newCgs, 0, oldCgs.length);
}
newCgs[newCgs.length - 1] = newCg;
cpd.setConfigurationGroups(newCgs);
}
private String[] addOverrideToArray(String[] overrides, String newOverride) {
if (null == overrides)
return new String[] { newOverride };
String[] newOverrides = new String[overrides.length + 1];
System.arraycopy(overrides, 0, newOverrides, 0, overrides.length);
newOverrides[overrides.length] = newOverride;
return newOverrides;
}
private ConfigurationParameter[] addParmToArray(ConfigurationParameter[] cps,
ConfigurationParameter newCP) {
if (null == cps) {
return new ConfigurationParameter[] { newCP };
}
ConfigurationParameter[] newCps = new ConfigurationParameter[cps.length + 1];
System.arraycopy(cps, 0, newCps, 0, cps.length);
newCps[cps.length] = newCP;
return newCps;
}
/**
*
* @param names
* @return true if there is a group whose names are the same set
*/
private boolean groupNameAlreadyDefined(String[] names) {
ConfigurationGroup[] cgs = cpd.getConfigurationGroups();
if (null != cgs) {
for (int i = 0; i < cgs.length; i++) {
if (setEqual(names, cgs[i].getNames()))
return true;
}
}
return false;
}
public static boolean parameterNameAlreadyDefinedNoMsg(String name,
ConfigurationParameterDeclarations pCpd) {
if (pCpd.getCommonParameters() != null) {
if (parameterInArray(name, pCpd.getCommonParameters()))
return true;
}
if (pCpd.getConfigurationParameters() != null) {
if (parameterInArray(name, pCpd.getConfigurationParameters()))
return true;
}
ConfigurationGroup[] groups;
if ((groups = pCpd.getConfigurationGroups()) != null) {
for (int i = 0; i < groups.length; i++) {
if (parameterInArray(name, groups[i].getConfigurationParameters()))
return true;
}
}
return false;
}
public boolean parameterNameAlreadyDefined(String name) {
boolean alreadyDefined = parameterNameAlreadyDefinedNoMsg(name, cpd);
if (alreadyDefined) {
Utility.popMessage("Parameter Already Defined",
"The following parameter is already defined in the list. Parameter names must be unique."
+ "\n\nParameter: " + name, MessageDialog.ERROR);
}
return alreadyDefined;
}
private static boolean parameterInArray(String name, ConfigurationParameter[] cps) {
for (int i = 0; i < cps.length; i++) {
if (name.equals(cps[i].getName()))
return true;
}
return false;
}
private void commonActionFinish() {
valueChanged = true;
commonActionFinishDirtyIfChange();
}
/**
* called by Edit operations which might not make any changes They set the dirty state if any
* changes occur, so don't set it here.
*
*/
private void commonActionFinishDirtyIfChange() {
if (valueChanged)
setFileDirty();
enable();
}
public void enable() {
usingGroupsButton.setEnabled(!isAggregate());
boolean usingGroups = usingGroupsButton.getSelection();
groupingControl.setVisible(usingGroups);
addButton.setEnabled(isPrimitive() || tree.getSelectionCount() == 1
&& (isParmSelection() || isOverrideSelection()));
addGroupButton.setEnabled(isPrimitive() && usingGroups);
removeButton.setEnabled(tree.getSelectionCount() == 1
&& (isParmSelection() || isGroupSelection() || isOverrideSelection()));
editButton
.setEnabled(tree.getSelectionCount() == 1
&& ((/* isPrimitive() && */isParmSelection()) || isOverrideSelection() || (isPrimitive()
&& isGroupSelection() && !isCommonGroupSelection())));
}
public Tree getTree() {
return tree;
}
/**
* Given a ConfigurationParameter, find the corresponding item in the tree. Note: parameters with
* the same name can exist in different groups, so we don't match using the parm name, but rather
* do an "EQ" test
*
* @param p
* @return
*/
private TreeItem getTreeItemParm(ConfigurationParameter p) {
TreeItem[] groups = tree.getItems();
for (int i = 0; i < groups.length; i++) {
TreeItem[] parms = groups[i].getItems();
for (int j = 0; j < parms.length; j++) {
if (getCorrespondingModelParm(parms[j]) == p)
return parms[j];
}
}
throw new InternalErrorCDE("invalid state");
}
/**
* Given a ConfigGroup - find the corresponding tree item. Match is done against the display form
* of the name(s), with special casing for the not-in-any-group and common.
*
* @param g
* @return
*/
private TreeItem getTreeItemGroup(ConfigGroup g) {
switch (g.getKind()) {
case ConfigGroup.NOT_IN_ANY_GROUP:
return tree.getItems()[0];
case ConfigGroup.COMMON:
return tree.getItems()[1];
}
TreeItem[] items = tree.getItems();
for (int i = 2; i < items.length; i++) {
if (getName(items[i].getText()).equals(g.getName()))
return items[i];
}
throw new InternalErrorCDE("invalid state");
}
private TreeItem getSettingsTreeGroup(String groupName) {
TreeItem[] items = settingsTree.getItems();
for (int i = 0; i < items.length; i++) {
if (groupName.equals(getName(items[i].getText())))
return items[i];
}
return null;
}
}