The PSP Tools User Interface


The PSP Tools User Interface

Developing a user interface is its own special art. There are many guidelines and standards to follow, some of them contradictory when you develop for multiple platforms. Neither Chris nor Gary is an expert user interface designer. However, we have had some training on what makes a usable UI and applied that knowledge to the PSP Tools user interface. This section describes some of the challenges and our approach to designing the UI.

The User Interface Ripple Effect

On most projects, the UI will go through several iterations and revisions before it is ready to ship. These continual changes have two significant consequences.

First, UI changes can affect your testing effort. If your test scripts are executed manually, they are very susceptible to simple changes in the UI. For example, if the text of a menu item or button changes, the test script must be changed so the tester knows which selection to make or button to push. Keeping the tests in synchronization with the code can be time consuming.

If you are using automated test tools (and we highly recommend that you do), you need to make sure that you design your tests in such a way that cosmetic changes to the UI require little or no change to the tests. This often means that you need to do more than use a record-playback testing tool. You need to read the script that the tool produces to ensure that it accommodates changes to the UI in the best possible way. Sometimes it is better to write the test script without recording the initial test gestures. In any case, the test tool you use should work on the specific objects in a way that does not identify the object by the text on a label or some other textual or positional property of the object.

The second item that is affected by UI changes is the documentation. When the text of a visible item on the screen changes, the documentation may require an associated change. When you move, add, or remove items on the screen, the screen shots that you might want to include in the documentation immediately become obsolete.

These self-defense tips will help you avoid many last-minute documentation changes:

  • Negotiate with the project leader to establish a UI freeze date that's earlier than the documentation and code freeze dates. Even if you agree to a week-long grace period, that gives you enough time to catch and correct last-minute changes. This technique also helps raise engineers ' awareness of the impact of UI changes on your work.

  • Write in a top-down fashion, starting with organization, then working on use cases, and writing the conceptual information. Fill in the details about using the user interface as late as possible in the project.

  • Minimize your use of screen shots, using them for significant milestones in long procedures or to visually describe a procedure that's difficult to explain in words. When you do use screen shots, capture only the relevant portion of the screen, not the entire screen or desktop.

  • Work closely with the QA team. Because the documentation and the tests should be based on use cases, your documentation can serve as one of the test cases for the product. In return, it is helpful to ask testers to review your work. This collaboration helps both the writers and the testers work more efficiently because it eliminates duplicate work. More importantly, your customers benefit by receiving a more bug-free product with more accurate documentation.

  • Maintain a sense of humor and an attitude of flexibility. You can minimize last-minute changes but you can't eliminate them entirely.

Our First UI

The Elaboration Iteration Plan identified the use cases and scenarios we planned to implement: Create a New Task and Open the Project Database. We were most concerned with the code in the control and logic and in the persistent data layers. We felt the highest risks to the project's success were in the code in these layers . But we had to show the complete sequence of operations, so we could not completely ignore the UI.

We had an idea of what we wanted the application to look like (see Figure 6.6), but we were unsure about the details. For the Elaboration phase we deferred these details and only created enough of the UI to show that we had successfully implemented the planned functionality. The user interface we created early in the Elaboration phase is shown in Figure 7.3.

Figure 7.3. UI early in the Elaboration phase

graphics/07fig03.jpg

The UI in Figure 7.3 is not suitable for delivery to customers. It has just one menu, usually a sign that the full functionality is not implemented, or that it is a very simple application. Further, the tabbed panes take up too little space in their enclosing pane. The text fields are not large enough to display much information. We were not sure what the tree in the left pane would look like, but at this point we thought there would be separate folders in the tree for tasks , time entries, and reports . If you take a moment to think about what we needed, this UI required more work. We needed to show defects. And, in general, it is not clear what you can or cannot do by just looking at this UI. Yet, there is enough of a framework for the UI that we could build upon it and modify it easily.

Exploring the UI Code

There are a few Java Swing components that are key to understanding the structure of the user interface. If you are an experienced Java programmer, you can probably skip to the end of this section, but for those of you who are new to Java, or to Swing, you will find our explaination helpful for exploring the code on your own. The key Swing components for the main PSP Tools window are shown in Figure 7.4.

Figure 7.4. Key Swing items in the PSP Tools main window

graphics/07fig04.jpg

We began developing the user interface with the GUI builder from the Forte IDE. While it was easy to create the components and make them work, we found that the generated code wasn't always easy to understand, making it difficult to modify when we were not working with the GUI builder. We also found places where dependencies on Forte libraries were inserted into the code. Even before we decided to switch to the Eclipse IDE, we began writing our UI code without resorting to the GUI builder.

Creating and composing the Swing components identified in Figure 7.4 involved more than just creating objects and gluing them together. Each component requires initialization and customization. When we refactored and rewrote the code to remove the GUI builder dependencies, we made sure that each constructor called an initialize method that did the work of initialization and customization. The initialization for the JFrame, which is in our class PSPMainFrame , is shown in Listing 7.1. [3]

[3] The code you can download from the book's Web site may look slightly different. Chris and Gary planned on making a final review and refactoring pass through the code before packaging it for the site.

Listing 7.1 PSPMainFrame initialization code
 /**       * Initialize the frame by setting default behaviors such       * as the default close operation, and so on.       */  private void  initializeFrame()      {             setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);             setTitle(APP_TITLE);             setupMenus();             setJMenuBar(menuBar);             addWindowListener(  new  WindowAdapter()                 {  public void  windowClosing(WindowEvent evt)                     {                          doFileExit();                     }                });  int  width = PSPUserPrefs.getWidth();  int  height= PSPUserPrefs.getHeight();  if  (width == 0  height == 0)                { setBounds(INITIAL_X, INITIAL_Y, INITIAL_WIDTH,  INITIAL_HEIGHT);                }  else  {                setBounds(INITIAL_X, INITIAL_Y, width, height);                }           mainPanel =  new  JPanel();           /*            * DO NOT remove the next line. It seems to do nothing, but            * it is necessary to get the pane into memory.            */           JRootPane rootPane = getRootPane();           getContentPane().add(createSplitPane(),                 BorderLayout.CENTER);      } 

Notice that the code only creates the split panel. The tree and the tabbed panes are not built. They will be added to the left and right sides of the split panel when a database is opened or created.

One technique we used consistently is shown in Listing 7.1, where we add the window listener. We need to add an instance of the WindowAdapter class to the set of listeners attached to the window. This enables us to recognize when the user clicks the close box in the upper right corner. The default behavior is to simply exit the application and close the window and any of the window's children. We want to override this behavior by calling the doFileExit() method [4] to gracefully exit the program when the window closes .

[4] The name doFileExit follows a naming convention we use for methods that are called from menu selections. In this case, the name tells us that this is the Exit command selected from the File menu.

We only need one instance of this specific window adapter class. Rather than creating a separately named class, the Java language lets us create an anonymous class . The anonymous class is declared inline as shown. The only method we need to override is the windowClosing() method, which we declare in the anonymous class definition.

The PSPMainFrame.java file contains quite a bit of code since it is the main interface for the PSP Tools user. Most of the code, especially the code developed during the Elaboration phase, is not very interesting. After the frame is initialized , the main frame waits for the user to do something by interacting with it. This interaction occurs in one of the following ways:

  • Making a menu selection

  • Clicking on an item in the tree, if a tree is displayed in the left panel

  • Closing the window and exiting the program through the close box

  • Selecting a tab in the tabbed panel, if one is displayed

  • Entering data from the keyboard into one of the fields in a panel

There are other gestures the user might make, such as minimizing and restoring a window, but these are handled directly by the Swing class instances and require no intervention on the part of our code.

We use a simple approach to handling menu commands. We have an ActionListener class object attached to each menu selection. The ActionListener is responsible for "listening" to what is happening in the application, and when the event that it is listening for occurs, it invokes some action. We install the ActionListener when we create the menu command. The menu commands are created when we set up the menus . The third statement in the method in Listing 7.1 calls the setupMenus() method, which is shown in Listing 7.2.

Listing 7.2 Setting up the PSP Tools menus
 /**  * Set up the menus for the application.  */  private void  setupMenus() {      menuBar =  new  JMenuBar();      menuBar.add(createFileMenu());      menuBar.add(createProjectMenu());      menuBar.add(createToolsMenu());      menuBar.add(createHelpMenu()); } 

It is easy to add a new menu to the main menu bar. You add a method to create the menu and add the returned menu to the menu bar. The more interesting code is in the methods that create the menus. They are the ones that create the specific action listeners. Listing 7.3 shows the section of code in createFileMenu() that adds the menu item for opening a project database. All of the menu items are added in a similar fashion.

Listing 7.3 Adding the Open item to the File menu
 // Open Project Database JMenuItem fileOpen =  new  JMenuItem("Open..."); fileOpen.setMnemonic('O'); fileOpen.addActionListener(  new  ActionListener()      {  public void  actionPerformed(ActionEvent evt)           {                doFileOpen(  null  );           }      }); fileMenu.add(fileOpen); 

The sequence we use to add an item to a menu is as follows:

  1. Create the new JMenuItem with the appropriate label.

  2. Set the mnemonic (that is, the key that is used with the system-specific "mouseless modifier"usually Alt) to select the menu item.

  3. Add the action listener, using an anonymous class.

  4. Add the menu item to the appropriate menu.

We will close this section by providing an insight to the tree that appears in the left pane of the UI. Trees are very powerful and provide a visual model that users are familiar with. We often see file systems presented in a tree form. Trees in Java require the programmer to know a little more than most of the other Swing components. However, if you just need to perform standard tasks with your tree, Java makes life a little easier for you. We chose the easy way, shown in Listing 7.4. The "easy way" means that you use a default tree model, which is sufficient for modeling the tree node behavior and appearance for most applications.

Listing 7.4 The PSPTree constructor
 /**       * Default constructor.       */  public  PSPTree()      {  super  ();           model =  new  DefaultTreeModel(rootNode);           setModel(model);           getSelectionModel().setSelectionMode(                  TreeSelectionModel.SINGLE_TREE_SELECTION);           putClientProperty("JTree.lineStyle", "Horizontal");           setShowsRootHandles(  true  );           //Listen for RMB clicks           addMouseListener (myMouseListener);           //Listen for when the selection changes.           addTreeSelectionListener(  new  TreeSelectionListener()           {  public void  valueChanged(TreeSelectionEvent e)                {                     DefaultMutableTreeNode node =           (DefaultMutableTreeNode)getLastSelectedPathComponent();  if  (node ==  null  ) {  return  ;                     }                     Object nodeInfo = node.getUserObject() ;  if  (nodeInfo  instanceof  Task) {                          (Task)nodeInfo.setTopTab(                                getRequestedTab());                          JPanel newPanel =                          ((Task)nodeInfo).getPanel(nodeInfo);                          ((PSPMainFrame)getTopLevelAncestor()).                                setRightPane(newPanel);                          ((PSPMainFrame)getTopLevelAncestor()).                                setMenuFor(PSPMainFrame.PSP_TASK);                          ItemID = ((Task)nodeInfo).getTaskID();                          tm =  null  ;                     }  else if  (nodeInfo  instanceof  PSPTimeSummary){ // ... } else if                     (nodeInfo  instanceof  PSPDefectSummary) {                          // ...                     }  else  {     // this is the Root Object                          // ...                     }                }           }); 

We will populate the tree after we create it. The constructor shown in Listing 7.4 creates an empty tree that has a default tree model. Trees, like many other graphical objects in Swing and other graphical frameworks, have a separate data model for which the graphical object provides a view on that data. A JTree object ( PSPTree is a subclass of JTree ) requires a model that is a class implementing the TreeModel interface. If you want standard behavior, which we do, you can use the DefaultTreeModel , which is defined in the Swing framework. We need to set the property in the tree model that ensures that only a single item in the tree can be selected at any time.

We finish the constructor by adding a listener that is a TreeSelectionListener . This object listens for events, such as mouse clicks that select a tree item, and takes appropriate action. In our constructor, we look to see if the node is a task, time summary, or a report. For formatting purposes, we inserted comments instead of code where there are repetitive types of code segments. The final version of PSPTree looks different since we reorganized and refined the UI.

The PSPTree class has several methods that handle the actions invoked by the tree selection listener. If you want to understand how the tree is structured, study the loadTasks() method. When a project database is open, this method is called. It asks the database object to return the items (tasks) for the current user, and these are added individually to the tree with the proper structure. The root node of the tree is kept as a private variable in the PSPTree instance.

There is a lot more code to the PSP Tools UI than we have shown here. But this is not a book on Java. There are several books available that can help you to get better information than we can provide here. We want to give you a feel for the code so that you can explore for yourself and understand it enough to begin to modify it for your own needs.



Software Development for Small Teams. A RUP-Centric Approach
Software Development for Small Teams: A RUP-Centric Approach (The Addison-Wesley Object Technology Series)
ISBN: 0321199502
EAN: 2147483647
Year: 2003
Pages: 112

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net