/* $Id: ConditionEditorView.java,v 1.2 2007/12/11 09:54:58 nito Exp $
 * 
 * Copyright (c)ARGO 21, Corporation. 2005, 2006.  All rights reserved.
 * 
 * This file is part of Nautica Workflow.
 * 
 *  Nautica Workflow 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 2 of the License, or
 *  (at your option) any later version.
 * 
 *  Nautica Workflow 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 Nautica Workflow; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *  
 */
package jp.co.argo21.nautica.tool.wfd;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.text.Document;

import jp.co.argo21.nautica.commons.swing.BooleanDocument;
import jp.co.argo21.nautica.commons.swing.ByteLimitedDocument;
import jp.co.argo21.nautica.commons.swing.DialogUtilities;
import jp.co.argo21.nautica.commons.swing.NumericDocument;
import jp.co.argo21.nautica.commons.util.ResourceManager;
import jp.co.argo21.nautica.tool.wfd.element.Element;
import jp.co.argo21.nautica.tool.wfd.element.VariableElement;
import jp.co.argo21.nautica.tool.wfd.expression.ExceptionExpression;
import jp.co.argo21.nautica.tool.wfd.expression.Expression;
import jp.co.argo21.nautica.tool.wfd.expression.LogicalExpression;
import jp.co.argo21.nautica.tool.wfd.expression.OtherwiseExpression;
import jp.co.argo21.nautica.tool.wfd.expression.RelationalExpression;
import jp.co.argo21.nautica.tool.wfd.expression.UnaryExpression;

/**
 * 条件エディタビューである。
 * 
 * 
 * @author  Norihiro Itoh(ARGO 21 Corp.)
 * @version $Revision: 1.2 $
 * @since   Nautica Workflow 1.0
 */
public class ConditionEditorView extends JTabbedPane
{
	/** シリアルバージョンID */
	private static final long serialVersionUID = 1L;

	/** 文字列条件用演算子名 */
	public static String[] STR_OPS;
	/** 数値条件用演算子名 */
	public static String[] NUM_OPS;
	/** 真理条件用演算子名 */
	public static String[] BOOL_OPS;
	/** 論理条件用演算子名 */
	public static String[] LOG_OPS;

	/** 変数テーブルカラム名 */
	private static String varTableColumn;
	/** 条件式テーブルカラム名 */
	private static String condTableColumn;

	/** 枠線 */
	protected static final Border border = BorderFactory.createEtchedBorder();

	/** 条件式ボタン */
	private JRadioButton condButton;
	/** OTHERWISEボタン */
	private JRadioButton otherButton;
	/** EXCEPTIONボタン */
	private JRadioButton exButton;
	/** プロセス変数一覧 */
	private JTable varTable;
	/** 基本式演算子 */
	private JComboBox basOpeBox;
	/** 基本式右辺フィールド */
	private JTextField basRField;
	/** 単項論理式フィールド */
	private JTextField unaryField;
	/** 二項論理式左辺フィールド */
	private JTextField logLField;
	/** 基本式演算子 */
	private JComboBox logOpeBox;
	/** 二項論理式右辺フィールド */
	private JTextField logRField;
	/** 基本式ボタン */
	private JRadioButton basButton;
	/** 単項論理式ボタン */
	private JRadioButton unaryButton;
	/** 二項論理式ボタン */
	private JRadioButton logButton;
	/** 条件一覧 */
	private JTable condTable;
	/** 選択ボタン */
	private JButton selUniButton;
	/** 選択ボタン */
	private JButton selLogLButton;
	/** 選択ボタン */
	private JButton selLogRButton;
	/** 追加ボタン */
	private JButton addButton;
	/** 式表示フィールド */
	private JTextArea previewArea;

	/** 条件式 */
	private Expression expression;
	
	/** 変数一覧 */
	private List<VariableElement> vars;
	
	/** 条件式一覧 */
	private List<Expression> expressions = new ArrayList<Expression>();

	/** 論理条件の左辺条件式 */
	private Expression logLExp;
	/** 論理条件の右辺条件式 */
	private Expression logRExp;
	/** 否定条件の条件式 */
	private Expression unaryExp;
	
	
	/** 文字列入力制御 */
	private Document strDocument = new ByteLimitedDocument(128);
	
	/** 数値入力制御 */
	private Document numDocument = new NumericDocument(9, true);
	
	/** 真理入力制御 */
	private Document boolDocument = new BooleanDocument();

	/**
	 * 定数の初期化
	 */
	static
	{
		ResourceManager rm = WorkflowDesignerManager.getResourceManager();

		STR_OPS = new String[2];
		STR_OPS[0] = rm.getResource("ConditionEditorView.basicope.0");
		STR_OPS[1] = rm.getResource("ConditionEditorView.basicope.1");

		NUM_OPS = new String[6];
		NUM_OPS[0] = rm.getResource("ConditionEditorView.basicope.0");
		NUM_OPS[1] = rm.getResource("ConditionEditorView.basicope.1");
		NUM_OPS[2] = rm.getResource("ConditionEditorView.basicope.2");
		NUM_OPS[3] = rm.getResource("ConditionEditorView.basicope.3");
		NUM_OPS[4] = rm.getResource("ConditionEditorView.basicope.4");
		NUM_OPS[5] = rm.getResource("ConditionEditorView.basicope.5");

		BOOL_OPS = new String[2];
		BOOL_OPS[0] = rm.getResource("ConditionEditorView.basicope.0");
		BOOL_OPS[1] = rm.getResource("ConditionEditorView.basicope.1");

		LOG_OPS = new String[2];
		LOG_OPS[0] = rm.getResource("ConditionEditorView.logope.0");
		LOG_OPS[1] = rm.getResource("ConditionEditorView.logope.1");

		varTableColumn = rm.getResource("ConditionEditorView.column.0");
		condTableColumn = rm.getResource("ConditionEditorView.column.1");
	}
	
	/**
	 * 条件エディタビューを生成する。
	 */
	public ConditionEditorView()
	{
		ResourceManager rm = WorkflowDesignerManager.getResourceManager();

		JPanel panel = createConditionEditorPanel(rm);
		addTab(rm.getResource("ConditionEditorView.tab.0"), panel);

		validate();
	}
	
	/**
	 * パネルを生成する。
	 * 
	 * @param rm リソースマネージャ
	 * @return パネル
	 */
	private JPanel createConditionEditorPanel(ResourceManager rm)
	{
		JPanel panel = new JPanel();
		panel.setLayout(null);
		panel.setBorder(border);
		Dimension size = new Dimension(580, 370);
		panel.setSize(size);
		panel.setPreferredSize(size);
		JLabel l0 = new JLabel(rm.getResource("ConditionEditorView.label.0"));

		condButton = new JRadioButton(rm.getResource("ConditionEditorView.kind.0"));
		condButton.addActionListener(new SelectConditionAction());
		otherButton = new JRadioButton(rm.getResource("ConditionEditorView.kind.1"));
		otherButton.addActionListener(new SelectOtherwiseAction());
		exButton = new JRadioButton(rm.getResource("ConditionEditorView.kind.2"));
		exButton.addActionListener(new SelectExceptionAction());

		JPanel kindPane = new JPanel();
		kindPane.setLayout(new GridLayout(1, 3, 5, 5));
		kindPane.setBorder(border);
		kindPane.add(condButton);
		kindPane.add(otherButton);
		kindPane.add(exButton);

		ButtonGroup kindGroup = new ButtonGroup();
		kindGroup.add(condButton);
		kindGroup.add(otherButton);
		kindGroup.add(exButton);

		basButton = new JRadioButton(rm.getResource("ConditionEditorView.cond.0"));
		basButton.addActionListener(new SelectBasicExpressionAction());
		unaryButton = new JRadioButton(rm.getResource("ConditionEditorView.cond.1"));
		unaryButton.addActionListener(new SelectUnaryExpressionAction());
		logButton = new JRadioButton(rm.getResource("ConditionEditorView.cond.2"));
		logButton.addActionListener(new SelectLogicalExpressionAction());

		ButtonGroup expGroup = new ButtonGroup();
		expGroup.add(basButton);
		expGroup.add(unaryButton);
		expGroup.add(logButton);

		varTable = new JTable(new VarTableModel());
		varTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		varTable.setRowHeight(35);
		varTable.getColumnModel().getColumn(0).setCellRenderer(new VarRenderer());
		ListSelectionModel vlsm = varTable.getSelectionModel();
		vlsm.addListSelectionListener(new VarSelectAction());
		JScrollPane sp0 = new JScrollPane();
		sp0.setViewportView(varTable);
		basOpeBox = new JComboBox(STR_OPS);
		basRField = new JTextField();
		basRField.setDocument(strDocument);

		unaryField = new JTextField();
		unaryField.setEditable(false);

		logLField = new JTextField();
		logLField.setEditable(false);
		logOpeBox = new JComboBox(LOG_OPS);
		logRField = new JTextField();
		logRField.setEditable(false);
		selUniButton = new JButton(rm.getResource("JButton.label.select"));
		selUniButton.addActionListener(new SelectExpressionAction(unaryField));
		selLogLButton = new JButton(rm.getResource("JButton.label.select"));
		selLogLButton.addActionListener(new SelectExpressionAction(logLField));
		selLogRButton = new JButton(rm.getResource("JButton.label.select"));
		selLogRButton.addActionListener(new SelectExpressionAction(logRField));

		condTable = new JTable(new ConditionTableModel());
		condTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		condTable.setRowHeight(35);
		condTable.getColumnModel().getColumn(0).setCellRenderer(new ConditionRenderer());
		ListSelectionModel clsm = condTable.getSelectionModel();
		clsm.addListSelectionListener(new ConditionSelectAction());
		JScrollPane sp1 = new JScrollPane();
		sp1.setViewportView(condTable);
		addButton = new JButton(rm.getResource("JButton.label.add"));
		addButton.addActionListener(new AddExpressionAction());
		previewArea = new JTextArea();
		previewArea.setLineWrap(true);
		previewArea.setEditable(false);
		JScrollPane sp2 = new JScrollPane();
		sp2.setViewportView(previewArea);

		condButton.setSelected(true);
		basButton.setSelected(true);
		setConditionEditable(true);
		setBasicExpressionEditable();

		panel.add(locate(l0,             10,  10, 100,  25));
		panel.add(locate(kindPane,       10,  40, 560,  35));
		panel.add(locate(basButton,      10,  80, 105,  25));
		panel.add(locate(unaryButton,      10, 190, 105,  25));
		panel.add(locate(logButton,      10, 220, 105,  25));
		panel.add(locate(sp0,           120,  80, 165, 105));
		panel.add(locate(basOpeBox,     290, 130, 100,  25));
		panel.add(locate(basRField,     290, 160, 100,  25));
		panel.add(locate(unaryField,      120, 190, 100,  25));
		panel.add(locate(selUniButton,  225, 190,  60,  25));
		panel.add(locate(logOpeBox,     290, 220, 100,  25));
		panel.add(locate(logLField,     120, 220, 100,  25));
		panel.add(locate(selLogLButton, 225, 220,  60,  25));
		panel.add(locate(logRField,     120, 250, 100,  25));
		panel.add(locate(selLogRButton, 225, 250,  60,  25));
		panel.add(locate(sp1,           400,  80, 170, 225));
		panel.add(locate(addButton,     330, 280,  60,  25));
		panel.add(locate(sp2,            10, 310, 560,  50));

		validate();
		
		return panel;
	}

	/**
	 * 条件編集の可否を設定する。
	 * 
	 * @param b	編集の可否
	 */	
	private void setConditionEditable(boolean b)
	{
		basButton.setEnabled(b);
		unaryButton.setEnabled(b);
		logButton.setEnabled(b);
		varTable.setEnabled(b);
		basOpeBox.setEnabled(b);
		basRField.setEditable(b);
		selUniButton.setEnabled(b);
		logOpeBox.setEnabled(b);
		selLogLButton.setEnabled(b);
		selLogRButton.setEnabled(b);
		addButton.setEnabled(b);
	}

	/**
	 * 基本条件の編集を可能にする。
	 */	
	private void setBasicExpressionEditable()
	{
		varTable.setEnabled(true);
		basOpeBox.setEnabled(true);
		basRField.setEditable(true);
		selUniButton.setEnabled(false);
		logOpeBox.setEnabled(false);
		selLogLButton.setEnabled(false);
		selLogRButton.setEnabled(false);
		addButton.setEnabled(true);
		varTable.clearSelection();
		basOpeBox.setSelectedIndex(0);
		basRField.setText("");
		basRField.setToolTipText("");
	}

	/**
	 * 否定条件の編集を可能にする。
	 */
	private void setUnaryExpressionEditable()
	{
		varTable.setEnabled(false);
		basOpeBox.setEnabled(false);
		basRField.setEditable(false);
		selUniButton.setEnabled(true);
		logOpeBox.setEnabled(false);
		selLogLButton.setEnabled(false);
		selLogRButton.setEnabled(false);
		addButton.setEnabled(true);
		unaryField.setText("");
		unaryField.setToolTipText("");
		unaryExp = null;
	}

	/**
	 * 論理条件の編集を可能にする。
	 */
	private void setLogicalExpressionEditable()
	{
		varTable.setEnabled(false);
		basOpeBox.setEnabled(false);
		basRField.setEditable(false);
		selUniButton.setEnabled(false);
		logOpeBox.setEnabled(true);
		selLogLButton.setEnabled(true);
		selLogRButton.setEnabled(true);
		addButton.setEnabled(true);
		logLField.setText("");
		logLField.setToolTipText("");
		logOpeBox.setSelectedIndex(0);
		logRField.setText("");
		logRField.setToolTipText("");
		logLExp = null;
		logRExp = null;
	}

	/**
	 * 選択された変数の型に応じて画面の状態を更新する。
	 * 
	 * @param var	変数
	 */	
	private void variableSelected(VariableElement var)
	{
		int type = var.getType();
		if (type == VariableElement.INTEGER) {
			basOpeBox.setModel(new DefaultComboBoxModel(NUM_OPS));
			basRField.setHorizontalAlignment(SwingConstants.RIGHT);
		} else if (type == VariableElement.BOOLEAN) {
			basOpeBox.setModel(new DefaultComboBoxModel(BOOL_OPS));
			basRField.setHorizontalAlignment(SwingConstants.LEFT);
		} else {
			basOpeBox.setModel(new DefaultComboBoxModel(STR_OPS));
			basRField.setHorizontalAlignment(SwingConstants.LEFT);
		}
		basOpeBox.updateUI();
	}

	/**
	 * 新たな基本条件を作成する。
	 */
	private void makeNewBasicExpression()
	{
		ResourceManager rm = WorkflowDesignerManager.getResourceManager();
		int selected = varTable.getSelectedRow();
		if (selected < 0) {
			DialogUtilities.showError(rm.getResource("message.error.0041"));
			return;
		}
		int ope = RelationalExpression.EQUAL;
		if (basOpeBox.getSelectedIndex() == 1) ope = RelationalExpression.NOT_EQUAL;
		else if (basOpeBox.getSelectedIndex() == 2) ope = RelationalExpression.LESS_THAN;
		else if (basOpeBox.getSelectedIndex() == 3) ope = RelationalExpression.LESS_EQUAL;
		else if (basOpeBox.getSelectedIndex() == 4) ope = RelationalExpression.GREATER_THAN;
		else if (basOpeBox.getSelectedIndex() == 5) ope = RelationalExpression.GREATER_EQUAL;
		
		VariableElement v = (VariableElement)vars.get(selected);
		
		Expression exp = new RelationalExpression(v.getID(), ope, basRField.getText());
		expressions.add(exp);

		setBasicExpressionEditable();
		condTable.updateUI();
	}

	/**
	 * 新たな否定条件を作成する。
	 */
	private void makeNewUnaryExpression()
	{
		if (unaryExp == null) {
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();
			DialogUtilities.showError(rm.getResource("message.error.0042"));
			return;
		}
		Expression exp = new UnaryExpression(unaryExp);
		expressions.add(exp);

		setUnaryExpressionEditable();
		condTable.updateUI();
	}

	/**
	 * 新たな論理条件を作成する。
	 */
	private void makeNewLogicalExpression()
	{
		if (logLExp == null) {
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();
			DialogUtilities.showError(rm.getResource("message.error.0043"));
			return;
		}
		if (logRExp == null) {
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();
			DialogUtilities.showError(rm.getResource("message.error.0044"));
			return;
		}
		int ope = LogicalExpression.OR;
		if (logOpeBox.getSelectedIndex() == 0) ope = LogicalExpression.AND;
		
		Expression exp = new LogicalExpression(logLExp, ope, logRExp);
		expressions.add(exp);

		setLogicalExpressionEditable();
		condTable.updateUI();
	}

	/**
	 * 条件式を返す。
	 * 
	 * @return	条件式
	 */
	public Expression getExpression()
	{
		return expression;
	}

	/**
	 * 条件式を設定する。
	 * 
	 * @param exp	条件式
	 */	
	public void setExpression(Expression exp)
	{
		expression = exp;
		int ix = -1;
		if (exp == null) {
			setConditionEditable(true);
			condButton.setSelected(true);
		} else if (exp instanceof OtherwiseExpression) {
			setConditionEditable(false);
			otherButton.setSelected(true);
		} else if (exp instanceof ExceptionExpression) {
			setConditionEditable(false);
			exButton.setSelected(true);
		} else {
			setConditionEditable(true);
			condButton.setSelected(true);
			exp.getAllExpressions(expressions);
			ix = expressions.indexOf(exp);			
		}
		repaint();
		if (ix > -1) condTable.getSelectionModel().setLeadSelectionIndex(ix);
	}

	/**
	 * 終了前のチェックを行う。
	 * 
	 * @return	問題なければtrue。
	 */	
	public boolean check()
	{
		if (condButton.isSelected()) {
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();
			int selected = condTable.getSelectedRow();
			if (selected < 0) {
				DialogUtilities.showWarning(rm.getResource("message.warn.0005"));
				return false;
			}
		}
		return true;
	}

	/**
	 * 編集結果をコミットする。
	 */	
	public void commit()
	{
		if (condButton.isSelected()) {
			int selected = condTable.getSelectedRow();
			expression = (Expression)expressions.get(selected);
		} else if (otherButton.isSelected()) {
			expression = new OtherwiseExpression();
		} else if (exButton.isSelected()) {
			expression = new ExceptionExpression();
		}
	}

	/**
	 * 指定されたコンポーネントの属性を指定の大きさと座標で更新する。
	 * 
	 * @param component 対象コンポーネント
	 * @param x 左上のX座標
	 * @param y 左上のY座標
	 * @param w 幅
	 * @param h 高さ
	 * @return 変更されたコンポーネント
	 */
	protected Component locate(Component component, int x, int y, int w, int h)
	{
		component.setLocation(x, y);
		component.setSize(w, h);
		return  component;
	}

	/**
	 * 条件編集を選択した場合の処理
	 */	
	class SelectConditionAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 条件編集を可能にする。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			setConditionEditable(true);
		}
	}
	
	/**
	 * OTHERWISEが選択された場合の処理
	 */	
	class SelectOtherwiseAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 条件編集を不可にする。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			setConditionEditable(false);
		}
	}
	
	/**
	 * EXCEPTIONが選択された場合の処理
	 */	
	class SelectExceptionAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 条件編集を不可にする。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			setConditionEditable(false);
		}
	}
	
	/**
	 * 基本条件が選択された場合の処理
	 */	
	class SelectBasicExpressionAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 基本条件を編集可能にする。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			setBasicExpressionEditable();
		}
	}
	
	/**
	 * 論理条件が選択された場合の処理
	 */	
	class SelectLogicalExpressionAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 論理条件を編集可能にする。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			setLogicalExpressionEditable();
		}
	}
	
	/**
	 * 否定条件が選択された場合の処理
	 */	
	class SelectUnaryExpressionAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 否定条件を編集可能にする。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			setUnaryExpressionEditable();
		}
	}
	
	/**
	 * 追加ボタンが押された場合の処理
	 */	
	class AddExpressionAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 入力項目からあらたな条件を作成し、一覧に追加する。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			if (basButton.isSelected()) {
				makeNewBasicExpression();
			} else if (unaryButton.isSelected()) {
				makeNewUnaryExpression();
			} else if (logButton.isSelected()) {
				makeNewLogicalExpression();
			}
		}
	}
	
	/**
	 * 選択ボタンが押された場合の処理
	 */
	class SelectExpressionAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/** 対応するテキストフィールド */
		private JTextField field;
		
		/**
		 * アクションを生成する。
		 * 
		 * @param f	テキストフィールド
		 */
		SelectExpressionAction(JTextField f)
		{
			this.field = f;
		}
		
		/**
		 * 選択された条件式をテキストフィールドに割り付ける。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();
			int selected = condTable.getSelectedRow();
			if (selected < 0) {
				DialogUtilities.showWarning(rm.getResource("message.warn.0005"));
				return;
			}
			Expression exp = (Expression)expressions.get(selected);
			if (field == unaryField) {
				unaryExp = exp;
			} else if (field == logLField) {
				logLExp = exp;
			} else if (field == logRField) {
				logRExp = exp;
			}
			field.setText(exp.getExpressionString(vars));
			field.setToolTipText(exp.getExpressionString(vars));
		}
	}

	/**
	 * 変数テーブルが選択された場合の処理
	 */	
	class VarSelectAction implements ListSelectionListener
	{
		/**
		 * テーブルの変更を画面に反映する。
		 * 
		 * @param e	イベント
		 * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
		 */
		public void valueChanged(ListSelectionEvent e)
		{
			if (e.getValueIsAdjusting()) return;

			ListSelectionModel lsm = (ListSelectionModel)e.getSource();
			if (lsm.isSelectionEmpty() == false) {
				int selected = lsm.getMinSelectionIndex();
				VariableElement v = (VariableElement)vars.get(selected);
				variableSelected(v);
				int type = v.getType();
				String s = v.getInitialValue();
				if (s == null) s = "";
				basRField.setText(s);
				if (type == VariableElement.INTEGER) {
					basRField.setDocument(numDocument);
					basRField.setHorizontalAlignment(SwingUtilities.RIGHT);
				} else if (type == VariableElement.BOOLEAN) {
					basRField.setDocument(boolDocument);
					basRField.setHorizontalAlignment(SwingUtilities.LEFT);
				} else {
					basRField.setDocument(strDocument);
					basRField.setHorizontalAlignment(SwingUtilities.LEFT);
				}
			}
		}
	}

	/**
	 * 条件式テーブルが選択された場合の処理
	 */	
	class ConditionSelectAction implements ListSelectionListener
	{
		/**
		 * テーブルの変更を画面に反映する。
		 * 
		 * @param e
		 * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
		 */
		public void valueChanged(ListSelectionEvent e)
		{
			if (e.getValueIsAdjusting()) return;

			ListSelectionModel lsm = (ListSelectionModel)e.getSource();
			if (lsm.isSelectionEmpty() == false) {
				int selected = lsm.getMinSelectionIndex();
				previewArea.setText(((Expression)expressions.get(selected)).getExpressionString(vars));
			}
		}
	}

	/**
	 * 変数テーブル制御モデル
	 */
	class VarTableModel extends AbstractTableModel
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 変数テーブル制御モデルを生成する。
		 */
		VarTableModel()
		{
			vars = WorkflowDesignerManager.getMainFrame().getPackage().getVariables();
		}

		/**
		 * データソースオブジェクトが管理する列数を返す。
		 * JTableはこのメソッドを使って、初期化時に作成および表示する
		 * 必要のある列数を判断する。
		 *
		 * @return	モデルの列数
		 */
		public int getColumnCount()
		{
			return 1;
		}

		/**
		 * データソースオブジェクトが管理するレコード数を返す。
		 * JTableはこのメソッドを使って、作成および表示する必要のある行数を判断する。
		 *
		 * @return	モデルの行数
		 */
		public int getRowCount()
		{
			return vars.size();
		}

		/**
		 * colにある列の名前を返す。
		 * このメソッドは、テーブルの列ヘッダ名を初期化するために使われる。
		 *
		 * @param	col		列のインデックス
		 * @return	列ヘッダ名
		 */
		public String getColumnName(int col)
		{
			return varTableColumn;
		}

		/**
		 * セルの値を返す。
		 *
		 * @param	row		値が参照される行
		 * @param	col		値が参照される列
		 * @return	指定されたセルにある値
		 */
		public Object getValueAt(int row, int col)
		{
			return vars.get(row);
		}

		/**
		 * 列のClassを返す。
		 *
		 * @param	col		列
		 * @return	モデルのオブジェクト値の共通の上位クラス
		 */
		public Class<?> getColumnClass(int col)
		{
			return Element.class;
		}

		/**
		 * rowとcolにあるセルが編集可能な場合はtrueを返す。
		 * そうでない場合、セルでsetValueAt()を呼び出しても、そのセルの値は変更されない。
		 *
		 * @param	row		値が参照される行
		 * @param	col		値が参照される列
		 * @return	セルが編集可能な場合はtrue
		 */
		public boolean isCellEditable(int row, int col)
		{
			return false;
		}
	}

	/**
	 * 変数テーブルのセルレンダラー。
	 */	
	class VarRenderer extends DefaultTableCellRenderer
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/** アイコン */
		private Icon icon;
		
		/**
		 * 変数テーブル用セルレンダラーを生成する。
		 */
		VarRenderer()
		{
			String name = WorkflowDesignerConstants.EL_VARIABLE + "-cur";
			icon = IconManager.getIcon(name);
		}
		
		/**
		 * セルのレンダリングを行う。
		 * 
		 * @param table	テーブル
		 * @param o	セル内容
		 * @param isSelected	選択状態
		 * @param hasFocus	フォーカス状態
		 * @param row	行
		 * @param column	列
		 * @return	レンダリングされたセル
		 * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
		 */
		public Component getTableCellRendererComponent(
		JTable table,
		Object o,
		boolean isSelected,
		boolean hasFocus,
		int row,
		int column)
		{
			super.getTableCellRendererComponent(table, o, isSelected, hasFocus, row, column);
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();

			Element elem = (Element)o;
			setText(elem.getName());

			if (icon != null) setIcon(icon);
			setToolTipText(elem.getTooltipText(rm));
			return this;
		}
	}

	/**
	 * 条件式テーブル制御モデル
	 */
	class ConditionTableModel extends AbstractTableModel
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 条件式テーブル制御モデルを生成する。
		 */
		ConditionTableModel()
		{
			vars = WorkflowDesignerManager.getMainFrame().getPackage().getVariables();
		}

		/**
		 * データソースオブジェクトが管理する列数を返す。
		 * JTableはこのメソッドを使って、初期化時に作成および表示する
		 * 必要のある列数を判断する。
		 *
		 * @return	モデルの列数
		 */
		public int getColumnCount()
		{
			return 1;
		}

		/**
		 * データソースオブジェクトが管理するレコード数を返す。
		 * JTableはこのメソッドを使って、作成および表示する必要のある行数を判断する。
		 *
		 * @return	モデルの行数
		 */
		public int getRowCount()
		{
			return expressions.size();
		}

		/**
		 * colにある列の名前を返す。
		 * このメソッドは、テーブルの列ヘッダ名を初期化するために使われる。
		 *
		 * @param	col		列のインデックス
		 * @return	列ヘッダ名
		 */
		public String getColumnName(int col)
		{
			return condTableColumn;
		}

		/**
		 * セルの内容を返す。
		 *
		 * @param	row		値が参照される行
		 * @param	col		値が参照される列
		 * @return	指定されたセルにある値
		 */
		public Object getValueAt(int row, int col)
		{
			return expressions.get(row);
		}

		/**
		 * 列のClassを返す。
		 *
		 * @param	col		列
		 * @return	モデルのオブジェクト値の共通の上位クラス
		 */
		public Class<?> getColumnClass(int col)
		{
			return Expression.class;
		}

		/**
		 * rowとcolにあるセルが編集可能な場合はtrueを返す。
		 * そうでない場合、セルでsetValueAt()を呼び出しても、そのセルの値は変更されない。
		 *
		 * @param	row		値が参照される行
		 * @param	col		値が参照される列
		 * @return	セルが編集可能な場合はtrue
		 */
		public boolean isCellEditable(int row, int col)
		{
			return false;
		}
	}

	/**
	 * 条件式テーブルのセルレンダラー。
	 */	
	class ConditionRenderer extends DefaultTableCellRenderer
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/** アイコン */
		private Icon icon;
		
		/**
		 * 条件式テーブル用セルレンダラーを生成する。
		 */
		ConditionRenderer()
		{
			String name = "condition-cur";
			icon = IconManager.getIcon(name);
		}
		
		/**
		 * セルのレンダリングを行う。
		 * 
		 * @param table	テーブル
		 * @param o	セル内容
		 * @param isSelected	選択状態
		 * @param hasFocus	フォーカス状態
		 * @param row	行
		 * @param column	列
		 * @return	レンダリングされたセル
		 * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
		 */
		public Component getTableCellRendererComponent(
		JTable table,
		Object o,
		boolean isSelected,
		boolean hasFocus,
		int row,
		int column)
		{
			super.getTableCellRendererComponent(table, o, isSelected, hasFocus, row, column);
			@SuppressWarnings("unused")
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();

			Expression exp = (Expression)o;
			String s = exp.getExpressionString(vars);
			setText(s);

			if (icon != null) setIcon(icon);
			setToolTipText(s);
			return this;
		}
	}
}
