1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 365718: Support tree option style in managed build options

Managed build options in tools provide several styles
for option type, for example: string, boolean, libPaths, enumerated, ...
The enumerated type allows the user to select from a pre-defined list of
values.

A usability problem might happen if the list of possible values is Huge,
in this case the simple drop-box wouldn't be sufficient for the user to
properly and easily select the needed option. In most of those cases the
huge list of options can be organized in some hierarchy that allows the
user to easily pick the needed option.

The attached patch attempts to support this by doing the following:

1- Adding support of a new option valueType "tree"
    - Adding schema for treeOption
    - Adding support for tree type similar to enumerated option type
2- Provide UI to easily select items from this tree
    - Provide a field editor with a text box and browse button
    - Provide popup tree picker with filtered search
    - Each item in the tree can optionally provide an icon, and specify
its relative order among its peers.

Updates:
- Expose TreeSelectionDialog and TreeRoot to allow usage in other
contexts
- Remove extra whitespaces.
- Support Double-click to select
- Added unit test

Change-Id: I3e7e8c6e3e9878f7c6dadeb149326b375cd3631d
Reviewed-on: https://git.eclipse.org/r/5558
Reviewed-by: Doug Schaefer <dschaefer@qnx.com>
IP-Clean: Doug Schaefer <dschaefer@qnx.com>
Tested-by: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
mhussein 2012-05-03 18:12:57 +03:00 committed by Doug Schaefer
parent 621ee0fe22
commit a2cfb6e5cd
23 changed files with 1230 additions and 60 deletions

View file

@ -9311,4 +9311,66 @@
name="Test Plugin GCC BOP Patterns Highlighter">
</errorparser>
</extension>
<!-- Tree Option -->
<extension
id="cdt.managed.build.test.tree.option"
name="Test Managed Build TreeOption"
point="org.eclipse.cdt.managedbuilder.core.buildDefinitions">
<managedBuildRevision fileVersion="4.0.0"/>
<tool
natureFilter="cnature"
name="Test Tool"
outputFlag="-o"
command="gcc"
id="cdt.managedbuild.tool.gnu.c.linker.test.tree.tool"
errorParsers="org.eclipse.cdt.core.GLDErrorParser">
<option
defaultValue="grandChild_1_1_1"
name="Dummy Tree Option"
command="-dummy"
id="cdt.managedbuild.tool.gnu.c.linker.test.tree.option"
valueType="tree">
<treeOptionRoot name="root" id="option.tree.root">
<treeOption name="Parent 1" id="parent_1">
<treeOption name="Child 1 1" id="child_1_1">
<treeOption name="Grand Child 1 1 1" id="grandChild_1_1_1" />
<treeOption name="Grand Child 1 1 2" id="grandChild_1_1_2" />
<treeOption name="Grand Child 1 1 3" id="grandChild_1_1_3" />
</treeOption>
<treeOption name="Child 1 2" id="child_1_2">
<treeOption name="Grand Child 1 2 1" id="grandChild_1_2_1" />
<treeOption name="Grand Child 1 2 2" id="grandChild_1_2_2" command="-dummy122" />
<treeOption name="Grand Child 1 2 3" id="grandChild_1_2_3" />
</treeOption>
</treeOption>
<treeOption name="Parent 2" id="parent_2">
<treeOption name="Child 2 1" id="child_2_1">
<treeOption name="Grand Child 2 1 1" id="grandChild_2_1_1" />
<treeOption name="Grand Child 2 1 2" id="grandChild_2_1_2" />
<treeOption name="Grand Child 2 1 3" id="grandChild_2_1_3" />
</treeOption>
<treeOption name="Child 2 2" id="child_2_2">
<treeOption name="Grand Child 2 2 1" id="grandChild_2_2_1" />
<treeOption name="Grand Child 2 2 2" id="grandChild_2_2_2" />
<treeOption name="Grand Child 2 2 3" id="grandChild_2_2_3" />
</treeOption>
</treeOption>
<treeOption name="Parent 3" id="parent_3" order="0">
<treeOption name="Child 3 1" id="child_3_1">
<treeOption name="Grand Child 3 1 1" id="grandChild_3_1_1" />
<treeOption name="Grand Child 3 1 2" id="grandChild_3_1_2" />
<treeOption name="Grand Child 3 1 3" id="grandChild_3_1_3" />
</treeOption>
<treeOption name="Child 3 2" id="child_3_2">
<treeOption name="Grand Child 3 2 1" id="grandChild_3_2_1" />
<treeOption name="Grand Child 3 2 2" id="grandChild_3_2_2" />
<treeOption name="Grand Child 3 2 3" id="grandChild_3_2_3" />
</treeOption>
</treeOption>
</treeOptionRoot>
</option>
</tool>
</extension>
</plugin>

View file

@ -22,6 +22,9 @@ import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.IBuilder;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IOption;
import org.eclipse.cdt.managedbuilder.core.IOption.ITreeOption;
import org.eclipse.cdt.managedbuilder.core.IOption.ITreeRoot;
import org.eclipse.cdt.managedbuilder.core.IOptionApplicability;
import org.eclipse.cdt.managedbuilder.core.IOptionCategory;
import org.eclipse.cdt.managedbuilder.core.IProjectType;
import org.eclipse.cdt.managedbuilder.core.ITargetPlatform;
@ -30,6 +33,7 @@ import org.eclipse.cdt.managedbuilder.core.IToolChain;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.internal.core.Builder;
import org.eclipse.core.runtime.IConfigurationElement;
import org.junit.Assert;
public class ManagedBuildCoreTests extends TestCase {
@ -44,6 +48,7 @@ public class ManagedBuildCoreTests extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite(ManagedBuildCoreTests.class.getName());
suite.addTest(new ManagedBuildCoreTests("testLoadManifest"));
suite.addTest(new ManagedBuildCoreTests("testTreeOptions"));
return suite;
}
@ -598,5 +603,64 @@ public class ManagedBuildCoreTests extends TestCase {
} // end for
} // end routine
/**
* Tests Options of type tree as implemented in bug 365718
* @throws Exception
*/
public void testTreeOptions() throws Exception {
IOption treeOption = ManagedBuildManager.getExtensionOption("cdt.managedbuild.tool.gnu.c.linker.test.tree.option");
assertNotNull(treeOption);
// standard options
assertEquals(IOption.TREE, treeOption.getValueType());
assertEquals("grandChild_1_1_1", treeOption.getValue());
assertEquals("grandChild_1_1_1", treeOption.getDefaultValue());
assertEquals("cdt.managedbuild.tool.gnu.c.linker.test.tree.option", treeOption.getId());
assertEquals("-dummy", treeOption.getCommand());
assertEquals("-dummy122", treeOption.getCommand("grandChild_1_2_2"));
String[] applicableValues = treeOption.getApplicableValues();
String[] expected = new String[18];
int index = 0;
for (int i = 1; i < 4; i++) {
for (int j = 1; j < 3; j++) {
for (int k = 1; k < 4; k++) {
expected[index++] = "Grand Child " + i + ' ' + j + ' ' + k;
}
}
}
Assert.assertArrayEquals(expected, applicableValues);
ITreeRoot treeRoot = treeOption.getTreeRoot();
assertNotNull(treeRoot);
// test some tree option attributes
ITreeOption[] children = treeRoot.getChildren();
assertNotNull(children);
assertEquals(0, children[2].getOrder());
assertEquals("Parent 2", children[1].getName());
assertTrue(children[0].isContainer());
ITreeOption findNode = treeRoot.findNode("grandChild_2_1_3");
assertNotNull(findNode);
int size = children.length;
treeRoot.addChild("newID", "New Name");
assertEquals(size+1, treeRoot.getChildren().length);
assertEquals("newID", treeRoot.getChild("New Name").getID());
// check tree only methods
IOption nonTreeOption = ManagedBuildManager.getExtensionOption("testgnu.c.compiler.exe.debug.option.debugging.level");
assertFalse(IOption.TREE == nonTreeOption.getValueType());
boolean exception = false;
try {
nonTreeOption.getTreeRoot();
} catch (Exception e) {
exception = true;
}
assertTrue(exception);
}
} // end class

View file

@ -1178,6 +1178,7 @@ Options can also be associated with a toolchain. However in such a case the opti
<choice>
<element ref="listOptionValue" minOccurs="0" maxOccurs="unbounded"/>
<element ref="enumeratedOptionValue" minOccurs="0" maxOccurs="unbounded"/>
<element ref="treeOptionRoot" minOccurs="0" maxOccurs="1"/>
</choice>
<element ref="enablement" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
@ -1289,6 +1290,8 @@ Additional special types exist to flag options of special relevance to the build
</enumeration>
<enumeration value="undefSymbolFiles">
</enumeration>
<enumeration value="tree">
</enumeration>
</restriction>
</simpleType>
</attribute>
@ -1512,6 +1515,118 @@ A custom field-editor needs to be registered, under the same ID, through the &lt
</complexType>
</element>
<element name="treeOption">
<complexType>
<sequence minOccurs="0" maxOccurs="unbounded">
<element ref="treeOption"/>
</sequence>
<attribute name="id" type="string" use="required">
<annotation>
<documentation>
The id should be the value used for determining which treeOption is selected, it has to be unique within the tree.
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string" use="required">
<annotation>
<documentation>
Display name for the option
</documentation>
<appInfo>
<meta.attribute translatable="true"/>
</appInfo>
</annotation>
</attribute>
<attribute name="description" type="string">
<annotation>
<documentation>
Description of the option to be presented to the user
</documentation>
<appInfo>
<meta.attribute translatable="true"/>
</appInfo>
</annotation>
</attribute>
<attribute name="command" type="string">
<annotation>
<documentation>
The command that the tree value translates to on the command line.
</documentation>
</annotation>
</attribute>
<attribute name="isDefault" type="boolean">
<annotation>
<documentation>
Flags this tree value as the default to apply to the option if the user has not changed the setting.
</documentation>
</annotation>
</attribute>
<attribute name="icon" type="string">
<annotation>
<documentation>
An icon to be used for this node in the tree representation. Should use full path for the icon: e.g., platform:/plugin/org.eclipse.cdt/icons/wizard.png
</documentation>
<appInfo>
<meta.attribute kind="resource"/>
</appInfo>
</annotation>
</attribute>
<attribute name="order" type="string">
<annotation>
<documentation>
An integer representing the order of this option within its peers in the tree. The order is a relative number, were smaller numbers appear on top of larger numbers.
If no order is defined a default order is assumed, see &quot;org.eclipse.cdt.managedbuilder.core.IOption.ITreeOption.DEFAULT_ORDER&quot; for more details.
</documentation>
</annotation>
</attribute>
</complexType>
</element>
<element name="treeOptionRoot">
<annotation>
<documentation>
Represents the root of a tree of options. Note that the root is never shown to the user and can&apos;t be selected. It is a place holder for settings affecting the options tree behavior
</documentation>
</annotation>
<complexType>
<sequence minOccurs="1" maxOccurs="unbounded">
<element ref="treeOption"/>
</sequence>
<attribute name="id" type="string" use="required">
<annotation>
<documentation>
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string" use="required">
<annotation>
<documentation>
</documentation>
</annotation>
</attribute>
<attribute name="icon" type="string">
<annotation>
<documentation>
The tree root icon can be used in branding the UI representation of the tree. Should use full path for the icon: e.g., platform:/plugin/org.eclipse.cdt/icons/wizard.png
</documentation>
<appInfo>
<meta.attribute kind="resource"/>
</appInfo>
</annotation>
</attribute>
<attribute name="selectLeafOnly" type="boolean">
<annotation>
<documentation>
Determines whether this tree allows selecting categories as well as leaf nodes, or leaf nodes only.
Default is true (leaf nodes only).
</documentation>
</annotation>
</attribute>
</complexType>
</element>
<element name="builder">
<annotation>
<documentation>

View file

@ -55,6 +55,12 @@ public interface IOption extends IBuildObject {
public static final int LIBRARY_FILES = 10;
public static final int MACRO_FILES = 11;
/**
* Tree of items to select one from.
* @since 8.1
*/
public static final int TREE = 12;
public static final int UNDEF_INCLUDE_PATH = -INCLUDE_PATH;
public static final int UNDEF_PREPROCESSOR_SYMBOLS = -PREPROCESSOR_SYMBOLS;
public static final int UNDEF_INCLUDE_FILES = -INCLUDE_FILES;
@ -84,6 +90,14 @@ public interface IOption extends IBuildObject {
/** @since 7.0 */
public static final String BROWSE_FILTER_EXTENSIONS = "browseFilterExtensions"; //$NON-NLS-1$
public static final String CATEGORY = "category"; //$NON-NLS-1$
/**
* @since 8.1
*/
public static final String ICON = "icon"; //$NON-NLS-1$
/**
* @since 8.1
*/
public static final String ORDER = "order"; //$NON-NLS-1$
public static final String COMMAND = "command"; //$NON-NLS-1$
public static final String COMMAND_FALSE = "commandFalse"; //$NON-NLS-1$
/** @since 8.0 */
@ -92,6 +106,22 @@ public interface IOption extends IBuildObject {
public static final String CONTEXT_ID = "contextId"; //$NON-NLS-1$
public static final String DEFAULT_VALUE = "defaultValue"; //$NON-NLS-1$
public static final String ENUM_VALUE = "enumeratedOptionValue"; //$NON-NLS-1$
/**
* @since 8.1
*/
public static final String TREE_ROOT = "treeOptionRoot"; //$NON-NLS-1$
/**
* @since 8.1
*/
public static final String SELECT_LEAF_ONLY = "selectLeafOnly"; //$NON-NLS-1$
/**
* @since 8.1
*/
public static final String TREE_VALUE = "treeOption"; //$NON-NLS-1$
/**
* @since 8.1
*/
public static final String DESCRIPTION = "description"; //$NON-NLS-1$
public static final String IS_DEFAULT = "isDefault"; //$NON-NLS-1$
public static final String LIST_VALUE = "listOptionValue"; //$NON-NLS-1$
public static final String RESOURCE_FILTER = "resourceFilter"; //$NON-NLS-1$
@ -114,6 +144,10 @@ public interface IOption extends IBuildObject {
public static final String TYPE_UNDEF_LIB_FILES = "undefLibFiles"; //$NON-NLS-1$
public static final String TYPE_UNDEF_INC_FILES = "undefIncludeFiles"; //$NON-NLS-1$
public static final String TYPE_UNDEF_SYMBOL_FILES = "undefSymbolFiles"; //$NON-NLS-1$
/**
* @since 8.1
*/
public static final String TYPE_TREE = "tree"; //$NON-NLS-1$
public static final String VALUE = "value"; //$NON-NLS-1$
public static final String VALUE_TYPE = "valueType"; //$NON-NLS-1$
@ -325,18 +359,59 @@ public interface IOption extends IBuildObject {
*/
public String getEnumCommand (String id) throws BuildException;
/**
* Returns the command associated with the child of this option
* with the given id. Applies to options of types that has children
* for example {@link #TREE} or {@link #ENUMERATED}
*
* @param id - child id
* @return the command associated with the child id. For
* example, if the child id was <code>gnu.debug.level.default</code>
* for the debug level option of the Gnu compiler, and the plugin
* manifest defined that as -g, then the return value would be the
* String "-g"
*
* @throws BuildException
* @since 8.1
*/
public String getCommand (String id) throws BuildException;
/**
* @param id - enumeration id
* @return the "name" associated with the enumeration id.
*/
public String getEnumName (String id) throws BuildException;
/**
* Returns the name associated with the child of this option
* with the given id. Applies to options of types that has children
* for example {@link #TREE} or {@link #ENUMERATED}
*
* @param id The id to look for
* @return Name of the child with the passed id or <code>null</code> if not found.
* @throws BuildException if any issue happened while searching.
* @since 8.1
*/
public abstract String getName(String id) throws BuildException;
/**
* @param name - a "name" associated with enumeration id
* @return enumeration id
*/
public String getEnumeratedId(String name) throws BuildException;
/**
* Returns the id associated with the child of this option
* with the given name. Applies to options of types that has children
* for example {@link #TREE} or {@link #ENUMERATED}
*
* @param name the name of the child to look for.
* @return The id of the found child or <code>null</code> if not found.
* @throws BuildException if any error happened while searching
* @since 8.1
*/
public abstract String getId(String name) throws BuildException;
/**
* @return an array of <code>String</code> containing the includes paths
* defined in the build model.
@ -514,6 +589,7 @@ public interface IOption extends IBuildObject {
* <li/>{@link IOption#BOOLEAN}
* <li/>{@link IOption#STRING}
* <li/>{@link IOption#ENUMERATED}
* <li/>{@link IOption#TREE}
* <li/>{@link IOption#STRING_LIST} - corresponds to
* {@link IOption#INCLUDE_PATH}, {@link IOption#PREPROCESSOR_SYMBOLS}, {@link IOption#LIBRARIES},
* {@link IOption#OBJECTS}, {@link IOption#INCLUDE_FILES}, {@link IOption#LIBRARY_PATHS},
@ -528,4 +604,101 @@ public interface IOption extends IBuildObject {
String[] getBasicStringListValue() throws BuildException;
public OptionStringValue[] getBasicStringListValueElements() throws BuildException;
/**
* Returns the tree root of this option if it is of type {@link #TREE}
* @return tree root of this option or <code>null</code> if not found.
* @throws BuildException if this option is not of type {@link #TREE}
* @since 8.1
*/
public ITreeRoot getTreeRoot() throws BuildException;
/**
* Represents the root of the tree of values in options of
* type {@link IOption#TREE}
* @author mhussein
* @since 8.1
*
*/
public interface ITreeRoot extends ITreeOption {
/**
* Determines whether this tree allows selecting leaf nodes
* only or any nodes.
* @return <code>true</code> if only leaf nodes are allowed.
* <code>false</code> if all child nodes could be selected.
* @see ITreeOption#isContainer()
*/
boolean isSelectLeafsOnly();
/**
* Locates the node with the given id anywhere in the tree.
* @param id the id to search for
* @return the found child or <code>null</code> if not found.
*/
ITreeOption findNode(String id);
/**
* Adds a new node to the tree.
* @param id The id of the new child.
* @param name The name of the new child.
* @param category The category of the new child.category is a '.'
* separated string representing hierarchical path
* of the child from the root of the tree.
* can cause other nodes to be created to construct the
* full path to the new child.
* @param order The order of the newly created node among its peers.
* see {@link ITreeOption#getOrder()} for more information.
* Note: this order will apply to any parents auto-created
* according to the passed category.
* if <code>null</code> the {@link ITreeOption#DEFAULT_ORDER}
* will be used.
* @return the newly added node.
*/
ITreeOption addNode(String id, String name, String category, Integer order);
}
/**
* Represents a one of the possible values for options of type
* {@link IOption#TREE}
* @author mhussein
* @since 8.1
*
*/
public interface ITreeOption {
/**
* The default order for tree nodes without order specified.
* Tree options with Orders smaller than this should appear above
* tree options with no order specified and vice versa.
*/
public static final int DEFAULT_ORDER = 1000;
String getName();
String getID();
String getDescription();
/**
* The order that determines UI appearance of the tree node,
* not necessarily its position in {@link #getChildren()}
* @return The order of this tree option relative to its peers.
* Smaller number means it should appear above peers.
* @see #DEFAULT_ORDER
*/
int getOrder();
void setOrder(int order);
ITreeOption[] getChildren();
ITreeOption getParent();
boolean isContainer();
String getCommand();
ITreeOption getChild(String name);
/**
* Adds a new child directly under this node.
* @param id
* @param name
* @return
*/
ITreeOption addChild(String id, String name);
void remove();
String getIcon();
}
}

View file

@ -120,6 +120,7 @@ public class ManagedOptionValueHandler implements
}
break;
case IOption.ENUMERATED:
case IOption.TREE:
if (option.getValue().toString().equals(defaultValue.toString())) {
return true;
}

View file

@ -657,7 +657,7 @@ public class BuildStep implements IBuildStep {
} else {
ManagedBuildManager.setOption(cfg, fTool, assignToOption, false);
}
} else if (optType == IOption.ENUMERATED) {
} else if (optType == IOption.ENUMERATED || optType == IOption.TREE) {
if (bRcs.length > 0) {
ManagedBuildManager.setOption(cfg, fTool, assignToOption, BuildDescriptionManager.getRelPath(cwd, bRcs[0].getLocation()).toOSString());
}

View file

@ -132,6 +132,7 @@ public class ConfigurationV2 extends BuildObject implements IConfigurationV2 {
new OptionReference(newRef, opt).setValue(optRef.getBooleanValue());
break;
case IOption.STRING:
case IOption.TREE:
new OptionReference(newRef, opt).setValue(optRef.getStringValue());
break;
case IOption.ENUMERATED:

View file

@ -39,6 +39,7 @@ import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
import org.eclipse.cdt.managedbuilder.core.ManagedOptionValueHandler;
import org.eclipse.cdt.managedbuilder.core.OptionStringValue;
import org.eclipse.cdt.managedbuilder.core.IOption.ITreeOption;
import org.eclipse.cdt.managedbuilder.internal.enablement.OptionEnablementExpression;
import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData;
import org.eclipse.cdt.managedbuilder.macros.IOptionContextData;
@ -71,9 +72,9 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
private String commandFalse;
private String tip;
private String contextId;
private List<String> enumList;
private Map<String, String> enumCommands;
private Map<String, String> enumNames;
private List<String> applicableValuesList;
private Map<String, String> commandsMap;
private Map<String, String> namesMap;
private Object value;
private Object defaultValue;
private Integer valueType;
@ -87,6 +88,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
private IConfigurationElement applicabilityCalculatorElement = null;
private IOptionApplicability applicabilityCalculator = null;
private BooleanExpressionApplicabilityCalculator booleanExpressionCalculator = null;
private ITreeRoot treeRoot;
// Miscellaneous
private boolean isExtensionOption = false;
private boolean isDirty = false;
@ -222,10 +224,13 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
if (option.resourceFilter != null) {
resourceFilter = new Integer(option.resourceFilter.intValue());
}
if (option.enumList != null) {
enumList = new ArrayList<String>(option.enumList);
enumCommands = new HashMap<String, String>(option.enumCommands);
enumNames = new HashMap<String, String>(option.enumNames);
if (option.applicableValuesList != null) {
applicableValuesList = new ArrayList<String>(option.applicableValuesList);
commandsMap = new HashMap<String, String>(option.commandsMap);
namesMap = new HashMap<String, String>(option.namesMap);
}
if (option.treeRoot != null) {
treeRoot = new TreeRoot((TreeRoot) option.treeRoot);
}
if (option.valueType != null) {
@ -245,6 +250,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
break;
case STRING:
case ENUMERATED:
case TREE:
if (option.value != null) {
value = new String((String)option.value);
}
@ -549,18 +555,18 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
ICStorageElement configElement = configNode;
String optId = SafeStringInterner.safeIntern(configElement.getAttribute(ID));
if (i == 0) {
enumList = new ArrayList<String>();
applicableValuesList = new ArrayList<String>();
if (defaultValue == null) {
defaultValue = optId; // Default value to be overridden is default is specified
}
}
enumList.add(optId);
applicableValuesList.add(optId);
if (configElement.getAttribute(COMMAND) != null) {
getEnumCommandMap().put(optId, SafeStringInterner.safeIntern(configElement.getAttribute(COMMAND)));
getCommandMap().put(optId, SafeStringInterner.safeIntern(configElement.getAttribute(COMMAND)));
} else {
getEnumCommandMap().put(optId, EMPTY_STRING);
getCommandMap().put(optId, EMPTY_STRING);
}
getEnumNameMap().put(optId, SafeStringInterner.safeIntern(configElement.getAttribute(NAME)));
getNameMap().put(optId, SafeStringInterner.safeIntern(configElement.getAttribute(NAME)));
if (configElement.getAttribute(IS_DEFAULT) != null) {
Boolean isDefault = new Boolean(configElement.getAttribute(IS_DEFAULT));
if (isDefault.booleanValue()) {
@ -570,6 +576,14 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
}
}
break;
case TREE:
if (element.getAttribute(VALUE) != null) {
value = element.getAttribute(VALUE);
}
if (element.getAttribute(DEFAULT_VALUE) != null) {
defaultValue = element.getAttribute(DEFAULT_VALUE);
}
break;
case STRING_LIST:
case INCLUDE_PATH:
case PREPROCESSOR_SYMBOLS:
@ -727,6 +741,8 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
return UNDEF_INCLUDE_FILES;
else if (valueTypeStr.equals(TYPE_UNDEF_SYMBOL_FILES))
return UNDEF_MACRO_FILES;
else if (valueTypeStr.equals(TYPE_TREE))
return TREE;
else {
// TODO: This was the CDT 2.0 default - should we keep it?
return PREPROCESSOR_SYMBOLS;
@ -789,6 +805,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
break;
case STRING:
case ENUMERATED:
case TREE:
element.setAttribute(VALUE, (String)value);
break;
case STRING_LIST:
@ -834,6 +851,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
break;
case STRING:
case ENUMERATED:
case TREE:
element.setAttribute(DEFAULT_VALUE, (String)defaultValue);
break;
default:
@ -898,6 +916,9 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
case UNDEF_MACRO_FILES:
str = TYPE_UNDEF_SYMBOL_FILES;
break;
case TREE:
str = TYPE_TREE;
break;
default:
// TODO; is this a problem...
str = EMPTY_STRING;
@ -1039,7 +1060,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
@Override
public String[] getApplicableValues() {
// Does this option instance have the list of values?
if (enumList == null) {
if (applicableValuesList == null) {
if (superClass != null) {
return superClass.getApplicableValues();
} else {
@ -1047,13 +1068,13 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
}
}
// Get all of the enumerated names from the option
if (enumList.size() == 0) {
if (applicableValuesList.size() == 0) {
return EMPTY_STRING_ARRAY;
} else {
// Return the elements in the order they are specified in the manifest
String[] enumNames = new String[enumList.size()];
for (int index = 0; index < enumList.size(); ++ index) {
enumNames[index] = getEnumNameMap().get(enumList.get(index));
String[] enumNames = new String[applicableValuesList.size()];
for (int index = 0; index < applicableValuesList.size(); ++ index) {
enumNames[index] = getNameMap().get(applicableValuesList.get(index));
}
return enumNames;
}
@ -1311,35 +1332,35 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IOption#getEnumCommand(java.lang.String)
* @see org.eclipse.cdt.managedbuilder.core.IOption#getCommand(java.lang.String)
*/
@Override
public String getEnumCommand(String id) throws BuildException {
public String getCommand(String id) throws BuildException {
// Sanity
if (id == null) return EMPTY_STRING;
// Does this option instance have the list of values?
if (enumList == null) {
if (applicableValuesList == null) {
if (superClass != null) {
return superClass.getEnumCommand(id);
return superClass.getCommand(id);
} else {
return EMPTY_STRING;
}
}
if (getValueType() != ENUMERATED) {
if (getValueType() != ENUMERATED && getValueType() != TREE) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
// First check for the command in ID->command map
String cmd = getEnumCommandMap().get(id);
String cmd = getCommandMap().get(id);
if (cmd == null) {
// This may be a 1.2 project or plugin manifest. If so, the argument is the human readable
// name of the enumeration. Search for the ID that maps to the name and use that to find the
// command.
for (String realID : enumList) {
String name = getEnumNameMap().get(realID);
for (String realID : applicableValuesList) {
String name = getNameMap().get(realID);
if (id.equals(name)) {
cmd = getEnumCommandMap().get(realID);
cmd = getCommandMap().get(realID);
break;
}
}
@ -1347,18 +1368,31 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
return cmd == null ? EMPTY_STRING : cmd;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IOption#getEnumCommand(java.lang.String)
*/
@Override
public String getEnumCommand(String id) throws BuildException {
return getCommand(id);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IOption#getEnumName(java.lang.String)
*/
@Override
public String getEnumName(String id) throws BuildException {
return getName(id);
}
@Override
public String getName(String id) throws BuildException {
// Sanity
if (id == null) return EMPTY_STRING;
// Does this option instance have the list of values?
if (enumList == null) {
if (applicableValuesList == null) {
if (superClass != null) {
return superClass.getEnumName(id);
return superClass.getName(id);
} else {
return EMPTY_STRING;
}
@ -1368,7 +1402,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
}
// First check for the command in ID->name map
String name = getEnumNameMap().get(id);
String name = getNameMap().get(id);
if (name == null) {
// This may be a 1.2 project or plugin manifest. If so, the argument is the human readable
// name of the enumeration.
@ -1384,11 +1418,11 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
* @return a Map of enumerated option value IDs to actual commands that are passed
* to a tool on the command line.
*/
private Map<String, String> getEnumCommandMap() {
if (enumCommands == null) {
enumCommands = new HashMap<String, String>();
private Map<String, String> getCommandMap() {
if (commandsMap == null) {
commandsMap = new HashMap<String, String>();
}
return enumCommands;
return commandsMap;
}
/* (non-Javadoc)
@ -1396,23 +1430,28 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
*/
@Override
public String getEnumeratedId(String name) throws BuildException {
return getId(name);
}
@Override
public String getId(String name) throws BuildException {
if (name == null) return null;
// Does this option instance have the list of values?
if (enumList == null) {
if (applicableValuesList == null) {
if (superClass != null) {
return superClass.getEnumeratedId(name);
return superClass.getId(name);
} else {
return EMPTY_STRING;
}
}
if (getValueType() != ENUMERATED) {
if (getValueType() != ENUMERATED && getValueType() != TREE) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
Set<String> idSet = getEnumNameMap().keySet();
Set<String> idSet = getNameMap().keySet();
for (String id : idSet) {
String enumName = getEnumNameMap().get(id);
String enumName = getNameMap().get(id);
if (name.equals(enumName)) {
return id;
}
@ -1424,11 +1463,11 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
*
* @return a Map of enumerated option value IDs to the selection displayed to the user.
*/
private Map<String, String> getEnumNameMap() {
if (enumNames == null) {
enumNames = new HashMap<String, String>();
private Map<String, String> getNameMap() {
if (namesMap == null) {
namesMap = new HashMap<String, String>();
}
return enumNames;
return namesMap;
}
/* (non-Javadoc)
@ -1537,7 +1576,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
*/
@Override
public String getStringValue() throws BuildException {
if (getValueType() != STRING && getValueType() != ENUMERATED) {
if (getValueType() != STRING && getValueType() != ENUMERATED && getValueType() != TREE) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
return getValue() == null ? EMPTY_STRING : (String)getValue();
@ -1609,6 +1648,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
val = new Boolean(false);
break;
case STRING:
case TREE:
val = EMPTY_STRING;
break;
case ENUMERATED:
@ -1669,6 +1709,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
val = new Boolean(false);
break;
case STRING:
case TREE:
val = EMPTY_STRING;
break;
case ENUMERATED:
@ -1949,7 +1990,7 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
@Override
public void setValue(String value) throws BuildException {
// Note that we can still set the human-readable value here
if (/*!isExtensionElement() && */(getValueType() == STRING || getValueType() == ENUMERATED)) {
if (/*!isExtensionElement() && */(getValueType() == STRING || getValueType() == ENUMERATED || getValueType() == TREE)) {
this.value = value;
} else {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
@ -2281,19 +2322,43 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
for (int i = 0; i < enumElements.length; ++i) {
String optId = SafeStringInterner.safeIntern(enumElements[i].getAttribute(ID));
if (i == 0) {
enumList = new ArrayList<String>();
applicableValuesList = new ArrayList<String>();
if (defaultValue == null) {
defaultValue = optId; // Default value to be overridden if default is specified
}
}
enumList.add(optId);
getEnumCommandMap().put(optId, SafeStringInterner.safeIntern(enumElements[i].getAttribute(COMMAND)));
getEnumNameMap().put(optId, SafeStringInterner.safeIntern(enumElements[i].getAttribute(NAME)));
applicableValuesList.add(optId);
getCommandMap().put(optId, SafeStringInterner.safeIntern(enumElements[i].getAttribute(COMMAND)));
getNameMap().put(optId, SafeStringInterner.safeIntern(enumElements[i].getAttribute(NAME)));
Boolean isDefault = new Boolean(enumElements[i].getAttribute(IS_DEFAULT));
if (isDefault.booleanValue()) {
defaultValue = optId;
}
}
break;
case TREE:
value = element.getAttribute(VALUE);
defaultValue = element.getAttribute(DEFAULT_VALUE);
IManagedConfigElement[] treeRootConfigs = element.getChildren(TREE_ROOT);
if (treeRootConfigs != null && treeRootConfigs.length == 1) {
IManagedConfigElement treeRootConfig = treeRootConfigs[0];
treeRoot = new TreeRoot(treeRootConfig, element, getParent() instanceof IToolChain);
applicableValuesList = new ArrayList<String>();
iterateOnTree(treeRoot, new ITreeNodeIterator() {
@Override
public void iterateOnNode(ITreeOption node) {}
@Override
public void iterateOnLeaf(ITreeOption leafNode) {
applicableValuesList.add(leafNode.getID());
getCommandMap().put(leafNode.getID(), leafNode.getCommand());
getNameMap().put(leafNode.getID(), leafNode.getName());
}
});
}
break;
case STRING_LIST:
case INCLUDE_PATH:
@ -2613,6 +2678,8 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
return IOption.STRING;
case IOption.ENUMERATED:
return IOption.ENUMERATED;
case IOption.TREE:
return IOption.TREE;
default:
return IOption.STRING_LIST;
}
@ -2658,4 +2725,267 @@ public class Option extends BuildObject implements IOption, IBuildPropertiesRest
}
return 0;
}
public static class TreeRoot extends TreeOption implements ITreeRoot {
private boolean selectLeafOnly = true;
TreeRoot(IManagedConfigElement element, IManagedConfigElement buildOption, boolean readTool) {
super(element, null, readTool);
String leaf = element.getAttribute(SELECT_LEAF_ONLY);
if (leaf != null) {
selectLeafOnly = Boolean.valueOf(leaf);
}
String toolTip = buildOption.getAttribute(TOOL_TIP);
if (description == null && toolTip != null) {
description = toolTip;
}
}
public TreeRoot() {
super("", "", null); //$NON-NLS-1$ //$NON-NLS-2$
}
public TreeRoot(TreeRoot clone) {
super(clone, null);
selectLeafOnly = clone.selectLeafOnly;
}
@Override
public boolean isSelectLeafsOnly() {
return selectLeafOnly;
}
@Override
public ITreeOption findNode(String id) {
if(id == null) return null;
return find(id, children);
}
private ITreeOption find(String id, List<ITreeOption> children) {
ITreeOption found = null;
if (children != null) {
for (ITreeOption child : children) {
if (id.equals(child.getID())) {
found = child;
break;
}
found = find(id, ((TreeOption)child).children);
if (found != null) break;
}
}
return found;
}
@Override
public ITreeOption addNode(String id, String name, String category, Integer order) {
ITreeOption parent = this;
if (category != null && category.length() > 0) {
ITreeOption tempParent;
String tempCategory = "";
String[] categories = category.split("\\."); //$NON-NLS-1$
for (String cat : categories) {
tempCategory += cat;
tempParent = parent.getChild(cat);
if (tempParent == null) {
tempParent = parent.addChild(cat, cat);
if (order != null) {
tempParent.setOrder(order);
}
}
parent = tempParent;
tempCategory += '.';
}
}
ITreeOption child = parent.addChild(id, name);
if (order != null) {
child.setOrder(order);
}
return child;
}
}
private static class TreeOption implements ITreeOption {
private String treeNodeId;
private String treeNodeName;
protected String description;
protected String icon;
protected String command;
protected List<ITreeOption> children = null;
private int order = DEFAULT_ORDER;
private ITreeOption parent;
TreeOption(IManagedConfigElement element, ITreeOption parent, boolean readTool) {
treeNodeId = element.getAttribute(ID);
treeNodeName = element.getAttribute(NAME);
description = element.getAttribute(DESCRIPTION);
command = element.getAttribute(COMMAND);
icon = element.getAttribute(ICON);
String orderStr = element.getAttribute(ORDER);
if (orderStr != null && orderStr.trim().length() > 0) {
try {
order = Integer.parseInt(orderStr);
} catch (NumberFormatException e) {
// Do nothing, default value is used.
}
}
this.parent = parent;
IManagedConfigElement[] treeChildren = element.getChildren(TREE_VALUE);
if (treeChildren != null && treeChildren.length > 0) {
children = new ArrayList<IOption.ITreeOption>();
for (IManagedConfigElement configElement : treeChildren) {
children.add(new TreeOption(configElement, this, readTool));
}
}
}
TreeOption(TreeOption clone, ITreeOption parent) {
treeNodeId = clone.treeNodeId;
treeNodeName = clone.treeNodeName;
description = clone.description;
command = clone.command;
icon = clone.icon;
order = clone.order;
this.parent = parent;
if (clone.children != null) {
children = new ArrayList<IOption.ITreeOption>();
for (ITreeOption cloneChild : clone.children) {
children.add(new TreeOption((TreeOption) cloneChild, this));
}
}
}
private TreeOption(String id, String name, ITreeOption parent) {
this.treeNodeId = id;
this.treeNodeName = name;
this.parent = parent;
}
@Override
public ITreeOption addChild(String id, String name) {
ITreeOption option = new TreeOption(id, name, this);
if (children == null) {
children = new ArrayList<IOption.ITreeOption>();
}
children.add(0, option);
return option;
}
@Override
public boolean isContainer() {
return children != null && !children.isEmpty(); // TODO do we need explicit marking as container for empty ones
}
@Override
public String getName() {
return treeNodeName;
}
@Override
public String getID() {
return treeNodeId;
}
@Override
public String getDescription() {
return description;
}
@Override
public String getCommand() {
return command;
}
@Override
public String getIcon() {
return icon;
}
@Override
public ITreeOption[] getChildren() {
if (children == null) return null;
return children.toArray(new ITreeOption[children.size()]);
}
@Override
public ITreeOption getChild(String name) {
if (children == null || name == null) return null;
for (ITreeOption child : children) {
if (name.equals(child.getName())) {
return child;
}
}
return null;
}
@Override
public ITreeOption getParent() {
return parent;
}
@Override
public int getOrder() {
return order;
}
@Override
public void setOrder(int order) {
this.order = order;
}
@Override
public void remove() {
((TreeOption)parent).children.remove(this);
}
@Override
public String toString() {
return getName();
}
}
/**
* Calls the iterator (visitor) on the passed parent as well as all nodes in its subtree.
* @param it
* @param parent
*/
public static void iterateOnTree(ITreeOption parent, ITreeNodeIterator it) {
it.iterateOnNode(parent);
if (!parent.isContainer()) {
it.iterateOnLeaf(parent);
}
ITreeOption[] children = parent.getChildren();
if (children != null) {
for (ITreeOption option : children) {
iterateOnTree(option, it);
}
}
}
public interface ITreeNodeIterator {
void iterateOnNode(ITreeOption node);
void iterateOnLeaf(ITreeOption leafNode);
}
@Override
public ITreeRoot getTreeRoot() throws BuildException {
if (treeRoot == null) {
if (superClass != null) {
return superClass.getTreeRoot();
} else {
return null;
}
}
if (getValueType() != TREE) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
return treeRoot;
}
}

View file

@ -117,6 +117,7 @@ public class OptionReference implements IOption {
value = new Boolean(element.getAttribute(DEFAULT_VALUE));
break;
case STRING:
case TREE:
case ENUMERATED:
// Pre-2.0 the value was the string for the UI
// Post-2.0 it is the ID of the enumerated option
@ -189,6 +190,7 @@ public class OptionReference implements IOption {
case STRING:
value = element.getAttribute(DEFAULT_VALUE);
break;
case TREE:
case ENUMERATED:
String temp = element.getAttribute(DEFAULT_VALUE);
if (temp != null) {
@ -248,6 +250,7 @@ public class OptionReference implements IOption {
element.setAttribute(DEFAULT_VALUE, ((Boolean)value).toString());
break;
case STRING:
case TREE:
case ENUMERATED:
element.setAttribute(DEFAULT_VALUE, (String)value);
break;
@ -384,6 +387,19 @@ public class OptionReference implements IOption {
return new String();
}
public String getCommand(String id) throws BuildException {
if (!resolved) {
resolveReferences();
}
if (option != null) {
try {
String command = option.getCommand(id);
return command;
} catch (BuildException e) {}
}
return new String();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.build.managed.IOption#getEnumName(java.lang.String)
*/
@ -401,6 +417,19 @@ public class OptionReference implements IOption {
return new String();
}
public String getName(String id) throws BuildException {
if (!resolved) {
resolveReferences();
}
if (option != null) {
try {
String name = option.getName(id);
return name;
} catch (BuildException e) {}
}
return new String();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.core.IOption#getEnumeratedId(java.lang.String)
*/
@ -418,6 +447,19 @@ public class OptionReference implements IOption {
return new String();
}
public String getId(String name) throws BuildException {
if (!resolved) {
resolveReferences();
}
if (option != null) {
try {
String id = option.getId(name);
return id;
} catch (BuildException e) {}
}
return new String();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.build.managed.IBuildObject#getId()
*/
@ -730,7 +772,7 @@ public class OptionReference implements IOption {
@Override
public void setValue(String value) throws BuildException {
// Note that we can still set the human-readable value here
if (getValueType() == STRING || getValueType() == ENUMERATED) {
if (getValueType() == STRING || getValueType() == ENUMERATED || getValueType() == TREE) {
this.value = value;
} else {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
@ -1024,6 +1066,8 @@ public class OptionReference implements IOption {
return IOption.STRING;
case IOption.ENUMERATED:
return IOption.ENUMERATED;
case IOption.TREE:
return IOption.TREE;
default:
return IOption.STRING_LIST;
}
@ -1039,4 +1083,17 @@ public class OptionReference implements IOption {
}
return ve;
}
public ITreeRoot getTreeRoot() {
if (!resolved) {
resolveReferences();
}
if (option != null) {
try {
return option.getTreeRoot();
} catch (BuildException e) {
}
}
return null;
}
}

View file

@ -2625,6 +2625,13 @@ public class Tool extends HoldsOptions implements ITool, IOptionCategory, IMatch
}
break;
case IOption.TREE :
String treeVal = option.getCommand(option.getStringValue());
if (treeVal.length() > 0) {
sb.append(treeVal);
}
break;
case IOption.STRING :{
String strCmd = option.getCommand();
String val = option.getStringValue();

View file

@ -201,7 +201,9 @@ public class ToolReference implements IToolReference {
clone.setValue(parent.getBooleanValue());
break;
case IOption.STRING:
case IOption.TREE:
clone.setValue(parent.getStringValue());
break;
case IOption.ENUMERATED:
clone.setValue(parent.getSelectedEnum());
break;
@ -518,6 +520,13 @@ public class ToolReference implements IToolReference {
}
break;
case IOption.TREE :
String treeVal = option.getCommand(option.getStringValue());
if (treeVal.length() > 0) {
buf.append(treeVal + WHITE_SPACE);
}
break;
case IOption.STRING :
String strCmd = option.getCommand();
String val = option.getStringValue();

View file

@ -112,6 +112,7 @@ public class CheckOptionExpression implements IBooleanExpression {
switch(option.getValueType()){
case IOption.STRING:
case IOption.TREE:
case IOption.ENUMERATED:{
String stringValue = option.getStringValue();
stringValue = provider.resolveValue(stringValue, inexVal, delimiter,
@ -177,6 +178,7 @@ public class CheckOptionExpression implements IBooleanExpression {
switch(option.getValueType()){
case IOption.STRING:
case IOption.TREE:
case IOption.ENUMERATED:{
String stringValue = option.getStringValue();
stringValue = provider.resolveValue(stringValue, inexVal, delimiter,

View file

@ -298,6 +298,7 @@ public class OptionEnablementExpression extends AndExpression{
}
break;
case IOption.ENUMERATED:
case IOption.TREE:
case IOption.STRING:
if(extensionAdjustment)
setOption.setValue(value);

View file

@ -913,6 +913,8 @@ public class MbsMacroSupplier extends BuildCdtVariablesSupplierBase {
break;
case IOption.ENUMERATED:
break;
case IOption.TREE:
break;
case IOption.STRING_LIST:
fType = IBuildMacro.VALUE_TEXT_LIST;
fStringListValue = option.getStringListValue();
@ -1138,6 +1140,8 @@ public class MbsMacroSupplier extends BuildCdtVariablesSupplierBase {
break;
case IOption.ENUMERATED:
break;
case IOption.TREE:
break;
case IOption.STRING_LIST:
can = true;
break;

View file

@ -3044,7 +3044,7 @@ public class GnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 {
boolean b = false;
if (allRes.size() > 0) b = true;
ManagedBuildManager.setOption(rcInfo, tool, assignToOption, b);
} else if (optType == IOption.ENUMERATED) {
} else if (optType == IOption.ENUMERATED || optType == IOption.TREE) {
if (allRes.size() > 0) {
String s = allRes.get(0).toString();
ManagedBuildManager.setOption(rcInfo, tool, assignToOption, s);

View file

@ -422,7 +422,7 @@ public class ManagedBuildGnuToolInfo implements IManagedBuildGnuToolInfo {
} else {
ManagedBuildManager.setOption(config, tool, assignToOption, false);
}
} else if (optType == IOption.ENUMERATED) {
} else if (optType == IOption.ENUMERATED || optType == IOption.TREE) {
if (itCommandInputs.size() > 0) {
ManagedBuildManager.setOption(config, tool, assignToOption, itCommandInputs.firstElement());
}

View file

@ -397,6 +397,19 @@ class UpdateManagedProject12 {
}
configuration.setOption(tool, newOpt, idValue != null ? idValue : name);
break;
case IOption.TREE:
// This is going to be the human readable form of the tree value
name = optRef.getAttribute(IOption.DEFAULT_VALUE);
// Convert it to the ID
idValue = newOpt.getId(name);
if (idValue == null) {
// If the name does not match one of the enumerations values, probably because
// the list of enumerands has changed, set the name to be the name used for the
// enumeration's default value
name = (String)newOpt.getDefaultValue();
}
configuration.setOption(tool, newOpt, idValue != null ? idValue : name);
break;
case IOption.STRING_LIST:
case IOption.INCLUDE_PATH:
case IOption.PREPROCESSOR_SYMBOLS:

View file

@ -427,6 +427,7 @@ class UpdateManagedProject20 {
break;
}
case IOption.ENUMERATED:
case IOption.TREE:
case IOption.STRING:{
if(optRef.hasAttribute(IOption.DEFAULT_VALUE))
configuration.setOption(tool,option,optRef.getAttribute(IOption.DEFAULT_VALUE));

View file

@ -118,7 +118,7 @@ public class SetMBSStringOptionValue extends ProcessRunner {
for (IOption option : options) {
if (option.getBaseId().toLowerCase().matches(lowerId)) {
int optionType = option.getValueType();
if ((optionType == IOption.STRING) || (optionType == IOption.ENUMERATED)) {
if ((optionType == IOption.STRING) || (optionType == IOption.ENUMERATED) || (optionType == IOption.TREE)) {
ManagedBuildManager.setOption(resourceConfig, optionHolder, option, value);
modified = true;
}
@ -133,7 +133,7 @@ public class SetMBSStringOptionValue extends ProcessRunner {
for (IOption option : options) {
if (option.getBaseId().toLowerCase().matches(lowerId)) {
int optionType = option.getValueType();
if ((optionType == IOption.STRING) || (optionType == IOption.ENUMERATED)) {
if ((optionType == IOption.STRING) || (optionType == IOption.ENUMERATED) || (optionType == IOption.TREE)) {
ManagedBuildManager.setOption(config, optionHolder, option, value);
modified = true;
}

View file

@ -14,8 +14,12 @@
package org.eclipse.cdt.managedbuilder.ui.properties;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -28,6 +32,8 @@ import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IHoldsOptions;
import org.eclipse.cdt.managedbuilder.core.IManagedOptionValueHandler;
import org.eclipse.cdt.managedbuilder.core.IOption;
import org.eclipse.cdt.managedbuilder.core.IOption.ITreeOption;
import org.eclipse.cdt.managedbuilder.core.IOption.ITreeRoot;
import org.eclipse.cdt.managedbuilder.core.IOptionApplicability;
import org.eclipse.cdt.managedbuilder.core.IOptionCategory;
import org.eclipse.cdt.managedbuilder.core.IResourceInfo;
@ -42,18 +48,37 @@ import org.eclipse.cdt.ui.newui.AbstractPage;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.DirectoryFieldEditor;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.jface.preference.FileFieldEditor;
import org.eclipse.jface.preference.StringButtonFieldEditor;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.TextProcessor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
@ -61,10 +86,13 @@ import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.osgi.framework.Bundle;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
/**
* Option settings page in project properties Build Settings under Tool Settings tab.
@ -87,6 +115,35 @@ public class BuildOptionSettingsUI extends AbstractToolSettingUI {
** currently set to Enter rather than Hover since the former seems more responsive **/
private final static int selectAction = SWT.MouseEnter;
private final class TreeBrowseFieldEditor extends StringButtonFieldEditor {
private final String nameStr;
private final IOption option;
private String contextId;
private TreeBrowseFieldEditor(String name, String labelText, Composite parent, String nameStr,
IOption option, String contextId) {
super(name, labelText, parent);
this.nameStr = nameStr;
this.option = option;
this.contextId = contextId;
}
@Override
protected String changePressed() {
ITreeRoot treeRoot;
try {
treeRoot = option.getTreeRoot();
TreeSelectionDialog dlg = new TreeSelectionDialog(getShell(), treeRoot, nameStr, contextId);
if (dlg.open() == Window.OK) {
ITreeOption selected = dlg.getSelection();
return selected.getName();
}
} catch (BuildException e) {
}
return null;
}
}
private class TipInfo {
private String name;
private String tip;
@ -212,7 +269,7 @@ public class BuildOptionSettingsUI extends AbstractToolSettingUI {
if (applicabilityCalculator == null || applicabilityCalculator.isOptionVisible(config, holder, opt)) {
String optId = getToolSettingsPrefStore().getOptionId(opt);
String nameStr = TextProcessor.process(opt.getName());
final String nameStr = TextProcessor.process(opt.getName());
String tipStr = TextProcessor.process(opt.getToolTip());
String contextId = opt.getContextId();
@ -374,6 +431,20 @@ public class BuildOptionSettingsUI extends AbstractToolSettingUI {
}
} break;
case IOption.TREE:
fieldEditor = new TreeBrowseFieldEditor(optId, nameStr, fieldEditorParent, nameStr, opt, contextId);
((StringButtonFieldEditor)fieldEditor).setChangeButtonText("..."); //$NON-NLS-1$
if (pageHasToolTipBox) {
Text text = ((StringButtonFieldEditor)fieldEditor).getTextControl(fieldEditorParent);
Label label = fieldEditor.getLabelControl(fieldEditorParent);
text.setData(new TipInfo(nameStr,tipStr));
text.addListener(selectAction, tipSetListener);
label.setData(new TipInfo(nameStr,tipStr));
label.addListener(selectAction, tipSetListener);
}
break;
case IOption.INCLUDE_PATH:
case IOption.STRING_LIST:
case IOption.PREPROCESSOR_SYMBOLS:
@ -563,8 +634,9 @@ public class BuildOptionSettingsUI extends AbstractToolSettingUI {
// }
break;
case IOption.ENUMERATED :
case IOption.TREE :
String enumVal = clonedOption.getStringValue();
String enumId = clonedOption.getEnumeratedId(enumVal);
String enumId = clonedOption.getId(enumVal);
setOption = ManagedBuildManager.setOption(realCfg, realHolder, realOption,
(enumId != null && enumId.length() > 0) ? enumId : enumVal);
// Reset the preference store since the Id may have changed
@ -755,6 +827,15 @@ public class BuildOptionSettingsUI extends AbstractToolSettingUI {
ManagedBuildManager.setOption(fInfo,changedHolder,changedOption,
(enumId != null && enumId.length() > 0) ? enumId : name);
}
break;
case IOption.TREE:
if(fe instanceof TreeBrowseFieldEditor){
String name = ((TreeBrowseFieldEditor)fe).getStringValue();
String treeId = changedOption.getId(name);
ManagedBuildManager.setOption(fInfo,changedHolder,changedOption,
(treeId != null && treeId.length() > 0) ? treeId : name);
}
break;
case IOption.INCLUDE_PATH:
@ -1004,5 +1085,237 @@ public class BuildOptionSettingsUI extends AbstractToolSettingUI {
}
}
/**
* @since 8.1
*/
public static class TreeSelectionDialog extends TitleAreaDialog {
private final ITreeRoot treeRoot;
private ITreeOption selected;
private final String name;
private String contextId;
private String baseMessage = ""; //$NON-NLS-1$
public TreeSelectionDialog(Shell parentShell, ITreeRoot root, String name, String contextId) {
super(parentShell);
treeRoot = root;
setShellStyle(getShellStyle() | SWT.RESIZE);
if (root.getIcon() != null) {
Image img = createImage(root.getIcon());
if (img != null) {
setTitleImage(img);
}
}
this.name = name;
this.contextId = contextId;
if (contextId != null && contextId.length() > 0) {
setHelpAvailable(true);
}
}
@Override
protected Control createDialogArea(Composite parent) {
if (contextId != null && contextId.length() > 0) {
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, contextId);
}
Composite control = new Composite(parent, SWT.NULL);
GridData gd= new GridData(GridData.FILL_BOTH);
GridLayout topLayout = new GridLayout();
topLayout.numColumns = 1;
control.setLayout(topLayout);
control.setLayoutData(gd);
PatternFilter filter = new PatternFilter();
filter.setIncludeLeadingWildcard(true);
FilteredTree tree = new FilteredTree(control,
SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER,
filter, true);
final TreeViewer viewer = tree.getViewer();
viewer.setContentProvider(new ITreeContentProvider() {
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
@Override
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
@Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof ITreeOption) {
ITreeOption[] children = ((ITreeOption)parentElement).getChildren();
// Not entirely sure whether this method is allowed to return null,
// but let's play safe.
if (children == null)
return null;
List<ITreeOption> childrenList = new ArrayList<ITreeOption>(Arrays.asList(children));
// Check if any of the children has empty name
List<ITreeOption> toRemove = null;
for (ITreeOption child : children) {
if (child.getName() == null || child.getName().trim().length() == 0) {
if (toRemove == null) {
toRemove = new ArrayList<ITreeOption>();
}
toRemove.add(child);
}
}
if (toRemove != null) {
childrenList.removeAll(toRemove);
}
// Sort the children.
Collections.sort(childrenList, new Comparator<ITreeOption>() {
@Override
public int compare(ITreeOption arg0, ITreeOption arg1) {
if (arg0.getOrder() == arg1.getOrder()) {
return arg0.getName().compareToIgnoreCase(arg1.getName());
} else {
return arg0.getOrder() - arg1.getOrder();
}
}
});
return childrenList.toArray(new ITreeOption[0]);
}
return null;
}
@Override
public Object getParent(Object element) {
if (element instanceof ITreeOption) {
return ((ITreeOption)element).getParent();
}
return null;
}
@Override
public boolean hasChildren(Object element) {
Object[] children = getChildren(element);
return children != null && children.length > 0;
}
});
viewer.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
if (element instanceof ITreeOption) {
return ((ITreeOption)element).getName();
}
return super.getText(element);
}
@Override
public Image getImage(Object element) {
if (element instanceof ITreeOption) {
String icon = ((ITreeOption)element).getIcon();
return createImage(icon);
}
return super.getImage(element);
}
});
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
if (selection instanceof IStructuredSelection) {
Object selectedObj = ((IStructuredSelection)selection).getFirstElement();
if (selectedObj instanceof ITreeOption) {
selected = (ITreeOption) selectedObj;
updateOKButton(selected);
// Adjust Message
String description = selected.getDescription();
if (description == null) {
ITreeOption node = selected;
description = ""; //$NON-NLS-1$
String sep = ": "; //$NON-NLS-1$
while (node != null && node.getParent() != null) { // ignore root
description = sep + node.getName() + description;
node = node.getParent();
}
description = description.substring(sep.length()); // remove the first separator.
}
setMessage(baseMessage + description);
}
}
}
});
viewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
ISelection selection = event.getSelection();
if (!selection.isEmpty() && selection instanceof IStructuredSelection && ((IStructuredSelection)selection).size() == 1) {
Object selectedNode = ((IStructuredSelection)selection).getFirstElement();
if (selectedNode instanceof ITreeOption) {
if (updateOKButton((ITreeOption)selectedNode)) {
TreeSelectionDialog.this.okPressed();
} else { // if doubleclick is not on selectable item, expand/collapse
viewer.setExpandedState(selectedNode,!viewer.getExpandedState(selectedNode));
}
}
}
}
});
viewer.setInput(treeRoot);
String msg = "Select " + name; //$NON-NLS-1$
getShell().setText(msg);
setTitle(msg);
if (treeRoot.getDescription() != null) {
baseMessage = treeRoot.getDescription();
setMessage(baseMessage);
baseMessage += "\nCurrent Selection: "; //$NON-NLS-1$
} else {
setMessage(msg);
}
return control;
}
public ITreeOption getSelection() {
return selected;
}
private Image createImage(String icon) {
if (icon != null) {
URL url = null;
try {
url = FileLocator.find(new URL(icon));
} catch (Exception e) {
}
if (url != null) {
ImageDescriptor desc = ImageDescriptor.createFromURL(url);
return desc.createImage();
}
}
return null;
}
private boolean updateOKButton(ITreeOption selection) {
// Check if Valid selection (only allow selecting leaf nodes)
if (treeRoot.isSelectLeafsOnly()) {
boolean enableOK = !selection.isContainer();
getButton(IDialogConstants.OK_ID).setEnabled(enableOK);
return enableOK;
}
return false;
}
}
}

View file

@ -20,6 +20,7 @@ import java.util.Vector;
import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.IOption;
import org.eclipse.cdt.managedbuilder.core.IOption.ITreeRoot;
import org.eclipse.cdt.managedbuilder.core.IResourceInfo;
import org.eclipse.cdt.managedbuilder.core.ITool;
import org.eclipse.cdt.managedbuilder.internal.core.MultiResourceInfo;
@ -316,6 +317,20 @@ public class BuildToolSettingUI extends AbstractToolSettingUI {
if (!enumeration.equals("")) //$NON-NLS-1$
setOption(opt, enumeration);
break;
case IOption.TREE :
String selectedID = ""; //$NON-NLS-1$
ITreeRoot treeRoot = opt.getTreeRoot();
String[] treeValues = opt.getApplicableValues();
for (int i = 0; i < treeValues.length; i++) {
if (opt.getCommand(treeValues[i]).equals(
optionValue)) {
selectedID = treeValues[i];
optionValueExist = true;
}
}
if (!selectedID.equals("")) //$NON-NLS-1$
setOption(opt, selectedID);
break;
case IOption.STRING_LIST :
case IOption.INCLUDE_PATH :
case IOption.PREPROCESSOR_SYMBOLS :

View file

@ -205,8 +205,8 @@ public class ToolSettingsPrefStore implements IPreferenceStore {
try {
IOption opt = (IOption)option[1];
Object val = opt.getValue();
if(opt.getValueType() == IOption.ENUMERATED && val instanceof String)
val = opt.getEnumName((String)val);
if((opt.getValueType() == IOption.ENUMERATED || opt.getValueType() == IOption.TREE) && val instanceof String)
val = opt.getName((String)val);
return val;
} catch (BuildException e) {
}
@ -313,9 +313,10 @@ public class ToolSettingsPrefStore implements IPreferenceStore {
}
break;
case IOption.ENUMERATED:
case IOption.TREE:
if(value instanceof String){
String val = (String)value;
String enumId = option.getEnumeratedId(val);
String enumId = option.getId(val);
newOption = rcInfo.setOption(holder, option,
(enumId != null && enumId.length() > 0) ? enumId : val);
}

View file

@ -568,8 +568,9 @@ public class ToolSettingsTab extends AbstractCBuildPropertyTab implements IPrefe
ManagedBuildManager.setOption(res, dst, op2, boolVal);
break;
case IOption.ENUMERATED :
case IOption.TREE :
String enumVal = op1.getStringValue();
String enumId = op1.getEnumeratedId(enumVal);
String enumId = op1.getId(enumVal);
String out = (enumId != null && enumId.length() > 0) ? enumId : enumVal;
ManagedBuildManager.setOption(res, dst, op2, out);
break;