/*******************************************************************************
* Copyright (c) 2010-2015 Henshin developers. 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:
* TU Berlin, University of Luxembourg, SES S.A.
*******************************************************************************/
package de.tub.tfs.muvitor.gef.directedit;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartListener;
import org.eclipse.gef.TreeEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.requests.DirectEditRequest;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellEditorListener;
import org.eclipse.jface.viewers.ICellEditorValidator;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.window.DefaultToolTip;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import de.tub.tfs.muvitor.gef.editparts.AdapterTreeEditPart;
import de.tub.tfs.muvitor.ui.utils.SWTResourceManager;
/**
* A helper class to perform a direct edit with a TextCellEditor on
* {@link IDirectEditPart}s that have a {@link MuvitorTreeDirectEditPolicy}
* installed. Adapted for {@link TreeEditPart}s from
* {@link MuvitorDirectEditManager}.
*
* @see AdapterTreeEditPart
*
* @author Tony Modica
*/
public class MuvitorTreeDirectEditManager {
private CellEditor cellEditor;
private ICellEditorListener cellEditorListener;
private boolean committing = false;
private EditPartListener editPartListener;
private DirectEditRequest request;
private final TreeEditPart source;
private org.eclipse.swt.custom.TreeEditor tableEditor;
private final ICellEditorValidator validator;
/**
* Is <code>true</code> if the cell editor's value has been changed.
*/
boolean dirty;
DefaultToolTip errorToolTip;
/**
* Constructs a new DirectEditManager for the given source edit part. A new
* TextCellEditor will be created and placed using the given
* CellEditorLocator.
*
* @param source
* The source edit part
*/
public MuvitorTreeDirectEditManager(final TreeEditPart source) {
Assert.isTrue(
source instanceof IDirectEditPart,
"MuvitorTreeDirectEditManager must not be installed on edit parts that do not implement IDirectEditPart!");
this.source = source;
validator = ((IDirectEditPart) source).getDirectEditValidator();
}
/**
* Shows the cell editor when direct edit is started.
*/
public void show() {
if (cellEditor != null) {
return;
}
final TreeItem treeItem = (TreeItem) source.getWidget();
final Composite composite = treeItem.getParent();
cellEditor = new TextCellEditor(composite) {
@Override
protected boolean isCorrect(final Object value) {
if (super.isCorrect(value)) {
// do not hide (possibly just create) errorToolTip if not
// necessary
if (errorToolTip != null) {
getErrorToolTip().hide();
}
text.setForeground(SWTResourceManager.getColor(0, 0, 0));
text.setToolTipText(getErrorMessage());
return true;
}
text.setForeground(SWTResourceManager.getColor(255, 0, 0));
getErrorToolTip().setText(getErrorMessage());
getErrorToolTip().show(
new Point(treeItem.getBounds().width, treeItem.getBounds().height));
return false;
}
};
hookListeners();
tableEditor = new org.eclipse.swt.custom.TreeEditor((Tree) composite);
final CellEditor.LayoutData layout = cellEditor.getLayoutData();
tableEditor.horizontalAlignment = layout.horizontalAlignment;
tableEditor.grabHorizontal = layout.grabHorizontal;
tableEditor.minimumWidth = layout.minimumWidth;
tableEditor.setEditor(cellEditor.getControl(), (TreeItem) source.getWidget(), 0);
cellEditor.setValidator(validator);
final EObject model = (EObject) source.getModel();
final int featureID = ((IDirectEditPart) source).getDirectEditFeatureID();
if (featureID > Integer.MIN_VALUE){
final EStructuralFeature feature = model.eClass().getEStructuralFeature(featureID);
// TODO Fehler wenn value noch nicht initianalisiert und = null
if (model.eGet(feature) != null) {
cellEditor.setValue(model.eGet(feature).toString());
} else {
cellEditor.setValue("");
}
cellEditor.activate();
cellEditor.setFocus();
} else {
unhookListeners();
if (cellEditor != null) {
cellEditor.setValidator(null);
cellEditor.deactivate();
cellEditor.dispose();
cellEditor = null;
}
if (tableEditor != null) {
if (tableEditor.getEditor() != null )
tableEditor.getEditor().dispose();
tableEditor.dispose();
tableEditor = null;
}
}
}
private DirectEditRequest getDirectEditRequest() {
if (request == null) {
request = new DirectEditRequest();
}
return request;
}
private void hookListeners() {
cellEditorListener = new ICellEditorListener() {
@Override
public void applyEditorValue() {
commit();
}
@Override
public void cancelEditor() {
bringDown();
}
@Override
public void editorValueChanged(final boolean old, final boolean newState) {
dirty = newState;
}
};
cellEditor.addListener(cellEditorListener);
editPartListener = new EditPartListener.Stub() {
@Override
public void selectedStateChanged(final EditPart editpart) {
if (editpart.getSelected() != 2) {
bringDown();
}
}
};
source.addEditPartListener(editPartListener);
}
/**
* Unhooks listeners. Called from {@link #bringDown()}.
*/
private void unhookListeners() {
source.removeEditPartListener(editPartListener);
editPartListener = null;
if (cellEditor != null) {
cellEditor.removeListener(cellEditorListener);
cellEditorListener = null;
}
}
/**
* Cleanup is done here. Any feedback is erased and listeners unhooked. If
* the cell editor is not <code>null</code>, it will be
* {@link CellEditor#deactivate() deativated}, {@link CellEditor#dispose()
* disposed}, and set to <code>null</code>.
*/
void bringDown() {
if (getErrorToolTip() != null){
getErrorToolTip().hide();
getErrorToolTip().deactivate();
}
unhookListeners();
if (cellEditor != null) {
cellEditor.setValidator(null);
cellEditor.deactivate();
cellEditor.dispose();
cellEditor = null;
}
if (tableEditor != null) {
tableEditor.getEditor().dispose();
tableEditor.dispose();
tableEditor = null;
}
request = null;
dirty = false;
}
/**
* Commits the current value of the cell editor by getting a {@link Command}
* from the source edit part and executing it via the {@link CommandStack}.
* Finally, {@link #bringDown()} is called to perform and necessary cleanup.
*/
void commit() {
if (committing) {
return;
}
committing = true;
try {
if (dirty) {
getDirectEditRequest().setDirectEditFeature(cellEditor.getValue());
final CommandStack stack = source.getViewer().getEditDomain().getCommandStack();
stack.execute(source.getCommand(getDirectEditRequest()));
}
} finally {
bringDown();
committing = false;
}
}
DefaultToolTip getErrorToolTip() {
if (cellEditor == null)
return null;
if (errorToolTip == null) {
errorToolTip = new DefaultToolTip(cellEditor.getControl(), ToolTip.RECREATE, true);
}
return errorToolTip;
}
}