Java tutorial
/* * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * This component and the accompanying materials are made available * under the terms of the License "Eclipse Public License v1.0" * which accompanies this distribution, and is available * at the URL "http://www.eclipse.org/legal/epl-v10.html". * * Initial Contributors: * Nokia Corporation - initial contribution. * * Contributors: * * Description: * */ package com.nokia.carbide.cpp.internal.project.ui.editors.common; import com.nokia.cpp.internal.api.utils.core.Check; import com.nokia.cpp.internal.api.utils.core.ListenerList; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.resource.JFaceColors; import org.eclipse.jface.viewers.*; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import java.util.*; import java.util.List; /** * Base class of framework providing these services: * - populate control/viewer from data model (in subclasses that are model-aware) * - respond to control/viewer events by creating undoable operations (in subclasses that are model-aware) * - utilities for populating control/viewer values without triggering undo stack modifications * - validation that's simpler than SWT verify events * * The handler is attached to the control's data map. Given a Control the handler can * be retrieved view getHandlerForControl. Given a Viewe the handler can be retrieved via * getHandlerForViewer. */ public class ControlHandler { public interface IValidator { /** * Return null or OK status if control state is valid */ IStatus validate(Control control); } private final Control control; // optional viewer associated with the control private final StructuredViewer viewer; private final IValidator validator; private final Listener swtListener; private final boolean viewerCaseSensitive; // optional label associated with the control private Control label; private boolean updatingControl; private ICheckStateListener checkStateListener; private ListenerList<ControlHandlerListener> listeners = new ListenerList<ControlHandlerListener>(); private String listDelimiter = "\\ "; //$NON-NLS-1$ static final String DATA_KEY = ControlHandler.class.getPackage() + "." + ControlHandler.class.getName(); //$NON-NLS-1$ interface ControlHandlerListener { void valueModified(Control control); void controlSelected(Control control); void validationFailed(Control control, String message); void validationSucceeded(Control control); } public static class ControlHandlerAdapter implements ControlHandlerListener { public void valueModified(Control control) { } public void controlSelected(Control control) { } public void validationFailed(Control control, String message) { } public void validationSucceeded(Control control) { } } public ControlHandler(Control control, IValidator validator) { this(control, null, validator, true); } /** * Initialize to use a structured view to interact with the control * @param viewer the viewer * @param caseSensitive true if when setting the value to match with case * insensitive comparisons */ public ControlHandler(StructuredViewer viewer, boolean caseSensitive) { this(viewer.getControl(), viewer, null, caseSensitive); } protected ControlHandler(final Control control, final StructuredViewer viewer, IValidator validator, boolean caseSensitive) { Check.checkState(getHandlerForControl(control) == null); this.control = control; this.viewer = viewer; this.validator = validator; this.viewerCaseSensitive = caseSensitive; swtListener = new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.Modify: if (!updatingControl) { textModified(); } break; case SWT.Selection: if (!updatingControl) { controlSelected(); } break; case SWT.Dispose: control.setData(DATA_KEY, null); break; case SWT.FocusIn: controlFocused(); break; } } }; control.addListener(SWT.Modify, swtListener); control.addListener(SWT.Selection, swtListener); control.addListener(SWT.Dispose, swtListener); control.addListener(SWT.FocusIn, swtListener); if (viewer instanceof ICheckable) { checkStateListener = new ICheckStateListener() { public void checkStateChanged(CheckStateChangedEvent event) { ControlHandler.this.checkStateChanged(event.getElement(), event.getChecked()); } }; ICheckable checkable = (ICheckable) viewer; checkable.addCheckStateListener(checkStateListener); } control.setData(DATA_KEY, this); Check.checkState(getHandlerForControl(control) == this); } public Control getControl() { return control; } public StructuredViewer getViewer() { return viewer; } public void setLabel(Control label) { this.label = label; } public Control getLabel() { return label; } public static ControlHandler getHandlerForControl(Control control) { ControlHandler result = null; if (control != null) { Object obj = control.getData(DATA_KEY); if (obj instanceof ControlHandler) { result = (ControlHandler) obj; } } return result; } public static ControlHandler getHandlerForViewer(StructuredViewer viewer) { return getHandlerForControl(viewer.getControl()); } protected void textModified() { fireTextModified(); validate(); } protected void controlSelected() { fireControlSelected(); } protected void controlFocused() { validate(); } /** * Utility to pull the text of of various kinds of Control. */ public static String getControlText(Control control) { String result = null; Object value = getControlValue(control); if (value instanceof List) { ControlHandler handler = getHandlerForControl(control); if (handler != null) { result = handler.listToText((List) value); } } else if (value != null) { result = value.toString(); } return result; } public static Object getControlValue(Control control) { Object result = null; ControlHandler handler = getHandlerForControl(control); if (handler != null && handler.viewer != null) { ISelection selection = handler.viewer.getSelection(); if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; List list = ss.toList(); if (list.size() == 1) { result = list.get(0); } else { result = list; } } } else if (control instanceof Text) { result = ((Text) control).getText(); } else if (control instanceof Combo) { result = ((Combo) control).getText(); } else if (control instanceof Button) { result = ((Button) control).getSelection(); } return result; } /** * Match the incoming string to the casing in the viewer data */ private static String matchViewerStringCase(StructuredViewer viewer, String value) { String result = value; IContentProvider contentProvider = viewer.getContentProvider(); if (contentProvider instanceof IStructuredContentProvider) { IStructuredContentProvider scp = (IStructuredContentProvider) contentProvider; Object[] elements = scp.getElements(viewer.getInput()); for (Object element : elements) { String strElement = element.toString(); if (value.equalsIgnoreCase(strElement)) { result = strElement; break; } } } return result; } /** * Utility to set the text in various kinds of Control */ public static void setControlText(Control control, String value) { if (value == null) value = ""; //$NON-NLS-1$ ControlHandler handler = getHandlerForControl(control); if (handler != null && handler.viewer != null) { if (!handler.viewerCaseSensitive) { value = matchViewerStringCase(handler.viewer, value); } IStructuredSelection ss = new StructuredSelection(value); handler.viewer.setSelection(ss, true); } else if (control instanceof Text) { Text t = (Text) control; t.setText(value); } else if (control instanceof Combo) { Combo c = (Combo) control; c.setText(value); } } public IStatus validate() { IStatus result = Status.OK_STATUS; if (validator != null) { result = validator.validate(control); if (result == null || result.isOK()) { clearLabelModifications(); // this is needed so UI can clear out error indications fireValidationSucceeded(); } else { if (label != null) { label.setForeground(JFaceColors.getErrorText(control.getDisplay())); } fireValidationFailed(result.getMessage()); } } return result; } public void clearLabelModifications() { if (label != null) { label.setForeground(null); } } protected void whileUpdatingControl(Runnable r) { boolean savedUpdating = updatingControl; updatingControl = true; try { r.run(); } finally { updatingControl = savedUpdating; } } /** * Set the control's text without modifying the operation stack * @param value */ public void storeText(final String value) { whileUpdatingControl(new Runnable() { public void run() { setControlText(control, value); validate(); } }); } public void setValue(Object valueParam) { final Object value = valueParam != null ? valueParam : ""; //$NON-NLS-1$ whileUpdatingControl(new Runnable() { public void run() { if (viewer != null) { if (value instanceof List) { IStructuredSelection ss = new StructuredSelection((List) value); viewer.setSelection(ss, true); } else if (value instanceof Object[]) { IStructuredSelection ss = new StructuredSelection((Object[]) value); viewer.setSelection(ss, true); } else { IStructuredSelection ss = new StructuredSelection(value); viewer.setSelection(ss, true); } } else { if (control instanceof Button) { Button btn = (Button) control; btn.setSelection(Boolean.valueOf(value.toString())); } else { if (value instanceof List) { setControlText(control, listToText((List) value)); } else { setControlText(control, value.toString()); } } } validate(); } }); } /** * Hook to translate viewer element objects to underlying model * objects. Default version returns the input umodified */ public List<Object> viewerToModelElements(List<Object> elements) { return elements; } /** * Hook to translate model objects to viewer objects. Default * version returns the input unmodified */ public List<Object> modelToViewerElements(List<Object> elements) { return elements; } /** * Set the input on a viewer without modifying the operation stack */ public void setViewerInput(final Object input) { Check.checkState(viewer != null); whileUpdatingControl(new Runnable() { public void run() { viewer.setInput(input); validate(); } }); } protected void checkStateChanged(Object element, boolean checked) { } public void addListItems(List items) { boolean savedUpdating = updatingControl; updatingControl = true; try { if (viewer != null) { refresh(); } else { StringBuffer buf = new StringBuffer(getControlText(control)); if (buf.length() > 0) { buf.append(listDelimiter); } buf.append(listToText(items)); storeText(buf.toString()); } } finally { updatingControl = savedUpdating; } } /** * Do anything needed to update the control from the model. */ public void refresh() { boolean savedUpdating = updatingControl; updatingControl = true; try { clearLabelModifications(); doRefresh(); } finally { updatingControl = savedUpdating; } } /** * Subclasses that cannot relying on simple Viewer refreshing * must override this to populate the control value. */ protected void doRefresh() { if (viewer != null) { viewer.refresh(); } } public void setListDelimiter(String delimiter) { this.listDelimiter = delimiter; } public void removeListItems(List items) { boolean savedUpdating = updatingControl; updatingControl = true; try { if (viewer != null) { refresh(); } else { String[] strings = splitText(); ArrayList<String> list = new ArrayList<String>(); for (String str : strings) { list.add(str); } list.removeAll(items); storeText(listToText(list)); } } finally { updatingControl = savedUpdating; } } public String[] splitText() { String text = getControlText(control); String[] strings = text.split(listDelimiter); return strings; } public String listToText(List items) { StringBuffer result = new StringBuffer(); if (items != null) { for (Object object : items) { if (result.length() > 0) { result.append(listDelimiter); } result.append(object); } } return result.toString(); } public void addListener(ControlHandlerListener l) { listeners.add(l); } public void removeListener(ControlHandlerListener l) { listeners.remove(l); } protected void fireTextModified() { for (ControlHandlerListener l : listeners) { l.valueModified(control); } } protected void fireControlSelected() { for (ControlHandlerListener l : listeners) { l.controlSelected(control); } } protected void fireValidationFailed(String message) { for (ControlHandlerListener l : listeners) { l.validationFailed(control, message); } } protected void fireValidationSucceeded() { for (ControlHandlerListener l : listeners) { l.validationSucceeded(control); } } }