From f9aa6d22522d85b53035f800ca697bca8c29e3cc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Cl=C3=A9ment=20DAVID?= Date: Fri, 19 Jun 2020 12:03:07 +0200 Subject: [PATCH] * Bug 11852 fixed: now filebrowser updates (again) 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 --- .../java/org/scilab/modules/ui_data/BrowseVar.java | 115 +++++---- .../modules/ui_data/filebrowser/FileNode.java | 70 ++---- .../filebrowser/ScilabFileBrowserModel.java | 247 +++++++++++++++----- .../filebrowser/ScilabTreeTableModelAdapter.java | 70 +++--- .../ui_data/filebrowser/SwingScilabTreeTable.java | 160 +++++++------ 5 files changed, 417 insertions(+), 245 deletions(-) diff --git a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/BrowseVar.java b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/BrowseVar.java index 98d94cb..b9cb61b 100644 --- a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/BrowseVar.java +++ b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/BrowseVar.java @@ -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(); } diff --git a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/FileNode.java b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/FileNode.java index aa63288..00309b1 100644 --- a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/FileNode.java +++ b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/FileNode.java @@ -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(); } diff --git a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabFileBrowserModel.java b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabFileBrowserModel.java index 5a6463d..138bef2 100644 --- a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabFileBrowserModel.java +++ b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabFileBrowserModel.java @@ -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 * @@ -12,56 +13,182 @@ * 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 { + + public DirWatcher(FileNode root) { + watchDirectories(new Object[] {root}); + } + + @Override + protected Void doInBackground() throws Exception { + for (; ; ) { + WatchKey key = watcher.take(); + List 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 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 chunks) { + for (Object[] o : chunks) { + WatchKey key = (WatchKey) o[0]; + Object[] path = (Object[]) o[1]; + + List> 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() { + SwingWorker worker = + new SwingWorker() { 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; diff --git a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabTreeTableModelAdapter.java b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabTreeTableModelAdapter.java index 1a46133..a1b1081 100644 --- a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabTreeTableModelAdapter.java +++ b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/ScilabTreeTableModelAdapter.java @@ -15,17 +15,20 @@ 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); } diff --git a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/SwingScilabTreeTable.java b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/SwingScilabTreeTable.java index 9810ba6..10a3c46 100644 --- a/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/SwingScilabTreeTable.java +++ b/scilab/modules/ui_data/src/java/org/scilab/modules/ui_data/filebrowser/SwingScilabTreeTable.java @@ -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); } - } -- 1.7.9.5