All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tinymediamanager.ui.components.treetable.TmmTreeTableTreePathSupport Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012 - 2019 Manuel Laggner
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.tinymediamanager.ui.components.treetable;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.SwingUtilities;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.AbstractLayoutCache;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

/**
 * Manages expanded/collapsed paths for the TreeTable.
 *
 * @author Manuel Laggner
 */
final class TmmTreeTableTreePathSupport {
  private List  expansionListeners  = new ArrayList<>();
  private List willExpandListeners = new ArrayList<>();
  private AbstractLayoutCache          layout;

  TmmTreeTableTreePathSupport(AbstractLayoutCache layout) {
    this.layout = layout;
  }

  void clear() {
  }

  void expandPath(TreePath path) {
    assert SwingUtilities.isEventDispatchThread();
    if (layout.isExpanded(path)) {
      return;
    }

    TreePath parentPath = path.getParentPath();
    if (parentPath != null) {
      expandPath(parentPath);
    }

    TreeExpansionEvent treeExpansionEvent = new TreeExpansionEvent(this, path);
    try {
      fireTreeWillExpand(treeExpansionEvent, true);
      layout.setExpandedState(path, true);
      fireTreeExpansion(treeExpansionEvent, true);
    }
    catch (Exception ignored) {
    }
  }

  public void collapsePath(TreePath path) {
    assert SwingUtilities.isEventDispatchThread();
    if (!layout.isExpanded(path)) {
      return;
    }

    TreeExpansionEvent treeExpansionEvent = new TreeExpansionEvent(this, path);
    try {
      fireTreeWillExpand(treeExpansionEvent, false);
      layout.setExpandedState(path, false);
      fireTreeExpansion(treeExpansionEvent, false);
    }
    catch (Exception ignored) {
    }
  }

  private void fireTreeExpansion(TreeExpansionEvent e, boolean expanded) {
    for (TreeExpansionListener listener : new ArrayList<>(expansionListeners)) {
      if (expanded) {
        listener.treeExpanded(e);
      }
      else {
        listener.treeCollapsed(e);
      }
    }
  }

  private void fireTreeWillExpand(TreeExpansionEvent e, boolean expanded) throws ExpandVetoException {
    for (TreeWillExpandListener listener : new ArrayList<>(willExpandListeners)) {
      if (expanded) {
        listener.treeWillExpand(e);
      }
      else {
        listener.treeWillCollapse(e);
      }
    }
  }

  boolean isExpanded(TreePath path) {
    assert SwingUtilities.isEventDispatchThread();
    if (path == null) {
      return false;
    }

    if (!layout.isRootVisible() && path.getParentPath() == null) {
      return true; // Invisible root is always expanded
    }

    // Is this node expanded?
    boolean nodeExpanded = layout.isExpanded(path);
    if (!nodeExpanded) {
      return false;
    }

    // It is, make sure its parent is also expanded.
    TreePath parentPath = path.getParentPath();

    if (parentPath != null) {
      return isExpanded(parentPath);
    }

    return true;
  }

  boolean isVisible(TreePath path) {
    if (path != null) {
      TreePath parentPath = path.getParentPath();

      if (parentPath != null) {
        return isExpanded(parentPath);
      }
      // Root.
      return true;
    }
    return false;
  }

  TreePath[] getExpandedDescendants(TreePath parent) {
    assert SwingUtilities.isEventDispatchThread();
    TreePath[] result = new TreePath[0];
    if (isExpanded(parent)) {
      TreePath path;
      List results = null;

      Enumeration tpe = layout.getVisiblePathsFrom(parent);
      if (tpe != null) {
        while (tpe.hasMoreElements()) {
          path = tpe.nextElement();
          // Add the path if it is expanded, a descendant of parent, and it is visible (all parents expanded). This is rather expensive!
          if (path != parent && layout.isExpanded(path) && parent.isDescendant(path)) {

            if (results == null) {
              results = new ArrayList<>();
            }
            results.add(path);
          }
        }
        if (results != null) {
          result = results.toArray(result);
        }
      }
    }
    return result;
  }

  synchronized void addTreeExpansionListener(TreeExpansionListener listener) {
    expansionListeners.add(listener);
  }

  synchronized void removeTreeExpansionListener(TreeExpansionListener listener) {
    expansionListeners.remove(listener);
  }

  synchronized void addTreeWillExpandListener(TreeWillExpandListener listener) {
    willExpandListeners.add(listener);
  }

  synchronized void removeTreeWillExpandListener(TreeWillExpandListener listener) {
    willExpandListeners.remove(listener);
  }

  void treeStructureChanged(TreeModelEvent event) {
    TreePath path = event.getTreePath();
    TreeModel model = layout.getModel();
    if ((path == null) && (model != null)) {
      Object root = model.getRoot();
      if (root != null) {
        path = new TreePath(root);
      }
    }

    TreePath[] expandedDescendants = getExpandedDescendants(path);

    layout.treeStructureChanged(event);

    for (TreePath tp : expandedDescendants) {
      layout.setExpandedState(tp, true);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy