2 * jSite2 - FileManager.java -
3 * Copyright © 2008 David Roden
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 package net.pterodactylus.jsite.gui;
22 import java.awt.BorderLayout;
23 import java.awt.Color;
24 import java.awt.Component;
25 import java.awt.Dimension;
26 import java.awt.FlowLayout;
28 import java.awt.GridBagConstraints;
29 import java.awt.GridBagLayout;
30 import java.awt.Insets;
31 import java.awt.Point;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.awt.event.MouseEvent;
35 import java.awt.event.MouseListener;
36 import java.beans.PropertyChangeEvent;
37 import java.beans.PropertyChangeListener;
39 import java.util.ArrayList;
40 import java.util.Collections;
41 import java.util.HashMap;
42 import java.util.List;
44 import java.util.logging.Level;
45 import java.util.logging.Logger;
47 import javax.swing.BorderFactory;
48 import javax.swing.JButton;
49 import javax.swing.JCheckBoxMenuItem;
50 import javax.swing.JDialog;
51 import javax.swing.JLabel;
52 import javax.swing.JOptionPane;
53 import javax.swing.JPanel;
54 import javax.swing.JPopupMenu;
55 import javax.swing.JScrollPane;
56 import javax.swing.JTextField;
57 import javax.swing.JTree;
58 import javax.swing.event.TreeModelEvent;
59 import javax.swing.event.TreeModelListener;
60 import javax.swing.event.TreeSelectionEvent;
61 import javax.swing.event.TreeSelectionListener;
62 import javax.swing.tree.DefaultTreeCellRenderer;
63 import javax.swing.tree.TreeModel;
64 import javax.swing.tree.TreePath;
66 import net.pterodactylus.jsite.i18n.I18n;
67 import net.pterodactylus.jsite.i18n.I18nable;
68 import net.pterodactylus.jsite.i18n.gui.I18nAction;
69 import net.pterodactylus.jsite.i18n.gui.I18nLabel;
70 import net.pterodactylus.jsite.project.FileOverride;
71 import net.pterodactylus.jsite.project.Project;
72 import net.pterodactylus.jsite.project.ProjectFile;
73 import net.pterodactylus.util.logging.Logging;
74 import net.pterodactylus.util.swing.SwingUtils;
77 * Manages physical and virtual files in a project.
79 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
81 public class FileManager extends JDialog implements I18nable, ActionListener, TreeSelectionListener, MouseListener {
84 private static final Logger logger = Logging.getLogger(FileManager.class.getName());
86 /** The Swing interface. */
87 private final SwingInterface swingInterface;
89 /** The project whose files to manage. */
90 private final Project project;
92 /** The tree model for the project files. */
93 private final ProjectFileTreeModel fileTreeModel;
95 /** The tree cell renderer. */
96 private final FileCellRenderer fileCellRenderer;
98 /** The “rescan” action. */
99 private I18nAction rescanAction;
101 /** The “close” action. */
102 private I18nAction closeAction;
104 /** The “set default file” action. */
105 private I18nAction setDefaultFileAction;
107 /** The “insert” action. */
108 private I18nAction insertAction;
110 /** The “project files” label. */
111 private I18nLabel projectFilesLabel;
113 /** The tree that shows the files. */
114 private JTree fileTree;
116 /** The scroll pane that holds the file tree. */
117 private JScrollPane fileScrollPane;
119 /** The “file properties” label. */
120 private I18nLabel filePropertiesLabel;
122 /** The “file path” label. */
123 private I18nLabel filePathLabel;
125 /** The “file path” textfield. */
126 private JTextField filePathTextField;
128 /** The “file name” label. */
129 private I18nLabel fileNameLabel;
131 /** The “file name” textfield. */
132 private JTextField fileNameTextField;
134 /** The “file size” label. */
135 private I18nLabel fileSizeLabel;
137 /** The “file size” text field. */
138 private JTextField fileSizeTextField;
140 /** The context menu for the tree. */
141 private JPopupMenu treeContextMenu;
143 /** The “insert” checkbox. */
144 private JCheckBoxMenuItem insertCheckBoxMenuItem;
147 * Creates a new file manager.
149 * @param swingInterface
150 * The Swing interface
152 * The project whose files to manage
154 public FileManager(SwingInterface swingInterface, Project project) {
155 super(swingInterface.getMainWindow(), I18n.get("fileManager.title", project.getName()), true);
156 logger.log(Level.FINEST, "project: " + project);
157 this.swingInterface = swingInterface;
158 this.project = project;
159 fileTreeModel = new ProjectFileTreeModel();
160 project.addPropertyChangeListener(fileTreeModel);
161 fileCellRenderer = new FileCellRenderer();
165 SwingUtils.center(this);
173 * @see java.awt.Component#setVisible(boolean)
176 public void setVisible(boolean visible) {
180 super.setVisible(visible);
188 * Initializes all actions.
190 private void initActions() {
191 closeAction = new I18nAction("fileManager.button.close") {
196 public void actionPerformed(ActionEvent e) {
200 rescanAction = new I18nAction("fileManager.button.rescan") {
205 @SuppressWarnings("synthetic-access")
206 public void actionPerformed(ActionEvent actionEvent) {
210 setDefaultFileAction = new I18nAction("fileManager.menu.item.setDefaultFile") {
215 public void actionPerformed(ActionEvent actionEvent) {
216 TreePath selectedPath = fileTree.getSelectionPath();
217 if (selectedPath == null) {
218 logger.log(Level.WARNING, "nothing selected!");
221 ProjectFileWrapper projectFileWrapper = (ProjectFileWrapper) selectedPath.getLastPathComponent();
222 if (isHidden(projectFileWrapper)) {
224 JOptionPane.showMessageDialog(FileManager.this, I18n.get(""), I18n.get(""), JOptionPane.ERROR_MESSAGE);
227 if (projectFileWrapper.getProjectFile().isDirectory()) {
229 JOptionPane.showMessageDialog(FileManager.this, I18n.get(""), I18n.get(""), JOptionPane.ERROR_MESSAGE);
232 String completePath = projectFileWrapper.getProjectFile().getCompletePath();
233 project.setDefaultFile(completePath);
236 insertAction = new I18nAction("fileManager.menu.item.insert") {
241 public void actionPerformed(ActionEvent e) {
248 * Initializes all components.
250 private void initComponents() {
251 treeContextMenu = new JPopupMenu();
252 treeContextMenu.add(setDefaultFileAction);
253 insertCheckBoxMenuItem = new JCheckBoxMenuItem(insertAction);
254 treeContextMenu.add(insertCheckBoxMenuItem);
256 JPanel contentPanel = new JPanel(new BorderLayout(12, 12));
257 contentPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
259 contentPanel.add(createFileManagerPanel(), BorderLayout.CENTER);
260 contentPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
262 setContentPane(contentPanel);
266 * Creates the main panel with the file tree and the file properties.
268 * @return The mail panel
270 private Component createFileManagerPanel() {
271 JPanel fileManagerPanel = new JPanel(new BorderLayout(12, 12));
273 /* file tree panel */
274 JPanel fileTreePanel = new JPanel(new BorderLayout(12, 12));
275 fileManagerPanel.add(fileTreePanel, BorderLayout.LINE_START);
277 fileTree = new JTree(fileTreeModel);
278 fileTree.setShowsRootHandles(false);
279 fileTree.addTreeSelectionListener(this);
280 fileTree.addMouseListener(this);
281 fileTree.setCellRenderer(fileCellRenderer);
282 fileTreePanel.add(fileScrollPane = new JScrollPane(fileTree), BorderLayout.CENTER);
283 fileScrollPane.setPreferredSize(new Dimension(200, 350));
285 projectFilesLabel = new I18nLabel("fileManager.label.projectFiles", fileTree);
286 JPanel projectFilesLabelPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
287 fileTreePanel.add(projectFilesLabelPanel, BorderLayout.NORTH);
288 projectFilesLabelPanel.add(projectFilesLabel);
290 /* the right panel */
291 JPanel rightPanel = new JPanel(new BorderLayout(12, 12));
292 fileManagerPanel.add(rightPanel, BorderLayout.CENTER);
294 /* properties panel */
295 JPanel propertiesPanel = new JPanel(new GridBagLayout());
296 rightPanel.add(propertiesPanel, BorderLayout.CENTER);
297 propertiesPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEtchedBorder(), BorderFactory.createEmptyBorder(12, 12, 12, 12)));
298 propertiesPanel.setPreferredSize(new Dimension(400, 350));
300 filePropertiesLabel = new I18nLabel("fileManager.label.fileProperties");
301 filePropertiesLabel.setFont(filePropertiesLabel.getFont().deriveFont(Font.BOLD));
302 propertiesPanel.add(filePropertiesLabel, new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
304 filePathLabel = new I18nLabel("fileManager.label.filePath");
305 filePathTextField = new JTextField();
306 filePathTextField.setEditable(false);
307 propertiesPanel.add(filePathLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(12, 24, 0, 0), 0, 0));
308 propertiesPanel.add(filePathTextField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(12, 12, 0, 0), 0, 0));
310 fileNameLabel = new I18nLabel("fileManager.label.fileName");
311 fileNameTextField = new JTextField();
312 fileNameTextField.setEditable(false);
313 propertiesPanel.add(fileNameLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(12, 24, 0, 0), 0, 0));
314 propertiesPanel.add(fileNameTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(12, 12, 0, 0), 0, 0));
316 fileSizeLabel = new I18nLabel("fileManager.label.fileSize");
317 fileSizeTextField = new JTextField();
318 fileSizeTextField.setEditable(false);
319 propertiesPanel.add(fileSizeLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(12, 24, 0, 0), 0, 0));
320 propertiesPanel.add(fileSizeTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(12, 12, 0, 0), 0, 0));
323 propertiesPanel.add(new JPanel(), new GridBagConstraints(0, 4, 2, 1, 1.0, 1.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
325 /* action button panel */
326 JPanel actionButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
327 rightPanel.add(actionButtonPanel, BorderLayout.PAGE_END);
328 actionButtonPanel.setBorder(BorderFactory.createEtchedBorder());
330 JButton rescanButton = new JButton(rescanAction);
331 actionButtonPanel.add(rescanButton);
333 return fileManagerPanel;
337 * Creates the button panel.
339 * @return The button panel
341 private Component createButtonPanel() {
342 JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
344 buttonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
345 JButton closeButton = new JButton(closeAction);
346 buttonPanel.add(closeButton);
348 getRootPane().setDefaultButton(closeButton);
353 * Initiates a file scan.
355 private void initiateFileScan() {
356 swingInterface.getThreadPool().execute(new Runnable() {
359 * @see java.lang.Runnable#run()
361 @SuppressWarnings("synthetic-access")
363 fileTree.setEnabled(false);
364 rescanAction.setEnabled(false);
365 ProjectFile baseProjectFile = project.getBaseFile();
366 if (baseProjectFile != null) {
367 fileTreeModel.setBaseProjectFile(baseProjectFile);
369 // fileScrollPane.revalidate();
370 rescanAction.setEnabled(true);
371 fileTree.setEnabled(true);
378 * Checks whether the given mouse event is a popup trigger and occured over
379 * a file. If so, the context menu is shown.
382 * The mouse event to check
384 private void maybeShowContextMenu(MouseEvent mouseEvent) {
385 if (!mouseEvent.isPopupTrigger()) {
388 Point eventLocation = mouseEvent.getPoint();
389 TreePath clickedPath = fileTree.getPathForLocation(eventLocation.x, eventLocation.y);
390 if (clickedPath == null) {
393 fileTree.setSelectionPath(clickedPath);
394 ProjectFileWrapper projectFileWrapper = (ProjectFileWrapper) clickedPath.getLastPathComponent();
395 insertCheckBoxMenuItem.setSelected(!isHidden(projectFileWrapper));
396 treeContextMenu.show(fileTree, eventLocation.x, eventLocation.y);
400 * Finds whether the {@link ProjectFile} given by
401 * <code>projectFileWrapper</code> is hidden.
403 * @param projectFileWrapper
404 * The wrapped project file
405 * @return <code>true</code> if the file is hidden and should not be
406 * inserted, <code>false</code> otherwise
408 private boolean isHidden(ProjectFileWrapper projectFileWrapper) {
409 ProjectFile projectFile = projectFileWrapper.getProjectFile();
410 FileOverride fileOverride = project.getFileOverrides().get(projectFile.getCompletePath());
411 return ((fileOverride == null) && projectFile.isHidden()) || ((fileOverride != null) && (fileOverride.isInsert()));
415 // INTERFACE I18nable
421 public void updateI18n() {
422 setTitle(I18n.get("fileManager.title", project.getName()));
423 projectFilesLabel.updateI18n();
424 filePropertiesLabel.updateI18n();
425 filePathLabel.updateI18n();
429 // INTERFACE TreeSelectionListener
435 public void valueChanged(TreeSelectionEvent treeSelectionEvent) {
436 TreePath[] selectedPaths = fileTree.getSelectionPaths();
437 filePathTextField.setText("");
438 fileNameTextField.setText("");
439 fileSizeTextField.setText("");
440 if ((selectedPaths != null) && (selectedPaths.length == 1)) {
441 Object lastPathComponent = selectedPaths[0].getLastPathComponent();
442 if (!(lastPathComponent instanceof ProjectFileWrapper)) {
443 logger.log(Level.SEVERE, "lastPathComponent is not a ProjectFileWrapper!");
446 ProjectFileWrapper projectFileWrapper = (ProjectFileWrapper) lastPathComponent;
447 ProjectFile projectFile = projectFileWrapper.getProjectFile();
448 if (projectFile.isFile()) {
449 String completePath = projectFile.getCompletePath();
450 int lastSeparator = completePath.lastIndexOf(File.separatorChar);
451 if (lastSeparator == -1) {
452 filePathTextField.setText("");
454 filePathTextField.setText(completePath.substring(0, lastSeparator));
456 fileNameTextField.setText(projectFile.getName());
457 fileSizeTextField.setText(String.valueOf(projectFile.getSize()));
463 // INTERFACE ActionListener
469 public void actionPerformed(ActionEvent actionEvent) {
474 // INTERFACE MouseListener
480 public void mouseClicked(MouseEvent mouseEvent) {
481 maybeShowContextMenu(mouseEvent);
487 public void mouseEntered(MouseEvent mouseEvent) {
494 public void mouseExited(MouseEvent mouseEvent) {
501 public void mousePressed(MouseEvent mouseEvent) {
502 maybeShowContextMenu(mouseEvent);
508 public void mouseReleased(MouseEvent mouseEvent) {
509 maybeShowContextMenu(mouseEvent);
513 * Tree cell renderer that takes care of certain display properties for
514 * project-specific stuff.
516 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
518 private class FileCellRenderer extends DefaultTreeCellRenderer {
528 * @see javax.swing.tree.TreeCellRenderer#getTreeCellRendererComponent(javax.swing.JTree,
529 * java.lang.Object, boolean, boolean, boolean, int, boolean)
531 @SuppressWarnings("synthetic-access")
533 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
534 Component superCellRenderer = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
535 if (!(superCellRenderer instanceof JLabel)) {
536 logger.log(Level.SEVERE, "superCellRenderer is not a JLabel!");
537 return superCellRenderer;
539 if (!(value instanceof ProjectFileWrapper)) {
540 logger.log(Level.SEVERE, "value is not a ProjectFileWrapper!");
541 return superCellRenderer;
543 ProjectFileWrapper projectFileWrapper = (ProjectFileWrapper) value;
544 ProjectFile projectFile = projectFileWrapper.getProjectFile();
545 String completePath = projectFile.getCompletePath();
546 boolean paintBold = false;
547 boolean paintHalfColor = false;
548 if (projectFile.isFile() && projectFile.isHidden()) {
549 /* TODO - check override */
550 paintHalfColor = true;
551 } else if (completePath.equals(project.getDefaultFile())) {
553 } else if (projectFile.getParents().size() == 1) {
556 if (paintHalfColor) {
557 /* TODO - cache colors */
558 Color foreground = superCellRenderer.getForeground();
559 Color background = selected ? getBackgroundSelectionColor() : getBackgroundNonSelectionColor();
560 Color averageColor = new Color((foreground.getRed() + background.getRed()) / 2, (foreground.getGreen() + background.getGreen()) / 2, (foreground.getBlue() + background.getBlue()) / 2);
561 superCellRenderer.setForeground(averageColor);
563 superCellRenderer.setForeground(selected ? getTextSelectionColor() : getTextNonSelectionColor());
566 superCellRenderer.setFont(superCellRenderer.getFont().deriveFont(Font.BOLD));
568 superCellRenderer.setFont(superCellRenderer.getFont().deriveFont(Font.PLAIN));
570 return superCellRenderer;
576 * TreeModel that is based on {@link Project#getBaseFile()}.
578 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
580 private class ProjectFileTreeModel implements TreeModel, PropertyChangeListener {
582 /** Tree model listeners. */
583 private final List<TreeModelListener> treeModelListeners = Collections.synchronizedList(new ArrayList<TreeModelListener>());
585 /** The base project file. */
586 private ProjectFile baseProjectFile;
588 /** Maps path names to project files. */
589 private final Map<String, ProjectFile> pathProjectFiles = Collections.synchronizedMap(new HashMap<String, ProjectFile>());
591 /** Maps project files to wrappers. */
592 private final Map<ProjectFile, ProjectFileWrapper> projectFileWrappers = Collections.synchronizedMap(new HashMap<ProjectFile, ProjectFileWrapper>());
597 ProjectFileTreeModel() {
608 public void addTreeModelListener(TreeModelListener treeModelListener) {
609 treeModelListeners.add(treeModelListener);
615 public void removeTreeModelListener(TreeModelListener treeModelListener) {
616 treeModelListeners.remove(treeModelListener);
620 * Notifies all listeners that a node has changed.
622 * @param changedProjectFileWrapper
623 * The wrapper around the changed project file
625 protected void fireTreeNodesChanged(ProjectFileWrapper changedProjectFileWrapper) {
626 ProjectFile changedProjectFile = changedProjectFileWrapper.getProjectFile();
627 ProjectFile changedProjectFileParent = changedProjectFile.getParent();
628 ProjectFile currentProjectFileParent = changedProjectFile;
629 List<ProjectFileWrapper> parentProjectFileWrappers = new ArrayList<ProjectFileWrapper>();
631 parentProjectFileWrappers.add(0, projectFileWrappers.get(currentProjectFileParent));
632 currentProjectFileParent = currentProjectFileParent.getParent();
633 } while (currentProjectFileParent != null);
634 TreeModelEvent treeModelEvent = new TreeModelEvent(this, parentProjectFileWrappers.toArray(), new int[] { getIndexOfChild(projectFileWrappers.get(changedProjectFileParent), changedProjectFileWrapper) }, new Object[] { changedProjectFileWrapper });
635 for (TreeModelListener treeModelListener : treeModelListeners) {
636 treeModelListener.treeNodesChanged(treeModelEvent);
641 * Notifies all listeners that the tree structure has changed
644 * @see TreeModelListener#treeStructureChanged(TreeModelEvent)
647 protected void fireTreeStructureChanged(ProjectFileWrapper newRootNode) {
648 for (TreeModelListener treeModelListener : treeModelListeners) {
649 treeModelListener.treeStructureChanged(new TreeModelEvent(this, new Object[] { newRootNode }));
658 * Sets the new base project file. This causes the model to reload.
660 * @param baseProjectFile
661 * The new base project file
663 @SuppressWarnings("synthetic-access")
664 public synchronized void setBaseProjectFile(ProjectFile baseProjectFile) {
665 this.baseProjectFile = baseProjectFile;
666 projectFileWrappers.clear();
667 pathProjectFiles.clear();
668 createWrappers(baseProjectFile);
669 projectFileWrappers.get(baseProjectFile).setNameOverride(project.getName());
670 fireTreeStructureChanged(projectFileWrappers.get(baseProjectFile));
678 * Creates {@link ProjectFileWrapper}s for all files below the given
682 * The base project file for all project files to create
685 private void createWrappers(ProjectFile projectFile) {
686 projectFileWrappers.put(projectFile, new ProjectFileWrapper(projectFile));
687 pathProjectFiles.put(projectFile.getCompletePath(), projectFile);
688 for (ProjectFile projectFileChild : projectFile.getFiles()) {
689 if (projectFileChild.isDirectory()) {
690 createWrappers(projectFileChild);
692 projectFileWrappers.put(projectFileChild, new ProjectFileWrapper(projectFileChild));
693 pathProjectFiles.put(projectFileChild.getCompletePath(), projectFileChild);
698 // INTERFACE TreeModel
704 public Object getRoot() {
705 return projectFileWrappers.get(baseProjectFile);
711 @SuppressWarnings("synthetic-access")
712 public Object getChild(Object parent, int index) {
713 if (!(parent instanceof ProjectFileWrapper)) {
714 logger.log(Level.SEVERE, "parent is not a ProjectFileWrapper!");
717 ProjectFileWrapper projectFileWrapper = (ProjectFileWrapper) parent;
718 ProjectFile projectFile = projectFileWrapper.getProjectFile();
719 return projectFileWrappers.get(projectFile.getFiles().get(index));
725 @SuppressWarnings("synthetic-access")
726 public int getChildCount(Object parent) {
727 if (!(parent instanceof ProjectFileWrapper)) {
728 logger.log(Level.SEVERE, "parent is not a ProjectFileWrapper!");
731 ProjectFileWrapper projectFileWrapper = (ProjectFileWrapper) parent;
732 ProjectFile projectFile = projectFileWrapper.getProjectFile();
733 return projectFile.getFiles().size();
739 @SuppressWarnings("synthetic-access")
740 public int getIndexOfChild(Object parent, Object child) {
741 if (!(parent instanceof ProjectFileWrapper)) {
742 logger.log(Level.SEVERE, "parent is not a ProjectFileWrapper!");
745 if (!(child instanceof ProjectFileWrapper)) {
746 logger.log(Level.SEVERE, "child is not a ProjectFileWrapper!");
749 ProjectFileWrapper projectFileWrapper = (ProjectFileWrapper) parent;
750 ProjectFile projectFile = projectFileWrapper.getProjectFile();
751 return projectFile.getFiles().indexOf(((ProjectFileWrapper) child).getProjectFile());
757 @SuppressWarnings("synthetic-access")
758 public boolean isLeaf(Object node) {
759 if (!(node instanceof ProjectFileWrapper)) {
760 logger.log(Level.SEVERE, "node is not a ProjectFileWrapper!");
763 ProjectFileWrapper projectFileWrapper = (ProjectFileWrapper) node;
764 return projectFileWrapper.getProjectFile().isFile();
770 public void valueForPathChanged(TreePath path, Object newValue) {
771 /* ignore, items will not be modified in tree. */
775 // INTERFACE PropertyChangeListener
779 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
781 public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
782 if (Project.PROPERTY_DEFAULT_FILE.equals(propertyChangeEvent.getPropertyName())) {
783 String oldCompletePath = (String) propertyChangeEvent.getOldValue();
784 String newCompletePath = (String) propertyChangeEvent.getNewValue();
785 ProjectFile oldProjectFile = pathProjectFiles.get(oldCompletePath);
786 ProjectFile newProjectFile = pathProjectFiles.get(newCompletePath);
787 ProjectFileWrapper oldProjectFileWrapper = projectFileWrappers.get(oldProjectFile);
788 ProjectFileWrapper newProjectFileWrapper = projectFileWrappers.get(newProjectFile);
789 System.out.println("oldProjectFileWrapper: " + oldProjectFileWrapper);
790 System.out.println("newProjectFileWrapper: " + newProjectFileWrapper);
791 fireTreeNodesChanged(oldProjectFileWrapper);
792 fireTreeNodesChanged(newProjectFileWrapper);
793 /* HACK - swing sucks a bit. */
794 fileTree.setShowsRootHandles(false);
801 * Wrapper around a {@link ProjectFile} that overwrites
802 * {@link Object#toString()} to return the project file’s name.
804 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
806 private static class ProjectFileWrapper {
808 /** The wrapped project file. */
809 private final ProjectFile projectFile;
811 /** The override name. */
812 private String nameOverride;
815 * Creates a new wrapper around a project file.
818 * The project file to wrap
820 public ProjectFileWrapper(ProjectFile projectFile) {
821 this.projectFile = projectFile;
825 * Returns the wrapped project file.
827 * @return The wrapped project file
829 public ProjectFile getProjectFile() {
834 * Sets the name override. If the name override is not <code>null</code>
835 * it will be shown insted of the project file’s name.
837 * @param nameOverride
840 void setNameOverride(String nameOverride) {
841 this.nameOverride = nameOverride;
848 public String toString() {
849 return (nameOverride != null) ? nameOverride : projectFile.getName();