/******************************************************************************* * Copyright (c) 2011 Tasktop Technologies and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Tasktop Technologies - initial API and implementation * Pawel Niewiadomski - fix for bug 287832 *******************************************************************************/ package org.eclipse.mylyn.internal.tasks.ui.editors; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.window.Window; import org.eclipse.mylyn.commons.ui.dialogs.AbstractInPlaceDialog; import org.eclipse.mylyn.commons.ui.dialogs.IInPlaceDialogListener; import org.eclipse.mylyn.commons.ui.dialogs.InPlaceDialogEvent; import org.eclipse.mylyn.commons.workbench.InPlaceCheckBoxTreeDialog; import org.eclipse.mylyn.commons.workbench.WorkbenchUtil; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskDataModel; import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor; import org.eclipse.mylyn.tasks.ui.editors.LayoutHint; import org.eclipse.mylyn.tasks.ui.editors.LayoutHint.ColumnSpan; import org.eclipse.mylyn.tasks.ui.editors.LayoutHint.RowSpan; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.forms.widgets.SharedScrolledComposite; /** * @author Shawn Minto * @author Sam Davis */ public class CheckboxMultiSelectAttributeEditor extends AbstractAttributeEditor { private Text valueText; private Composite parent; private Button button; private boolean suppressRefresh; public CheckboxMultiSelectAttributeEditor(TaskDataModel manager, TaskAttribute taskAttribute) { super(manager, taskAttribute); setLayoutHint(new LayoutHint(RowSpan.SINGLE, ColumnSpan.MULTIPLE)); } @Override public void createControl(Composite parent, FormToolkit toolkit) { if (isReadOnly()) { valueText = new Text(parent, SWT.FLAT | SWT.READ_ONLY | SWT.WRAP); valueText.setFont(EditorUtil.TEXT_FONT); toolkit.adapt(valueText, false, false); valueText.setData(FormToolkit.KEY_DRAW_BORDER, Boolean.FALSE); valueText.setToolTipText(getDescription()); refresh(); setControl(valueText); } else { this.parent = parent; Composite composite = toolkit.createComposite(parent); composite.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); GridLayout layout = new GridLayout(2, false); layout.marginWidth = 0; layout.marginBottom = 0; layout.marginLeft = 0; layout.marginRight = 0; layout.marginTop = 0; layout.marginHeight = 0; composite.setLayout(layout); valueText = toolkit.createText(composite, "", SWT.FLAT | SWT.WRAP); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).applyTo(valueText); valueText.setFont(EditorUtil.TEXT_FONT); valueText.setEditable(false); valueText.setToolTipText(getDescription()); button = toolkit.createButton(composite, "", SWT.ARROW | SWT.DOWN); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.TOP).applyTo(button); button.addSelectionListener(createSelectionListener()); toolkit.adapt(valueText, false, false); refresh(); setControl(composite); } } protected SelectionListener createSelectionListener() { return new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { final List<String> values = getValueList(); final InPlaceCheckBoxTreeDialog selectionDialog = createInPlaceCheckBoxTreeDialog(values); addEventListener(values, selectionDialog); selectionDialog.open(); } }; } protected List<String> getValueList() { final List<String> values = getValues(); return values; } protected InPlaceCheckBoxTreeDialog createInPlaceCheckBoxTreeDialog(List<String> values) { Map<String, String> validValues = getAttributeMapper().getOptions(getTaskAttribute()); final InPlaceCheckBoxTreeDialog selectionDialog = new InPlaceCheckBoxTreeDialog(WorkbenchUtil.getShell(), button, values, validValues, NLS.bind(Messages.CheckboxMultiSelectAttributeEditor_Select_X, getLabel())); return selectionDialog; } private void addEventListener(final List<String> values, final InPlaceCheckBoxTreeDialog selectionDialog) { selectionDialog.addEventListener(new IInPlaceDialogListener() { public void buttonPressed(InPlaceDialogEvent event) { suppressRefresh = true; try { if (event.getReturnCode() == Window.OK) { Set<String> newValues = selectionDialog.getSelectedValues(); if (!new HashSet<String>(values).equals(newValues)) { setValues(new ArrayList<String>(newValues)); refresh(); } } else if (event.getReturnCode() == AbstractInPlaceDialog.ID_CLEAR) { Set<String> newValues = new HashSet<String>(); if (!new HashSet<String>(values).equals(newValues)) { setValues(new ArrayList<String>(newValues)); refresh(); } } } finally { suppressRefresh = false; } } }); } /** * Update scroll bars of the enclosing form. * * @see Section#reflow() */ private void reflow() { Composite c = parent; while (c != null) { c.setRedraw(false); c = c.getParent(); if (c instanceof SharedScrolledComposite || c instanceof Shell) { break; } } c = parent; while (c != null) { c.layout(true); c = c.getParent(); if (c instanceof SharedScrolledComposite) { ((SharedScrolledComposite) c).reflow(true); break; } } c = parent; while (c != null) { c.setRedraw(true); c = c.getParent(); if (c instanceof SharedScrolledComposite || c instanceof Shell) { break; } } } public List<String> getValues() { return getAttributeMapper().getValues(getTaskAttribute()); } public List<String> getValuesLabels() { return getAttributeMapper().getValueLabels(getTaskAttribute()); } public void setValues(List<String> newValues) { getAttributeMapper().setValues(getTaskAttribute(), newValues); attributeChanged(); } @Override protected void decorateIncoming(Color color) { super.decorateIncoming(color); if (valueText != null && !valueText.isDisposed()) { valueText.setBackground(color); } if (button != null && !button.isDisposed()) { button.setBackground(color); } } @Override public void refresh() { if (valueText == null || valueText.isDisposed()) { return; } StringBuilder valueString = new StringBuilder(); List<String> values = getValuesLabels(); Collections.sort(values); for (int i = 0; i < values.size(); i++) { valueString.append(values.get(i)); if (i != values.size() - 1) { valueString.append(", "); //$NON-NLS-1$ } } valueText.setText(valueString.toString()); if (valueText != null && parent != null && parent.getParent() != null && parent.getParent().getParent() != null) { Point size = valueText.getSize(); // subtract 1 from size for border Point newSize = valueText.computeSize(size.x - 1, SWT.DEFAULT); if (newSize.y != size.y) { reflow(); } } } @Override public boolean shouldAutoRefresh() { return !suppressRefresh; } protected Button getButton() { return button; } }