/******************************************************************************
* Copyright (c) 2014 Oracle
* 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:
* Ling Hao - initial implementation and ongoing maintenance
******************************************************************************/
package org.eclipse.sapphire.ui.swt.gef.parts;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.editparts.ZoomListener;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.requests.DirectEditRequest;
import org.eclipse.gef.tools.CellEditorLocator;
import org.eclipse.gef.tools.DirectEditManager;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.sapphire.Value;
import org.eclipse.sapphire.ui.diagram.editor.FunctionUtil;
import org.eclipse.sapphire.ui.diagram.editor.TextPart;
import org.eclipse.sapphire.ui.swt.gef.SapphireDiagramEditor;
import org.eclipse.sapphire.ui.swt.gef.figures.TextFigure;
import org.eclipse.sapphire.ui.swt.gef.model.ShapeModelUtil;
import org.eclipse.sapphire.ui.swt.gef.presentation.ShapePresentation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.CellEditorActionHandler;
/**
* @author <a href="mailto:ling.hao@oracle.com">Ling Hao</a>
* @author <a href="mailto:shenxue.zhou@oracle.com">Shenxue Zhou</a>
*/
public class NodeDirectEditManager extends DirectEditManager {
private IActionBars actionBars;
private CellEditorActionHandler actionHandler;
private IAction copy, cut, paste, undo, redo, find, selectAll, delete;
private double cachedZoom = -1.0;
private Font scaledFont;
private ZoomListener zoomListener = new ZoomListener() {
public void zoomChanged(double newZoom) {
updateScaledFont(newZoom);
}
};
private Label label;
protected SapphireDiagramEditor diagramEditor;
protected TextPart textPart;
protected Value<?> property;
protected IFigure textFigure;
protected IFigure parentFigure;
private String initValue;
private boolean committed = false;
public NodeDirectEditManager(GraphicalEditPart source, TextPart textPart, CellEditorLocator locator, Label label) {
super(source, null, locator);
this.textPart = textPart;
this.label = label;
ShapeEditPart shapeEditPart = (ShapeEditPart)source;
DiagramNodeEditPart nodeEditPart = shapeEditPart.getNodeEditPart();
ShapePresentation shapePresentation = ShapeModelUtil.getChildShapePresentation(
nodeEditPart.getCastedModel().getShapePresentation(), textPart);
this.textFigure = shapePresentation.getFigure();
this.parentFigure = shapePresentation.getParentFigure();
this.diagramEditor = ((ShapeEditPart)source).getConfigurationManager().getDiagramEditor();
this.property = FunctionUtil.getFunctionProperty(this.textPart.getLocalModelElement(),
this.textPart.getContentFunction());
}
/**
* @see org.eclipse.gef.tools.DirectEditManager#bringDown()
*/
protected void bringDown() {
if (!committed && isDirty()) {
if (getCellEditor() instanceof TextCellEditor) {
Text text = (Text) getCellEditor().getControl();
text.setText(initValue);
internalCommit();
}
}
this.diagramEditor.setDirectEditingActive(false);
ZoomManager zoomMgr = (ZoomManager) this.diagramEditor.getGraphicalViewer()
.getProperty(ZoomManager.class.toString());
if (zoomMgr != null)
zoomMgr.removeZoomListener(zoomListener);
if (actionHandler != null) {
actionHandler.dispose();
actionHandler = null;
}
if (actionBars != null) {
restoreSavedActions(actionBars);
actionBars.updateActionBars();
actionBars = null;
}
super.bringDown();
// dispose any scaled fonts that might have been created
disposeScaledFont();
label.setVisible(true);
}
@Override
public void show()
{
diagramEditor.setDirectEditingActive(true);
super.show();
}
@Override
protected CellEditor createCellEditorOn(Composite composite)
{
return new DiagramTextCellEditor(this.textPart, composite, SWT.CENTER);
}
private void disposeScaledFont() {
if (scaledFont != null) {
scaledFont.dispose();
scaledFont = null;
}
}
@Override
protected void initCellEditor() {
// update text
initValue = this.property.text();
if (initValue == null)
{
initValue = this.textPart.getContent();
}
getCellEditor().setValue(initValue);
initCellEditorPresentation();
}
@Override
protected DirectEditRequest createDirectEditRequest()
{
DirectEditRequest req = super.createDirectEditRequest();
Map<String, TextPart> extendedData = new HashMap<String, TextPart>();
extendedData.put(DiagramNodeEditPart.DIRECT_EDIT_REQUEST_PARAM, this.textPart);
req.setExtendedData(extendedData);
return req;
}
protected void initCellEditorPresentation()
{
// Shenxue: set text to "" doesn't work since it messes the size calculation in parent's
// layout manager. It'd shrink the label figure size to 0. Use figure's visibility instead.
//label.setText("");
label.setVisible(false);
// update font
ZoomManager zoomMgr = (ZoomManager) getEditPart().getViewer()
.getProperty(ZoomManager.class.toString());
if (zoomMgr != null) {
// this will force the font to be set
cachedZoom = -1.0;
updateScaledFont(zoomMgr.getZoom());
zoomMgr.addZoomListener(zoomListener);
} else
getCellEditor().getControl().setFont(label.getFont());
// Hook the cell editor's copy/paste actions to the actionBars so that
// they can
// be invoked via keyboard shortcuts.
actionBars = this.diagramEditor.getEditorSite().getActionBars();
saveCurrentActions(actionBars);
actionHandler = new CellEditorActionHandler(actionBars);
actionHandler.addCellEditor(getCellEditor());
actionBars.updateActionBars();
}
@Override
protected void handleValueChanged()
{
internalCommit();
// TextPart's content might be a function with default values for empty String property.
// But we don't want the cell size to jump. So resetting TextFigure's content again to avoid
// cell size jump.
String cellText = (String)getCellEditor().getValue();
if (cellText == null || cellText.isEmpty())
{
((TextFigure)textFigure).setText(" ");
}
// In Kepler when the cell editor is brought up and the focus is set on the text, the text
// triggers a focus lost event which causes direct edit manager's bringDown() method to be called.
// The overridden bringDown() method would set the label to be visible again. Resetting the label's
// visibility here is a workaround.
label.setVisible(false);
super.handleValueChanged();
}
@Override
protected void commit()
{
this.committed = true;
super.commit();
((TextFigure)textFigure).setText(textPart.getContent());
}
public TextPart getTextPart()
{
return this.textPart;
}
private void internalCommit()
{
CommandStack stack = getEditPart().getViewer().getEditDomain()
.getCommandStack();
stack.execute(getEditPart().getCommand(getDirectEditRequest()));
}
private void restoreSavedActions(IActionBars actionBars) {
actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), copy);
actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), paste);
actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), delete);
actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(),
selectAll);
actionBars.setGlobalActionHandler(ActionFactory.CUT.getId(), cut);
actionBars.setGlobalActionHandler(ActionFactory.FIND.getId(), find);
actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), undo);
actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), redo);
}
private void saveCurrentActions(IActionBars actionBars) {
copy = actionBars.getGlobalActionHandler(ActionFactory.COPY.getId());
paste = actionBars.getGlobalActionHandler(ActionFactory.PASTE.getId());
delete = actionBars
.getGlobalActionHandler(ActionFactory.DELETE.getId());
selectAll = actionBars.getGlobalActionHandler(ActionFactory.SELECT_ALL
.getId());
cut = actionBars.getGlobalActionHandler(ActionFactory.CUT.getId());
find = actionBars.getGlobalActionHandler(ActionFactory.FIND.getId());
undo = actionBars.getGlobalActionHandler(ActionFactory.UNDO.getId());
redo = actionBars.getGlobalActionHandler(ActionFactory.REDO.getId());
}
private void updateScaledFont(double zoom) {
if (cachedZoom == zoom || getCellEditor() == null)
return;
Font font = this.label.getFont();
disposeScaledFont();
cachedZoom = zoom;
if (zoom == 1.0) {
getCellEditor().getControl().setFont(font);
}
else {
FontData fd = font.getFontData()[0];
fd.setHeight((int) (fd.getHeight() * zoom));
this.scaledFont = new Font(null, fd);
getCellEditor().getControl().setFont(this.scaledFont);
}
}
}