From 3eb4edc44869e2731dfdbe7018c8b9857072232f Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Fri, 24 Apr 2020 17:42:43 +0200 Subject: [PATCH] remove now duplicated utils from fanfix-swing (now in nikiroo-utils) --- .../fanfix_swing/gui/utils/DelayWorker.java | 220 --- .../fanfix_swing/gui/utils/ListModel.java | 393 ------ .../fanfix_swing/gui/utils/ListenerPanel.java | 101 -- .../gui/utils/TreeCellSpanner.java | 169 --- .../gui/utils/TreeModelTransformer.java | 1217 ----------------- .../fanfix_swing/gui/utils/TreeSnapshot.java | 127 -- .../fanfix_swing/gui/utils/UiHelper.java | 11 - 7 files changed, 2238 deletions(-) delete mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/DelayWorker.java delete mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/ListModel.java delete mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/ListenerPanel.java delete mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/TreeCellSpanner.java delete mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/TreeModelTransformer.java delete mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/TreeSnapshot.java diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/DelayWorker.java b/src/be/nikiroo/fanfix_swing/gui/utils/DelayWorker.java deleted file mode 100644 index 6d630c5d..00000000 --- a/src/be/nikiroo/fanfix_swing/gui/utils/DelayWorker.java +++ /dev/null @@ -1,220 +0,0 @@ -package be.nikiroo.fanfix_swing.gui.utils; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.TreeSet; - -import javax.swing.SwingWorker; - -/** - * This class helps you delay some graphical actions and execute the most recent - * ones when under contention. - *

- * How does it work? - *

- * - * @author niki - * - */ -@SuppressWarnings("rawtypes") -public class DelayWorker { - private Map lazyEnCours; - private Object lazyEnCoursLock; - - private TreeSet wip; - - private Object waiter; - - private boolean cont; - private boolean paused; - private Thread loop; - - /** - * Create a new {@link DelayWorker} with the given delay (in milliseconds) - * before each drain of the queue. - * - * @param delayMs - * the delay in milliseconds (can be 0, cannot be negative) - */ - public DelayWorker(final int delayMs) { - if (delayMs < 0) { - throw new IllegalArgumentException( - "A waiting delay cannot be negative"); - } - - lazyEnCours = new HashMap(); - lazyEnCoursLock = new Object(); - wip = new TreeSet(); - waiter = new Object(); - cont = true; - paused = false; - - loop = new Thread(new Runnable() { - @Override - public void run() { - while (cont) { - try { - Thread.sleep(delayMs); - } catch (InterruptedException e) { - } - - Map workers = new HashMap(); - synchronized (lazyEnCoursLock) { - for (String key : new ArrayList( - lazyEnCours.keySet())) { - if (!wip.contains(key)) { - workers.put(key, lazyEnCours.remove(key)); - } - } - } - - for (final String key : workers.keySet()) { - SwingWorker worker = workers.get(key); - - synchronized (lazyEnCoursLock) { - wip.add(key); - } - - worker.addPropertyChangeListener( - new PropertyChangeListener() { - @Override - public void propertyChange( - PropertyChangeEvent evt) { - synchronized (lazyEnCoursLock) { - wip.remove(key); - } - wakeup(); - } - }); - - // Start it, at last - worker.execute(); - } - - synchronized (waiter) { - do { - try { - if (cont) - waiter.wait(); - } catch (InterruptedException e) { - } - } while (cont && paused); - } - } - } - }); - - loop.setDaemon(true); - loop.setName("Loop for DelayWorker"); - } - - /** - * Start the internal loop that will drain the processing queue. MUST - * NOT be started twice (but see {@link DelayWorker#pause()} and - * {@link DelayWorker#resume()} instead). - */ - public void start() { - loop.start(); - } - - /** - * Pause the system until {@link DelayWorker#resume()} is called -- note - * that it will still continue on the processes currently scheduled to run, - * but will pause after that. - *

- * Can be called even if already paused, will just do nothing in that - * context. - */ - public void pause() { - paused = true; - } - - /** - * Check if the {@link DelayWorker} is currently paused. - * - * @return TRUE if it is - */ - public boolean isPaused() { - return paused; - } - - /** - * Resume the system after a pause. - *

- * Can be called even if already running, will just do nothing in that - * context. - */ - public void resume() { - synchronized (waiter) { - paused = false; - wakeup(); - } - } - - /** - * Stop the system. - *

- * Note: this is final, you MUST NOT call {@link DelayWorker#start()} - * a second time (but see {@link DelayWorker#pause()} and - * {@link DelayWorker#resume()} instead). - */ - public void stop() { - synchronized (waiter) { - cont = false; - wakeup(); - } - } - - /** - * Clear all the processes that were put on the queue but not yet scheduled - * to be executed -- note that it will still continue on the processes - * currently scheduled to run. - */ - public void clear() { - synchronized (lazyEnCoursLock) { - lazyEnCours.clear(); - wip.clear(); - } - } - - /** - * Put a new process in the delay queue. - * - * @param id - * the ID of this process (if you want to skip workers when they - * are superseded by a new one, you need to use the same ID key) - * @param worker - * the process to delay - */ - public void delay(final String id, final SwingWorker worker) { - synchronized (lazyEnCoursLock) { - lazyEnCours.put(id, worker); - } - - wakeup(); - } - - /** - * Wake up the loop thread. - */ - private void wakeup() { - synchronized (waiter) { - waiter.notifyAll(); - } - } -} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/ListModel.java b/src/be/nikiroo/fanfix_swing/gui/utils/ListModel.java deleted file mode 100644 index 6f9c1961..00000000 --- a/src/be/nikiroo/fanfix_swing/gui/utils/ListModel.java +++ /dev/null @@ -1,393 +0,0 @@ -package be.nikiroo.fanfix_swing.gui.utils; - -import java.awt.Component; -import java.awt.Point; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import javax.swing.JList; -import javax.swing.JPopupMenu; -import javax.swing.ListCellRenderer; - -import be.nikiroo.utils.compat.DefaultListModel6; -import be.nikiroo.utils.compat.JList6; -import be.nikiroo.utils.compat.ListCellRenderer6; - -/** - * A {@link javax.swing.ListModel} that can maintain 2 lists; one with the - * actual data (the elements), and a second one with the items that are - * currently displayed (the items). - *

- * It also offers filter options, supports hovered changes and some more utility - * functions. - * - * @author niki - * - * @param - * the type of elements and items (the same type) - */ -public class ListModel extends DefaultListModel6 { - private static final long serialVersionUID = 1L; - - /** - * A filter interface, to check for a condition (note that a Predicate class - * already exists in Java 1.8+, and is compatible with this one if you - * change the signatures -- but I support java 1.6+). - * - * @author niki - * - * @param - * the type of elements and items (the same type) - */ - public interface Predicate { - /** - * Check if an item or an element pass a filter. - * - * @param item - * the item to test - * - * @return TRUE if the test passed, FALSE if not - */ - public boolean test(T item); - } - - /** - * A simple interface your elements must implement if you want to use - * {@link ListModel#generateRenderer(ListModel)}. - * - * @author niki - */ - public interface Hoverable { - /** - * The element is currently selected. - * - * @param selected - * TRUE for selected, FALSE for unselected - */ - public void setSelected(boolean selected); - - /** - * The element is currently under the mouse cursor. - * - * @param hovered - * TRUE if it is, FALSE if not - */ - public void setHovered(boolean hovered); - } - - private int hoveredIndex; - private List items = new ArrayList(); - private JList6 list; - - /** - * Create a new {@link ListModel}. - * - * @param list - * the {@link JList} we will handle the data of (cannot be NULL) - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) // not compatible Java 1.6 - public ListModel(JList list) { - this((JList6) list); - } - - /** - * Create a new {@link ListModel}. - * - * @param list - * the {@link JList} we will handle the data of (cannot be NULL) - * @param popup - * the popup to use and keep track of (can be NULL) - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) // not compatible Java 1.6 - public ListModel(final JList list, final JPopupMenu popup) { - this((JList6) list, popup); - } - - /** - * Create a new {@link ListModel}. - * - * @param list - * the {@link JList6} we will handle the data of (cannot be NULL) - */ - public ListModel(JList6 list) { - this(list, null); - } - - /** - * Create a new {@link ListModel}. - * - * @param list - * the {@link JList6} we will handle the data of (cannot be NULL) - * @param popup - * the popup to use and keep track of (can be NULL) - */ - public ListModel(final JList6 list, final JPopupMenu popup) { - this.list = list; - list.setModel(this); - - list.addMouseMotionListener(new MouseAdapter() { - @Override - public void mouseMoved(MouseEvent me) { - if (popup != null && popup.isShowing()) - return; - - Point p = new Point(me.getX(), me.getY()); - int index = list.locationToIndex(p); - if (index != hoveredIndex) { - int oldIndex = hoveredIndex; - hoveredIndex = index; - fireElementChanged(oldIndex); - fireElementChanged(index); - } - } - }); - - list.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - check(e); - } - - @Override - public void mouseReleased(MouseEvent e) { - check(e); - } - - @Override - public void mouseExited(MouseEvent e) { - if (popup != null && popup.isShowing()) - return; - - if (hoveredIndex > -1) { - int oldIndex = hoveredIndex; - hoveredIndex = -1; - fireElementChanged(oldIndex); - } - } - - private void check(MouseEvent e) { - if (popup == null) { - return; - } - - if (e.isPopupTrigger()) { - if (list.getSelectedIndices().length <= 1) { - list.setSelectedIndex( - list.locationToIndex(e.getPoint())); - } - - popup.show(list, e.getX(), e.getY()); - } - } - }); - } - - /** - * Check if this element is currently under the mouse. - * - * @param element - * the element to check - * - * @return TRUE if it is - */ - public boolean isHovered(T element) { - return indexOf(element) == hoveredIndex; - } - - /** - * Check if this element is currently under the mouse. - * - * @param index - * the index of the element to check - * - * @return TRUE if it is - */ - public boolean isHovered(int index) { - return index == hoveredIndex; - } - - /** - * Add an item to the model. - * - * @param item - * the new item to add - */ - public void addItem(T item) { - items.add(item); - } - - /** - * Add items to the model. - * - * @param items - * the new items to add - */ - public void addAllItems(Collection items) { - this.items.addAll(items); - } - - /** - * Removes the first occurrence of the specified element from this list, if - * it is present (optional operation). - * - * @param item - * the item to remove if possible (can be NULL) - * - * @return TRUE if one element was removed, FALSE if not found - */ - public boolean removeItem(T item) { - return items.remove(item); - } - - /** - * Remove the items that pass the given filter (or all items if the filter - * is NULL). - * - * @param filter - * the filter (if the filter returns TRUE, the item will be - * removed) - * - * @return TRUE if at least one item was removed - */ - public boolean removeItemIf(Predicate filter) { - boolean changed = false; - if (filter == null) { - changed = !items.isEmpty(); - clearItems(); - } else { - for (int i = 0; i < items.size(); i++) { - if (filter.test(items.get(i))) { - items.remove(i--); - changed = true; - } - } - } - - return changed; - } - - /** - * Removes all the items from this model. - */ - public void clearItems() { - items.clear(); - } - - /** - * Filter the current elements. - *

- * This method will clear all the elements then look into all the items: - * those that pass the given filter will be copied as elements. - * - * @param filter - * the filter to select which elements to keep; an item that pass - * the filter will be copied as an element (can be NULL, in that - * case all items will be copied as elements) - */ - @SuppressWarnings("unchecked") // ListModel and JList are not java 1.6 - public void filter(Predicate filter) { - clear(); - for (T item : items) { - if (filter == null || filter.test(item)) { - addElement(item); - } - } - - list.repaint(); - } - - /** - * Return the currently selected elements. - * - * @return the selected elements - */ - public List getSelectedElements() { - List selected = new ArrayList(); - for (int index : list.getSelectedIndices()) { - selected.add(get(index)); - } - - return selected; - } - - /** - * Return the selected element if one and only one element is - * selected. I.E., if zero, two or more elements are selected, NULL will be - * returned. - * - * @return the element if it is the only selected element, NULL otherwise - */ - public T getUniqueSelectedElement() { - List selected = getSelectedElements(); - if (selected.size() == 1) { - return selected.get(0); - } - - return null; - } - - /** - * Notify that this element has been changed. - * - * @param index - * the index of the element - */ - public void fireElementChanged(int index) { - if (index >= 0) { - fireContentsChanged(this, index, index); - } - } - - /** - * Notify that this element has been changed. - * - * @param element - * the element - */ - public void fireElementChanged(T element) { - int index = indexOf(element); - if (index >= 0) { - fireContentsChanged(this, index, index); - } - } - - @SuppressWarnings("unchecked") // ListModel and JList are not java 1.6 - @Override - public T get(int index) { - return (T) super.get(index); - } - - /** - * Generate a {@link ListCellRenderer} that supports {@link Hoverable} - * elements. - * - * @param - * the type of elements and items (the same type), which should - * implement {@link Hoverable} (it will not cause issues if not, - * but then, it will be a default renderer) - * @param model - * the model to use - * - * @return a suitable, {@link Hoverable} compatible renderer - */ - static public ListCellRenderer6 generateRenderer( - final ListModel model) { - return new ListCellRenderer6() { - @Override - public Component getListCellRendererComponent(JList6 list, - T item, int index, boolean isSelected, - boolean cellHasFocus) { - if (item instanceof Hoverable) { - Hoverable hoverable = (Hoverable) item; - hoverable.setSelected(isSelected); - hoverable.setHovered(model.isHovered(index)); - } - - return item; - } - }; - } -} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/ListenerPanel.java b/src/be/nikiroo/fanfix_swing/gui/utils/ListenerPanel.java deleted file mode 100644 index 9dc8dfe8..00000000 --- a/src/be/nikiroo/fanfix_swing/gui/utils/ListenerPanel.java +++ /dev/null @@ -1,101 +0,0 @@ -package be.nikiroo.fanfix_swing.gui.utils; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.LinkedList; -import java.util.Queue; - -import javax.swing.JPanel; - -/** - * A {@link JPanel} with the default {@link ActionListener} add/remove/fire - * methods. - *

- * Note that it will queue all events until at least one listener comes (or - * comes back!); this first (or at least currently unique) listener will drain - * the queue. - * - * @author niki - */ -public class ListenerPanel extends JPanel { - private static final long serialVersionUID = 1L; - - /** Waiting queue until at least one listener is here to get the events. */ - private final Queue waitingQueue; - - /** - * Create a new {@link ListenerPanel}. - */ - public ListenerPanel() { - waitingQueue = new LinkedList(); - } - - /** - * Check that this {@link ListenerPanel} currently has - * {@link ActionListener}s that listen on it. - * - * @return TRUE if it has - */ - public synchronized boolean hasListeners() { - return listenerList.getListenerList().length > 1; - } - - /** - * Check how many events are currently waiting for an - * {@link ActionListener}. - * - * @return the number of waiting events (can be 0) - */ - public synchronized int getWaitingEventCount() { - return waitingQueue.size(); - } - - /** - * Adds the specified action listener to receive action events from this - * {@link ListenerPanel}. - * - * @param listener - * the action listener to be added - */ - public synchronized void addActionListener(ActionListener listener) { - if (!hasListeners()) { - while (!waitingQueue.isEmpty()) { - listener.actionPerformed(waitingQueue.remove()); - } - } - - listenerList.add(ActionListener.class, listener); - } - - /** - * Removes the specified action listener so that it no longer receives - * action events from this {@link ListenerPanel}. - * - * @param listener - * the action listener to be removed - */ - public synchronized void removeActionListener(ActionListener listener) { - listenerList.remove(ActionListener.class, listener); - } - - /** - * Notify the listeners of an action. - * - * @param listenerCommand - * A string that may specify a command (possibly one of several) - * associated with the event - */ - protected synchronized void fireActionPerformed(String listenerCommand) { - ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, - listenerCommand); - - ActionListener[] listeners = getListeners(ActionListener.class); - if (listeners.length > 0) { - for (ActionListener action : listeners) { - action.actionPerformed(e); - } - } else { - waitingQueue.add(e); - } - } -} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/TreeCellSpanner.java b/src/be/nikiroo/fanfix_swing/gui/utils/TreeCellSpanner.java deleted file mode 100644 index d3a7a84f..00000000 --- a/src/be/nikiroo/fanfix_swing/gui/utils/TreeCellSpanner.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -// Can be found at: https://code.google.com/archive/p/aephyr/source/default/source -// package aephyr.swing; -package be.nikiroo.fanfix_swing.gui.utils; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.tree.*; - -import java.util.*; - -public class TreeCellSpanner extends Container implements TreeCellRenderer, ComponentListener { - - public TreeCellSpanner(JTree tree, TreeCellRenderer renderer) { - if (tree == null || renderer == null) - throw new NullPointerException(); - this.tree = tree; - this.renderer = renderer; - treeParent = tree.getParent(); - if (treeParent != null && treeParent instanceof JViewport) { - treeParent.addComponentListener(this); - } else { - treeParent = null; - tree.addComponentListener(this); - } - } - - protected final JTree tree; - - private TreeCellRenderer renderer; - - private Component rendererComponent; - - private Container treeParent; - - private Map offsets = new HashMap(); - - private TreePath path; - - public TreeCellRenderer getRenderer() { - return renderer; - } - - @Override - public Component getTreeCellRendererComponent(JTree tree, Object value, - boolean selected, boolean expanded, boolean leaf, int row, - boolean hasFocus) { - path = tree.getPathForRow(row); - if (path != null && path.getLastPathComponent() != value) - path = null; - rendererComponent = renderer.getTreeCellRendererComponent( - tree, value, selected, expanded, leaf, row, hasFocus); - if (getComponentCount() < 1 || getComponent(0) != rendererComponent) { - removeAll(); - add(rendererComponent); - } - return this; - } - - @Override - public void doLayout() { - int x = getX(); - if (x < 0) - return; - if (path != null) { - Integer offset = offsets.get(path); - if (offset == null || offset.intValue() != x) { - offsets.put(path, x); - fireTreePathChanged(path); - } - } - rendererComponent.setBounds(getX(), getY(), getWidth(), getHeight()); - } - - @Override - public void paint(Graphics g) { - if (rendererComponent != null) - rendererComponent.paint(g); - } - - @Override - public Dimension getPreferredSize() { - Dimension s = rendererComponent.getPreferredSize(); - // check if path count is greater than 1 to exclude the root - if (path != null && path.getPathCount() > 1) { - Integer offset = offsets.get(path); - if (offset != null) { - int width; - if (tree.getParent() == treeParent) { - width = treeParent.getWidth(); - } else { - if (treeParent != null) { - treeParent.removeComponentListener(this); - tree.addComponentListener(this); - treeParent = null; - } - if (tree.getParent() instanceof JViewport) { - treeParent = tree.getParent(); - tree.removeComponentListener(this); - treeParent.addComponentListener(this); - width = treeParent.getWidth(); - } else { - width = tree.getWidth(); - } - } - s.width = width - offset; - } - } - return s; - } - - - protected void fireTreePathChanged(TreePath path) { - if (path.getPathCount() > 1) { - // this cannot be used for the root node or else - // the entire tree will keep being revalidated ad infinitum - TreeModel model = tree.getModel(); - Object node = path.getLastPathComponent(); - if (node instanceof TreeNode && (model instanceof DefaultTreeModel - || (model instanceof TreeModelTransformer && - (model=((TreeModelTransformer)model).getModel()) instanceof DefaultTreeModel))) { - ((DefaultTreeModel)model).nodeChanged((TreeNode)node); - } else { - model.valueForPathChanged(path, node.toString()); - } - } else { - // root! - - } - } - - - private int lastWidth; - - @Override - public void componentHidden(ComponentEvent e) {} - - @Override - public void componentMoved(ComponentEvent e) {} - - @Override - public void componentResized(ComponentEvent e) { - if (e.getComponent().getWidth() != lastWidth) { - lastWidth = e.getComponent().getWidth(); - for (int row=tree.getRowCount(); --row>=0;) { - fireTreePathChanged(tree.getPathForRow(row)); - } - } - } - - @Override - public void componentShown(ComponentEvent e) {} - -} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/TreeModelTransformer.java b/src/be/nikiroo/fanfix_swing/gui/utils/TreeModelTransformer.java deleted file mode 100644 index b339f664..00000000 --- a/src/be/nikiroo/fanfix_swing/gui/utils/TreeModelTransformer.java +++ /dev/null @@ -1,1217 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -// Can be found at: https://code.google.com/archive/p/aephyr/source/default/source -// package aephyr.swing; -package be.nikiroo.fanfix_swing.gui.utils; - -import java.text.Collator; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Iterator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.swing.JTree; -import javax.swing.SortOrder; -import javax.swing.event.EventListenerList; -import javax.swing.event.TreeExpansionEvent; -import javax.swing.event.TreeExpansionListener; -import javax.swing.event.TreeModelEvent; -import javax.swing.event.TreeModelListener; -import javax.swing.event.TreeWillExpandListener; -import javax.swing.tree.ExpandVetoException; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; - - -public class TreeModelTransformer implements TreeModel { - - public TreeModelTransformer(JTree tree, TreeModel model) { - if (tree == null) - throw new IllegalArgumentException(); - if (model == null) - throw new IllegalArgumentException(); - this.tree = tree; - this.model = model; - handler = createHandler(); - addListeners(); - } - - private JTree tree; - - private TreeModel model; - - private Handler handler; - - private Filter filter; - - private TreePath filterStartPath; - - private int filterDepthLimit; - - private SortOrder sortOrder = SortOrder.UNSORTED; - - private Map converters; - - protected EventListenerList listenerList = new EventListenerList(); - - protected Handler createHandler() { - return new Handler(); - } - - protected void addListeners() { - tree.addTreeExpansionListener(handler); - model.addTreeModelListener(handler); - } - - protected void removeListeners() { - tree.removeTreeExpansionListener(handler); - model.removeTreeModelListener(handler); - } - - public void dispose() { - removeListeners(); - } - - public TreeModel getModel() { - return model; - } - - private Converter getConverter(Object node) { - return converters == null ? null : converters.get(node); - } - - int convertRowIndexToView(Object parent, int index) { - Converter converter = getConverter(parent); - if (converter != null) - return converter.convertRowIndexToView(index); - return index; - } - - int convertRowIndexToModel(Object parent, int index) { - Converter converter = getConverter(parent); - if (converter != null) - return converter.convertRowIndexToModel(index); - return index; - } - - @Override - public Object getChild(Object parent, int index) { - return model.getChild(parent, convertRowIndexToModel(parent, index)); - } - - @Override - public int getChildCount(Object parent) { - Converter converter = getConverter(parent); - if (converter != null) - return converter.getChildCount(); - return model.getChildCount(parent); - } - - @Override - public int getIndexOfChild(Object parent, Object child) { - int index = model.getIndexOfChild(parent, child); - if (index < 0) - return -1; - return convertRowIndexToView(parent, index); - } - - @Override - public Object getRoot() { - return model.getRoot(); - } - - @Override - public boolean isLeaf(Object node) { - return model.isLeaf(node); - } - - @Override - public void valueForPathChanged(TreePath path, Object newValue) { - model.valueForPathChanged(path, newValue); - } - - @Override - public void addTreeModelListener(TreeModelListener l) { - listenerList.add(TreeModelListener.class, l); - } - - @Override - public void removeTreeModelListener(TreeModelListener l) { - listenerList.remove(TreeModelListener.class, l); - } - - /** - * Set the comparator that compares nodes in sorting. - * @param comparator - * @see #getComparator() - */ - public void setComparator(Comparator comparator) { - handler.setComparator(comparator); - } - - /** - * @return comparator that compares nodes - * @see #setComparator(Comparator) - */ - public Comparator getComparator() { - return handler.getComparator(); - } - - public void setSortOrder(SortOrder newOrder) { - SortOrder oldOrder = sortOrder; - if (oldOrder == newOrder) - return; - sortOrder = newOrder; - ArrayList paths = null; - switch (newOrder) { - case ASCENDING: - if (oldOrder == SortOrder.DESCENDING) { - flip(); - } else { - paths = sort(); - } - break; - case DESCENDING: - if (oldOrder == SortOrder.ASCENDING) { - flip(); - } else { - paths = sort(); - } - break; - case UNSORTED: - unsort(); - break; - } - fireTreeStructureChangedAndExpand(new TreePath(getRoot()), paths, true); - } - - public SortOrder getSortOrder() { - return sortOrder; - } - - public void toggleSortOrder() { - setSortOrder(sortOrder == SortOrder.ASCENDING ? - SortOrder.DESCENDING : SortOrder.ASCENDING); - } - - - /** - * Flip all sorted paths. - */ - private void flip() { - for (Converter c : converters.values()) { - flip(c.viewToModel); - } - } - - /** - * Flip array. - * @param array - */ - private static void flip(int[] array) { - for (int left=0, right=array.length-1; - left cons = converters.values().iterator(); - while (cons.hasNext()) { - Converter converter = cons.next(); - if (!converter.isFiltered()) { - cons.remove(); - } else { - Arrays.sort(converter.viewToModel); - } - } - } - } - - /** - * Sort root and expanded descendants. - * @return list of paths that were sorted - */ - private ArrayList sort() { - if (converters == null) - converters = createConvertersMap(); //new IdentityHashMap(); - return sortHierarchy(new TreePath(model.getRoot())); - } - - /** - * Sort path and expanded descendants. - * @param path - * @return list of paths that were sorted - */ - private ArrayList sortHierarchy(TreePath path) { - ValueIndexPair[] pairs = createValueIndexPairArray(20); - ArrayList list = new ArrayList(); - pairs = sort(path.getLastPathComponent(), pairs); - list.add(path); - Enumeration paths = tree.getExpandedDescendants(path); - if (paths != null) - while (paths.hasMoreElements()) { - path = paths.nextElement(); - pairs = sort(path.getLastPathComponent(), pairs); - list.add(path); - } - return list; - } - - private ValueIndexPair[] sort(Object node, ValueIndexPair[] pairs) { - Converter converter = getConverter(node); - TreeModel mdl = model; - int[] vtm; - if (converter != null) { - vtm = converter.viewToModel; - if (pairs.length < vtm.length) - pairs = createValueIndexPairArray(vtm.length); - for (int i=vtm.length; --i>=0;) { - int idx = vtm[i]; - pairs[i].index = idx; - pairs[i].value = (N)mdl.getChild(node, idx); - } - } else { - int count = mdl.getChildCount(node); - if (count <= 0) - return pairs; - if (pairs.length < count) - pairs = createValueIndexPairArray(count); - for (int i=count; --i>=0;) { - pairs[i].index = i; - pairs[i].value = (N)mdl.getChild(node, i); - } - vtm = new int[count]; - } - Arrays.sort(pairs, 0, vtm.length, handler); - for (int i=vtm.length; --i>=0;) - vtm[i] = pairs[i].index; - if (converter == null) { - converters.put(node, new Converter(vtm, false)); - } - if (sortOrder == SortOrder.DESCENDING) - flip(vtm); - return pairs; - } - - private ValueIndexPair[] createValueIndexPairArray(int len) { - ValueIndexPair[] pairs = new ValueIndexPair[len]; - for (int i=len; --i>=0;) - pairs[i] = new ValueIndexPair(); - return pairs; - } - - public void setFilter(Filter filter) { - setFilter(filter, null); - } - - public void setFilter(Filter filter, TreePath startingPath) { - setFilter(filter, null, -1); - } - - public void setFilter(Filter filter, TreePath startingPath, int depthLimit) { - if (filter == null && startingPath != null) - throw new IllegalArgumentException(); - if (startingPath != null && startingPath.getPathCount() == 1) - startingPath = null; - Filter oldFilter = this.filter; - TreePath oldStartPath = filterStartPath; - this.filter = filter; - filterStartPath = startingPath; - filterDepthLimit = depthLimit; - applyFilter(oldFilter, oldStartPath, null, true); - } - - public Filter getFilter() { - return filter; - } - - public TreePath getFilterStartPath() { - return filterStartPath; - } - - private void applyFilter(Filter oldFilter, TreePath oldStartPath, Collection expanded, boolean sort) { - TreePath startingPath = filterStartPath; - ArrayList expand = null; - if (filter == null) { - converters = null; - } else { - if (converters == null || startingPath == null) { - converters = createConvertersMap(); - } else if (oldFilter != null) { - // unfilter the oldStartPath if oldStartPath isn't descendant of startingPath - if (oldStartPath == null) { - converters = createConvertersMap(); - fireTreeStructureChangedAndExpand(new TreePath(getRoot()), null, true); - } else if (!startingPath.isDescendant(oldStartPath)) { - Object node = oldStartPath.getLastPathComponent(); - handler.removeConverter(getConverter(node), node); - fireTreeStructureChangedAndExpand(oldStartPath, null, true); - } - } - expand = new ArrayList(); - TreePath path = startingPath != null ? startingPath : new TreePath(getRoot()); - if (!applyFilter(filter, path, expand, filterDepthLimit)) { - converters.put(path.getLastPathComponent(), new Converter(Converter.EMPTY, true)); - } - } - if (startingPath == null) - startingPath = new TreePath(getRoot()); - fireTreeStructureChanged(startingPath); - if (expanded != null) - expand.retainAll(expanded); - expandPaths(expand); - if (sort && sortOrder != SortOrder.UNSORTED) { - if (filter == null) - converters = createConvertersMap(); - if (startingPath.getPathCount() > 1 && oldFilter != null) { - // upgrade startingPath or sort oldStartPath - if (oldStartPath == null) { - startingPath = new TreePath(getRoot()); - } else if (oldStartPath.isDescendant(startingPath)) { - startingPath = oldStartPath; - } else if (!startingPath.isDescendant(oldStartPath)) { - expand = sortHierarchy(oldStartPath); - fireTreeStructureChanged(oldStartPath); - expandPaths(expand); - } - } - expand = sortHierarchy(startingPath); - fireTreeStructureChanged(startingPath); - expandPaths(expand); - } - - } - - private boolean applyFilter(Filter filter, TreePath path, ArrayList expand) { - int depthLimit = filterDepthLimit; - if (depthLimit >= 0) { - depthLimit -= filterStartPath.getPathCount() - path.getPathCount(); - if (depthLimit <= 0) - return false; - } - return applyFilter(filter, path, expand, depthLimit); - } - - private boolean applyFilter(Filter filter, TreePath path, ArrayList expand, int depthLimit) { - Object node = path.getLastPathComponent(); - int count = model.getChildCount(node); - int[] viewToModel = null; - int viewIndex = 0; - boolean needsExpand = false; - boolean isExpanded = false; - if (depthLimit > 0) - depthLimit--; - for (int i=0; i 1) { - expand.add(path); - } - if (viewToModel != null) { - if (viewIndex < viewToModel.length) - viewToModel = Arrays.copyOf(viewToModel, viewIndex); - // a node must have a converter to signify that tree modifications - // need to query the filter, so have to put in converter - // even if viewIndex == viewToModel.length - converters.put(node, new Converter(viewToModel, true)); - return true; - } - return false; - } - - - private void expandPaths(ArrayList paths) { - if (paths == null || paths.isEmpty()) - return; - JTree tre = tree; - for (TreePath path : paths) - tre.expandPath(path); - } - - - private void fireTreeStructureChangedAndExpand(TreePath path, ArrayList list, boolean retainSelection) { - Enumeration paths = list != null ? - Collections.enumeration(list) : tree.getExpandedDescendants(path); - TreePath[] sel = retainSelection ? tree.getSelectionPaths() : null; - fireTreeStructureChanged(path); - if (paths != null) - while (paths.hasMoreElements()) - tree.expandPath(paths.nextElement()); - if (sel != null) - tree.setSelectionPaths(sel); - } - - - - protected void fireTreeStructureChanged(TreePath path) { - Object[] listeners = listenerList.getListenerList(); - TreeModelEvent e = null; - for (int i = listeners.length-2; i>=0; i-=2) { - if (listeners[i]==TreeModelListener.class) { - if (e == null) - e = new TreeModelEvent(this, path, null, null); - ((TreeModelListener)listeners[i+1]).treeStructureChanged(e); - } - } - } - - protected void fireTreeNodesChanged(TreePath path, int[] childIndices, Object[] childNodes) { - Object[] listeners = listenerList.getListenerList(); - TreeModelEvent e = null; - for (int i = listeners.length-2; i>=0; i-=2) { - if (listeners[i]==TreeModelListener.class) { - if (e == null) - e = new TreeModelEvent(this, path, childIndices, childNodes); - ((TreeModelListener)listeners[i+1]).treeNodesChanged(e); - } - } - } - - protected void fireTreeNodesInserted(TreePath path, int[] childIndices, Object[] childNodes) { - Object[] listeners = listenerList.getListenerList(); - TreeModelEvent e = null; - for (int i = listeners.length-2; i>=0; i-=2) { - if (listeners[i]==TreeModelListener.class) { - if (e == null) - e = new TreeModelEvent(this, path, childIndices, childNodes); - ((TreeModelListener)listeners[i+1]).treeNodesInserted(e); - } - } - } - - protected void fireTreeNodesRemoved(TreePath path, int[] childIndices, Object[] childNodes) { - Object[] listeners = listenerList.getListenerList(); - TreeModelEvent e = null; - for (int i = listeners.length-2; i>=0; i-=2) { - if (listeners[i]==TreeModelListener.class) { - if (e == null) - e = new TreeModelEvent(this, path, childIndices, childNodes); - ((TreeModelListener)listeners[i+1]).treeNodesRemoved(e); - } - } - } - - - protected class Handler implements Comparator>, - TreeModelListener, TreeExpansionListener { - - private Comparator comparator; - - private Collator collator = Collator.getInstance(); - - void setComparator(Comparator cmp) { - comparator = cmp; - collator = cmp == null ? Collator.getInstance() : null; - } - - Comparator getComparator() { - return comparator; - } - - // TODO, maybe switch to TreeWillExpandListener? - // TreeExpansionListener was used in case an expanded node - // had children that would also be expanded, but it is impossible - // for hidden nodes' expansion state to survive a SortOrder change - // since they are all erased when the tree structure change event - // is fired after changing the SortOrder. - - @Override - public void treeCollapsed(TreeExpansionEvent e) {} - - @Override - public void treeExpanded(TreeExpansionEvent e) { - if (sortOrder != SortOrder.UNSORTED) { - TreePath path = e.getPath(); - Converter converter = getConverter(path.getLastPathComponent()); - if (converter == null) { - ArrayList paths = sortHierarchy(path); - fireTreeStructureChangedAndExpand(path, paths, false); - } - } - } - - private boolean isFiltered(Object node) { - Converter c = getConverter(node); - return c == null ? false : c.isFiltered(); - } - - private boolean acceptable(TreePath path, Object[] childNodes, int index, ArrayList expand) { - return acceptable(path, childNodes, index) || - applyFilter(filter, path.pathByAddingChild(childNodes[index]), expand); - } - - @Override - public void treeNodesChanged(TreeModelEvent e) { - treeNodesChanged(e.getTreePath(), e.getChildIndices(), e.getChildren()); - } - - protected void treeNodesChanged(TreePath path, int[] childIndices, Object[] childNodes) { - if (childIndices == null) { - // path should be root path - // reapply filter - if (filter != null) - applyFilter(null, null, null, true); - return; - } - Converter converter = getConverter(path.getLastPathComponent()); - ArrayList expand = null; - if (converter != null) { - expand = new ArrayList(); - int childIndex = 0; - for (int i=0; i= 0) { - // see if the filter dislikes the nodes new state - if (converter.isFiltered() && - !isFiltered(childNodes[i]) && - !acceptable(path, childNodes, i)) { - // maybe it likes a child nodes state - if (!applyFilter(filter, path.pathByAddingChild(childNodes[i]), expand)) - remove(path, childNodes[i]); - continue; - } - childNodes[childIndex] = childNodes[i]; - childIndices[childIndex++] = idx; - } else if (acceptable(path, childNodes, i, expand)) { - int viewIndex = insert(path.getLastPathComponent(), - childNodes[i], childIndices[i], converter); - fireTreeNodesInserted(path, indices(viewIndex), nodes(childNodes[i])); - } - } - if (childIndex == 0) { - maybeFireStructureChange(path, expand); - return; - } - if (sortOrder != SortOrder.UNSORTED && converter.getChildCount() > 1) { - sort(path.getLastPathComponent(), createValueIndexPairArray(converter.getChildCount())); - fireTreeStructureChangedAndExpand(path, null, true); - expandPaths(expand); - return; - } - if (childIndex != childIndices.length) { - childIndices = Arrays.copyOf(childIndices, childIndex); - childNodes = Arrays.copyOf(childNodes, childIndex); - } - } else if (filter != null && isFilteredOut(path)) { - // see if the filter likes the nodes new states - expand = new ArrayList(); - int[] vtm = null; - int idx = 0; - for (int i=0; i expand) { - if (expand != null && !expand.isEmpty()) { - Enumeration expanded = tree.getExpandedDescendants(path); - fireTreeStructureChanged(path); - if (expanded != null) - while (expanded.hasMoreElements()) - tree.expandPath(expanded.nextElement()); - expandPaths(expand); - } - } - - @Override - public void treeNodesInserted(TreeModelEvent e) { - treeNodesInserted(e.getTreePath(), e.getChildIndices(), e.getChildren()); - } - - protected void treeNodesInserted(TreePath path, int[] childIndices, Object[] childNodes) { - Object parent = path.getLastPathComponent(); - Converter converter = getConverter(parent); - ArrayList expand = null; - if (converter != null) { -// if (childIndices.length > 3 && !converter.isFiltered() -// && childIndices.length > converter.getChildCount()/10) { -// TreePath expand = sortHierarchy(path); -// fireTreeStructureChangedAndExpand(expand); -// return; -// } - int childIndex = 0; - for (int i=0; i(); - if (!applyFilter(filter, path.pathByAddingChild(childNodes[i]), expand)) - continue; - } - // shift the appropriate cached modelIndices - int[] vtm = converter.viewToModel; - int modelIndex = childIndices[i]; - for (int j=vtm.length; --j>=0;) { - if (vtm[j] >= modelIndex) - vtm[j] += 1; - } - // insert modelIndex to converter - int viewIndex = insert(parent, childNodes[i], modelIndex, converter); - childNodes[childIndex] = childNodes[i]; - childIndices[childIndex++] = viewIndex; - } - if (childIndex == 0) - return; - if (childIndex != childIndices.length) { - childIndices = Arrays.copyOf(childIndices, childIndex); - childNodes = Arrays.copyOf(childNodes, childIndex); - } - if (childIndex > 1 && sortOrder != SortOrder.UNSORTED) { - sort(childIndices, childNodes); - } - } else if (filter != null && isFilteredOut(path)) { - // apply filter to inserted nodes - int[] vtm = null; - int idx = 0; - expand = new ArrayList(); - for (int i=0; i= 0) { - childNodes[len] = childNodes[i]; - childIndices[len++] = viewIndex; - } - } - if (len == 0) - return; - if (converter.isFiltered() && converter.getChildCount() == len) { - ArrayList expand = new ArrayList(); - if (applyFilter(filter, path, expand)) { - expand.retainAll(getExpandedPaths(path)); - if (sortOrder != SortOrder.UNSORTED) - sortHierarchy(path); - fireTreeStructureChangedAndExpand(path, expand, true); - } else if (isFilterStartPath(path)) { - converters.put(parent, new Converter(Converter.EMPTY, true)); - fireTreeStructureChanged(path); - } else { - remove(path.getParentPath(), parent); - } - return; - } - if (len != childIndices.length) { - childIndices = Arrays.copyOf(childIndices, len); - childNodes = Arrays.copyOf(childNodes, len); - } - if (len > 1 && sortOrder != SortOrder.UNSORTED) { - sort(childIndices, childNodes); - } - if (childIndices.length == 1) { - converter.remove(converter.convertRowIndexToModel(childIndices[0])); - } else { - converter.remove(childIndices); - } - } else if (filter != null && isFilteredOut(path)) { - return; - } - fireTreeNodesRemoved(path, childIndices, childNodes); - } - - private Collection getExpandedPaths(TreePath path) { - Enumeration en = tree.getExpandedDescendants(path); - if (en == null) - return Collections.emptySet(); - HashSet expanded = new HashSet(); - while (en.hasMoreElements()) - expanded.add(en.nextElement()); - return expanded; - } - - @Override - public void treeStructureChanged(TreeModelEvent e) { - if (converters != null) { - // not enough information to properly clean up - // reapply filter/sort - converters = createConvertersMap(); - TreePath[] sel = tree.getSelectionPaths(); - if (filter != null) { - applyFilter(null, null, getExpandedPaths(new TreePath(getRoot())), false); - } - if (sortOrder != SortOrder.UNSORTED) { - TreePath path = new TreePath(getRoot()); - ArrayList expand = sortHierarchy(path); - fireTreeStructureChangedAndExpand(path, expand, false); - } - if (sel != null) { - tree.clearSelection(); - TreePath changedPath = e.getTreePath(); - for (TreePath path : sel) { - if (!changedPath.isDescendant(path)) - tree.addSelectionPath(path); - } - } - } else { - fireTreeStructureChanged(e.getTreePath()); - } - } - - - @Override - public final int compare(ValueIndexPair a, ValueIndexPair b) { - return compareNodes(a.value, b.value); - } - - - protected int compareNodes(N a, N b) { - if (comparator != null) - return comparator.compare(a, b); - return collator.compare(a.toString(), b.toString()); - } - - private void removeConverter(Object node) { - Converter c = getConverter(node); - if (c != null) - removeConverter(c, node); - } - - private void removeConverter(Converter converter, Object node) { - for (int i=converter.getChildCount(); --i>=0;) { - int index = converter.convertRowIndexToModel(i); - Object child = model.getChild(node, index); - Converter c = getConverter(child); - if (c != null) - removeConverter(c, child); - } - converters.remove(node); - } - - private boolean isFilteredOut(TreePath path) { - if (filterStartPath != null && !filterStartPath.isDescendant(path)) - return false; - TreePath parent = path.getParentPath(); - // root should always have a converter if filter is non-null, - // so if parent is ever null, there is a bug somewhere else - Converter c = getConverter(parent.getLastPathComponent()); - if (c != null) { - return getIndexOfChild( - parent.getLastPathComponent(), - path.getLastPathComponent()) < 0; - } - return isFilteredOut(parent); - } - - private void filterIn(int[] vtm, int vtmLength, TreePath path, ArrayList expand) { - Object node = path.getLastPathComponent(); - if (vtmLength != vtm.length) - vtm = Arrays.copyOf(vtm, vtmLength); - Converter converter = new Converter(vtm, true); - converters.put(node, converter); - insert(path.getParentPath(), node); - tree.expandPath(path); - expandPaths(expand); - } - - private boolean acceptable(TreePath path, Object[] nodes, int index) { - Object node = nodes[index]; - return filter.acceptNode(path, (N)node, model.isLeaf(node)); - } - - private int ascInsertionIndex(int[] vtm, Object parent, N node, int idx) { - for (int i=vtm.length; --i>=0;) { - int cmp = compareNodes(node, (N)model.getChild(parent, vtm[i])); - if (cmp > 0 || (cmp == 0 && idx > vtm[i])) { - return i+1; - } - } - return 0; - } - - - private int dscInsertionIndex(int[] vtm, Object parent, N node, int idx) { - for (int i=vtm.length; --i>=0;) { - int cmp = compareNodes(node, (N)model.getChild(parent, vtm[i])); - if (cmp < 0) { - return i+1; - } else if (cmp == 0 && idx < vtm[i]) { - return i; - } - } - return 0; - } - - - /** - * Inserts the specified path and node and any parent paths as necessary. - *

- * Fires appropriate event. - * @param path - * @param node - */ - private void insert(TreePath path, Object node) { - Object parent = path.getLastPathComponent(); - Converter converter = converters.get(parent); - int modelIndex = model.getIndexOfChild(parent, node); - if (converter == null) { - converter = new Converter(indices(modelIndex), true); - converters.put(parent, converter); - insert(path.getParentPath(), parent); - } else { - int viewIndex = insert(parent, node, modelIndex, converter); - fireTreeNodesInserted(path, indices(viewIndex), nodes(node)); - } - } - - /** - * Inserts node into parent in correct sort order. - *

- * Responsibility of caller to fire appropriate event with the returned viewIndex. - * @param path - * @param node - * @param modelIndex - * @param converter - * @return viewIndex - */ - private int insert(Object parent, Object node, int modelIndex, Converter converter) { - int[] vtm = converter.viewToModel; - int viewIndex; - switch (sortOrder) { - case ASCENDING: - viewIndex = ascInsertionIndex(vtm, parent, (N)node, modelIndex); - break; - case DESCENDING: - viewIndex = dscInsertionIndex(vtm, parent, (N)node, modelIndex); - break; - default: case UNSORTED: - viewIndex = unsortedInsertionIndex(vtm, modelIndex); - break; - } - int[] a = new int[vtm.length+1]; - System.arraycopy(vtm, 0, a, 0, viewIndex); - System.arraycopy(vtm, viewIndex, a, viewIndex+1, vtm.length-viewIndex); - a[viewIndex] = modelIndex; - converter.viewToModel = a; - return viewIndex; - } - - private void remove(TreePath path, Object node) { - Object parent = path.getLastPathComponent(); - if (path.getPathCount() == 1 || (filterStartPath != null && filterStartPath.equals(path))) { - removeConverter(node); - converters.put(parent, new Converter(Converter.EMPTY, true)); - fireTreeNodesRemoved(path, indices(0), nodes(node)); - return; - } - Converter converter = converters.get(parent); - int modelIndex = model.getIndexOfChild(parent, node); - int viewIndex = converter.remove(modelIndex); - switch (viewIndex) { - default: - removeConverter(node); - fireTreeNodesRemoved(path, indices(viewIndex), nodes(node)); - break; - case Converter.ONLY_INDEX: -// if (path.getParentPath() == null) { -// // reached filter root -// removeConverter(node); -// converters.put(parent, new Converter(Converter.EMPTY, true)); -// fireTreeNodesRemoved(path, indices(0), nodes(node)); -// return; -// } - remove(path.getParentPath(), parent); - break; - case Converter.INDEX_NOT_FOUND: - removeConverter(node); - } - } - - - - } - - - - private static int unsortedInsertionIndex(int[] vtm, int idx) { - for (int i=vtm.length; --i>=0;) - if (vtm[i] < idx) - return i+1; - return 0; - } - - private static void sort(int[] childIndices, Object[] childNodes) { - int len = childIndices.length; - ValueIndexPair[] pairs = new ValueIndexPair[len]; - for (int i=len; --i>=0;) - pairs[i] = new ValueIndexPair(childIndices[i], childNodes[i]); - Arrays.sort(pairs); - for (int i=len; --i>=0;) { - childIndices[i] = pairs[i].index; - childNodes[i] = pairs[i].value; - } - } - - private static int[] indices(int...indices) { - return indices; - } - - private static Object[] nodes(Object...nodes) { - return nodes; - } - - - - - /** - * This class has a dual purpose, both related to comparing/sorting. - *

- * The Handler class sorts an array of ValueIndexPair based on the value. - * Used for sorting the view. - *

- * ValueIndexPair sorts itself based on the index. - * Used for sorting childIndices for fire* methods. - */ - private static class ValueIndexPair implements Comparable> { - ValueIndexPair() {} - - ValueIndexPair(int idx, N val) { - index = idx; - value = val; - } - - N value; - - int index; - - public int compareTo(ValueIndexPair o) { - return index - o.index; - } - } - - private static class Converter { - - static final int[] EMPTY = new int[0]; - - static final int ONLY_INDEX = -2; - - static final int INDEX_NOT_FOUND = -1; - - Converter(int[] vtm, boolean filtered) { - viewToModel = vtm; - isFiltered = filtered; - } - - private int[] viewToModel; - - private boolean isFiltered; - -// public boolean equals(Converter conv) { -// if (conv == null) -// return false; -// if (isFiltered != conv.isFiltered) -// return false; -// return Arrays.equals(viewToModel, conv.viewToModel); -// } - - boolean isFiltered() { - return isFiltered; - } - - void remove(int viewIndices[]) { - int len = viewToModel.length - viewIndices.length; - if (len == 0) { - viewToModel = EMPTY; - } else { - int[] oldVTM = viewToModel; - int[] newVTM = new int[len]; - for (int oldIndex=0, newIndex=0, removeIndex=0; - newIndex=0;) - if (newVTM[i] > idx) - newVTM[i]--; - for (int i=oldIndex; i idx) - oldVTM[i]--; - } - newVTM[newIndex] = oldVTM[oldIndex]; - } - viewToModel = newVTM; - } - } - - /** - * @param modelIndex - * @return viewIndex that was removed
- * or ONLY_INDEX if the modelIndex is the only one in the view
- * or INDEX_NOT_FOUND if the modelIndex is not in the view - */ - int remove(int modelIndex) { - int[] vtm = viewToModel; - for (int i=vtm.length; --i>=0;) { - if (vtm[i] > modelIndex) { - vtm[i] -= 1; - } else if (vtm[i] == modelIndex) { - if (vtm.length == 1) { - viewToModel = EMPTY; - return ONLY_INDEX; - } - int viewIndex = i; - while (--i>=0) { - if (vtm[i] > modelIndex) - vtm[i] -= 1; - } - int[] a = new int[vtm.length-1]; - if (viewIndex > 0) - System.arraycopy(vtm, 0, a, 0, viewIndex); - int len = a.length-viewIndex; - if (len > 0) - System.arraycopy(vtm, viewIndex+1, a, viewIndex, len); - viewToModel = a; - return viewIndex; - } - } - return INDEX_NOT_FOUND; - } - - - int getChildCount() { - return viewToModel.length; - } - - /** - * @param modelIndex - * @return viewIndex corresponding to modelIndex
- * or INDEX_NOT_FOUND if the modelIndex is not in the view - */ - int convertRowIndexToView(int modelIndex) { - int[] vtm = viewToModel; - for (int i=vtm.length; --i>=0;) { - if (vtm[i] == modelIndex) - return i; - } - return INDEX_NOT_FOUND; - } - - int convertRowIndexToModel(int viewIndex) { - return viewToModel[viewIndex]; - } - } - - public interface Filter { - boolean acceptNode(TreePath parent, N node, boolean leaf); - } - - public static class RegexFilter implements Filter { - - public RegexFilter(Pattern pattern, boolean leaf) { - matcher = pattern.matcher(""); - leafOnly = leaf; - } - - private Matcher matcher; - - private boolean leafOnly; - - public boolean acceptNode(TreePath parent, N node, boolean leaf) { - if (leafOnly && !leaf) - return false; - matcher.reset(getStringValue(node)); - return matcher.find(); - } - - protected String getStringValue(N node) { - return node.toString(); - } - } - - - private static Map createConvertersMap() { - return new HashMap(); - } -} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/TreeSnapshot.java b/src/be/nikiroo/fanfix_swing/gui/utils/TreeSnapshot.java deleted file mode 100644 index ad734a14..00000000 --- a/src/be/nikiroo/fanfix_swing/gui/utils/TreeSnapshot.java +++ /dev/null @@ -1,127 +0,0 @@ -package be.nikiroo.fanfix_swing.gui.utils; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import javax.swing.JTree; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; - -public class TreeSnapshot { - private interface NodeAction { - public void run(TreeNode node); - } - - private JTree tree; - private TreePath[] selectionPaths; - private List expanded; - - public TreeSnapshot(JTree tree) { - this.tree = tree; - - selectionPaths = tree.getSelectionPaths(); - if (selectionPaths == null) { - selectionPaths = new TreePath[0]; - } - - expanded = new ArrayList(); - forEach(tree, new NodeAction() { - @Override - public void run(TreeNode node) { - TreePath path = nodeToPath(node); - if (path != null) { - if (TreeSnapshot.this.tree.isExpanded(path)) { - expanded.add(path); - } - } - } - }); - } - - public void apply() { - applyTo(tree); - } - - public void applyTo(JTree tree) { - final List newExpanded = new ArrayList(); - final List newSlectionPaths = new ArrayList(); - - forEach(tree, new NodeAction() { - @Override - public void run(TreeNode newNode) { - TreePath newPath = nodeToPath(newNode); - if (newPath != null) { - for (TreePath path : selectionPaths) { - if (isSamePath(path, newPath)) { - newSlectionPaths.add(newPath); - if (expanded.contains(path)) { - newExpanded.add(newPath); - } - } - } - } - } - }); - - for (TreePath newPath : newExpanded) { - tree.expandPath(newPath); - } - - tree.setSelectionPaths(newSlectionPaths.toArray(new TreePath[0])); - } - - // You can override this - protected boolean isSamePath(TreePath oldPath, TreePath newPath) { - return newPath.toString().equals(oldPath.toString()); - } - - private void forEach(JTree tree, NodeAction action) { - forEach(tree.getModel(), tree.getModel().getRoot(), action); - } - - private void forEach(TreeModel model, Object parent, NodeAction action) { - if (!(parent instanceof TreeNode)) - return; - - TreeNode node = (TreeNode) parent; - - action.run(node); - int count = model.getChildCount(node); - for (int i = 0; i < count; i++) { - Object child = model.getChild(node, i); - forEach(model, child, action); - } - } - - private static TreePath nodeToPath(TreeNode node) { - List nodes = new LinkedList(); - if (node != null) { - nodes.add(node); - node = node.getParent(); - while (node != null) { - nodes.add(0, node); - node = node.getParent(); - } - } - - return nodes.isEmpty() ? null : new TreePath(nodes.toArray()); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Tree Snapshot of: ").append(tree).append("\n"); - builder.append("Selected paths:\n"); - for (TreePath path : selectionPaths) { - builder.append("\t").append(path).append("\n"); - } - builder.append("Expanded paths:\n"); - for (TreePath epath : expanded) { - builder.append("\t").append(epath).append("\n"); - } - - return builder.toString(); - } -} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/UiHelper.java b/src/be/nikiroo/fanfix_swing/gui/utils/UiHelper.java index 08a65b07..7cc0a3d2 100644 --- a/src/be/nikiroo/fanfix_swing/gui/utils/UiHelper.java +++ b/src/be/nikiroo/fanfix_swing/gui/utils/UiHelper.java @@ -4,10 +4,7 @@ import java.awt.Color; import java.awt.Component; import javax.swing.JButton; -import javax.swing.JComponent; import javax.swing.JOptionPane; -import javax.swing.JScrollPane; -import javax.swing.JTree; import javax.swing.SwingUtilities; import be.nikiroo.fanfix.Instance; @@ -37,14 +34,6 @@ public class UiHelper { button.setBackground(pressed ? buttonPressed : buttonNormal); } - static public JComponent scroll(JComponent pane) { - JScrollPane scroll = new JScrollPane(pane); - scroll.getVerticalScrollBar().setUnitIncrement(16); - scroll.setHorizontalScrollBarPolicy( - JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - return scroll; - } - /** * Display an error message and log the linked {@link Exception}. * -- 2.27.0