123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- /*
- * Copyright (c) 2006-2017 DMDirc Developers
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
- * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
- * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
- package com.dmdirc.addons.ui_swing.framemanager.tree;
-
- import com.dmdirc.addons.ui_swing.EDTInvocation;
- import com.dmdirc.addons.ui_swing.UIUtilities;
- import com.dmdirc.addons.ui_swing.actions.CloseWindowAction;
- import com.dmdirc.addons.ui_swing.components.frames.TextFrame;
- import com.dmdirc.addons.ui_swing.events.SwingActiveWindowChangeRequestEvent;
- import com.dmdirc.addons.ui_swing.events.SwingEventBus;
- import com.dmdirc.config.binding.ConfigBinding;
- import com.dmdirc.interfaces.config.AggregateConfigProvider;
-
- import java.awt.Rectangle;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.awt.event.MouseEvent;
- import java.awt.event.MouseListener;
- import java.awt.event.MouseMotionListener;
- import java.util.Optional;
-
- import javax.swing.BorderFactory;
- import javax.swing.JComponent;
- import javax.swing.JMenuItem;
- import javax.swing.JPopupMenu;
- import javax.swing.JTree;
- import javax.swing.UIManager;
- import javax.swing.tree.DefaultTreeModel;
- import javax.swing.tree.MutableTreeNode;
- import javax.swing.tree.TreeModel;
- import javax.swing.tree.TreePath;
- import javax.swing.tree.TreeSelectionModel;
-
- import net.miginfocom.layout.PlatformDefaults;
-
- /**
- * Specialised JTree for the frame manager.
- */
- public class Tree extends JTree implements MouseMotionListener, MouseListener, ActionListener {
-
- /** A version number for this class. */
- private static final long serialVersionUID = 1;
- /** Tree frame manager. */
- private final TreeFrameManager manager;
- /** The swing event bus to post events to. */
- private final SwingEventBus eventBus;
- /** Config manager. */
- private final AggregateConfigProvider config;
- /** Drag selection enabled? */
- private boolean dragSelect;
- /** Drag button 1? */
- private boolean dragButton;
- /** Show handles. */
- private boolean showHandles;
-
- /**
- * Specialised JTree for frame manager.
- *
- * @param manager Frame manager
- * @param model tree model.
- * @param eventBus The swing event bus to post events to.
- * @param globalConfig The config to read settings from.
- * @param domain The domain to read settings from.
- */
- public Tree(
- final TreeFrameManager manager,
- final TreeModel model,
- final SwingEventBus eventBus,
- final AggregateConfigProvider globalConfig,
- final String domain) {
- super(model);
-
- this.manager = manager;
- this.config = globalConfig;
- this.eventBus = eventBus;
-
- putClientProperty("JTree.lineStyle", "Angled");
- getInputMap().setParent(null);
- getInputMap(JComponent.WHEN_FOCUSED).clear();
- getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).clear();
- getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).clear();
- getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
- setRootVisible(false);
- setRowHeight(getFontMetrics(UIManager.getFont("Tree.font")).getHeight() + 2);
- setOpaque(true);
- setBorder(BorderFactory.createEmptyBorder(
- (int) PlatformDefaults.getUnitValueX("related").getValue(),
- (int) PlatformDefaults.getUnitValueX("related").getValue(),
- (int) PlatformDefaults.getUnitValueX("related").getValue(),
- (int) PlatformDefaults.getUnitValueX("related").getValue()));
- setFocusable(false);
-
- config.getBinder().withDefaultDomain(domain).bind(this, Tree.class);
- // TODO: Create a nicer lifecycle and unbind
-
- addMouseListener(this);
- addMouseMotionListener(this);
- }
-
- @Override
- public void scrollRectToVisible(final Rectangle aRect) {
- final Rectangle rect = new Rectangle(0, aRect.y, aRect.width, aRect.height);
- super.scrollRectToVisible(rect);
- }
-
- /**
- * Set path.
- *
- * @param path Path
- */
- public void setTreePath(final TreePath path) {
- UIUtilities.invokeLater(() -> setSelectionPath(path));
- }
-
- /**
- * Returns the node for the specified location, returning null if rollover is disabled or there
- * is no node at the specified location.
- *
- * @param x x coordiantes
- * @param y y coordiantes
- *
- * @return node or null
- */
- public TreeViewNode getNodeForLocation(final int x,
- final int y) {
- TreeViewNode node = null;
- final TreePath selectedPath = getPathForLocation(x, y);
- if (selectedPath != null) {
- node = (TreeViewNode) selectedPath.getLastPathComponent();
- }
- return node;
- }
-
- @ConfigBinding(key = "dragSelection", invocation = EDTInvocation.class)
- public void handleDragSelection(final String value) {
- dragSelect = config.getOptionBool("treeview", "dragSelection");
- }
-
- @ConfigBinding(key="showtreeexpands")
- public void handleTreeExpands(final String value) {
- showHandles = Boolean.valueOf(value);
- setShowsRootHandles(showHandles);
- putClientProperty("showHandles", showHandles);
- }
-
- @Override
- public void mouseDragged(final MouseEvent e) {
- if (dragSelect && dragButton) {
- final TreeViewNode node = getNodeForLocation(e.getX(), e.getY());
- if (node != null) {
- eventBus.publishAsync(new SwingActiveWindowChangeRequestEvent(
- Optional.ofNullable(((TreeViewNode) new TreePath(node.getPath())
- .getLastPathComponent()).getWindow())));
- }
- }
- manager.checkRollover(e);
- }
-
- @Override
- public void mouseMoved(final MouseEvent e) {
- manager.checkRollover(e);
- }
-
- @Override
- public void mouseClicked(final MouseEvent e) {
- processMouseEvents(e);
- }
-
- @Override
- public void mousePressed(final MouseEvent e) {
- if (e.getButton() == MouseEvent.BUTTON1) {
- dragButton = true;
- final TreePath selectedPath = getPathForLocation(e.getX(),
- e.getY());
- if (selectedPath != null) {
- eventBus.publishAsync(new SwingActiveWindowChangeRequestEvent(
- Optional.ofNullable(((TreeViewNode) selectedPath.getLastPathComponent())
- .getWindow())));
- }
- }
- processMouseEvents(e);
- }
-
- @Override
- public void mouseReleased(final MouseEvent e) {
- dragButton = false;
- processMouseEvents(e);
- }
-
- @Override
- public void mouseEntered(final MouseEvent e) {
- //Ignore
- }
-
- @Override
- public void mouseExited(final MouseEvent e) {
- manager.checkRollover(null);
- }
-
- /**
- * Processes every mouse button event to check for a popup trigger.
- *
- * @param e mouse event
- */
- void processMouseEvents(final MouseEvent e) {
- final TreePath localPath = getPathForLocation(e.getX(), e.getY());
- if (localPath != null && e.isPopupTrigger()) {
- final TextFrame frame = ((TreeViewNode) localPath.getLastPathComponent()).getWindow();
-
- if (frame == null) {
- return;
- }
-
- final JPopupMenu popupMenu = frame.getPopupMenu(null,
- new Object[][]{new Object[]{""}});
- frame.addCustomPopupItems(popupMenu);
- if (popupMenu.getComponentCount() > 0) {
- popupMenu.addSeparator();
- }
- final TreeViewNodeMenuItem popoutMenuItem;
- if (frame.getPopoutFrame() == null) {
- popoutMenuItem = new TreeViewNodeMenuItem("Pop Out", "popout",
- (TreeViewNode) localPath.getLastPathComponent());
- } else {
- popoutMenuItem = new TreeViewNodeMenuItem("Pop In", "popin",
- (TreeViewNode) localPath.getLastPathComponent());
- }
- popupMenu.add(popoutMenuItem);
- popupMenu.addSeparator();
- popoutMenuItem.addActionListener(this);
-
- final TreeViewNodeMenuItem moveUp = new TreeViewNodeMenuItem("Move Up", "Up",
- (TreeViewNode) localPath.getLastPathComponent());
- final TreeViewNodeMenuItem moveDown = new TreeViewNodeMenuItem("Move Down", "Down",
- (TreeViewNode) localPath.getLastPathComponent());
-
- moveUp.addActionListener(this);
- moveDown.addActionListener(this);
-
- popupMenu.add(moveUp);
- popupMenu.add(moveDown);
- popupMenu.add(new JMenuItem(new CloseWindowAction(frame.getContainer())));
- popupMenu.show(this, e.getX(), e.getY());
- }
- }
-
- @Override
- public void actionPerformed(final ActionEvent e) {
- final TreeViewNode node = ((TreeViewNodeMenuItem) e.getSource()).
- getTreeNode();
- int index = getModel().getIndexOfChild(node.getParent(), node);
- switch (e.getActionCommand()) {
- case "Up":
- if (index == 0) {
- index = node.getSiblingCount() - 1;
- } else {
- index--;
- }
- break;
- case "Down":
- if (index == node.getSiblingCount() - 1) {
- index = 0;
- } else {
- index++;
- }
- break;
- case "popout":
- node.getWindow().setPopout(true);
- break;
- case "popin":
- node.getWindow().setPopout(false);
- break;
- }
- final MutableTreeNode parentNode = (MutableTreeNode) node.getParent();
- final TreePath nodePath = new TreePath(node.getPath());
- final boolean isExpanded = isExpanded(nodePath);
- ((DefaultTreeModel) getModel()).removeNodeFromParent(node);
- ((DefaultTreeModel) getModel()).insertNodeInto(node, parentNode, index);
- setExpandedState(nodePath, isExpanded);
- }
-
- }
|