Package org.solarus.editor.gui.tree

Source Code of org.solarus.editor.gui.tree.QuestTree$FileElementPopupMenu

/*
* Copyright (C) 2006-2014 Christopho, Solarus - http://www.solarus-games.org
*
* Solarus Quest Editor 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.
*
* Solarus Quest Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.solarus.editor.gui.tree;


import java.awt.Component;
import java.awt.event.*;
import java.io.File;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import org.solarus.editor.*;
import org.solarus.editor.gui.*;

/**
* A tree that shows the project data directory, resources and scripts.
* Under the root node, there is a node for each subdirectory, resource file
* or Lua script. Other files are ignored.
*
* The tree keeps the hierarchy order and the alphabetical order of files.
*
* All files or directory nodes have a FileElement user object, and all
* resource nodes have a ResourceElement user object.
*
* - Root (FileElement)
*   - FileElement
*     - FileElement
*       - FileElement (script)
*       - FileElement (script)
*       - ...
*       - ResourceElement
*       - ResourceElement
*       - ...
*     - FileElement (script)
*     - ...
*     - ResourceElement
*     - ...
*   - FileElement
*     - FileElement (script)
*     - ...
*     - ResourceElement
*     - ...
*   - FileElement (script)
*   - ...
*/
public class QuestTree extends JTree implements ProjectObserver {

    private EditorWindow editorWindow;  // The main window.

    private NaturalOrderComparator<String> fileNameComparator;

    /**
     * Creates a quest tree.
     * @param parent The main quest editor window.
     */
    public QuestTree(EditorWindow parent) {
        setModel(null)// Because Java makes a stupid example tree by default.
        this.editorWindow = parent;
        this.fileNameComparator = new NaturalOrderComparator<String>();

        setDragEnabled(true);
        addMouseListener(new QuestTreeMouseAdapter());

        Project.addProjectObserver(this);

        setTransferHandler(new QuestTreeTransferHandler());
    }

    /**
     * Called when another project becomes active.
     */
    @Override
    public void currentProjectChanged() {
        rebuildTree();

        // Initially expand maps.
        DefaultMutableTreeNode node = getFileElement(ResourceType.MAP.getDirName());
        if (node != null) {
            DefaultMutableTreeNode root = (DefaultMutableTreeNode) getModel().getRoot();
            expandRow(root.getIndex(node) + 1);
        }
    }

    /**
     * Called when a new resource element has just been created.
     * @param resourceType Type of resource.
     * @param id Id of the new element.
     */
    @Override
    public void resourceElementAdded(ResourceType resourceType, String id) {

        try {
            addResourceElementToTree(new ResourceElement(resourceType, id));
        } catch (QuestEditorException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Called when a new resource element has just been deleted.
     * @param resourceType Type of resource.
     * @param id Id of the deleted element.
     */
    @Override
    public void resourceElementRemoved(ResourceType resourceType, String id) {

        DefaultMutableTreeNode node = getResourceElement(resourceType, id);
        if (node != null) {
            DefaultTreeModel model = (DefaultTreeModel) getModel();
            model.removeNodeFromParent(node);
            repaint();
        }
    }

    /**
     * Called when a new resource element has just been moved.
     * @param resourceType Type of resource.
     * @param oldId Old id of the element.
     * @param newId New id of the element.
     */
    @Override
    public void resourceElementMoved(ResourceType resourceType, String oldId,
            String newId) {

        resourceElementRemoved(resourceType, oldId);
        resourceElementAdded(resourceType, newId);
    }

    /**
     * Called when a resource element has just been renamed.
     * @param resourceType Type of resource.
     * @param id Id of the element.
     * @param name New human-readable name of the element.
     */
    @Override
    public void resourceElementRenamed(ResourceType resourceType,
            String id, String name) {

        try {
            ResourceElement element = new ResourceElement(resourceType, id);
            DefaultMutableTreeNode node = getResourceElement(resourceType, id);
            if (node != null) {
                node.setUserObject(element);
                repaint();
            }
        } catch (QuestEditorException ex) {
            // if project isn't loaded
            ex.printStackTrace();
        }
    }

    /**
     * Rebuilds the whole tree from the data project directory.
     *
     * Initially expands the maps directory.
     */
    public void rebuildTree() {

        try {
            DefaultMutableTreeNode root =
                    new DefaultMutableTreeNode(new FileElement(""), true);
            DefaultTreeModel model = new DefaultTreeModel(root);
            model.setAsksAllowsChildren(true);
            setCellRenderer(new QuestCellRenderer());
            setModel(model);

            // add resources
            for (ResourceType type: ResourceType.values()) {
                for (String id: Project.getResource(type).getIds()) {
                    addResourceElementToTree(new ResourceElement(type, id));
                }
            }

            // add lua script files
            buildNode("", new File(Project.getDataPath()));

            repaint();
        }
        catch (QuestEditorException ex) {
            // if the data project directory doesn't exists, can not happen
            ex.printStackTrace();
        }
    }

    /**
     * Updates the tree to reflect any change on the filesystem.
     */
    public void refreshTree() {

        rebuildTree();

        // TODO Restore the expanded state.
    }

    private void buildNode(String prefix, File directory) {

        if (!directory.exists() || !directory.isDirectory()) {
            return;
        }

        for (File file: directory.listFiles()) {

            String path = (prefix.isEmpty() ? "" : prefix + "/") + file.getName();
            if (file.isDirectory()) {

                // add the directory if isn't the text directory or a
                // sub directory of the language resources directory.
                // these directories could be added after, if it's necessary
                if (!path.equals("text") && !path.startsWith(ResourceType.LANGUAGE.getDirName())) {
                    addFileElementToTree(path);
                }
                buildNode(path, file);
            }
            else if (path.endsWith(".lua")) {

                // the file script isn't a resource
                if (!isResourcePath(path)) {
                    addFileElementToTree(path);
                }
            }
        }
    }

    /**
     * Checks if a path corresponds to an existing resource.
     * @param path the path to check
     * @return true if the path corresponds to an existing resource, false otherwise
     */
    private boolean isResourcePath(String path) {

        if (path.contains("/") && (path.endsWith(".dat") || path.endsWith(".lua"))) {

            path = path.replace(".dat", "").replace(".lua", "");

            for (ResourceType type: ResourceType.values()) {
                if (path.startsWith(type.getDirName() + "/")) {
                    String id = path.substring(path.indexOf("/") + 1);
                    if (Project.getResource(type).exists(id)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Returns a specified file node.
     * @param path the path corresponding to the node
     * @return The found node or null if no exists
     */
    private DefaultMutableTreeNode getFileElement(String path) {

        DefaultMutableTreeNode node = (DefaultMutableTreeNode) getModel().getRoot();

        if (!path.isEmpty()) {
            node = getFileChildNode(node, path);
        }

        return node;
    }

    /**
     * Returns a specified child file node.
     * @param parentNode the parent node that contains the node
     * @param path the path corresponding to the node
     * @return the node or null if no exists
     */
    private DefaultMutableTreeNode getFileChildNode(
            DefaultMutableTreeNode parentNode,String path) {

        DefaultMutableTreeNode child = null;

        if (parentNode.getChildCount() > 0) {
            child = (DefaultMutableTreeNode) parentNode.getFirstChild();
        }

        while (child != null) {

            Object userObject = child.getUserObject();
            if (userObject instanceof FileElement) {

                FileElement type = (FileElement) userObject;
                if (path.equals(type.getPath())) {
                    return child;
                }
                else if (type.isDirectory() && path.startsWith(type.getPath())) {
                    return getFileChildNode(child, path);
                }
            }

            child = child.getNextSibling();
        }

        return child;
    }

    /**
     * Returns a specified resource node.
     * @param resourceType the type of the resource
     * @param id the id of the resource
     * @return The found node or null if no exists
     */
    private DefaultMutableTreeNode getResourceElement(ResourceType resourceType, String id) {

        DefaultMutableTreeNode node = (DefaultMutableTreeNode) getModel().getRoot();
        return getResourceChildNode(node, resourceType, id);
    }

    /**
     * Returns a specified child resource node.
     * @param parentNode the parent node that contains the node
     * @param resourceType the type of the resource
     * @param id the id of the resource
     * @return the node or null if no exists
     */
    private DefaultMutableTreeNode getResourceChildNode(
            DefaultMutableTreeNode parentNode, ResourceType resourceType, String id) {

        DefaultMutableTreeNode child = null;

        if (parentNode.getChildCount() > 0) {
            child = (DefaultMutableTreeNode) parentNode.getFirstChild();
        }

        while (child != null) {

            Object userObject = child.getUserObject();
            if (userObject instanceof ResourceElement) {

                ResourceElement nodeElement = (ResourceElement) userObject;
                if (nodeElement.type == resourceType && nodeElement.id.equals(id)) {
                    return child;
                }
            }
            else if (userObject instanceof FileElement) {

                FileElement type = (FileElement) userObject;
                if (type.isDirectory()) {
                    DefaultMutableTreeNode node = getResourceChildNode(child, resourceType, id);
                    if (node != null) {
                        return node;
                    }
                }
            }

            child = child.getNextSibling();
        }

        return child;
    }

    /**
     * Adds a node element that represent a file to the tree.
     * @param path the path corresponding to the node
     */
    private void addFileElementToTree(String path) {

        // if the node already exists
        if (getFileElement(path) != null) {
            return;
        }
        DefaultMutableTreeNode node, parentNode;

        try {
            FileElement element = new FileElement(path);
            node = new DefaultMutableTreeNode(element, element.isDirectory());
            // if is in the root dir
            if (!path.contains("/")) {
                parentNode = (DefaultMutableTreeNode) getModel().getRoot();
            }
            else {
                path = path.substring(0, path.lastIndexOf("/"));
                parentNode = getFileElement(path);
                // try to create directory if is not exists
                if (parentNode == null) {
                    addFileElementToTree(path);
                    parentNode = getFileElement(path);
                }
            }

            if (parentNode != null) {
                DefaultTreeModel model = (DefaultTreeModel) getModel();
                int location = findNewFileLocation(parentNode, element);
                model.insertNodeInto(node, parentNode, location);
                repaint();
            }
        } catch (QuestEditorException ex) {
            // if the project isn't loaded, can not be happen
            ex.printStackTrace();
        }
    }

    /**
     * Find a location for a new file in a node.
     * Lets keep the alphabetical order of files, and keep a separation between
     * files and directories.
     * @param node the node to insert the new file
     * @param element the file element of the node to add
     * @return the new location
     */
    private int findNewFileLocation(DefaultMutableTreeNode node, FileElement element) {

        int location = 0;

        if (node.getChildCount() > 0) {

            DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getFirstChild();
            while (child != null) {

                Object userObject = child.getUserObject();
                if (userObject instanceof FileElement) {

                    FileElement file = (FileElement) userObject;
                    if (element.isDirectory()) {
                        if (file.isDirectory()) {
                            if (fileNameComparator.compare(file.getPath(), element.getPath()) > 0) {
                                return location;
                            }
                        } else {
                            return location;
                        }
                    }
                    else {
                        if (!file.isDirectory() && fileNameComparator.compare(file.getPath(), element.getPath()) > 0) {
                            return location;
                        }
                    }
                } else if (userObject instanceof ResourceElement) {
                    return location;
                }

                child = child.getNextSibling();
                location++;
            }
        }

        return location;
    }

    /**
     * Removes a file element node from the tree.
     * If element is a directory, it must be empty to be deleted.
     * @param path the path of the file element
     */
    private void removeFileElement(String path) {

        DefaultMutableTreeNode node = getFileElement(path);
        if (node != null) {
            if (node.getUserObject() instanceof FileElement) {

                File file = new File(Project.getDataPath() + "/" + path);
                if (!file.isDirectory() || file.list().length == 0) {
                    DefaultTreeModel model = (DefaultTreeModel) getModel();
                    model.removeNodeFromParent(node);
                }
            }
        }
    }

    /**
     * Move a file element node in the tree.
     * The lua script file will be moved in the file system.
     * @param oldPath the path of file element ot move
     * @param newPath the new path of the file element
     * @throws QuestEditorException if the script cannot be move
     */
    public void moveFileElement(String oldPath, String newPath)
            throws QuestEditorException {

        if (newPath.equals(oldPath)) {
            return;
        }

        try {
            // check old path
            DefaultMutableTreeNode node = getFileElement(oldPath);
            if (node == null) {
                throw new QuestEditorException("this script doesn't exist");
            }
            // check new path
            DefaultMutableTreeNode newNode = getFileElement(newPath);
            if (newNode != null) {
                throw new QuestEditorException("the new script already exists");
            }
            // trying to move a resource
            if (!(node.getUserObject() instanceof FileElement)) {
                throw new QuestEditorException("the script corresponds to a resource");
            }
            // trying to move a directory
            File file = new File(Project.getDataPath() + "/" + oldPath);
            if (file.isDirectory()) {
                throw new QuestEditorException("the path corresponds to a directory");
            }

            // rename file
            editorWindow.closeTextEditor(file, false);
            File newFile = new File(Project.getDataPath() + "/" + newPath);
            if (!file.renameTo(newFile)) {
                throw new QuestEditorException("error on renaming");
            }
            // remove node
            DefaultTreeModel model = (DefaultTreeModel) getModel();
            model.removeNodeFromParent(node);
            // add new node
            addFileElementToTree(newPath);
        }
        catch (QuestEditorException ex) {
            throw new QuestEditorException("cannot rename script '" + oldPath +
                    "' in '" + newPath + "': " + ex.getMessage());
        }
    }

    /**
     * Adds a node element that represent a resource to the tree.
     * @param element The resource element to add.
     */
    private void addResourceElementToTree(ResourceElement element) {

        String path = element.type.getDirName() + "/" + element.id + ".lua";
        DefaultMutableTreeNode node = getResourceElement(element.type, element.id);
        // if the resource node already exists
        if (node != null) {
            return;
        }

        node = getFileElement(path);
        // if the node exists as a script
        if (node != null) {
            node.setUserObject(element);
        }
        else {
            node = new DefaultMutableTreeNode(element, false);

            path = path.substring(0, path.lastIndexOf("/"));
            DefaultMutableTreeNode parentNode = getFileElement(path);
            // try to create if no exists
            if (parentNode == null) {
                addFileElementToTree(path);
                parentNode = getFileElement(path);
            }

            if (parentNode != null) {
                DefaultTreeModel model = (DefaultTreeModel) getModel();
                int location = findNewResourceLocation(parentNode, element);
                model.insertNodeInto(node, parentNode, location);
                repaint();
            }
        }

        repaint();
    }

    /**
     * Find a location for a new resource in a node.
     * Lets keep the alphabetical order of resources.
     * @param node the node to insert the new file
     * @param element the resource element of the node to add
     * @return the new location
     */
    private int findNewResourceLocation(DefaultMutableTreeNode node, ResourceElement element) {

        int location = 0;

        if (node.getChildCount() > 0) {

            DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getFirstChild();
            while (child != null) {

                Object userObject = child.getUserObject();
                if (userObject instanceof ResourceElement) {

                    ResourceElement resource = (ResourceElement) userObject;
                    if (fileNameComparator.compare(resource.id, element.id) > 0) {
                        return location;
                    }
                }

                child = child.getNextSibling();
                location++;
            }
        }

        return location;
    }

    /**
     * Quest tree file userObject type.
     */
    protected class FileElement {

        // is a directory
        private final boolean isDirectory;
        // path file corresponding to the file relative to the data project directory
        private final String path;
        // the name to display node (by default filename without extension)
        private String name;

        /**
         * Constructor.
         * @param path path file corresponding to the node file relative to the data project directory
         * @throws QuestEditorException if file no exists
         */
        public FileElement(String path) throws QuestEditorException {

            this.path = path;

            File file = new File(Project.getDataPath() + "/" + path);
            isDirectory = file.isDirectory();
            // if is the root
            if (path.isEmpty()) {
                name = Project.getRootPath();
                name = "<html>Quest <font style=\"color:gray;\">(" + name  + ")</font></html>";
            }
            else {
                name = file.getName();
            }
        }

        /**
         * Checks if the node represents a directory.
         * @return true if the node reprensents a directory, false otherwise
         */
        public boolean isDirectory() {

            return isDirectory;
        }

        /**
         * Returns the path file.
         * @return path file
         */
        public String getPath() {

            return path;
        }

        @Override
        public String toString() {

            return name;
        }
    }

    private void openPopupMenu (DefaultMutableTreeNode node, JComponent source, int x, int y) {

        JPopupMenu popupMenu = null;
        Object userObject = node.getUserObject();

        if (userObject instanceof ResourceElement) {

            ResourceElement element = (ResourceElement) userObject;
            popupMenu = new ResourceElementPopupMenu(element);
        }
        else if (userObject instanceof FileElement) {

            FileElement element = (FileElement) userObject;
            String path = element.getPath();

            if (element.isDirectory()) {
                for (ResourceType type: ResourceType.values()) {
                    String dirName = type.getDirName();
                    if (path.equals(dirName)) {
                        popupMenu = new ResourceParentPopupMenu(path, type, "");
                        break;
                    }
                    else if (path.startsWith(dirName)) {
                        String basepath = path.substring(path.indexOf("/") + 1);
                        popupMenu = new ResourceParentPopupMenu(path, type, basepath);
                        break;
                    }
                }

                if (popupMenu == null) {
                    popupMenu = new DirectoryPopupMenu(path);
                }

            } else {
                popupMenu = new FileElementPopupMenu(path);
            }
        }

        if (popupMenu != null) {
            popupMenu.show(source, x, y);
        }
    }

    /**
     * Handles the mouse events received by the quest tree.
     */
    private class QuestTreeMouseAdapter extends MouseAdapter {

        /**
         * Called when a mouse button is pressed on the tree component.
         */
        @Override
        public void mousePressed(MouseEvent ev) {

            int row = QuestTree.this.getRowForLocation(ev.getX(), ev.getY());
            if (row != -1) {
                QuestTree.this.setSelectionRow(row);
            }

            TreePath selectionPath = QuestTree.this.getSelectionPath();
            if (selectionPath == null) {
                return;
            }

            // Retrieve the node clicked.
            DefaultMutableTreeNode clickedNode = (DefaultMutableTreeNode)
                    selectionPath.getLastPathComponent();

            if (ev.getButton() == MouseEvent.BUTTON3) {
                // Right click.
                openPopupMenu(clickedNode, (JComponent) ev.getSource(), ev.getX(), ev.getY());
            }
            else if (ev.getClickCount() == 2) {
                // Double-click: open the clicked element.
                Object clickedObject = clickedNode.getUserObject();
                if (clickedObject instanceof ResourceElement) {
                    ResourceElement element = (ResourceElement) clickedObject;
                    editorWindow.openResourceElement(element.type, element.id);
                }
                else if  (clickedObject instanceof FileElement) {
                    FileElement element = (FileElement) clickedObject;
                    if (!element.isDirectory()) {
                        editorWindow.openTextEditor(new File(Project.getDataPath()
                                + "/" + element.getPath()));
                    }
                }
            }
        }
    }

    /**
     * Popup menu of any script file node.
     */
    private class FileElementPopupMenu extends JPopupMenu {

        /**
         * Creates the popup menu of a script file.
         * @param path The path of the file
         */
        public FileElementPopupMenu(final String path) {

            // Open.
            JMenuItem menuItem = new JMenuItem("Open script");
            add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    editorWindow.openTextEditor(new File(Project.getDataPath() + "/" + path));
                }
            });

            // Rename.
            menuItem = new JMenuItem("Rename script");
            add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String newName = (String) JOptionPane.showInputDialog(
                        null,
                        "Please enter a new name for the script '" + path + "'",
                        "Change name of script '" + path + "'",
                        JOptionPane.QUESTION_MESSAGE, null, null, path);
                    if (newName != null) {
                        try {
                            if (!newName.endsWith(".lua")) {
                                newName += ".lua";
                            }
                            moveFileElement(path, newName);
                        } catch (QuestEditorException ex) {
                            GuiTools.errorDialog(ex.getMessage());
                        }
                    }
                }
            });

            // Delete.
            menuItem = new JMenuItem("Delete script");
            add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    File file = new File(Project.getDataPath() + "/" + path);

                    int answer = JOptionPane.showConfirmDialog(editorWindow,
                    "Are you sure you want to delete '"
                            + path + "' script ?",
                    "Are you sure?",
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.WARNING_MESSAGE);

                    // if yes, delete the file
                    if (answer == JOptionPane.YES_OPTION && file.delete()) {
                        removeFileElement(path);
                        editorWindow.closeTextEditor(file, false);
                    }
                }
            });

            // Refresh tree.
            menuItem = new JMenuItem("Refresh tree");
            menuItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ev) {
                    refreshTree();
                }
            });
            addSeparator();
            add(menuItem);
        }
    }

    /**
     * Popup menu of any directory node.
     */
    private class DirectoryPopupMenu extends JPopupMenu {

        /**
         * Creates the popup menu of a directory.
         * @param path the path of the directory.
         */
        public DirectoryPopupMenu(final String path) {

            buildDirectoryMenu(path);
        }

        /**
         * Creates the popup menu of a directory.
         * This constructor does not build the menu, you can call the
         * buildDirectoryMenu method to do that.
         */
        protected DirectoryPopupMenu() {
        }

        /**
         * Builds the directory menu.
         * @param path the path of the directory.
         */
        protected void buildDirectoryMenu(final String path) {

            // new script
            JMenuItem elementItem = new JMenuItem("New script");
            elementItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ev) {

                    String name = editorWindow.createNewLuaScript(path);
                    if (name != null && !name.isEmpty()) {
                        addFileElementToTree(name);
                    }
                }
            });
            add(elementItem);

            // new directory
            elementItem = new JMenuItem("New directory");
            elementItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ev) {

                    String name = editorWindow.createNewDirectory(path);
                    if (name != null && !name.isEmpty()) {
                        addFileElementToTree(name);
                    }
                }
            });
            add(elementItem);

            // delete directory (if empty)
            final File file = new File(Project.getDataPath() + "/" + path);
            elementItem = new JMenuItem("Delete directory");
            elementItem.setEnabled(file.isDirectory() && file.list().length == 0);
            elementItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ev) {
                    if (file.delete()) {
                        removeFileElement(path);
                    }
                }
            });
            addSeparator();
            add(elementItem);

            // Refresh tree.
            elementItem = new JMenuItem("Refresh tree");
            elementItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ev) {
                    refreshTree();
                }
            });
            addSeparator();
            add(elementItem);
        }
    }

    /**
     * Popup menu of any resource parent node.
     */
    private class ResourceParentPopupMenu extends DirectoryPopupMenu {

        /**
         * Creates the popup menu of a resource type.
         * @param path the path of the director
         * @param resourceType A resource type.y.
         * @param basepath the default path of the resource.
         */
        public ResourceParentPopupMenu(final String path,
                final ResourceType resourceType, final String basepath) {
            super();

            JMenuItem elementItem = new JMenuItem(
                    "New " + resourceType.getName().toLowerCase());
            elementItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ev) {

                    editorWindow.createResourceElement(resourceType, basepath);
                }
            });
            add(elementItem);

            addSeparator();
            buildDirectoryMenu(path);
        }
    }

    /**
     * Popup menu of a resource element.
     */
    private class ResourceElementPopupMenu extends JPopupMenu {

        /**
         * Creates a popup menu for the given resource element.
         * @param element A resource element.
         */
        public ResourceElementPopupMenu(final ResourceElement element) {

            // Open.
            String resourceTypeName = element.type.getName().toLowerCase();
            JMenuItem menuItem;

            // Open dialogs (specific to languages).
            if (element.type == ResourceType.LANGUAGE) {
                menuItem = new JMenuItem("Open dialogs");
                add(menuItem);
                menuItem.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        editorWindow.openTextEditor(Project.getDialogsFile(element.id));
                    }
                });

                // Open strings (specific to languages).
                menuItem = new JMenuItem("Open strings");
            }
            else {
                // Open <resource type name>
                menuItem = new JMenuItem("Open " + resourceTypeName);
            }
            add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    editorWindow.openResourceElement(element.type, element.id);
                }
            });

            // Open map script (specific to maps).
            if (element.type == ResourceType.MAP) {
                menuItem = new JMenuItem("Open map script");
                add(menuItem);
                menuItem.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        editorWindow.openTextEditor(Project.getMapScriptFile(element.id));
                    }
                });
            }

            // Move.
            menuItem = new JMenuItem("Change id");
            add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    editorWindow.moveResourceElement(element.type, element.id);
                }
            });

            // Rename.
            menuItem = new JMenuItem("Change friendly name");
            add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    editorWindow.renameResourceElement(element.type, element.id);
                }
            });

            // Delete.
            menuItem = new JMenuItem("Delete " + resourceTypeName);
            add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    editorWindow.deleteResourceElement(element.type, element.id);
                }
            });

            // Refresh tree.
            menuItem = new JMenuItem("Refresh tree");
            menuItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ev) {
                    refreshTree();
                }
            });
            addSeparator();
            add(menuItem);
        }
    }


    /**
     * Cell renderer used to show a custom icon for some nodes.
     */
    private class QuestCellRenderer extends DefaultTreeCellRenderer {

        @Override
        public Component getTreeCellRendererComponent(
                JTree tree,
                Object node,
                boolean selected,
                boolean expanded,
                boolean leaf,
                int row,
                boolean hasFocus
        ) {

            super.getTreeCellRendererComponent(
                    tree,
                    node,
                    selected,
                    expanded,
                    leaf,
                    row,
                    hasFocus
            );

            // Decide the appropriate icon.
            String iconFileName = "";
            Object info = ((DefaultMutableTreeNode) node).getUserObject();
            if (info instanceof FileElement) {
                // Regular file or directory.
                FileElement fileElement = (FileElement) info;

                String path = fileElement.getPath();

                if (path.isEmpty()) {
                    // Root node: put the Solarus logo.
                    iconFileName = "icon_solarus.png";
                }
                if (fileElement.isDirectory()) {
                    for (ResourceType type: ResourceType.values()) {
                        String dirName = type.getDirName();
                        if (path.equals(dirName)) {
                            // Directory of a resource.
                            iconFileName = "icon_folder_open_" + type.getLuaName() + ".png";
                        }
                    }
                    if (iconFileName.isEmpty()) {
                        // Other directory: usual folder icon.
                        iconFileName = expanded ? "icon_folder_open.png" : "icon_folder_closed.png";
                    }
                }
                else {
                    if (path.endsWith(".lua")) {
                        // Lua script that is not a resource.
                        iconFileName = "icon_script.png";
                    }
                }
            }
            else if (info instanceof ResourceElement) {
                ResourceElement resourceElement = (ResourceElement) info;
                iconFileName = "icon_resource_" + resourceElement.type.getLuaName() + ".png";
            }

            if (!iconFileName.isEmpty()) {
                setIcon(Project.getEditorImageIconOrEmpty(iconFileName));
            }

            return this;
        }

    }

}
TOP

Related Classes of org.solarus.editor.gui.tree.QuestTree$FileElementPopupMenu

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.