Coverage Report - org.argouml.cognitive.ui.ToDoPane
 
Classes in this File Line Coverage Branch Coverage Complexity
ToDoPane
59%
95/159
39%
17/43
2
ToDoPane$1
0%
0/4
0%
0/2
2
ToDoPane$2
80%
8/10
66%
4/6
2
ToDoPane$3
100%
5/5
50%
1/2
2
ToDoPane$4
0%
0/5
0%
0/2
2
 
 1  
 /* $Id: ToDoPane.java 18817 2010-10-27 15:52:25Z tfmorris $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    tfmorris
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2008 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.cognitive.ui;
 40  
 
 41  
 import java.awt.BorderLayout;
 42  
 import java.awt.Color;
 43  
 import java.awt.Dimension;
 44  
 import java.awt.event.ItemEvent;
 45  
 import java.awt.event.ItemListener;
 46  
 import java.awt.event.MouseEvent;
 47  
 import java.awt.event.MouseListener;
 48  
 import java.text.MessageFormat;
 49  
 import java.util.ArrayList;
 50  
 import java.util.List;
 51  
 
 52  
 import javax.swing.BorderFactory;
 53  
 import javax.swing.JComboBox;
 54  
 import javax.swing.JLabel;
 55  
 import javax.swing.JPanel;
 56  
 import javax.swing.JScrollPane;
 57  
 import javax.swing.JTree;
 58  
 import javax.swing.SwingUtilities;
 59  
 import javax.swing.event.TreeSelectionEvent;
 60  
 import javax.swing.event.TreeSelectionListener;
 61  
 import javax.swing.tree.TreeModel;
 62  
 import javax.swing.tree.TreePath;
 63  
 
 64  
 import org.apache.log4j.Logger;
 65  
 import org.argouml.cognitive.Designer;
 66  
 import org.argouml.cognitive.ToDoItem;
 67  
 import org.argouml.cognitive.ToDoList;
 68  
 import org.argouml.cognitive.ToDoListEvent;
 69  
 import org.argouml.cognitive.ToDoListListener;
 70  
 import org.argouml.cognitive.Translator;
 71  
 import org.argouml.ui.DisplayTextTree;
 72  
 import org.argouml.ui.PerspectiveSupport;
 73  
 import org.argouml.ui.ProjectBrowser;
 74  
 import org.argouml.ui.SplashScreen;
 75  
 
 76  
 /**
 77  
  * The lower-left pane of the main ArgoUML window, which shows the list
 78  
  * of active critics and todo items. <p>
 79  
  *
 80  
  * This pane shows a list or tree of all the "to do" items that
 81  
  * the designer should consider. <p>
 82  
  *
 83  
  * This class is similar to the NavigatorPane.
 84  
  * It uses the same treemodel class and JTree implementation. <p>
 85  
  *
 86  
  * Perspectives are now built here. <p>
 87  
  *
 88  
  * Future plans may involve:<ol>
 89  
  * <li> DecisionModelListener implementation
 90  
  * <li> GoalListener implementation
 91  
  * </ol>
 92  
  *
 93  
  *<pre>
 94  
  * possible future additions:
 95  
  *  ToDoPerspective difficulty = new ToDoByDifficulty();
 96  
  *  ToDoPerspective skill = new ToDoBySkill();
 97  
  *</pre>
 98  
  */
 99  4252
 public class ToDoPane extends JPanel
 100  
     implements ItemListener,
 101  
         TreeSelectionListener,
 102  
         MouseListener,
 103  
         ToDoListListener {
 104  
     /**
 105  
      * Logger.
 106  
      */
 107  900
     private static final Logger LOG = Logger.getLogger(ToDoPane.class);
 108  
 
 109  
     private static final int WARN_THRESHOLD = 50;
 110  
     private static final int ALARM_THRESHOLD = 100;
 111  900
     private static final Color WARN_COLOR = Color.yellow;
 112  900
     private static final Color ALARM_COLOR = Color.pink;
 113  
 
 114  
     private static int clicksInToDoPane;
 115  
     private static int dblClicksInToDoPane;
 116  
     private static int toDoPerspectivesChanged;
 117  
 
 118  
     private JTree tree;
 119  
     private JComboBox combo;
 120  
 
 121  
     /**
 122  
      * List of TreeModels.
 123  
      */
 124  
     private List<ToDoPerspective> perspectives;
 125  
     private ToDoPerspective curPerspective;
 126  
 
 127  
     private ToDoList root;
 128  
     private JLabel countLabel;
 129  
     private Object lastSel;
 130  
 
 131  
     /**
 132  
      * Construct the ToDoPane.
 133  
      * @param splash Unused parameter for backwards compatibility.
 134  
      * 
 135  
      * @deprecated for 0.31.7 by tfmorris.  Use 0-arg constructor.
 136  
      */
 137  
     @Deprecated
 138  
     public ToDoPane(@SuppressWarnings("unused") SplashScreen splash) {
 139  0
         this();
 140  0
     }
 141  
     
 142  
     /**
 143  
      * Construct the ToDoPane.
 144  
      */
 145  900
     public ToDoPane() {
 146  
 
 147  900
         setLayout(new BorderLayout());
 148  
 
 149  900
         combo = new JComboBox();
 150  900
         tree = new DisplayTextTree();
 151  
 
 152  900
         perspectives = new ArrayList<ToDoPerspective>();
 153  
 
 154  900
         countLabel = new JLabel(formatCountLabel(999));
 155  900
         countLabel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4));
 156  
 
 157  900
         JPanel toolbarPanel = new JPanel(new BorderLayout());
 158  900
         toolbarPanel.add(countLabel, BorderLayout.EAST);
 159  900
         toolbarPanel.add(combo, BorderLayout.CENTER);
 160  900
         add(toolbarPanel, BorderLayout.NORTH);
 161  
 
 162  900
         add(new JScrollPane(tree), BorderLayout.CENTER);
 163  
 
 164  900
         combo.addItemListener(this);
 165  
 
 166  900
         tree.addTreeSelectionListener(this);
 167  900
         tree.setCellRenderer(new ToDoTreeRenderer());
 168  900
         tree.addMouseListener(this);
 169  
 
 170  
         // next line coming from projectbrowser
 171  900
         setRoot(Designer.theDesigner().getToDoList());
 172  900
         Designer.theDesigner().getToDoList().addToDoListListener(this);
 173  
 
 174  900
         setPerspectives(buildPerspectives());
 175  
 
 176  900
         setMinimumSize(new Dimension(120, 100));
 177  
 
 178  900
         Dimension preferredSize = getPreferredSize();
 179  900
         preferredSize.height = 120;
 180  900
         setPreferredSize(preferredSize);
 181  900
     }
 182  
 
 183  
 
 184  
     /**
 185  
      * @param r the root
 186  
      */
 187  
     public void setRoot(ToDoList r) {
 188  900
         root = r;
 189  900
         updateTree();
 190  900
     }
 191  
 
 192  
     /**
 193  
      * @return the root
 194  
      */
 195  
     public ToDoList getRoot() {
 196  0
         return root;
 197  
     }
 198  
 
 199  
 
 200  
     /**
 201  
      * @return the perspectives treemodels
 202  
      */
 203  
     public List<ToDoPerspective> getPerspectiveList() {
 204  0
         return perspectives;
 205  
     }
 206  
     
 207  
     /**
 208  
      * @param pers the perspectives
 209  
      */
 210  
     public void setPerspectives(List<ToDoPerspective> pers) {
 211  900
         perspectives = pers;
 212  900
         if (pers.isEmpty()) {
 213  0
             curPerspective = null;
 214  
         } else {
 215  900
             curPerspective = pers.get(0);
 216  
         }
 217  
 
 218  900
         for (ToDoPerspective tdp : perspectives) {
 219  5400
             combo.addItem(tdp);
 220  
         }
 221  
 
 222  900
         if (pers.isEmpty()) {
 223  0
             curPerspective = null;
 224  900
         } else if (pers.contains(curPerspective)) {
 225  900
             setCurPerspective(curPerspective);
 226  
         } else {
 227  0
             setCurPerspective(perspectives.get(0));
 228  
         }
 229  900
         updateTree();
 230  900
     }
 231  
     
 232  
     /**
 233  
      * @return the current perspectives
 234  
      */
 235  
     public ToDoPerspective getCurPerspective() {
 236  0
         return curPerspective;
 237  
     }
 238  
 
 239  
     /**
 240  
      * @param per the current perspective
 241  
      */
 242  
     public void setCurPerspective(TreeModel per) {
 243  900
         if (perspectives == null || !perspectives.contains(per)) {
 244  0
             return;
 245  
         }
 246  900
         combo.setSelectedItem(per);
 247  900
         toDoPerspectivesChanged++;
 248  900
     }
 249  
 
 250  
     /**
 251  
      * @return the last <code>Object</code> in the first selected node's
 252  
      *      <code>TreePath</code>,
 253  
      *      or <code>null</code> if nothing is selected
 254  
      */
 255  
     public Object getSelectedObject() {
 256  0
         return tree.getLastSelectedPathComponent();
 257  
     }
 258  
 
 259  
     /**
 260  
      * @param item the item to be selected
 261  
      */
 262  
     public void selectItem(ToDoItem item) {
 263  0
         Object[] path = new Object[3];
 264  0
         Object category = null;
 265  0
         int size = curPerspective.getChildCount(root);
 266  0
         for (int i = 0; i < size; i++) {
 267  0
             category = curPerspective.getChild(root, i);
 268  0
             if (curPerspective.getIndexOfChild(category, item) != -1) {
 269  0
                 break;
 270  
             }
 271  
         }
 272  0
         if (category == null) {
 273  0
             return;
 274  
         }
 275  0
         path[0] = root;
 276  0
         path[1] = category;
 277  0
         path[2] = item;
 278  0
         TreePath trPath = new TreePath(path);
 279  0
         tree.expandPath(trPath);
 280  0
         tree.scrollPathToVisible(trPath);
 281  0
         tree.setSelectionPath(trPath);
 282  0
     }
 283  
 
 284  
     // ------------ ItemListener implementation ----------------------
 285  
 
 286  
     /**
 287  
      * Called when the user selects a perspective from the perspective
 288  
      * combo. <p>
 289  
      * {@inheritDoc}
 290  
      */
 291  
     public void itemStateChanged(ItemEvent e) {
 292  900
         if (e.getSource() == combo) {
 293  900
             updateTree();
 294  
         }
 295  900
     }
 296  
 
 297  
     // -------------TreeSelectionListener implementation -----------
 298  
 
 299  
     /*
 300  
      * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent)
 301  
      */
 302  
     public void valueChanged(TreeSelectionEvent e) {
 303  0
         LOG.debug("ToDoPane valueChanged");
 304  
         //TODO: should fire its own event and ProjectBrowser
 305  
         //should register a listener - tfm
 306  0
         Object sel = getSelectedObject();
 307  0
         ProjectBrowser.getInstance().setToDoItem(sel);
 308  0
         LOG.debug("lastselection: " + lastSel);
 309  0
         LOG.debug("sel: " + sel);
 310  0
         if (lastSel instanceof ToDoItem) {
 311  0
             ((ToDoItem) lastSel).deselect();
 312  
         }
 313  0
         if (sel instanceof ToDoItem) {
 314  0
             ((ToDoItem) sel).select();
 315  
         }
 316  0
         lastSel = sel;
 317  0
     }
 318  
 
 319  
     // ------------- MouseListener implementation ---------------
 320  
 
 321  
     /*
 322  
      * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
 323  
      */
 324  
     public void mousePressed(MouseEvent e) { 
 325  
         // Empty implementation.
 326  0
     }
 327  
 
 328  
     /*
 329  
      * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
 330  
      */
 331  
     public void mouseReleased(MouseEvent e) {  
 332  
         // Empty implementation.
 333  0
     }
 334  
 
 335  
     /*
 336  
      * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
 337  
      */
 338  
     public void mouseEntered(MouseEvent e) {  
 339  
         // Empty implementation.
 340  0
     }
 341  
 
 342  
     /*
 343  
      * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
 344  
      */
 345  
     public void mouseExited(MouseEvent e) { 
 346  
         // Empty implementation.
 347  0
     }
 348  
 
 349  
     /*
 350  
      * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
 351  
      */
 352  
     public void mouseClicked(MouseEvent e) {
 353  0
         int row = tree.getRowForLocation(e.getX(), e.getY());
 354  0
         TreePath path = tree.getPathForLocation(e.getX(), e.getY());
 355  0
         if (row != -1) {
 356  0
             if (e.getClickCount() >= 2) {
 357  0
                 myDoubleClick(row, path);
 358  
             } else {
 359  0
                 mySingleClick(row, path);
 360  
             }
 361  
         }
 362  0
         e.consume();
 363  0
     }
 364  
 
 365  
     ////////////////////////////////////////////////////////////////
 366  
     // ToDoListListener implementation
 367  
 
 368  
     /**
 369  
      * Invoke a task on the Swing thread. If we are running on the Swing
 370  
      * thread, this happens immediately. Otherwise the task is queued for later
 371  
      * execution using SwingUtilities.invokeLater (actually for the moment
 372  
      * invokeAndWait but this should be resolved in future).
 373  
      * <p>
 374  
      * This is necessary because event notification of ToDoListener events is
 375  
      * likely to be coming from the ToDo Validity Checker thread running in the
 376  
      * background.
 377  
      * 
 378  
      * @param task a Runnable task who's run() method will be invoked
 379  
      */
 380  
     private void swingInvoke(Runnable task) {
 381  2126
         if (SwingUtilities.isEventDispatchThread()) {
 382  68
             task.run();
 383  
         } else {
 384  2058
             SwingUtilities.invokeLater(task);
 385  
         }
 386  2126
     }
 387  
     
 388  
     /*
 389  
      * @see org.argouml.cognitive.ToDoListListener#toDoItemsChanged(org.argouml.cognitive.ToDoListEvent)
 390  
      */
 391  
     public void toDoItemsChanged(final ToDoListEvent tde) {
 392  0
         swingInvoke(new Runnable() {
 393  
             public void run() {
 394  0
                 if (curPerspective instanceof ToDoListListener) {
 395  0
                     ((ToDoListListener) curPerspective).toDoItemsChanged(tde);
 396  
                 }
 397  0
             }
 398  
         });
 399  0
     }
 400  
 
 401  
 
 402  
     /*
 403  
      * @see org.argouml.cognitive.ToDoListListener#toDoItemsAdded(org.argouml.cognitive.ToDoListEvent)
 404  
      */
 405  
     public void toDoItemsAdded(final ToDoListEvent tde) {
 406  1967
         swingInvoke(new Runnable() {
 407  
             public void run() {
 408  1967
                 if (curPerspective instanceof ToDoListListener) {
 409  1967
                     ((ToDoListListener) curPerspective).toDoItemsAdded(tde);
 410  
                 }
 411  1967
                 List<ToDoItem> items = tde.getToDoItemList();
 412  1967
                 for (ToDoItem todo : items) {
 413  1967
                     if (todo.getPriority() 
 414  
                             >= ToDoItem.INTERRUPTIVE_PRIORITY) {
 415  
                         // keep nagging until the user solves the problem:
 416  
                         // This seems a nice way to nag:
 417  0
                         selectItem(todo);
 418  0
                         break; // Only interrupt for one todoitem
 419  
                     }
 420  
                 }
 421  1967
                 updateCountLabel();
 422  1967
             }
 423  
         });
 424  1967
     }
 425  
     
 426  
     /*
 427  
      * @see org.argouml.cognitive.ToDoListListener#toDoItemsRemoved(org.argouml.cognitive.ToDoListEvent)
 428  
      */
 429  
     public void toDoItemsRemoved(final ToDoListEvent tde) {
 430  159
         swingInvoke(new Runnable() {
 431  
             public void run() {
 432  159
                 if (curPerspective instanceof ToDoListListener) {
 433  159
                     ((ToDoListListener) curPerspective).toDoItemsRemoved(tde);
 434  
                 }
 435  159
                 updateCountLabel();
 436  159
             }
 437  
         });
 438  159
     }
 439  
 
 440  
     /*
 441  
      * @see org.argouml.cognitive.ToDoListListener#toDoListChanged(org.argouml.cognitive.ToDoListEvent)
 442  
      */
 443  
     public void toDoListChanged(final ToDoListEvent tde) {
 444  0
         swingInvoke(new Runnable() {
 445  
             public void run() {
 446  0
                 if (curPerspective instanceof ToDoListListener) {
 447  0
                     ((ToDoListListener) curPerspective).toDoListChanged(tde);
 448  
                 }
 449  0
                 updateCountLabel();
 450  0
             }
 451  
         });
 452  0
     }
 453  
 
 454  
     /* TODO: Indicate the direction! */
 455  
     private static String formatCountLabel(int size) {
 456  3026
         switch (size) {
 457  
         case 0:
 458  68
             return Translator.localize("label.todopane.no-items");
 459  
         case 1:
 460  948
             return MessageFormat.
 461  
                 format(Translator.localize("label.todopane.item"),
 462  
                        new Object[] {
 463  
                            Integer.valueOf(size),
 464  
                        });
 465  
         default:
 466  2010
             return MessageFormat.
 467  
                 format(Translator.localize("label.todopane.items"),
 468  
                        new Object[] {
 469  
                            Integer.valueOf(size),
 470  
                        });
 471  
         }
 472  
     }
 473  
 
 474  
     /**
 475  
      * Update the count label.
 476  
      */
 477  
     public void updateCountLabel() {
 478  2126
         int size = Designer.theDesigner().getToDoList().size();
 479  2126
         countLabel.setText(formatCountLabel(size));
 480  2126
         countLabel.setOpaque(size > WARN_THRESHOLD);
 481  2126
         countLabel.setBackground((size >= ALARM_THRESHOLD) ? ALARM_COLOR
 482  
                                   : WARN_COLOR);
 483  2126
     }
 484  
 
 485  
     /**
 486  
      * Update the todo tree.
 487  
      */
 488  
     protected void updateTree() {
 489  2700
         ToDoPerspective tm = (ToDoPerspective) combo.getSelectedItem();
 490  2700
         curPerspective = tm;
 491  2700
         if (curPerspective == null) {
 492  900
             tree.setVisible(false);
 493  
         } else {
 494  1800
             LOG.debug("ToDoPane setting tree model");
 495  1800
             curPerspective.setRoot(root);
 496  1800
             tree.setShowsRootHandles(true);
 497  1800
             tree.setModel(curPerspective);
 498  1800
             tree.setVisible(true); // blinks?
 499  
         }
 500  2700
     }
 501  
 
 502  
     /**
 503  
      * Called when the user clicks once on an item in the tree. <p>
 504  
      *
 505  
      * Q: What should the difference be between a single
 506  
      * and double click? <p>
 507  
      * A: A single click selects the todo item in the tree,
 508  
      * shows the red indication on the diagram,
 509  
      * and selects the todo tab in the details panel.
 510  
      * A double click additionally
 511  
      * selects the offender in the explorer,
 512  
      * and selects the offender in the diagram (blue selection),
 513  
      * and selects the properties tab in the details panel.
 514  
      * In both cases, the focus (for keyboard actions) remains in the todo tree.
 515  
      *
 516  
      * @param row the selected row in the tree
 517  
      * @param path the path in the tree of the selected item
 518  
      */
 519  
     public static void mySingleClick(
 520  
             @SuppressWarnings("unused") int row, 
 521  
             @SuppressWarnings("unused") TreePath path) {
 522  0
         clicksInToDoPane++;
 523  0
     }
 524  
 
 525  
     /**
 526  
      * Called when the user clicks twice on an item in the tree.
 527  
      * myDoubleClick will invoke the action() on the ToDoItem.
 528  
      *
 529  
      * @param row the selected row in the tree
 530  
      * @param path the path in the tree of the selected item
 531  
      */
 532  
     public void myDoubleClick(
 533  
             @SuppressWarnings("unused") int row, 
 534  
             @SuppressWarnings("unused") TreePath path) {
 535  0
         dblClicksInToDoPane++;
 536  0
         if (getSelectedObject() == null) {
 537  0
             return;
 538  
         }
 539  0
         Object sel = getSelectedObject();
 540  0
         if (sel instanceof ToDoItem) {
 541  0
             ((ToDoItem) sel).action();
 542  
         }
 543  
 
 544  
         //TODO: should fire its own event and ProjectBrowser
 545  
         //TODO: should register a listener
 546  0
         LOG.debug("2: " + getSelectedObject().toString());
 547  0
     }
 548  
 
 549  
     /**
 550  
      * The perspectives to be chosen in the combobox are built here.
 551  
      */
 552  
     private static List<ToDoPerspective> buildPerspectives() {
 553  
 
 554  900
         ToDoPerspective priority = new ToDoByPriority();
 555  900
         ToDoPerspective decision = new ToDoByDecision();
 556  900
         ToDoPerspective goal = new ToDoByGoal();
 557  900
         ToDoPerspective offender = new ToDoByOffender();
 558  900
         ToDoPerspective poster = new ToDoByPoster();
 559  900
         ToDoPerspective type = new ToDoByType();
 560  
 
 561  
         // add the perspectives to a list for the combobox
 562  900
         List<ToDoPerspective> perspectives = new ArrayList<ToDoPerspective>();
 563  
 
 564  900
         perspectives.add(priority);
 565  900
         perspectives.add(decision);
 566  900
         perspectives.add(goal);
 567  900
         perspectives.add(offender);
 568  900
         perspectives.add(poster);
 569  900
         perspectives.add(type);
 570  
 
 571  900
         PerspectiveSupport.registerRule(new GoListToDecisionsToItems());
 572  900
         PerspectiveSupport.registerRule(new GoListToGoalsToItems());
 573  900
         PerspectiveSupport.registerRule(new GoListToPriorityToItem());
 574  900
         PerspectiveSupport.registerRule(new GoListToTypeToItem());
 575  900
         PerspectiveSupport.registerRule(new GoListToOffenderToItem());
 576  900
         PerspectiveSupport.registerRule(new GoListToPosterToItem());
 577  
 
 578  900
         return perspectives;
 579  
     }
 580  
 
 581  
     /**
 582  
      * The UID.
 583  
      */
 584  
     private static final long serialVersionUID = 1911401582875302996L;
 585  
 }