//{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.dataeditor;
import com.nexirius.framework.FWLog;
import com.nexirius.framework.datamodel.DataModel;
import com.nexirius.framework.datamodel.DataModelEvent;
import com.nexirius.framework.datamodel.TreeHook;
import com.nexirius.framework.dataviewer.*;
import com.nexirius.util.SortedVector;
import com.nexirius.util.assertion.Assert;
import javax.swing.*;
import javax.swing.tree.TreePath;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
/**
* This class displays a split pane which has on its left side a JTree and on the right side
* a DataEditor which is changing when highlighting items on the tree.
*
* @author Marcel Baumann
*/
public class NavigatorEditor
extends DataViewer {
/**
* The number of components which are held in a table to quickly jump from one node
* to the next.
*/
public static int BUFFERED_COMPONENTS = 20;
public int editKey = KeyEvent.VK_F12;
// protected ViewerFactory factory;
protected TreeViewer treeViewer = null;
TreePopupMenu menu = null;
// protected DataModel model = null;
protected ViewerTable viewerTable = new ViewerTable();
JSplitPane splitPane;
JComponent rightComponent = null;
public NavigatorEditor(DataModel model) {
super(model);
}
public String getViewerName() {
return "NavigatorEditor";
}
/**
*/
public void create() {
Assert.pre(model != null, "Parameter model is not null");
this.viewerTable.removeAll();
//getDataModel().addDataModelListener(this);
// try to create tree viewer
treeViewer = (TreeViewer) factory.createViewer(new TreeViewerCreator(), this.model);
if (menu == null) {
menu = new DefaultTreePopupMenu();
}
setTreePopupMenu(menu);
splitPane = new JSplitPane();
setJComponent(splitPane);
splitPane.setLeftComponent(this.treeViewer.getJComponent());
this.treeViewer.addMouseListener(new TreeMouseAdapter());
this.treeViewer.addKeyListener(new TreeKeyAdapter());
}
public void update() {
}
public JComponent getRightComponent() {
return rightComponent;
}
public void setRightComponent(JComponent c) {
rightComponent = c;
splitPane.setRightComponent(new JScrollPane(c));
}
/**
* Define a specific tree popup menu generator.
*
* @see com.nexirius.framework.dataviewer.DefaultTreePopupMenu
*/
public void setTreePopupMenu(TreePopupMenu menu) {
this.menu = menu;
if (this.treeViewer != null) {
treeViewer.setTreePopupMenu(menu);
}
}
/**
* On grab focus events setActivePath is called.
*
* @see #setActivePath
*/
public void dataModelGrabFocus(DataModelEvent event) {
super.dataModelGrabFocus(event);
FWLog.debug("NAV:dataModelGrabFocus event = " + event);
setActivePath(event.getTreePath());
}
/**
* Find the node in the data model hierarchie which is an editor for the
* last component in the tree path and show it on the right hand side.
* If the editor does not exist it is automatically generated and stored in
* a buffer. The size of the buffer is limited by BUFFERED_COMPONENTS.
*/
public void setActivePath(TreePath path) {
this.treeViewer.setSelectedPath(path);
DataModel viewer_model = null;
DataModel active_model = null;
if (path == null) {
active_model = model;
viewer_model = model;
} else {
Object c = path.getLastPathComponent();
Assert.assertion(c instanceof TreeHook, "Navigator node is instance of TreeHook");
// Apply the mode to the command set according to the node selected
active_model = ((TreeHook) c).getDataModel();
viewer_model = active_model;
DataModel parent_model = active_model.getParentDataModel();
while (parent_model != getDataModel() && parent_model.isChildEditor()) {
viewer_model = parent_model;
parent_model = viewer_model.getParentDataModel();
}
}
JComponent component = null;
component = (JComponent) this.viewerTable.get(viewer_model);
if (component == null) {
try {
component = this.factory.createDefaultEditor(viewer_model).getJComponent();
this.viewerTable.put(viewer_model, component);
// call grab focus again (now the component exists)
//FIX active_model.grabFocus();
FWLog.debug("NEW component created for: " + viewer_model.getFieldName());
} catch (Exception ex) {
//FIX
ex.printStackTrace();
}
} else {
FWLog.debug("Reuse the existing component");
}
// display this node on the right side
if (getRightComponent() != component) {
setRightComponent(component);
}
}
class TreeMouseAdapter extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 1) {
JTree tree = (JTree) e.getSource();
TreePath path = tree.getClosestPathForLocation(e.getPoint().x, e.getPoint().y);
if (path != null) {
Object c = path.getLastPathComponent();
Assert.assertion(c instanceof TreeHook, "Navigator node is instance of TreeHook");
// Apply the mode to the command set according to the node selected
DataModel model = ((TreeHook) c).getDataModel();
model.grabFocus();
}
}
}
}
class TreeKeyAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == editKey) {
TreePath path = treeViewer.getSelectedPath();
if (path != null) {
Object c = path.getLastPathComponent();
Assert.assertion(c instanceof TreeHook, "Navigator node is instance of TreeHook");
// Apply the mode to the command set according to the node selected
DataModel model = ((TreeHook) c).getDataModel();
model.grabFocus();
}
}
}
}
class ViewerTable extends SortedVector {
class Entry {
DataModel model;
JComponent component;
Entry(DataModel m, JComponent c) {
model = m;
component = c;
}
}
public Entry getEntry(DataModel model) {
Enumeration e = elements();
while (e.hasMoreElements()) {
Entry entry = (Entry) e.nextElement();
if (entry.model == model) {
return entry;
}
}
return null;
}
public JComponent get(DataModel model) {
Entry e = getEntry(model);
if (e != null) {
// shift it to the end
removeElement(e);
addElement(e);
return e.component;
}
return null;
}
public void put(DataModel m, JComponent c) {
addElement(new Entry(m, c));
while (size() > BUFFERED_COMPONENTS) {
removeElementAt(0);
}
FWLog.debug("Number of elements in the NavigatorEditor now: " + size());
}
public void removeAll() {
removeAllElements();
}
}
}