00001
00058 package com.arcle.rmt.j2se.swing.vc;
00059
00060 import javax.swing.*;
00061 import javax.swing.event.*;
00062 import javax.swing.tree.*;
00063
00064 import java.beans.PropertyChangeListener;
00065 import java.beans.PropertyChangeEvent;
00066
00067 import java.awt.event.MouseListener;
00068 import java.awt.event.KeyListener;
00069 import java.awt.event.ActionEvent;
00070 import java.awt.event.MouseEvent;
00071 import java.awt.event.KeyEvent;
00072 import java.awt.BorderLayout;
00073
00074 import java.util.Collections;
00075 import java.util.Enumeration;
00076 import java.util.Iterator;
00077 import java.util.Observable;
00078 import java.util.Observer;
00079 import java.util.Vector;
00080 import java.util.List;
00081 import java.util.Map;
00082 import java.util.ArrayList;
00083 import java.util.Collection;
00084
00085 import com.arcle.rmt.rqml.Description;
00086 import com.arcle.rmt.rqml.RQMLFirstClass;
00087 import com.arcle.rmt.j2se.swing.ui.ComponentView;
00088 import com.arcle.rmt.j2se.swing.ui.Controller;
00089 import com.arcle.rmt.j2se.swing.ui.ExceptionSafeActionWrapper;
00090 import com.arcle.rmt.j2se.framework.Document;
00091 import com.arcle.rmt.j2se.model.RQMLDocument;
00092 import com.arcle.rmt.j2se.model.RQMLDocumentUpdateEvent;
00093 import com.arcle.rmt.j2se.model.RQMLFirstClassFactory;
00094 import com.arcle.rmt.j2se.util.GenericClassMap;
00095 import com.arcle.rmt.j2se.util.ClassMapVisitor;
00096 import com.arcle.rmt.j2se.util.MoreCollections;
00097 import com.arcle.rmt.j2se.util.CollectionVisitor;
00098 import com.arcle.rmt.xplat.util.MutableBoolean;
00099
00100
00113 public abstract class AbstractElementList extends ComponentView {
00114
00115 protected AbstractElementList(ElementEditFactory f) {
00116 _editFactory = f;
00117 }
00118
00119
00120
00121
00130 protected void doEditElement(RQMLFirstClass elem) {
00131 if (shouldOpenElementEditors) {
00132
00133 ElementEdit ee = getElementEditFactory().createElementEdit(elem);
00134 ee.setDocument(getDocument());
00135 }
00136 }
00137
00141 protected void initChildren() { }
00142
00143 protected void layoutChildren() {
00144 setLayout(new BorderLayout());
00145 JSplitPane sp1;
00146
00147
00148 sp1 = createSplitPane(JSplitPane.VERTICAL_SPLIT);
00149 sp1.add(createScrollPane(getTree()), JSplitPane.TOP);
00150 sp1.add(createScrollPane(getCurrentDescription()), JSplitPane.BOTTOM);
00151 sp1.setOneTouchExpandable(true);
00152 sp1.setResizeWeight(PANE_WEIGHT);
00153 add(sp1, BorderLayout.CENTER);
00154 }
00155
00156
00157
00158
00159
00160
00165 public void update(Observable o, Object param) {
00166 if(o != null && o == getDocument()) {
00167 if (param instanceof RQMLDocumentUpdateEvent) {
00168 RQMLDocumentUpdateEvent evt = (RQMLDocumentUpdateEvent) param;
00169 RQMLFirstClass elem = (RQMLFirstClass) evt.getElement();
00170 switch (evt.getEventType()) {
00171 case RQMLDocumentUpdateEvent.ET_NEW_ELEMENT:
00172 handleNewElement(elem);
00173 break;
00174 case RQMLDocumentUpdateEvent.ET_DELETING_ELEMENT:
00175 handleDeleteElement(elem);
00176 break;
00177 }
00178 }
00179 } else {
00180 super.update(o, param);
00181 }
00182 }
00183
00189 public void setDocument(Document doc) {
00190 super.setDocument(doc);
00191 boolean hasDocument = doc != null;
00192 if (hasDocument) {
00193 loadData();
00194 }
00195 getTree().setEnabled(hasDocument);
00196 getCurrentDescription().setEnabled(hasDocument);
00197 }
00198
00199
00200 public Controller getController() {
00201 if (_controller == null) {
00202 _controller = createController();
00203 }
00204 return _controller;
00205 }
00206
00210 protected ElementTypeNodeFacade getElementTypeNodeFacade() {
00211 if (_nodeFacade == null) {
00212 _nodeFacade = createElementTypeNodeFacade();
00213 }
00214 return _nodeFacade;
00215 }
00216
00217
00218
00219
00220
00226 protected void handleNewElement(RQMLFirstClass elem) {
00227 createChild(elem);
00228 }
00229
00235 protected void handleDeleteElement(RQMLFirstClass elem) {
00236 deleteChild(elem);
00237 }
00238
00244 protected void createChild(final RQMLFirstClass elem) {
00245 ElementTypeNode node = (ElementTypeNode)
00246 getElementTypeNodeFacade().findFirstInstance(elem);
00247 if (node != null) {
00248
00249 node.createChild(elem);
00250 } else {
00251 throw new UnsupportedOperationException(
00252 "Cannot create child for element: " + elem);
00253 }
00254 }
00255
00259 protected void deleteChild(final RQMLFirstClass elem) {
00260 ElementTypeNode node = (ElementTypeNode)
00261 getElementTypeNodeFacade().findFirstInstance(elem);
00262 if (node != null) {
00263
00264 node.deleteChild(elem);
00265 } else {
00266 throw new UnsupportedOperationException(
00267 "Cannot delete child for element: " + elem);
00268 }
00269 }
00270
00271
00275 protected void loadData() {
00276 RQMLDocument doc = getRQMLDocument();
00277 if (doc == null) {
00278 throw new IllegalStateException(
00279 "Must set document before calling loadData()");
00280 }
00281 clearTypeNodes();
00282
00283 shouldOpenElementEditors = false;
00284 try {
00285 Iterator elems = doc.getElements();
00286 while (elems.hasNext()) {
00287 Object elem = elems.next();
00288 createChild((RQMLFirstClass) elem);
00289 }
00290 TreeModelAdapter tm = (TreeModelAdapter) getTreeModel();
00291 tm.reload();
00292 } finally {
00293 shouldOpenElementEditors = true;
00294 }
00295 }
00296
00300 protected void clearTypeNodes() {
00301 ClassMapVisitor visitor = new ClassMapVisitor() {
00302 public boolean visitClassMap(Class cls, Object obj) {
00303 ElementTypeNode node = (ElementTypeNode) obj;
00304 node.clear();
00305 return true;
00306 }
00307 };
00308 getElementTypeNodeFacade().visitClasses(visitor);
00309 }
00310
00311
00312
00313
00314
00321 protected JTree createTree() {
00322 JTree tree = new JTree();
00323 tree.setModel(getTreeModel());
00324 tree.getSelectionModel().setSelectionMode(
00325 TreeSelectionModel.SINGLE_TREE_SELECTION);
00326 tree.setEnabled(false);
00327
00328 TreeController ctrl = createTreeController();
00329 tree.addTreeSelectionListener(ctrl);
00330 tree.addMouseListener(ctrl);
00331 tree.addKeyListener(ctrl);
00332 return tree;
00333 }
00334
00338 protected TreeController createTreeController() {
00339 return new TreeController();
00340 }
00341
00345 protected DescriptionText createCurrentDescription() {
00346 DescriptionText dt = new DescriptionText();
00347 dt.setEnabled(false);
00348 dt.setLineWrap(true);
00349 dt.setWrapStyleWord(true);
00350 return dt;
00351 }
00352
00356 protected JScrollPane createScrollPane(JComponent c) {
00357 return new JScrollPane(c);
00358 }
00359
00365 protected JSplitPane createSplitPane(int splitMode) {
00366 return new JSplitPane(splitMode);
00367 }
00368
00372 protected RootNode createRootNode() {
00373 return new RootNode();
00374 }
00375
00379 protected TreeModelAdapter createTreeModel() {
00380 return new TreeModelAdapter(createRootNode());
00381 }
00382
00383
00387 protected Controller createController() {
00388 return new ElementListController();
00389 }
00390
00391
00392 protected abstract ElementTypeNodeFacade createElementTypeNodeFacade();
00393
00394
00395
00396
00397
00401 protected JTree getTree() {
00402 if (_tree == null) {
00403 _tree = createTree();
00404 }
00405 return _tree;
00406 }
00407
00411 protected DescriptionText getCurrentDescription() {
00412 if (_currentDescription == null) {
00413 _currentDescription = createCurrentDescription();
00414 }
00415 return _currentDescription;
00416 }
00417
00421 protected RQMLDocument getRQMLDocument() {
00422 return (RQMLDocument) getDocument();
00423 }
00424
00425
00429 protected TreeModelAdapter getTreeModel() {
00430 if (_treeModel == null) {
00431 _treeModel = createTreeModel();
00432 }
00433 return _treeModel;
00434 }
00435
00436 protected RootNode getRootNode() {
00437 return (RootNode) getTreeModel().getRoot();
00438 }
00439
00440 protected ElementEditFactory getElementEditFactory() {
00441 return _editFactory;
00442 }
00443
00444
00445
00446
00451 protected boolean shouldOpenElementEditors = true;
00452
00456 private JTree _tree = null;
00457
00462 private DescriptionText _currentDescription = null;
00463
00464
00468 private Controller _controller;
00469
00473 private TreeModelAdapter _treeModel = null;
00474
00475 private ElementEditFactory _editFactory;
00476
00477
00478 private ElementTypeNodeFacade _nodeFacade = null;
00479
00483 private static final float PANE_WEIGHT = 0.8f;
00484
00485
00486
00487
00491 protected class TreeController implements TreeSelectionListener,
00492 MouseListener, KeyListener {
00493
00494
00495
00496
00497 public void valueChanged(TreeSelectionEvent e) {
00498 JTree tree = getTree();
00499 if (e.getSource() != tree || !tree.isEnabled()) {
00500
00501
00502 return;
00503 }
00504 DescriptionText desc = getCurrentDescription();
00505
00506 Object path = tree.getLastSelectedPathComponent();
00507 if (path instanceof ElementTypeNode) {
00508 ElementTypeNode node = (ElementTypeNode) path;
00509 desc.setDescription(null);
00510 } else if (path instanceof ElementNode) {
00511 ElementNode node = (ElementNode) path;
00512 RQMLFirstClass elem = node.getElement();
00513 desc.setDescription(elem.getDescription());
00514 }
00515 }
00516
00517
00518
00519
00523 public void mouseClicked(MouseEvent e) { }
00524
00528 public void mouseEntered(MouseEvent e) { }
00529
00533 public void mouseExited(MouseEvent e) { }
00534
00540 public void mousePressed(MouseEvent e) {
00541 JTree tree = getTree();
00542 if (e.getSource() != tree || !tree.isEnabled()) {
00543
00544
00545 return;
00546 }
00547
00548 int selRow = tree.getRowForLocation(e.getX(), e.getY());
00549 TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
00550 if (selRow != -1) {
00551 if(e.getClickCount() == 2) {
00552 Object clicked = selPath.getLastPathComponent();
00553 if (clicked instanceof Node) {
00554 doEditNode((Node) clicked);
00555 }
00556 }
00557 }
00558 }
00559
00563 public void mouseReleased(MouseEvent e) { }
00564
00565
00566
00567
00573 public void keyPressed(KeyEvent e) {
00574 JTree tree = getTree();
00575 if (e.getSource() != tree || !tree.isEnabled()) {
00576
00577
00578 return;
00579 }
00580
00581 Object selected = tree.getLastSelectedPathComponent();
00582 if (selected instanceof Node) {
00583 switch (e.getKeyCode()) {
00584 case KeyEvent.VK_ENTER:
00585 doEditNode((Node) selected);
00586 break;
00587 }
00588 }
00589 }
00590
00594 public void keyReleased(KeyEvent e) { }
00595
00599 public void keyTyped(KeyEvent e) { }
00600
00601
00602
00603
00610 protected void doEditNode(Node node) {
00611 if (node instanceof ElementTypeNode) {
00612 ElementTypeNode etn = (ElementTypeNode) node;
00613 etn.cmNewElement();
00614 } else if (node instanceof ElementNode) {
00615 ElementNode en = (ElementNode) node;
00616 en.cmEditElement();
00617 } else {
00621
00622 }
00623 }
00624 }
00625
00631 protected class ElementListController implements Controller {
00632 public List getActions() {
00633 ElementTypeNodeFacade facade
00634 = (ElementTypeNodeFacade) getElementTypeNodeFacade();
00635 Collection nodes = facade.getNodes();
00636 final List actions = new ArrayList(nodes.size());
00637
00638 CollectionVisitor visitor = new CollectionVisitor() {
00639 public boolean visitCollection(Object element) {
00640 ElementTypeNode node = (ElementTypeNode) element;
00641 actions.add(createActionWrapper(node.getNewElementAction()));
00642 return true;
00643 }
00644 };
00645
00646 MoreCollections.visitCollection(nodes, visitor);
00647 return actions;
00648 }
00649
00654 protected Action createActionWrapper(Action wrapped) {
00655 return new ExceptionSafeActionWrapper(AbstractElementList.this,
00656 wrapped);
00657 }
00658 }
00659
00660
00661
00662
00666 protected class DescriptionText extends JTextArea implements Observer {
00667 public DescriptionText() {
00676 setEditable(false);
00677 }
00678
00679 public void update(Observable source, Object param) {
00680 if (desc != null && (source == desc || param == desc) ) {
00681 setText(desc.getString());
00682 }
00683 }
00684
00685 public void setDescription(Description d) {
00686 if (d == desc) {
00687 return;
00688 }
00689 Description old = desc;
00694 if (desc != null && isEditable()) {
00695 desc.setString(getText());
00696 if (desc instanceof Observable) {
00697 ((Observable) desc).deleteObserver(this);
00698 }
00699 }
00700 desc = d;
00701 if (desc instanceof Observable) {
00702 ((Observable) desc).addObserver(this);
00703 }
00704 if (desc != null) {
00705 setText(desc.getString());
00706 }
00707
00708 this.firePropertyChange("description", old, desc);
00709 }
00710
00714 protected Description desc = null;
00715 }
00716
00717
00718
00719
00725 protected class TreeModelAdapter extends DefaultTreeModel {
00726 public TreeModelAdapter(RootNode root) {
00727 super(root, true);
00728 }
00729
00730
00731 }
00732
00737 protected abstract class Node implements TreeNode {
00738 public Node(Node p) {
00739 parent = p;
00740 }
00741
00742 public TreeNode getChildAt(int childIndex) {
00743 return (TreeNode) getChildren().get(childIndex);
00744 }
00745
00746 public int getChildCount() {
00747 return getChildren().size();
00748 }
00749
00750 public TreeNode getParent() {
00751 return parent;
00752 }
00753
00754 public int getIndex(TreeNode node) {
00755 return getChildren().indexOf(node);
00756 }
00757
00758 public boolean getAllowsChildren() {
00759 return true;
00760 }
00761
00762 public boolean isLeaf() {
00763 return false;
00764 }
00765
00766 public Enumeration children() {
00767 return Collections.enumeration(getChildren());
00768 }
00769
00770 protected List getChildren() {
00771 if (children == null) {
00772 children = createChildren();
00773 }
00774 return children;
00775 }
00776
00781 protected abstract List createChildren();
00782
00786 private List children = null;
00787
00791 private Node parent;
00792 }
00793
00794
00800 protected class ElementTypeNode extends Node {
00804 public ElementTypeNode(RootNode p, String t, NewElementAction f) {
00805 super(p);
00806 title = t;
00807 elementFactory = f;
00808 }
00809
00810 public boolean getAllowsChildren() {
00811 return true;
00812 }
00813
00814 public String toString() {
00815 return title;
00816 }
00817
00818 public boolean isLeaf() {
00819 return false;
00820 }
00821
00822 protected List createChildren() {
00823 return new Vector();
00824 }
00825
00826
00830 public void clear() {
00831 getChildren().clear();
00832 }
00833
00834
00835
00836
00840 public void cmNewElement() {
00841
00842
00843 elementFactory.createRQMLFirstClass();
00844 }
00845
00850 public void createChild(RQMLFirstClass elem) {
00851 ElementNode child = new ElementNode(this, elem);
00852 List children = getChildren();
00853 children.add(child);
00854 doEditElement(elem);
00855 getTreeModel().nodesWereInserted(this, new int[]{children.size()-1});
00856 }
00857
00858 public void deleteChild(RQMLFirstClass elem) {
00859 Iterator iter = getChildren().iterator();
00860 while (iter.hasNext()) {
00861 ElementNode cur = (ElementNode) iter.next();
00862 if (cur.getElement() == elem) {
00863 cur.notifyRemoved();
00864 iter.remove();
00865 }
00866 }
00867 getTreeModel().nodeStructureChanged(this);
00868 }
00869
00870
00871 public Action getNewElementAction() {
00872 return elementFactory;
00873 }
00874
00875
00876
00877
00878 protected String title;
00879
00883 protected NewElementAction elementFactory;
00884 }
00885
00891 protected class ElementNode extends Node implements Observer {
00892 public ElementNode(ElementTypeNode p, RQMLFirstClass elem) {
00893 super(p);
00894 _element = elem;
00895 addObservable(elem);
00896 }
00897
00898 public String toString() {
00899 RQMLFirstClass e = getElement();
00900 String id = e.getID();
00901 String name = e.getName().getString();
00902 return (id != null ? id : "") + " " + (name != null ? name : "");
00903 }
00904
00908 public boolean isLeaf() {
00909 return true;
00910 }
00911
00918 public boolean getAllowsChildren() {
00919 return false;
00920 }
00921
00927 protected List createChildren() {
00928 return null;
00929 }
00930
00931
00932
00933
00934 public void update(Observable source, Object param) {
00935 getTreeModel().nodeChanged(this);
00936 }
00937
00938
00939
00940
00941 public RQMLFirstClass getElement() {
00942 return _element;
00943 }
00944
00945
00946 public void cmEditElement() {
00947 doEditElement(getElement());
00948 getTreeModel().nodeChanged(this);
00949 }
00950
00954 public void notifyRemoved() {
00955 deleteObservable(getElement());
00956 }
00957
00958 protected boolean addObservable(Object observable) {
00959 if (observable instanceof Observable) {
00960 Observable obs = (Observable) observable;
00961 obs.addObserver(this);
00962 return true;
00963 }
00964 return false;
00965 }
00966
00967 protected boolean deleteObservable(Object observable) {
00968 if (observable instanceof Observable) {
00969 Observable obs = (Observable) observable;
00970 obs.deleteObserver(this);
00971 return true;
00972 }
00973 return false;
00974 }
00975
00976
00977
00978
00979 private RQMLFirstClass _element;
00980 }
00981
00986 protected class RootNode extends Node {
00987 public RootNode() {
00988 super(null);
00989 }
00990
00991 public String toString() {
00992 return "RQML";
00993 }
00994
00995 protected List createChildren() {
00996 return new ArrayList(getElementTypeNodeFacade().getNodes());
00997 }
00998
00999 }
01000
01001
01002
01003
01007 protected abstract class ElementTypeNodeFacade extends GenericClassMap {
01008
01012 public ElementTypeNode getElementTypeNode(Class interfaceClass) {
01013 return (ElementTypeNode) getMappings().get(interfaceClass);
01014 }
01015
01018 public Collection getNodes() {
01019 return getMappings().values();
01020 }
01021
01024 protected abstract Map createMappings();
01025 }
01026
01027
01028
01029
01034 protected abstract class NewElementAction extends AbstractAction
01035 implements RQMLFirstClassFactory, PropertyChangeListener {
01036
01037 public NewElementAction(String name) {
01038 super(name);
01039 AbstractElementList.this.addPropertyChangeListener(this);
01040 checkEnabled();
01041 }
01042
01043
01044
01045
01046 public abstract RQMLFirstClass createRQMLFirstClass();
01047
01048
01049
01050
01051 public void actionPerformed(ActionEvent e) {
01052
01053
01054 createRQMLFirstClass();
01055 }
01056
01057
01058
01059
01060 public void propertyChange(PropertyChangeEvent evt) {
01061 if (evt.getSource() == AbstractElementList.this) {
01062 if ("document".equals(evt.getPropertyName())) {
01063 checkEnabled();
01064 }
01065 }
01066 }
01067
01068
01069
01070
01071 protected void checkEnabled() {
01072 setEnabled(getDocument() != null);
01073 }
01074 }
01075 }