Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

AbstractElementList.java

Go to the documentation of this file.
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     // Strategy Methods
00121 
00130     protected void doEditElement(RQMLFirstClass elem) {
00131         if (shouldOpenElementEditors) {
00132             // the editor window will be automatically displayed.
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         // left panel
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     // View implementations
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     // Own implementations
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             // ask the node to create a child
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             // ask the node to create a child
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         // don't open editors while we're loading document.
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     // Factory Methods
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); // initially disabled
00327         //tree.putClientProperty("JTree.lineStyle", "Horizontal");
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); // initially disabled
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     // accessor methods
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     // Controller classes
00487 
00491     protected class TreeController implements TreeSelectionListener,
00492             MouseListener, KeyListener {
00493 
00494         //-------------------------------------------------------------------
00495         // TreeSelectionListener implementations
00496 
00497         public void valueChanged(TreeSelectionEvent e) {
00498             JTree tree = getTree();
00499             if (e.getSource() != tree || !tree.isEnabled()) {
00500                 // this isn't the tree we're supposed to control
00501                 // or the tree is disabled.
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         // MouseListener implementations
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                 // this isn't the tree we're supposed to control
00544                 // or the tree is disabled.
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         // KeyListener implementations
00567 
00573         public void keyPressed(KeyEvent e) {
00574             JTree tree = getTree();
00575             if (e.getSource() != tree || !tree.isEnabled()) {
00576                 // this isn't the tree we're supposed to control
00577                 // or the tree is disabled
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         // strategy methods
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                 // System.out.println(node);
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     // Custom Components
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             //setEditable(desc != null);
00708             this.firePropertyChange("description", old, desc);
00709         }
00710 
00714         protected Description desc = null;
00715     }
00716 
00717     //-----------------------------------------------------------------------
00718     // Model Adapters
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         // Own implementation methods
00836 
00840         public void cmNewElement() {
00841             // the element will be created in the document and the
00842             // editor window will be automatically displayed.
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         // Member variables
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         // Observable implementation
00933 
00934         public void update(Observable source, Object param) {
00935             getTreeModel().nodeChanged(this);
00936         }
00937 
00938         //-------------------------------------------------------------------
00939         // Own implementation
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         // Member Variables
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     // ElementTypeNodeFacade
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     // Action classes
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         // RQMLFirstClassFactory methods
01045 
01046         public abstract RQMLFirstClass createRQMLFirstClass();
01047 
01048         //-------------------------------------------------------------------
01049         // AbstractAction implementations
01050 
01051         public void actionPerformed(ActionEvent e) {
01052             // the element will be created in the document and the
01053             // editor window will be automatically displayed.
01054             createRQMLFirstClass();
01055         }
01056 
01057         //-------------------------------------------------------------------
01058         // PropertyChangeListener implementations
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         // Own implementations
01070 
01071         protected void checkEnabled() {
01072             setEnabled(getDocument() != null);
01073         }
01074     }
01075 }

Generated on Fri Jun 18 19:50:26 2004 for Arcle Rambutan by doxygen 1.3.5