001    package nl.cwi.sen1.gui.plugin;
002    
003    import java.awt.BorderLayout;
004    import java.awt.Component;
005    import java.awt.Graphics2D;
006    import java.awt.Image;
007    import java.awt.event.MouseListener;
008    import java.awt.image.BufferedImage;
009    import java.util.Enumeration;
010    
011    import javax.swing.Icon;
012    import javax.swing.ImageIcon;
013    import javax.swing.JPanel;
014    import javax.swing.JScrollPane;
015    import javax.swing.JTree;
016    import javax.swing.event.TreeSelectionEvent;
017    import javax.swing.event.TreeSelectionListener;
018    import javax.swing.tree.DefaultTreeCellRenderer;
019    import javax.swing.tree.TreePath;
020    
021    import nl.cwi.sen1.gui.plugin.data.Module;
022    import nl.cwi.sen1.gui.plugin.data.ModuleSelectionListener;
023    import nl.cwi.sen1.gui.plugin.data.ModuleSelectionModel;
024    import nl.cwi.sen1.gui.plugin.data.ModuleTreeModel;
025    import nl.cwi.sen1.gui.plugin.data.ModuleTreeNode;
026    import aterm.ATerm;
027    
028    public class ModuleTree extends JPanel {
029            private JTree tree;
030    
031            private Enumeration<TreePath> expansionState;
032    
033            private final ModuleTreeModel manager;
034    
035            public ModuleTree(Navigator modulebrowser, final ModuleTreeModel manager) {
036                    this.manager = manager;
037    
038                    setLayout(new BorderLayout());
039    
040                    tree = new JTree(manager);
041                    tree.setRootVisible(false);
042                    tree.setShowsRootHandles(true);
043                    tree.setExpandsSelectedPaths(true);
044                    tree.setSelectionModel(new ModuleSelectionModel());
045                    tree.addTreeSelectionListener(new TreeSelectionListener() {
046                            public void valueChanged(TreeSelectionEvent e) {
047                                    manager.selectModule(getCurrentModule());
048                            }
049                    });
050    
051                    ImageIcon folderIcon = new ImageIcon(getClass().getResource(
052                                    "/resources/images/folder.png"));
053                    ImageIcon documentIcon = new ImageIcon(getClass().getResource(
054                                    "/resources/images/document.png"));
055                    ImageIcon errorOverlayIcon = new ImageIcon(getClass().getResource(
056                                    "/resources/images/error-overlay.png"));
057    
058                    ImageIcon errorFolderIcon = createOverlayIcon(folderIcon, errorOverlayIcon);
059                    ImageIcon errorDocumentIcon = createOverlayIcon(documentIcon, errorOverlayIcon);
060    
061                    tree.setCellRenderer(new TreeIconCellRenderer(folderIcon, documentIcon,
062                                    errorFolderIcon, errorDocumentIcon));
063    
064                    add(new JScrollPane(tree));
065    
066                    manager.addModuleSelectionListener(new ModuleSelectionListener() {
067                            public void moduleSelected(Module module) {
068                                    if (module != null) {
069                                            TreePath path = manager.makeTreePath(module.getFile());
070                                            tree.setSelectionPath(path);
071                                            tree.scrollPathToVisible(path);
072                                    } else {
073                                            tree.clearSelection();
074                                    }
075                            }
076                    });
077            }
078    
079            private ImageIcon createOverlayIcon(ImageIcon icon, ImageIcon overlay) {
080                    Image image = icon.getImage();
081                    BufferedImage bufferedImage = new BufferedImage(image.getWidth(null),
082                                    image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
083    
084                    Graphics2D g = bufferedImage.createGraphics();
085                    g.drawImage(image, null, null);
086                    g.drawImage(overlay.getImage(), 0, 0, null);
087                    g.dispose();
088                    return new ImageIcon(bufferedImage);
089            }
090    
091            public void saveExpansionState() {
092                    expansionState = tree.getExpandedDescendants(new TreePath(tree
093                                    .getModel().getRoot()));
094            }
095    
096            public void loadExpansionState() {
097                    if (expansionState != null) {
098                            while (expansionState.hasMoreElements()) {
099                                    TreePath treePath = expansionState.nextElement();
100                                    tree.expandPath(treePath);
101                            }
102                    }
103            }
104    
105            public ATerm selectModule(int X, int Y) {
106                    TreePath path = tree.getClosestPathForLocation(X, Y);
107                    if (path != null) {
108                            tree.setSelectionPath(path);
109                            ModuleTreeNode selectedModule = (ModuleTreeNode) path
110                                            .getLastPathComponent();
111                            return selectedModule.getId();
112                    }
113                    return null;
114            }
115    
116            private Module getCurrentModule() {
117                    TreePath path = tree.getSelectionPath();
118    
119                    if (path != null) {
120                            ModuleTreeNode selectedModule = (ModuleTreeNode) path
121                                            .getLastPathComponent();
122                            return manager.getModule(selectedModule.getId());
123                    }
124    
125                    return null;
126            }
127    
128            public void addMouseListener(MouseListener l) {
129                    tree.addMouseListener(l);
130            }
131    
132            class TreeIconCellRenderer extends DefaultTreeCellRenderer {
133                    private Icon folderIcon;
134                    private Icon documentIcon;
135                    private Icon errorFolderIcon;
136                    private Icon errorDocumentIcon;
137    
138                    public TreeIconCellRenderer(Icon folderIcon, Icon documentIcon,
139                                    Icon errorFolderIcon, Icon errorDocumentIcon) {
140                            this.folderIcon = folderIcon;
141                            this.documentIcon = documentIcon;
142                            this.errorFolderIcon = errorFolderIcon;
143                            this.errorDocumentIcon = errorDocumentIcon;
144                    }
145    
146                    public Component getTreeCellRendererComponent(JTree tree, Object value,
147                                    boolean sel, boolean expanded, boolean leaf, int row,
148                                    boolean hasFocus) {
149    
150                            super.getTreeCellRendererComponent(tree, value, sel, expanded,
151                                            leaf, row, hasFocus);
152    
153                            ModuleTreeNode treeNode = (ModuleTreeNode) value;
154                            if (treeNode.hasError() == true) {
155                                    if (treeNode.isLeaf() == true) {
156                                            setIcon(errorDocumentIcon);
157                                    } else {
158                                            setIcon(errorFolderIcon);
159                                    }
160                            } else {
161                                    if (treeNode.isLeaf() == true) {
162                                            setIcon(documentIcon);
163                                    } else {
164                                            setIcon(folderIcon);
165                                    }
166                            }
167    
168                            return this;
169                    }
170            }
171    }