/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.pms.ui;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.LineAttributes;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.pentaho.di.core.DescriptionInterface;
import org.pentaho.di.core.NotePadMeta;
import org.pentaho.di.core.dnd.DragAndDropContainer;
import org.pentaho.di.core.dnd.XMLTransfer;
import org.pentaho.di.core.gui.Point;
import org.pentaho.di.core.gui.Redrawable;
import org.pentaho.di.core.gui.SnapAllignDistribute;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.dialog.EnterTextDialog;
import org.pentaho.di.ui.core.dialog.ErrorDialog;
import org.pentaho.pms.ui.locale.Messages;
import org.pentaho.pms.schema.BusinessModel;
import org.pentaho.pms.schema.BusinessTable;
import org.pentaho.pms.schema.PhysicalTable;
import org.pentaho.pms.schema.RelationshipMeta;
import org.pentaho.pms.schema.concept.ConceptInterface;
import org.pentaho.pms.schema.concept.ConceptUtilityInterface;
import org.pentaho.pms.ui.concept.editor.Constants;
import org.pentaho.pms.ui.util.Const;
import org.pentaho.pms.ui.util.GUIResource;
public class MetaEditorGraph extends Canvas implements Redrawable {
private static final int HOP_SEL_MARGIN = 9;
private static final int RIGHT_HAND_SLOP = 20;
private Shell shell;
private MetaEditorGraph metaEditorGraph;
private LogChannelInterface log;
private int iconsize;
private int linewidth;
private Point lastclick;
private BusinessTable selected_items[];
private BusinessTable selected_icon;
private Point prev_locations[];
private NotePadMeta selected_note;
private RelationshipMeta candidate;
private Point drop_candidate;
private MetaEditor metaEditor;
private Point offset, iconoffset, noteoffset;
private ScrollBar hori;
private ScrollBar vert;
public boolean shift, control;
private int last_button;
private Rectangle selrect;
private PropsUI props;
private Menu mPop;
private static LineAttributes unknownRelationshipLineAttributes =
new LineAttributes(1.0f, SWT.CAP_FLAT, SWT.JOIN_MITER, SWT.LINE_CUSTOM, new float[] { 3.0f, 3.0f, }, 3.0f, 3.0f);
public MetaEditorGraph(Composite par, int style, MetaEditor pm) {
super(par, style);
shell = par.getShell();
log = new LogChannel(toString());
this.metaEditor = pm;
metaEditorGraph = this;
props = PropsUI.getInstance();
iconsize = props.getIconSize();
selrect = null;
candidate = null;
last_button = 0;
selected_items = null;
selected_note = null;
hori = getHorizontalBar();
vert = getVerticalBar();
hori.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
redraw();
}
});
vert.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
redraw();
}
});
hori.setThumb(100);
vert.setThumb(100);
hori.setVisible(true);
vert.setVisible(true);
setVisible(true);
newProps();
metaEditorGraph.setBackground(GUIResource.getInstance().getColorBackground());
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
MetaEditorGraph.this.paintControl(e);
}
});
selected_items = null;
lastclick = null;
addKeyListener(metaEditor.modKeys);
/*
* Handle the mouse...
*/
addMouseListener(new MouseAdapter() {
public void mouseDoubleClick(MouseEvent e) {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
if (activeModel == null)
return;
selected_items = null;
selected_icon = null;
selected_note = null;
candidate = null;
iconoffset = null;
selrect = null;
Point real = screen2real(e.x, e.y);
BusinessTable businessTable = activeModel.getTable(real.x, real.y, iconsize);
if (businessTable != null) {
if (e.button == 1)
editBusinessTable(activeModel, businessTable);
else
editDescription(businessTable.getConcept());
} else {
// Check if point lies on one of the many hop-lines...
RelationshipMeta online = findRelationship(real.x, real.y);
if (online != null) {
editRelationship(online);
} else {
NotePadMeta ni = activeModel.getNote(real.x, real.y);
if (ni != null) {
selected_note = null;
editNote(ni);
}
}
}
}
public void mouseDown(MouseEvent e) {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
if (activeModel == null)
return;
last_button = e.button;
selected_items = null;
selected_icon = null;
selected_note = null;
candidate = null;
iconoffset = null;
selrect = null;
Point real = screen2real(e.x, e.y);
// Clear the tooltip!
setToolTipText(null);
if (last_button == 3) {
createPopup(real.x, real.y);
}
// Did we click on a step?
BusinessTable ti = activeModel.getTable(real.x, real.y, iconsize);
if (ti != null) {
selected_items = activeModel.getSelectedTables();
selected_icon = ti;
// make sure this is correct!!!
// When an icon is moved that is not selected, it gets selected too late.
// It is not captured here, but in the mouseMoveListener...
prev_locations = activeModel.getSelectedLocations();
Point p = ti.getLocation();
iconoffset = new Point(real.x - p.x, real.y - p.y);
} else {
// Dit we hit a note?
NotePadMeta ni = activeModel.getNote(real.x, real.y);
if (ni != null && last_button == 1) {
selected_note = ni;
Point loc = ni.getLocation();
noteoffset = new Point(real.x - loc.x, real.y - loc.y);
} else {
if (!control)
selrect = new Rectangle(real.x, real.y, 0, 0);
}
}
lastclick = new Point(real.x, real.y);
redraw();
}
public void mouseUp(MouseEvent e) {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
if (activeModel == null)
return;
if (iconoffset == null)
iconoffset = new Point(0, 0);
Point real = screen2real(e.x, e.y);
// Quick new hop option? (drag from one step to another)
//
if (candidate != null) {
if (activeModel.findRelationship(candidate.getTableFrom().getId(), candidate.getTableTo().getId()) == null) {
activeModel.addRelationship(candidate);
metaEditor.synchronize(candidate);
//metaEditor.refreshTree();
}
candidate = null;
selected_items = null;
last_button = 0;
}
// Did we select a region on the screen? Mark steps in region as selected
//
else if (selrect != null) {
selrect.width = real.x - selrect.x;
selrect.height = real.y - selrect.y;
activeModel.unselectAll();
activeModel.selectInRect(selrect);
selrect = null;
}
// Clicked on an icon?
//
else if (selected_icon != null) {
if (e.button == 1) {
if (lastclick.x == e.x && lastclick.y == e.y) {
// Flip selection when control is pressed!
if (control) {
selected_icon.flipSelected();
} else {
// Otherwise, select only the icon clicked on!
activeModel.unselectAll();
selected_icon.setSelected(true);
}
} else // We moved around some items: store undo info...
if (selected_items != null && prev_locations != null) {
// int indexes[] = activeView.getTableIndexes(selected_items);
}
}
selected_items = null;
}
// Notes?
else if (selected_note != null) {
// Point note = new Point(real.x - noteoffset.x, real.y - noteoffset.y);
if (last_button == 1) {
if (lastclick.x != e.x || lastclick.y != e.y) {
// int indexes[] = new int[] { activeView.indexOfNote(selected_note) };
}
}
selected_note = null;
}
redraw();
}
});
addMouseMoveListener(new MouseMoveListener() {
public void mouseMove(MouseEvent e) {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
if (activeModel == null)
return;
if (iconoffset == null)
iconoffset = new Point(0, 0);
Point real = screen2real(e.x, e.y);
Point icon = new Point(real.x - iconoffset.x, real.y - iconoffset.y);
setToolTip(real.x, real.y);
// First see if the icon we clicked on was selected.
// If the icon was not selected, we should unselect all other icons,
// selected and move only the one icon
if (selected_icon != null && !selected_icon.isSelected()) {
activeModel.unselectAll();
selected_icon.setSelected(true);
selected_items = new BusinessTable[] { selected_icon };
prev_locations = new Point[] { selected_icon.getLocation() };
}
// Did we select a region...?
if (selrect != null) {
selrect.width = real.x - selrect.x;
selrect.height = real.y - selrect.y;
metaEditor.refreshGraph();
}
// Or just one entry on the screen?
else if (selected_items != null) {
if (last_button == 1) {
/*
* One or more icons are selected and moved around...
*
* new : new position of the ICON (not the mouse pointer) dx : difference with previous position
*/
int dx = icon.x - selected_icon.getLocation().x;
int dy = icon.y - selected_icon.getLocation().y;
// Adjust position (location) of selected steps...
for (int i = 0; i < selected_items.length; i++) {
BusinessTable businessTable = selected_items[i];
businessTable.setLocation(businessTable.getLocation().x + dx, businessTable.getLocation().y + dy);
}
metaEditor.refreshGraph();
}
// The middle button perhaps?
else if (last_button == 2) {
BusinessTable businessTable = activeModel.getTable(real.x, real.y, iconsize);
if (businessTable != null && !selected_icon.equals(businessTable)) {
if (candidate == null) {
candidate = new RelationshipMeta(selected_icon, businessTable, null, null);
redraw();
}
} else {
if (candidate != null) {
candidate = null;
metaEditor.refreshGraph();
}
}
}
} else if (selected_note != null) {
// Move around a note...
if (last_button == 1) {
Point note = new Point(real.x - noteoffset.x, real.y - noteoffset.y);
selected_note.setLocation(note.x, note.y);
metaEditor.refreshGraph();
}
}
}
});
// Drag & Drop for tables etc.
Transfer[] ttypes = new Transfer[] { XMLTransfer.getInstance() };
DropTarget ddTarget = new DropTarget(this, DND.DROP_MOVE);
ddTarget.setTransfer(ttypes);
ddTarget.addDropListener(new DropTargetListener() {
public void dragEnter(DropTargetEvent event) {
selected_items = null;
selected_icon = null;
selrect = null;
drop_candidate = getRealPosition(metaEditorGraph, event.x, event.y);
redraw();
}
public void dragLeave(DropTargetEvent event) {
drop_candidate = null;
redraw();
}
public void dragOperationChanged(DropTargetEvent event) {
}
public void dragOver(DropTargetEvent event) {
drop_candidate = getRealPosition(metaEditorGraph, event.x, event.y);
redraw();
}
public void drop(DropTargetEvent event) {
// no data to copy, indicate failure in event.detail
if (event.data == null) {
event.detail = DND.DROP_NONE;
return;
}
// What's the real drop position?
Point p = getRealPosition(metaEditorGraph, event.x, event.y);
//
// We expect a Drag and Drop container... (encased in XML)
try {
DragAndDropContainer container = (DragAndDropContainer) event.data;
switch (container.getType()) {
//
// Drag physical table onto metaEditorGraph:
// 0) Look up the referenced Physical Table name, if it exists continue
// 1) If there is an active business model use that one, if not ask name, create one, edit it
// 2) Create the business table based on the physical table, edit
// 3) Place the business table on the selected coordinates.
//
case DragAndDropContainer.TYPE_PHYSICAL_TABLE: {
PhysicalTable physicalTable = metaEditor.getSchemaMeta().findPhysicalTable(container.getData()); // 0)
if (physicalTable != null) {
BusinessModel businessModel = metaEditor.getSchemaMeta().getActiveModel();
if (businessModel == null)
businessModel = metaEditor.newBusinessModel(); // 1)
if (businessModel != null) {
BusinessTable businessTable = metaEditor.newBusinessTable(physicalTable); // 2)
if (businessTable != null) {
businessTable.setLocation(p.x, p.y);
businessTable.setDrawn(true);
businessTable.setSelected(true);
metaEditor.refreshAll();
}
}
}
}
break;
//
// Nothing we can use: give an error!
//
default: {
MessageBox mb = new MessageBox(shell, SWT.OK);
mb.setMessage(Messages.getString("MetaEditorGraph.USER_CANT_PLACE_ON_GRAPH")); //$NON-NLS-1$
mb.setText(Messages.getString("General.USER_TITLE_ERROR")); //$NON-NLS-1$
mb.open();
return;
}
}
} catch (Exception e) {
new ErrorDialog(
shell,
Messages.getString("MetaEditorGraph.USER_TITLE_DND_ERROR"), Messages.getString("MetaEditorGraph.USER_DND_ERROR"), e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
public void dropAccept(DropTargetEvent event) {
}
});
// Keyboard shortcuts...
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
if (activeModel == null)
return;
if (e.character == 1) // CTRL-A
{
activeModel.selectAll();
redraw();
}
if (e.keyCode == SWT.ESC) {
activeModel.unselectAll();
redraw();
}
// CTRL-UP : allignTop();
if (e.keyCode == SWT.ARROW_UP && (e.stateMask & SWT.MOD1) != 0) {
alligntop();
}
// CTRL-DOWN : allignBottom();
if (e.keyCode == SWT.ARROW_DOWN && (e.stateMask & SWT.MOD1) != 0) {
allignbottom();
}
// CTRL-LEFT : allignleft();
if (e.keyCode == SWT.ARROW_LEFT && (e.stateMask & SWT.MOD1) != 0) {
allignleft();
}
// CTRL-RIGHT : allignRight();
if (e.keyCode == SWT.ARROW_RIGHT && (e.stateMask & SWT.MOD1) != 0) {
allignright();
}
// ALT-RIGHT : distributeHorizontal();
if (e.keyCode == SWT.ARROW_RIGHT && (e.stateMask & SWT.ALT) != 0) {
distributehorizontal();
}
// ALT-UP : distributeVertical();
if (e.keyCode == SWT.ARROW_UP && (e.stateMask & SWT.ALT) != 0) {
distributevertical();
}
// ALT-HOME : snap to grid
if (e.keyCode == SWT.HOME && (e.stateMask & SWT.ALT) != 0) {
snaptogrid(Const.GRID_SIZE);
}
}
});
addKeyListener(metaEditor.defKeys);
setBackground(GUIResource.getInstance().getColorBackground());
}
public Point screen2real(int x, int y) {
offset = getOffset();
Point real = new Point(x - offset.x, y - offset.y);
return real;
}
public Point real2screen(int x, int y) {
getOffset();
Point screen = new Point(x + offset.x, y + offset.y);
return screen;
}
public Point getRealPosition(Composite canvas, int x, int y) {
Point p = new Point(0, 0);
Composite follow = canvas;
while (follow != null) {
org.eclipse.swt.graphics.Point loc = follow.getLocation();
Point xy = new Point(loc.x, loc.y);
p.x += xy.x;
p.y += xy.y;
follow = follow.getParent();
}
p.x = x - p.x - 8;
p.y = y - p.y - 48;
return screen2real(p.x, p.y);
}
// See if location (x,y) is on a line between two entities: the relationship!
// return the Relationship if so, otherwise: null
private RelationshipMeta findRelationship(int x, int y) {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
if (activeModel == null)
return null; // no active business model
for (int i = 0; i < activeModel.nrRelationships(); i++) {
RelationshipMeta ri = activeModel.getRelationship(i);
BusinessTable fs = ri.getTableFrom();
BusinessTable ts = ri.getTableTo();
if (fs != null && ts != null) {
int line[] = new int[4];
getLine(fs, ts, line);
if (pointOnLine(x, y, line))
return ri;
}
}
return null;
}
private double getLine(BusinessTable fs, BusinessTable ts, int line[]) {
Point from = fs.getLocation();
Point to = ts.getLocation();
offset = getOffset();
Point A = new Point(from.x, from.y);
Point B = new Point(to.x, to.y);
Point X = new Point(0, 0);
Point Y = new Point(0, 0);
double angle = calcRelationshipLine(A, B, X, Y);
line[0] = X.x;
line[1] = X.y;
line[2] = Y.x;
line[3] = Y.y;
return angle;
}
private void createPopup(int x, int y) {
if (mPop != null) {
mPop.dispose();
}
setMenu(null);
mPop = new Menu(this);
final BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
if (activeModel == null)
return;
final String activeLocale = metaEditor.getSchemaMeta().getActiveLocale();
// final String activeLocale = metaEditor.getSchemaMeta().getActiveLocale();
final BusinessTable bTable = activeModel.getTable(x, y, iconsize);
if (bTable != null) // We clicked on a Step!
{
int sels = activeModel.nrSelected();
if (sels == 1) {
MenuItem miNewBTable = new MenuItem(mPop, SWT.CASCADE);
miNewBTable.setText(Messages.getString("MetaEditorGraph.USER_NEW_BUSINESS_TABLE")); //$NON-NLS-1$
miNewBTable.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selected_items = null;
newBusinessTable();
}
});
MenuItem miEditBTable = new MenuItem(mPop, SWT.CASCADE);
miEditBTable.setText(Messages.getString("MetaEditorGraph.USER_EDIT_BUSINESS_TABLE")); //$NON-NLS-1$
miEditBTable.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selected_items = null;
editBusinessTable(activeModel, bTable);
}
});
MenuItem miDupeBTable = new MenuItem(mPop, SWT.CASCADE);
miDupeBTable.setText(Messages.getString("MetaEditorGraph.USER_DUPE_BUSINESS_TABLE")); //$NON-NLS-1$
miDupeBTable.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
dupeBusinessTable(activeModel, bTable);
}
});
MenuItem miDelStep = new MenuItem(mPop, SWT.CASCADE);
miDelStep.setText(Messages.getString("MetaEditorGraph.USER_DELETE_TABLE")); //$NON-NLS-1$
miDelStep.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
int nrsels = activeModel.nrSelected();
if (nrsels == 0) {
metaEditor.delPhysicalTable(bTable.getId());
} else {
if (!bTable.isSelected())
nrsels++;
MessageBox mb = new MessageBox(shell, SWT.YES | SWT.NO | SWT.ICON_WARNING);
mb.setText(Messages.getString("MetaEditorGraph.USER_WARNING")); //$NON-NLS-1$
String message = Messages.getString(
"MetaEditorGraph.USER_CONFRIM_DELETE_TABLES", Integer.toString(nrsels)); //$NON-NLS-1$
for (int i = activeModel.nrBusinessTables() - 1; i >= 0; i--) {
BusinessTable tableinfo = activeModel.getBusinessTable(i);
if (tableinfo.isSelected() || bTable.equals(tableinfo)) {
message += " " + tableinfo.getId() + Const.CR; //$NON-NLS-1$
}
}
mb.setMessage(message);
int result = mb.open();
if (result == SWT.YES) {
for (int i = activeModel.nrBusinessTables() - 1; i >= 0; i--) {
BusinessTable tableinfo = activeModel.getBusinessTable(i);
if (tableinfo.isSelected() || bTable.equals(tableinfo)) {
metaEditor.delBusinessTable(tableinfo);
}
}
}
}
}
});
new MenuItem(mPop, SWT.SEPARATOR);
MenuItem miSetParentConcept = new MenuItem(mPop, SWT.CASCADE);
miSetParentConcept.setText(Messages.getString("MetaEditorGraph.USER_SET_PARENT_CONCEPT")); //$NON-NLS-1$
miSetParentConcept.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ConceptUtilityInterface[] conceptUtilityInterfaces = metaEditor
.getSelectedConceptUtilityInterfacesInMainTree();
metaEditor.setParentConcept(conceptUtilityInterfaces);
}
});
MenuItem miClearParentConcept = new MenuItem(mPop, SWT.CASCADE);
miClearParentConcept.setText(Messages.getString("MetaEditorGraph.USER_CLEAR_PARENT_CONCEPT")); //$NON-NLS-1$
miClearParentConcept.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ConceptUtilityInterface[] conceptUtilityInterfaces = metaEditor
.getSelectedConceptUtilityInterfacesInMainTree();
metaEditor.clearParentConcept(conceptUtilityInterfaces);
}
});
MenuItem miRemoveChildProps = new MenuItem(mPop, SWT.CASCADE);
miRemoveChildProps.setText(Messages.getString("MetaEditorGraph.USER_REMOVE_CHILD_PROPS")); //$NON-NLS-1$
miRemoveChildProps.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ConceptUtilityInterface[] conceptUtilityInterfaces = metaEditor
.getSelectedConceptUtilityInterfacesInMainTree();
metaEditor.removeChildProperties(conceptUtilityInterfaces);
}
});
new MenuItem(mPop, SWT.SEPARATOR);
MenuItem miEditPTable = new MenuItem(mPop, SWT.CASCADE);
miEditPTable.setText(Messages.getString(
"MetaEditorGraph.USER_EDIT_PHYSICAL_TABLE", bTable.getPhysicalTable().getDisplayName(activeLocale))); //$NON-NLS-1$
if (bTable.getPhysicalTable() != null) {
miEditPTable.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
metaEditor.editPhysicalTable(bTable.getPhysicalTable());
}
});
}
MenuItem miDupeStep = new MenuItem(mPop, SWT.CASCADE);
miDupeStep.setText(Messages.getString("MetaEditorGraph.USER_DUPLICATE_TABLE")); //$NON-NLS-1$
miDupeStep.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (activeModel.nrSelected() <= 1) {
metaEditor.dupePhysicalTable(bTable.getPhysicalTable());
} else {
for (int i = 0; i < activeModel.nrBusinessTables(); i++) {
BusinessTable businessTable = activeModel.getBusinessTable(i);
if (businessTable.isSelected()) {
metaEditor.dupePhysicalTable(businessTable.getPhysicalTable());
}
}
}
}
});
} else if (sels == 2) {
MenuItem miNewHop = new MenuItem(mPop, SWT.CASCADE);
miNewHop.setText(Messages.getString("MetaEditorGraph.USER_ADD_RELATIONSHIP")); //$NON-NLS-1$
miNewHop.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selected_items = null;
newRelationship();
}
});
}
// Allign & Distribute options...
if (sels > 1) {
new MenuItem(mPop, SWT.SEPARATOR);
MenuItem miPopAD = new MenuItem(mPop, SWT.CASCADE);
miPopAD.setText(Messages.getString("MetaEditorGraph.USER_ALIGN_DISTRIBUTE")); //$NON-NLS-1$
Menu mPopAD = new Menu(miPopAD);
MenuItem miPopALeft = new MenuItem(mPopAD, SWT.CASCADE);
miPopALeft.setText(Messages.getString("MetaEditorGraph.USER_ALIGN_LEFT")); //$NON-NLS-1$
MenuItem miPopARight = new MenuItem(mPopAD, SWT.CASCADE);
miPopARight.setText(Messages.getString("MetaEditorGraph.USER_ALIGN_RIGHT")); //$NON-NLS-1$
MenuItem miPopATop = new MenuItem(mPopAD, SWT.CASCADE);
miPopATop.setText(Messages.getString("MetaEditorGraph.USER_ALIGN_TOP")); //$NON-NLS-1$
MenuItem miPopABottom = new MenuItem(mPopAD, SWT.CASCADE);
miPopABottom.setText(Messages.getString("MetaEditorGraph.USER_ALIGN_BOTTOM")); //$NON-NLS-1$
new MenuItem(mPopAD, SWT.SEPARATOR);
MenuItem miPopDHoriz = new MenuItem(mPopAD, SWT.CASCADE);
miPopDHoriz.setText(Messages.getString("MetaEditorGraph.USER_DISTRIBUTE_HORIZ")); //$NON-NLS-1$
MenuItem miPopDVertic = new MenuItem(mPopAD, SWT.CASCADE);
miPopDVertic.setText(Messages.getString("MetaEditorGraph.USER_DISTRIBUTE_VERT")); //$NON-NLS-1$
new MenuItem(mPopAD, SWT.SEPARATOR);
MenuItem miPopSSnap = new MenuItem(mPopAD, SWT.CASCADE);
miPopSSnap.setText(Messages.getString("MetaEditorGraph.USER_SNAP_TO_GRID", Integer.toString(Const.GRID_SIZE))); //$NON-NLS-1$
miPopAD.setMenu(mPopAD);
miPopALeft.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
allignleft();
}
});
miPopARight.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
allignright();
}
});
miPopATop.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
alligntop();
}
});
miPopABottom.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
allignbottom();
}
});
miPopDHoriz.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
distributehorizontal();
}
});
miPopDVertic.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
distributevertical();
}
});
miPopSSnap.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
snaptogrid(Const.GRID_SIZE);
}
});
}
} else {
final RelationshipMeta relationshipMeta = findRelationship(x, y);
if (relationshipMeta != null) // We clicked on a relationship!
{
final BusinessModel model = metaEditor.getSchemaMeta().getActiveModel(); // not null because we found a relationship
MenuItem miEditHop = new MenuItem(mPop, SWT.CASCADE);
miEditHop.setText(Messages.getString("MetaEditorGraph.USER_EDIT_RELATIONSHIP")); //$NON-NLS-1$
miEditHop.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selrect = null;
editRelationship(relationshipMeta);
}
});
MenuItem miDelHop = new MenuItem(mPop, SWT.CASCADE);
miDelHop.setText(Messages.getString("MetaEditorGraph.USER_DELETE_RELATIONSHIP")); //$NON-NLS-1$
miDelHop.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selrect = null;
int idx = model.indexOfRelationship(relationshipMeta);
model.removeRelationship(idx);
metaEditor.synchronize(relationshipMeta);
metaEditor.refreshGraph();
}
});
} else {
// Clicked on the background: maybe we hit a note?
final NotePadMeta ni = activeModel.getNote(x, y);
if (ni != null) {
// Delete note
// Edit note
MenuItem miNoteEdit = new MenuItem(mPop, SWT.CASCADE);
miNoteEdit.setText(Messages.getString("MetaEditorGraph.USER_EDIT_NOTE")); //$NON-NLS-1$
MenuItem miNoteDel = new MenuItem(mPop, SWT.CASCADE);
miNoteDel.setText(Messages.getString("MetaEditorGraph.USER_DELETE_NOTE")); //$NON-NLS-1$
miNoteEdit.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selrect = null;
editNote(ni);
}
});
miNoteDel.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selrect = null;
int idx = activeModel.indexOfNote(ni);
if (idx >= 0) {
activeModel.removeNote(idx);
redraw();
}
}
});
} else {
// New note
MenuItem miNoteNew = new MenuItem(mPop, SWT.CASCADE);
miNoteNew.setText(Messages.getString("MetaEditorGraph.USER_NEW_NOTE")); //$NON-NLS-1$
miNoteNew.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selrect = null;
String title = Messages.getString("MetaEditorGraph.USER_TITLE_NOTES"); //$NON-NLS-1$
String message = Messages.getString("MetaEditorGraph.USER_NOTE_TEXT"); //$NON-NLS-1$
EnterTextDialog dd = new EnterTextDialog(shell, title, message, ""); //$NON-NLS-1$
String n = dd.open();
if (n != null) {
NotePadMeta npi = new NotePadMeta(n, lastclick.x, lastclick.y, Const.NOTE_MIN_SIZE, Const.NOTE_MIN_SIZE);
activeModel.addNote(npi);
redraw();
}
}
});
MenuItem miNewBTable = new MenuItem(mPop, SWT.CASCADE);
miNewBTable.setText(Messages.getString("MetaEditorGraph.USER_NEW_BUSINESS_TABLE")); //$NON-NLS-1$
miNewBTable.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selrect = null;
newBusinessTable();
}
});
MenuItem miNewRelationship = new MenuItem(mPop, SWT.CASCADE);
miNewRelationship.setText(Messages.getString("MetaEditorGraph.USER_NEW_RELATIONSHIP")); //$NON-NLS-1$
miNewRelationship.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selrect = null;
newRelationship();
}
});
// MenuItem miSetLocale = new MenuItem(mPop, SWT.CASCADE);
// miSetLocale.setText(Messages.getString("MetaEditorGraph.USER_SET_LOCALE")); //$NON-NLS-1$
// miSetLocale.addSelectionListener(new SelectionAdapter() {
// public void widgetSelected(SelectionEvent e) {
// selrect = null;
// // TODO implement setLocale
// log.logError("Not Implemented", "Set Locale functionality not yet implemented"); //$NON-NLS-1$ //$NON-NLS-2$
// }
// });
}
}
}
setMenu(mPop);
mPop.setVisible(true);
}
private void setToolTip(int x, int y) {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
if (activeModel == null)
return;
String activeLocale = metaEditor.getSchemaMeta().getActiveLocale();
final BusinessTable businessTable = activeModel.getTable(x, y, iconsize);
if (businessTable != null) // We clicked on a Step!
{
ConceptInterface concept = businessTable.getConcept();
// Also: set the tooltip!
if (concept.getDescription(activeLocale) != null) {
String desc = concept.getDescription(activeLocale);
int le = desc.length() >= 200 ? 200 : desc.length();
String tip = desc.substring(0, le);
if (!tip.equalsIgnoreCase(getToolTipText())) {
setToolTipText(tip);
}
} else {
setToolTipText(null);
}
} else {
final RelationshipMeta hi = findRelationship(x, y);
if (hi != null) // We clicked on a HOP!
{
// Set the tooltip for the hop:
setToolTipText(Const.NVL(hi.getDescription(), hi.toString()));
} else {
setToolTipText(null);
}
}
}
public void editDescription(final ConceptInterface conceptInterface) {
final String activeLocale = metaEditor.getSchemaMeta().getActiveLocale();
DescriptionInterface descriptionInterface = new DescriptionInterface() {
public void setDescription(String desc) {
conceptInterface.setDescription(activeLocale, desc);
}
public String getDescription() {
return conceptInterface.getDescription(activeLocale);
}
};
EnterTextDialog
.editDescription(
shell,
descriptionInterface,
Messages.getString("MetaEditorGraph.USER_TABLE_DESCRIPTION_DIALOG"), Messages.getString("MetaEditorGraph.USER_TABLE_DESCRIPTION")); //$NON-NLS-1$ //$NON-NLS-2$
}
public void paintControl(PaintEvent e) {
Point area = getArea();
if (area.x == 0 || area.y == 0)
return; // nothing to do!
Display disp = shell.getDisplay();
Image img = new Image(disp, area.x, area.y);
GC gc = new GC(img);
// First clear the image in the background color
gc.setBackground(GUIResource.getInstance().getColorBackground());
gc.fillRectangle(0, 0, area.x, area.y);
// Then draw stuff on it!
drawSchema(gc);
e.gc.drawImage(img, 0, 0);
gc.dispose();
img.dispose();
metaEditor.setShellText();
}
public void drawSchema(GC gc) {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
String activeLocale = metaEditor.getSchemaMeta().getActiveLocale();
if (props.isAntiAliasingEnabled())
gc.setAntialias(SWT.ON);
gc.setBackground(GUIResource.getInstance().getColorBackground());
// Draw the active business model. If there is none, don't draw anything except the drop rectangles ;-)
if (activeModel != null) {
// display the name/description of the business model
//
String title = activeModel.getDisplayName(activeLocale);
gc.setFont(GUIResource.getInstance().getFontLarge());
org.eclipse.swt.graphics.Point point = gc.textExtent(title);
gc.drawText(title, 10, 10);
gc.setFont(GUIResource.getInstance().getFontMedium());
String description = activeModel.getConcept().getDescription(activeLocale);
if (description != null) {
description = paginateString(gc, description);
gc.drawText(description, 10, 10 + point.y, SWT.DRAW_DELIMITER);
}
// Display the active locale in the right hand corner.
org.eclipse.swt.graphics.Rectangle rect = gc.getClipping();
gc.setFont(GUIResource.getInstance().getFontMedium());
String localeMessage = Messages.getString("MetaEditorGraph.USER_LOCALE", activeLocale); //$NON-NLS-1$
org.eclipse.swt.graphics.Point messageSize = gc.textExtent(localeMessage);
gc.drawText(localeMessage, rect.width - messageSize.x - 20, 10);
// Back to our regular show...
Point area = getArea();
Point max = activeModel.getMaximum();
Point thumb = getThumb(area, max);
offset = getOffset(thumb, area);
hori.setThumb(thumb.x);
vert.setThumb(thumb.y);
// First the notes
for (int i = 0; i < activeModel.nrNotes(); i++) {
NotePadMeta ni = activeModel.getNote(i);
drawNote(gc, ni);
}
for (int i = 0; i < activeModel.nrRelationships(); i++) {
RelationshipMeta hi = activeModel.getRelationship(i);
drawRelationship(gc, hi);
}
if (candidate != null) {
drawRelationship(gc, candidate, true);
}
for (int i = 0; i < activeModel.nrBusinessTables(); i++) {
BusinessTable si = activeModel.getBusinessTable(i);
drawBusinessTable(gc, si);
}
drawRect(gc, selrect);
} else {
// Set the name of the business model
//
int h = (int) GUIResource.getInstance().getFontLarge().getFontData()[0].height;
gc.setFont(GUIResource.getInstance().getFontLarge());
int nrModels = metaEditor.getSchemaMeta().nrBusinessModels();
String message1, message2;
switch (nrModels) {
case 0:
message1 = Messages.getString("MetaEditorGraph.USER_NO_BUSINESS_MODELS_DEFINED");message2 = Messages.getString("MetaEditorGraph.USER_CREATE_ONE_FIRST");break; //$NON-NLS-1$ //$NON-NLS-2$
case 1:
message1 = Messages.getString("MetaEditorGraph.USER_ONE_BUSINESS_MODEL_DEFINED");message2 = Messages.getString("MetaEditorGraph.USER_SELECT_IN_TREE");break; //$NON-NLS-1$ //$NON-NLS-2$
default:
message1 = Messages.getString("MetaEditorGraph.USER_N_BUSINESS_MODELS_DEFINED", Integer.toString(nrModels));message2 = Messages.getString("MetaEditorGraph.USER_SELECT_ONE_IN_TREE");break; //$NON-NLS-1$ //$NON-NLS-2$
}
gc.drawText(message1, 10, 10, true);
gc.drawText(message2, 10, 20 + h, true);
}
if (drop_candidate != null) {
gc.setLineStyle(SWT.LINE_SOLID);
gc.setForeground(GUIResource.getInstance().getColorBlack());
Point screen = real2screen(drop_candidate.x, drop_candidate.y);
gc.drawRectangle(screen.x, screen.y, iconsize, iconsize);
}
}
/**
* @param gc - The Graphics content
* @param src - The string to break up
* @return String that contains \n characters where the distance between each
* \n character is less than the width of the frame
*/
private String paginateString(GC gc, String strSrc) {
int stringWidth = gc.textExtent(strSrc).x;
int frameWidth = getSize().x - RIGHT_HAND_SLOP;
if (stringWidth <= frameWidth) {
return strSrc;
}
String[] tokens = strSrc.split("\\s"); //$NON-NLS-1$
String result = "";
ArrayList<String> textRuns = new ArrayList<String>();
for (int i=0; i<tokens.length; i++) {
if (gc.textExtent(result + tokens[i]).x < frameWidth) {
result = result + " " + tokens[i]; //$NON-NLS-1$
} else {
textRuns.add(result);
result = tokens[i];
}
}
textRuns.add(result);
result = "";
Iterator iter = textRuns.iterator();
while (iter.hasNext()) {
result += iter.next().toString() + "\n";
}
return result;
}
private void drawRelationship(GC gc, RelationshipMeta hi) {
drawRelationship(gc, hi, false);
}
private void drawNote(GC gc, NotePadMeta ni) {
int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT;
org.eclipse.swt.graphics.Point ext = gc.textExtent(ni.getNote(), flags);
Point p = new Point(ext.x, ext.y);
Point loc = ni.getLocation();
Point note = real2screen(loc.x, loc.y);
int margin = Const.NOTE_MARGIN;
p.x += 2 * margin;
p.y += 2 * margin;
int width = ni.width;
int height = ni.height;
if (p.x > width)
width = p.x;
if (p.y > height)
height = p.y;
gc.setForeground(GUIResource.getInstance().getColorGray());
gc.setBackground(GUIResource.getInstance().getColorYellow());
int noteshape[] = new int[] { note.x, note.y, // Top left
note.x + width + 2 * margin, note.y, // Top right
note.x + width + 2 * margin, note.y + height, // bottom right 1
note.x + width, note.y + height + 2 * margin, // bottom right 2
note.x + width, note.y + height, // bottom right 3
note.x + width + 2 * margin, note.y + height, // bottom right 1
note.x + width, note.y + height + 2 * margin, // bottom right 2
note.x, note.y + height + 2 * margin // bottom left
};
gc.fillPolygon(noteshape);
gc.drawPolygon(noteshape);
gc.setForeground(GUIResource.getInstance().getColorBlack());
gc.drawText(ni.getNote(), note.x + margin, note.y + margin, flags);
ni.width = width; // Save for the "mouse" later on...
ni.height = height;
}
private void drawRelationship(GC gc, RelationshipMeta hi, boolean is_candidate) {
BusinessTable fs = hi.getTableFrom();
BusinessTable ts = hi.getTableTo();
if (fs != null && ts != null) {
drawRelationshipLine(gc, fs, ts, hi, is_candidate);
}
}
private void drawBusinessTable(GC gc, BusinessTable businessTable) {
Point pt = businessTable.getLocation();
int x, y;
if (pt != null) {
x = pt.x;
y = pt.y;
} else {
x = 50;
y = 50;
}
Point screen = real2screen(x, y);
int sizeX = iconsize;
int sizeY = iconsize;
String name = businessTable.getDisplayName(metaEditor.getSchemaMeta().getActiveLocale());
Image im = Constants.getImageRegistry(Display.getCurrent()).get("bus-table-graph-icon");
org.eclipse.swt.graphics.Rectangle bounds = im.getBounds();
gc.drawImage(im, 0, 0, bounds.width, bounds.height, screen.x, screen.y, iconsize, iconsize);
// PMD-204: Previously, the boxes were colored according to type; leaving this code commented out for reference
// if (businessTable.isFactTable()) {
// gc.setBackground(GUIResource.getInstance().getColorOrange());
// } else if (businessTable.isDimensionTable()) {
// gc.setBackground(GUIResource.getInstance().getColorYellow());
// } else {
// gc.setBackground(GUIResource.getInstance().getColorLightGray());
// }
if (businessTable.isSelected()) {
gc.setLineWidth(linewidth + 2);
gc.setBackground(GUIResource.getInstance().getColorBackground());
gc.drawRectangle(screen.x - 1, screen.y - 1, sizeX + 1, sizeY + 1);
}
org.eclipse.swt.graphics.Point ext = gc.textExtent(name);
Point textsize = new Point(ext.x, ext.y);
gc.setBackground(GUIResource.getInstance().getColorDarkGray());
gc.setForeground(GUIResource.getInstance().getColorBlack());
gc.setLineWidth(linewidth);
int xpos = screen.x + (sizeX / 2) - (textsize.x / 2);
int ypos = screen.y + sizeY + Const.SYMBOLSIZE + 4;
gc.drawText(name, xpos, ypos, SWT.DRAW_TRANSPARENT);
}
private void drawRelationshipLine(GC gc, BusinessTable fs, BusinessTable ts, RelationshipMeta hi, boolean is_candidate) {
int line[] = new int[4];
double angle = getLine(fs, ts, line);
gc.setLineWidth(linewidth);
Color col;
if (is_candidate) {
col = GUIResource.getInstance().getColorBlue();
} else {
col = GUIResource.getInstance().getColorBlack();
}
gc.setForeground(col);
drawArrow(gc, line, hi, angle);
gc.setForeground(GUIResource.getInstance().getColorBlack());
gc.setBackground(GUIResource.getInstance().getColorBackground());
}
private Point getArea() {
org.eclipse.swt.graphics.Rectangle rect = getClientArea();
Point area = new Point(rect.width, rect.height);
return area;
}
private Point getThumb(Point area, Point max) {
Point thumb = new Point(0, 0);
if (max.x <= area.x)
thumb.x = 100;
else
thumb.x = 100 * area.x / max.x;
if (max.y <= area.y)
thumb.y = 100;
else
thumb.y = 100 * area.y / max.y;
return thumb;
}
private Point getOffset() {
Point area = getArea();
Point max = new Point(0, 0);
if (metaEditor.getSchemaMeta().getActiveModel() != null) {
max = metaEditor.getSchemaMeta().getActiveModel().getMaximum();
}
Point thumb = getThumb(area, max);
Point off = getOffset(thumb, area);
return off;
}
private Point getOffset(Point thumb, Point area) {
Point p = new Point(0, 0);
Point sel = new Point(hori.getSelection(), vert.getSelection());
if (thumb.x == 0 || thumb.y == 0)
return p;
p.x = -sel.x * area.x / thumb.x;
p.y = -sel.y * area.y / thumb.y;
return p;
}
public int sign(int n) {
return n < 0 ? -1 : (n > 0 ? 1 : 1);
}
private void newBusinessTable() {
metaEditor.newBusinessTable(null);
}
private void editBusinessTable(BusinessModel activeModel, BusinessTable businessTable) {
metaEditor.editBusinessTable(businessTable);
}
private void dupeBusinessTable(BusinessModel activeModel, BusinessTable businessTable) {
metaEditor.dupeBusinessTable(businessTable);
}
private void editNote(NotePadMeta ni) {
String title = Messages.getString("MetaEditorGraph.USER_TITLE_NOTES"); //$NON-NLS-1$
String message = Messages.getString("MetaEditorGraph.USER_NOTE_TEXT"); //$NON-NLS-1$
EnterTextDialog dd = new EnterTextDialog(shell, title, message, ni.getNote());
String n = dd.open();
if (n != null) {
ni.setChanged();
ni.setNote(n);
ni.width = Const.NOTE_MIN_SIZE;
ni.height = Const.NOTE_MIN_SIZE;
metaEditor.refreshGraph();
}
}
private void editRelationship(RelationshipMeta hopinfo) {
String name = hopinfo.toString();
log.logDebug(Messages.getString("MetaEditorGraph.DEBUG_EDITING_RELATIONSHIP", name)); //$NON-NLS-1$
metaEditor.editRelationship(hopinfo);
}
private void newRelationship() {
if (metaEditor.getSchemaMeta().getActiveModel() == null)
return;
BusinessTable from = null;
BusinessTable to = null;
BusinessTable[] selectedTables = metaEditor.getSchemaMeta().getActiveModel().getSelectedTables();
if (selectedTables != null){
from = selectedTables[0];
if (selectedTables.length > 1){
to = metaEditor.getSchemaMeta().getActiveModel().getSelectedTables()[1];
}
}
metaEditor.newRelationship(from, to);
}
private double calcRelationshipLine(Point A, Point B, Point X, Point Y) {
double angle = calcAngle(A, B);
if (angle > -45 && angle <= 45) {
X.x = A.x + iconsize + Const.SYMBOLSIZE;
Y.x = B.x - Const.SYMBOLSIZE;
X.y = A.y + iconsize / 2;
Y.y = B.y + iconsize / 2;
} else if (angle > 45 && angle <= 135) {
X.x = A.x + iconsize / 2;
Y.x = B.x + iconsize / 2;
X.y = A.y + iconsize + Const.SYMBOLSIZE;
Y.y = B.y - Const.SYMBOLSIZE;
} else if (angle > 135 || angle <= -135) {
X.x = A.x - Const.SYMBOLSIZE;
Y.x = B.x + iconsize + Const.SYMBOLSIZE;
X.y = A.y + iconsize / 2;
Y.y = B.y + iconsize / 2;
} else if (angle <= -45) {
X.x = A.x + iconsize / 2;
Y.x = B.x + iconsize / 2;
X.y = A.y - Const.SYMBOLSIZE;
Y.y = B.y + iconsize + Const.SYMBOLSIZE;
}
return angle;
}
private double calcAngle(Point A, Point B) {
return Math.atan2(B.y - A.y, B.x - A.x) * 360 / (2 * Math.PI);
}
private void drawArrow(GC gc, int line[], RelationshipMeta ri, double angle) {
Point X = real2screen(line[0], line[1]);
Point Y = real2screen(line[2], line[3]);
if (ri.getType()==RelationshipMeta.TYPE_RELATIONSHIP_UNDEFINED) {
gc.setLineAttributes(unknownRelationshipLineAttributes);
}
// Main line connecting the 2 entities (tables)
gc.drawLine(X.x, X.y, Y.x, Y.y);
// If there is a join order key set, draw that...
//
if (!Const.isEmpty(ri.getJoinOrderKey())) {
Point middle = new Point( (X.x+Y.x)/2, (X.y+Y.y)/2);
Color oldColor = gc.getForeground();
gc.setForeground(GUIResource.getInstance().getColorBlue());
gc.drawText(ri.getJoinOrderKey(), middle.x, middle.y, SWT.DRAW_TRANSPARENT);
gc.setForeground(oldColor);
}
Point a, b, c;
Point a2, b2, c2;
// Start of the relationship N:, 1:, 0:
// 1:
if (ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_1_0
|| ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_1_1
|| ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_1_N || ri.isComplex()) {
if (angle > -45 && angle <= 45) {
b = new Point(X.x - Const.SYMBOLSIZE, X.y);
} else if (angle > 45 && angle <= 135) {
b = new Point(X.x, X.y - Const.SYMBOLSIZE);
} else if (angle > 135 || angle <= -135) {
b = new Point(X.x + Const.SYMBOLSIZE, X.y);
} else // (angle<=-45)
{
b = new Point(X.x, X.y + Const.SYMBOLSIZE);
}
gc.drawLine(X.x, X.y, b.x, b.y);
} else
// N:
if (ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_N_0
|| ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_N_1
|| ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_N_N) {
if (angle > -45 && angle <= 45) {
a = new Point(X.x - Const.SYMBOLSIZE, X.y - Const.SYMBOLSIZE);
b = new Point(X.x - Const.SYMBOLSIZE, X.y);
c = new Point(X.x - Const.SYMBOLSIZE, X.y + Const.SYMBOLSIZE);
} else if (angle > 45 && angle <= 135) {
a = new Point(X.x - Const.SYMBOLSIZE, X.y - Const.SYMBOLSIZE);
b = new Point(X.x, X.y - Const.SYMBOLSIZE);
c = new Point(X.x + Const.SYMBOLSIZE, X.y - Const.SYMBOLSIZE);
} else if (angle > 135 || angle <= -135) {
a = new Point(X.x + Const.SYMBOLSIZE, X.y - Const.SYMBOLSIZE);
b = new Point(X.x + Const.SYMBOLSIZE, X.y);
c = new Point(X.x + Const.SYMBOLSIZE, X.y + Const.SYMBOLSIZE);
} else // (angle<=-45)
{
a = new Point(X.x - Const.SYMBOLSIZE, X.y + Const.SYMBOLSIZE);
b = new Point(X.x, X.y + Const.SYMBOLSIZE);
c = new Point(X.x + Const.SYMBOLSIZE, X.y + Const.SYMBOLSIZE);
}
gc.drawLine(X.x, X.y, a.x, a.y);
gc.drawLine(X.x, X.y, b.x, b.y);
gc.drawLine(X.x, X.y, c.x, c.y);
} else // 0:
{
if (angle > -45 && angle <= 45) {
a = new Point(X.x - Const.SYMBOLSIZE, X.y - Const.SYMBOLSIZE / 2);
} else if (angle > 45 && angle <= 135) {
a = new Point(X.x - Const.SYMBOLSIZE / 2, X.y - Const.SYMBOLSIZE);
} else if (angle > 135 || angle <= -135) {
a = new Point(X.x, X.y - Const.SYMBOLSIZE / 2);
} else // (angle<=-45)
{
a = new Point(X.x - Const.SYMBOLSIZE / 2, X.y);
}
gc.drawOval(a.x, a.y, Const.SYMBOLSIZE, Const.SYMBOLSIZE);
}
// Start of the relationship :N, :1, :0
// :1
if (ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_0_1
|| ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_1_1
|| ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_N_1 || ri.isComplex()) {
if (angle > -45 && angle <= 45) // -->
{
b2 = new Point(Y.x + Const.SYMBOLSIZE, Y.y);
} else if (angle > 45 && angle <= 135) // |
{ // \|/
// '
b2 = new Point(Y.x, Y.y + Const.SYMBOLSIZE);
} else if (angle > 135 || angle <= -135) // <--
{
b2 = new Point(Y.x - Const.SYMBOLSIZE, Y.y);
} else // (angle<=-45) // .
{ // /|\
// |
b2 = new Point(Y.x, Y.y - Const.SYMBOLSIZE);
}
gc.drawLine(Y.x, Y.y, b2.x, b2.y);
} else // :N
if (ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_0_N
|| ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_1_N
|| ri.getType() == RelationshipMeta.TYPE_RELATIONSHIP_N_N) {
if (angle > -45 && angle <= 45) // -->
{
a2 = new Point(Y.x + Const.SYMBOLSIZE, Y.y - Const.SYMBOLSIZE);
b2 = new Point(Y.x + Const.SYMBOLSIZE, Y.y);
c2 = new Point(Y.x + Const.SYMBOLSIZE, Y.y + Const.SYMBOLSIZE);
} else if (angle > 45 && angle <= 135) // |
{ // \|/
// '
a2 = new Point(Y.x + Const.SYMBOLSIZE, Y.y + Const.SYMBOLSIZE);
b2 = new Point(Y.x, Y.y + Const.SYMBOLSIZE);
c2 = new Point(Y.x - Const.SYMBOLSIZE, Y.y + Const.SYMBOLSIZE);
} else if (angle > 135 || angle <= -135) // <--
{
a2 = new Point(Y.x - Const.SYMBOLSIZE, Y.y - Const.SYMBOLSIZE);
b2 = new Point(Y.x - Const.SYMBOLSIZE, Y.y);
c2 = new Point(Y.x - Const.SYMBOLSIZE, Y.y + Const.SYMBOLSIZE);
} else // (angle<=-45) // .
{ // /|\
// |
a2 = new Point(Y.x + Const.SYMBOLSIZE, Y.y - Const.SYMBOLSIZE);
b2 = new Point(Y.x, Y.y - Const.SYMBOLSIZE);
c2 = new Point(Y.x - Const.SYMBOLSIZE, Y.y - Const.SYMBOLSIZE);
}
gc.drawLine(Y.x, Y.y, a2.x, a2.y);
gc.drawLine(Y.x, Y.y, b2.x, b2.y);
gc.drawLine(Y.x, Y.y, c2.x, c2.y);
} else // :0
{
if (angle > -45 && angle <= 45) {
a2 = new Point(Y.x, Y.y - Const.SYMBOLSIZE / 2);
} else if (angle > 45 && angle <= 135) {
a2 = new Point(Y.x - Const.SYMBOLSIZE / 2, Y.y);
} else if (angle > 135 || angle <= -135) {
a2 = new Point(Y.x - Const.SYMBOLSIZE, Y.y - Const.SYMBOLSIZE / 2);
} else // (angle<=-45)
{
a2 = new Point(Y.x - Const.SYMBOLSIZE / 2, Y.y - Const.SYMBOLSIZE);
}
gc.drawOval(a2.x, a2.y, Const.SYMBOLSIZE, Const.SYMBOLSIZE);
}
gc.setLineStyle(SWT.LINE_SOLID);
}
private boolean pointOnLine(int x, int y, int line[]) {
int dx, dy;
int pm = HOP_SEL_MARGIN / 2;
boolean retval = false;
for (dx = -pm; dx <= pm && !retval; dx++) {
for (dy = -pm; dy <= pm && !retval; dy++) {
retval = pointOnThinLine(x + dx, y + dy, line);
}
}
return retval;
}
private boolean pointOnThinLine(int x, int y, int line[]) {
int x1 = line[0];
int y1 = line[1];
int x2 = line[2];
int y2 = line[3];
// Not in the square formed by these 2 points: ignore!
if (!(((x >= x1 && x <= x2) || (x >= x2 && x <= x1)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))))
return false;
double angle_line = Math.atan2(y2 - y1, x2 - x1) + Math.PI;
double angle_point = Math.atan2(y - y1, x - x1) + Math.PI;
// Same angle, or close enough?
if (angle_point >= angle_line - 0.01 && angle_point <= angle_line + 0.01)
return true;
return false;
}
/**
* Note: we know that we have an active business model here so it's safe to use this BusinessModel.$
*
* @return a new SnapAllignDistribute object
*/
private SnapAllignDistribute createSnapAllignDistribute() {
BusinessModel activeModel = metaEditor.getSchemaMeta().getActiveModel();
List<BusinessTable> elements;
int[] indices;
if (activeModel != null) {
elements = activeModel.getSelectedDrawnBusinessTableList();
indices = activeModel.getBusinessTableIndexes((BusinessTable[]) elements.toArray(new BusinessTable[elements
.size()]));
} else {
elements = new ArrayList<BusinessTable>();
indices = new int[] {};
}
// null in position 1 and 4 are related. The old code had null in the
// 4th position which meant that the 1st argument was originally ignored.
return new SnapAllignDistribute(null, elements, indices, null, this);
}
void snaptogrid(int size) {
createSnapAllignDistribute().snaptogrid(size);
}
void allignleft() {
createSnapAllignDistribute().allignleft();
}
void allignright() {
createSnapAllignDistribute().allignright();
}
void alligntop() {
createSnapAllignDistribute().alligntop();
}
void allignbottom() {
createSnapAllignDistribute().allignbottom();
}
void distributehorizontal() {
createSnapAllignDistribute().distributehorizontal();
}
public void distributevertical() {
createSnapAllignDistribute().distributevertical();
redraw();
}
private void drawRect(GC gc, Rectangle rect) {
if (rect == null)
return;
gc.setLineStyle(SWT.LINE_DASHDOT);
gc.setLineWidth(linewidth);
gc.setForeground(GUIResource.getInstance().getColorGray());
gc.drawRectangle(rect.x + offset.x, rect.y + offset.y, rect.width, rect.height);
gc.setLineStyle(SWT.LINE_SOLID);
}
public void newProps() {
GUIResource.getInstance().reload();
iconsize = props.getIconSize();
linewidth = props.getLineWidth();
}
public String toString() {
return this.getClass().getName();
}
}