weka.gui.knowledgeflow.VisibleLayout Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weka-dev Show documentation
Show all versions of weka-dev Show documentation
The Waikato Environment for Knowledge Analysis (WEKA), a machine
learning workbench. This version represents the developer version, the
"bleeding edge" of development, you could say. New functionality gets added
to this version.
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* VisibleLayout.java
* Copyright (C) 2015 University of Waikato, Hamilton, New Zealand
*
*/
package weka.gui.knowledgeflow;
import weka.core.Copyright;
import weka.core.Environment;
import weka.core.PluginManager;
import weka.core.Settings;
import weka.core.WekaException;
import weka.gui.beans.LogPanel;
import weka.knowledgeflow.BaseExecutionEnvironment;
import weka.knowledgeflow.ExecutionFinishedCallback;
import weka.knowledgeflow.Flow;
import weka.knowledgeflow.FlowExecutor;
import weka.knowledgeflow.FlowRunner;
import weka.knowledgeflow.JSONFlowUtils;
import weka.knowledgeflow.KFDefaults;
import weka.knowledgeflow.LogManager;
import weka.knowledgeflow.StepManager;
import weka.knowledgeflow.StepManagerImpl;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
/**
* Panel that wraps a flow and makes it visible in the KnowledgeFlow, along with
* it's associated log panel
*
* @author Mark Hall (mhall{[at]}pentaho{[dot]}com)
* @version $Revision: $
*/
public class VisibleLayout extends JPanel {
/** the flow layout width */
protected static final int LAYOUT_WIDTH = 2560;
/** the flow layout height */
protected static final int LAYOUT_HEIGHT = 1440;
/** The scrollbar increment of the layout scrollpane */
protected static final int SCROLLBAR_INCREMENT = 50;
private static final long serialVersionUID = -3644458365810712479L;
protected Flow m_flow;
/** The log panel to use for this layout */
protected KFLogPanel m_logPanel = new KFLogPanel();
/** Current zoom setting for this layout */
protected int m_zoomSetting = 100;
/** Current path on disk for this flow */
protected File m_filePath;
/** Keeps track of any highlighted steps on the canvas */
protected List m_selectedSteps = new ArrayList();
/** Keeps track of the undo buffer for this flow */
protected Stack m_undoBuffer = new Stack();
/** True if the flow has been edited, but not yet saved */
protected boolean m_hasBeenEdited;
/** The flow executor used to execute the flow */
protected FlowExecutor m_flowExecutor;
/** Environment variables to use */
protected Environment m_env = new Environment();
/** True if this flow is executing */
protected boolean m_isExecuting;
/** A reference to the main perspective */
protected MainKFPerspective m_mainPerspective;
/** The steps to be rendered on this layout */
protected List m_renderGraph = new ArrayList();
/** The current layout operation */
protected LayoutOperation m_userOpp = LayoutOperation.NONE;
/** The panel used to render the flow */
protected LayoutPanel m_layout;
/** Reference to the step being edited (if any) */
protected StepVisual m_editStep;
/**
* The name of the user-selected connection if the user has initiated a
* connection from a source step (stored in m_editStep)
*/
protected String m_editConnection;
/**
* Constructor
*
* @param mainPerspective the main Knowledge Flow perspective
*/
public VisibleLayout(MainKFPerspective mainPerspective) {
super();
setLayout(new BorderLayout());
m_flow = new Flow();
m_mainPerspective = mainPerspective;
m_layout = new LayoutPanel(this);
JPanel p1 = new JPanel();
p1.setLayout(new BorderLayout());
JScrollPane js = new JScrollPane(m_layout);
p1.add(js, BorderLayout.CENTER);
js.getVerticalScrollBar().setUnitIncrement(
KFDefaults.SCROLL_BAR_INCREMENT_LAYOUT);
js.getHorizontalScrollBar().setUnitIncrement(
KFDefaults.SCROLL_BAR_INCREMENT_LAYOUT);
m_layout.setSize(m_mainPerspective.getSetting(KFDefaults.LAYOUT_WIDTH_KEY,
KFDefaults.LAYOUT_WIDTH), m_mainPerspective.getSetting(
KFDefaults.LAYOUT_HEIGHT_KEY, KFDefaults.LAYOUT_HEIGHT));
Dimension d = m_layout.getPreferredSize();
m_layout.setMinimumSize(d);
m_layout.setPreferredSize(d);
m_logPanel = new KFLogPanel();
setUpLogPanel(m_logPanel);
Dimension d2 = new Dimension(100, 170);
m_logPanel.setPreferredSize(d2);
m_logPanel.setMinimumSize(d2);
m_filePath = new File("-NONE-");
JSplitPane p2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, p1, m_logPanel);
p2.setOneTouchExpandable(true);
p2.setDividerLocation(0.7);
// p2.setDividerLocation(500);
p2.setResizeWeight(1.0);
add(p2, BorderLayout.CENTER);
}
/**
* Get a list of the steps (wrapped in {@code StepVisual} instances) that make
* up the flow rendered/edited by this panel
*
* @return a list of steps
*/
protected List getRenderGraph() {
return m_renderGraph;
}
/**
* Get the main perspective that owns this layout
*
* @return the main perspective
*/
protected MainKFPerspective getMainPerspective() {
return m_mainPerspective;
}
/**
* Get the step currently being "edited". Returns null if no step is being
* edited
*
* @return the step being edited
*/
protected StepVisual getEditStep() {
return m_editStep;
}
/**
* Set the step to "edit"
*
* @param step the step to edit
*/
protected void setEditStep(StepVisual step) {
m_editStep = step;
}
/**
* If the user has initiated the connection process, then this method returns
* the name of the connection involved
*
* @return the name of the connection if the user has initiated the connection
* process
*/
protected String getEditConnection() {
return m_editConnection;
}
/**
* Set the name of the connection involved in a connection operation
*
* @param connName the name of the connection
*/
protected void setEditConnection(String connName) {
m_editConnection = connName;
}
/**
* Get the list of selected steps. The list will be empty if there are no
* selected (highlighted) steps on the canvas.
*
* @return the list of selected steps
*/
protected List getSelectedSteps() {
return m_selectedSteps;
}
/**
* Set a list of steps to be considered "selected". Setting an empty list
* clears any current selection.
*
* @param selected a list of steps to be considered as selected
*/
protected void setSelectedSteps(List selected) {
// turn off any set ones
for (StepVisual s : m_selectedSteps) {
s.setDisplayConnectors(false);
}
m_selectedSteps = selected;
// highlight any new ones
for (StepVisual s : m_selectedSteps) {
s.setDisplayConnectors(true);
}
if (m_selectedSteps.size() > 0) {
m_mainPerspective.getMainToolBar().enableWidgets(
MainKFPerspectiveToolBar.Widgets.CUT_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.COPY_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.DELETE_BUTTON.toString());
} else {
m_mainPerspective.getMainToolBar().disableWidgets(
MainKFPerspectiveToolBar.Widgets.CUT_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.COPY_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.DELETE_BUTTON.toString());
}
}
/**
* Removes the currently selected list of steps from the layout
*
* @throws WekaException if a problem occurs
*/
protected void removeSelectedSteps() throws WekaException {
addUndoPoint();
for (StepVisual v : m_selectedSteps) {
m_flow.removeStep(v.getStepManager());
m_renderGraph.remove(v);
m_layout.remove(v);
String key =
v.getStepName() + "$" + v.getStepManager().getManagedStep().hashCode();
m_logPanel.statusMessage(key + "|remove");
}
setSelectedSteps(new ArrayList());
m_mainPerspective.getMainToolBar().disableWidgets(
MainKFPerspectiveToolBar.Widgets.DELETE_BUTTON.toString());
m_mainPerspective.getMainToolBar().enableWidget(
MainKFPerspectiveToolBar.Widgets.SELECT_ALL_BUTTON.toString(),
m_flow.size() > 0);
m_layout.repaint();
}
/**
* Copies the currently selected list of steps to the global clipboard
*
* @throws WekaException if a problem occurs
*/
protected void copySelectedStepsToClipboard() throws WekaException {
copyStepsToClipboard(getSelectedSteps());
}
/**
* Copies the supplied list of steps to the global clipboard
*
* @param steps the steps to copy to the clipboard
* @throws WekaException if a problem occurs
*/
protected void copyStepsToClipboard(List steps)
throws WekaException {
m_mainPerspective.copyStepsToClipboard(steps);
}
/**
* Pastes the contents (if any) of the global clipboard to this layout
*
* @param x the x coordinate to paste at
* @param y the y cooridinate to paste at
* @throws WekaException if a problem occurs
*/
protected void pasteFromClipboard(int x, int y) throws WekaException {
addUndoPoint();
Flow fromPaste = Flow.JSONToFlow(m_mainPerspective.getPasteBuffer(), true);
List added = addAll(fromPaste.getSteps(), false);
// adjust x,y coords of pasted steps. Look for the smallest
// x and the smallest y (top left corner of bounding box)
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
for (StepVisual v : added) {
if (v.getX() < minX) {
minX = v.getX();
}
if (v.getY() < minY) {
minY = v.getY();
}
}
int deltaX = x - minX;
int deltaY = y - minY;
for (StepVisual v : added) {
v.setX(v.getX() + deltaX);
v.setY(v.getY() + deltaY);
}
m_layout.revalidate();
m_layout.repaint();
setSelectedSteps(added);
}
/**
* Add an undo point
*/
protected void addUndoPoint() {
try {
File tempFile =
File.createTempFile("knowledgeflow",
MainKFPerspective.FILE_EXTENSION_JSON);
tempFile.deleteOnExit();
JSONFlowUtils.writeFlow(m_flow, tempFile);
m_undoBuffer.push(tempFile);
if (m_undoBuffer.size() > m_mainPerspective.getSetting(
KFDefaults.MAX_UNDO_POINTS_KEY, KFDefaults.MAX_UNDO_POINTS)) {
m_undoBuffer.remove(0);
}
m_mainPerspective.getMainToolBar().enableWidgets(
MainKFPerspectiveToolBar.Widgets.UNDO_BUTTON.toString());
} catch (Exception ex) {
m_logPanel
.logMessage("[KnowledgeFlow] a problem occurred while trying to "
+ "create an undo point : " + ex.getMessage());
}
}
/**
* Get the number of entries in the undo stack
*
* @return the number of entries in the undo stack
*/
protected int getUndoBufferSize() {
return m_undoBuffer.size();
}
/**
* Snap the selected steps (if any) to the grid
*/
protected void snapSelectedToGrid() {
if (m_selectedSteps.size() > 0) {
m_layout.snapSelectedToGrid();
}
}
/**
* Initiate the process of adding a note to the layout
*/
protected void initiateAddNote() {
m_layout.initiateAddNote();
}
/**
* Get the flow being edited by this layout
*
* @return the flow being edited by this layout
*/
public Flow getFlow() {
return m_flow;
}
/**
* Set the flow to edit in this layout
*
* @param flow the flow to edit in this layout
*/
public void setFlow(Flow flow) {
m_flow = flow;
m_renderGraph.clear();
Iterator iter = m_flow.iterator();
m_layout.removeAll();
while (iter.hasNext()) {
StepManagerImpl manager = iter.next();
StepVisual visual = StepVisual.createVisual(manager);
manager.setStepVisual(visual);
m_renderGraph.add(visual);
m_layout.add(visual);
}
m_mainPerspective.getMainToolBar().enableWidget(
MainKFPerspectiveToolBar.Widgets.SELECT_ALL_BUTTON.toString(),
m_flow.size() > 0);
m_layout.revalidate();
m_layout.repaint();
}
/**
* Add all the supplied steps to the flow managed by this layout
*
* @param steps the steps to add
* @return a list of all the added steps, where each has been wrapped in an
* appropriate {@code StepVisual} instance.
*/
protected List addAll(List steps) {
return addAll(steps, true);
}
/**
* Add all the supplied steps to the flow managed by this layout
*
* @param steps the steps to add
* @param revalidate true if the GUI should be repainted
* @return a list of all the added steps, where each has been wrapped in an
* appropriate {@code StepVisual} instance.
*/
protected List addAll(List steps,
boolean revalidate) {
List added = new ArrayList();
m_flow.addAll(steps);
for (StepManagerImpl s : steps) {
StepVisual visual = StepVisual.createVisual(s);
s.setStepVisual(visual);
added.add(visual);
m_renderGraph.add(visual);
m_layout.add(visual);
}
if (revalidate) {
m_layout.repaint();
}
return added;
}
/**
* Add the supplied step to the flow managed by this layout
*
* @param manager the {@code StepManager} instance managing the step to be
* added
* @param x the x coordinate to add at
* @param y the y coordinate to add at
*/
protected void addStep(StepManagerImpl manager, int x, int y) {
m_flow.addStep(manager);
StepVisual visual = StepVisual.createVisual(manager);
Dimension d = visual.getPreferredSize();
int dx = (int) (d.getWidth() / 2);
int dy = (int) (d.getHeight() / 2);
x -= dx;
y -= dy;
if (x >= 0 && y >= 0) {
visual.setX(x);
visual.setY(y);
}
// manager will overwrite x and y if this step has been sourced
// from JSON and has valid x, y settings
manager.setStepVisual(visual);
m_renderGraph.add(visual);
m_layout.add(visual);
visual.setLocation(x, y);
m_mainPerspective.setCursor(Cursor
.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
m_mainPerspective.getMainToolBar().enableWidget(
MainKFPerspectiveToolBar.Widgets.SELECT_ALL_BUTTON.toString(),
m_flow.size() > 0);
}
/**
* Connect the supplied source step to the supplied target step using the
* specified connection type
*
* @param source the {@code StepManager} instance managing the source step
* @param target the {@code StepManager} instance managing the target step
* @param connectionType the connection type to use
*/
public void connectSteps(StepManagerImpl source, StepManagerImpl target,
String connectionType) {
if (m_mainPerspective.getDebug()) {
System.err.println("[KF] connecting steps: " + source.getName() + " to "
+ target.getName());
}
boolean success = m_flow.connectSteps(source, target, connectionType);
if (m_mainPerspective.getDebug()) {
if (success) {
System.err.println("[KF] connection successful");
} else {
System.err.println("[KF] connection failed");
}
}
m_layout.repaint();
}
/**
* Rename a step
*
* @param oldName the old name of the step to rename
* @param newName the new name to give the step
*/
protected void renameStep(String oldName, String newName) {
try {
m_flow.renameStep(oldName, newName);
} catch (WekaException ex) {
m_mainPerspective.showErrorDialog(ex);
}
}
/**
* Remove a step from the flow displayed/edited by this layout
*
* @param step the {@code StepVisual} instance wrapping the step to be removed
* @throws WekaException if a problem occurs
*/
protected void removeStep(StepVisual step) throws WekaException {
m_flow.removeStep(step.getStepManager());
m_renderGraph.remove(step);
m_layout.remove(step);
m_layout.repaint();
}
/**
* Get the number of steps in the layout
*
* @return the number of steps in the layout
*/
protected int numSteps() {
return m_renderGraph.size();
}
/**
* Get the environment variables being used by this layout
*
* @return the environment variables being used by this layout
*/
public Environment getEnvironment() {
return m_env;
}
/**
* Set the environment variables to use with this layout
*
* @param env the environment variables to use
*/
public void setEnvironment(Environment env) {
m_env = env;
}
public String environmentSubstitute(String source) {
Environment env = m_env != null ? m_env : Environment.getSystemWide();
try {
source = env.substitute(source);
} catch (Exception ex) {
}
return source;
}
/**
* Get the {@code FlowExecutor} being used for execution of this flow
*
* @return the {@code FlowExecutor} in use by this layout
*/
public FlowExecutor getFlowExecutor() {
return m_flowExecutor;
}
/**
* Set the {@code FlowExcecutor} to use for executing the flow
*
* @param executor the {@code FlowExecutor} to use for executing the flow in
* this layout
*/
public void setFlowExecutor(FlowExecutor executor) {
m_flowExecutor = executor;
}
/**
* Get the current path (if any) of the flow being edited in this layout
*
* @return the current path on disk of the flow
*/
public File getFilePath() {
return m_filePath;
}
/**
* Set the file path for the flow being edited by this layout
*
* @param path the path on disk for the flow being edited
*/
public void setFilePath(File path) {
m_filePath = path != null ? path : new File("-NONE-");
if (path != null) {
File absolute = new File(path.getAbsolutePath());
getEnvironment().addVariable(KFGUIConsts.FLOW_DIRECTORY_KEY,
absolute.getParent());
}
}
/**
* Get the log panel in use by this layout
*
* @return the log panel
*/
public KFLogPanel getLogPanel() {
return m_logPanel;
}
/**
* Get the current zoom setting for this layout
*
* @return the current zoom setting
*/
public int getZoomSetting() {
return m_zoomSetting;
}
/**
* Set the current zoom setting for this layout
*
* @param zoom the current zoom setting
*/
public void setZoomSetting(int zoom) {
m_zoomSetting = zoom;
}
/**
* Get whether this flow has been altered since the last save operation
*
* @return true if the flow has been altered
*/
public boolean getEdited() {
return m_hasBeenEdited;
}
/**
* Set the edited status of this flow
*
* @param edited true if the flow has been altered
*/
public void setEdited(boolean edited) {
m_hasBeenEdited = edited;
// pass on the edited status so that the tab title can be made
// bold if necessary
m_mainPerspective.setCurrentTabTitleEditedStatus(edited);
}
/**
* Returns true if the flow managed by this layout is currently executing
*
* @return true if the flow is executing
*/
public boolean isExecuting() {
return m_isExecuting;
}
/**
* Get the current flow edit operation
*
* @return the current flow edit operation
*/
protected LayoutOperation getFlowLayoutOperation() {
return m_userOpp;
}
/**
* Set the current flow edit operation
*
* @param mode the current flow edit operation
*/
protected void setFlowLayoutOperation(LayoutOperation mode) {
m_userOpp = mode;
}
/**
* Execute the flow managed by this layout
*
* @param sequential true if the flow's start points are to be launched
* sequentially rather than in parallel
* @throws WekaException if a problem occurs
*/
public synchronized void executeFlow(boolean sequential) throws WekaException {
if (isExecuting()) {
throw new WekaException("The flow is already executing!");
}
Settings appSettings =
m_mainPerspective.getMainApplication().getApplicationSettings();
if (m_flowExecutor == null) {
String execName =
appSettings.getSetting(KFDefaults.APP_ID,
KnowledgeFlowApp.KnowledgeFlowGeneralDefaults.EXECUTION_ENV_KEY,
KnowledgeFlowApp.KnowledgeFlowGeneralDefaults.EXECUTION_ENV);
BaseExecutionEnvironment execE = null;
try {
execE =
(BaseExecutionEnvironment) PluginManager.getPluginInstance(
BaseExecutionEnvironment.class.getCanonicalName(), execName);
} catch (Exception ex) {
// drop through
}
if (execE == null) {
execE = new BaseExecutionEnvironment();
}
m_flowExecutor = execE.getDefaultFlowExecutor();
/*
* m_flowExecutor = new FlowRunner(m_mainPerspective.getMainApplication()
* .getApplicationSettings());
*/
m_flowExecutor.setLogger(m_logPanel);
m_flowExecutor
.addExecutionFinishedCallback(new ExecutionFinishedCallback() {
@Override
public void executionFinished() {
m_isExecuting = false;
m_logPanel.statusMessage("@!@[KnowledgeFlow]|OK.");
if (m_flowExecutor.wasStopped()) {
m_logPanel.setMessageOnAll(false, "Stopped.");
}
m_mainPerspective.getMainToolBar().enableWidgets(
MainKFPerspectiveToolBar.Widgets.PLAY_PARALLEL_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.PLAY_SEQUENTIAL_BUTTON
.toString());
m_mainPerspective.getMainToolBar().disableWidgets(
MainKFPerspectiveToolBar.Widgets.STOP_BUTTON.toString());
}
});
}
m_flowExecutor.setSettings(appSettings);
m_mainPerspective.getMainToolBar().disableWidgets(
MainKFPerspectiveToolBar.Widgets.PLAY_PARALLEL_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.PLAY_SEQUENTIAL_BUTTON.toString());
m_mainPerspective.getMainToolBar().enableWidgets(
MainKFPerspectiveToolBar.Widgets.STOP_BUTTON.toString());
m_flowExecutor.getExecutionEnvironment().setEnvironmentVariables(m_env);
m_flowExecutor.getExecutionEnvironment().setHeadless(false);
m_flowExecutor.getExecutionEnvironment()
.setGraphicalEnvironmentCommandHandler(
new KFGraphicalEnvironmentCommandHandler(m_mainPerspective));
m_isExecuting = true;
// Flow toRun = m_flow.copyFlow();
m_flowExecutor.setFlow(m_flow);
m_logPanel.clearStatus();
m_logPanel.statusMessage("@!@[KnowledgeFlow]|Executing...");
if (sequential) {
m_flowExecutor.runSequentially();
} else {
m_flowExecutor.runParallel();
}
}
/**
* Stop the flow from executing
*/
public void stopFlow() {
if (isExecuting()) {
m_flowExecutor.stopProcessing();
}
}
/**
* Find the first step whose bounds enclose the supplied point
*
* @param p the point
* @return the first step in the flow whose visible bounds enclose the
* supplied point, or null if no such step exists
*/
protected StepVisual findStep(Point p) {
Rectangle tempBounds = new Rectangle();
for (StepVisual v : m_renderGraph) {
tempBounds = v.getBounds();
if (tempBounds.contains(p)) {
return v;
}
}
return null;
}
/**
* Find a list of steps that exist within the supplied bounding box
*
* @param boundingBox the bounding box to check
* @return a list of steps that fall within the bounding box
*/
protected List findSteps(Rectangle boundingBox) {
List steps = new ArrayList();
for (StepVisual v : m_renderGraph) {
int centerX = v.getX() + (v.getWidth() / 2);
int centerY = v.getY() + (v.getHeight() / 2);
if (boundingBox.contains(centerX, centerY)) {
steps.add(v);
}
}
return steps;
}
/**
* Find a list of steps in the flow that can accept the supplied connection
* type
*
* @param connectionName the type of connection to check for
* @return a list of steps that can accept the supplied connection type
*/
protected List findStepsThatCanAcceptConnection(
String connectionName) {
List result = new ArrayList();
for (StepManagerImpl step : m_flow.getSteps()) {
List incomingConnNames =
step.getManagedStep().getIncomingConnectionTypes();
if (incomingConnNames != null
&& incomingConnNames.contains(connectionName)) {
result.add(step);
}
}
return result;
}
/**
* Find all connections within delta of the supplied point
*
* @param point the point on the canvas to find steps at
* @param delta the radius around point for detecting connections
* @return a map keyed by connection type name of connected steps. The value
* is a list of 2 element arrays, where each array contains source and
* target steps for the connection in question
*/
protected Map> findClosestConnections(
Point point, int delta) {
Map> closestConnections =
new HashMap>();
for (StepManagerImpl sourceManager : m_flow.getSteps()) {
for (Map.Entry> outCons : sourceManager
.getOutgoingConnections().entrySet()) {
List targetsOfConnType = outCons.getValue();
for (StepManager target : targetsOfConnType) {
StepManagerImpl targetManager = (StepManagerImpl) target;
String connName = outCons.getKey();
StepVisual sourceVisual = sourceManager.getStepVisual();
StepVisual targetVisual = targetManager.getStepVisual();
Point bestSourcePt =
sourceVisual.getClosestConnectorPoint(new Point(targetVisual.getX()
+ targetVisual.getWidth() / 2, targetVisual.getY()
+ targetVisual.getHeight() / 2));
Point bestTargetPt =
targetVisual.getClosestConnectorPoint(new Point(sourceVisual.getX()
+ sourceVisual.getWidth() / 2, sourceVisual.getY()
+ sourceVisual.getHeight() / 2));
int minx = (int) Math.min(bestSourcePt.getX(), bestTargetPt.getX());
int maxx = (int) Math.max(bestSourcePt.getX(), bestTargetPt.getX());
int miny = (int) Math.min(bestSourcePt.getY(), bestTargetPt.getY());
int maxy = (int) Math.max(bestSourcePt.getY(), bestTargetPt.getY());
// check to see if supplied pt is inside bounding box
if (point.getX() >= minx - delta && point.getX() <= maxx + delta
&& point.getY() >= miny - delta && point.getY() <= maxy + delta) {
// now see if the point is within delta of the line
// formulate ax + by + c = 0
double a = bestSourcePt.getY() - bestTargetPt.getY();
double b = bestTargetPt.getX() - bestSourcePt.getX();
double c =
(bestSourcePt.getX() * bestTargetPt.getY())
- (bestTargetPt.getX() * bestSourcePt.getY());
double distance =
Math.abs((a * point.getX()) + (b * point.getY()) + c);
distance /= Math.abs(Math.sqrt((a * a) + (b * b)));
if (distance <= delta) {
List conList =
closestConnections.get(connName);
if (conList == null) {
conList = new ArrayList();
closestConnections.put(connName, conList);
}
StepManagerImpl[] conn = { sourceManager, targetManager };
conList.add(conn);
}
}
}
}
}
return closestConnections;
}
/**
* Returns true if there is a previous (prior to index) connection to the
* supplied target step in the supplied map of connections.
*
*
* @param outConns the map of connections to check
* @param target the target step to check for
* @param index connections to the target prior to this index in the map count
* @return true if a previous connection is found
*/
protected boolean previousConn(Map> outConns,
StepManagerImpl target, int index) {
boolean result = false;
int count = 0;
for (Entry> e : outConns.entrySet()) {
List connectedSteps = e.getValue();
for (StepManager c : connectedSteps) {
StepManagerImpl cI = (StepManagerImpl) c;
if (target.getManagedStep() == cI.getManagedStep() && count < index) {
result = true;
break;
}
}
if (result) {
break;
}
count++;
}
return result;
}
private void setUpLogPanel(final LogPanel logPanel) {
String date =
(new SimpleDateFormat("EEEE, d MMMM yyyy")).format(new Date());
logPanel.logMessage("Weka Knowledge Flow was written by Mark Hall");
logPanel.logMessage("Weka Knowledge Flow");
logPanel.logMessage("(c) 2002-" + Copyright.getToYear() + " "
+ Copyright.getOwner() + ", " + Copyright.getAddress());
logPanel.logMessage("web: " + Copyright.getURL());
logPanel.logMessage(date);
logPanel
.statusMessage("@!@[KnowledgeFlow]|Welcome to the Weka Knowledge Flow");
logPanel.getStatusTable().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (logPanel.getStatusTable().rowAtPoint(e.getPoint()) == 0) {
if (((e.getModifiers() & InputEvent.BUTTON1_MASK) != InputEvent.BUTTON1_MASK)
|| e.isAltDown()) {
System.gc();
Runtime currR = Runtime.getRuntime();
long freeM = currR.freeMemory();
long totalM = currR.totalMemory();
long maxM = currR.maxMemory();
logPanel
.logMessage("[KnowledgeFlow] Memory (free/total/max.) in bytes: "
+ String.format("%,d", freeM) + " / "
+ String.format("%,d", totalM) + " / "
+ String.format("%,d", maxM));
logPanel
.statusMessage("@!@[KnowledgeFlow]|Memory (free/total/max.) in bytes: "
+ String.format("%,d", freeM)
+ " / "
+ String.format("%,d", totalM)
+ " / "
+ String.format("%,d", maxM));
}
}
}
});
}
/**
* Save the flow managed by this layout
*
* @param showDialog true if a file dialog should be displayed
*/
protected void saveLayout(boolean showDialog) {
boolean shownDialog = false;
int returnVal = JFileChooser.APPROVE_OPTION;
File sFile = getFilePath();
if (showDialog || sFile.getName().equals("-NONE-")) {
returnVal = m_mainPerspective.m_saveFileChooser.showSaveDialog(this);
shownDialog = true;
}
if (returnVal == JFileChooser.APPROVE_OPTION) {
if (shownDialog) {
sFile = m_mainPerspective.m_saveFileChooser.getSelectedFile();
}
// add extension if necessary
if (!sFile.getName().toLowerCase().endsWith(".kf")) {
sFile = new File(sFile.getParent(), sFile.getName() + ".kf");
}
try {
String fName = sFile.getName();
if (fName.indexOf(".") > 0) {
fName = fName.substring(0, fName.lastIndexOf('.'));
}
m_flow.setFlowName(fName.replace(".kf", ""));
m_flow.saveFlow(sFile);
setFilePath(sFile);
setEdited(false);
m_mainPerspective.setCurrentTabTitle(fName);
} catch (WekaException e) {
m_mainPerspective.showErrorDialog(e);
}
}
}
/**
* Pop an undo point and load the flow it encapsulates
*/
protected void popAndLoadUndo() {
if (m_undoBuffer.size() > 0) {
File undo = m_undoBuffer.pop();
if (m_undoBuffer.size() == 0) {
m_mainPerspective.getMainToolBar().disableWidgets(
MainKFPerspectiveToolBar.Widgets.UNDO_BUTTON.toString());
}
loadLayout(undo, true);
}
}
/**
* Load a flow into this layout
*
* @param fFile the file containing the flow
* @param isUndo true if this is an "undo" layout
*/
protected void loadLayout(File fFile, boolean isUndo) {
stopFlow();
m_mainPerspective.getMainToolBar().disableWidgets(
MainKFPerspectiveToolBar.Widgets.PLAY_PARALLEL_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.PLAY_SEQUENTIAL_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.SAVE_FLOW_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.SAVE_FLOW_AS_BUTTON.toString());
if (!isUndo) {
File absolute = new File(fFile.getAbsolutePath());
getEnvironment().addVariable("Internal.knowledgeflow.directory",
absolute.getParent());
}
try {
Flow flow = Flow.loadFlow(fFile, m_logPanel);
setFlow(flow);
if (!isUndo) {
setFilePath(fFile);
}
if (!getFlow().getFlowName().equals("Untitled")) {
m_mainPerspective.setCurrentTabTitle(getFlow().getFlowName());
}
} catch (WekaException e) {
m_logPanel
.statusMessage("@!@[KnowledgeFlow]|Unable to load flow (see log).");
m_logPanel.logMessage("[KnowledgeFlow] Unable to load flow\n"
+ LogManager.stackTraceToString(e));
m_mainPerspective.showErrorDialog(e);
}
m_mainPerspective.getMainToolBar().enableWidgets(
MainKFPerspectiveToolBar.Widgets.PLAY_PARALLEL_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.PLAY_SEQUENTIAL_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.SAVE_FLOW_BUTTON.toString(),
MainKFPerspectiveToolBar.Widgets.SAVE_FLOW_AS_BUTTON.toString());
m_mainPerspective.getMainToolBar().enableWidget(
MainKFPerspectiveToolBar.Widgets.SELECT_ALL_BUTTON.toString(),
m_flow.size() > 0);
}
/**
* Editing operations on the layout
*/
protected static enum LayoutOperation {
NONE, MOVING, CONNECTING, ADDING, SELECTING, PASTING;
}
/**
* Small subclass of LogPanel for use by layouts
*/
protected class KFLogPanel extends LogPanel {
/** For serialization */
private static final long serialVersionUID = -2224509243343105276L;
public synchronized void
setMessageOnAll(boolean mainKFLine, String message) {
for (String key : m_tableIndexes.keySet()) {
if (!mainKFLine && key.equals("[KnowledgeFlow]")) {
continue;
}
String tm = key + "|" + message;
statusMessage(tm);
}
}
}
/**
* Utility method to serialize a list of steps (encapsulated in StepVisuals)
* to a JSON flow.
*
* @param steps the steps to serialize
* @param name the name to set in the encapsulating Flow before serializing
* @return the serialized Flow
* @throws WekaException if a problem occurs
*/
public static String
serializeStepsToJSON(List steps, String name)
throws WekaException {
if (steps.size() > 0) {
List toCopy = new ArrayList();
for (StepVisual s : steps) {
toCopy.add(s.getStepManager());
}
Flow temp = new Flow();
temp.setFlowName("Clipboard copy");
temp.addAll(toCopy);
return JSONFlowUtils.flowToJSON(temp);
}
throw new WekaException("No steps to serialize!");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy