* Bug 11852 fixed: now filebrowser updates (again) 06/21506/7
Clément DAVID [Fri, 19 Jun 2020 10:03:07 +0000 (12:03 +0200)]
This implementation track changes using filesystems capabilities to
reload part of the filebrowser model on file creation/deletion and for
visible nodes.

This reverts commit 93c93ccfffbfc7bd69002596ac86b98e98d70f58 and provide
a better implementation.

Change-Id: If900b9001d04153fec8f75e52658d8ed902e8ffb

scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/BrowseVar.java
scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/FileNode.java
scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabFileBrowserModel.java
scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabTreeTableModelAdapter.java
scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/SwingScilabTreeTable.java

index 98d94cb..b9cb61b 100644 (file)
@@ -17,18 +17,13 @@ package org.scilab.modules.ui_data;
 
 import javax.swing.ImageIcon;
 import javax.swing.JLabel;
-
 import org.scilab.modules.commons.gui.FindIconHelper;
 import org.scilab.modules.localization.Messages;
 import org.scilab.modules.types.ScilabTypeEnum;
 import org.scilab.modules.types.ScilabTypeEnumDescription;
 import org.scilab.modules.ui_data.variablebrowser.ScilabVariableBrowser;
 
-/**
- *
- * Static class to open/close Scilab Variable browser
- *
- */
+/** Static class to open/close Scilab Variable browser */
 public class BrowseVar {
 
     public static final int ICON_COLUMN_INDEX = 0;
@@ -42,23 +37,36 @@ public class BrowseVar {
     public static final int NB_ROWS_INDEX = 8;
     public static final int NB_COLS_INDEX = 9;
 
-    public static final String[] COLUMNNAMES = new String[] {"", /* Icon */
-            Messages.gettext("Name"),
-            Messages.gettext("Value"),
-            Messages.gettext("Type"),
-            Messages.gettext("Visibility"),
-            Messages.gettext("Memory"),
-            Messages.gettext("User"),
-            Messages.gettext("Type int value"),
-            "", /* nbrows */
-            "" /* nbcols */
-                                                            };
-
-    public static final int[] COLUMNSALIGNMENT = new int[] { -1, JLabel.LEFT, JLabel.RIGHT, JLabel.RIGHT, JLabel.RIGHT, JLabel.RIGHT, JLabel.RIGHT, JLabel.RIGHT};
+    public static final String[] COLUMNNAMES =
+        new String[] {
+        "", /* Icon */
+        Messages.gettext("Name"),
+        Messages.gettext("Value"),
+        Messages.gettext("Type"),
+        Messages.gettext("Visibility"),
+        Messages.gettext("Memory"),
+        Messages.gettext("User"),
+        Messages.gettext("Type int value"),
+        "", /* nbrows */
+        "" /* nbcols */
+    };
+
+    public static final int[] COLUMNSALIGNMENT =
+        new int[] {
+        -1,
+        JLabel.LEFT,
+        JLabel.RIGHT,
+        JLabel.RIGHT,
+        JLabel.RIGHT,
+        JLabel.RIGHT,
+        JLabel.RIGHT,
+        JLabel.RIGHT
+        };
 
     private static final ImageIcon NO_ICON = new ImageIcon(FindIconHelper.findIcon("noicon"));
     private static final ImageIcon DOUBLE_ICON = new ImageIcon(FindIconHelper.findIcon("double"));
-    private static final ImageIcon POLYNOMIAL_ICON = new ImageIcon(FindIconHelper.findIcon("polynomial"));
+    private static final ImageIcon POLYNOMIAL_ICON =
+        new ImageIcon(FindIconHelper.findIcon("polynomial"));
     private static final ImageIcon BOOLEAN_ICON = new ImageIcon(FindIconHelper.findIcon("boolean"));
     private static final ImageIcon SPARSE_ICON = new ImageIcon(FindIconHelper.findIcon("sparse"));
     private static final ImageIcon INT_ICON = new ImageIcon(FindIconHelper.findIcon("int"));
@@ -72,13 +80,12 @@ public class BrowseVar {
     private static final ImageIcon USER_ICON = new ImageIcon(FindIconHelper.findIcon("user"));
     private static final ImageIcon FPTR_ICON = new ImageIcon(FindIconHelper.findIcon("fptr"));
 
-    /**
-     * Default private constructor for utility class
-     */
-    private BrowseVar() { }
+    /** Default private constructor for utility class */
+    private BrowseVar() {}
 
     /**
      * Get ImageIcon instance from Scilab type (as int)
+     *
      * @param type : scilab type as integer
      * @return instance of type Icon
      */
@@ -103,8 +110,8 @@ public class BrowseVar {
             case 11:
             case 13:
                 return FUNCTION_ICON;
-                /*case 14:
-                  return LIBRARY_ICON;*/
+            /*case 14:
+            return LIBRARY_ICON;*/
             case 15:
                 return LIST_ICON;
             case 16:
@@ -123,15 +130,14 @@ public class BrowseVar {
         }
     }
 
-    /**
-     * Open Variable Browser
-     */
+    /** Open Variable Browser */
     public static void openVariableBrowser() {
         ScilabVariableBrowser.openVariableBrowser();
     }
 
     /**
      * Set the Variable Browser data given by Scilab
+     *
      * @param dataNames : scilab variable name
      * @param dataBytes : scilab variable size in bytes
      * @param dataTypes : scilab variable type (as integer)
@@ -140,20 +146,34 @@ public class BrowseVar {
      * @param dataVisibility : local or global variable
      * @param dataFromUser : Scilab data or user data
      */
-    public static void setVariableBrowserData(String[] dataNames, long[] dataBytes, int[] dataTypes, int[] dataIntegerTypes, String[] variableListTypes, String[] dataSizes, int[] dataNbRows, int[] dataNbCols, String[] dataVisibility, boolean[] dataFromUser) {
+    public static void setVariableBrowserData(
+        String[] dataNames,
+        long[] dataBytes,
+        int[] dataTypes,
+        int[] dataIntegerTypes,
+        String[] variableListTypes,
+        String[] dataSizes,
+        int[] dataNbRows,
+        int[] dataNbCols,
+        String[] dataVisibility,
+        boolean[] dataFromUser) {
         Object[][] data = new Object[dataNames.length][COLUMNNAMES.length];
         for (int i = 0; i < dataNames.length; ++i) {
             data[i][ICON_COLUMN_INDEX] = getIconFromType(dataTypes[i]);
             data[i][NAME_COLUMN_INDEX] = dataNames[i];
             data[i][SIZE_COLUMN_INDEX] = dataSizes[i];
-            data[i][TYPE_DESC_COLUMN_INDEX] = ScilabTypeEnumDescription.getTypeDescriptionFromId(dataTypes[i]);
+            data[i][TYPE_DESC_COLUMN_INDEX] =
+                ScilabTypeEnumDescription.getTypeDescriptionFromId(dataTypes[i]);
 
             if (dataTypes[i] == ScilabTypeEnum.sci_ints.swigValue() && dataIntegerTypes[i] != 0) {
                 // It is an integer. We want to detail the precision of the int
-                data[i][TYPE_DESC_COLUMN_INDEX] = data[i][TYPE_DESC_COLUMN_INDEX] + " " + dataIntegerTypes[i];
+                data[i][TYPE_DESC_COLUMN_INDEX] =
+                    data[i][TYPE_DESC_COLUMN_INDEX] + " " + dataIntegerTypes[i];
             }
 
-            if ((dataTypes[i] == ScilabTypeEnum.sci_tlist.swigValue() || dataTypes[i] == ScilabTypeEnum.sci_mlist.swigValue()) && !variableListTypes[i].equals("")) {
+            if ((dataTypes[i] == ScilabTypeEnum.sci_tlist.swigValue()
+                    || dataTypes[i] == ScilabTypeEnum.sci_mlist.swigValue())
+                    && !variableListTypes[i].equals("")) {
                 // Improve the display of the list
                 String varType = ScilabTypeEnumDescription.getListTypeDescription(variableListTypes[i]);
 
@@ -162,18 +182,21 @@ public class BrowseVar {
             }
             data[i][VISIBILITY_COLUMN_INDEX] = dataVisibility[i];
             data[i][BYTES_COLUMN_INDEX] = humanReadableByteCount(dataBytes[i], true);
-            data[i][FROM_SCILAB_COLUMN_INDEX] = dataFromUser[i]; /* Tag if it is a variable from the user or from Scilab (%pi, %eps, etc) */
+            data[i][FROM_SCILAB_COLUMN_INDEX] =
+                dataFromUser[
+                    i]; /* Tag if it is a variable from the user or from Scilab (%pi, %eps, etc) */
             data[i][TYPE_COLUMN_INDEX] = dataTypes[i];
             data[i][NB_ROWS_INDEX] = dataNbRows[i];
             data[i][NB_COLS_INDEX] = dataNbCols[i];
         }
         ScilabVariableBrowser.setVariableBrowserData(data);
     }
-    
+
     /**
      * Convert a byte-count into a human readable string
-     * @see https://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java/3758880#3758880
-     * 
+     *
+     * @see
+     *     https://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java/3758880#3758880
      * @param bytes the number of bytes
      * @param si true if you wish to format as International System, false for Binary System
      * @return a formatted string
@@ -181,31 +204,25 @@ public class BrowseVar {
     public static String humanReadableByteCount(long bytes, boolean si) {
         int unit = si ? 1000 : 1024;
         if (bytes < unit) {
-                       return bytes + " B";
-               }
+            return bytes + " B";
+        }
 
         int exp = (int) (Math.log(bytes) / Math.log(unit));
-        String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
+        String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
         return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
     }
 
-    /**
-     * Update Variable Browser
-     */
+    /** Update Variable Browser */
     public static void updateVariableBrowserData() {
         ScilabVariableBrowser.updateVariableBrowser();
     }
 
-    /**
-     * @return true if an instance of BrowseVar already exists.
-     */
+    /** @return true if an instance of BrowseVar already exists. */
     public static boolean isVariableBrowserOpened() {
         return ScilabVariableBrowser.isBrowseVarOpened();
     }
 
-    /**
-     * Close Variable Browser
-     */
+    /** Close Variable Browser */
     public static void closeVariableBrowser() {
         ScilabVariableBrowser.closeVariableBrowser();
     }
index aa63288..00309b1 100644 (file)
@@ -19,16 +19,15 @@ import java.io.File;
 import java.util.Comparator;
 import java.util.TreeSet;
 import java.util.regex.Pattern;
-
 import javax.swing.Icon;
 import javax.swing.SortOrder;
-
 import org.scilab.modules.commons.CommonFileUtils;
 import org.scilab.modules.commons.ScilabConstants;
 import org.scilab.modules.ui_data.utils.UiDataMessages;
 
 /**
  * Handle a File as a node in the JTree
+ *
  * @author Calixte DENIZET
  */
 public class FileNode {
@@ -62,6 +61,7 @@ public class FileNode {
 
     /**
      * Default constructor
+     *
      * @param file the file in this node
      */
     public FileNode(File file, int position) {
@@ -89,16 +89,15 @@ public class FileNode {
         return position;
     }
 
-    /**
-     * @param pat the pattern to filter the files
-     */
+    /** @param pat the pattern to filter the files */
     public void setFilter(Pattern pat) {
         this.pat = pat;
         resetChildren();
     }
 
     /**
-     * @param order the order to use to sort the file. If order is positive, then ascending order is used.
+     * @param order the order to use to sort the file. If order is positive, then ascending order is
+     *     used.
      */
     public void setOrder(int order) {
         this.order = order;
@@ -139,15 +138,14 @@ public class FileNode {
         setOrder(sign * order);
     }
 
-    /**
-     * @return the used order
-     */
+    /** @return the used order */
     public SortOrder getOrder() {
         return order > 0 ? SortOrder.ASCENDING : SortOrder.DESCENDING;
     }
 
     /**
      * Sort a column according to the natural order for its.
+     *
      * @param nameColumn the column name
      */
     public void toggleSortOrder(String nameColumn) {
@@ -180,6 +178,7 @@ public class FileNode {
 
     /**
      * Sort the files
+     *
      * @param order the order to use
      * @param files the files to order
      * @return the ordered FileNodes
@@ -198,9 +197,7 @@ public class FileNode {
         }
     }
 
-    /**
-     * Returns the string to be used to display this leaf in the JTree.
-     */
+    /** Returns the string to be used to display this leaf in the JTree. */
     public String toString() {
         String name = file.getName();
         if (name.isEmpty()) {
@@ -209,37 +206,27 @@ public class FileNode {
         return name;
     }
 
-    /**
-     * @return the file associated with this node
-     */
+    /** @return the file associated with this node */
     public File getFile() {
         return file;
     }
 
-    /**
-     * @return true if this represents the user-home directory
-     */
+    /** @return true if this represents the user-home directory */
     public boolean isUserHome() {
         return userHome;
     }
 
-    /**
-     * @return true if this represents the SCI directory
-     */
+    /** @return true if this represents the SCI directory */
     public boolean isSCI() {
         return sci;
     }
 
-    /**
-     * @return the last modified time for this file
-     */
+    /** @return the last modified time for this file */
     public long getLastModified() {
         return lastModified;
     }
 
-    /**
-     * @return the icon associated with this file
-     */
+    /** @return the icon associated with this file */
     public Icon getIcon() {
         if (icon == null) {
             icon = FileUtils.getIconForFile(file);
@@ -248,16 +235,12 @@ public class FileNode {
         return icon;
     }
 
-    /**
-     * @return true if the file is not a directory or if it is an empty one
-     */
+    /** @return true if the file is not a directory or if it is an empty one */
     public boolean isLeaf() {
         return isEmpty;
     }
 
-    /**
-     * @return the number of files in the directory representated by this file
-     */
+    /** @return the number of files in the directory representated by this file */
     public int getChildrenCount() {
         if (!isEmpty) {
             synchronized (file) {
@@ -274,9 +257,7 @@ public class FileNode {
         return 0;
     }
 
-    /**
-     * @return the children FileNode of this FileNode
-     */
+    /** @return the children FileNode of this FileNode */
     protected Object[] getChildren() {
         if (children == null && !isEmpty) {
             children = listFiles();
@@ -285,6 +266,10 @@ public class FileNode {
         return children;
     }
 
+    public FileNode[] getRawChildren() {
+        return children;
+    }
+
     public FileNode[] listFiles() {
         String[] filesName = file.list();
         if (filesName != null) {
@@ -321,23 +306,18 @@ public class FileNode {
         return null;
     }
 
-    /**
-     * Reset children only
-     */
+    /** Reset children only */
     public void resetChildren() {
         children = null;
+        isEmpty = isFile || CommonFileUtils.isEmptyDirectory(file.getAbsolutePath()) == 1;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public boolean equals(Object o) {
         return (o instanceof FileNode) && ((FileNode) o).file.equals(file);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public int hashCode() {
         return file.hashCode();
     }
index 5a6463d..138bef2 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2011 - DIGITEO - Calixte DENIZET
+ * Copyright (C) 2020 - ESI Group - Clement DAVID
  *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
  *
  * along with this program.
  *
  */
-
 package org.scilab.modules.ui_data.filebrowser;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.nio.file.Watchable;
 import java.text.DecimalFormat;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.regex.Pattern;
-
+import java.util.stream.Collectors;
 import javax.swing.SwingWorker;
-
 import org.scilab.modules.ui_data.utils.UiDataMessages;
 
 /**
  * The tree table model abstract implementation
+ *
  * @author Calixte DENIZET
  */
-public class ScilabFileBrowserModel extends AbstractScilabTreeTableModel implements ScilabTreeTableModel {
+public class ScilabFileBrowserModel extends AbstractScilabTreeTableModel
+    implements ScilabTreeTableModel {
 
-    private static final String[] names = {UiDataMessages.NAME_COLUMN,
-                                           UiDataMessages.SIZE_COLUMN,
-                                           UiDataMessages.TYPE_COLUMN,
-                                           UiDataMessages.LASTMODIF_COLUMN
-                                          };
+    private static final String[] names = {
+        UiDataMessages.NAME_COLUMN, UiDataMessages.SIZE_COLUMN,
+        UiDataMessages.TYPE_COLUMN, UiDataMessages.LASTMODIF_COLUMN
+    };
 
-    private static final Class[] types = {ScilabTreeTableModel.class,
-                                          FileSize.class,
-                                          String.class,
-                                          Date.class
-                                         };
+    private static final Class[] types = {
+        ScilabTreeTableModel.class, FileSize.class, String.class, Date.class
+    };
 
     private static final FileSize MINUSONE = new FileSize(-1);
 
+    /** Will trigger a model update on file creation/deletion */
+    private final class DirWatcher extends SwingWorker<Void, Object[]> {
+
+        public DirWatcher(FileNode root) {
+            watchDirectories(new Object[] {root});
+        }
+
+        @Override
+        protected Void doInBackground() throws Exception {
+            for (; ; ) {
+                WatchKey key = watcher.take();
+                List<FileNode> treePath = new ArrayList<>();
+                FileNode fn = null;
+
+                // identify the associated file and publish for update on EDT
+                Watchable wa = key.watchable();
+                if (wa instanceof Path) {
+                    Path p = (Path) wa;
+                    Path r = ((FileNode) root).file.toPath().relativize(p);
+
+                    // reconstruct a TreePath
+                    treePath.add((FileNode) root);
+                    Iterator<Path> it = r.iterator();
+                    while (it.hasNext()) {
+                        Path name = it.next();
+                        FileNode[] children = (FileNode[]) treePath.get(treePath.size() - 1).getChildren();
+                        for (FileNode node : children) {
+                            if (node.name.equals(name.toString())) {
+                                treePath.add(node);
+                                break;
+                            }
+                        }
+                    }
+
+                    // in case of directory deletion, only reset the hierarchy up to an
+                    // existing directory
+                    treePath = treePath.stream().filter(n -> n.file.exists()).collect(Collectors.toList());
+                    if (treePath.isEmpty()) {
+                        // if the root is remove then cancel the watcher
+                        watcher.close();
+                        watcher = null;
+                        return null;
+                    }
+
+                    // retrieve the corresponding FileNode
+                    fn = treePath.get(treePath.size() - 1);
+
+                    // reset the children of the FileNode
+                    fn.resetChildren();
+                    Object[] children = fn.getChildren();
+
+                    // on directory creation, add them to the watch list
+                    watchDirectories(children);
+                }
+
+                // trigger a refresh on the EDT for the full treepath
+                publish(new Object[] {key, treePath.toArray()});
+            }
+        }
+
+        @Override
+        protected void process(List<Object[]> chunks) {
+            for (Object[] o : chunks) {
+                WatchKey key = (WatchKey) o[0];
+                Object[] path = (Object[]) o[1];
+
+                List<WatchEvent<?>> events = key.pollEvents();
+                if (events.isEmpty()) {
+                    continue;
+                }
+
+                // reinstall a watch on the directory
+                key.reset();
+
+                // reload part of the model
+                ScilabFileBrowserModel.this.fireTreeStructureChanged(this, path, null, null);
+            }
+        }
+
+        /**
+         * append directories to be watched
+         *
+         * @param children file list
+         */
+        public void watchDirectories(Object[] children) {
+            for (Object o : children) {
+                if (!(o instanceof FileNode)) {
+                    continue;
+                }
+                FileNode fn = (FileNode) o;
+                if (fn.isFile) {
+                    continue;
+                }
+                Path p = fn.file.toPath();
+                try {
+                    p.register(
+                        watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
+                } catch (IOException ex) {
+                    ex.printStackTrace();
+                    Logger.getLogger(SwingScilabTreeTable.class.getName()).log(Level.SEVERE, null, ex);
+                    cancel(false);
+                }
+            }
+        }
+    }
+
     private int order = 1;
     private String baseDir = "";
+    WatchService watcher;
+    private DirWatcher dirWatcher;
 
-    /**
-     * Default constructor
-     */
+    /** Default constructor */
     public ScilabFileBrowserModel() {
         super();
+
+        try {
+            // Setup watchers
+            watcher = FileSystems.getDefault().newWatchService();
+        } catch (IOException ex) {
+            Logger.getLogger(SwingScilabTreeTable.class.getName()).log(Level.SEVERE, null, ex);
+            watcher = null;
+        }
     }
 
     /**
      * Set the base directory
+     *
      * @param baseDir the base directory
      * @param stt the associated treetable component
      */
     public void setBaseDir(final String baseDir, final SwingScilabTreeTable stt) {
         this.baseDir = baseDir;
-        SwingWorker worker = new SwingWorker<Void, Void>() {
+        SwingWorker worker =
+        new SwingWorker<Void, Void>() {
             protected Void doInBackground() throws Exception {
                 File f = new File(baseDir);
                 setRoot(new FileNode(f, -1));
@@ -89,19 +216,35 @@ public class ScilabFileBrowserModel extends AbstractScilabTreeTableModel impleme
     public void setRoot(Object root) {
         super.setRoot(root);
 
-        // Force the root to load its children in the SwingWorker thread rather than in EDT
-        ((FileNode) root).getChildrenCount();
+        // watch for changes
+        if (watcher != null) {
+            if (dirWatcher != null) {
+                dirWatcher.cancel(true);
+            }
+            dirWatcher = new DirWatcher((FileNode) root);
+            dirWatcher.execute();
+        }
+
+        // Force the root to load its children in the SwingWorker thread rather than in
+        // EDT
+        watchDirectories(((FileNode) root).getChildren());
     }
 
-    /**
-     * @return the base directory of this model
-     */
+    Object[] watchDirectories(Object[] objects) {
+        if (watcher != null && dirWatcher != null && objects != null) {
+            dirWatcher.watchDirectories(objects);
+        }
+        return objects;
+    }
+
+    /** @return the base directory of this model */
     public String getBaseDir() {
         return baseDir;
     }
 
     /**
      * Set the filter pattern
+     *
      * @pat the pattern
      */
     public void setFilter(Pattern pat) {
@@ -123,7 +266,12 @@ public class ScilabFileBrowserModel extends AbstractScilabTreeTableModel impleme
      */
     protected Object[] getChildren(Object node) {
         FileNode fileNode = (FileNode) node;
-        return fileNode.getChildren();
+        FileNode[] raw = fileNode.getRawChildren();
+        if (raw == null) {
+            return watchDirectories(fileNode.getChildren());
+        } else {
+            return fileNode.getChildren();
+        }
     }
 
     /**
@@ -131,7 +279,12 @@ public class ScilabFileBrowserModel extends AbstractScilabTreeTableModel impleme
      * @return the number of children of this node
      */
     public int getChildCount(Object node) {
-        int count = ((FileNode) node).getChildrenCount();
+        Object[] children = getChildren(node);
+        int count = 0;
+        if (children != null) {
+            count = children.length;
+        }
+
         if (parent == null || node != getRoot()) {
             return count;
         }
@@ -170,31 +323,24 @@ public class ScilabFileBrowserModel extends AbstractScilabTreeTableModel impleme
         return node != getRoot() && ((FileNode) node).isLeaf();
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public int getColumnCount() {
-        // TODO : remove the comment and let the choice to the user to remove or not the columns
-        return 1;//names.length;
+        // TODO : remove the comment and let the choice to the user to remove or not the
+        // columns
+        return 1; // names.length;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public String getColumnName(int column) {
         return names[column];
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public Class getColumnClass(int column) {
         return types[column];
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public Object getValueAt(Object node, int column) {
         File file = getFile(node);
         try {
@@ -217,41 +363,32 @@ public class ScilabFileBrowserModel extends AbstractScilabTreeTableModel impleme
                 case 3:
                     return new Date(file.lastModified());
             }
-        } catch (SecurityException se) { }
+        } catch (SecurityException se) {
+        }
 
         return null;
     }
 
-    /**
-     * Inner class to represent the parent node of a file node
-     */
+    /** Inner class to represent the parent node of a file node */
     public static class ParentNode extends FileNode {
 
-        /**
-         * {@inheritDoc}
-         */
+        /** {@inheritDoc} */
         public ParentNode(File f) {
             super(f, -1);
         }
 
-        /**
-         * {@inheritDoc}
-         */
+        /** {@inheritDoc} */
         public boolean isLeaf() {
             return true;
         }
 
-        /**
-         * {@inheritDoc}
-         */
+        /** {@inheritDoc} */
         public String toString() {
             return "..";
         }
     }
 
-    /**
-     * Inner class to represent the size of file
-     */
+    /** Inner class to represent the size of file */
     public static class FileSize {
 
         int size;
index 1a46133..a1b1081 100644 (file)
 
 package org.scilab.modules.ui_data.filebrowser;
 
-import javax.swing.table.AbstractTableModel;
 import javax.swing.JTree;
-import javax.swing.tree.TreePath;
 import javax.swing.event.TreeExpansionEvent;
 import javax.swing.event.TreeExpansionListener;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.tree.TreePath;
 
 /**
  * The tree table model abstract implementation
+ *
  * @author Calixte DENIZET
  */
-@SuppressWarnings(value = { "serial" })
+@SuppressWarnings(value = {"serial"})
 public class ScilabTreeTableModelAdapter extends AbstractTableModel {
 
     private JTree tree;
@@ -33,75 +36,86 @@ public class ScilabTreeTableModelAdapter extends AbstractTableModel {
 
     /**
      * Default constructor
+     *
      * @param treeTableModel the table model
      * @param tree the tree
      */
     public ScilabTreeTableModelAdapter(ScilabTreeTableModel treeTableModel, JTree tree) {
         this.tree = tree;
         this.treeTableModel = treeTableModel;
-        tree.addTreeExpansionListener(new TreeExpansionListener() {
+        tree.addTreeExpansionListener(
+        new TreeExpansionListener() {
             public void treeExpanded(TreeExpansionEvent event) {
                 fireTableDataChanged();
             }
+
             public void treeCollapsed(TreeExpansionEvent event) {
                 fireTableDataChanged();
             }
         });
+        tree.getModel()
+        .addTreeModelListener(
+        new TreeModelListener() {
+
+            @Override
+            public void treeStructureChanged(TreeModelEvent e) {
+                fireTableDataChanged();
+            }
+
+            @Override
+            public void treeNodesRemoved(TreeModelEvent e) {
+                fireTableDataChanged();
+            }
+
+            @Override
+            public void treeNodesInserted(TreeModelEvent e) {
+                fireTableDataChanged();
+            }
+
+            @Override
+            public void treeNodesChanged(TreeModelEvent e) {
+                fireTableDataChanged();
+            }
+        });
     }
 
-    /**
-     * {@inheritdoc}
-     */
+    /** {@inheritdoc} */
     public int getColumnCount() {
         return treeTableModel.getColumnCount();
     }
 
-    /**
-     * {@inheritdoc}
-     */
+    /** {@inheritdoc} */
     public String getColumnName(int column) {
         return treeTableModel.getColumnName(column);
     }
 
-    /**
-     * {@inheritdoc}
-     */
+    /** {@inheritdoc} */
     public Class getColumnClass(int column) {
         return treeTableModel.getColumnClass(column);
     }
 
-    /**
-     * {@inheritdoc}
-     */
+    /** {@inheritdoc} */
     public int getRowCount() {
         return tree.getRowCount();
     }
 
-    /**
-     * {@inheritdoc}
-     */
+    /** {@inheritdoc} */
     protected Object nodeForRow(int row) {
         TreePath treePath = tree.getPathForRow(row);
         return treePath.getLastPathComponent();
     }
 
-    /**
-     * {@inheritdoc}
-     */
+    /** {@inheritdoc} */
     public Object getValueAt(int row, int column) {
         return treeTableModel.getValueAt(nodeForRow(row), column);
     }
 
-    /**
-     * {@inheritdoc}
-     */
+    /** {@inheritdoc} */
     public boolean isCellEditable(int row, int column) {
         return treeTableModel.isCellEditable(nodeForRow(row), column);
     }
 
-    /**
-     * {@inheritdoc}
-     */
+    /** {@inheritdoc} */
     public void setValueAt(Object value, int row, int column) {
         treeTableModel.setValueAt(value, nodeForRow(row), column);
     }
index 9810ba6..10a3c46 100644 (file)
@@ -31,7 +31,6 @@ import java.lang.reflect.Method;
 import java.text.DateFormat;
 import java.util.Date;
 import java.util.regex.Pattern;
-
 import javax.swing.ActionMap;
 import javax.swing.ImageIcon;
 import javax.swing.InputMap;
@@ -43,13 +42,12 @@ import javax.swing.JScrollPane;
 import javax.swing.JTable;
 import javax.swing.KeyStroke;
 import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
 import javax.swing.border.AbstractBorder;
 import javax.swing.border.Border;
 import javax.swing.plaf.basic.BasicTreeUI;
 import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.SwingWorker;
 import javax.swing.tree.TreePath;
-
 import org.scilab.modules.commons.gui.FindIconHelper;
 import org.scilab.modules.gui.events.callback.CommonCallBack;
 import org.scilab.modules.ui_data.filebrowser.actions.ChangeCWDAction;
@@ -66,15 +64,18 @@ import org.scilab.modules.ui_data.utils.UiDataMessages;
 
 /**
  * The tree table model abstract implementation
+ *
  * @author Calixte DENIZET
  */
-@SuppressWarnings(value = { "serial" })
+@SuppressWarnings(value = {"serial"})
 public class SwingScilabTreeTable extends JTable {
 
     private static final Insets INSETS = new Insets(0, 2, 0, 0);
-    private static final DateFormat DATEFORMAT = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
+    private static final DateFormat DATEFORMAT =
+        DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
 
-    private static final Border BORDER = new AbstractBorder() {
+    private static final Border BORDER =
+    new AbstractBorder() {
         public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
             g.setColor(Color.LIGHT_GRAY);
             g.drawLine(x, y, x, y + height);
@@ -91,20 +92,21 @@ public class SwingScilabTreeTable extends JTable {
 
     private SwingWorker dirRefresher;
     private ScilabFileBrowserModel model;
-    private boolean resetScrollBar = true;
 
     private Method isLocationInExpandControl;
 
     protected ScilabTreeTableCellRenderer tree;
     protected ScilabFileSelectorComboBox combobox;
     protected ScilabFileBrowserHistory history;
-    
+
     /**
      * Default Constructor
+     *
      * @param treeTableModel the tree table model
      * @param combobox the combox used to set the path
      */
-    public SwingScilabTreeTable(ScilabTreeTableModel treeTableModel, ScilabFileSelectorComboBox combobox) {
+    public SwingScilabTreeTable(
+        ScilabTreeTableModel treeTableModel, ScilabFileSelectorComboBox combobox) {
         super();
         this.combobox = combobox;
         combobox.setTreeTable(this);
@@ -114,13 +116,18 @@ public class SwingScilabTreeTable extends JTable {
 
         // Install the tree editor renderer and editor.
         setDefaultRenderer(ScilabTreeTableModel.class, tree);
-        setDefaultRenderer(Date.class, new DefaultTableCellRenderer() {
+        setDefaultRenderer(
+            Date.class,
+        new DefaultTableCellRenderer() {
             {
                 setHorizontalTextPosition(DefaultTableCellRenderer.LEFT);
             }
 
-            public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focus, int row, int col) {
-                JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, selected, focus, row, col);
+            public Component getTableCellRendererComponent(
+                JTable table, Object value, boolean selected, boolean focus, int row, int col) {
+                JLabel label =
+                    (JLabel)
+                    super.getTableCellRendererComponent(table, value, selected, focus, row, col);
                 label.setText(DATEFORMAT.format((Date) value));
                 if (col == 1) {
                     label.setBorder(BORDER);
@@ -128,13 +135,17 @@ public class SwingScilabTreeTable extends JTable {
                 return label;
             }
         });
-        setDefaultRenderer(ScilabFileBrowserModel.FileSize.class, new DefaultTableCellRenderer() {
+        setDefaultRenderer(
+            ScilabFileBrowserModel.FileSize.class,
+        new DefaultTableCellRenderer() {
             {
                 setHorizontalTextPosition(DefaultTableCellRenderer.LEFT);
             }
 
-            public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focus, int row, int col) {
-                Component c = super.getTableCellRendererComponent(table, value, selected, focus, row, col);
+            public Component getTableCellRendererComponent(
+                JTable table, Object value, boolean selected, boolean focus, int row, int col) {
+                Component c =
+                    super.getTableCellRendererComponent(table, value, selected, focus, row, col);
                 if (col == 1) {
                     JLabel jl = (JLabel) c;
                     jl.setBorder(BORDER);
@@ -142,13 +153,17 @@ public class SwingScilabTreeTable extends JTable {
                 return c;
             }
         });
-        setDefaultRenderer(String.class, new DefaultTableCellRenderer() {
+        setDefaultRenderer(
+            String.class,
+        new DefaultTableCellRenderer() {
             {
                 setHorizontalTextPosition(DefaultTableCellRenderer.LEFT);
             }
 
-            public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focus, int row, int col) {
-                Component c = super.getTableCellRendererComponent(table, value, selected, focus, row, col);
+            public Component getTableCellRendererComponent(
+                JTable table, Object value, boolean selected, boolean focus, int row, int col) {
+                Component c =
+                    super.getTableCellRendererComponent(table, value, selected, focus, row, col);
                 if (col == 1) {
                     JLabel jl = (JLabel) c;
                     jl.setBorder(BORDER);
@@ -164,33 +179,53 @@ public class SwingScilabTreeTable extends JTable {
         setAutoResizeMode(AUTO_RESIZE_NEXT_COLUMN);
 
         try {
-            isLocationInExpandControl = BasicTreeUI.class.getDeclaredMethod("isLocationInExpandControl", new Class[] {TreePath.class, int.class, int.class});
+            isLocationInExpandControl =
+                BasicTreeUI.class.getDeclaredMethod(
+                    "isLocationInExpandControl", new Class[] {TreePath.class, int.class, int.class});
             isLocationInExpandControl.setAccessible(true);
-        } catch (NoSuchMethodException e) { }
+        } catch (NoSuchMethodException e) {
+        }
 
-        addMouseListener(new MouseAdapter() {
+        addMouseListener(
+        new MouseAdapter() {
             public void mousePressed(MouseEvent e) {
                 Point p = e.getPoint();
                 int col = columnAtPoint(p);
-                if (getColumnClass(col) == ScilabTreeTableModel.class && SwingUtilities.isLeftMouseButton(e)) {
+                if (getColumnClass(col) == ScilabTreeTableModel.class
+                        && SwingUtilities.isLeftMouseButton(e)) {
                     MouseEvent me = e;
                     if (isLocationInExpandControl != null) {
                         try {
                             int row = rowAtPoint(p);
                             TreePath path = tree.getPathForRow(row);
-                            boolean isOnExpander = ((Boolean) isLocationInExpandControl.invoke(tree.getUI(), path, e.getX(), e.getY())).booleanValue();
+                            boolean isOnExpander =
+                                ((Boolean)
+                                 isLocationInExpandControl.invoke(
+                                     tree.getUI(), path, e.getX(), e.getY()))
+                                .booleanValue();
                             Rectangle r = tree.getRowBounds(row);
                             if (!isOnExpander && !r.contains(p)) {
-                                me = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers(), r.x, r.y, e.getClickCount(), e.isPopupTrigger());
+                                me =
+                                    new MouseEvent(
+                                    (Component) e.getSource(),
+                                    e.getID(),
+                                    e.getWhen(),
+                                    e.getModifiers(),
+                                    r.x,
+                                    r.y,
+                                    e.getClickCount(),
+                                    e.isPopupTrigger());
                             }
-                        } catch (Exception ex) { }
+                        } catch (Exception ex) {
+                        }
                     }
                     tree.dispatchEvent(me);
                 }
             }
         });
 
-        addKeyListener(new KeyAdapter() {
+        addKeyListener(
+        new KeyAdapter() {
             public void keyTyped(KeyEvent e) {
                 char c = e.getKeyChar();
                 if (Character.isLetter(c)) {
@@ -206,7 +241,8 @@ public class SwingScilabTreeTable extends JTable {
                         start = modulo(rows[0] + step, count);
                     }
                     for (int i = start; i != start - step; i = modulo(i + step, count)) {
-                        char first = ((FileNode) tree.getPathForRow(i).getLastPathComponent()).toString().charAt(0);
+                        char first =
+                            ((FileNode) tree.getPathForRow(i).getLastPathComponent()).toString().charAt(0);
                         first = Character.toLowerCase(first);
                         if (first == c) {
                             scrollRectToVisible(tree.getRowBounds(i));
@@ -218,34 +254,28 @@ public class SwingScilabTreeTable extends JTable {
             }
         });
 
-
         initActions();
         setComponentPopupMenu(createPopup());
     }
 
-    /**
-     * @return the Next button used in history
-     */
+    /** @return the Next button used in history */
     public JButton getNextButton() {
         return history.getNextButton();
     }
 
-    /**
-     * @return the Previous button used in history
-     */
+    /** @return the Previous button used in history */
     public JButton getPreviousButton() {
         return history.getPreviousButton();
     }
 
-    /**
-     * @return the combobox used to set the path
-     */
+    /** @return the combobox used to set the path */
     public ScilabFileSelectorComboBox getComboBox() {
         return combobox;
     }
 
     /**
      * Get the selected rows as file path
+     *
      * @return the paths
      */
     public String[] getSelectedPaths() {
@@ -262,6 +292,7 @@ public class SwingScilabTreeTable extends JTable {
 
     /**
      * Get the selected rows as file
+     *
      * @return the paths
      */
     public File[] getSelectedFiles() {
@@ -276,22 +307,19 @@ public class SwingScilabTreeTable extends JTable {
         return files;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public int getRowHeight(int row) {
         return getRowHeight();
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public boolean isOpaque() {
         return false;
     }
 
     /**
      * Set the base directory
+     *
      * @param baseDir the base directory
      */
     public void setBaseDir(String baseDir) {
@@ -300,6 +328,7 @@ public class SwingScilabTreeTable extends JTable {
 
     /**
      * Set the base directory
+     *
      * @param baseDir the base directory
      * @param addInHistory if true the dir is add in the history
      */
@@ -317,14 +346,13 @@ public class SwingScilabTreeTable extends JTable {
         }
         combobox.setBaseDir(baseDir);
         if (model != null) {
+            boolean sameDir = baseDir.equals(model.getBaseDir());
             File f = new File(baseDir);
-            if (cancelled || (f.exists() && f.isDirectory() && f.canRead())) {
-                boolean sameDir = baseDir.equals(model.getBaseDir());
+            if (cancelled || (!sameDir && f.exists() && f.isDirectory() && f.canRead())) {
                 tree.setModel(null);
-                if (!sameDir && addInHistory) {
+                if (addInHistory) {
                     history.addPathInHistory(baseDir);
                 }
-                resetScrollBar = !sameDir;
                 model.setBaseDir(baseDir, this);
             }
         }
@@ -332,6 +360,7 @@ public class SwingScilabTreeTable extends JTable {
 
     /**
      * Set the file filter to use in table
+     *
      * @param pat the pattern to use
      */
     public void setFilter(Pattern pat) {
@@ -342,19 +371,16 @@ public class SwingScilabTreeTable extends JTable {
         reload(model);
     }
 
-    /**
-     * Reload the table
-     */
+    /** Reload the table */
     public void reload(ScilabFileBrowserModel model) {
         tree.setModel(model);
         tree.setRowHeight(getRowHeight());
         tree.setLargeModel(true);
         TreePath path = new TreePath(model.getRoot());
         tree.collapsePath(path);
-        if (resetScrollBar) {
-            ((JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this)).getVerticalScrollBar().setValue(0);
-        }
-        resetScrollBar = true;
+        ((JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this))
+        .getVerticalScrollBar()
+        .setValue(0);
         tree.expandPath(path);
         if (getRowCount() >= 1) {
             repaint(tree.getRowBounds(0));
@@ -362,11 +388,12 @@ public class SwingScilabTreeTable extends JTable {
         editingRow = 0;
     }
 
-    /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to
-     * paint the editor. The UI currently uses different techniques to
-     * paint the renderers and editors and overriding setBounds() below
-     * is not the right thing to do for an editor. Returning -1 for the
-     * editing row in this case, ensures the editor is never painted.
+    /*
+     * Workaround for BasicTableUI anomaly. Make sure the UI never tries to paint
+     * the editor. The UI currently uses different techniques to paint the renderers
+     * and editors and overriding setBounds() below is not the right thing to do for
+     * an editor. Returning -1 for the editing row in this case, ensures the editor
+     * is never painted.
      */
     public int getEditingRow() {
         if (getColumnClass(editingColumn) == ScilabTreeTableModel.class) {
@@ -376,9 +403,7 @@ public class SwingScilabTreeTable extends JTable {
         }
     }
 
-    /**
-     * Init the actions
-     */
+    /** Init the actions */
     private void initActions() {
         final ActionMap actions = getActionMap();
         actions.put("scinotes", new OpenFileInSciNotesAction(this));
@@ -395,7 +420,9 @@ public class SwingScilabTreeTable extends JTable {
             actions.put("open", new OpenFileWithDefaultAppAction(this));
         }
         actions.put("validate", new ValidateAction(this));
-        actions.put("validateorexpand", new CommonCallBack(null) {
+        actions.put(
+            "validateorexpand",
+        new CommonCallBack(null) {
             public void callBack() {
                 int[] rows = getSelectedRows();
                 if (rows != null && rows.length != 0) {
@@ -420,9 +447,7 @@ public class SwingScilabTreeTable extends JTable {
         map.put(KeyStroke.getKeyStroke("ENTER"), "validateorexpand");
     }
 
-    /**
-     * Create the popup menu
-     */
+    /** Create the popup menu */
     private JPopupMenu createPopup() {
         ActionMap actions = getActionMap();
         JPopupMenu popup = new JPopupMenu();
@@ -467,7 +492,6 @@ public class SwingScilabTreeTable extends JTable {
         return popup;
     }
 
-
     public synchronized void setDirRefresher(SwingWorker refresher, ScilabFileBrowserModel model) {
         dirRefresher = refresher;
         this.model = model;
@@ -475,6 +499,7 @@ public class SwingScilabTreeTable extends JTable {
 
     /**
      * A modulo for negative numbers
+     *
      * @param n an int
      * @param p another int
      * @return n modulo p
@@ -485,5 +510,4 @@ public class SwingScilabTreeTable extends JTable {
         }
         return p - (-n % p);
     }
-
 }