//{HEADER
/**
* This class is part of jnex 'Nexirius Application Framework for Java'
*
* Copyright (C) Nexirius GmbH, CH-4450 Sissach, Switzerland (www.nexirius.ch)
*
* <p>This library is free software; you can redistribute it and/or<br>
* modify it under the terms of the GNU Lesser General Public<br>
* License as published by the Free Software Foundation; either<br>
* version 2.1 of the License, or (at your option) any later version.</p>
*
* <p>This library is distributed in the hope that it will be useful,<br>
* but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU<br>
* Lesser General Public License for more details.</p>
*
* <p>You should have received a copy of the GNU Lesser General Public<br>
* License along with this library; if not, write to the Free Software<br>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p>
* </blockquote>
*
* <p>
* Nexirius GmbH, hereby disclaims all copyright interest in<br>
* the library jnex' 'Nexirius Application Framework for Java' written<br>
* by Marcel Baumann.</p>
*/
//}HEADER
package com.nexirius.framework.dataviewer;
import com.nexirius.framework.datamodel.DataModel;
import com.nexirius.framework.datamodel.DataModelEvent;
import com.nexirius.framework.datamodel.DataModelTree;
import com.nexirius.framework.datamodel.TreeHook;
import com.nexirius.util.assertion.Assert;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeCellRenderer;
import java.awt.*;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* This viewer is designed to show DataModelContainer data as Swing tree.
*
* @author Marcel Baumann
* @see TreeViewerCellRenderer
*/
public class TreeViewer extends DataViewer {
public static final String s_viewername = "TreeViewer";
JTree tree = null;
TreePopupMenu menu = null;
DataModelTree treeModel;
boolean fireGrabFocusEvents = false;
boolean acceptGrabFocusEvents = false;
TreeCellRenderer treeCellRenderer;
/**
* Uses a specific wrapper class for data models
*
* @param treeModel The data model wrapper which enables swing tree model behaviour.
* @see DataModelTree
*/
public TreeViewer(DataModelTree treeModel) {
super(treeModel.getDataModel());
this.treeModel = treeModel;
setTreePopupMenu(new DefaultTreePopupMenu());
}
/**
* fires grab focus events on the model which are selected
* and/or
* accepts grab focus events on models and unfolds the associated tree path
*/
public void manageGrabFocusEvents(boolean fire, boolean accept) {
fireGrabFocusEvents = fire;
acceptGrabFocusEvents = accept;
}
/**
* Assotiate a specific popup menu generator (default is null)
*
* @see DefaultTreePopupMenu
*/
public void setTreePopupMenu(TreePopupMenu menu) {
Assert.pre(menu != null, "menu is not null");
this.menu = menu;
}
public void setTreeCellRenderer(TreeCellRenderer treeCellRenderer) {
this.treeCellRenderer = treeCellRenderer;
}
/**
* Creates the actual tree.
*/
public void create() {
if (isCreated()) {
return;
}
if (this.factory == null) {
throw new RuntimeException("Can't create a TreeViewer with null factory (call setFactory())");
}
this.tree = new JTree(this.treeModel);
this.tree.setBackground(SystemColor.control);
this.tree.setSelectionModel(this.treeModel.getTreeSelectionModel());
this.tree.setCellRenderer(getTreeCellRenderer());
this.tree.addMouseListener(new PopupMouseAdapter());
this.tree.getSelectionModel().addTreeSelectionListener(new MyTreeSelectionListener());
setJComponent(new JScrollPane(this.tree));
}
public TreeCellRenderer getTreeCellRenderer() {
if (treeCellRenderer == null) {
treeCellRenderer = new TreeViewerCellRenderer(this.factory);
}
return treeCellRenderer;
}
/**
* Adds a mouse listener to the tree (creates the tree first if needed)
*/
public void addMouseListener(MouseListener adapter) {
create();
this.tree.addMouseListener(adapter);
}
/**
* Adds a key listener to the tree (creates the tree first if needed)
*/
public void addKeyListener(KeyListener adapter) {
create();
this.tree.addKeyListener(adapter);
}
/**
* Adds a tree selection listener to the tree (creates the tree first if needed)
*/
public void addTreeSelectionListener(TreeSelectionListener listener) {
create();
this.tree.getSelectionModel().addTreeSelectionListener(listener);
}
/**
* Tries to remove a tree selection listener
*/
public void removeTreeSelectionListener(TreeSelectionListener listener) {
if (isCreated()) {
this.tree.getSelectionModel().removeTreeSelectionListener(listener);
}
}
/**
* If the tree is created then this method selects the given tree path
*/
public void setSelectedPath(TreePath path) {
if (isCreated()) {
if (path == null) {
this.tree.getSelectionModel().clearSelection();
} else {
if (!path.equals(getSelectedPath())) {
this.tree.getSelectionModel().setSelectionPath(path);
this.tree.scrollPathToVisible(path);
}
}
}
}
/**
* Returns the currently selected tree path or null (if the tree is not created yet)
*/
public TreePath getSelectedPath() {
if (isCreated()) {
return this.tree.getSelectionModel().getSelectionPath();
}
return null;
}
/**
* Only used for debugging
*/
public String getViewerName() {
return s_viewername;
}
public void update() {
}
// Inner class used to process popup triggering events
// ("right mouse key" in windows)
private class PopupMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
showPopup(e);
}
}
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
showPopup(e);
}
}
public void mouseClicked(MouseEvent e) {
if (e.isPopupTrigger()) {
showPopup(e);
}
}
private void showPopup(MouseEvent e) {
Point position = e.getPoint();
// check if there is a popup menu factory
if (menu == null) {
return;
}
// If anything is selected, then generate a menu
JPopupMenu popup = menu.createPopupMenu(factory, getDataModel(e));
if (popup != null) {
// Display popup menu at the given mouse position
popup.show(tree, position.x, position.y);
}
}
DataModel getDataModel(MouseEvent e) {
TreePath path = tree.getClosestPathForLocation(e.getX(), e.getY());
if (path != null) {
return ((TreeHook) path.getLastPathComponent()).getDataModel();
}
return null;
}
}
class MyTreeSelectionListener implements TreeSelectionListener {
public void valueChanged(TreeSelectionEvent e) {
fireGrabFocusEvent();
}
}
/**
* fire grab focus event on selected model
*
* @return the model which has received the grab focus event (or null)
*/
public DataModel fireGrabFocusEvent() {
if (!fireGrabFocusEvents) {
return null;
}
TreePath path = getSelectedPath();
if (path != null) {
DataModel m = ((TreeHook) path.getLastPathComponent()).getDataModel();
if (m != null) {
m.grabFocus();
return m;
}
}
return null;
}
/**
* unfolds the specified tree path
*/
public void dataModelGrabFocus(DataModelEvent event) {
if (!acceptGrabFocusEvents || event == null) {
return;
}
setSelectedPath(event.getTreePath());
}
}