Skip to content

Ninniku IT Hub

Provide open-source solutions for businesses.

Menu
  • Home
  • Technical Support
  • Traning
    • Arduino for IoT and ERP Integration
  • Expert Certification
  • Plug-ins (Taiwan)
    • Accounting for Taiwan
    • Meeting Room Booking
Menu

Workflow Editor 增欄位數量

Posted on 2022-09-23

iDempiere ERP. Workflow Editor 預設的編輯的欄位數為4個。 (圖 1)
在較複雜的Workflow設計圖時,可能就不敷使用。本篇文章說明如何修改Soruce code來增加欄位。
在 JIRA 提供 Patch檔或參考下列說明。
https://idempiere.atlassian.net/browse/IDEMPIERE-5431

圖 1

我們在工作列上增加一個 NumberBox,可以用來任意調整Workflow 畫布的欄位數。變更後按Refresh即可變更畫布欄位數。(圖 2)
畫布欄位數預設值為 4, 也可以透過System Configuration 來設定預設值 (關鍵字為 WORKFLOW_EDITOR_COLUMNS)

圖 2
org.adempiere.webui.apps.wf.WFNodeContainer 增加一個 setNoOfColumns method
        public int getNoOfColumns() {
		return noOfColumns;
	}

	public void setNoOfColumns(int noOfColumns) {
		this.noOfColumns = noOfColumns;
	}

org.adempiere.webui.apps.wf.WFEditor
增加一個 NumbreBox

private NumberBox columnsBox;

在initForm method中,將NumberBox 加入Toolbar
NumberBox預設值為4,

columnsBox = new NumberBox(true);
columnsBox.setValue(MSysConfig.getIntValue("WORKFLOW_EDITOR_COLUMNS", 4,Env.getAD_Client_ID(Env.getCtx())));
toolbar.appendChild(columnsBox);

在 load method 中加入

nodeContainer.setNoOfColumns(columnsBox.getValue().intValue());
for(int c = 0; c < 4; c++) {
改成下列程式碼
for(int c = 0; c < columnsBox.getValue().intValue(); c++) {

WFNodeContainer及WFEditor 完整程式如下。

/******************************************************************************
 * Copyright (C) 2008 Low Heng Sin                                            *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. 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, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 *****************************************************************************/
package org.adempiere.webui.apps.wf;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;

import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.component.ConfirmPanel;
import org.adempiere.webui.component.ListItem;
import org.adempiere.webui.component.Listbox;
import org.adempiere.webui.component.ListboxFactory;
import org.adempiere.webui.component.NumberBox;
import org.adempiere.webui.component.Textbox;
import org.adempiere.webui.component.ToolBar;
import org.adempiere.webui.component.Window;
import org.adempiere.webui.event.DialogEvents;
import org.adempiere.webui.panel.ADForm;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.ZKUpdateUtil;
import org.compiere.apps.wf.WFGraphLayout;
import org.compiere.apps.wf.WFNodeWidget;
import org.compiere.model.MRole;
import org.compiere.model.MSysConfig;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg;
import org.compiere.util.Util;
import org.compiere.wf.MWFNode;
import org.compiere.wf.MWFNodeNext;
import org.compiere.wf.MWorkflow;
import org.zkoss.zhtml.Table;
import org.zkoss.zhtml.Td;
import org.zkoss.zhtml.Tr;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.DropEvent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Borderlayout;
import org.zkoss.zul.Center;
import org.zkoss.zul.Div;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Menupopup;
import org.zkoss.zul.North;
import org.zkoss.zul.Separator;
import org.zkoss.zul.South;
import org.zkoss.zul.Space;
import org.zkoss.zul.Toolbarbutton;
import org.zkoss.zul.Vbox;

/**
 *
 * @author Low Heng Sin
 *
 */
public class WFEditor extends ADForm {
	/**
	 * 
	 */
	private static final long serialVersionUID = 4293422396394778274L;

	private Listbox workflowList;
	private int m_workflowId = 0;
	private Toolbarbutton zoomButton;
	private Toolbarbutton refreshButton;
	private Toolbarbutton newButton;
	private Table table;
	private Center center;
	private MWorkflow m_wf;
	private WFNodeContainer nodeContainer;
	private NumberBox columnsBox;
	@Override
	protected void initForm() {
		ZKUpdateUtil.setHeight(this, "100%");
		Borderlayout layout = new Borderlayout();
		layout.setStyle("width: 100%; height: 100%; position: relative;");
		appendChild(layout);
		String sql;
		boolean isBaseLanguage = Env.isBaseLanguage(Env.getCtx(), "AD_Workflow");
		if (isBaseLanguage)
			sql = MRole.getDefault().addAccessSQL(
				"SELECT AD_Workflow_ID, Name FROM AD_Workflow WHERE IsActive='Y' ORDER BY 2",
				"AD_Workflow", MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);	//	all
		else
			sql = MRole.getDefault().addAccessSQL(
					"SELECT AD_Workflow.AD_Workflow_ID, AD_Workflow_Trl.Name FROM AD_Workflow INNER JOIN AD_Workflow_Trl ON (AD_Workflow.AD_Workflow_ID=AD_Workflow_Trl.AD_Workflow_ID) "
					+ " WHERE AD_Workflow.IsActive='Y' AND AD_Workflow_Trl.AD_Language='"+Env.getAD_Language(Env.getCtx())+"' ORDER BY 2","AD_Workflow", MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO);	//	all
		KeyNamePair[] pp = DB.getKeyNamePairs(sql, true);

		workflowList = ListboxFactory.newDropdownListbox();
		for (KeyNamePair knp : pp) {
			workflowList.addItem(knp);
		}
		workflowList.addEventListener(Events.ON_SELECT, this);

		North north = new North();
		layout.appendChild(north);
		ToolBar toolbar = new ToolBar();
		north.appendChild(toolbar);
		toolbar.appendChild(workflowList);
		// Zoom
		zoomButton = new Toolbarbutton();
		if (ThemeManager.isUseFontIconForImage())
			zoomButton.setIconSclass("z-icon-Zoom");
		else
			zoomButton.setImage(ThemeManager.getThemeResource("images/Zoom16.png"));
		toolbar.appendChild(zoomButton);
		zoomButton.addEventListener(Events.ON_CLICK, this);
		zoomButton.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Zoom")));
		// New Node
		newButton = new Toolbarbutton();
		if (ThemeManager.isUseFontIconForImage())
			newButton.setIconSclass("z-icon-New");
		else
			newButton.setImage(ThemeManager.getThemeResource("images/New16.png"));
		toolbar.appendChild(newButton);
		newButton.addEventListener(Events.ON_CLICK, this);
		newButton.setTooltiptext(Msg.getMsg(Env.getCtx(), "CreateNewNode"));
		// Refresh
		refreshButton = new Toolbarbutton();
		if (ThemeManager.isUseFontIconForImage())
			refreshButton.setIconSclass("z-icon-Refresh");
		else
			refreshButton.setImage(ThemeManager.getThemeResource("images/Refresh16.png"));
		toolbar.appendChild(refreshButton);
		refreshButton.addEventListener(Events.ON_CLICK, this);
		refreshButton.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Refresh")));
		ZKUpdateUtil.setHeight(north, "30px");
	
		columnsBox = new NumberBox(true);
	    columnsBox.setValue(MSysConfig.getIntValue("WORKFLOW_EDITOR_COLUMNS", 4,Env.getAD_Client_ID(Env.getCtx())));
		toolbar.appendChild(columnsBox);
		createTable();
		center = new Center();
		layout.appendChild(center);
		center.setAutoscroll(true);
		center.appendChild(table);

		ConfirmPanel confirmPanel = new ConfirmPanel(true);
		confirmPanel.addActionListener(this);
		South south = new South();
		layout.appendChild(south);
		south.appendChild(confirmPanel);
		ZKUpdateUtil.setHeight(south, "36px");
	}

	private void createTable() {
		table = new Table();
		table.setDynamicProperty("cellpadding", "0");
		table.setDynamicProperty("cellspacing", "0");
		table.setDynamicProperty("border", "none");
		table.setStyle("margin:0;padding:0");
	}

	@Override
	public void onEvent(Event event) throws Exception {
		if (event.getTarget().getId().equals(ConfirmPanel.A_CANCEL))
			this.detach();
		else if (event.getTarget().getId().equals(ConfirmPanel.A_OK))
			this.detach();
		else if (event.getTarget() == workflowList) {
			center.removeChild(table);
			createTable();
			center.appendChild(table);
			ListItem item = workflowList.getSelectedItem();
			KeyNamePair knp = item != null ? item.toKeyNamePair() : null;
			if (knp != null && knp.getKey() > 0) {
				load(knp.getKey(), true);
			}
		}
		else if (event.getTarget() == zoomButton) {
			if (workflowList.getSelectedIndex() > 0)
				zoom();
		}
		else if (event.getTarget() == refreshButton) {
			if (workflowList.getSelectedIndex() > 0)
				reload(m_workflowId, true);
		}
		else if (event.getTarget() == newButton) {
			if (workflowList.getSelectedIndex() > 0)
				createNewNode();
		}
		else if (event.getTarget() instanceof WFPopupItem) {
			WFPopupItem item = (WFPopupItem) event.getTarget();
			item.execute(this);
		}
		else if (event.getName().equals(Events.ON_DROP)) {
			DropEvent dropEvent = (DropEvent) event;
			Integer AD_WF_Node_ID = (Integer) dropEvent.getDragged().getAttribute("AD_WF_Node_ID");
			Integer xPosition = (Integer) event.getTarget().getAttribute("Node.XPosition");
			Integer yPosition = (Integer) event.getTarget().getAttribute("Node.YPosition");
			if (AD_WF_Node_ID != null) {
				WFNodeWidget widget = (WFNodeWidget) nodeContainer.getGraphScene().findWidget(AD_WF_Node_ID);
				if (widget != null) {
					widget.getModel().setXPosition(xPosition);
					widget.getModel().setYPosition(yPosition);
					widget.getModel().saveEx();
					reload(m_workflowId, true);
				}
			}
		}
	}

	private void createNewNode() {
		String nameLabel = Msg.getElement(Env.getCtx(), MWFNode.COLUMNNAME_Name);
		String title = Msg.getMsg(Env.getCtx(), "CreateNewNode");
		final Window w = new Window();
		w.setTitle(title);
		Vbox vbox = new Vbox();
		w.appendChild(vbox);
		vbox.appendChild(new Separator());
		Hbox hbox = new Hbox();
		hbox.appendChild(new Label(nameLabel));
		hbox.appendChild(new Space());
		final Textbox text = new Textbox();
		hbox.appendChild(text);
		vbox.appendChild(hbox);
		vbox.appendChild(new Separator());
		final ConfirmPanel panel = new ConfirmPanel(true, false, false, false, false, false, false);
		vbox.appendChild(panel);
		panel.addActionListener(Events.ON_CLICK, new EventListener<Event>() {

			public void onEvent(Event event) throws Exception {
				if (event.getTarget() == panel.getButton(ConfirmPanel.A_CANCEL)) {
					text.setText("");
				}
				w.onClose();
			}
		});
		
		ZKUpdateUtil.setWidth(w, "250px");
		w.setBorder("normal");
		w.setPage(this.getPage());
		w.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener<Event>() {

			@Override
			public void onEvent(Event event) throws Exception {
				String name = text.getText();
				if (name != null && name.length() > 0)
				{
					int AD_Client_ID = Env.getAD_Client_ID(Env.getCtx());
					MWFNode node = new MWFNode(m_wf, name, name);
					node.setClientOrg(AD_Client_ID, 0);
					node.saveEx();
					reload(m_wf.getAD_Workflow_ID(), true);
				}
			}
		});
		w.doHighlighted();				
	}

	protected void reload(int workflowId, boolean reread) {
		center.removeChild(table);
		createTable();
		center.appendChild(table);
		load(workflowId, reread);
	}

	private void load(int workflowId, boolean reread) {
		//	Get Workflow
		m_wf = MWorkflow.get(Env.getCtx(), workflowId);
		m_workflowId = workflowId;
		nodeContainer = new WFNodeContainer();
		nodeContainer.setNoOfColumns(columnsBox.getValue().intValue());
		nodeContainer.setWorkflow(m_wf);
		
		if (reread) {
			m_wf.reloadNodes();
		}

		//	Add Nodes for Paint
		MWFNode[] nodes = m_wf.getNodes(true, Env.getAD_Client_ID(Env.getCtx()));
		List<Integer> added = new ArrayList<Integer>();
		for (int i = 0; i < nodes.length; i++)
		{
			if (!added.contains(nodes[i].getAD_WF_Node_ID()))
				nodeContainer.addNode(nodes[i]);
		}
		
		//  Add lines
		for (int i = 0; i < nodes.length; i++)
		{
			MWFNodeNext[] nexts = nodes[i].getTransitions(Env.getAD_Client_ID(Env.getCtx()));
			for (int j = 0; j < nexts.length; j++)
			{
				nodeContainer.addEdge(nexts[j]);
			}
		}

		Dimension dimension = nodeContainer.getDimension();
		BufferedImage bi = new BufferedImage (dimension.width, dimension.height, BufferedImage.TYPE_INT_ARGB);
		Graphics2D graphics = bi.createGraphics();
		nodeContainer.validate(graphics);
		nodeContainer.paint(graphics);

		try {
			int row = nodeContainer.getRowCount();
			for(int i = 0; i < row+1; i++) {
				Tr tr = new Tr();
				table.appendChild(tr);
				for(int c = 0; c < columnsBox.getValue().intValue(); c++) {
					BufferedImage t = new BufferedImage(WFGraphLayout.COLUMN_WIDTH, WFGraphLayout.ROW_HEIGHT, BufferedImage.TYPE_INT_ARGB);
					Graphics2D tg = t.createGraphics();
					Td td = new Td();
					td.setStyle("border: 1px dotted lightgray");
					tr.appendChild(td);
					
					if (i < row)
					{
						int x = c * WFGraphLayout.COLUMN_WIDTH;
						int y = i * WFGraphLayout.ROW_HEIGHT;

						tg.drawImage(bi.getSubimage(x, y, WFGraphLayout.COLUMN_WIDTH, WFGraphLayout.ROW_HEIGHT), 0, 0, null);
						org.zkoss.zul.Image image = new org.zkoss.zul.Image();
						image.setContent(t);
						td.appendChild(image);
						String imgStyle = "border:none;margin:0;padding:0";

						WFNodeWidget widget = nodeContainer.findWidget(i+1, c+1);
						if (widget != null)
						{
							MWFNode node = widget.getModel();
							if (node.getHelp(true) != null) {
								image.setTooltiptext(node.getHelp(true));
							}
							image.setAttribute("AD_WF_Node_ID", node.getAD_WF_Node_ID());
							image.addEventListener(Events.ON_CLICK, new EventListener<Event>() {

								public void onEvent(Event event) throws Exception {
									showNodeMenu(event.getTarget());
								}
							});
							image.setDraggable("WFNode");
							imgStyle = imgStyle + ";cursor:pointer";
						}
						else
						{
							image.setDroppable("WFNode");
							image.addEventListener(Events.ON_DROP, this);
							image.setAttribute("Node.XPosition", c+1);
							image.setAttribute("Node.YPosition", i+1);
						}
						image.setStyle(imgStyle);
					}
					else
					{
						Div div = new Div();
						ZKUpdateUtil.setWidth(div, (WFGraphLayout.COLUMN_WIDTH) + "px");
						ZKUpdateUtil.setHeight(div, (WFGraphLayout.ROW_HEIGHT) + "px");
						div.setAttribute("Node.XPosition", c+1);
						div.setAttribute("Node.YPosition", i+1);
						div.setDroppable("WFNode");
						div.addEventListener(Events.ON_DROP, this);
						td.appendChild(div);
					}

					tg.dispose();
				}
			}

		} catch (Exception e) {
			logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
		}

	}

	protected void showNodeMenu(Component target) {
		Integer AD_WF_Node_ID = (Integer) target.getAttribute("AD_WF_Node_ID");
		if (AD_WF_Node_ID != null) {
			WFNodeWidget widget = (WFNodeWidget) nodeContainer.getGraphScene().findWidget(AD_WF_Node_ID);
			if (widget != null) {
				MWFNode node = widget.getModel();
				Menupopup popupMenu = new Menupopup();
				if (node.getAD_Client_ID() == Env.getAD_Client_ID(Env.getCtx()))
				{
					// Zoom
					addMenuItem(popupMenu, Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Zoom")), node, WFPopupItem.WFPOPUPITEM_ZOOM);
					// Properties
					addMenuItem(popupMenu, Msg.getMsg(Env.getCtx(), "Properties"), node, WFPopupItem.WFPOPUPITEM_PROPERTIES);
					// Delete node
					String title = Msg.getMsg(Env.getCtx(), "DeleteNode") +
						": " + node.getName(true);
					addMenuItem(popupMenu, title, node, WFPopupItem.WFPOPUPITEM_DELETENODE);
				}
				MWFNode[] nodes = m_wf.getNodes(true, Env.getAD_Client_ID(Env.getCtx()));
				MWFNodeNext[] lines = node.getTransitions(Env.getAD_Client_ID(Env.getCtx()));
				//	Add New Line
				for (MWFNode nn : nodes)
				{
					if (nn.getAD_WF_Node_ID() == node.getAD_WF_Node_ID())
						continue;	//	same
					if (nn.getAD_WF_Node_ID() == node.getAD_Workflow().getAD_WF_Node_ID())
						continue;	//	don't add line to starting node
					boolean found = false;
					for (MWFNodeNext line : lines)
					{
						if (nn.getAD_WF_Node_ID() == line.getAD_WF_Next_ID())
						{
							found = true; // line already exists
							break;
						}
					}
					if (!found) {
						// Check that inverse line doesn't exist
						for (MWFNodeNext revline : nn.getTransitions(Env.getAD_Client_ID(Env.getCtx()))) {
							if (node.getAD_WF_Node_ID() == revline.getAD_WF_Next_ID())
							{
								found = true; // inverse line already exists
								break;
							}
						}
					}
					if (!found)
					{
						String title = Msg.getMsg(Env.getCtx(), "AddLine")
							+ ": " + node.getName(true) + " -> " + nn.getName(true);
						addMenuItem(popupMenu, title, node, nn.getAD_WF_Node_ID());
					}
				}
				//	Delete Lines
				for (MWFNodeNext line : lines)
				{
					if (line.getAD_Client_ID() != Env.getAD_Client_ID(Env.getCtx()))
						continue;
					MWFNode next = MWFNode.get(Env.getCtx(), line.getAD_WF_Next_ID());
					String title = Msg.getMsg(Env.getCtx(), "DeleteLine")
						+ ": " + node.getName(true) + " -> " + next.getName(true);
					addMenuItem(popupMenu, title, line);
				}
				popupMenu.setPage(target.getPage());
				popupMenu.open(target);
			}

		}
	}

	/**
	 * 	Zoom to WorkFlow
	 */
	private void zoom()
	{
		if (m_workflowId > 0) {
			AEnv.zoom(MWorkflow.Table_ID, m_workflowId);
		}
	}	//	zoom

	/**
	 * 	Add Menu Item to - add new line to node
	 *	@param menu base menu
	 *	@param title title
	 */
	private void addMenuItem (Menupopup menu, String title, MWFNode node, int AD_WF_NodeTo_ID)
	{
		WFPopupItem item = new WFPopupItem (title, node, AD_WF_NodeTo_ID);
		menu.appendChild(item);
		item.addEventListener(Events.ON_CLICK, this);
	}	//	addMenuItem

	/**
	 * 	Add Menu Item to - delete line
	 *	@param menu base menu
	 *	@param title title
	 */
	private void addMenuItem (Menupopup menu, String title, MWFNodeNext line)
	{
		WFPopupItem item = new WFPopupItem (title, line);
		menu.appendChild(item);
		item.addEventListener(Events.ON_CLICK, this);
	}	//	addMenuItem
}
/******************************************************************************
 * Copyright (C) 2008 Low Heng Sin                                            *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. 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, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 *****************************************************************************/
package org.adempiere.webui.apps.wf;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.HashMap;
import java.util.Map;

import org.compiere.apps.wf.WFGraphLayout;
import org.compiere.apps.wf.WFNodeWidget;
import org.compiere.apps.wf.WorkflowGraphScene;
import org.compiere.model.X_AD_Workflow;
import org.compiere.util.CLogger;
import org.compiere.wf.MWFNode;
import org.compiere.wf.MWFNodeNext;
import org.compiere.wf.MWorkflow;
import org.netbeans.api.visual.graph.GraphScene;
import org.netbeans.api.visual.graph.layout.GraphLayout;
import org.netbeans.api.visual.layout.LayoutFactory;
import org.netbeans.api.visual.layout.SceneLayout;

/**
 *
 * @author Low Heng Sin
 *
 */
public class WFNodeContainer
{
	/**	Logger			*/
	@SuppressWarnings("unused")
	private static final CLogger	log = CLogger.getCLogger(WFNodeContainer.class);

	/** The Workflow		*/
	private MWorkflow	m_wf = null;

	private int currentRow = 1;
	private int currentColumn = 0;
	private int noOfColumns = 8;
	private int maxColumn = 0;
	private int rowCount = 0;

	private WorkflowGraphScene graphScene = new WorkflowGraphScene();

	private Map<Integer, Integer[]> matrix = null;

	/**
	 * 	WFContentPanel
	 */
	public WFNodeContainer ()
	{
		matrix = new HashMap<Integer, Integer[]>();
	}	//	WFContentPanel

	/**
	 * 	Set Workflow
	 *	@param wf workflow
	 */
	public void setWorkflow (MWorkflow wf)
	{
		m_wf = wf;
	}	//	setWorkflow


	public int getNoOfColumns() {
		return noOfColumns;
	}

	public void setNoOfColumns(int noOfColumns) {
		this.noOfColumns = noOfColumns;
	}

	/**
	 * 	Remove All and their listeners
	 */
	public void removeAll ()
	{
		graphScene = new WorkflowGraphScene();
		currentColumn = 0;
		currentRow = 1;
		matrix = new HashMap<Integer, Integer[]>();
	}	//	removeAll


	public void addNode(MWFNode node) {
		int oldRow = currentRow;
		int oldColumn = currentColumn;
		if (node.getXPosition() > 0 && node.getYPosition() > 0) {
			currentColumn = node.getXPosition();
			currentRow = node.getYPosition();
			if (currentColumn > noOfColumns) {
				currentColumn = 1;
				currentRow ++;
			}
		} else if (currentColumn == noOfColumns) {
			currentColumn = 1;
			if (m_wf.getWorkflowType().equals(X_AD_Workflow.WORKFLOWTYPE_General)) {
				currentRow++;
			} else {
				currentRow = currentRow + 2;
			}
		} else {
			if (m_wf.getWorkflowType().equals(X_AD_Workflow.WORKFLOWTYPE_General) || currentColumn == 0) {
				currentColumn++;
			} else {
				currentColumn = currentColumn + 2;
				if (currentColumn > noOfColumns) {
					currentColumn = 1;
					currentRow = currentRow + 2;
				}
			}
		}

		if (currentRow > rowCount) {
			rowCount = currentRow;
		}

		Integer[] nodes = matrix.get(currentRow);
		if (nodes == null) {
			nodes = new Integer[noOfColumns];
			matrix.put(currentRow, nodes);
		} else {
			//detect collision
			while (nodes[currentColumn - 1] != null) {
				if (nodes[currentColumn - 1] == node.getAD_WF_Node_ID()) {
					break;
				} else if (currentColumn == noOfColumns) {
					currentColumn = 1;
					currentRow ++;
					nodes = matrix.get(currentRow);
					if (nodes == null) {
						nodes = new Integer[noOfColumns];
						matrix.put(currentRow, nodes);
					}
				} else {
					currentColumn ++;
				}
			}
		}

		WFNodeWidget w = (WFNodeWidget) graphScene.addNode(node.getAD_WF_Node_ID());
		w.setColumn(currentColumn);
		w.setRow(currentRow);

		nodes[currentColumn - 1] = node.getAD_WF_Node_ID();
		if (currentColumn > maxColumn) {
			maxColumn = currentColumn;
		}

		if (currentRow < oldRow) {
			currentRow = oldRow;
			currentColumn = oldColumn;
		} else if ( currentRow == oldRow && currentColumn < oldColumn) {
			currentColumn = oldColumn;
		}
	}

	public void addEdge(MWFNodeNext edge) {
		graphScene.addEdge(edge);
		graphScene.setEdgeSource(edge, edge.getAD_WF_Node_ID());
		graphScene.setEdgeTarget(edge, edge.getAD_WF_Next_ID());
	}

	/**
	 *
	 * @param row row #, starting from 1
	 * @param column column #, starting from 1
	 * @return WFNodeWidget
	 */
	public WFNodeWidget findWidget(int row, int column) {
		WFNodeWidget widget = null;
		Integer[] nodeRow = matrix.get(row);
		if (nodeRow != null && column <= nodeRow.length) {
			widget = (WFNodeWidget) graphScene.findWidget(nodeRow[column - 1]);
		}
		return widget;
	}

	/**
	 * 	Get Bounds of WF Node Icon
	 * 	@param AD_WF_Node_ID node id
	 * 	@return bounds of node with ID or null
	 */
	public Rectangle findBounds (int AD_WF_Node_ID)
	{
		WFNodeWidget widget = (WFNodeWidget) graphScene.findWidget(AD_WF_Node_ID);
		if (widget == null)
			return null;

		Point p = widget.getPreferredLocation();
		return new Rectangle(p.x, p.y, WFNodeWidget.NODE_WIDTH, WFNodeWidget.NODE_HEIGHT);
	}	//	findBounds

	public Dimension getDimension()
	{
		return new Dimension(noOfColumns * WFGraphLayout.COLUMN_WIDTH, currentRow * WFGraphLayout.ROW_HEIGHT);
	}

	public void validate(Graphics2D graphics)
	{
		GraphLayout<Integer, MWFNodeNext> graphLayout = new WFGraphLayout();
		graphLayout.setAnimated(false);
		SceneLayout sceneGraphLayout = LayoutFactory.createSceneGraphLayout (graphScene, graphLayout);
		sceneGraphLayout.invokeLayoutImmediately();

		graphScene.validate(graphics);
	}


	public void paint(Graphics2D graphics) {
		graphScene.paint(graphics);
	}

	public int getRowCount() {
		return rowCount;
	}

	public int getCurrentRow() {
		return currentRow;
	}

	public int getCurrentColumn() {
		return currentColumn;
	}

	public int getColumnCount() {
		return noOfColumns;
	}

	public int getMaxColumnWithNode() {
		return maxColumn;
	}

	public GraphScene<Integer, MWFNodeNext> getGraphScene() {
		return graphScene;
	}
}	//	WFContentPanel

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Categories

  • Apple
  • iDempiere
  • IoT
  • IT Tools
  • Linux
  • Productivity
  • SAP
  • uncategorized
  • Wordpress

Tags

Access Arduino Bad Dept Booking Business One Button Confirmation Developer ERP Exam Free git github GPIO iDempiere Jasper Report Java Language LED Linux M1 MacOS Material Receipt Maven Meeting room Open Source OSGi Period Control Permission Plug-In PostgreSQL Potentiometer Premiere Pro Process PWM Raspberry PI Resistor Role Sales Management SWT Tips Ubuntu Video Editor Wordpress Workflow

Recent Posts

  • Unlocking Creative Potential: Top Open-Source Alternatives to Adobe Premiere Pro for Video Editing
  • Enhancing Meeting Room Efficiency with the iDempiere Meeting Room Booking Plug-in
  • How to Create a GitHub Repository from a Local Folder
  • Demystifying OSGi Service Ranking: A Comprehensive Guide
  • PostgreSQL Time Travel: Upgrading from Version 9.6 to 14

Meta

  • Register
  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org
©2023 Ninniku IT Hub | Design: Newspaperly WordPress Theme