/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.ext.erd.part;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.*;
import org.eclipse.gef.commands.CommandStackListener;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Control;
import org.jkiss.dbeaver.ext.erd.ERDActivator;
import org.jkiss.dbeaver.ext.erd.ERDConstants;
import org.jkiss.dbeaver.ext.erd.ERDMessages;
import org.jkiss.dbeaver.ext.erd.figures.EntityDiagramFigure;
import org.jkiss.dbeaver.ext.erd.layout.DelegatingLayoutManager;
import org.jkiss.dbeaver.ext.erd.layout.GraphAnimation;
import org.jkiss.dbeaver.ext.erd.layout.GraphLayoutAuto;
import org.jkiss.dbeaver.ext.erd.model.ERDEntity;
import org.jkiss.dbeaver.ext.erd.model.ERDNote;
import org.jkiss.dbeaver.ext.erd.model.EntityDiagram;
import org.jkiss.dbeaver.ext.erd.policy.DiagramContainerEditPolicy;
import org.jkiss.dbeaver.ui.UIUtils;
import java.beans.PropertyChangeEvent;
import java.util.EventObject;
import java.util.Iterator;
import java.util.List;
/**
* Edit part for Schema object, and uses a SchemaDiagram figure as
* the container for all graphical objects
*
* @author Serge Rider
*/
public class DiagramPart extends PropertyAwarePart {
CommandStackListener stackListener = new CommandStackListener() {
@Override
public void commandStackChanged(EventObject event)
{
if (delegatingLayoutManager.getActiveLayoutManager() instanceof GraphLayoutAuto) {
if (!GraphAnimation.captureLayout(getFigure())) {
return;
}
while (GraphAnimation.step())
getFigure().getUpdateManager().performUpdate();
GraphAnimation.end();
} else {
getFigure().getUpdateManager().performUpdate();
}
}
};
private DelegatingLayoutManager delegatingLayoutManager;
private Font normalFont, boldFont, italicFont, boldItalicFont;
/**
* Adds this EditPart as a command stack listener, which can be used to call
* performUpdate() when it changes
*/
@Override
public void activate()
{
super.activate();
getViewer().getEditDomain().getCommandStack().addCommandStackListener(stackListener);
}
/**
* Removes this EditPart as a command stack listener
*/
@Override
public void deactivate()
{
resetFonts();
getViewer().getEditDomain().getCommandStack().removeCommandStackListener(stackListener);
super.deactivate();
}
public void resetFonts()
{
UIUtils.dispose(boldFont);
UIUtils.dispose(italicFont);
UIUtils.dispose(boldItalicFont);
normalFont = null;
boldFont = null;
italicFont = null;
boldItalicFont = null;
}
@Override
protected IFigure createFigure()
{
Figure figure = new EntityDiagramFigure();
delegatingLayoutManager = new DelegatingLayoutManager(this);
figure.setLayoutManager(delegatingLayoutManager);
/*
ConnectionLayer cLayer = (ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER);
ViewportAwareConnectionLayerClippingStrategy clippingStrategy = new ViewportAwareConnectionLayerClippingStrategy(cLayer);
figure.setClippingStrategy(clippingStrategy);
*/
Control control = getViewer().getControl();
ConnectionLayer cLayer = (ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER);
if ((control.getStyle() & SWT.MIRRORED) == 0) {
cLayer.setAntialias(SWT.ON);
}
FanRouter router = new FanRouter();
router.setSeparation(15);
//router.setNextRouter(new BendpointConnectionRouter());
router.setNextRouter(new ShortestPathConnectionRouter(figure));
//router.setNextRouter(new ManhattanConnectionRouter());
//router.setNextRouter(new BendpointConnectionRouter());
cLayer.setConnectionRouter(router);
return figure;
}
public EntityDiagram getDiagram()
{
return (EntityDiagram) getModel();
}
public Font getNormalFont()
{
if (normalFont == null) {
normalFont = getViewer().getControl().getFont();
}
return normalFont;
}
public Font getBoldFont()
{
if (boldFont == null) {
boldFont = UIUtils.makeBoldFont(getNormalFont());
}
return boldFont;
}
public Font getItalicFont()
{
if (italicFont == null) {
italicFont = UIUtils.modifyFont(getNormalFont(), SWT.ITALIC);
}
return italicFont;
}
public Font getBoldItalicFont()
{
if (boldItalicFont == null) {
boldItalicFont = UIUtils.modifyFont(getNormalFont(), SWT.BOLD | SWT.ITALIC);
}
return boldItalicFont;
}
public void rearrangeDiagram()
{
//delegatingLayoutManager.set
delegatingLayoutManager.rearrange(getFigure());
//getFigure().setLayoutManager(delegatingLayoutManager);
//getFigure().getLayoutManager().layout(getFigure());
getFigure().repaint();
}
/**
* @return the children Model objects as a new ArrayList
*/
@Override
protected List<?> getModelChildren()
{
return getDiagram().getContents();
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#isSelectable()
*/
@Override
public boolean isSelectable()
{
return false;
}
/**
* Creates EditPolicy objects for the EditPart. The LAYOUT_ROLE policy is
* left to the delegating layout manager
*/
@Override
protected void createEditPolicies()
{
installEditPolicy(EditPolicy.CONTAINER_ROLE, new DiagramContainerEditPolicy());
installEditPolicy(EditPolicy.LAYOUT_ROLE, null);
}
/**
* Updates the table bounds in the model so that the same bounds can be
* restored after saving
*
* @return whether the procedure execute successfully without any omissions.
* The latter occurs if any EntityFigure has no bounds set for any of
* the Table model objects
*/
public boolean setTableModelBounds()
{
List<?> entityParts = getChildren();
for (Iterator<?> iter = entityParts.iterator(); iter.hasNext();) {
NodePart entityPart = (NodePart) iter.next();
IFigure entityFigure = entityPart.getFigure();
//if we don't find a node for one of the children then we should
// continue
if (entityFigure == null) {
continue;
}
Rectangle bounds = entityFigure.getBounds().getCopy();
entityPart.setBounds(bounds);
}
return true;
}
/**
* Updates the bounds of the table figure (without invoking any event
* handling), and sets layout constraint data
*
* @return whether the procedure execute successfully without any omissions.
* The latter occurs if any Table objects have no bounds set or if
* no figure is available for the EntityPart
*/
public boolean setTableFigureBounds(boolean updateConstraint)
{
List<?> tableParts = getChildren();
for (Iterator<?> iter = tableParts.iterator(); iter.hasNext();) {
NodePart entityPart = (NodePart) iter.next();
//now check whether we can find an entry in the tableToNodesMap
Rectangle bounds = entityPart.getBounds();
if (bounds == null) {
//TODO handle this better
return false;
} else {
IFigure entityFigure = entityPart.getFigure();
if (entityFigure == null) {
return false;
} else {
if (updateConstraint) {
//pass the constraint information to the xy layout
//setting the width and height so that the preferred size will be applied
delegatingLayoutManager.setXYLayoutConstraint(entityFigure, new Rectangle(bounds.x, bounds.y, -1, -1));
}
}
}
}
return true;
}
public void changeLayout()
{
//Boolean layoutType = (Boolean) evt.getNewValue();
//boolean isManualLayoutDesired = layoutType.booleanValue();
getFigure().setLayoutManager(delegatingLayoutManager);
}
/**
* Passes on to the delegating layout manager that the layout type has
* changed. The delegating layout manager will then decide whether to
* delegate layout to the XY or Graph layout
*/
/**
* Sets layout constraint only if XYLayout is active
*/
@Override
public void setLayoutConstraint(EditPart child, IFigure childFigure, Object constraint)
{
super.setLayoutConstraint(child, childFigure, constraint);
}
/**
* Passes on to the delegating layout manager that the layout type has
* changed. The delegating layout manager will then decide whether to
* delegate layout to the XY or Graph layout
*/
@Override
protected void handleChildChange(PropertyChangeEvent evt)
{
super.handleChildChange(evt);
}
@Override
public Object getAdapter(Class key)
{
if (key == SnapToHelper.class) {
final IPreferenceStore store = ERDActivator.getDefault().getPreferenceStore();
if (store.getBoolean(ERDConstants.PREF_GRID_ENABLED) && store.getBoolean(ERDConstants.PREF_GRID_SNAP_ENABLED)) {
return new SnapToGrid(this);
} else {
return null;
}
}
return super.getAdapter(key);
}
public EntityPart getEntityPart(ERDEntity erdEntity)
{
for (Object child : getChildren()) {
if (child instanceof EntityPart && ((EntityPart) child).getTable() == erdEntity) {
return (EntityPart) child;
}
}
return null;
}
public NotePart getNotePart(ERDNote erdNote)
{
for (Object child : getChildren()) {
if (child instanceof NotePart && ((NotePart) child).getNote() == erdNote) {
return (NotePart) child;
}
}
return null;
}
@Override
public String toString()
{
return ERDMessages.entity_diagram_ + getDiagram().getName();
}
}