/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/07/13, 13:12
!  AUTHOR(S): KOGA, Junichiro
!  File : ProjectDirBrowser.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.projectbrowser.projectdirbrowser;

import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.border.TitledBorder;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;

import ciss.phase_viewer.common.MyThread;
import ciss.phase_viewer.common.Utils;
import ciss.phase_viewer.jdom.MyElement;
import ciss.phase_viewer.jdom.XMLUtils;
import ciss.phase_viewer.mainpanel.ChaseGUI;
import ciss.phase_viewer.mainpanel.ChaseProgressMonitor;
import ciss.phase_viewer.mainpanel.Desk;
import ciss.phase_viewer.mainpanel.ProgressInfo;
import ciss.phase_viewer.projectbrowser.ProjectBrowser;
import ciss.phase_viewer.projectbrowser.ProjectBrowserUtils;
import ciss.phase_viewer.projectbrowser.ProjectInfo;
import ciss.phase_viewer.projectbrowser.ProjectManipulator;
import ciss.phase_viewer.projectbrowser.projectstatemanipulator.NewProjectCreator;
import ciss.phase_viewer.projectbrowser.projectstatemanipulator.NewSubProjectCreator;
import ciss.phase_viewer.projectbrowser.projectstatemanipulator.ProjectRemover;
import ciss.phase_viewer.projectbrowser.projectstatemanipulator.ProjectState;
import ciss.phase_viewer.projectbrowser.projectstatemanipulator.ProjectStateChangeEvent;
import ciss.phase_viewer.projectbrowser.projectstatemanipulator.ProjectStateChangeListener;
import ciss.phase_viewer.settings.GlobalProperties;
import ciss.phase_viewer.settings.PropertiesManager;

/**
 * creates a JTree representation of user projects. User projects are specified
 * in $HOME/.phase-viewer/my_projects.xml file, and should basically be
 * self-explanatory.
 * 
 * @author KOGA, Junichiro
 */
public class ProjectDirBrowser extends JPanel implements
        ProjectDirBrowserNodeChangeListener, ProjectStateChangeListener,
        Serializable {
    private Logger logger = Logger.getLogger(ProjectDirBrowser.class.getName());

    private JSplitPane splitpane;

    public static String MY_PROJECTS = System.getProperty("user.home")
            + System.getProperty("file.separator") + ".phase-viewer"
            + System.getProperty("file.separator") + "my_projects.xml";

    private ProjectDirBrowserTree tree;

    private DefaultTreeModel treeModel;

    private ProjectDirBrowserNode rootNode;

    private ProjectBrowser parent;

    private static Document doc;

    private boolean reuse = false;

    private GlobalProperties gp = PropertiesManager
            .getGlobalProperties(PropertiesManager.PROPERTIES_PVIEWER);

    private Vector nodelisteners = new Vector();

    private ProjectDirBrowser browser;

    private boolean monitor = false;

    private Vector projbuf = new Vector();

    /** Creates a new instance of ProjectDirBrowser */
    public ProjectDirBrowser(String title) {
        this.setBorder(new TitledBorder(title));
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        this.browser = this;
        reuse = new Boolean(gp.getProperty("project_browser_reuse_window"))
                .booleanValue();
        nodelisteners.addElement(this);
        init();
    }

    public ProjectDirBrowser(String title, boolean monitor) {
        this.monitor = monitor;
        this.setBorder(new TitledBorder(title));
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        this.browser = this;
        reuse = new Boolean(gp.getProperty("project_browser_reuse_window"))
                .booleanValue();
        nodelisteners.addElement(this);
        init();
    }

    class Monitor implements Runnable, ProgressInfo {
        Window wi;

        public void run() {
            ChaseProgressMonitor mon = ChaseProgressMonitor.getMonitor();
            mon.setProgress(this);
            JFrame win = new JFrame();
            wi = new Window(win);
            int scrx = ChaseGUI.getScreenWidth();
            int scry = ChaseGUI.getScreenHeight();
            Dimension dim = mon.getPreferredSize();
            int centerx = (int) ((scrx / 2) - (dim.getWidth() / 2));
            int centery = (int) (scry / 2) + 150;
            wi.setLocation(centerx, centery);
            wi.setSize(mon.getPreferredSize());
            wi.add(mon);
            wi.setVisible(true);
        }

        public boolean isDone() {
            return currentsubproject >= numproj;
        }

        public String getNameOfProgress() {
            return "loading project info...";
        }

        public int getLength() {
            return numproj;
        }

        public String getCurrentMessage() {
            return null;
        }

        public int getCurrent() {
            return currentsubproject;
        }

        public void done() {
            logger.debug("!!finished loading projects!!");
            if (wi != null) {
                wi.setVisible(false);
                wi.dispose();
            }
        }
    }

    /**
     * (自分自身以外の)リスナーを渡しておいた方が便利な場合もある.
     * 
     * @param title
     * @param listener
     *            nodeの変更を通知されるクラス.
     */
    public ProjectDirBrowser(String title,
            ProjectDirBrowserNodeChangeListener[] listener) {
        this.setBorder(new TitledBorder(title));
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        reuse = new Boolean(gp.getProperty("project_browser_reuse_window"))
                .booleanValue();
        if (listener != null) {
            for (int i = 0; i < listener.length; i++) {
                nodelisteners.addElement(listener[i]);
            }
        }
        init();
    }

    public void setProjectBrowser(ProjectBrowser parent) {
        this.parent = parent;
    }

    /**
     * 付属のサンプルをロードするメソッド. サンプルは,
     * CHASE_HOME/samples/gui_samples/spec.xmlを指定すればロードできるようにしておく.
     * このファイルが無い場合なにもしない.
     */
    public void loadSample() {
        File sampleSpec = new File(System.getProperty("pviewer.home")
                + System.getProperty("file.separator") + "samples"
                + System.getProperty("file.separator") + "gui_samples"
                + System.getProperty("file.separator") + "spec.xml");
        // int size = Utils.getDirSize(new
        // File(System.getProperty("pviewer.home")+System.getProperty("file.separator")+"samples"+System.getProperty("file.separator")+"gui_samples"));
        int numdir = Utils.getTotalNumDir(new File(System
                .getProperty("pviewer.home")
                + System.getProperty("file.separator")
                + "samples"
                + System.getProperty("file.separator") + "gui_samples"));
        logger.debug("number of directories: " + numdir);
        ProgressBar ba = new ProgressBar(numdir, getRootNode());
        String versionno = ciss.phase_viewer.main.PhaseViewerMain
                .getDefaultPropertiesDocument().getRootElement()
                .getChildTextTrim("version");
        if (sampleSpec.exists())
            importSub(sampleSpec, getRootNode(), "_ver" + versionno);
        ba.dispose();
    }

    class ProgressBar extends JFrame {
        private JProgressBar bar;
        private ProjectDirBrowserNode currnode;
        private javax.swing.Timer timer;

        ProgressBar(int numdir, ProjectDirBrowserNode currnode) {
            super("loading samples...");
            this.currnode = currnode;
            bar = new JProgressBar(0, numdir);
            bar.setPreferredSize(new Dimension(300, 20));
            bar.setStringPainted(true);
            update();

            getContentPane().add(bar);
            pack();
            int scrx = ChaseGUI.getScreenWidth();
            int scry = ChaseGUI.getScreenHeight();
            int centerx = (int) (scrx / 2 - getSize().width / 2);
            int centery = (int) (scry / 2 - getSize().height / 2);
            setLocation(centerx, centery);
            setVisible(true);
            timer = new javax.swing.Timer(0, new ActionListener() {
                public void actionPerformed(ActionEvent ae) {
                    update();
                }
            });
            timer.start();
        }

        private int currnumdir = 0;

        void setCurrDirNum(int currnumdir) {
            this.currnumdir = currnumdir;
        }

        private void update() {
            bar.setValue(Utils.getTotalNumDir(new File(currnode
                    .getProjectInfo().getProjectDirectory())));
        }

        public void dispose() {
            super.dispose();
            timer.stop();
            timer = null;
        }
    }

    /**
     * this method is called when a node is selected by the user. From the node,
     * we first get an instance of a ProjectInfo class, which encapsulates
     * information regarding the selected project, i.e., the type of project,
     * the date of creation, or the path to its base directory. In particular,
     * once the 'type' of the project is known, it is possible to create a
     * concrete object of a 'ProjectManipulator', which is shown on the right of
     * the ProjectBrowser frame, and is responsible for whatever manipulations
     * we want to provide for the user.
     */
    public void nodeSelected(ProjectDirBrowserNodeChangeEvent e) {
        if (e == null || e.getSource() == null) {
            return;
        }
        ProjectDirBrowserNode node = (ProjectDirBrowserNode) e.getSource();
        ProjectInfo proj = node.getProjectInfo();

        ProjectManipulator component = null;
        if (proj != null) {
            component = ProjectManipulator.createProjectManipulator(proj);
            if (component == null) {
                return;
            }
        }
        // String sx = gp.getProperty("project_browser_init_x");
        // String sy = gp.getProperty("project_browser_init_y");
        // int x = 980;
        // int y = 630;
        // try {
        // x = Integer.parseInt(sx);
        // y = Integer.parseInt(sy);
        // } catch(NumberFormatException nfe){
        // } catch(NullPointerException npe) {
        // }
        if (!reuse) {
            if (node.getProjectBrowser() == null
                    || !node.getProjectBrowser().isVisible()) {
                Dimension dim = proj.getInitialBrowserSize();
                parent = new ProjectBrowser(dim, proj);
            } else {
                if (!node.getProjectBrowser().isSelected()) {
                    try {
                        node.getProjectBrowser().setSelected(true);
                    } catch (java.beans.PropertyVetoException vpe) {
                    }
                }
                return;
            }
        } else {
            if (parent == null || !parent.isVisible()) {
                Dimension dim = proj.getInitialBrowserSize();
                parent = new ProjectBrowser(dim, proj);
            }
            parent.setTitle(proj.getProjectName());
        }

        if (component != null) {
            component.init();
            parent.setProjectManipulator(component);
            parent.registerProjectManipulators(component);
        }
        proj.setParent(parent);
        node.setProjectBrowser(parent);
        parent.setAssociatedNode(node);
        parent.revalidate();
    }

    public void projectStateChanged(ProjectStateChangeEvent e) {
        updateTree();
        String selectMe = e.select();
        // logger.info("selectMe: "+selectMe);
        if (selectMe != null && selectMe.length() != 0
                && tree.getSelectionRows() != null) {
            TreePath path = tree.getNextMatch(selectMe,
                    tree.getSelectionRows()[0],
                    javax.swing.text.Position.Bias.Forward);
            tree.setSelectionPath(path);
            logger.debug("new proj path: " + path);
        }
    }

    public void recreate() {
        int[] rows = tree.getSelectionRows();
        int row = -1;
        if (rows != null && rows.length > 0) {
            row = rows[0];
        }
        boolean bool = false;
        if (row >= 0) {
            bool = tree.isExpanded(row);
        }
        removeAll();
        init();
        if (row >= 0) {
            tree.setSelectionRow(row);
            if (bool) {
                tree.expandRow(row);
            }
        }
        revalidate();
    }

    public void updateTree() {
        tree.revalidate();
        tree.repaint();
    }

    public void updateTree(ProjectDirBrowserNode node) {
        ((DefaultTreeModel) tree.getModel()).nodeChanged(node);
    }

    public ProjectInfo getSelectedProject() {
        TreePath path = tree.getSelectionPath();
        if (path == null) {
            logger.warn("no project selected.");
            return null;
        }
        Object o = path.getLastPathComponent();
        ProjectInfo ret = null;
        if (o instanceof ProjectDirBrowserNode) {
            ret = ((ProjectDirBrowserNode) o).getProjectInfo();
        }
        return ret;
    }

    public ProjectInfo getRootProject() {
        TreePath path = tree.getPathForRow(0);
        Object o = path.getPathComponent(0);
        ProjectInfo ret = null;
        if (o instanceof ProjectDirBrowserNode) {
            ret = ((ProjectDirBrowserNode) o).getProjectInfo();
        }
        return ret;
    }

    public ProjectDirBrowserNode getRootNode() {
        return this.rootNode;
    }

    public ProjectDirBrowserNode getSelectedNode() {
        TreePath path = tree.getSelectionPath();
        if (path == null) {
            // logger.warn("no project selected.");
            return null;
        }
        Object o = path.getLastPathComponent();
        ProjectDirBrowserNode ret = null;
        if (o instanceof ProjectDirBrowserNode) {
            ret = (ProjectDirBrowserNode) o;
        }
        return ret;
    }

    public JTree getTree() {
        return this.tree;
    }

    public static TreePath getPath(TreeNode node) {
        java.util.List list = new ArrayList();

        // Add all nodes to list
        while (node != null) {
            list.add(node);
            node = node.getParent();
        }
        Collections.reverse(list);

        // Convert array of nodes to TreePath
        return new TreePath(list.toArray());
    }

    /**
     * $HOME/.phase-viewer/my_projects.xmlのDocumentを取得する.
     * 
     * @return 全projectの情報を記述したDocument.
     */
    public static Document getMyProjectsDocument() {
        if (doc == null) {
            doc = ProjectBrowser.getDocument(new File(MY_PROJECTS));
        }
        return doc;
    }

    /**
     * $HOME/.phase-viewer/my_projects.xmlのDocumentを保存.
     */
    public static void saveMyProjectsDocument() {
        ciss.phase_viewer.jdom.XMLUtils.saveDocumentTo(doc, MY_PROJECTS);
    }

    private void defineAccelerators() {
        tree.getInputMap().put(
                KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK),
                "CUT");
        tree.getActionMap().put("CUT", new AbstractAction() {
            public void actionPerformed(ActionEvent ae) {
                doProjectCut(getSelectedNode());
            }
        });
        tree.getInputMap().put(
                KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK),
                "COPY");
        tree.getActionMap().put("COPY", new AbstractAction() {
            public void actionPerformed(ActionEvent ae) {
                doProjectCopy(getSelectedNode());
            }
        });
        tree.getInputMap().put(
                KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK),
                "PASTE");
        tree.getActionMap().put("PASTE", new AbstractAction() {
            public void actionPerformed(ActionEvent ae) {
                doProjectPaste();
            }
        });
        tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0),
                "RENAME");
        tree.getActionMap().put("RENAME", new AbstractAction() {
            public void actionPerformed(ActionEvent ae) {
                bootRenamer(getSelectedNode());
            }
        });
        tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
                "ACTIVATE");
        tree.getActionMap().put("ACTIVATE", new AbstractAction() {
            public void actionPerformed(ActionEvent ae) {
                ProjectDirBrowserNode node = getSelectedNode();
                if (node != null) {
                    node.selectMe();
                    saveMyProjects();
                }
            }
        });
        tree.getInputMap().put(
                KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_MASK),
                "NEWPROJ");
        tree.getActionMap().put("NEWPROJ", new AbstractAction() {
            public void actionPerformed(ActionEvent ae) {
                bootProjectCreator();
            }
        });
        tree.getInputMap().put(
                KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.SHIFT_MASK
                        + KeyEvent.CTRL_MASK), "NEWSUBPROJ");
        tree.getActionMap().put("NEWSUBPROJ", new AbstractAction() {
            public void actionPerformed(ActionEvent ae) {
                bootSubProjectCreator();
            }
        });
        tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
                "REMOVE");
        tree.getActionMap().put("REMOVE", new AbstractAction() {
            public void actionPerformed(ActionEvent ae) {
                bootProjectRemover();
            }
        });

        String os = System.getProperty("os.name").toLowerCase();
        if (os.startsWith("windows") || os.startsWith("linux")) {
            tree.getInputMap().put(
                    KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK),
                    "OPENDIR");
            tree.getActionMap().put("OPENDIR", new AbstractAction() {
                public void actionPerformed(ActionEvent ae) {
                    ProjectDirBrowserNode node = getSelectedNode();
                    if (node != null) {
                        openDir(node.getProjectInfo().getProjectDirectory());
                    }
                }
            });
        }
        tree.getInputMap().put(
                KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_MASK),
                "OPENDIR_BY_PROMPT");
        tree.getActionMap().put("OPENDIR_BY_PROMPT", new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                ProjectDirBrowserNode node = getSelectedNode();
                if (node != null)
                    openDirByPrompt(node.getProjectInfo().getProjectDirectory());
            }
        });

    }

    private int currentsubproject = 0;

    private void init() {
        doc = getMyProjectsDocument();
        Element root = doc.getRootElement();
        if (monitor) {
            calculateNumProjects(root);
            new Thread(new Monitor()).start();
            logger.debug("number of 'subprojects': " + numproj);
        }

        rootNode = new ProjectDirBrowserNode(root, this, monitor);
        for (int i = 0; i < nodelisteners.size(); i++) {
            rootNode.addProjectDirBrowserNodeChangeListener((ProjectDirBrowserNodeChangeListener) nodelisteners
                    .get(i));
        }
        logger.debug(rootNode);
        treeModel = new DefaultTreeModel(rootNode);
        treeModel.addTreeModelListener(new MyTreeModelListener());
        tree = new ProjectDirBrowserTree();
        tree.setModel(treeModel);
        tree.addMouseListener(new MouseAdapterProjectDirBrowser());
        ProjectDirBrowserRenderer renderer = new ProjectDirBrowserRenderer();
        tree.setCellRenderer(renderer);
        tree.setShowsRootHandles(true);

        JScrollPane scrpane = new JScrollPane(tree);

        addToTree(root, rootNode);
        TreePath path = tree.getPathForRow(0);
        tree.expandPath(path);

        setExpanded(rootNode);

        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
        p.add(scrpane);

        defineAccelerators();
        super.add(p);
    }

    private void setExpanded(ProjectDirBrowserNode node) {
        int numChild = node.getChildCount();
        for (int i = 0; i < numChild; i++) {
            ProjectDirBrowserNode cnode = (ProjectDirBrowserNode) node
                    .getChildAt(i);
            if (cnode.isExpanded()) {
                logger.debug("node is expanded...");
                tree.scrollPathToVisible(new TreePath(cnode.getPath()));
            }

            if (cnode.isSelected()) {
                logger.debug("node is selected...");
                tree.setSelectionPath(new TreePath(cnode.getPath()));
                cnode.selectMe();
            }
            setExpanded(cnode);
        }
    }

    public void requestFocus() {
        tree.requestFocus();
    }

    public void addToTree(Element element, ProjectDirBrowserNode node) {
        String hasSub = element.getAttributeValue("hassub");
        currentsubproject++;
        boolean bhasSub = false;
        if (hasSub != null) {
            bhasSub = new Boolean(hasSub).booleanValue();
        }

        // if ( bhasSub ) {
        java.util.List list = element.getChildren();
        for (int i = 0; i < list.size(); i++) {
            logger.debug("processing nodes for element: " + list.get(i));
            Element tmpelement = (Element) list.get(i);
            String disp = tmpelement.getAttributeValue("display");
            boolean bdisp = false;
            if (disp != null) {
                bdisp = new Boolean(disp).booleanValue();
            }

            if (bdisp) {
                ProjectDirBrowserNode tmpnode = new ProjectDirBrowserNode(
                        tmpelement, this, monitor);
                if (!new File(tmpnode.getProjectInfo().getProjectDirectory())
                        .exists()) {
                    tmpelement.detach();
                    continue;
                }

                for (int j = 0; j < nodelisteners.size(); j++) {
                    tmpnode.addProjectDirBrowserNodeChangeListener((ProjectDirBrowserNodeChangeListener) nodelisteners
                            .get(j));
                }
                addToTree(tmpelement, tmpnode);
                node.add(tmpnode);
            }

        }
        // }
    }

    /** Remove the currently selected node. */
    public void removeCurrentNode() {
        TreePath currentSelection = tree.getSelectionPath();
        if (currentSelection != null) {
            ProjectDirBrowserNode currentNode = (ProjectDirBrowserNode) currentSelection
                    .getLastPathComponent();
            ProjectDirBrowserNode parent = (ProjectDirBrowserNode) currentNode
                    .getParent();
            if (parent != null) {
                treeModel.removeNodeFromParent(currentNode);
                currentNode.getProjectElement().getParentElement()
                        .removeContent(currentNode.getProjectElement());
                // currentNode.getProjectElement()
                return;
            }
        }
    }

    /** Add child to the currently selected node. */
    public ProjectDirBrowserNode addObject(Object child) {
        ProjectDirBrowserNode parentNode = null;
        TreePath parentPath = tree.getSelectionPath();

        if (parentPath == null) {
            parentNode = rootNode;
        } else {
            parentNode = (ProjectDirBrowserNode) parentPath
                    .getLastPathComponent();
        }

        return addObject(parentNode, child, true, true);
    }

    public ProjectDirBrowserNode addObject(ProjectDirBrowserNode parent,
            Object child) {
        return addObject(parent, child, false, true);
    }

    public ProjectDirBrowserNode addObject(ProjectDirBrowserNode parent,
            Object child, boolean shouldBeVisible, boolean updateMyProjects) {
        ProjectDirBrowserNode childNode = null;
        Element proj = parent.getProjectElement();
        ProjectInfo info = parent.getProjectInfo();
        if (child instanceof ProjectDirBrowserNode) {
            childNode = (ProjectDirBrowserNode) child;
        }

        if (parent == null) {
            parent = rootNode;
        }

        treeModel.insertNodeInto(childNode, parent, parent.getChildCount());

        if (updateMyProjects) {
            // take care xml objects
            try {
                proj.addContent(childNode.getProjectElement());
            } catch (Exception e) {
            }
        }
        // then take care of project info
        info.addSubProjectInfo(childNode.getProjectInfo());

        // Make sure the user can see the lovely new node.
        if (shouldBeVisible) {
            tree.scrollPathToVisible(new TreePath(childNode.getPath()));
        }
        return childNode;
    }

    public ProjectDirBrowserNode addObject(ProjectDirBrowserNode parent,
            Object child, boolean shouldBeVisible) {
        return addObject(parent, child, shouldBeVisible, true);
    }

    public void bootProjectCreator() {
        ProjectDirBrowserNode nd = getSelectedNode();
        if (nd == null) {
            nd = getRootNode();
        }
        if (nd.getProjectInfo().getInfoType() == ProjectInfo.SUB) {
            logger.info("projects can't be created under subprojects");
            return;
        }
        if (!nd.getProjectInfo().isEditable()) {
            logger.info("projects can't be created under this node");
            return;
        }
        NewProjectCreator cr = new NewProjectCreator(nd, this);
        cr.addProjectStateChangeListener(this);
    }

    public void bootProjectRemover() {
        ProjectDirBrowserNode nd = getSelectedNode();
        if (nd == null) {
            logger.info("project dir not selected.");
            return;
        } else if (nd == getRootNode()) {
            logger.info("root node can't be removed.");
            return;
        }
        if (!nd.getProjectInfo().isEditable()) {
            logger.info("can't remove this project.");
            return;
        }
        // if ( nd.getProjectInfo().getInfoType() == ProjectInfo.SUB ) {
        // logger.info("use `remove sub project' to remove sub projects.");
        // return;
        // }
        ProjectRemover rm = new ProjectRemover("remove", nd, this);
        rm.addProjectStateChangeListener(this);
    }

    public void bootSubProjectRemover() {
        ProjectDirBrowserNode nd = getSelectedNode();
        if (nd == null) {
            logger.info("project dir not selected.");
            return;
        } else if (nd == getRootNode()) {
            logger.info("root node can't be removed.");
            return;
        } else if (!nd.getProjectInfo().isEditable()) {
            logger.info("can't remove this project.");
            return;
        } else if (nd.getProjectInfo().getInfoType() == ProjectInfo.BASE) {
            logger.info("use `remove project' to remove projects.");
            return;
        }
        ProjectRemover rm = new ProjectRemover("remove sub project", nd, this);
        rm.addProjectStateChangeListener(this);
    }

    public void bootSubProjectCreator() {
        ProjectDirBrowserNode nd = getSelectedNode();
        if (nd == null) {
            logger.error("project not selected.");
            return;
        } else if (nd == getRootNode()) {
            logger.info("sub projects can't be created under root node.");
            return;
        } else if (!nd.getProjectInfo().isEditable()) {
            logger.info("sub projects can't be created under this node");
            return;
        }

        NewSubProjectCreator cr = new NewSubProjectCreator(nd, this);
        cr.addProjectStateChangeListener(this);
    }

    protected Vector getProjBuf() {
        return this.projbuf;
    }

    public void doProjectCopy(ProjectDirBrowserNode currNode) {
        if (!currNode.getProjectInfo().isEditable()) {
            logger.info("uneditable node.");
            return;
        }
        ProjectState state = new ProjectState(currNode,
                (ProjectDirBrowserNode) currNode.getParent(),
                ProjectState.PROJECT_COPY);
        projbuf.addElement(state);
    }

    public void doProjectCut(ProjectDirBrowserNode currNode) {
        if (!currNode.getProjectInfo().isEditable()) {
            logger.info("uneditable node.");
            return;
        }
        ProjectState state = new ProjectState(currNode,
                (ProjectDirBrowserNode) currNode.getParent(),
                ProjectState.PROJECT_CUT);
        projbuf.addElement(state);
        ProjectBrowser browser = currNode.getProjectBrowser();
        if (browser != null) {
            browser.dispose();
        }
        ((DefaultTreeModel) tree.getModel()).removeNodeFromParent(currNode);
        updateTree();
    }

    public void doProjectPaste() {
        if (projbuf.size() == 0) {
            logger.info("no data in buffer.");
            return;
        }
        ProjectState state = (ProjectState) projbuf.remove(projbuf.size() - 1);
        ProjectDirBrowserNode nd = getSelectedNode();

        if (nd == null) {
            logger.info("node not selected.");
            projbuf.add(state);
            return;
        }
        ProjectInfo selected = nd.getProjectInfo();
        if (selected == null) {
            logger.error("projectinfo not registered.");
            projbuf.add(state);
            return;
        }
        if (!selected.isEditable()) {
            logger.info("projects/subprojects can't be added under this node.");
            return;
        }
        if (!state.getNode().getProjectInfo().isEditable()) {
            return;
        }
        if (state.getNode().getProjectInfo().getInfoType() == ProjectInfo.BASE
                && selected.getInfoType() == ProjectInfo.SUB) {
            projbuf.add(state);
            logger.info("projects can't be added under subprojects.");
            return;
        }
        if (state.getNode().getProjectInfo().getInfoType() == ProjectInfo.SUB
                && selected.isRoot()) {
            projbuf.add(state);
            logger.info("subprojects can't be added under root.");
            return;
        }
        if (!ProjectBrowserUtils.changeProjectState(this, state)) {
            projbuf.add(state);
        }
    }

    public void bootRenamer(ProjectDirBrowserNode currNode) {
        String oldName = currNode.getProjectInfo().getProjectName();
        String newName = (String) JOptionPane.showInternalInputDialog(
                Desk.getDesktop(), "input new name", "rename",
                JOptionPane.PLAIN_MESSAGE);
        if (newName == null || newName.trim().length() == 0) {
            logger.info("rename canceled.");
            return;
        }
        ProjectInfo info = currNode.getProjectInfo();
        info.setProjectName(newName);
        info.setProjectDirectory(new File(info.getProjectDirectory())
                .getParent() + System.getProperty("file.separator") + newName);
        ProjectBrowserUtils.changeProjectState(this, new ProjectState(currNode,
                (ProjectDirBrowserNode) currNode.getParent(),
                ProjectState.PROJECT_RENAME));
    }

    public void saveMyProjects() {
        setShouldBeVisible(getRootNode());
        ciss.phase_viewer.jdom.XMLUtils.saveDocumentTo(doc, MY_PROJECTS);
    }

    private void setShouldBeVisible(TreeNode node) {
        TreePath path = new TreePath(((DefaultMutableTreeNode) node).getPath());
        JTree tree = this.getTree();

        if (node instanceof ProjectDirBrowserNode) {
            Element elem = ((ProjectDirBrowserNode) node).getProjectElement();
            String shouldbevisible = "false";
            if (tree.isExpanded(path)) {
                shouldbevisible = "true";
            }
            elem.setAttribute(new Attribute("shouldbevisible", shouldbevisible));

            String selected = "false";
            if (tree.isPathSelected(path)) {
                selected = "true";
            }
            elem.setAttribute(new Attribute("selected", selected));
        }

        for (int i = 0; i < node.getChildCount(); i++) {
            setShouldBeVisible(node.getChildAt(i));
        }
    }

    private int numproj = 0;

    private void calculateNumProjects(Element element) {
        java.util.List subprojects = element.getChildren("subproject");
        numproj += subprojects.size();
        java.util.List projects = element.getChildren("project");
        if (projects == null || projects.size() == 0) {
            return;
        }
        numproj += projects.size();
        for (int i = 0; i < projects.size(); i++) {
            calculateNumProjects((Element) projects.get(i));
        }
    }

    protected void doProjectExport() {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogType(JFileChooser.OPEN_DIALOG);
        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        if (chooser.showDialog(this, "open") != JFileChooser.APPROVE_OPTION) {
            return;
        }
        String exportDir = chooser.getSelectedFile().getAbsolutePath();
        ProjectDirBrowserNode currNode = getSelectedNode();
        ProjectInfo currInfo = currNode.getProjectInfo();
        if (!Utils.copyDir(new File(currInfo.getProjectDirectory()), new File(
                exportDir))) {
            logger.error("error.");
            return;
        }
        Document document = new Document();
        Element root = new Element("projects");
        document.setRootElement(root);
        root.addContent((Element) currInfo.getProjectElement().clone());
        XMLUtils.saveDocumentTo(document,
                exportDir + System.getProperty("file.separator") + "spec.xml");
    }

    /**
     * ディレクトリーから, 再帰的にプロジェクトを再構築する. いくつかの属性は復旧しきれない, かもしれない 差し当たり隠しておくか...
     */
    private void importFromDir(File dir, ProjectDirBrowserNode currNode) {
        java.util.List list = ProjectBrowserUtils.getElementFromDir(dir);
        Document document = getMyProjectsDocument();
        Element rootElement = document.getRootElement();
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                Element ele = (Element) list.get(i);
                rootElement.addContent(ele);
            }
        }
        saveMyProjectsDocument();
    }

    protected void doProjectImport() {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogType(JFileChooser.OPEN_DIALOG);
        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        FileFilter ff1 = new ImportFileFilterXML();
        FileFilter ff2 = new ImportFileFilterV1();
        FileFilter ff3 = new ImportFileFilterGenericFolder();
        chooser.addChoosableFileFilter(ff1);
        chooser.addChoosableFileFilter(ff2);
        // chooser.addChoosableFileFilter(ff3);
        chooser.setFileFilter(ff1);

        if (chooser.showDialog(this, "open") != JFileChooser.APPROVE_OPTION) {
            return;
        }

        File specFile = chooser.getSelectedFile().getAbsoluteFile();
        ProjectDirBrowserNode currNode = getSelectedNode();
        FileFilter ffilter = chooser.getFileFilter();
        if (ffilter instanceof ImportFileFilterXML) {
            if (!specFile.isDirectory()) {
                importSub(specFile, currNode);
            } else {
                importFromDir(specFile, currNode); // 隠し機能じゃ
            }
        } else if (ffilter instanceof ImportFileFilterV1) {
            if (specFile.isDirectory()) {
                File foo = v1tov2(specFile);
                importSub(foo, currNode);
                foo.delete();
            } else
                logger.error("you must specify a directory to import chase v1 projects.");
        } else if (ffilter instanceof ImportFileFilterGenericFolder) {
            // importFromGenericDir(specFile);
            // File foo = importFromDir(specFile);
            // importSub(foo, currNode);
            // foo.delete();
        }
    }

    class ImportFileFilterXML extends FileFilter {
        public boolean accept(File f) {
            String name = f.getName().trim().toLowerCase();
            return name.endsWith(".xml") || f.isDirectory();
        }

        public String getDescription() {
            return "project specification file (*.xml, *.XML)";
        }
    }

    class ImportFileFilterV1 extends FileFilter {
        public boolean accept(File f) {
            if (f.isDirectory())
                return true;
            return false;
        }

        public String getDescription() {
            return "CHASE-3pt version 1 project directory";
        }
    }

    class ImportFileFilterGenericFolder extends FileFilter {
        public boolean accept(File f) {
            if (f.isDirectory())
                return true;
            return false;
        }

        public String getDescription() {
            return "generic folder (PHASE only)";
        }
    }

    /**
     * バージョン1のディレクトリーからバージョン2のプロジェクトへ変換
     * 
     * @param rootDirs
     *            ディレクトリーの配列; これ以下が再帰的に変換される.
     * @return バージョン2プロジェクトのspecification file.
     */
    private File v1tov2(File rootDirs) {
        File[] directories = rootDirs.listFiles(new java.io.FileFilter() {
            public boolean accept(File pathname) {
                if (pathname.isDirectory())
                    return true;
                return false;
            }
        });
        if (directories == null || directories.length == 0)
            return null;

        Document document = new Document();
        Element projects = new Element("projects");
        document.setRootElement(projects);

        Element rootProj = new Element("project");
        rootProj.setAttribute(new Attribute("display", "true"));
        rootProj.setAttribute("subident", "subproject");
        rootProj.setAttribute("hassub", "true");
        rootProj.setAttribute("shouldbevisible", "false");
        rootProj.setAttribute("selected", "false");

        rootProj.addContent(new Element("name").setText(MyElement
                .encode(rootDirs.getName())));
        rootProj.addContent(new Element("directory").setText(MyElement
                .encode(rootDirs.getAbsolutePath())));
        rootProj.addContent(new Element("type").setText("chase project"));
        rootProj.addContent(new Element("date").setText(MyElement
                .encode(new Date(rootDirs.lastModified()).toString())));

        projects.addContent(rootProj);

        for (int i = 0; i < directories.length; i++) {
            Element proj = importFromDirSub(directories[i], true);
            rootProj.addContent(proj);
        }

        File chasexml = new File(rootDirs.getParent()
                + System.getProperty("file.separator") + "spec.xml");
        XMLUtils.saveDocumentTo(document, chasexml);

        return chasexml;
    }

    private File importFromDir(File rootDirs) {
        File[] directories = rootDirs.listFiles(new java.io.FileFilter() {
            public boolean accept(File pathname) {
                if (pathname.isDirectory())
                    return true;
                return false;
            }
        });
        if (directories == null || directories.length == 0)
            return null;

        Document document = new Document();
        Element projects = new Element("projects");
        document.setRootElement(projects);

        Element rootProj = new Element("project");
        rootProj.setAttribute(new Attribute("display", "true"));
        rootProj.setAttribute("subident", "subproject");
        rootProj.setAttribute("hassub", "true");
        rootProj.setAttribute("shouldbevisible", "false");
        rootProj.setAttribute("selected", "false");

        rootProj.addContent(new Element("name").setText(MyElement
                .encode(rootDirs.getName())));
        rootProj.addContent(new Element("directory").setText(MyElement
                .encode(rootDirs.getAbsolutePath())));
        rootProj.addContent(new Element("type").setText("chase project"));
        rootProj.addContent(new Element("date").setText(MyElement
                .encode(new Date(rootDirs.lastModified()).toString())));

        projects.addContent(rootProj);

        for (int i = 0; i < directories.length; i++) {
            Element proj = importFromDirSub(directories[i], false);
            rootProj.addContent(proj);
        }

        File chasexml = new File(rootDirs.getParent()
                + System.getProperty("file.separator") + "spec.xml");
        XMLUtils.saveDocumentTo(document, chasexml);

        return chasexml;
    }

    private Element importFromDirSub(File directory, boolean v1proj) {
        File[] chasepars = directory.listFiles(new java.io.FileFilter() {
            public boolean accept(File pathname) {
                if (pathname.getName().equals("chase.par"))
                    return true;
                return false;
            }
        });

        if (v1proj && chasepars == null || chasepars.length == 0)
            return null;

        Element project = new Element("subproject");

        long lastModified = directory.lastModified();
        String date = new Date(lastModified).toString();

        project.setAttribute(new Attribute("display", "true"));
        project.setAttribute(new Attribute("shouldbevisible", "false"));
        project.setAttribute(new Attribute("selected", "false"));
        project.addContent(new Element("date").setText(MyElement.encode(date)));
        project.addContent(new Element("name").setText(MyElement
                .encode(directory.getName())));
        project.addContent(new Element("type").setText("phase"));
        project.addContent(new Element("directory").setText(MyElement
                .encode(directory.getAbsolutePath())));
        File[] subdirs = directory.listFiles(new java.io.FileFilter() {
            public boolean accept(File pathname) {
                if (pathname.isDirectory())
                    return true;
                return false;
            }
        });

        if (subdirs != null && subdirs.length != 0) {
            for (int ek = 0; ek < subdirs.length; ek++) {

                File[] chasepars_subdir = subdirs[ek]
                        .listFiles(new java.io.FileFilter() {
                            public boolean accept(File pathname) {
                                if (pathname.getName().equals("chase.par"))
                                    return true;
                                return false;
                            }
                        });

                if (chasepars_subdir != null && chasepars_subdir.length != 0) {
                    Element subelem = importFromDirSub(subdirs[ek], v1proj);
                    project.addContent(subelem);
                } else {
                    Element ekcal = new Element("subproject");
                    ekcal.setAttribute("display", "true");
                    ekcal.setAttribute("shouldbevisible", "false");
                    ekcal.setAttribute("selected", "false");
                    ekcal.addContent(new Element("date").setText(MyElement
                            .encode(new Date(subdirs[ek].lastModified())
                                    .toString())));
                    ekcal.addContent(new Element("name").setText(subdirs[ek]
                            .getName()));
                    if (v1proj)
                        ekcal.addContent(new Element("type").setText("ekcal"));
                    else
                        ekcal.addContent(new Element("type").setText("ekcal"));
                    ekcal.addContent(new Element("directory").setText(MyElement
                            .encode(subdirs[ek].getAbsolutePath())));
                    if (v1proj) {
                        Element par = new Element("associated_directory");
                        par.setAttribute("type", "parent");
                        String pardir = Utils.getRelativePath(
                                subdirs[ek].getAbsolutePath(),
                                directory.getAbsolutePath());
                        par.setText(MyElement.encode(pardir));
                        ekcal.addContent(par);
                    }

                    project.addContent(ekcal);
                }
            }
        }
        return project;
    }

    protected void openDirByPrompt(String path) {
        if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            MyThread th = new MyThread("cmd.exe /c start cmd.exe", "",
                    new File(path));
        } else {
            MyThread th = new MyThread("xterm", "", new File(path));
        }
    }

    protected void openDir(String path) {
        if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            MyThread thread = new MyThread("explorer " + Utils.getPathDQ(path));
        } else {
            MyThread thread = new MyThread("konqueror " + Utils.getPathDQ(path));
        }
    }

    private void importSub(File specFile, ProjectDirBrowserNode currNode) {
        importSub(specFile, currNode, null);
    }

    private void importSub(File specFile, ProjectDirBrowserNode currNode,
            String suffix__) {
        if (suffix__ == null)
            suffix__ = "_";

        Document document = XMLUtils.getDocumentFromFile(specFile);
        if (document == null) {
            logger.error("invalid specfile: " + specFile.getAbsolutePath());
            return;
        }
        Element root = document.getRootElement();
        if (root == null) {
            logger.error("invalid specfile: " + specFile.getAbsolutePath());
            return;
        }
        java.util.List projects = root.getChildren("project");
        if (projects == null || projects.size() == 0) {
            logger.error("no projects in " + specFile.getAbsolutePath());
            return;
        }

        File[] files = specFile.getParentFile().listFiles();
        if (files == null || files.length == 0) {
            return;
        }

        Element parentElement = currNode.getProjectElement();
        if (parentElement == null) {
            return;
        }
        logger.debug("parent dir: "
                + currNode.getProjectInfo().getProjectDirectory());

        File baseDir = new File(currNode.getProjectInfo().getProjectDirectory());
        File[] subfiles = baseDir.listFiles();

        for (int i = 0; i < files.length; i++) {
            if (!files[i].isDirectory()) {
                continue;
            }
            boolean boo = false;
            for (int j = 0; j < projects.size(); j++) {
                String nam = ((Element) projects.get(j)).getChild("name")
                        .getTextTrim();
                if (nam.equals(files[i].getName()))
                    boo = true;
            }

            String suffix = "";
            // 同名ディレクトリーの場合の処理
            for (int j = 0; j < subfiles.length; j++)
                if (subfiles[j].getName().equals(files[i].getName()))
                    suffix = suffix__;

            if (!boo)
                continue;
            // if ( ignore[i] ) {
            // logger.info("project "+files[i].getName()+" exists...
            // ignoring.");
            // for ( int j=0 ; j<projects.size() ; j++ ) {
            // Element proj = (Element) projects.get(j);
            // Element nam = proj.getChild("name");
            // if ( nam != null && nam.getTextTrim().equals(files[i].getName())
            // ){
            // projects.remove(proj);
            // }
            // }
            // continue;
            // }
            boolean aa = true;
            if (suffix.length() != 0)
                aa = Utils.copyDir(files[i], baseDir, files[i].getName()
                        + suffix);
            else
                aa = Utils.copyDir(files[i], baseDir, false);
            if (!aa)
                logger.warn("failed copy");
        }

        for (int i = 0; i < projects.size(); i++) {
            Element elem = (Element) ((Element) projects.get(i)).clone();
            java.util.List li = parentElement.getChildren();
            boolean found = false;
            for (int il = 0; il < li.size(); il++) {
                Element el = (Element) li.get(il);
                String foo = el.getChildTextTrim("name");
                if (foo != null && foo.equals(elem.getChildTextTrim("name"))) {
                    found = true;
                    break;
                }
            }
            if (found)
                elem.getChild("name").setText(
                        elem.getChildTextTrim("name") + suffix__);
            parentElement.addContent(elem);
        }

        saveMyProjectsDocument();
        recreate();
    }

    class MouseAdapterProjectDirBrowser extends MouseAdapter {
        private Logger logger = Logger
                .getLogger(MouseAdapterProjectDirBrowser.class.getName());

        private ProjectInfo info;

        private ProjectDirBrowserNode node;

        public void mousePressed(MouseEvent e) {
            int x = e.getX();
            int y = e.getY();
            JTree tree = (JTree) e.getSource();
            TreePath path = tree.getPathForLocation(x, y);
            if (path != null) {
                node = (ProjectDirBrowserNode) path.getLastPathComponent();
                info = node.getProjectInfo();
                processMouseEvent(e);
            }
            saveMyProjects();
        }

        private void processMouseEvent(MouseEvent e) {
            if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
                node.selectMe();
            } else if (e.getButton() == MouseEvent.BUTTON3) {
                showMenu(e);
            }
        }

        private void showMenu(MouseEvent e) {
            // if ( menuCreator == null ) {
            ProjectDirBrowserMenu menuCreator = new ProjectDirBrowserMenu(
                    browser);
            // }
            JPopupMenu popup = new JPopupMenu();
            JMenuItem[] items = menuCreator.getMenuItems();
            if (items != null) {
                for (int i = 0; i < items.length; i++) {
                    if (items[i] == null) {
                        if (i != items.length - 1) {
                            popup.addSeparator();
                        }
                    } else {
                        popup.add(items[i]);
                    }
                }
                popup.show(e.getComponent(), e.getX(), e.getY());
            }
        }

        // private JMenuItem[] getItems() {
        // Vector items = new Vector();
        //
        // JMenuItem open = new JMenuItem("open");
        // open.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent ae) {
        // // ProjectDirBrowserNode node = getSelectedNode();
        // if (node != null) {
        // node.selectMe();
        // saveMyProjects();
        // }
        // }
        // });
        // open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
        //
        // JMenuItem rename = new JMenuItem("rename");
        // rename.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // bootRenamer(node);
        // }
        // });
        // rename.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
        //
        // JMenuItem cut = new JMenuItem("cut");
        // cut.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // doProjectCut(node);
        // }
        // });
        // cut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
        // KeyEvent.CTRL_MASK));
        //
        // JMenuItem copy = new JMenuItem("copy");
        // copy.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // doProjectCopy(node);
        // }
        // });
        // copy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
        // KeyEvent.CTRL_MASK));
        //
        // JMenuItem paste = new JMenuItem("paste");
        // paste.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // doProjectPaste();
        // }
        // });
        // paste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,
        // KeyEvent.CTRL_MASK));
        // paste.setEnabled(projbuf.size() != 0);
        //
        // JMenuItem remove = new JMenuItem("remove");
        // remove.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // bootProjectRemover();
        // }
        // });
        // remove
        // .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,
        // 0));
        //
        // JMenuItem create = new JMenuItem("create project");
        // create.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // bootProjectCreator();
        // }
        // });
        // create.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
        // KeyEvent.CTRL_MASK));
        //
        // JMenuItem sub = new JMenuItem("create sub project");
        // sub.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // bootSubProjectCreator();
        // }
        // });
        // sub.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
        // KeyEvent.CTRL_MASK + KeyEvent.SHIFT_MASK));
        //
        // JMenuItem export = new JMenuItem("export project");
        // export.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent ae) {
        // doProjectExport();
        // }
        // });
        //
        // JMenuItem impor = new JMenuItem("import project");
        // impor.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent ae) {
        // doProjectImport();
        // }
        // });
        //
        // JMenuItem openexp = null;
        // JMenuItem cmd = null;
        // if (info.getInfoType() == ProjectInfo.SUB) {
        // items.addElement(open);
        // }
        // if (System.getProperty("os.name").toLowerCase().startsWith(
        // "windows")) {
        // openexp = new JMenuItem("open folder by explorer");
        // items.addElement(openexp);
        // } else if (System.getProperty("os.name").toLowerCase().startsWith(
        // "linux")) {
        // openexp = new JMenuItem("open directory by konqueror");
        // items.addElement(openexp);
        // }
        // if (openexp != null) {
        // openexp.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // openDir(info.getProjectDirectory());
        // }
        // });
        // openexp.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
        // KeyEvent.CTRL_MASK));
        // }
        //
        // JMenuItem openprompt=new JMenuItem("open terminal");
        // openprompt.addActionListener(new ActionListener(){
        // public void actionPerformed(ActionEvent e) {
        // openDirByPrompt(info.getProjectDirectory());
        // }
        // });
        // openprompt.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,KeyEvent.CTRL_MASK));
        //
        // items.addElement(openprompt);
        // items.addElement(null);
        //
        // // if (info.getInfoType() == ProjectInfo.SUB && openexp == null) {
        // //items.addElement(null);
        // //}
        //
        // if (!info.isEditable()) {
        // JMenuItem[] ite = new JMenuItem[items.size()];
        // items.copyInto(ite);
        // return ite;
        // }
        //
        // if (info.getProjectType().equals("root")) {
        // items.addElement(create);
        // items.addElement(null);
        // items.addElement(export);
        // items.addElement(impor);
        // } else if (info.getInfoType() == ProjectInfo.BASE
        // && !info.getProjectType().equals("root")) {
        // items.addElement(create);
        // items.addElement(sub);
        // items.addElement(null);
        // items.addElement(rename);
        // items.addElement(cut);
        // items.addElement(copy);
        // items.addElement(paste);
        // items.addElement(remove);
        // items.addElement(null);
        // items.addElement(export);
        // items.addElement(impor);
        // } else if (info.getInfoType() == ProjectInfo.SUB) {
        // items.addElement(sub);
        // items.addElement(null);
        // items.addElement(rename);
        // items.addElement(cut);
        // items.addElement(copy);
        // items.addElement(paste);
        // items.addElement(remove);
        // }
        //
        // if (items.size() != 0) {
        // JMenuItem[] jitems = new JMenuItem[items.size()];
        // for (int i = 0; i < items.size(); i++) {
        // jitems[i] = (JMenuItem) items.elementAt(i);
        // }
        // return jitems;
        // }
        // return null;
        // }
    }

    class MyTreeModelListener implements TreeModelListener {
        public void treeNodesChanged(TreeModelEvent e) {
            DefaultMutableTreeNode node;
            node = (DefaultMutableTreeNode) (e.getTreePath()
                    .getLastPathComponent());
            try {
                int index = e.getChildIndices()[0];
                node = (DefaultMutableTreeNode) (node.getChildAt(index));
            } catch (NullPointerException exc) {
            }
        }

        public void treeNodesInserted(TreeModelEvent e) {
        }

        public void treeNodesRemoved(TreeModelEvent e) {
        }

        public void treeStructureChanged(TreeModelEvent e) {
        }
    }

}
