/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.texteditor; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.ICellEditorListener; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.xmind.ui.viewers.MButton; /** * @author Frank Shaka * */ public abstract class MEmbeddedEditor { private Composite composite; private MButton button; private Composite editorWrap; private StackLayout stack; private ListenerList editorListeners = new ListenerList(); /** * */ public MEmbeddedEditor(Composite parent) { this(parent, MButton.NORMAL); hideEditor(); } /** * */ public MEmbeddedEditor(Composite parent, int buttonStyle) { createControl(parent, buttonStyle); hideEditor(); } private void createControl(Composite parent, int buttonStyle) { parent = createContainer(parent); composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getBackground()); stack = new StackLayout(); composite.setLayout(stack); createButton(composite, buttonStyle); createWrap(composite); } protected Composite createContainer(Composite parent) { return parent; } private void createButton(Composite parent, int buttonStyle) { button = new MButton(parent, buttonStyle); button.getControl().setBackground(parent.getBackground()); button.addOpenListener(new IOpenListener() { public void open(OpenEvent event) { startEditing(); } }); } private void createWrap(Composite parent) { editorWrap = new Composite(parent, SWT.NONE); editorWrap.setBackground(parent.getBackground()); GridLayout gridLayout = new GridLayout(1, false); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; gridLayout.verticalSpacing = 0; gridLayout.horizontalSpacing = 0; editorWrap.setLayout(gridLayout); createEditor(editorWrap); } protected abstract void createEditor(Composite parent); public Control getControl() { return composite; } /** * @return the button */ public MButton getButton() { return button; } public void startEditing() { showEditor(); setFocus(); } protected void showEditor() { stack.topControl = editorWrap; button.getControl().setVisible(false); editorWrap.setVisible(true); composite.layout(); editorWrap.layout(); } protected void hideEditor() { stack.topControl = button.getControl(); button.getControl().setVisible(true); editorWrap.setVisible(false); composite.layout(); editorWrap.layout(); } public void cancelEditing() { if (isEditing()) { fireCancelEditor(); } hideEditor(); } public void endEditing() { if (isEditing()) { fireApplyEditorValue(); } hideEditor(); } public boolean isEditing() { return stack.topControl == editorWrap; } public void setEnabled(boolean enabled) { button.setEnabled(enabled); } public void setFocus() { if (isEditing()) { setEditorFocus(); } else { button.getControl().setFocus(); } } protected abstract void setEditorFocus(); public void addEditorListener(ICellEditorListener listener) { editorListeners.add(listener); } public void removeEditorListener(ICellEditorListener listener) { editorListeners.remove(listener); } protected void fireApplyEditorValue() { Object[] listeners = editorListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { final ICellEditorListener l = (ICellEditorListener) listeners[i]; SafeRunner.run(new SafeRunnable() { public void run() throws Exception { l.applyEditorValue(); } }); } } protected void fireCancelEditor() { Object[] listeners = editorListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { final ICellEditorListener l = (ICellEditorListener) listeners[i]; SafeRunner.run(new SafeRunnable() { public void run() throws Exception { l.cancelEditor(); } }); } } protected void endEditingWhenFocusOut() { if (!isEditing() || editorWrap.isDisposed() || !hasFocus(editorWrap)) return; Display.getCurrent().timerExec(10, new Runnable() { public void run() { if (editorWrap.isDisposed()) return; if (!hasFocus(editorWrap)) { endEditing(); } } }); } private boolean hasFocus(Control control) { if (control.isFocusControl()) return true; if (control instanceof Composite) { Control[] children = ((Composite) control).getChildren(); for (int i = 0; i < children.length; i++) { Control child = children[i]; if (child.isFocusControl()) return true; if (child instanceof Composite && hasFocus((Composite) child)) return true; } } return false; } }