kr.ac.kaist.swrc.jhannanum.demo.GUIDemo.java Source code

Java tutorial

Introduction

Here is the source code for kr.ac.kaist.swrc.jhannanum.demo.GUIDemo.java

Source

/*  Copyright 2010, 2011 Semantic Web Research Center, KAIST
    
This file is part of JHanNanum.
    
JHanNanum 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.
    
JHanNanum 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 JHanNanum.  If not, see <http://www.gnu.org/licenses/>   */

package kr.ac.kaist.swrc.jhannanum.demo;

import kr.ac.kaist.swrc.jhannanum.hannanum.Workflow;
import kr.ac.kaist.swrc.jhannanum.plugin.MajorPlugin.MorphAnalyzer.ChartMorphAnalyzer.ChartMorphAnalyzer;
import kr.ac.kaist.swrc.jhannanum.plugin.MajorPlugin.PosTagger.HmmPosTagger.HMMTagger;
import kr.ac.kaist.swrc.jhannanum.plugin.SupplementPlugin.MorphemeProcessor.SimpleMAResult09.SimpleMAResult09;
import kr.ac.kaist.swrc.jhannanum.plugin.SupplementPlugin.MorphemeProcessor.SimpleMAResult22.SimpleMAResult22;
import kr.ac.kaist.swrc.jhannanum.plugin.SupplementPlugin.MorphemeProcessor.UnknownMorphProcessor.UnknownProcessor;
import kr.ac.kaist.swrc.jhannanum.plugin.SupplementPlugin.PlainTextProcessor.InformalSentenceFilter.InformalSentenceFilter;
import kr.ac.kaist.swrc.jhannanum.plugin.SupplementPlugin.PlainTextProcessor.SentenceSegmentor.SentenceSegmentor;
import kr.ac.kaist.swrc.jhannanum.plugin.SupplementPlugin.PosProcessor.NounExtractor.NounExtractor;
import kr.ac.kaist.swrc.jhannanum.plugin.SupplementPlugin.PosProcessor.SimplePOSResult09.SimplePOSResult09;
import kr.ac.kaist.swrc.jhannanum.plugin.SupplementPlugin.PosProcessor.SimplePOSResult22.SimplePOSResult22;
import kr.ac.kaist.swrc.jhannanum.share.JSONReader;
import org.json.JSONException;

import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.*;
import java.io.*;
import java.util.HashMap;

/**
 * This is a GUI-based demo program of the HanNanum that helps users to understand the concept
 * of work flow and use the HanNanum library easily. It shows a window that has components for plug-in pool,
 * work flow, plug-in information, work flow controls, input text and analysis result. Users can easily
 * set up various work flows by drag-and-drop the plug-ins from the plug-in pool to the work flow component,
 * and see the analysis result. <br>
 * <br>
 * Users can use this GUI demo program by following procedure:<br>
 *       1. Browse the plug-ins in the plug-in pool. The brief information about the selected plug-in will be
 *         displayed so that you can refer the information when set the work flow up.<br>
 *      2. Drag and drop plug-ins from the plug-in pool to the list in the work flow considering the phase
 *         and type of the plug-in.<br>
 *         - If you want to remove the plug-in on the work flow, simply double click it.<br>
 *         - If you change the order of the supplement plug-ins in each phase, simply drag and drop a plug-in
 *           to the position you want.<br>
 *      3. Once you finish to set the work flow up, choose 'Multi-thread Mode' or 'Single-thread Mode'.<br>
 *      4. Click 'Activate the work flow' button.<br>
 *      5. Type or copy-and-past text that you want to analyze into the 'Input Text' area.<br>
 *      6. Click 'Analyze Text' button.<br>
 *      7. You can see the analysis result on 'Result' area.<br>
 *      8. Repeat 5~7 to analyze other text with the activated work flow.<br>
 *         Or click 'Close the work flow' button and go to step 1 to set up new work flow.<br>
 * <br>
 * @author Sangwon Park (hudoni@world.kaist.ac.kr), CILab, SWRC, KAIST
 */
public class GUIDemo {
    private JFrame mainFrame = null;
    private JMenuBar menuBar = null;
    private JMenu menuFile = null;
    private JMenu menuHelp = null;
    private JMenuItem menuItemFileOpen = null;
    private JMenuItem menuItemHelp = null;
    private JTree tree;
    private HashMap<String, String> pluginInfoMap = null;

    private JList listPluginMajor2 = null;
    private JList listPluginMajor3 = null;
    private JList listPluginSupplement1 = null;
    private JList listPluginSupplement2 = null;
    private JList listPluginSupplement3 = null;

    private DefaultListModel listModelMajor2 = null;
    private DefaultListModel listModelMajor3 = null;
    private DefaultListModel listModelSupplement1 = null;
    private DefaultListModel listModelSupplement2 = null;
    private DefaultListModel listModelSupplement3 = null;

    private JTextArea areaPluginInfo = null;

    private JTextArea inputTextArea = null;
    private JTextArea outputTextArea = null;

    private JSplitPane splitPaneTop = null;
    private JSplitPane splitPaneBottom = null;

    private JRadioButton radioMultiThread = null;
    private JRadioButton radioSingleThread = null;

    private JButton buttonActivate = null;
    private JButton buttonAnalysis = null;
    private JButton buttonReset = null;

    private PluginInfo selectedPlugin = null;
    private PluginInfo tempPlugin = null;

    private boolean multiThreadMode = true;
    private boolean activated = false;

    private Workflow workflow = null;

    /**
     * Run this demo program.
     * @param args
     */
    public static void main(String[] args) {
        GUIDemo demo = new GUIDemo();
        demo.run();
    }

    /**
     * Sets the GUI up and launch the demo.
     */
    public void run() {
        ///////////////////////////////////////////////////////////////////
        // Basic setting for the mainFrame                                    
        ///////////////////////////////////////////////////////////////////
        mainFrame = new JFrame();

        Toolkit kit = mainFrame.getToolkit();
        Dimension windowSize = kit.getScreenSize();

        mainFrame.setBounds(windowSize.width / 20, windowSize.height / 20, windowSize.width * 18 / 20,
                windowSize.height * 18 / 20);
        mainFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        mainFrame.setTitle("HanNanum Korean Morphological Analyzer - A Plug-in Component based System (GUI Demo)");

        Font font = new Font("MonoSpaced", Font.PLAIN, 12);
        UIManager.put("TextArea.font", font);

        ///////////////////////////////////////////////////////////////////
        // Layout setting for the mainFrame                  
        ///////////////////////////////////////////////////////////////////
        mainFrame.setLayout(new BorderLayout());
        mainFrame.getContentPane().add(createPaneCenter(), BorderLayout.CENTER);
        mainFrame.getContentPane().add(createPaneNorth(), BorderLayout.NORTH);

        ///////////////////////////////////////////////////////////////////
        // Menu Setting                                 
        ///////////////////////////////////////////////////////////////////      
        menuBar = new JMenuBar();
        menuFile = new JMenu("File");
        menuItemFileOpen = new JMenuItem("Open", KeyEvent.VK_O);
        menuHelp = new JMenu("Help");
        menuItemHelp = new JMenuItem("Help", KeyEvent.VK_H);

        menuItemFileOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK));
        menuItemHelp.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, ActionEvent.ALT_MASK));

        menuBar.add(menuFile);
        menuBar.add(menuHelp);
        menuFile.add(menuItemFileOpen);
        menuHelp.add(menuItemHelp);
        mainFrame.setJMenuBar(menuBar);

        ///////////////////////////////////////////////////////////////////
        // Event Handler Setting                                 
        ///////////////////////////////////////////////////////////////////
        menuItemFileOpen.addActionListener(new SharedActionHandler());
        menuItemHelp.addActionListener(new SharedActionHandler());
        buttonActivate.addActionListener(new SharedActionHandler());
        buttonAnalysis.addActionListener(new SharedActionHandler());
        buttonReset.addActionListener(new SharedActionHandler());
        radioMultiThread.addActionListener(new SharedActionHandler());
        radioSingleThread.addActionListener(new SharedActionHandler());

        listPluginMajor2.addMouseListener(new PluginListMouseListener(listPluginMajor2, listModelMajor2));
        listPluginMajor3.addMouseListener(new PluginListMouseListener(listPluginMajor3, listModelMajor3));
        listPluginSupplement1
                .addMouseListener(new PluginListMouseListener(listPluginSupplement1, listModelSupplement1));
        listPluginSupplement2
                .addMouseListener(new PluginListMouseListener(listPluginSupplement2, listModelSupplement2));
        listPluginSupplement3
                .addMouseListener(new PluginListMouseListener(listPluginSupplement3, listModelSupplement3));

        listPluginMajor2.setTransferHandler(new PluginTransferHandler(PluginInfo.PHASE2, PluginInfo.MAJOR));
        listPluginMajor3.setTransferHandler(new PluginTransferHandler(PluginInfo.PHASE3, PluginInfo.MAJOR));
        listPluginSupplement1
                .setTransferHandler(new PluginTransferHandler(PluginInfo.PHASE1, PluginInfo.SUPPLEMENT));
        listPluginSupplement2
                .setTransferHandler(new PluginTransferHandler(PluginInfo.PHASE2, PluginInfo.SUPPLEMENT));
        listPluginSupplement3
                .setTransferHandler(new PluginTransferHandler(PluginInfo.PHASE3, PluginInfo.SUPPLEMENT));

        listPluginSupplement1.setDropMode(DropMode.ON_OR_INSERT);
        listPluginSupplement2.setDropMode(DropMode.ON_OR_INSERT);
        listPluginSupplement3.setDropMode(DropMode.ON_OR_INSERT);
        listPluginMajor2.setDropMode(DropMode.ON_OR_INSERT);
        listPluginMajor3.setDropMode(DropMode.ON_OR_INSERT);

        listPluginMajor2.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listPluginMajor3.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listPluginSupplement1.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listPluginSupplement2.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listPluginSupplement3.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        listPluginMajor2.setDragEnabled(true);
        listPluginMajor3.setDragEnabled(true);
        listPluginSupplement1.setDragEnabled(true);
        listPluginSupplement2.setDragEnabled(true);
        listPluginSupplement3.setDragEnabled(true);

        tree.setDragEnabled(true);
        tempPlugin = new PluginInfo("", 0, 0);

        workflow = new Workflow();

        // Show the main frame on the screen
        mainFrame.setVisible(true);

        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.expandRow(i);
        }

        splitPaneTop.setDividerLocation(0.3);
        splitPaneBottom.setDividerLocation(0.5);
    }

    /**
     * Setting of the split panel for plug-in pool and the work flow.
     * @return the split panel
     */
    private JComponent createPaneNorth() {
        splitPaneTop = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        splitPaneTop.setLeftComponent(createPluginPool());
        splitPaneTop.setRightComponent(createWorkflow());
        splitPaneTop.setOneTouchExpandable(true);

        return splitPaneTop;
    }

    /**
     * Setting of the plug-in tree view.
     * @return the plug-in tree view
     */
    private JComponent createPluginPool() {
        DefaultMutableTreeNode top = new DefaultMutableTreeNode("HanNanum Plug-in Pool");
        createPluginNodes(top);
        loadPluginInformation();

        tree = new JTree(top);
        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        tree.addTreeSelectionListener(new PluginTreeSelectionListener());

        tree.putClientProperty("JTree.lineStyle", "Horizontal");

        JScrollPane treeView = new JScrollPane(tree);

        return treeView;
    }

    /**
     * Setting of the each plug-in which is in the tree view.
     * @param top - default top tree node
     */
    private void createPluginNodes(DefaultMutableTreeNode top) {
        DefaultMutableTreeNode phase = null;
        DefaultMutableTreeNode type = null;

        phase = new DefaultMutableTreeNode("Phase1 Plug-in. Plain Text Processing");
        type = new DefaultMutableTreeNode("Supplement Plugin");
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("InformalSentenceFilter", PluginInfo.PHASE1, PluginInfo.SUPPLEMENT)));
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("SentenceSegmentor", PluginInfo.PHASE1, PluginInfo.SUPPLEMENT)));
        phase.add(type);
        top.add(phase);

        phase = new DefaultMutableTreeNode("Phase2 Plug-in. Morphological Analysis");
        type = new DefaultMutableTreeNode("Major Plug-in");
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("ChartMorphAnalyzer", PluginInfo.PHASE2, PluginInfo.MAJOR)));
        phase.add(type);
        type = new DefaultMutableTreeNode("Supplement Plug-in");
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("UnknownMorphProcessor", PluginInfo.PHASE2, PluginInfo.SUPPLEMENT)));
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("SimpleMAResult09", PluginInfo.PHASE2, PluginInfo.SUPPLEMENT)));
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("SimpleMAResult22", PluginInfo.PHASE2, PluginInfo.SUPPLEMENT)));

        phase.add(type);
        top.add(phase);

        phase = new DefaultMutableTreeNode("Phase3 Plug-in. Part Of Speech Tagging");
        type = new DefaultMutableTreeNode("Major Plug-in");
        type.add(new DefaultMutableTreeNode(new PluginInfo("HmmPosTagger", PluginInfo.PHASE3, PluginInfo.MAJOR)));
        phase.add(type);
        type = new DefaultMutableTreeNode("Supplement Plug-in");
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("NounExtractor", PluginInfo.PHASE3, PluginInfo.SUPPLEMENT)));
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("SimplePOSResult09", PluginInfo.PHASE3, PluginInfo.SUPPLEMENT)));
        type.add(new DefaultMutableTreeNode(
                new PluginInfo("SimplePOSResult22", PluginInfo.PHASE3, PluginInfo.SUPPLEMENT)));
        phase.add(type);
        top.add(phase);
    }

    /**
     * It loads the meta information for each plug-in from the configuration files.
     */
    private void loadPluginInformation() {
        try {
            pluginInfoMap = new HashMap<String, String>();
            pluginInfoMap.put("InformalSentenceFilter", getPluginAbstarct(
                    "conf/plugin/SupplementPlugin/PlainTextProcessor/InformalSentenceFilter.json"));
            pluginInfoMap.put("SentenceSegmentor",
                    getPluginAbstarct("conf/plugin/SupplementPlugin/PlainTextProcessor/SentenceSegmentor.json"));
            pluginInfoMap.put("ChartMorphAnalyzer",
                    getPluginAbstarct("conf/plugin/MajorPlugin/MorphAnalyzer/ChartMorphAnalyzer.json"));
            pluginInfoMap.put("UnknownMorphProcessor",
                    getPluginAbstarct("conf/plugin/SupplementPlugin/MorphemeProcessor/UnknownMorphProcessor.json"));
            pluginInfoMap.put("SimpleMAResult09",
                    getPluginAbstarct("conf/plugin/SupplementPlugin/MorphemeProcessor/SimpleMAResult09.json"));
            pluginInfoMap.put("SimpleMAResult22",
                    getPluginAbstarct("conf/plugin/SupplementPlugin/MorphemeProcessor/SimpleMAResult22.json"));
            pluginInfoMap.put("HmmPosTagger",
                    getPluginAbstarct("conf/plugin/MajorPlugin/PosTagger/HmmPosTagger.json"));
            pluginInfoMap.put("NounExtractor",
                    getPluginAbstarct("conf/plugin/SupplementPlugin/PosProcessor/NounExtractor.json"));
            pluginInfoMap.put("SimplePOSResult09",
                    getPluginAbstarct("conf/plugin/SupplementPlugin/PosProcessor/SimplePOSResult09.json"));
            pluginInfoMap.put("SimplePOSResult22",
                    getPluginAbstarct("conf/plugin/SupplementPlugin/PosProcessor/SimplePOSResult22.json"));
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Returns the abstract text for a plug-in from the specified configuration file.
     * @param filePath - the configuration file for the plug-in written in JSON format
     * @return the abstract text for the specified plug-in
     * @throws JSONException
     * @throws IOException
     */
    private String getPluginAbstarct(String filePath) throws JSONException, IOException {
        JSONReader json = new JSONReader(filePath);
        String res = null;

        res = String.format("* Name: %s\n* Type: %s\n* Version: %s\n* Author: %s\n* Description: %s\n",
                json.getName(), json.getType(), json.getVersion(), json.getAuthor(), json.getDescription());
        return res;
    }

    /**
     * This class has the properties of a HanNanum plug-in.
     * 
     * @author Sangwon Park (hudoni@world.kaist.ac.kr), CILab, SWRC, KAIST
     */
    private class PluginInfo {
        /**
         * A plug-in for the first phase on the work flow.
         */
        public static final int PHASE1 = 1;

        /**
         * A plug-in for the second phase one the work flow.
         */
        public static final int PHASE2 = 2;

        /**
         * A plug-in for the third phase on the work flow.
         */
        public static final int PHASE3 = 3;

        /**
         * A plug-in that is a major.
         */
        public static final int MAJOR = 1;

        /**
         * A plug-in that is a supplement.
         */
        public static final int SUPPLEMENT = 2;

        /**
         * The name of the plug-in.
         */
        public String name = null;

        /**
         * The phase of the plug-in on the work flow. PHASE1 or PHASE2 or PHASE3.
         */
        public int phase = 0;

        /**
         * The type of the plug-in. MAJOR or SUPPLEMENT.
         */
        public int type = 0;

        /**
         * Constructor.
         * @param name - the name of the plug-in
         * @param phase - the phase of the plug-in on the work flow. PHASE1 or PHASE2 or PHASE3.
         * @param type - the type of the plug-in. MAJOR or SUPPLEMENT.
         */
        public PluginInfo(String name, int phase, int type) {
            this.name = name;
            this.phase = phase;
            this.type = type;
        }

        /**
         * Returns the name of the plug-in.
         */
        public String toString() {
            return name;
        }
    }

    /**
     * Event listener for the plug-in selection on the tree view.
     * 
     * @author Sangwon Park (hudoni@world.kaist.ac.kr), CILab, SWRC, KAIST
     */
    private class PluginTreeSelectionListener implements TreeSelectionListener {
        /**
         * It is called when the new plug-in was selected.
         */
        public void valueChanged(TreeSelectionEvent e) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

            if (node == null) {
                selectedPlugin = null;
                return;
            }

            Object nodeInfo = node.getUserObject();

            if (node.isLeaf()) {
                selectedPlugin = (PluginInfo) nodeInfo;
                areaPluginInfo.setText(pluginInfoMap.get((selectedPlugin.name)));
            } else {
                selectedPlugin = null;
            }
        }
    }

    /**
     * Event listener for the plug-in selection on the list for the work flow.
     * 
     * @author Sangwon Park (hudoni@world.kaist.ac.kr), CILab, SWRC, KAIST
     */
    private class PluginListMouseListener implements MouseListener {
        /**
         * The plug-in list where this listener is going to work.
         */
        private JList list = null;

        /**
         * The model of plug-in list where this listener is going to work.
         */
        private DefaultListModel listModel = null;

        /**
         * Constructor.
         * @param list - the plug-in list for the work flow
         * @param listModel - the model for the plug-in list
         */
        public PluginListMouseListener(JList list, DefaultListModel listModel) {
            this.list = list;
            this.listModel = listModel;
        }

        /**
         * It is called when an mouse click event occur on the list.
         */
        @Override
        public void mouseClicked(MouseEvent e) {
            if (e.getClickCount() == 2) {
                listModel.remove(this.list.locationToIndex(e.getPoint()));
            } else {
                try {
                    areaPluginInfo.setText(
                            pluginInfoMap.get((String) listModel.get(this.list.locationToIndex(e.getPoint()))));
                } catch (Exception e1) {
                }
            }
        }

        /**
          * It is called when an mouse enter event occur on the list.
          */
        @Override
        public void mouseEntered(MouseEvent e) {
        }

        /**
          * It is called when an mouse exited event occur on the list.
          */
        @Override
        public void mouseExited(MouseEvent e) {
        }

        /**
          * It is called when an mouse pressed event occur on the list.
          */
        @Override
        public void mousePressed(MouseEvent e) {
        }

        /**
          * It is called when an mouse released event occur on the list.
          */
        @Override
        public void mouseReleased(MouseEvent e) {
        }
    }

    /**
     * Returns the panel for the work flow.
     * 
     * @return the panel for the work flow
     */
    private JComponent createWorkflow() {
        JPanel workflowPanel = new JPanel(new GridLayout(1, 3));

        listModelMajor2 = new DefaultListModel();
        listModelMajor3 = new DefaultListModel();
        listModelSupplement1 = new DefaultListModel();
        listModelSupplement2 = new DefaultListModel();
        listModelSupplement3 = new DefaultListModel();

        listPluginMajor2 = new JList(listModelMajor2);
        listPluginMajor3 = new JList(listModelMajor3);
        listPluginSupplement1 = new JList(listModelSupplement1);
        listPluginSupplement2 = new JList(listModelSupplement2);
        listPluginSupplement3 = new JList(listModelSupplement3);

        // phase1
        JPanel phasePanel = new JPanel(new GridLayout(1, 1));
        phasePanel.setBorder(BorderFactory.createTitledBorder("Phase1. Plain Text Processing"));
        JPanel listPanel = new JPanel(new GridLayout(1, 1));
        listPanel.setBorder(BorderFactory.createTitledBorder("Supplement Plug-in"));
        JScrollPane scroll = new JScrollPane();
        scroll.setViewportView(listPluginSupplement1);
        listPanel.add(scroll);
        phasePanel.add(listPanel);
        workflowPanel.add(phasePanel);

        // phase2
        phasePanel = new JPanel(new GridLayout(1, 2));
        phasePanel.setBorder(BorderFactory.createTitledBorder("Phase2. Morphological Analysis"));
        listPanel = new JPanel(new GridLayout(1, 1));
        listPanel.setBorder(BorderFactory.createTitledBorder("Major Plug-in"));
        scroll = new JScrollPane();
        scroll.setViewportView(listPluginMajor2);
        listPanel.add(scroll);
        phasePanel.add(listPanel);

        listPanel = new JPanel(new GridLayout(1, 1));
        listPanel.setBorder(BorderFactory.createTitledBorder("Supplement Plug-in"));
        scroll = new JScrollPane();
        scroll.setViewportView(listPluginSupplement2);
        listPanel.add(scroll);
        phasePanel.add(listPanel);

        workflowPanel.add(phasePanel);

        // phase3
        phasePanel = new JPanel(new GridLayout(1, 2));
        phasePanel.setBorder(BorderFactory.createTitledBorder("Phase3. Part Of Speech Tagging"));
        listPanel = new JPanel(new GridLayout(1, 1));
        listPanel.setBorder(BorderFactory.createTitledBorder("Major Plug-in"));
        scroll = new JScrollPane();
        scroll.setViewportView(listPluginMajor3);
        listPanel.add(scroll);
        phasePanel.add(listPanel);

        listPanel = new JPanel(new GridLayout(1, 1));
        listPanel.setBorder(BorderFactory.createTitledBorder("Supplement Plug-in"));
        scroll = new JScrollPane();
        scroll.setViewportView(listPluginSupplement3);
        listPanel.add(scroll);
        phasePanel.add(listPanel);

        workflowPanel.add(phasePanel);

        /////////////////////////////////////////////////////////////////////////////////////

        JPanel controlPanel = new JPanel(new GridLayout(4, 1));
        controlPanel.setBorder(BorderFactory.createTitledBorder("Workflow Control"));
        buttonActivate = new JButton("Activate the workflow");
        buttonAnalysis = new JButton("Analyze Text");
        buttonReset = new JButton("Close the workflow");

        JPanel threadPanel = new JPanel(new GridLayout(1, 1));
        radioMultiThread = new JRadioButton("Mutli-thread Mode", true);
        radioSingleThread = new JRadioButton("Single-thread Mode", false);
        threadPanel.setBorder(BorderFactory.createTitledBorder("Thread Mode"));
        threadPanel.add(radioMultiThread);
        threadPanel.add(radioSingleThread);
        ButtonGroup groupThread = new ButtonGroup();
        groupThread.add(radioMultiThread);
        groupThread.add(radioSingleThread);

        controlPanel.add(threadPanel);
        controlPanel.add(buttonActivate);
        controlPanel.add(buttonAnalysis);
        controlPanel.add(buttonReset);

        buttonAnalysis.setEnabled(false);
        buttonReset.setEnabled(false);

        /////////////////////////////////////////////////////////////////////////////////////

        JPanel pluginInfoPanel = new JPanel(new GridLayout(1, 1));
        pluginInfoPanel.setBorder(BorderFactory.createTitledBorder("Plug-in Information"));
        areaPluginInfo = new JTextArea();
        areaPluginInfo.setLineWrap(true);
        scroll = new JScrollPane();
        scroll.setViewportView(areaPluginInfo);
        pluginInfoPanel.add(scroll);

        JPanel infoPanel = new JPanel(new GridLayout(1, 2));
        infoPanel.add(pluginInfoPanel);
        infoPanel.add(controlPanel);

        JPanel panel = new JPanel(new GridLayout(2, 1));
        workflowPanel.setBorder(BorderFactory.createTitledBorder("HanNanum Workflow"));
        panel.add(workflowPanel);
        panel.add(infoPanel);

        return panel;
    }

    /**
     * Returns a panel for the input and output text areas.
     * 
     * @return a panel for the input and output text areas
     */
    private JComponent createPaneCenter() {
        splitPaneBottom = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        JPanel panel = new JPanel(new GridLayout(1, 1));
        panel.setBorder(BorderFactory.createTitledBorder("Input Text"));
        inputTextArea = new JTextArea();
        JScrollPane scroll = new JScrollPane();
        scroll.setViewportView(inputTextArea);
        panel.add(scroll);
        splitPaneBottom.setLeftComponent(panel);

        panel = new JPanel(new GridLayout(1, 1));
        panel.setBorder(BorderFactory.createTitledBorder("Result"));
        outputTextArea = new JTextArea();
        scroll = new JScrollPane();
        scroll.setViewportView(outputTextArea);
        panel.add(scroll);
        splitPaneBottom.setRightComponent(panel);

        splitPaneBottom.setOneTouchExpandable(true);

        return splitPaneBottom;
    }

    /**
     * The event handler that is used in various purpose.
     * 
     * @author Sangwon Park (hudoni@world.kaist.ac.kr), CILab, SWRC, KAIST
     */
    private class SharedActionHandler implements ActionListener {
        /**
         * Performs an action depending on the given action event.
         */
        public void actionPerformed(ActionEvent e) {
            try {
                Object source = e.getSource();

                if (source == menuItemFileOpen) {
                    fileOpen();
                } else if (source == menuItemHelp) {
                    help();
                } else if (source == buttonActivate) {
                    initWorkflow();
                    activateWorkflow();
                } else if (source == buttonAnalysis) {
                    analyzeText();
                } else if (source == buttonReset) {
                    reset();
                } else if (source == radioMultiThread) {
                    multiThreadMode = true;
                } else if (source == radioSingleThread) {
                    multiThreadMode = false;
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }

        /**
         * Reads a text file, and use the text as the input data.
         */
        private void fileOpen() {
            JFileChooser chooser = new JFileChooser();

            chooser.setCurrentDirectory(new java.io.File("."));
            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            chooser.setAcceptAllFileFilterUsed(false);

            if (chooser.showOpenDialog(mainFrame) == JFileChooser.APPROVE_OPTION) {
                File selectedFile = chooser.getSelectedFile();

                try {
                    BufferedReader br = new BufferedReader(new FileReader(selectedFile));
                    String line = null;
                    while ((line = br.readLine()) != null) {
                        inputTextArea.append(line + "\n");
                    }
                    br.close();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * Show 'help' window.
         */
        private void help() {
            String helpStr = "  This is a GUI-based demo program of the HanNanum that helps users to understand the concept\n"
                    + "of work flow and use the HanNanum library easily. This consists of components for plug-in pool,\n"
                    + "work flow, plug-in information, work flow controls, input text and analysis result. Users can\n"
                    + "easily set up various work flows by drag-and-drop the plug-ins from the plug-in pool to the work\n"
                    + "flow component, and see the analysis result.\n\n" +

                    "  Users can use this GUI demo program by following procedure:\n\n"
                    + "  1. Browse the plug-ins in the plug-in pool. The brief information about the selected plug-in will be\n"
                    + "    displayed so that you can refer the information when set the work flow up.\n\n"
                    + "  2. Drag and drop plug-ins from the plug-in pool to the list in the work flow considering the phase\n"
                    + "    and type of the plug-in.\n "
                    + "    - If you want to remove the plug-in on the work flow, simply double click it.\n "
                    + "    - If you change the order of the supplement plug-ins in each phase, simply drag and drop a plug-in\n"
                    + "      to the position you want.\n\n"
                    + "  3. Once you finish to set the work flow up, choose 'Multi-thread Mode' or 'Single-thread Mode'.\n\n"
                    + "  4. Click 'Activate the work flow' button.\n\n"
                    + "  5. Type or copy-and-past text that you want to analyze into the 'Input Text' area.\n\n"
                    + "  6. Click 'Analyze Text' button.\n\n"
                    + "  7. You can see the analysis result on 'Result' area.\n\n"
                    + "  8. Repeat 5~7 to analyze other text with the activated work flow.\n"
                    + "    Or click 'Close the work flow' button and go to step 1 to set up new work flow. \n\n" +

                    "  Author: Sangwon Park (hudoni@world.kaist.ac.kr), CILab, SWRC, KAIST\n";
            JOptionPane.showMessageDialog(mainFrame, helpStr);
        }

        /**
         * Initialize the work flow with the sequence of the plug-ins that the user selected.
         */
        private void initWorkflow() {
            /* Clear the previous work flow */
            workflow.clear();

            /* Set the work flow up */
            String pluginName = null;

            // phase1 plug-in
            for (int i = 0; i < listModelSupplement1.size(); i++) {
                pluginName = (String) listModelSupplement1.get(i);
                if (pluginName.equals("InformalSentenceFilter")) {
                    workflow.appendPlainTextProcessor(new InformalSentenceFilter(), null);
                } else if (pluginName.equals("SentenceSegmentor")) {
                    workflow.appendPlainTextProcessor(new SentenceSegmentor(), null);
                }
            }

            // phase2 plug-in
            if (listModelMajor2.size() > 0) {
                pluginName = (String) listModelMajor2.get(0);
                if (pluginName.equals("ChartMorphAnalyzer")) {
                    workflow.setMorphAnalyzer(new ChartMorphAnalyzer(),
                            "conf/plugin/MajorPlugin/MorphAnalyzer/ChartMorphAnalyzer.json");
                }
            } else {
                return;
            }

            for (int i = 0; i < listModelSupplement2.size(); i++) {
                pluginName = (String) listModelSupplement2.get(i);
                if (pluginName.equals("UnknownMorphProcessor")) {
                    workflow.appendMorphemeProcessor(new UnknownProcessor(), null);
                } else if (pluginName.equals("SimpleMAResult09")) {
                    workflow.appendMorphemeProcessor(new SimpleMAResult09(), null);
                } else if (pluginName.equals("SimpleMAResult22")) {
                    workflow.appendMorphemeProcessor(new SimpleMAResult22(), null);
                }
            }

            // phase3 plug-in
            if (listModelMajor3.size() > 0) {
                pluginName = (String) listModelMajor3.get(0);
                if (pluginName.equals("HmmPosTagger")) {
                    workflow.setPosTagger(new HMMTagger(), "conf/plugin/MajorPlugin/PosTagger/HmmPosTagger.json");
                }
            } else {
                return;
            }
            for (int i = 0; i < listModelSupplement3.size(); i++) {
                pluginName = (String) listModelSupplement3.get(i);
                if (pluginName.equals("NounExtractor")) {
                    workflow.appendPosProcessor(new NounExtractor(), null);
                } else if (pluginName.equals("SimplePOSResult09")) {
                    workflow.appendPosProcessor(new SimplePOSResult09(), null);
                } else if (pluginName.equals("SimplePOSResult22")) {
                    workflow.appendPosProcessor(new SimplePOSResult22(), null);
                }
            }
        }

        /**
         * Activates the work flow.
         */
        private void activateWorkflow() {
            try {
                workflow.activateWorkflow(multiThreadMode);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            buttonAnalysis.setEnabled(true);
            buttonReset.setEnabled(true);
            buttonActivate.setEnabled(false);
            radioMultiThread.setEnabled(false);
            radioSingleThread.setEnabled(false);
            listPluginSupplement1.setEnabled(false);
            listPluginSupplement2.setEnabled(false);
            listPluginSupplement3.setEnabled(false);
            listPluginMajor2.setEnabled(false);
            listPluginMajor3.setEnabled(false);

            activated = true;
        }

        /**
         * Analyze the input text with the activated work flow.
         */
        private void analyzeText() {
            String text = inputTextArea.getText();

            if (text != null && text.length() > 0) {
                workflow.analyze(inputTextArea.getText());
                outputTextArea.setText(workflow.getResultOfDocument());

                buttonReset.setEnabled(true);
                buttonActivate.setEnabled(false);
            } else {
                outputTextArea.setText("");
            }
        }

        /**
         * Reset the work flow and the demo program.
         */
        private void reset() {
            workflow.clear();

            buttonActivate.setEnabled(true);
            buttonAnalysis.setEnabled(false);
            buttonReset.setEnabled(false);
            radioMultiThread.setEnabled(true);
            radioSingleThread.setEnabled(true);
            listPluginSupplement1.setEnabled(true);
            listPluginSupplement2.setEnabled(true);
            listPluginSupplement3.setEnabled(true);
            listPluginMajor2.setEnabled(true);
            listPluginMajor3.setEnabled(true);

            activated = false;
        }
    }

    /**
     * Handler for the drag-and-drop functionality of plug-in from the plug-in pool to
     * the work flow.
     * 
     * @author Sangwon Park (hudoni@world.kaist.ac.kr), CILab, SWRC, KAIST
     */
    private class PluginTransferHandler extends TransferHandler {
        /**
         * serialVersionUID
         */
        private static final long serialVersionUID = 1L;

        /**
         * The phase of the plug-in on the work flow.
         * PluginInfo.PHASE1 or PluginInfo.PHASE2 or PluginInfo.PHASE3.
         */
        private int phase = 0;

        /**
         * The type of the plug-in.
         * PluginInfo.MAJOR or PluginInfo.SUPPLEMENT.
         */
        private int type = 0;

        /**
         * Constructor.
         * @param phase - the phase of the plug-in. PluginInfo.PHASE1 or PluginInfo.PHASE2 or PluginInfo.PHASE3.
         * @param type - the type of the plug-in. PluginInfo.MAJOR or PluginInfo.SUPPLEMENT.
         */
        public PluginTransferHandler(int phase, int type) {
            this.phase = phase;
            this.type = type;
        }

        /**
         * Returns true when it is possible to drag and drop the plug-in.
         */
        public boolean canImport(TransferHandler.TransferSupport info) {
            if (!activated && selectedPlugin != null && phase == selectedPlugin.phase
                    && type == selectedPlugin.type) {
                return true;
            }
            return false;
        }

        /**
         * It transfers the meta data of the plug-in from the plug-in pool to the work flow list.
         * 
         * @return true: transference was done correctly, otherwise false
         */
        public boolean importData(TransferHandler.TransferSupport info) {
            if (!info.isDrop()) {
                return false;
            }

            if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                return false;
            }

            JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
            DefaultListModel listModel = null;
            int index = dl.getIndex();

            switch (selectedPlugin.phase) {
            case PluginInfo.PHASE1:
                listModel = (DefaultListModel) listPluginSupplement1.getModel();
                break;
            case PluginInfo.PHASE2:
                if (selectedPlugin.type == PluginInfo.MAJOR) {
                    listModel = (DefaultListModel) listPluginMajor2.getModel();
                    listModel.clear();
                    index = 0;
                } else if (selectedPlugin.type == PluginInfo.SUPPLEMENT) {
                    listModel = (DefaultListModel) listPluginSupplement2.getModel();
                }
                break;
            case PluginInfo.PHASE3:
                if (selectedPlugin.type == PluginInfo.MAJOR) {
                    listModel = (DefaultListModel) listPluginMajor3.getModel();
                    listModel.clear();
                    index = 0;
                } else if (selectedPlugin.type == PluginInfo.SUPPLEMENT) {
                    listModel = (DefaultListModel) listPluginSupplement3.getModel();
                }
                break;
            }

            if (listModel == null) {
                return false;
            }

            try {
                Transferable t = info.getTransferable();
                String data = (String) t.getTransferData(DataFlavor.stringFlavor);
                int pIndex = listModel.indexOf(data);

                listModel.add(index, data);

                if (pIndex != -1) {
                    if (pIndex >= index) {
                        pIndex++;
                    }
                    listModel.remove(pIndex);
                }
            } catch (Exception e) {
                return false;
            }

            return false;
        }

        /**
         * Returns the type of action at the source component.
         */
        public int getSourceActions(JComponent c) {
            return COPY;
        }

        /**
         * Make it possible to transfer the selected plug-in.
         * Just one plug-in can be transfered, but it can be improved.
         */
        protected Transferable createTransferable(JComponent c) {
            JList list = (JList) c;
            Object[] values = list.getSelectedValues();

            StringBuffer buff = new StringBuffer();

            if (values.length >= 0) {
                Object val = values[0];
                buff.append(val);
            }

            tempPlugin.name = buff.toString();
            tempPlugin.phase = phase;
            tempPlugin.type = type;
            selectedPlugin = tempPlugin;

            return new StringSelection(buff.toString());
        }
    }
}