diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiFlagAttributeNode.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiFlagAttributeNode.java | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiFlagAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiFlagAttributeNode.java new file mode 100644 index 000000000..13fcdb6b2 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiFlagAttributeNode.java @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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 com.android.ide.eclipse.adt.internal.editors.uimodel; + +import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; +import com.android.ide.eclipse.adt.internal.editors.descriptors.FlagAttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper; +import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.resource.FontDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.dialogs.SelectionStatusDialog; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.TableWrapData; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +/** + * Represents an XML attribute that is defined by a set of flag values, + * i.e. enum names separated by pipe (|) characters. + * + * Note: in Android resources, a "flag" is a list of fixed values where one or + * more values can be selected using an "or", e.g. "align='left|top'". + * By contrast, an "enum" is a list of fixed values of which only one can be + * selected at a given time, e.g. "gravity='right'". + * <p/> + * This class handles the "flag" case. + * The "enum" case is done using {@link UiListAttributeNode}. + */ +public class UiFlagAttributeNode extends UiTextAttributeNode { + + public UiFlagAttributeNode(FlagAttributeDescriptor attributeDescriptor, + UiElementNode uiParent) { + super(attributeDescriptor, uiParent); + } + + /* (non-java doc) + * Creates a label widget and an associated text field. + * <p/> + * As most other parts of the android manifest editor, this assumes the + * parent uses a table layout with 2 columns. + */ + @Override + public void createUiControl(Composite parent, IManagedForm managedForm) { + setManagedForm(managedForm); + FormToolkit toolkit = managedForm.getToolkit(); + TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); + + Label label = toolkit.createLabel(parent, desc.getUiName()); + label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); + SectionHelper.addControlTooltip(label, DescriptorsUtils.formatTooltip(desc.getTooltip())); + + Composite composite = toolkit.createComposite(parent); + composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); + GridLayout gl = new GridLayout(2, false); + gl.marginHeight = gl.marginWidth = 0; + composite.setLayout(gl); + // Fixes missing text borders under GTK... also requires adding a 1-pixel margin + // for the text field below + toolkit.paintBordersFor(composite); + + final Text text = toolkit.createText(composite, getCurrentValue()); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK + text.setLayoutData(gd); + final Button selectButton = toolkit.createButton(composite, "Select...", SWT.PUSH); + + setTextWidget(text); + + selectButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + super.widgetSelected(e); + + String currentText = getTextWidgetValue(); + + String result = showDialog(selectButton.getShell(), currentText); + + if (result != null) { + setTextWidgetValue(result); + } + } + }); + } + + /** + * Get the flag names, either from the initial names set in the attribute + * or by querying the framework resource parser. + * + * {@inheritDoc} + */ + @Override + public String[] getPossibleValues(String prefix) { + String attr_name = getDescriptor().getXmlLocalName(); + String element_name = getUiParent().getDescriptor().getXmlName(); + + String[] values = null; + + if (getDescriptor() instanceof FlagAttributeDescriptor && + ((FlagAttributeDescriptor) getDescriptor()).getNames() != null) { + // Get enum values from the descriptor + values = ((FlagAttributeDescriptor) getDescriptor()).getNames(); + } + + if (values == null) { + // or from the AndroidTargetData + UiElementNode uiNode = getUiParent(); + AndroidXmlEditor editor = uiNode.getEditor(); + AndroidTargetData data = editor.getTargetData(); + if (data != null) { + values = data.getAttributeValues(element_name, attr_name); + } + } + + return values; + } + + /** + * Shows a dialog letting the user choose a set of enum, and returns a string + * containing the result. + */ + public String showDialog(Shell shell, String currentValue) { + FlagSelectionDialog dlg = new FlagSelectionDialog( + shell, currentValue.trim().split("\\s*\\|\\s*")); //$NON-NLS-1$ + dlg.open(); + Object[] result = dlg.getResult(); + if (result != null) { + StringBuilder buf = new StringBuilder(); + for (Object name : result) { + if (name instanceof String) { + if (buf.length() > 0) { + buf.append('|'); + } + buf.append(name); + } + } + + return buf.toString(); + } + + return null; + + } + + /** + * Displays a list of flag names with checkboxes. + */ + private class FlagSelectionDialog extends SelectionStatusDialog { + + private Set<String> mCurrentSet; + private Table mTable; + + public FlagSelectionDialog(Shell parentShell, String[] currentNames) { + super(parentShell); + + mCurrentSet = new HashSet<String>(); + for (String name : currentNames) { + if (name.length() > 0) { + mCurrentSet.add(name); + } + } + + int shellStyle = getShellStyle(); + setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); + } + + @Override + protected void computeResult() { + if (mTable != null) { + ArrayList<String> results = new ArrayList<String>(); + + for (TableItem item : mTable.getItems()) { + if (item.getChecked()) { + results.add((String)item.getData()); + } + } + + setResult(results); + } + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite= new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + composite.setLayout(new GridLayout(1, true)); + composite.setFont(parent.getFont()); + + Label label = new Label(composite, SWT.NONE); + label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + label.setText(String.format("Select the flag values for attribute %1$s:", + ((FlagAttributeDescriptor) getDescriptor()).getUiName())); + + mTable = new Table(composite, SWT.CHECK | SWT.BORDER); + GridData data = new GridData(); + // The 60,18 hints are the ones used by AbstractElementListSelectionDialog + data.widthHint = convertWidthInCharsToPixels(60); + data.heightHint = convertHeightInCharsToPixels(18); + data.grabExcessVerticalSpace = true; + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.FILL; + mTable.setLayoutData(data); + + mTable.setHeaderVisible(false); + final TableColumn column = new TableColumn(mTable, SWT.NONE); + + // List all the expected flag names and check those which are currently used + String[] names = getPossibleValues(null); + if (names != null) { + for (String name : names) { + TableItem item = new TableItem(mTable, SWT.NONE); + item.setText(name); + item.setData(name); + + boolean hasName = mCurrentSet.contains(name); + item.setChecked(hasName); + if (hasName) { + mCurrentSet.remove(name); + } + } + } + + // If there are unknown flag names currently used, display them at the end if the + // table already checked. + if (!mCurrentSet.isEmpty()) { + FontDescriptor fontDesc = JFaceResources.getDialogFontDescriptor(); + fontDesc = fontDesc.withStyle(SWT.ITALIC); + Font font = fontDesc.createFont(JFaceResources.getDialogFont().getDevice()); + + for (String name : mCurrentSet) { + TableItem item = new TableItem(mTable, SWT.NONE); + item.setText(String.format("%1$s (unknown flag)", name)); + item.setData(name); + item.setChecked(true); + item.setFont(font); + } + } + + // Add a listener that will resize the column to the full width of the table + // so that only one column appears in the table even if the dialog is resized. + ControlAdapter listener = new ControlAdapter() { + @Override + public void controlResized(ControlEvent e) { + Rectangle r = mTable.getClientArea(); + column.setWidth(r.width); + } + }; + + mTable.addControlListener(listener); + listener.controlResized(null /* event not used */); + + // Add a selection listener that will check/uncheck items when they are double-clicked + mTable.addSelectionListener(new SelectionAdapter() { + /** Default selection means double-click on "most" platforms */ + @Override + public void widgetDefaultSelected(SelectionEvent e) { + if (e.item instanceof TableItem) { + TableItem i = (TableItem) e.item; + i.setChecked(!i.getChecked()); + } + super.widgetDefaultSelected(e); + } + }); + + Dialog.applyDialogFont(composite); + setHelpAvailable(false); + + return composite; + } + } +} |