/*******************************************************************************
* Copyright (c) 2010 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.ui.widget.editor;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.GC;
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.jboss.tools.common.ui.CommonUIMessages;
/**
* This editor allows to add to a list several items by 'Add' button.
* If ListFieldEditorProvider is not set, selection dialog will have nothing to pick up.
*
* @author Viacheslav Kabanovich
*/
public class BaseListFieldEditor extends BaseFieldEditor {
private ListViewer viewer = null;
private ActionPanel actionPanel;
public BaseListFieldEditor(String name, String label, Object defaultValue) {
super(name, label, defaultValue);
}
@Override
public Object[] getEditorControls(Object composite) {
Composite root = (Composite)composite;
createLabelControl(root);
createListView(root);
createActionBar(root);
return new Control[] {getLabelControl(), viewer.getControl(), actionPanel};
}
@SuppressWarnings("unchecked")
protected void createListView(Composite parent) {
viewer = new ListViewer(parent, SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
viewer.setContentProvider(new IStructuredContentProvider() {
public Object[] getElements(Object inputElement) {
return (inputElement instanceof List) ? ((List<Object>) inputElement).toArray() : new Object[0];
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
viewer.refresh();
}
});
viewer.setLabelProvider(createLabelProvider());
viewer.setInput(getValue());
}
protected ILabelProvider createLabelProvider() {
return new LabelProvider();
}
protected void createActionBar(Composite parent) {
actionPanel = new ActionPanel(parent, new BaseAction[] { new AddAction(),
new RemoveAction() });
viewer.addSelectionChangedListener(actionPanel);
}
@Override
public Object[] getEditorControls() {
return new Control[]{getLabelControl(), viewer.getControl(), actionPanel};//new Control[] { root };
}
@Override
public int getNumberOfControls() {
return 3;
}
@Override
public void doFillIntoGrid(Object parent) {
Assert.isTrue(parent instanceof Composite,
"Error_Basic_Editor_Composite");
Assert.isTrue(((Composite) parent).getLayout() instanceof GridLayout,
"Error_JBoss_Basic_Editor_Support");
Composite aComposite = (Composite) parent;
getEditorControls(aComposite);
GridLayout gl = (GridLayout) ((Composite) parent).getLayout();
GridData gdLabel = new GridData();
gdLabel.horizontalSpan = 1;
getLabelControl().setLayoutData(gdLabel);
GridData gd = new GridData();
gd.horizontalSpan = gl.numColumns - 2;
gd.grabExcessHorizontalSpace = true;
gd.horizontalAlignment = GridData.FILL;
gd.verticalAlignment = GridData.FILL;
((Control) getEditorControls()[1]).setLayoutData(gd);
GridData dgAction = new GridData();
dgAction.horizontalSpan = 1;
dgAction.verticalAlignment = GridData.FILL;
((Control) getEditorControls()[2]).setLayoutData(dgAction);
}
protected int convertHorizontalDLUsToPixels(Control control, int dlus) {
GC gc= new GC(control);
gc.setFont(control.getFont());
int averageWidth= gc.getFontMetrics().getAverageCharWidth();
gc.dispose();
double horizontalDialogUnitSize = averageWidth * 0.25;
return (int)Math.round(dlus * horizontalDialogUnitSize);
}
public class ActionPanel extends Composite implements ISelectionChangedListener {
private BaseAction[] actions = null;
public ActionPanel(Composite parent, int style, BaseAction[] actions) {
super(parent, style);
this.actions = actions;
setLayout(new GridLayout(1, false));
for (BaseAction action : this.actions) {
new ActionButton(this, SWT.PUSH, action);
}
}
public ActionPanel(Composite parent, BaseAction[] actions) {
this(parent, SWT.NONE, actions);
}
public void selectionChanged(SelectionChangedEvent event) {
for (BaseAction action : actions) {
action.setSelection(event.getSelection());
}
}
}
public class ActionButton implements IPropertyChangeListener {
private Button button;
private BaseAction action;
public ActionButton(Composite parent, int style, BaseAction action) {
this.button = new Button(parent, style);
this.action = action;
GridData gd = new GridData(GridData.FILL_HORIZONTAL, GridData.BEGINNING, false, false);
gd.horizontalAlignment = GridData.FILL;
gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
gd.widthHint = convertHorizontalDLUsToPixels(button, IDialogConstants.BUTTON_WIDTH);
this.button.setLayoutData(gd);
this.action.addPropertyChangeListener(this);
this.button.setText(action.getText());
this.button.setEnabled(action.isEnabled());
this.button.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
ActionButton.this.action.run();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
public Control getControl() {
return button;
}
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(IAction.ENABLED)) {
button.setEnabled(((Boolean) event.getNewValue())
.booleanValue());
}
}
}
public static abstract class BaseAction extends Action {
Object[] objects = new Object[0];
public BaseAction(String name) {
super(name);
updateEnablement();
}
public void setSelection(ISelection selection) {
if (selection instanceof IStructuredSelection) {
List<Object> rts = new ArrayList<Object>();
for (Object rt : ((IStructuredSelection) selection).toArray()) {
rts.add(rt);
}
objects = rts.toArray(new Object[] {});
} else {
objects = new Object[0];
}
updateEnablement();
}
protected abstract void updateEnablement();
}
public class AddAction extends BaseAction {
public AddAction() {
super(CommonUIMessages.BUTTON_ADD);
setEnabled(true);
}
@Override
protected void updateEnablement() {
}
@Override
public void run() {
List<?> current = (List<?>)getValue();
List<Object> added = runAddAction();
added.removeAll(current);
if(!added.isEmpty()) {
added.addAll(current);
setValue(added);
viewer.setInput(getValue());
viewer.refresh();
}
}
}
/**
* Returns list of objects to be added.
* @return
*/
protected List<Object> runAddAction() {
return new ArrayList<Object>();
}
public class RemoveAction extends BaseAction {
public RemoveAction() {
super(CommonUIMessages.BUTTON_REMOVE);
}
@Override
protected void updateEnablement() {
setEnabled(objects.length > 0);
}
@Override
public void run() {
List<?> current = (List<?>)getValue();
List<Object> changed = new ArrayList<Object>();
changed.addAll(current);
for (Object rt : objects) {
changed.remove(rt);
}
objects = new Object[0];
if(changed.size() != current.size()) {
setValue(changed);
}
viewer.setInput(getValue());
viewer.refresh();
updateEnablement();
}
}
}