| /* |
| * 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; |
| } |
| } |
| } |