to Design and Write Java Programs with UML. A Masters Thesis ... Difficulties of
Teaching Students Object-Oriented Design and Programming ............................6.
••••••••••
Java-
DACTL: A Tool for Teaching Novice Programmers to Design and Write Java Programs with UML
A Masters Thesis Submitted to the Faculty of the School of Computer Science and Information Systems in Partial Requirement for the Degree of Master of Science
By Anna S. Armentrout Advisor Dr. Joseph Bergin Pace University Department of Computer Science
New York, NY August 31, 1999
Contents Introduction...................................................................................................................................4 Difficulties of Teaching Students Object-Oriented Design and Programming ............................6 The Overall View is More Important than the Details .....................................................7 Use Realistic Examples to Explore Design ......................................................................9 Relate the Design to the Implementation..........................................................................9 Show Students Many Examples of Design.....................................................................10 The Importance of UML.............................................................................................................11 Why Java?...................................................................................................................................12 A Description of Java-DACTL...................................................................................................13 General Description of Java-DACTL .............................................................................13 Technical Description of Java-DACTL Design ............................................................16 Conclusion and Future Work......................................................................................................18 Works Cited ................................................................................................................................21 Illustrations .................................................................................................................................23 Figure 1. Whole Screen View of Project................................................................23 Figure 2. Open/Save Document Interface ..............................................................24 Figure 3. Use Case Form........................................................................................25 Figure 4. Use Case Diagram ..................................................................................26 Figure 5. CRC Form...............................................................................................27 Figure 6. Class Diagram.........................................................................................28 Figure 7. Code Generation Window ......................................................................29 Figure 8. Code Files ...............................................................................................30 Code ............................................................................................................................................31 ActorButton.java ............................................................................................................31 ActorFigure.java .............................................................................................................31 BaseFrame.java...............................................................................................................32 BaseInternalFrame.java ..................................................................................................32 ClassDiagramCanvas.java ..............................................................................................33 ClassDiagramWindow.java ............................................................................................40 ClassForm.java ...............................................................................................................40 ClassObject.java .............................................................................................................57 ClassToolBar.java...........................................................................................................58 CodeGenerator.java ........................................................................................................59 CodeWindow.java...........................................................................................................62 ConnectButton.java ........................................................................................................63
Connection.java ..............................................................................................................63 ControlWindow.java.......................................................................................................64 DiagramCanvas.java .......................................................................................................74 DiagramToolBar.java .....................................................................................................78 DiagramWindow.java .....................................................................................................78 Figure.java ......................................................................................................................80 LabelChange.java ...........................................................................................................82 LifelineButton.java .........................................................................................................82 MoveButton.java ............................................................................................................83 OvalButton.java ..............................................................................................................83 OvalFigure.java ..............................................................................................................83 ProjectModel.java...........................................................................................................84 ProjectMutableTreeNode.java ........................................................................................85 ProjectTree.java ..............................................................................................................86 ProjectTreeModelListener.java ......................................................................................94 RectangleFigure.java ......................................................................................................94 ResizeButton.java ...........................................................................................................95 SequenceDiagramCanvas.java........................................................................................95 SequenceDiagramWindow.java....................................................................................102 SequenceToolBar.java ..................................................................................................102 SquareButton.java.........................................................................................................103 SystemRectangleFigure.java ........................................................................................103 TextButton.java ............................................................................................................104 ToolButton.java ............................................................................................................104 Update.java ...................................................................................................................105 UseCase.java.................................................................................................................106 UseCaseDiagramCanvas.java .......................................................................................107 UseCaseDiagramWindow.java .....................................................................................122 UseCaseForm.java ........................................................................................................122 UseCaseToolBar.java ...................................................................................................132
5
Introduction It is a matter of some recent controversy among teachers of CS1 courses whether objects can or should be taught early–before implementation principles. My project supports the view that objects and object-oriented design should be taught early, that is, in the student’s first programming class. The result of this project is a tool called Java-DACTL (Java Design, Analysis and Coding Tool). Java-DACTL is a simple program which allows beginners– students learning object-oriented design and programming for the first time–to use a modified (i.e., simplified) version of Unified Modeling Language (UML) to design and begin coding programs.
This tool is meant to be used by students who are participating in a class with an instructor. As beginners, these students lack an understanding of the peculiarities of objects, design, and possibly even programming. With a little guidance from the instructor, the students could begin using Java-DACTL to make simple program designs. A little later in the course, JavaDACTL helps the instructor to graphically illustrate the connection between design and implementation by generating skeleton code based on students’ designs. Java-DACTL helps introduce the student to the subtleties of object-oriented programming (OOP) while enforcing the importance of good design.
Java-DACTL allows programs to be designed using UML. UML is a recently developed modeling language intended to be the standard for designing object-oriented systems. UML is a powerful modeling language that, in its actual form, is much more complex than the
6 simplified version that is used in Java-DACTL. It makes sense, however, to use UML as a basis for Java-DACTL so that students are introduced to the very modeling language that they will probably be using in their future work. UML allows the student to approach designing a program from the top down, first specifying use cases, then finding objects, and eventually defining details like object interactions and member variables. In addition to UML, JavaDACTL also uses the Class-Responsibility-Collaboration (CRC) card model. CRC cards are useful because they remind the student what needs to be defined for each class, and they act as a repository for this information. CRC cards also allow more information to be provided about each class, resulting in more detailed skeleton code produced by the tool.
Java-DACTL was written in Java and produces skeleton code in Java. Java is a good language for learning object-oriented design. Java is a simple language that is authentically objectoriented and handles a number of important things (checking, pointers, garbage collection) automatically that are difficult to implement and often the source of bugs in C++. In theory, however, this tool can easily be modified to produce skeleton code for any object-oriented language, by substituting a code generator for that language.
This tool designed to be simple to use and easy to navigate. My goal was to produce a tool that could be used right away by the students, so that the time spent learning design and programming would be maximized. Java-DACTL includes several project views, menu keyboard shortcuts, and an intuitive interface. One advantage of this tool over a Computer Assisted Software Engineering (CASE) tool for use in teaching is that it is very simple and
7 quickly learned. There are some additions and improvements that would need to be made to Java-DACTL to make it a really complete tool for teaching first year programming students. A more complex class diagraming ability and the ability to make sequence diagrams, which would show messages being passed between objects in the program being designed, would allow better skeleton code to be produced. Moreover, the code-generation process would be improved so that it could be performed in reverse. This way a large, complex program, what Dr. Bergin calls a Larger Than Life (TJOE, 4), could be given to the students to study, improve or revise. The student would be able to use Java-DACTL to generate diagrams from the Larger Than Life code to see its structure. As it exists now, the tool is fairly simple yet powerful and robust. I hope Java-DACTL will prove useful for teaching novice programmers.
Difficulties of Teaching Students Object-Oriented Design and Programming
The problem of teaching object-oriented design has been discussed and debated frequently in recent years. A workshop at the OOPSLA ‘96 Conference, “Teaching and Learning Object Design in the First Academic Year”(Mercer), addressed this issue in detail. During this workshop Alistair Cockburn did an experiment which involved “coaching” six first year computer science students in design for a couple of hours, then having the students present their designs to the workshop participants. This experiment proved surprisingly successful, with the students producing “the best design [Cockburn] had yet seen, one that none of his industry groups had managed to reach,” according to the workshop report (Mercer, 4).
8 Clearly the success of Cockburn’s experiment indicates that object-oriented design (OOD) can be taught early. Those who are against early teaching stress (or at least feel strongly about) the student’s lack of readiness. The student, they argue, will be confused by the peculiarities of OOD without a background in implementation, and this initial confusion would become a hindrance to her subsequent computer education. The students in Cockburn’s experiment, however, claimed to find “what they knew about programming to be a hindrance,” mentioning “being distracted by thinking about parameter passing” as one example (Mercer, 5). Lack of readiness in the student doesn’t seem to be the issue. Rather the pedagogical question should not rest with the possible status of the student but with the form of the CS1 course itself. In other words, what is at issue is the readiness of the class, its structure and tools, and not of the student. So again: OOD can be taught early and effectively once the existing style of the CS1 course is revised to accommodate the peculiarities of object technology.
There are at least four basic ideas about how to change the CS1 course to effectively teach OOD to beginners. These ideas are (1) emphasize that the overall view is more important than the details; (2) use realistic, real world contexts to address design; (3) relate the structure or design of a program to the implementation in a way the student can understand; and (4) show students many examples of design. In what follows I will describe these ideas and show how my project works with these ideas.
9 The Overall View is More Important than the Details
It is important that beginning students understand the importance of the design over the details of the implementation. Any attempt at teaching objects “should proceed from the top down– from overall design to low-level detail” (Bergin, TJOE, 5). This concept becomes particularly important later, when the student is designing and programming large systems. As M.E. Evans puts it in his paper to the OOPSLA ‘96 workshop: “...in real-world design, issues of a macroperspective which emphasize the architectural organization and structural connections between and among identified components are of significantly more importance than those of the micro-design perspective” (Evans, 1). These ideas are easily demonstrated to students. When one student participating in Cockburn’s experiment complained of the difficulty of making design decisions, “[t]his question was ... posed: ‘Do you think it is better to make these decisions now rather than after 30,000 coffee machines were distributed around the country?’ The students nodded yes” (Mercer, 5). In other words, isn’t it more important to work through the difficulties of a particular problem at the beginning, rather than jump into an implementation that could be problematic?
Java-DACTL helps to emphasize the importance of design over implementation. It makes designing and design revisions easier for the student. It also allows a more extended focus on design, by providing a skeleton code generator, so that the student can go straight from her design to her implementation. In addition, Java-DACTL dramatically illustrates the secondary nature of implementation, as the implementation is automatically generated from a student’s
10 design, whereas the creative problem solving really occurs in the design phase.
Use Realistic Examples to Explore Design
It is fairly obvious that students will grasp design concepts much faster if the concepts are explained and experienced in the context of a real world example that the students can understand. At OOPSLA, “[t]here was strong agreement that design should be addressed in realistic contexts.” (Mercer, 7). The scale of this example must be sufficiently complex, so that the design solution is not immediately obvious. M.E. Evans states that “the identification of qualities of good design, and an understanding of applicable design tools can only be appreciated by studying “large, meaningful” problems” (2). It is not useful to choose an example that would involve only one or two objects, as this is not realistic. Such a small scale problem only demonstrates to the students that attempting to design a solution to a problem when the implementation of the solution is so apparent is a waste of time.
The only difficulty with introducing such a realistic and meaningfully complex problem to a class of OOD beginners is the risk of intimidating the students. Java-DACTL helps to ease this intimidation by allowing the student to approach the problem gradually, from the top down. The tool is also helpful in that it saves all of the student’s classes and use cases in one place, allowing the student to revise and improve her design over time. The experience of grappling with a realistic problem in this manner gives the student confidence as well as understanding of OOD.
11 Relate the Design to the Implementation
In order to gain a sense of purpose while executing a design, the student must understand the relationship between the design and the implementation. Students need to understand “how the details are derived from the principles” (Mercer, 6), in other words, how the implementation is derived from the design. Fortunately, “there is much less of a cusp in TO (Object Technology) between analysis/design on one hand and implementation on the other” (Bergin, TJOE, 3). The design of object-oriented programs is very closely related to the actual code of object-oriented programs.
In order to demonstrate this relationship, “[s]tudents must see the system’s logic from above and they must see the outcome of their work, that is to say the running program” (Angster 1). Java-DACTL very clearly illustrates this relationship by beginning the implementation process for the student based on the student’s design. The student can compare her design with the resulting skeleton code and understand how different elements of the design fit into the code.
Show Students Many Examples of Design
Students will often get stuck in a pattern of thinking and find it difficult to imagine more than one solution to a problem. It is helpful to show the student a number of solutions to one problem to get the student to think more creatively. This practice will make the students better designers: “Appreciation and development of good design is enhanced via the study of
12 alternative designs for the same product” (Evans, 2). One way of doing this is to have individual students or small groups of students come up with designs for the same problem, and present their designs to the class. If Java-DACTL is being used as a design tool in the class, solutions to a common problem can be demonstrated using a common medium (the tool), and the differences in actual solutions can be highlighted. Java-DACTL can also save particularly good solutions from one class so that it can be shown to later classes.
Java-DACTL is an attempt to address the specific concerns of teaching and learning OOD. Within the class setting, the tool mediates helpfully between the respective roles of the teacher and the student. Java-DACTL gives students practice in thinking from a macro-perspective. It helps the instructor approach OOD from the top down; helps the student to attempt to solve a real design problem; it helps the teacher more explicitly explain–and the student to understand–the relationship between the design and the implementation; and it can help the instructor to build a library of design examples to show to the student. With certain modifications in the tool, such as improved diagraming ability, Java-DACTL could be used by students in higher levels to speed the process of making a design and starting its implementation.
The Importance of UML
Modeling languages are useful because of their universality; they allow design ideas to be communicated to other programmers and archived for future reference or revision. Students
13 learning design will also need to communicate their design ideas, and so will need to use some sort of modeling language that is at least recognized and understood throughout the class. Java-DACTL is based on the modeling language UML. UML was developed from a number of popular object-oriented modeling methodologies (Booch, OMT-2, OOSE), with the intention that it would be the standard for modeling object-oriented systems. UML allows the design of a system to be approached from a number of different views, each view further defining some aspect or detail of the system as a whole. The sum of the views seen together describe the system as a whole. UML is also useful through different phases of systems design, from the initial analysis through implementation and revision. The decision to use UML in Java-DACTL was based on the idea that, as Bergin writes: “Students need to be able to design their programs–somehow. They may as well learn a technique into which they can grow” (TOOAD, 1).
For the sake of beginners, Java-DACTL uses a simplified version of UML. This tool is meant to be easy to use, and a design tool that implements all of UML, like Rational Rose, is not easy to learn or use. The UML concepts used in this tool can be quickly grasped by students. Meanwhile, by using part of UML they are making progress towards developing an essential competency in a modeling language that will most likely be important to them in the future.
Why Java?
14 Java is an excellent object-oriented language for beginners. Java is a simple language, yet powerful and robust. As a true object-oriented language it is superior to C++, which is developed from non-object C, and must be somewhat backwards compatible. C++ is a more difficult language than Java, and as certain OOD principles are not easily transferred to C++, “C++ is probably not the best language for a CS1 design course” (Evans, 3). The simplicity of Java means that the instructor can spend more time on design, and the student can pick up much of the implementation on her own. Java-DACTL is written in Java because of its other nice qualities, like platform independence. It is not vital, however, that Java be taught with Java-DACTL. Any good object-oriented language can be taught, once a code generator for that language has been written and substituted for the Java generator.
A Description of Java-DACTL
In the previous sections of this paper I have tried to show how Java-DACTL could be useful, and to explain why it is based in certain technologies. This section will be a description of the tool in general, followed by a more technical description of how Java-DACTL was put together. General Description of Java-DACTL
Java-DACTL enables students designing object-oriented programs to (1) analyze the problem at hand and work out how to attack it; (2) flesh out a design, based on classes and objects; (3) begin implementation by generating Java skeleton code from the finished design. Java-
15 DACTL is intended to be simple and easy to use because “time spent on learning CASE tools, notation, methodologies, and so on is time taken from topics in computer science that must be taught as necessary background in computer science” (Astrachan, 4). Because of the intuitive interface of Java-DACTL, a short introduction to UML and CRC cards by the instructor should be all that is required for the student to be on her way to designing an object-oriented program with this tool (Fig. 1).
The student starts by either opening a previously saved project or creating a new project (Fig. 2). Once a project is open, a tree appears on the left of the screen with the project name at the top and a list of the project’s existing use cases and classes below. This affords the student a handy overview of the project that is being worked on. The student can then choose to work in one of four views: she can fill in use case (Fig. 3) or CRC card (Fig. 5) forms or she can make use case (Fig. 4) or class diagrams (Fig. 6). The student can also change the names of the various objects or the project itself in the tree view.
To work in a particular view the student must select the menu item from the project menu or type its menu shortcut key. In order to maximize screen real estate, each view has its own window. These view windows appear on the right side of the interface (Fig. 1). The student can have as many or as few views open as a time as she desires. The student is able to switch back and forth easily between the views. Clicking on a view that is already displayed brings that view to the top. When the student enters or changes information for any one of the views, the tool updates the equivalent information for the other views. For example, if the name of a
16 class is changed in the tree view, the class name is automatically updated in the class diagram view and in the corresponding CRC card.
Each of the two diagraming views has its own specialized diagraming tools, which help the user to make “legal” diagrams. Figures in both of the diagram views can be moved, resized, deleted (either permanently or with “cut”) and restored (with “undo”). There is also a feature which prevents the user from accidentally drawing a figure so small that it can’t be selected and deleted (a common problem when I was testing the system). The form views also perform certain checks. To prevent the duplication of information in a project–for example, entering the same class multiple times into the system–the two form views supply lists of previously entered names, and will not add a new item with the same name as an old item; rather if an attempt is made to add a same-name item, the old item is selected. The two pairs of formdiagram views work together. Any use case that is drawn in the diagram view will appear in the use case form view as a new use case form. If a name for the use case is typed in the “name” field of the use case form, this name is added to the figure in the diagram view as a label. In this way, the user has a consistent view of the whole program being designed at all times.
When the student is satisfied with her design, she can generate Java skeleton code by choosing the “Generate Code” menu item (or shortcut key). A code generation window (Fig. 7) is opened by the tool. This window displays messages which describe what is happening while the skeleton code is being generated. The tool generates a separate *.java file for each class in
17 the design (Fig. 8), which it saves in a location that was selected by the student. The student can then save her design to be reopened and possibly modified at a later time, and begin to program by filling in the skeleton code.
Technical Description of Java-DACTL Design
As with all programs, Java-DACTL depends on contributions from a number of difference sources. These range from course work to textbooks. The earliest contributor was Bergin’s Java class CS631N, which emphasized object-oriented design. In this class students learned to “document ... object interactions with simple diagrams and with CRC cards. These simple diagrams can use a visual syntax taken from OO modeling tools, though in a simplified form” (Bergin, TJOE). As noted above, Java-DACTL is based on a simplified form of UML and CRC cards.
The “seed code” of the tool was the applet PaintDrawApplet from Bergin’s paper “Graphical User Interface Programming for Multi-Platform Applications.” At one point in this paper, Bergin speculatively assigns a project to his intended reader: “Learn about the Unified Modeling Language (UML), which is a graphical technique for designing object oriented software. Build me (in Java) a simple UML modeling tool” (GUIPMPA, 3:11). Java-DACTL is more or less the resulting product of this assignment.
More detailed requirements of such a modeling tool were provided by the technical discussion
18 in UML Toolkit. There the specific functions which any “modern CASE tool should provide” in order to be complete are specified. These functions are:
•
Draw diagrams ...
•
Act as a repository: ... If the name of a class is changed in one diagram, the change must be replaced in all other diagrams in which the class is used.
•
Support navigation: The tool should make it easy to navigate the model
[...] •
Generate code: An advanced tool should be able to generate code, where all the information in the model is translated into code skeletons that are used as a base for the implementation phase.
[...] •
Cover the model at all abstraction levels: The tools should be easy to navigate from the top-level description of the system ... down to the code level. (Erikksson, 34-36)
As described previously in this paper, Java-DACTL was built following these very helpful design guidelines.
The actual implementation of Java-DACTL was achieved using the Model-View-Controller pattern, which allows for a great deal of flexibility in how information is displayed to the user and stored in the system. The model acts as a repository for information for the current project and is not influenced by the mode of display. Because of the model’s independence the design
19 can be viewed or updated by the user in any one of five views, and any changes are reflected in each of the other views. Similarly, the model is not influenced by the kind of code that is generated from the finished design. Java-DACTL is capable of displaying information in a number of views quite easily, because of the fact that the model for each of the views is the same, and the views each “know” how to display the information in the model that is relevant to them.
In developing this project I adopted the method set forth in Bergin’s CS631N. The project, therefore, evolved in three stages, namely: Analysis, Design, and Implementation. In the initial Analysis and Design phases I had a poor understanding of who would eventually be using this tool, so it was difficult, at first, to understand what I was really trying to build. It is rather surprising that my initial scoping document is not all that different from the implementation that eventually evolved. The implementation phase took slightly longer that planned, which as we know is the norm in writing software, though the implementation itself was not terribly difficult. A few interruptions contributed to the delay in developing this project. One of these interruptions was the ITiCSE conference in Cracow, which I attended with Dr. Bergin and Al Rossi, to present a poster on this project. The conference was quite helpful in giving me an understanding of how Java-DACTL could be useful to instructors teaching object-oriented programming.
Conclusion and Future Work
20 As it exists now, Java-DACTL is a simple, flexible tool for teaching CS1 students objectoriented design and programming. This tool encourages a top-down approach, and could be an enhancement to patterns already used in teaching objects. In order to be a truly complete beginner’s design tool, however, there are a few additions that should be made to JavaDACTL. These additions would include the ability to print each of the views, and the ability to draw diagrams and make CRC cards from existing code. Another addition that would make the tool more powerful, which was mentioned above, is a more complex diagraming ability.
It would be fairly simple to add the printing capability to Java-DACTL. Students would be able to print diagram windows and detailed lists of use cases and CRC cards, in a presentable format. This would allow students to painlessly produce a design document from Java-DACTL that could be submitted to the instructor. This capability is desirable because ordinarily “students will resent producing such a document, mostly because the document doesn’t help solve the problem or write the program” (Astrachan, 3). In this case, producing the design document with the tool does help solve the problem and write the program.
The UML Toolkit includes among the requirements for a complete CASE tool “Reverse engineer: An advanced tool should be able to read existing code and produce models from it. Thus a model could be made from existing code; or a developer could iterate between working in the modeling tool and programming” (Erikksson, 35). In the case of Java-DACTL, adding a reverse engineering capability would be useful because an important OO teaching pattern, Readers-Writers, is based on the idea “that students can read and learn from artifacts more
21 complex than they can build” (Bergin, TJOE). The student would be able to take a large, complex program and reverse engineer it with Java-DACTL to discover its design. A more complex diagraming capability, one that would allow the user to make better class diagrams and add the ability to make sequence diagrams, would result in more explicit skeleton code. This embellishment would allow the tool to be used profitably in any CS course.
22
Works Cited Angster, Erzsébet. “A Simple OO System Pattern to Introduce OOP with Design.” The Eleventh Annual ACM Conference on Object-Oriented Programming Systems, Languages and Applications [6-10 October 1996]. 20 August 1999. Astrachan, Owen. “Object Design in the First Year: An Oxymoron.” The Eleventh Annual ACM Conference on Object-Oriented Programming Systems, Languages and Applications [6-10 October 1996]. 20 August 1999. Bergin, Joseph. “Graphical User Interface Programming for Multi-Platform Applications in Java 1.1 or GUI Programming in Java for Everyone” [GUIPMPAJ]. Vers. 2. Last modified June 1998. 11 August 1998. _____. “Outline of Model-View-Controller Paradigm as Expressed in the Java Libraries.” 1996-1999. 7 July 1999. _____. “Teaching Java / Objects Early” [TJOE]. Manuscript in E-mail to Anna Armentrout. 12 August 1999. _____. “Teaching Object-Oriented Analysis and Design in CS1” [TOOAD]. 3 August 1999. Eriksson, Hans-Erik and Magnus Penker. UML Toolkit. New York: Wiley, 1997. Evans, M.D. “CS1 As An Architectural Design Course.” The Eleventh Annual ACM Conference on Object-Oriented Programming Systems, Languages and Applications [6-10 October 1996]. 20 August 1999. Flanagan, David. Java in a Nutshell. Cambridge, MA: O'Reilly, 1997. Harmon, Paul and Mark Watson. Understanding UML: The Developer's Guide: With a Web-Based Application in Java. San Francisco: Kaufmann, 1998. Larman, Craig. Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design. Engelwood Cliffs, NJ: Prentice Hall, 1997. Mercer, Rick, Robert Biddle, Robert Duvall and Mike Clancy. “Teaching and Learning Object Design in the First Academic Year.” The Eleventh Annual ACM Conference on
23 Object-Oriented Programming Systems, Languages and Applications [6-10 October 1996]. 20 August 1999. UML Resource Center. Rational. 17 October 1998. “A Visual Index to the Swing Components.” The Java Tutorial. August 1999. Sun Microsystems.
24
Illustrations
Figure 1.
Whole Screen View of Project
25
Figure 2.
Open/Save Document Interface
26
Figure 3.
Use Case Form
27
Figure 4.
Use Case Diagram
28
29 Figure 5.
CRC Form
30
Figure 6.
Class Diagram
31
Figure 7.
Code Generation Window
32 //import java packages /** Displays the fortune */ class DisplayWindow extends Frame { //constructor public DisplayWindow () { } //attributes String name OkayButton ok //responsibilities //inner classes class OkayButton { //constructor public OkayButton () { } } }
Figure 8.
Code Files
33
Code ActorButton.java
import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * This is a GUI element that could be reused in a number of diagram * views. Could change image, as well */ class ActorButton extends ToolButton implements ActionListener { public ActorButton (DiagramCanvas target) { super (target,image, "Draw actor", target.ACTOR, Cursor.DEFAULT_CURSOR); } private static final ImageIcon image = new ImageIcon("images/actor.jpg"); }
ActorFigure.java import java.awt.*; /** * Handles the drawing of an actor figure.This class was elaborated from a * class written by J.Bergin for "PaintDrawApplet" 12.97 */ public class ActorFigure extends Figure implements java.io.Serializable { public ActorFigure(int ID, String label, int x, int y, int w, int h) { super(ID, label, x, y, w, h); } public void draw(Graphics g) { int x = bounds.x, y = bounds.y, h = bounds.height, w = bounds.width; g.drawOval(x+20, y, w/5, h/5); g.drawLine(x+25, y+10, x+25, y+30); g.drawLine(x, y+20, x+50, y+20); g.drawLine(x,y+50, x+25, y+30); g.drawLine(x+25, y+30, x+50, y+50); Color c = g.getColor(); //g.setColor(Color.white); //g.fillOval(x+1, y+1, w - 2, h - 2); g.setColor(Color.red); if (label != null) { FontMetrics font = g.getFontMetrics(); int centerX = findMiddleX(w,label,font); g.drawString(label, x + centerX, y+65); } g.setColor(c); if(selected) drawSelectors(g); }
34 public void drawOutline(Graphics g) { int x = bounds.x, y = bounds.y, h = bounds.height, w = bounds.width; g.drawOval(x+25, y+5, w/5, h/5); g.drawLine(x+25, y+10, x+25, y+30); g.drawLine(x, y+20, x+50, y+20); g.drawLine(x,y+50, x+25, y+30); g.drawLine(x+25, y+30, x+50, y+50); } } BaseFrame.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * This Frame from which the [main] ControlWindow is derived. * Just sets up a basic frame and menu bar * @see ControlWindow */ public class BaseFrame extends JFrame { public BaseFrame(String name, int actionOnClose) { super (name); setDefaultCloseOperation(actionOnClose); setSize(400,400); setTitle(name); getContentPane().setLayout (new BorderLayout()); menuBar = new JMenuBar(); fileMenu = new JMenu ("File", true); fileMenu.setMnemonic(KeyEvent.VK_F); menuBar.add(fileMenu); setJMenuBar(menuBar); } JMenuBar menuBar; JMenu fileMenu; JMenu editMenu; } BaseInternalFrame.java import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; /** * This is the superclass upon which all of the view windows are built. * sets up basic size, menu bar, default close operation. Superclass * JInternalFrame allows this Frame to be added (and not dragged outside of) * a parent frame. * @see DiagramWindow
35 */ public class BaseInternalFrame extends JInternalFrame { public BaseInternalFrame(String name) { super (name, resizable, closeable, maximizable, iconifiable); setDefaultCloseOperation(JInternalFrame.HIDE_ON_CLOSE); setSize(400,400); setTitle(name); getContentPane().setLayout (new BorderLayout()); menuBar = new JMenuBar(); fileMenu = new JMenu ("File", true); fileMenu.setMnemonic(KeyEvent.VK_F); menuBar.add(fileMenu); editMenu = new JMenu ("Edit", true); editMenu.setMnemonic(KeyEvent.VK_E); menuBar.add(editMenu); setJMenuBar(menuBar); } JMenuBar menuBar; JMenu fileMenu; JMenu editMenu; private static boolean resizable = true; private static boolean closeable = true; private static boolean maximizable= true; private static boolean iconifiable = true; } ClassDiagramCanvas.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.io.*; /** * Handles all mouse drawing events for ClassDiagram view. Key events are * handled by superclass, because key events for all diagram windows can * basically be handled in the same manner. * @see DiagramCanvas */ class ClassDiagramCanvas extends DiagramCanvas implements MouseMotionListener, MouseListener { public ClassDiagramCanvas(ProjectModel pm) { super (pm); addMouseMotionListener(this); addMouseListener(this); } public void mouseClicked(MouseEvent e) { boolean doDraw = false; switch (mode) { case MOVE: //a click while in move mode is a selection or deselection event Point p = e.getPoint();
36 Enumeration v = figures.elements(); selectedFigure = null; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { if(! f.isSelected()) { doDraw = true; f.setSelected(true); selectedFigure = f; } } else { if(f.isSelected()) { doDraw = true; f.setSelected(false); } } } break; case SQUARE: //if a user clicks while in square mode, draw a default sized square p = e.getPoint(); int ID = projectModel.newID(); RectangleFigure project = new RectangleFigure(ID, null, p.x, p.y,100,100); figures.add (project); doDraw = true; break; case OVAL: //if a user clicks while in oval mode, draw a default sized oval p = e.getPoint(); ID = projectModel.newID(); OvalFigure usecase = new OvalFigure(ID, null, p.x, p.y, 60, 30); figures.add(usecase); doDraw = true; break; case CONNECT: //if a user clicks while in connect mode, //remember the figure they clicked on (if one was clicked on). p = e.getPoint(); v = figures.elements(); selectedFigure = null; doDraw = false; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { //if not already remembering a figure they clicked on, //remember this one as "one" if (one == null) one = f; //if already remembering a figure they clicked on as "one",
37 //remember this one as "two" and make a new connection. else if (two == null) { doDraw = true; two = f; ID = projectModel.newID(); Connection c = new Connection (ID, null, one, two); connections.add(c); //then clear "one" and "two" for next time. one = null; two = null; } } } break; case TEXT: //if click occurs in text mode, figure out if click occurs on an //element of the diagram and begin the labeling process requestFocus(); stringBuilder = new StringBuffer(""); p = e.getPoint(); v = figures.elements(); labelFigure = null; stringIndex = -1; doDraw = false; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { doDraw = true; labelFigure = f; if (labelFigure.getLabel() != null) firstLetter = true; } } if (!doDraw) { v = connections.elements(); while (v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if (f.contains(p)) { doDraw = true; labelFigure = f; if (labelFigure.getLabel() != null) firstLetter = true; } } } break; } if (doDraw) repaint(); } public void mouseDragged(MouseEvent e) { e.consume();
38 switch (mode) { case MOVE: if(dragging) { flip(selectedFigure); selectedFigure.move(e.getPoint()); flip(selectedFigure); } break; case SQUARE: //in square mode, dragging indicates that object is being manually //drawn and sized Point secondPoint = e.getPoint(); originPoint = new Point(firstPointX, firstPointY); int width = secondPoint.x - firstPointX; if (width < 0) { width = -width; originPoint.x = secondPoint.x; } int height = secondPoint.y - firstPointY; if (height < 0) { height = -height; originPoint.y = secondPoint.y; } if (selectedFigure == null) { int ID = projectModel.newID(); RectangleFigure project = new RectangleFigure(ID, null, originPoint.x, originPoint.y,width,height); figures.add (project); selectedFigure = project; } else { selectedFigure.setLocation(originPoint); selectedFigure.setBounds(width, height); } break; case OVAL: //Dragging while in oval mode suggests that oval is being drawn //to user's preferred shape/size secondPoint = e.getPoint(); originPoint = new Point(firstPointX, firstPointY); width = secondPoint.x - firstPointX; if (width < 0) { width = -width; originPoint.x = secondPoint.x; } height = secondPoint.y - firstPointY; if (height < 0) { height = -height; originPoint.y = secondPoint.y; } if (selectedFigure == null) { int ID = projectModel.newID();
39 OvalFigure usecase = new OvalFigure (ID, null, originPoint.x, originPoint.y,width,height); figures.add (usecase); selectedFigure = usecase; } else { selectedFigure.setLocation(originPoint); selectedFigure.setBounds(width, height); } break; case RESIZE: //can't resize ActorFigure if (selectedFigure instanceof ActorFigure) break; else if (dragging) { Point p = e.getPoint(); int cursortype = drawCursor.getType(); Rectangle figbounds = selectedFigure.getBounds(); int differenceX; int differenceY; switch (cursortype) { case drawCursor.N_RESIZE_CURSOR: differenceY = figbounds.y - p.y; selectedFigure.setLocation(figbounds.x, p.y); selectedFigure.setBounds(figbounds.width, figbounds.height + differenceY); break; case drawCursor.S_RESIZE_CURSOR: differenceY = p.y - figbounds.y; selectedFigure.setBounds(figbounds.width, differenceY); break; case drawCursor.E_RESIZE_CURSOR: differenceX = p.x - figbounds.x; selectedFigure.setBounds(differenceX, figbounds.height); break; case drawCursor.W_RESIZE_CURSOR: differenceX = figbounds.x - p.x; selectedFigure.setLocation(p.x, figbounds.y); selectedFigure.setBounds(figbounds.width + differenceX, figbounds.height); break; case drawCursor.NW_RESIZE_CURSOR: differenceX = figbounds.x - p.x; differenceY = figbounds.y - p.y; selectedFigure.setLocation(p.x, p.y); selectedFigure.setBounds(figbounds.width + differenceX, figbounds.height + differenceY); break;
40 case drawCursor.NE_RESIZE_CURSOR: differenceX = p.x - figbounds.x; differenceY = figbounds.y - p.y; selectedFigure.setLocation(figbounds.x, p.y); selectedFigure.setBounds(differenceX, figbounds.height + differenceY); break; case drawCursor.SE_RESIZE_CURSOR: differenceX = p.x - figbounds.x; differenceY = p.y - figbounds.y; selectedFigure.setBounds(differenceX, differenceY); break; case drawCursor.SW_RESIZE_CURSOR: differenceX = figbounds.x - p.x; differenceY = p.y - figbounds.y; selectedFigure.setLocation(p.x, figbounds.y); selectedFigure.setBounds(figbounds.width + differenceX, differenceY); break; } } break; } repaint(); } //different cursors depending on where mouse is on diagram public void mouseMoved(MouseEvent e) { e.consume(); //if mode is resize, want to display special cursors on edges //and corners of a figure if (mode == RESIZE) { Point p = e.getPoint(); Enumeration v = figures.elements(); selectedFigure = null; boolean doDraw = false; int resultcursor = drawCursor.DEFAULT_CURSOR; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { int x = f.getBounds().x; int y = f.getBounds().y; int xw = f.getBounds().x + f.getBounds().width - 1; int yh = f.getBounds().y + f.getBounds().height - 1; boolean N = false; boolean S = false; boolean E = false; boolean W = false; if (p.x == x) W = true; if (p.x == xw) E = true;
41 if (p.y == y) N = true; if (p.y == yh) S = true; if (N && W) resultcursor = drawCursor.NW_RESIZE_CURSOR; else if (S && E) resultcursor = drawCursor.SE_RESIZE_CURSOR; else if (S && W) resultcursor = drawCursor.SW_RESIZE_CURSOR; else if (N && E) resultcursor = drawCursor.NE_RESIZE_CURSOR; else if (W) resultcursor = drawCursor.W_RESIZE_CURSOR; else if (E) resultcursor = drawCursor.E_RESIZE_CURSOR; else if (N) resultcursor = drawCursor.N_RESIZE_CURSOR; else if (S) resultcursor = drawCursor.S_RESIZE_CURSOR; selectedFigure = f; } drawCursor = drawCursor.getPredefinedCursor(resultcursor); setCursor(drawCursor); } } } public void mousePressed(MouseEvent e) { e.consume(); switch (mode) { case MOVE: if(selectedFigure != null && selectedFigure.contains(e.getPoint())) dragging = true; break; case SQUARE: case OVAL: selectedFigure = null; Point firstPoint = e.getPoint(); firstPointX = firstPoint.x; firstPointY = firstPoint.y; break; case ACTOR: int ID = projectModel.newID(); ActorFigure actor = new ActorFigure(ID, null, e.getX(), e.getY(), 50, 50); figures.add(actor); invalidate(); repaint(); break; case RESIZE:
42 int cursortype = drawCursor.getType(); if (cursortype != drawCursor.DEFAULT_CURSOR) dragging = true; break; case CONNECT: case TEXT: default: break; } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseReleased(MouseEvent e) { e.consume(); dragging = false; } private Figure one = null; private Figure two = null; private int firstPointX; private int firstPointY; private Point originPoint; } ClassDiagramWindow.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; /** * This window in which all the class diagraming action occurs. * Sets up appropriate toolbar and drawing canvas * @see DiagramWindow */ public class ClassDiagramWindow extends DiagramWindow { public ClassDiagramWindow(String name, ProjectModel pm) { super (name); usercanvas = new ClassDiagramCanvas(pm); classtools = new ClassToolBar(usercanvas); getContentPane().add(classtools, BorderLayout.WEST); getContentPane().add(usercanvas); }
43 ClassToolBar classtools; } ClassForm.java import java.awt.*; import java.awt.event.*; import java.lang.reflect.*; import javax.swing.*; import javax.swing.event.*; import java.util.*; import javax.swing.plaf.basic.*; /** * This view window is set up like a CRC card, allowing the user to add * classes and fill in information about each of the classes. */ public class ClassForm extends JInternalFrame implements Observer { public ClassForm(ProjectModel pm) { super("Class - Responsibility - Collaboration Form", true, true, true, true); setDefaultCloseOperation(JInternalFrame.HIDE_ON_CLOSE); setSize(550,450); setTitle("Class - Responsibility - Collaboration Form"); projectModel = pm; projectModel.addObserver(this); blankModel = new DefaultListModel(); Insets zeroInsets = new Insets(0,0,0,0); getContentPane().setLayout (new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = gbc.NONE; gbc.ipady = 10; gbc.ipadx = 10; gbc.insets = new Insets (5,5,0,0); //First column gbc.gridx = 0; gbc.gridy = 0; gbc.anchor = gbc.EAST; //ID: label JLabel label = new JLabel ("ID #: "); getContentPane().add(label, gbc); //Superclass: label gbc.gridy = 1; label = new JLabel("Superclass: "); getContentPane().add(label,gbc); //Function Description: label gbc.gridy = 2; label = new JLabel("Function: "); getContentPane().add(label, gbc); //Inner Classes: label gbc.gridy = 3; label = new JLabel("Inner Classes: ");
44 getContentPane().add(label, gbc); //Inner classes buttons gbc.gridy = 4; innerButton = new InnerButton(); innerButton.setMargin(zeroInsets); getContentPane().add(innerButton, gbc); gbc.anchor = gbc.CENTER; innerDeleteButton = new InnerDeleteButton(); innerDeleteButton.setMargin(zeroInsets); getContentPane().add(innerDeleteButton,gbc); //Collaborators: label gbc.anchor = gbc.EAST; gbc.gridy = 5; label = new JLabel("Collaborators: "); getContentPane().add(label, gbc); //Collaborators buttons gbc.gridy = 6; collabButton = new CollabButton(); collabButton.setMargin(zeroInsets); getContentPane().add(collabButton, gbc); //Back button gbc.gridy = 7; gbc.anchor = gbc.WEST; backButton = new BackButton(); backButton.setMargin(new Insets(1,1,1,1)); getContentPane().add (backButton, gbc); //Second column gbc.gridx = 1; gbc.gridy = 0; gbc.anchor = gbc.WEST; //ID text area idText = new JTextArea (1,3); idText.setEditable(false); getContentPane().add(idText, gbc); //Superclass list gbc.gridy = 1; //gbc.gridwidth = 2; superclassbox = new SuperComboBox(); superclassbox.setEditable(true); superclassbox.setPreferredSize(new Dimension(120,15)); getContentPane().add(superclassbox, gbc); //Function Description text area gbc.gridy = 2; gbc.gridwidth = 4; funcText = new JTextArea(1,28); JScrollPane textscroll = new JScrollPane(funcText); getContentPane().add(textscroll, gbc); //Inner Classes list gbc.gridwidth = 1; gbc.gridy = 3; innerModel = new DefaultListModel(); innerList = new JList(innerModel); innerList.setVisibleRowCount(3);
45 innerList.setPrototypeCellValue("BlahBlahBlahBlah"); innerList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); JScrollPane listScroll = new JScrollPane(innerList); getContentPane().add(listScroll, gbc); //Inner Classes add/delete textfield gbc.gridy = 4; innerText = new JTextField(8); getContentPane().add(innerText, gbc); //Collaborators list gbc.anchor = gbc.WEST; gbc.gridy = 5; collabModel = new DefaultListModel(); collabList = new JList(collabModel); collabList.setVisibleRowCount(3); collabList.setPrototypeCellValue("BlahBlahBlahBlah"); ListSelectionModel csm = collabList.getSelectionModel(); csm.addListSelectionListener(new CollabListSelectionHandler()); listScroll = new JScrollPane(collabList); getContentPane().add(listScroll, gbc); //Collaborators add/delete textfield gbc.gridy = 6; collabText = new JTextField(8); getContentPane().add(collabText, gbc); //Delete button gbc.anchor = gbc.WEST; gbc.gridwidth = 1; gbc.gridy = 7; deleteButton = new DeleteButton(); getContentPane().add(deleteButton, gbc); //Third column gbc.gridx = 2; gbc.gridy = 0; gbc.anchor = gbc.EAST; //Name label label = new JLabel ("Name: "); getContentPane().add(label,gbc); //Fourth column gbc.gridx = 3; gbc.gridy = 0; gbc.anchor = gbc.WEST; gbc.gridwidth = 2; //class name list classbox = new ClassComboBox(); classbox.setPreferredSize(new Dimension(200,15)); classbox.setEditable(true); getContentPane().add(classbox, gbc); //Responsibilities: label gbc.anchor = gbc.EAST; gbc.gridwidth = 1; gbc.gridy = 3; label = new JLabel("Responsibilities: "); getContentPane().add(label, gbc);
46 //Responsibilities buttons gbc.gridy = 4; responsButton = new ResponsButton(); responsButton.setMargin(zeroInsets); getContentPane().add(responsButton, gbc); gbc.anchor = gbc.CENTER; responsDeleteButton = new ResponsDeleteButton(); responsDeleteButton.setMargin(zeroInsets); getContentPane().add(responsDeleteButton,gbc); //Attributes: label gbc.anchor = gbc.EAST; gbc.gridy = 5; label = new JLabel("Attributes: "); getContentPane().add(label, gbc); //Attributes buttons gbc.gridy = 6; attribButton = new AttribButton(); attribButton.setMargin(zeroInsets); getContentPane().add(attribButton, gbc); gbc.anchor = gbc.CENTER; attribDeleteButton = new AttribDeleteButton(); attribDeleteButton.setMargin(zeroInsets); getContentPane().add(attribDeleteButton,gbc); //New button gbc.gridy = 7; newButton = new NewButton(); getContentPane().add(newButton, gbc); //Fifth column gbc.gridx = 4; gbc.gridy = 3; gbc.anchor = gbc.WEST; //Responsibilities list responsModel = new DefaultListModel(); responsList = new JList(responsModel); responsList.setVisibleRowCount(3); responsList.setPrototypeCellValue("BlahBlahBlahBlah"); responsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); listScroll = new JScrollPane(responsList); getContentPane().add(listScroll, gbc); //Responsibilities add/delete textfield gbc.gridy = 4; responsText = new JTextField(8); getContentPane().add(responsText, gbc); //Attributes list gbc.anchor = gbc.WEST; gbc.gridy = 5; attribModel = new DefaultListModel(); attribList = new JList(attribModel); attribList.setVisibleRowCount(3); attribList.setPrototypeCellValue("BlahBlahBlahBlah"); attribList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); listScroll = new JScrollPane(attribList); getContentPane().add(listScroll, gbc);
47 //Attributes add/delete textfield gbc.gridy = 6; attribText = new JTextField(8); getContentPane().add(attribText, gbc); //Next button gbc.gridy = 7; nextButton = new NextButton(); nextButton.setMargin(new Insets(1,1,1,1)); getContentPane().add (nextButton, gbc); classes = projectModel.getClasses(); currentDisplayIndex = -1; } JTextArea idText; ClassComboBox classbox; SuperComboBox superclassbox; JTextArea funcText; DefaultListModel blankModel; JList innerList; DefaultListModel innerModel; JTextField innerText; InnerButton innerButton; InnerDeleteButton innerDeleteButton; JList collabList; DefaultListModel collabModel; JTextField collabText; CollabButton collabButton; JList responsList; DefaultListModel responsModel; JTextField responsText; ResponsButton responsButton; ResponsDeleteButton responsDeleteButton; JList attribList; DefaultListModel attribModel; JTextField attribText; AttribButton attribButton; AttribDeleteButton attribDeleteButton; BackButton backButton; NextButton nextButton; DeleteButton deleteButton; NewButton newButton; //Save text in function description text area if it has been revised public void saveFuncText() { if (currentDisplayIndex >=0) { Action actions[] = funcText.getActions(); if (actions != null)
48 { ClassObject currentClass = (ClassObject)classes.elementAt(currentDisplayIndex); currentClass.setFuncDesc(funcText.getText()); Update updateClass = new Update(Update.CLASS_FORM, currentClass.getID(), Update.CHANGE, ClassObject.FUNC_DESC, funcText.getText()); projectModel.registerChange(); projectModel.notifyObservers(updateClass); } } } //Controls actions on the class list box (selections, additions) class ClassComboBox extends JComboBox implements ActionListener { public ClassComboBox() { super(); addActionListener(this); } private boolean updateChange; public void setUpdate() { updateChange = true; } public boolean findItem(String item) { for (int i = 0; i < getItemCount(); i++) { String test = (String)getItemAt(i); if (item.equals(test)) return true; } return false; } public void actionPerformed (ActionEvent e) { String newItem = e.getActionCommand(); //if there are no classes displayed, ignore action if (currentDisplayIndex >= 0) { //a simple selection change if (newItem.equals("comboBoxChanged")) { String item = (String)getSelectedItem(); if (item != null) displayClass(item); } else { if (findItem(newItem)) { //user types in a name already in list displayClass(newItem); } else { //a new item. add only if it isn't a blank item if (! newItem.equals("")) { ClassObject currentClass = (ClassObject)classes.elementAt(currentDisplayIndex); currentClass.setName(newItem); addItem(newItem);
49 collabModel.addElement(newItem); displayClass(currentDisplayIndex); if (!updateChange) { Update updateClass = new Update(Update.CLASS_FORM, currentClass.getID(), Update.CHANGE, ClassObject.NAME, newItem); projectModel.registerChange(); projectModel.notifyObservers(updateClass); } } } } } } } //Controls actions on the superclass list box (selections, additions) class SuperComboBox extends JComboBox implements ActionListener { public SuperComboBox() { super(); addActionListener(this); updateChange = false; } private boolean updateChange; public void setUpdate() { updateChange = true; } //check if item is already in list public boolean findItem(String item) { for (int i = 0; i < getItemCount(); i++) { String test = (String)getItemAt(i); if (item.equals(test)) return true; } return false; } public void actionPerformed (ActionEvent e) { String newItem = e.getActionCommand(); ClassObject currentClass = null; int ID = -1; if (newItem != null)//meaningless action { //could be adding a superclass with no classes yet if (currentDisplayIndex >= 0) { currentClass = (ClassObject)classes.elementAt(currentDisplayIndex); ID = currentClass.getID(); } //If comboBox is changing, new items must already //have been added, must be updating a use case if ((currentDisplayIndex >= 0) && (!updateChange) && (newItem.equals("comboBoxChanged")))
50 { String item = (String)getSelectedItem(); if ((!updateChange) && (item != null)) { currentClass.setSuperClass(item); Update updateClass = new Update(Update.CLASS_FORM, ID, Update.CHANGE, ClassObject.SUPER_CLASS, item); projectModel.registerChange(); projectModel.notifyObservers(updateClass); } } else if (!(newItem.equals("comboBoxChanged"))) { if (findItem(newItem))//item is duplicate of previous item. { if (currentDisplayIndex >= 0) currentClass.setSuperClass(newItem); if (!updateChange) { Update updateClass = new Update(Update.CLASS_FORM, ID, Update.CHANGE, ClassObject.SUPER_CLASS, newItem); projectModel.registerChange(); projectModel.notifyObservers(updateClass); } } else //completely new item { if (! newItem.equals("")) { setUpdate(); addItem(newItem); } if (currentDisplayIndex >=0) currentClass.setSuperClass(newItem); if (!updateChange) { Update updateClass = new Update(Update.CLASS_FORM, ID, Update.ADD, ClassObject.SUPER_CLASS, newItem); projectModel.registerChange(); projectModel.notifyObservers(updateClass); } int n = JOptionPane.showConfirmDialog(ClassForm.this, "Add new superclass to project as a class?","Add Superclass", JOptionPane.YES_NO_OPTION); if (n == JOptionPane.YES_OPTION) { int oldIndex = currentDisplayIndex; ClassObject newClass = new ClassObject(projectModel.newID()); newClass.setName(newItem); classes.add(newClass); classbox.setUpdate(); classbox.addItem(newItem); collabModel.addElement(newItem); Update addClass = new Update(Update.CLASS_FORM, newClass.getID(), Update.ADD, 0, newClass); projectModel.registerChange(); projectModel.notifyObservers(addClass); displayClass(oldIndex); } } } }
51 updateChange = false; } } //Controls actions on back arrow button //scrolls back one entry class BackButton extends JButton implements ActionListener { public BackButton() { super(); init (null, back); addActionListener(this); setToolTipText("Back"); } public final ImageIcon back = new ImageIcon("images/back.jpg"); public void actionPerformed(ActionEvent e) { saveFuncText(); if (currentDisplayIndex > 0) displayClass(currentDisplayIndex - 1); } } //Controls action on next arrow button //scrolls forward one entry class NextButton extends JButton implements ActionListener { public NextButton() { super(); init(null, next); addActionListener(this); setToolTipText("Next"); } public final ImageIcon next = new ImageIcon("images/next.jpg"); public void actionPerformed(ActionEvent e) { saveFuncText(); if (currentDisplayIndex >= 0) { if (!(currentDisplayIndex + 1 >= classes.size())) displayClass(currentDisplayIndex + 1); } } } //Allows a class to be deleted class DeleteButton extends JButton implements ActionListener { public DeleteButton() { super("Delete"); addActionListener(this); } public void actionPerformed(ActionEvent e) { if (currentDisplayIndex >= 0) { ClassObject currentClass =
52 (ClassObject) classes.elementAt(currentDisplayIndex); String name = currentClass.getName(); classes.removeElementAt(currentDisplayIndex); if (name != null); { classbox.setUpdate(); classbox.removeItem(currentClass.getName()); classbox.setUpdate(); classbox.setSelectedItem(null); collabModel.removeElement(currentClass.getName()); } if (classes.size() > 0) displayClass(0); else displayBlank(); projectModel.registerChange(); Update updateClass = new Update(Update.CLASS_FORM, currentClass.getID(), Update.DELETE, 0, null); projectModel.notifyObservers(updateClass); } } } //Allows a class to be added class NewButton extends JButton implements ActionListener { public NewButton() { super("New"); addActionListener(this); } public void actionPerformed(ActionEvent e) { saveFuncText(); int ID = projectModel.newID(); ClassObject newClass = new ClassObject(ID); classes.add(newClass); Update updateClass = new Update(Update.CLASS_FORM, ID, Update.ADD, 0, newClass); projectModel.registerChange(); projectModel.notifyObservers(updateClass); displayClass(classes.indexOf(newClass)); } } //Adds items in InnerClass list class InnerButton extends JButton implements ActionListener { public InnerButton() { super(); init (null, add); addActionListener(this); setToolTipText("Add"); } public final ImageIcon add = new ImageIcon("images/add.jpg"); public void actionPerformed(ActionEvent e)
53 { String newItem = innerText.getText(); if (! newItem.equals("")) { if (currentDisplayIndex >= 0) { ClassObject current = (ClassObject)classes.elementAt(currentDisplayIndex); innerModel.addElement(newItem); innerText.setText(""); Update update = new Update(Update.CLASS_FORM, current.getID(), Update.ADD, ClassObject.INNER_CLASS, newItem); projectModel.registerChange(); projectModel.notifyObservers(update); } } } } //Deletes items in InnerClass list class InnerDeleteButton extends JButton implements ActionListener { public InnerDeleteButton() { super(); init (null, delete); addActionListener(this); setToolTipText("Delete"); } public final ImageIcon delete = new ImageIcon("images/delete.jpg"); public void actionPerformed(ActionEvent e) { int index = innerList.getSelectedIndex(); if (index >= 0) { ClassObject current = (ClassObject)classes.elementAt(currentDisplayIndex); Update update = new Update( Update.CLASS_FORM, current.getID(), Update.DELETE, ClassObject.INNER_CLASS, innerList.getSelectedValue()); innerModel.remove(index); projectModel.registerChange(); projectModel.notifyObservers(update); } } }
//Adds items in Responsibilities list class ResponsButton extends JButton implements ActionListener { public ResponsButton() { super(); init (null, add); addActionListener(this); setToolTipText("Add"); } public final ImageIcon add = new ImageIcon("images/add.jpg");
54 public void actionPerformed(ActionEvent e) { String newItem = responsText.getText(); if (! newItem.equals("")) { if (currentDisplayIndex >= 0) { ClassObject current = (ClassObject)classes.elementAt(currentDisplayIndex); responsModel.addElement(newItem); responsText.setText(""); Update update = new Update(Update.CLASS_FORM, current.getID(), Update.CHANGE, ClassObject.RESPONSIBILITY, newItem); projectModel.registerChange(); projectModel.notifyObservers(update); } } } } //Deletes items in Responsibilities list class ResponsDeleteButton extends JButton implements ActionListener { public ResponsDeleteButton() { super(); init (null, delete); addActionListener(this); setToolTipText("Delete"); } public final ImageIcon delete = new ImageIcon("images/delete.jpg"); public void actionPerformed(ActionEvent e) { int index = responsList.getSelectedIndex(); if (index >= 0) { ClassObject current = (ClassObject)classes.elementAt(currentDisplayIndex); Update update = new Update(Update.CLASS_FORM, current.getID(), Update.DELETE, ClassObject.RESPONSIBILITY, responsList.getSelectedValue()); responsModel.remove(index); projectModel.registerChange(); projectModel.notifyObservers(update); } } } //Adds items in Collaborators list class CollabButton extends JButton implements ActionListener { public CollabButton() { super(); init (null, add); addActionListener(this); setToolTipText("Add"); }
55 public final ImageIcon add = new ImageIcon("images/add.jpg"); public void actionPerformed(ActionEvent e) { String newItem = collabText.getText(); if (! newItem.equals("")) { if (currentDisplayIndex >= 0) { ClassObject current = (ClassObject)classes.elementAt(currentDisplayIndex); collabModel.addElement(newItem); collabText.setText(""); //add this collaborator as a class int oldIndex = currentDisplayIndex; ClassObject newClass = new ClassObject(projectModel.newID()); newClass.setName(newItem); classes.add(newClass); classbox.setUpdate(); classbox.addItem(newItem); Update addClass = new Update(Update.CLASS_FORM, newClass.getID(), Update.ADD, 0, newClass); projectModel.registerChange(); projectModel.notifyObservers(addClass); displayClass(oldIndex); } } } } class CollabListSelectionHandler implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { ClassObject current = (ClassObject)classes.elementAt(currentDisplayIndex); int[] selectedList = collabList.getSelectedIndices(); Vector stringList = new Vector(); for (int i = 0; i < selectedList.length; i++) { int index = selectedList[i]; String selectedCollab = (String)collabModel.getElementAt(index); stringList.add(selectedCollab); } current.setCollaborators(stringList); } }
//Adds items in Attributes list class AttribButton extends JButton implements ActionListener { public AttribButton() { super(); init (null, add); addActionListener(this); setToolTipText("Add"); } public final ImageIcon add = new ImageIcon("images/add.jpg");
56 public void actionPerformed(ActionEvent e) { String newItem = attribText.getText(); if (! newItem.equals("")) { if (currentDisplayIndex >= 0) { ClassObject current = (ClassObject)classes.elementAt(currentDisplayIndex); attribModel.addElement(newItem); attribText.setText(""); Update update = new Update(Update.CLASS_FORM, current.getID(), Update.CHANGE, ClassObject.ATTRIBUTE, newItem); projectModel.registerChange(); projectModel.notifyObservers(update); } } } } //Deletes items in Attributes list class AttribDeleteButton extends JButton implements ActionListener { public AttribDeleteButton() { super(); init (null, delete); addActionListener(this); setToolTipText("Delete"); } public final ImageIcon delete = new ImageIcon("images/delete.jpg"); public void actionPerformed(ActionEvent e) { int index = attribList.getSelectedIndex(); if (index >= 0) { ClassObject current = (ClassObject)classes.elementAt(currentDisplayIndex); Update update = new Update(Update.CLASS_FORM, current.getID(), Update.DELETE, ClassObject.ATTRIBUTE, attribList.getSelectedValue()); attribModel.remove(index); projectModel.registerChange(); projectModel.notifyObservers(update); } } } //function necessary for this class to be an observer //this class gets updates from the observable it is registered with public void update (Observable pm, Object arg) { Update classUpdate = (Update) arg; //only care about certain updates if ((classUpdate.getOrigin() == classUpdate.CLASS_DIAGRAM) || (classUpdate.getOrigin() == classUpdate.TREE_CO)) { int act = classUpdate.getAction(); switch (act) { case classUpdate.ADD:
57 if (classUpdate.getField() == ClassObject.SUPER_CLASS) { String newItem = (String) classUpdate.getArg(); superclassbox.setUpdate(); superclassbox.addItem(newItem); if (currentDisplayIndex >= 0) displayClass(currentDisplayIndex); } else { ClassObject newClass = (ClassObject)classUpdate.getArg(); int index = classes.indexOf(newClass); displayClass(index); } break; case classUpdate.DELETE: if (classUpdate.getField() == ClassObject.SUPER_CLASS) { String deleteName = (String)classUpdate.getArg(); superclassbox.setUpdate(); superclassbox.removeItem((String)classUpdate.getArg()); if (currentDisplayIndex >= 0) displayClass(currentDisplayIndex); } else { String deleteItem = (String)classUpdate.getArg(); if (deleteItem != null) { classbox.removeItem(deleteItem); collabModel.removeElement(deleteItem); } if (classes.size() > 0) displayClass(0); else displayBlank(); } break; case classUpdate.CHANGE: int ID = classUpdate.getID(); int index = -1; if (ID >= 0) { ClassObject changeField = projectModel.findClass(ID); index = classes.indexOf(changeField); currentDisplayIndex = index; } if (classUpdate.getArg() instanceof String) { if (classUpdate.getField() == ClassObject.NAME) { String newItem = (String)classUpdate.getArg(); if (newItem != null) { classbox.setUpdate(); classbox.addItem(newItem); collabModel.addElement(newItem); displayClass(currentDisplayIndex); } }
58 } else { LabelChange lc = (LabelChange)classUpdate.getArg(); String oldItem = lc.getOld(); String newItem = lc.getNew(); if (newItem != null) { int field = classUpdate.getField(); switch (field) { case ClassObject.NAME: classbox.setUpdate(); classbox.removeItem(oldItem); collabModel.removeElement(oldItem); classbox.setUpdate(); classbox.addItem(newItem); collabModel.addElement(newItem); displayClass(currentDisplayIndex); break; case ClassObject.SUPER_CLASS: superclassbox.setUpdate(); superclassbox.removeItem(oldItem); superclassbox.setUpdate(); superclassbox.addItem(newItem); if (index >= 0) displayClass(currentDisplayIndex); break; case ClassObject.INNER_CLASS: ClassObject current = projectModel.findClass(ID); currentDisplayIndex = classes.indexOf(current); displayClass(currentDisplayIndex); innerModel.removeElement(oldItem); innerModel.addElement(newItem); break; } } } break; default: break; } } else if (classUpdate.getOrigin() == Update.OPEN) { if (! classes.isEmpty()) { for (int index = 0; index < classes.size(); index ++) { currentDisplayIndex = index; ClassObject current = (ClassObject)classes.elementAt(index); String name = current.getName(); String supr = current.getSuperClass(); if (name != null) { classbox.setUpdate(); classbox.addItem(name); collabModel.addElement(name);
59 } if (supr != null) { superclassbox.setUpdate(); superclassbox.addItem(supr); } } displayClass(0); } } } //Displays the selected class in the CRC Form public void displayClass(int index) { currentDisplayIndex = index; ClassObject currentClass = (ClassObject)classes.elementAt(currentDisplayIndex); Integer id = new Integer(currentClass.getID()); idText.setText(id.toString()); classbox.setSelectedItem(currentClass.getName()); String supername = currentClass.getSuperClass(); superclassbox.setSelectedItem(currentClass.getSuperClass()); funcText.setText(currentClass.getFuncDesc()); innerModel = currentClass.getInnerClasses(); innerList.setModel(innerModel); responsModel = currentClass.getResponsibilities(); responsList.setModel(responsModel); attribModel = currentClass.getAttributes(); attribList.setModel(attribModel); Vector collabs = currentClass.getCollaborators(); if (collabs.isEmpty()) collabList.clearSelection(); else { int [] list = new int[collabs.size()]; int listIndex = 0; for (int i = 0; i < collabModel.getSize(); i++) { String listItem = (String)collabModel.getElementAt(i); if (collabs.contains(listItem)) { list[listIndex] = i; listIndex ++; } } collabList.setSelectedIndices(list); } repaint(); } public void displayClass(String name) { int index; for (index = 0; index < classes.size(); index++) { ClassObject current = (ClassObject) classes.elementAt(index); if (name.equals(current.getName())) break; } if (index < classes.size())
60 displayClass(index); } //Displays a blank form public void displayBlank() { currentDisplayIndex = -1; idText.setText(""); classbox.setSelectedItem(null); superclassbox.setSelectedItem(null); funcText.setText(""); innerList.setModel(blankModel); repaint(); } protected ProjectModel projectModel; protected Vector classes; protected int currentDisplayIndex; }
ClassObject.java import java.io.*; import java.lang.*; import java.util.*; import javax.swing.text.*; import javax.swing.*; /** * The object that holds all the information about an individual class. * These are stored in a vector in ProjectModel and manipulated by ClassForm. * */ class ClassObject extends Object implements Serializable { public ClassObject(int num) { IDNumber = num; InnerClasses = new DefaultListModel(); Responsibilities = new DefaultListModel(); Attributes = new DefaultListModel(); Collaborators = new Vector(); } public int getID() { return IDNumber; } public String getName() { return Name; } public String getSuperClass() { return SuperClass; }
61 public String getFuncDesc() { return FuncDesc; } public DefaultListModel getInnerClasses() { return InnerClasses; } public DefaultListModel getResponsibilities() { return Responsibilities; } public Vector getCollaborators() { return Collaborators; } public void addCollaborator(String item) { Collaborators.add(item); } public void removeCollaborator(String item) { Collaborators.remove(item); } public void setCollaborators(Vector list) { Collaborators = list; } public DefaultListModel getAttributes() { return Attributes; } public void setName(String name) { Name = name; } public void setSuperClass(String name) { SuperClass = name; } public void setFuncDesc(String desc) { FuncDesc = desc; } public String toString() { return new String("Class: " + IDNumber + " name: " + Name + " super: " + SuperClass); } private int IDNumber; private String Name = null; private String SuperClass = null; private String FuncDesc; private DefaultListModel InnerClasses; private DefaultListModel Responsibilities;
62 private DefaultListModel Attributes; private Vector Collaborators; public static final int NAME = 1; public static final int SUPER_CLASS = 2; public static final int FUNC_DESC = 3; public static final int INNER_CLASS = 4; public static final int RESPONSIBILITY = 5; public static final int COLLABORATION = 6; public static final int ATTRIBUTE = 7; } ClassToolBar.java import javax.swing.*; import java.awt.event.*; /** * The tool bar that contains the tools specific to the class diagram view. * */ class ClassToolBar extends DiagramToolBar { public ClassToolBar(DiagramCanvas target) { super(target); add(move); add(square); add(text); add(connect); add(resize); } MoveButton move = new MoveButton (this.target); SquareButton square = new SquareButton (this.target, "Draw class"); TextButton text = new TextButton (this.target); ConnectButton connect = new ConnectButton(this.target, ConnectButton.classimage, "Draw association"); ResizeButton resize = new ResizeButton(this.target); } CodeGenerator.java import java.util.*; import java.io.*; import javax.swing.*; /** * This class should maybe be renamed JavaCodeGenerator. * Writes skeleton code based on the Class vector in ProjectModel * implements observer so it knows if the project has changed since * code was last generated. */ class CodeGenerator implements Observer { public CodeGenerator (ProjectModel pm, CodeWindow cw) { projectModel = pm; messages = cw; hasChanged = false; calledGenerate = false; fileChooser = new JFileChooser();
63 fileChooser.setFileSelectionMode(fileChooser.DIRECTORIES_ONLY); projectModel.addObserver(this); } public void update (Observable obs, Object arg) { Update codeUpdate = (Update)arg; int origin = codeUpdate.getOrigin(); switch (origin) { case (codeUpdate.PROJECT): case (codeUpdate.CLASS_FORM): case (codeUpdate.CLASS_DIAGRAM): case (codeUpdate.SEQUENCE_DIAGRAM): case (codeUpdate.TREE_CO): hasChanged = true; if (calledGenerate) { projectModel.setCodeState(hasChanged); Update generated = new Update(Update.CODE_GENERATOR, -1, 0,0,"true"); projectModel.registerChange(); projectModel.notifyObservers(generated); } break; case (codeUpdate.OPEN): hasChanged = ! projectModel.getCodeState(); break; default: break; } } public void generateCode() { calledGenerate = true; JTextArea messageArea = messages.getCodeArea(); //there have been changes to the model since code was last generated if (hasChanged) { //if code has been generated before, //sets the previously used directory as the default if (pathDirectory != null) fileChooser.setSelectedFile(pathDirectory); int returnVal = fileChooser.showDialog(messages, "Choose code location"); //user has picked a directory if (returnVal == JFileChooser.APPROVE_OPTION) { pathDirectory = fileChooser.getSelectedFile(); messageArea.setText("Code being generated in: " + pathDirectory.toString() + "\n"); String projectName = projectModel.getName(); File codeDirectory = new File(pathDirectory, projectName + " code"); codeDirectory.mkdir(); messageArea.append("Directory created: " + codeDirectory.toString() + "\n"); messageArea.append("\nGenerating skeleton code...\n"); Vector classes = projectModel.getClasses(); for (int i =0; i < classes.size(); i++) { ClassObject current = (ClassObject)classes.elementAt(i); String className = current.getName(); if (className == null)
64 className = "NewClass" + current.getID(); try { out = new PrintWriter(new FileOutputStream(codeDirectory + "\\" + className + ".java")); } catch (IOException e) { System.out.println("File error: " + e); } functionDescription(current); classDeclaration(className, current.getSuperClass()); constructor(className); attributes(current); responsibilities(current); innerClasses(current); end(); out.close(); messageArea.append(className + ".java" + " generated.\n"); } messageArea.append("...done."); hasChanged = false; projectModel.setCodeState(hasChanged); Update generated = new Update(Update.CODE_GENERATOR, -1, 0,0,"false"); projectModel.registerChange(); projectModel.notifyObservers(generated); } //user didn't select a directory in which to generate //code or user selected "cancel" else messageArea.setText("Generate code command cancelled by user.\n"); } else //model hasn't changed since code was last updated. messageArea.setText("There have been no updates since code was last generated."); } protected void functionDescription (ClassObject current) { out.println("//import java packages" ); out.println(""); out.println("/** " + current.getFuncDesc()); out.println(" */"); } protected void classDeclaration (String name, String superclass) { if (!(superclass == null)) { superclass = " extends " + superclass; out.println("class " + name + superclass); } else out.println("class " + name); } protected void constructor (String name) { out.println("{ //constructor"); out.println(indent + "public " + name + " ()"); out.println(indent + "{"); out.println(indent + "}"); out.println("");
65 } protected void attributes (ClassObject current) { DefaultListModel attribs = current.getAttributes(); out.println(indent + "//attributes"); for (int i = 0; i< attribs.getSize(); i++) { String member = (String)attribs.getElementAt(i); out.println(indent + member); } out.println(""); } protected void responsibilities (ClassObject current) { out.println(indent + "//responsibilities" ); DefaultListModel response = current.getResponsibilities(); for (int i = 0; i< response.getSize(); i++) { String function = (String)response.getElementAt(i); out.println(indent + "public void " + function + " ()"); out.println(indent + "{"); out.println(indent + "}"); out.println(""); } } protected void innerClasses (ClassObject current) { out.println(indent + "//inner classes"); DefaultListModel inClasses = current.getInnerClasses(); for (int i = 0; i< inClasses.getSize(); i++) { String inner = (String)inClasses.getElementAt(i); out.println(indent + "class " + inner); out.println(indent + "{ //constructor"); out.println(indent + indent + "public " + inner + " ()"); out.println(indent + indent + "{"); out.println(indent + indent + "}"); out.println(indent + "}"); out.println(""); } } protected void end() { out.println("}"); } public File getPath() { return pathDirectory; } private private private private private private private private }
ProjectModel projectModel; boolean hasChanged; boolean calledGenerate; CodeWindow messages = null; JFileChooser fileChooser; File pathDirectory; PrintWriter out; String indent = " ";
66 CodeWindow.java import java.awt.*; import javax.swing.*; import java.util.*; /** * A window that displays status messages when code is being generated. */ public class CodeWindow extends JInternalFrame { public CodeWindow(ProjectModel pm) { super("Skeleton Code Generation Messages", true, true); setSize(400,400); getContentPane().setLayout(new BorderLayout()); code = new JTextArea(400,400); JScrollPane scrollPane = new JScrollPane(code); getContentPane().add(scrollPane); projectModel = pm; } public JTextArea getCodeArea() { return code; } ProjectModel projectModel; JTextArea code; } ConnectButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * Tool bar button, action listener that changes mode so connections can * be drawn in diagram window. */ class ConnectButton extends ToolButton implements ActionListener { public ConnectButton (DiagramCanvas target, String imagename, String hint) { super (target,new ImageIcon(imagename), hint, target.CONNECT, Cursor.DEFAULT_CURSOR); } public static final String usecaseimage = "images/connect.jpg"; public static final String classimage = "images/bentcnct.jpg"; public static final String sequenceimage = "images/message.jpg"; } Connection.java import java.math.*; import java.awt.*;
67 /** * A figure that can be drawn in diagram views. Shows that two figures are * linked in some way. Based on a class written by J.Bergin for "PaintDrawApplet" 12.97 */ public class Connection extends Figure implements java.io.Serializable { protected Figure first; protected Figure second; public Connection(int ID, String label, Figure first, Figure second) { super(ID, label, 0, 0, 0, 0); this.first = first; this.second = second; int wide = second.center().x - first.center().x; int high = second.center().y - first.center().y; if (wide < 0) wide = -wide; if (high < 0) high = -high; setBounds (first.center().x, first.center().y, wide, high); } public void draw(Graphics g) { int x1 = first.center().x, y1 = first.center().y, x2 = second.center().x, y2 = second.center().y; g.drawLine(x1, y1, x2, y2); Color c = g.getColor(); g.setColor(Color.red); if (label != null) { FontMetrics font = g.getFontMetrics(); int centerX = findMiddleX(x1 + x2,label,font); g.drawString(label, centerX, (y1 + y2)/2-2); } g.setColor(c); } //checks if figure f is one part of a connection. public boolean checkConnect(Figure f) { if ((f.equals(first))||(f.equals(second))) return true; else return false; } public Figure getFirst() { return first; } public Figure getSecond() { return second; } public void drawOutline(Graphics g) { int x1 = first.center().x, y1 = first.center().y, x2 = second.center().x, y2 = second.center().y;
68 g.drawLine(x1, y1, x2, y2); } } ControlWindow.java //Java-DACTL, Java Design, Analysis, and Coding TooL with UML //Anna S. Armentrout //Copyright (c) 1999 //Pace University import java.io.*; import java.util.zip.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.tree.*; import java.beans.*; /** * The "main" class. This class sets up the GUI and allows view windows * to be displayed. */ public class ControlWindow extends BaseFrame { public static void main(String args[]) { try { UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch(Exception e){} ControlWindow control = new ControlWindow ("Java-DACTL"); control.setVisible(true); } public ControlWindow(String name) { super (name, DISPOSE_ON_CLOSE); setSize(800,600); newItem = new NewMenuItem(); openItem = new OpenMenuItem(); closeItem = new CloseMenuItem(); saveItem = new SaveMenuItem(); saveItem.setEnabled(false); printItem = new PrintMenuItem(); printItem.setEnabled(false); exitItem = new ExitMenuItem(); fileMenu.add(newItem); fileMenu.add(openItem); fileMenu.add(closeItem); fileMenu.add(saveItem); fileMenu.add(printItem); fileMenu.add(exitItem);
69 JMenu menu = new JMenu ("Project"); menu.setMnemonic(KeyEvent.VK_P); ucfItem = new UseCaseFormsItem(); ucfItem.setEnabled(false); ucdItem = new UseCaseDiagramItem(); ucdItem.setEnabled(false); classFormsItem = new ClassFormsItem(); classFormsItem.setEnabled(false); classDiagramItem = new ClassDiagramItem(); classDiagramItem.setEnabled(false); sequenceItem = new SequenceItem(); sequenceItem.setEnabled(false); codeItem = new CodeItem(); codeItem.setEnabled(false); menu.add(ucfItem); menu.add(ucdItem); menu.add(classFormsItem); menu.add(classDiagramItem); menu.add(sequenceItem); menu.add(codeItem); menuBar.add(menu); //May be added later //Would be nice if view windows on right could be "tiled" in some way //menu = new JMenu("Window"); //menu.setMnemonic(KeyEvent.VK_W); //menuBar.add(menu); //menu = new JMenu("Help"); //menu.setMnemonic(KeyEvent.VK_H); //menuBar.add(menu); scrollMenu = new JScrollPane(); scrollMenu.setPreferredSize(new Dimension(200,800)); windowArea = new JDesktopPane(); windowArea.putClientProperty("JDesktopPane.dragMode", "outline"); splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollMenu, windowArea); getContentPane().add(splitPane); addWindowListener(closer); } // Anonymous inner class extending WindowAdapter. //Handles the window close event. WindowListener closer = new WindowAdapter() { public void windowClosing(WindowEvent e) { dispose(); System.exit(0); } }; NewMenuItem newItem;
70 OpenMenuItem openItem; CloseMenuItem closeItem; SaveMenuItem saveItem; PrintMenuItem printItem; ExitMenuItem exitItem; UseCaseFormsItem ucfItem; UseCaseDiagramItem ucdItem; ClassFormsItem classFormsItem; ClassDiagramItem classDiagramItem; SequenceItem sequenceItem; CodeItem codeItem; JSplitPane splitPane; JScrollPane scrollMenu; JDesktopPane windowArea; UseCaseForm useCaseForm; UseCaseDiagramWindow useCaseDiagramWindow = null; ClassForm classForm; ClassDiagramWindow classDiagramWindow = null; SequenceDiagramWindow sequenceDiagramWindow = null; CodeGenerator codeGenerator; CodeWindow codeWindow; ProjectModel projectModel; boolean viewsDone = false; File openFile; JFileChooser fileOpener; File saveFile; JFileChooser fileSaver; public void createViews() { useCaseForm = new UseCaseForm(projectModel); useCaseForm.setVisible(false); useCaseDiagramWindow = new UseCaseDiagramWindow("Use Case Diagram", projectModel); useCaseDiagramWindow.setVisible(false); classForm = new ClassForm(projectModel); classForm.setVisible(false); classDiagramWindow = new ClassDiagramWindow("Class Diagram", projectModel); classDiagramWindow.setVisible(false); sequenceDiagramWindow = new SequenceDiagramWindow("Sequence Diagram", projectModel); sequenceDiagramWindow.setVisible(false); codeWindow = new CodeWindow(projectModel); codeGenerator = new CodeGenerator(projectModel, codeWindow); codeWindow.setVisible(false); windowArea.add(useCaseForm); windowArea.add(useCaseDiagramWindow); windowArea.add(classForm); windowArea.add(classDiagramWindow);
71 windowArea.add(sequenceDiagramWindow); windowArea.add(codeWindow); } public void enOrDisAble(boolean enable) { saveItem.setEnabled(enable); printItem.setEnabled(enable); ucfItem.setEnabled(enable); ucdItem.setEnabled(enable); classFormsItem.setEnabled(enable); classDiagramItem.setEnabled(enable); sequenceItem.setEnabled(enable); codeItem.setEnabled(enable); } class NewMenuItem extends JMenuItem implements ActionListener { public NewMenuItem() { super("New Project", KeyEvent.VK_N); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK)); addActionListener(this); } //Open a new project. (Should close any open project first) public void actionPerformed (ActionEvent e) { if (projectModel != null) closeItem.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "close")); //The model for this project projectModel = new ProjectModel(); //add the project name to the project model projectModel.setName("New Project"); ProjectMutableTreeNode treetop = new ProjectMutableTreeNode(projectModel.getName(), projectModel.getID()); ProjectTree tree = new ProjectTree(treetop, projectModel); scrollMenu.setViewportView(tree); createViews();//(re)create all the various views. viewsDone = true; enOrDisAble(true); scrollMenu.setVisible(true); DefaultTreeModel treeModel = (DefaultTreeModel)tree.getModel(); treeModel.reload(); } } class OpenMenuItem extends JMenuItem implements ActionListener { public OpenMenuItem() { super("Open Project", KeyEvent.VK_O); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
72 fileOpener = new JFileChooser(); addActionListener(this); } public void actionPerformed (ActionEvent e) { if (projectModel != null) closeItem.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "close")); if (openFile != null) { fileOpener.setCurrentDirectory(openFile); fileOpener.setSelectedFile(openFile); } else if (saveFile != null) { fileOpener.setCurrentDirectory(saveFile); fileOpener.setSelectedFile(saveFile); } else { if (codeGenerator != null) { File path = codeGenerator.getPath(); if (path != null) fileOpener.setSelectedFile(path); } } int returnVal = fileOpener.showOpenDialog(ControlWindow.this); if (returnVal == JFileChooser.APPROVE_OPTION) { openFile = fileOpener.getSelectedFile(); try { FileInputStream fileIn = new FileInputStream(openFile); GZIPInputStream decompress = new GZIPInputStream(fileIn); ObjectInputStream in = new ObjectInputStream(decompress); try { projectModel = (ProjectModel)in.readObject(); ProjectMutableTreeNode treetop = new ProjectMutableTreeNode(projectModel.getName(), projectModel.newID()); ProjectTree tree = new ProjectTree(treetop, projectModel); scrollMenu.setViewportView(tree); if (! viewsDone) { createViews(); viewsDone = true; } enOrDisAble(true); projectModel.registerChange(); Update open = new Update(Update.OPEN, 0,0,0,null); projectModel.notifyObservers(open); scrollMenu.setVisible(true); DefaultTreeModel treeModel = (DefaultTreeModel)tree.getModel(); treeModel.reload(); } catch(ClassNotFoundException cnfe) { System.out.println(cnfe); } }
73 catch (IOException ioe) { System.out.println(ioe); } } } } class CloseMenuItem extends JMenuItem implements ActionListener { public CloseMenuItem() { super("Close Project", KeyEvent.VK_C); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e) { //save first then close Object[] options = { "Save","Don't Save","Don't Close"}; int n = JOptionPane.showOptionDialog(ControlWindow.this, "Save Project before closing?","Close Options", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[2]); switch (n) { case JOptionPane.YES_OPTION: saveItem.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "save")); case JOptionPane.NO_OPTION: projectModel = null; useCaseForm.setVisible(false); useCaseDiagramWindow.setVisible(false); classForm.setVisible(false); classDiagramWindow.setVisible(false); sequenceDiagramWindow.setVisible(false); codeWindow.setVisible(false); enOrDisAble(false); scrollMenu.setVisible(false); break; case JOptionPane.CANCEL_OPTION: break; } } } class SaveMenuItem extends JMenuItem implements ActionListener { public SaveMenuItem() { super("Save Project", KeyEvent.VK_S); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); fileSaver = new JFileChooser();
74 addActionListener(this); } public void actionPerformed (ActionEvent e) { if (saveFile != null) { fileSaver.setCurrentDirectory(saveFile); fileSaver.setSelectedFile(saveFile); } else if (openFile != null) { fileSaver.setCurrentDirectory(openFile); fileSaver.setSelectedFile(openFile); } else { File path = codeGenerator.getPath(); if (path != null) fileSaver.setSelectedFile(path); } int returnVal = fileSaver.showSaveDialog(ControlWindow.this); if (returnVal == JFileChooser.APPROVE_OPTION) { saveFile = fileSaver.getSelectedFile(); try { FileOutputStream fileOut = new FileOutputStream(saveFile); GZIPOutputStream compress = new GZIPOutputStream(fileOut); ObjectOutputStream out = new ObjectOutputStream(compress); out.writeObject(projectModel); out.flush(); out.close(); } catch (IOException ioe) { System.out.println(ioe); } } } } class PrintMenuItem extends JMenuItem implements ActionListener { public PrintMenuItem() { super("Print Current Window", KeyEvent.VK_P); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e) { } } class ExitMenuItem extends JMenuItem implements ActionListener { public ExitMenuItem() { super("Exit", KeyEvent.VK_X); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, ActionEvent.ALT_MASK));
75 addActionListener(this); } public void actionPerformed (ActionEvent e) { int closeOp = getDefaultCloseOperation(); if (closeOp == DISPOSE_ON_CLOSE) { setVisible(false); dispose(); System.exit(0); } else setVisible(false); } } class UseCaseFormsItem extends JMenuItem implements ActionListener { public UseCaseFormsItem() { super("Use Case Forms", KeyEvent.VK_U); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e) { if (useCaseForm.isClosed()) { try { useCaseForm.setClosed(false); windowArea.add(useCaseForm); } catch(PropertyVetoException pve) { System.out.println("Error: unable to reopen Use Case Form.\n"); } } useCaseForm.setVisible(true); useCaseForm.moveToFront(); repaint(); } } class UseCaseDiagramItem extends JMenuItem implements ActionListener { public UseCaseDiagramItem() { super("Use Case Diagram", KeyEvent.VK_C); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e) { if (useCaseDiagramWindow.isClosed()) { try { useCaseDiagramWindow.setClosed(false); windowArea.add(useCaseDiagramWindow); } catch (PropertyVetoException pve) { System.out.println("Error: unable to reopen Use Case
76 Diagram Window.\n"); } } useCaseDiagramWindow.setVisible(true); useCaseDiagramWindow.moveToFront(); } } class ClassFormsItem extends JMenuItem implements ActionListener { public ClassFormsItem() { super("Class Forms", KeyEvent.VK_F); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_3, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e) { if (classForm.isClosed()) { try { classForm.setClosed(false); windowArea.add(classForm); } catch(PropertyVetoException pve) { System.out.println("Error: unable to reopen Class Form."); } } classForm.setVisible(true); classForm.moveToFront(); repaint(); } } class ClassDiagramItem extends JMenuItem implements ActionListener { public ClassDiagramItem() { super("Class Diagram", KeyEvent.VK_D); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_4, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e) { if (classDiagramWindow.isClosed()) { try { classDiagramWindow.setClosed(false); windowArea.add(classDiagramWindow); } catch (PropertyVetoException pve) { System.out.println("Error: unable to reopen Class Diagram Window.\n"); } } classDiagramWindow.setVisible(true); classDiagramWindow.moveToFront(); }
77 } class SequenceItem extends JMenuItem implements ActionListener { public SequenceItem() { super("Sequence Diagram", KeyEvent.VK_S); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_5, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e) { if (sequenceDiagramWindow.isClosed()) { try { sequenceDiagramWindow.setClosed(false); windowArea.add(sequenceDiagramWindow); } catch (PropertyVetoException pve) { System.out.println("Error: unable to reopen Sequence Diagram Window.\n"); } } sequenceDiagramWindow.setVisible(true); sequenceDiagramWindow.moveToFront(); } } class CodeItem extends JMenuItem implements ActionListener { public CodeItem() { super("Generate Code", KeyEvent.VK_G); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e) { if (codeWindow.isClosed()) { try { codeGenerator.generateCode(); codeWindow.setClosed(false); windowArea.add(codeWindow); } catch (PropertyVetoException pve) { System.out.println("Error: unable to open Code Window."); } } else codeGenerator.generateCode(); codeWindow.setVisible(true); codeWindow.moveToFront(); } } }
78 DiagramCanvas.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.io.*; /** * The superclass of other diagram canvases. This class defines all * of the Key Listener behavior, which is the same in all the diagram views. * This class was expanded from a class written by J.Bergin "PaintDrawApplet" 12.97 */ class DiagramCanvas extends JComponent implements KeyListener, Observer { public DiagramCanvas(ProjectModel pm) { setBackground(Color.white); addKeyListener(this); mode = defaultmode; stringBuilder = new StringBuffer(""); projectModel = pm; } public void update (Observable pm, Object arg) { } public void doLabelUpdate(String newLabel) { //overriden for each type of diagram canvas } public void doDeleteUpdate(boolean undo) {//overridden for each type of diagram canvas } public void doRestoreUpdate(Figure restoreItem) {//overridden for each type of diagram canvas } public void invalidate() { super.invalidate(); offscreen = null; } public void update (Graphics g) { if (doubleBuffering) paint (g); else super.update(g); } public void flip(Figure f) { Graphics g = getGraphics(); g.setXORMode(getBackground()); f.drawOutline(g); g.dispose(); }
79 private void doDraw(Graphics g) { Enumeration e = connections.elements(); while (e.hasMoreElements()) ((Figure) e.nextElement()).draw(g); e=figures.elements(); while (e.hasMoreElements()) ((Figure) e.nextElement()).draw(g); } public void paintComponent (Graphics g) { if (!doubleBuffering) { doDraw(g); return; } Dimension d = getSize(); int h = d.height; int w = d.width; if (offscreen == null) { offscreen = createImage (w,h); og = offscreen.getGraphics(); og.setColor(getBackground()); og.fillRect(0,0,w,h); } og = offscreen.getGraphics(); og.setClip(0,0,w,h); doDraw(og); g.drawImage(offscreen, 0,0,null); og.setColor(getBackground()); og.fillRect(0,0,w,h); og.dispose(); } public void keyPressed (KeyEvent e) { int pressed = e.getKeyCode(); switch (pressed) { case KeyEvent.VK_LEFT: if (stringIndex > 0) stringIndex --; else stringIndex = stringBuilder.length() - 1; break; case KeyEvent.VK_RIGHT: if (stringIndex >= 0) stringIndex = stringIndex + 2; if (stringIndex >= stringBuilder.length()) stringIndex = -1; break; case KeyEvent.VK_DELETE: deleteObject(false); break;
80 default: break; } } public void keyReleased (KeyEvent e) { } public void keyTyped (KeyEvent e) { e.consume(); char typed = e.getKeyChar(); switch (mode) { case TEXT: char stringfrag; switch (typed) { case KeyEvent.VK_ENTER: if (labelFigure != null) doLabelUpdate(stringBuilder.toString()); stringBuilder = new StringBuffer(""); firstLetter = false; labelFigure = null; stringIndex = -1; break; case KeyEvent.VK_BACK_SPACE: if (labelFigure != null) { if (firstLetter) firstLetter = false; else { if (stringIndex < 0) stringIndex = stringBuilder.length() - 1; if (stringIndex >= 0) stringBuilder.deleteCharAt(stringIndex); stringIndex --; } String changedlabel = stringBuilder.toString(); labelFigure.setLabel(changedlabel); } break; default: if (labelFigure != null) { if (firstLetter) { stringBuilder.append(labelFigure.getLabel()); firstLetter = false; } stringfrag = e.getKeyChar(); if (stringIndex >= 0) { stringBuilder.insert(stringIndex + 1, stringfrag); stringIndex ++; } else stringBuilder.append(stringfrag);
81 labelFigure.setLabel(stringBuilder.toString()); } break; } repaint(); break; default: break; } } public boolean deleteObject(boolean undo) { if (selectedFigure != null) { doDeleteUpdate(undo); boolean connected = false; for (int index = 0; index < connections.size(); index++) { Connection c = (Connection)connections.elementAt(index); connected = c.checkConnect(selectedFigure); if (connected) { connections.removeElement(c); index--; if (undo) deletes.push(c); connected = false; } } if (undo) deletes.push(selectedFigure); figures.removeElement(selectedFigure); } repaint(); selectedFigure = null; return !(deletes.empty()); } public boolean undoDeleteObject() { Figure restore = (Figure)deletes.pop(); figures.addElement((Object)restore); doRestoreUpdate(restore); while (!(deletes.empty())) { restore = (Figure)deletes.peek(); if (restore instanceof Connection) { connections.addElement(restore); deletes.pop(); doRestoreUpdate(restore); } else break; } repaint(); return !(deletes.empty()); } public void changeMode(int newmode) { if (mode == TEXT)
82 { if (labelFigure != null) doLabelUpdate(stringBuilder.toString()); } mode = newmode; selectedFigure = null; labelFigure = null; } private Image offscreen = null; private final boolean doubleBuffering = true; Graphics og; // The offscreen graphics context. protected Figure selectedFigure = null; protected Figure labelFigure = null; protected boolean firstLetter = false; protected StringBuffer stringBuilder; protected int stringIndex; protected boolean dragging = false; protected Vector figures = new Vector(); protected Vector connections = new Vector(); protected Stack deletes = new Stack(); protected Vector projectObjects; protected Stack deletedObjects = new Stack(); protected int mode; protected Cursor drawCursor; protected ProjectModel projectModel; public static final int defaultmode = 1; public static final int MOVE = 1; public static final int TEXT = 2; public static final int SQUARE = 3; public static final int OVAL = 4; public static final int ACTOR = 5; public static final int CONNECT = 6; public static final int RESIZE = 7; public static final int LIFELINE = 8; } DiagramToolBar.java import javax.swing.*; /** * The superclass of all diagram tool bars. This class sets up the * canvas that should respond to any tool actions. */ class DiagramToolBar extends JToolBar { public DiagramToolBar(DiagramCanvas target) { super(JToolBar.VERTICAL); this.target = target; } public DiagramCanvas target; }
83 DiagramWindow.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; /** * The superclass of all diagram windows. This class sets up the menus * and the "cut" and "undo" actions. */ public class DiagramWindow extends BaseInternalFrame implements KeyListener, Runnable { public DiagramWindow(String name) { super (name); undoMenuItem = new UndoMenuItem(); editMenu.add(undoMenuItem); CutMenuItem item = new CutMenuItem (); editMenu.add(item); addKeyListener(this); run(); } DiagramCanvas usercanvas; static final boolean undo = true; private boolean enabled = false; private UndoMenuItem undoMenuItem; public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_DELETE) usercanvas.deleteObject(!undo); } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } public void run() { } class CutMenuItem extends JMenuItem implements ActionListener { public CutMenuItem() { super("Cut", KeyEvent.VK_C); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK)); addActionListener(this); } public void actionPerformed (ActionEvent e)
84 { enabled = usercanvas.deleteObject(undo); undoMenuItem.setEnabled(enabled); } } class UndoMenuItem extends JMenuItem implements ActionListener { public UndoMenuItem() { super("Undo", KeyEvent.VK_U); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK)); addActionListener(this); setEnabled(enabled); } public void actionPerformed (ActionEvent e) { enabled = usercanvas.undoDeleteObject(); setEnabled(enabled); } } } Figure.java import java.awt.*; /** * This class was adapted from Figure.java from J.Bergin's * "PaintDrawApplet" 12.97 * It is the superclass of all figures in the diagram views. * Each figure knows its own ID number and draws its own label. */ public abstract class Figure implements java.io.Serializable { protected Rectangle bounds; protected String label; protected int IDNumber; protected boolean selected = false; public Figure (int ID, int x, int y, int w, int h) { bounds = new Rectangle (x,y,w,h); IDNumber = ID; } public Figure(int ID, String label, int x, int y, int w, int h) { bounds = new Rectangle(x, y, w, h); this.label = label; IDNumber = ID; } public String getLabel() { return label; } public void setLabel(String s) { label = s;
85 } public int getID() { return IDNumber; } public int findMiddleX(int width, String label, FontMetrics font) { int labelwidth = font.stringWidth(label); int beginningofmiddle = width/2 - labelwidth/2; return beginningofmiddle; } public int findMiddleY(int itemheight, FontMetrics font) { int labelheight = font.getHeight(); int bottomofmiddle = itemheight/2 + labelheight/4; return bottomofmiddle; } public void setBounds(int x, int y, int w, int h) { bounds = new Rectangle (x,y,w,h); } public void setBounds(int w, int h) { bounds.setSize(w,h); } public Rectangle getBounds() { return bounds; } public void setLocation(Point p) { bounds.setLocation(p); } public void setLocation(int x, int y) { bounds.setLocation(x,y); } public abstract void draw(Graphics g); public abstract void drawOutline(Graphics g); public Connection connect(int ID, String label, Figure b) { return new Connection(ID, label, this, b); } public boolean isSelected(){ return selected;} public void setSelected(boolean t){selected = t;} public void toggleSelected(){selected = !selected;} public void drawSelectors(Graphics g) { g.fillRect(bounds.x - 2 , bounds.y - 2, 4, 4); g.fillRect(bounds.x + bounds.width - 2 , bounds.y-2, 4, 4); g.fillRect(bounds.x-2 , bounds.y + bounds.height - 2, 4, 4); g.fillRect(bounds.x + bounds.width - 2 ,
86 bounds.y + bounds.height - 2, 4, 4); } public Rectangle rectangle(){ return bounds; } public Point location(){ return new Point(bounds.x, bounds.y); } public Point center(){ return new Point(bounds.x+bounds.width/2, bounds.y+bounds.height/2); } public Dimension dimension(){ return new Dimension(bounds.width, bounds.height);} public void move(int x, int y) { bounds.setLocation(x,y); } public void move(Point p) { bounds.setLocation(p); } public boolean contains(Point p) { return bounds.contains(p); } public boolean contains(int x, int y) { return bounds.contains(x, y); } public boolean contains(Figure f) { Rectangle figbounds = f.getBounds(); return bounds.contains(figbounds); } } LabelChange.java import java.lang.*; /** * This is the encapsulation of two strings. Both the old and new name * need to be known for certain name change updates. */ public class LabelChange { public LabelChange (String oldLabel, String newLabel) { this.oldLabel = oldLabel; this.newLabel = newLabel; } public String getOld() { return oldLabel; } public String getNew() { return newLabel; }
87 private String oldLabel; private String newLabel; } LifelineButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * This is a GUI element that changes the mode in the incomplete * sequence diagram view. */ class LifelineButton extends ToolButton implements ActionListener { public LifelineButton (DiagramCanvas target) { super (target,image, "Draw object lifeline", target.LIFELINE, Cursor.DEFAULT_CURSOR); } public static final ImageIcon image = new ImageIcon("images/lifeline.jpg"); } MoveButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * This is a GUI element that allows the mode of a diagram canvas to * be changed so that a figure can be moved around. */ class MoveButton extends ToolButton implements ActionListener { public MoveButton (DiagramCanvas target) { super (target,image, "Move", target.MOVE, Cursor.MOVE_CURSOR); } private static final ImageIcon image = new ImageIcon("images/move.jpg"); } OvalButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * Changes diagram mode so user can draw an oval. */ class OvalButton extends ToolButton implements ActionListener
88 { public OvalButton (DiagramCanvas target) { super (target,image, "Draw use case", target.OVAL, Cursor.CROSSHAIR_CURSOR); } private static final ImageIcon image = new ImageIcon("images/oval.jpg"); } OvalFigure.java import java.awt.*; /** * Oval figures have ID numbers that correspond to the ID numbers of * Use Cases in the use case vector of the project model. They are * diagramatic representations of use cases. This class was elaborated from a * class written by J.Bergin for "PaintDrawApplet" 12.97 * see@ Figure */ public class OvalFigure extends Figure implements java.io.Serializable { public OvalFigure(int ID, String label, int x, int y, int w, int h) { super(ID, label, x, y, w, h); } public void draw(Graphics g) { int x = bounds.x, y = bounds.y, h = bounds.height, w = bounds.width; g.drawOval(x, y, w, h); Color c = g.getColor(); g.setColor(Color.white); g.fillOval(x+1, y+1, w - 2, h - 2); g.setColor(Color.red); if (label != null) { FontMetrics font = g.getFontMetrics(); int centerX = findMiddleX(w,label,font); int centerY = findMiddleY(h,font); g.drawString(label, x + centerX, y + centerY); } g.setColor(c); if(selected) drawSelectors(g); } public void drawOutline(Graphics g) { int x = bounds.x, y = bounds.y, h = bounds.height, w = bounds.width; g.drawOval(x, y, w, h); } } ProjectModel.java //Java-DACTL, Java Design, Analysis, and Coding TooL with UML //Anna S. Armentrout //September 1999 //Copyright (c) 1999
89 //Pace University import java.util.*; import java.io.*; /** * The "heart" of the modeling tool, this is the model. Project model keeps * track of the additions and changes made in all the views, and alerts the * views of changes made. A fairly simple class, most changes are recorded in * the vitally important use case and class vectors by the views */ class ProjectModel extends Observable implements Serializable { public ProjectModel () { IDTag = 0; useCases = new Vector(); classes = new Vector(); codeCurrent = true; projectID = newID(); } public int newID() { int current = IDTag; IDTag ++; return current; } public int getID() { return projectID; } public synchronized void setName(String name) { projectName = name; } public String getName() { return projectName; } public synchronized Vector getUseCases() { return useCases; } public synchronized Vector getClasses() { return classes; } public void setCodeState(boolean changed) { codeCurrent = !changed; } public boolean getCodeState() { return codeCurrent; }
90 //access to private variable public void registerChange() { setChanged(); } //Find a use case in the use case vector public UseCase findUseCase(int IDnumber) { for (int i = 0; i < useCases.size(); i++) { UseCase current = (UseCase)useCases.elementAt(i); if (current.getID() == IDnumber) return current; } return null; } //Find a class in the class vector public ClassObject findClass(int IDnumber) { for (int i = 0; i < classes.size(); i++) { ClassObject current = (ClassObject)classes.elementAt(i); if (current.getID() == IDnumber) return current; } return null; } private int IDTag; private String projectName; private int projectID; private Vector useCases; private Vector classes; private boolean codeCurrent; } ProjectMutableTreeNode.java import javax.swing.tree.*; /** * A node in the Project Tree. * see@ ProjectTree */ public class ProjectMutableTreeNode extends DefaultMutableTreeNode { public ProjectMutableTreeNode(String name, int ID) { super (name); IDnumber = ID; } public int getID() { return IDnumber; } private int IDnumber; }
91 ProjectTree.java //Java-DACTL, Java Design, Analysis, and Coding TooL with UML //Anna S. Armentrout //September 1999 //Copyright (c) 1999 //Pace University import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.tree.*; import javax.swing.event.*; import java.util.*; /** * This tree is an overview of the project, and is displayed on the left side * of the GUI at all times. Is updated as user changes and adds to project. * see@ ProjectMutableTreeNode */ public class ProjectTree extends JTree implements Observer, TreeSelectionListener, KeyListener { public ProjectTree(ProjectMutableTreeNode topnode, ProjectModel pm) { super(topnode); setCellRenderer(new CodeChangeRenderer()); top = topnode; projectModel = pm; treeModel = (DefaultTreeModel)this.getModel(); setEditable(true); getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION); putClientProperty("JTree.lineStyle", "Angled"); setShowsRootHandles(true); addTreeSelectionListener(this); addKeyListener(this); projectModel.addObserver(this); } ProjectModel projectModel; DefaultTreeModel treeModel; ProjectMutableTreeNode selectedNode = null; ProjectMutableTreeNode top; ProjectMutableTreeNode usecaseNode = null; ProjectMutableTreeNode classNode = null; ProjectMutableTreeNode sequenceNode = null; ProjectMutableTreeNode codeNode = null; String oldNodeName = null; String codeCurrent = "Code is up-to-date."; String codeObsolete = "Code could be refreshed."; public ProjectMutableTreeNode findNode(int ID, ProjectMutableTreeNode typeNode) { ProjectMutableTreeNode foundNode = (ProjectMutableTreeNode)typeNode.getFirstChild(); while (foundNode != null)
92 { if (foundNode.getID() == ID) break; foundNode = (ProjectMutableTreeNode)typeNode.getChildAfter (foundNode); } return foundNode; } public void valueChanged(TreeSelectionEvent e) { ProjectMutableTreeNode node; node = (ProjectMutableTreeNode)(e.getPath().getLastPathComponent()); selectedNode = node; oldNodeName = (String)node.getUserObject(); } public void keyPressed (KeyEvent e) { } public void keyReleased (KeyEvent e) { } public void keyTyped (KeyEvent e) { char typed = e.getKeyChar(); if (typed == KeyEvent.VK_ENTER) { if (selectedNode != null) { Update nameChanged = null; int ID = selectedNode.getID(); String newName = (String)selectedNode.getUserObject(); //Naming a use case if (oldNodeName.equals("New Use Case")) { UseCase nameUC = projectModel.findUseCase(ID); nameUC.setName(newName); nameChanged = new Update(Update.TREE_UC, ID, Update.CHANGE, UseCase.NAME, newName); } //Naming a class else if (oldNodeName.equals("New Class")) { ClassObject nameClass = projectModel.findClass(ID); nameClass.setName(newName); nameChanged = new Update(Update.TREE_CO, ID, Update.CHANGE, ClassObject.NAME, newName); } //Naming a sequence diagram else if (oldNodeName.equals("New Sequence Diagram")) { } //These names can't be changed else if ( (oldNodeName.equals("Use Cases")) || (oldNodeName.equals("Classes")) || (oldNodeName.equals("Sequence Diagrams")) || (oldNodeName.equals(codeCurrent)) || (oldNodeName.equals(codeObsolete)) )
93 selectedNode.setUserObject(oldNodeName); //Renaming the project else if (selectedNode.equals(top)) { projectModel.setName(newName); nameChanged = new Update(Update.TREE_UC, ID, Update.CHANGE, 0, newName); } //The node had a name previously and it is being changed else { ProjectMutableTreeNode parent = (ProjectMutableTreeNode)selectedNode.getParent(); //use case name is being changed if (parent.equals(usecaseNode)) { UseCase nameUC = projectModel.findUseCase(ID); nameUC.setName(newName); nameChanged = new Update(Update.TREE_UC, ID, Update.CHANGE, UseCase.NAME, new LabelChange(oldNodeName, newName)); } //class name is being changed else if (parent.equals(classNode)) { ClassObject nameClass = projectModel.findClass(ID); nameClass.setName(newName); nameChanged = new Update(Update.TREE_CO, ID, Update.CHANGE, ClassObject.NAME, new LabelChange(oldNodeName, newName)); } //sequence diagram name is being changed else if (parent.equals(sequenceNode)) {//changing the name of a sequence diagram } else { ProjectMutableTreeNode grandparent = (ProjectMutableTreeNode)parent.getParent(); //name of an inner class is being changed if (grandparent.equals(classNode)) nameChanged = new Update(Update.TREE_CO, parent.getID(), Update.CHANGE, ClassObject.INNER_CLASS, new LabelChange(oldNodeName, newName)); } } //if one of the above cases was true if (nameChanged != null) { projectModel.registerChange(); projectModel.notifyObservers(nameChanged); } } } oldNodeName = null; selectedNode = null; } public void update(Observable pm, Object arg) { Update treeUpdate = (Update)arg; int origin = treeUpdate.getOrigin();
94 int action = treeUpdate.getAction(); switch (origin) { case Update.USE_CASE_FORM: case Update.USE_CASE_DIAGRAM: if (action == Update.ADD) { if (treeUpdate.getField() == 0) { if (usecaseNode == null) { usecaseNode = new ProjectMutableTreeNode("Use Cases", projectModel.newID()); treeModel.insertNodeInto(usecaseNode, top, top.getChildCount()); } UseCase newUC = (UseCase)treeUpdate.getArg(); ProjectMutableTreeNode newNode = new ProjectMutableTreeNode("New Use Case", treeUpdate.getID()); treeModel.insertNodeInto(newNode, usecaseNode, usecaseNode.getChildCount()); } } else if (action == Update.CHANGE) { if (treeUpdate.getField() == UseCase.NAME) { int findID = treeUpdate.getID(); ProjectMutableTreeNode changeNode = findNode(findID, usecaseNode); if (changeNode != null) { if (treeUpdate.getArg() instanceof String) changeNode.setUserObject(treeUpdate.getArg()); else { LabelChange lc = (LabelChange)treeUpdate.getArg(); changeNode.setUserObject(lc.getNew()); } } } treeModel.reload(); } else if (action == Update.DELETE) { if (treeUpdate.getField() != UseCase.ACTOR) { int deleteID = treeUpdate.getID(); ProjectMutableTreeNode deleteNode = findNode(deleteID, usecaseNode); if (deleteNode != null) treeModel.removeNodeFromParent(deleteNode); } } break; case Update.CLASS_FORM: case Update.CLASS_DIAGRAM: if (action == Update.ADD) { if (treeUpdate.getField() == 0) { if (classNode == null) { classNode = new ProjectMutableTreeNode("Classes", projectModel.newID());
95 treeModel.insertNodeInto(classNode, top, top.getChildCount()); } ClassObject newClass = (ClassObject)treeUpdate.getArg(); String name = newClass.getName(); if (name == null) name = "New Class"; ProjectMutableTreeNode newNode = new ProjectMutableTreeNode(name, treeUpdate.getID()); treeModel.insertNodeInto(newNode, classNode, classNode.getChildCount()); } else if (treeUpdate.getField() == ClassObject.INNER_CLASS) { int parentID = treeUpdate.getID(); ProjectMutableTreeNode parentNode = findNode(parentID, classNode); if (parentNode != null) { ProjectMutableTreeNode newNode = new ProjectMutableTreeNode((String)treeUpdate.getArg(), projectModel.newID()); treeModel.insertNodeInto(newNode, parentNode, parentNode.getChildCount()); } } } else if (action == Update.CHANGE) { if (treeUpdate.getField() == ClassObject.NAME) { int findID = treeUpdate.getID(); ProjectMutableTreeNode changeNode = findNode(findID, classNode); if (changeNode != null) { if (treeUpdate.getArg() instanceof String) changeNode.setUserObject(treeUpdate.getArg()); else { LabelChange lc = (LabelChange)treeUpdate.getArg(); changeNode.setUserObject(lc.getNew()); } } } else if (treeUpdate.getField() == ClassObject.INNER_CLASS) { } treeModel.reload(); } else if (action == Update.DELETE) { if (treeUpdate.getField() == 0) { int deleteID = treeUpdate.getID(); ProjectMutableTreeNode deleteNode = findNode(deleteID, classNode); if (deleteNode != null) treeModel.removeNodeFromParent(deleteNode); } if (treeUpdate.getField() == ClassObject.INNER_CLASS) { int parentID = treeUpdate.getID();
96 ProjectMutableTreeNode parent = findNode(parentID, classNode); if (parent != null) { String innerClass = (String)treeUpdate.getArg(); ProjectMutableTreeNode innerNode = (ProjectMutableTreeNode)parent.getFirstChild(); while (innerNode != null) { String checkString = (String)innerNode.getUserObject(); if (checkString.equals(innerClass)) break; innerNode =(ProjectMutableTreeNode) parent.getChildAfter(innerNode); } if (innerNode != null) treeModel.removeNodeFromParent(innerNode); } } } break; case Update.SEQUENCE_DIAGRAM: if (action == Update.ADD); else if (action == Update.CHANGE); else if (action == Update.DELETE); break; case Update.CODE_GENERATOR: String changed = (String)treeUpdate.getArg(); if (changed.equals("true")) { if (codeNode == null) { codeNode = new ProjectMutableTreeNode(codeObsolete, projectModel.newID()); treeModel.insertNodeInto(codeNode, top, top.getChildCount()); } else codeNode.setUserObject(codeObsolete); } else { if (codeNode == null) { codeNode = new ProjectMutableTreeNode(codeCurrent, projectModel.newID()); treeModel.insertNodeInto(codeNode, top, top.getChildCount()); } else codeNode.setUserObject(codeCurrent); } treeModel.reload(); break; case Update.OPEN: Vector objects = projectModel.getUseCases(); if (! objects.isEmpty()) { if (usecaseNode == null) { usecaseNode = new ProjectMutableTreeNode("Use Cases",
97 projectModel.newID()); treeModel.insertNodeInto(usecaseNode, top, top.getChildCount()); } for (int i = 0; i < objects.size(); i++) { UseCase current = (UseCase)objects.elementAt(i); String name = current.getName(); if (name == null) name = "New Use Case"; ProjectMutableTreeNode newNode = new ProjectMutableTreeNode(name, current.getID()); treeModel.insertNodeInto(newNode, usecaseNode, usecaseNode.getChildCount()); } } objects = projectModel.getClasses(); if (! objects.isEmpty()) { if (classNode == null) { classNode = new ProjectMutableTreeNode("Classes", projectModel.newID()); treeModel.insertNodeInto(classNode, top, top.getChildCount()); } for (int i = 0; i < objects.size(); i++) { ClassObject current = (ClassObject)objects.elementAt(i); String name = current.getName(); if (name == null) name = "New Class"; ProjectMutableTreeNode newNode = new ProjectMutableTreeNode(name, current.getID()); treeModel.insertNodeInto(newNode, classNode, classNode.getChildCount()); DefaultListModel inner = current.getInnerClasses(); if (! inner.isEmpty()) { for (int index = 0; index < inner.getSize(); index ++) { String innerName = (String)inner.getElementAt(index); ProjectMutableTreeNode innerNode = new ProjectMutableTreeNode(innerName, projectModel.newID()); treeModel.insertNodeInto(innerNode, newNode, newNode.getChildCount()); } } } } break; default: break; } }
class CodeChangeRenderer extends DefaultTreeCellRenderer
98 { public CodeChangeRenderer() { changedIcon = new ImageIcon("images/redleaf.gif"); sameIcon = new ImageIcon("images/blueleaf.gif"); } ImageIcon changedIcon; ImageIcon sameIcon; private static final int RED = 0; private static final int BLUE = 1; private static final int REGULAR = 2; public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); if (leaf) { int type = isCodeNode(value); switch (type) { case RED: setIcon(changedIcon); break; case BLUE: setIcon(sameIcon); break; } } return this; } protected int isCodeNode(Object value) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; if (node.equals(codeNode)) { String name = (String)node.getUserObject(); if (name.equals(codeObsolete)) return RED; else if (name.equals(codeCurrent)) return BLUE; } return REGULAR; } }
}
99 ProjectTreeModelListener.java import java.io.*; import javax.swing.tree.*; import javax.swing.event.*; /** * Allows Tree to know if one of the nodes' names has been changed. * This code was adapted from the tutorial on Trees at * http://java.sun.com/docs/books/tutorial/uiswing/components/ * example-swing/DynamicTree.java * based on an example by Richard Stanford. * see@ ProjectTree */ public class ProjectTreeModelListener implements TreeModelListener { public ProjectTreeModelListener() { super(); } public void treeStructureChanged(TreeModelEvent e) { } public void treeNodesInserted(TreeModelEvent e) { } public void treeNodesRemoved(TreeModelEvent e) { } public void treeNodesChanged(TreeModelEvent e) { ProjectMutableTreeNode node; node = (ProjectMutableTreeNode)(e.getTreePath().getLastPathComponent()); /* * If the event lists children, then the changed * node is the child of the node we've already * gotten. Otherwise, the changed node and the * specified node are the same. */ try { int index = e.getChildIndices()[0]; node = (ProjectMutableTreeNode)(node.getChildAt(index)); } catch (NullPointerException exc) { System.out.println ("Null pointer"); } System.out.println("The user has finished editing the node."); System.out.println("New value: " + node.getUserObject()); } } RectangleFigure.java
100 import java.awt.*; /** * Rectangle figures have ID numbers that correspond to the ID numbers of * Classes in the class vector of the project model. They are diagramatic * representations of classes. This class was elaborated from a class written * by J.Bergin for "PaintDrawApplet" 12.97 * see@ Figure */ public class RectangleFigure extends Figure implements java.io.Serializable { public RectangleFigure(int ID, String label, int x, int y, int w, int h) { super(ID, label, x, y, w, h); } public void draw(Graphics g) { int x = bounds.x, y = bounds.y, h = bounds.height, w = bounds.width; g.drawRect(x, y, w, h); Color c = g.getColor(); g.setColor(Color.white); g.fillRect(x+1, y+1, w - 1, h - 1); g.setColor(Color.red); if (label != null) { FontMetrics font = g.getFontMetrics(); int centerX = findMiddleX(w,label,font); int centerY = findMiddleY(h,font); g.drawString(label, x + centerX, y + centerY); } g.setColor(c); if(selected) drawSelectors(g); } public void drawOutline(Graphics g) { int x = bounds.x, y = bounds.y, h = bounds.height, w = bounds.width; g.drawRect(x, y, w, h); } } ResizeButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * Allows the user to change the mode in the current diagram canvas so that * they can change the dimensions of a figure. */ class ResizeButton extends ToolButton implements ActionListener { public ResizeButton (DiagramCanvas target) { super (target,image, "Resize figure", target.RESIZE, Cursor.DEFAULT_CURSOR); }
101 private static final ImageIcon image = new ImageIcon("images/resize.jpg"); } SequenceDiagramCanvas.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.io.*; /** * Canvas where sequence diagrams would be drawn. Allows user to show * interactions between objects. Sequence diagrams are currently not fully * implemented. */ class SequenceDiagramCanvas extends DiagramCanvas implements MouseMotionListener, MouseListener { public SequenceDiagramCanvas(ProjectModel pm) { super (pm); addMouseMotionListener(this); addMouseListener(this); } public void mouseClicked(MouseEvent e) { boolean doDraw = false; switch (mode) { case MOVE: Point p = e.getPoint(); Enumeration v = figures.elements(); selectedFigure = null; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { if(! f.isSelected()) { doDraw = true; f.setSelected(true); selectedFigure = f; } } else { if(f.isSelected()) { doDraw = true; f.setSelected(false); } } } break; case SQUARE: p = e.getPoint(); int ID = projectModel.newID(); RectangleFigure project = new RectangleFigure(ID, null, p.x,
102 p.y,100,100); figures.add (project); doDraw = true; break; case OVAL: p = e.getPoint(); ID = projectModel.newID(); OvalFigure usecase = new OvalFigure(ID, null, p.x, p.y, 60, 30); figures.add(usecase); doDraw = true; break; case CONNECT: p = e.getPoint(); v = figures.elements(); selectedFigure = null; doDraw = false; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { if (one == null) one = f; else if (two == null) { doDraw = true; two = f; ID = projectModel.newID(); Connection c = new Connection (ID, null, one, two); connections.add(c); one = null; two = null; } } } break; case TEXT: requestFocus(); stringBuilder = new StringBuffer(""); p = e.getPoint(); v = figures.elements(); labelFigure = null; stringIndex = -1; doDraw = false; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { doDraw = true; labelFigure = f; if (labelFigure.getLabel() != null) firstLetter = true; } } if (!doDraw)
103 { v = connections.elements(); while (v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if (f.contains(p)) { doDraw = true; labelFigure = f; if (labelFigure.getLabel() != null) firstLetter = true; } } } break; } if (doDraw) repaint(); } public void mouseDragged(MouseEvent e) { e.consume(); switch (mode) { case MOVE: if(dragging) { flip(selectedFigure); selectedFigure.move(e.getPoint()); flip(selectedFigure); } break; case SQUARE: Point secondPoint = e.getPoint(); originPoint = new Point(firstPointX, firstPointY); int width = secondPoint.x - firstPointX; if (width < 0) { width = -width; originPoint.x = secondPoint.x; } int height = secondPoint.y - firstPointY; if (height < 0) { height = -height; originPoint.y = secondPoint.y; } if (selectedFigure == null) { int ID = projectModel.newID(); RectangleFigure project = new RectangleFigure(ID, null, originPoint.x, originPoint.y,width,height); figures.add (project); selectedFigure = project; } else { selectedFigure.setLocation(originPoint); selectedFigure.setBounds(width, height); } break;
104 case OVAL: secondPoint = e.getPoint(); originPoint = new Point(firstPointX, firstPointY); width = secondPoint.x - firstPointX; if (width < 0) { width = -width; originPoint.x = secondPoint.x; } height = secondPoint.y - firstPointY; if (height < 0) { height = -height; originPoint.y = secondPoint.y; } if (selectedFigure == null) { int ID = projectModel.newID(); OvalFigure usecase = new OvalFigure (ID, null, originPoint.x, originPoint.y,width,height); figures.add (usecase); selectedFigure = usecase; } else { selectedFigure.setLocation(originPoint); selectedFigure.setBounds(width, height); } break; case RESIZE: if (selectedFigure instanceof ActorFigure) break; else if (dragging) { Point p = e.getPoint(); int cursortype = drawCursor.getType(); Rectangle figbounds = selectedFigure.getBounds(); int differenceX; int differenceY; switch (cursortype) { case drawCursor.N_RESIZE_CURSOR: differenceY = figbounds.y - p.y; selectedFigure.setLocation(figbounds.x, p.y); selectedFigure.setBounds(figbounds.width, figbounds.height + differenceY); break; case drawCursor.S_RESIZE_CURSOR: differenceY = p.y - figbounds.y; selectedFigure.setBounds(figbounds.width, differenceY); break; case drawCursor.E_RESIZE_CURSOR: differenceX = p.x - figbounds.x; selectedFigure.setBounds(differenceX, figbounds.height); break; case drawCursor.W_RESIZE_CURSOR:
105 differenceX = figbounds.x - p.x; selectedFigure.setLocation(p.x, figbounds.y); selectedFigure.setBounds(figbounds.width + differenceX, figbounds.height); break; case drawCursor.NW_RESIZE_CURSOR: differenceX = figbounds.x - p.x; differenceY = figbounds.y - p.y; selectedFigure.setLocation(p.x, p.y); selectedFigure.setBounds(figbounds.width + differenceX, figbounds.height + differenceY); break; case drawCursor.NE_RESIZE_CURSOR: differenceX = p.x - figbounds.x; differenceY = figbounds.y - p.y; selectedFigure.setLocation(figbounds.x, p.y); selectedFigure.setBounds(differenceX, figbounds.height + differenceY); break; case drawCursor.SE_RESIZE_CURSOR: differenceX = p.x - figbounds.x; differenceY = p.y - figbounds.y; selectedFigure.setBounds(differenceX, differenceY); break; case drawCursor.SW_RESIZE_CURSOR: differenceX = figbounds.x - p.x; differenceY = p.y - figbounds.y; selectedFigure.setLocation(p.x, figbounds.y); selectedFigure.setBounds(figbounds.width + differenceX, differenceY); break; } } break; } repaint(); } public void mouseMoved(MouseEvent e) { e.consume(); if (mode == RESIZE) { Point p = e.getPoint(); Enumeration v = figures.elements(); selectedFigure = null; boolean doDraw = false; int resultcursor = drawCursor.DEFAULT_CURSOR; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { int x = f.getBounds().x;
106 int y = f.getBounds().y; int xw = f.getBounds().x + f.getBounds().width - 1; int yh = f.getBounds().y + f.getBounds().height - 1; boolean N = false; boolean S = false; boolean E = false; boolean W = false; if (p.x == x) W = true; if (p.x == xw) E = true; if (p.y == y) N = true; if (p.y == yh) S = true; if (N && W) resultcursor = drawCursor.NW_RESIZE_CURSOR; else if (S && E) resultcursor = drawCursor.SE_RESIZE_CURSOR; else if (S && W) resultcursor = drawCursor.SW_RESIZE_CURSOR; else if (N && E) resultcursor = drawCursor.NE_RESIZE_CURSOR; else if (W) resultcursor = drawCursor.W_RESIZE_CURSOR; else if (E) resultcursor = drawCursor.E_RESIZE_CURSOR; else if (N) resultcursor = drawCursor.N_RESIZE_CURSOR; else if (S) resultcursor = drawCursor.S_RESIZE_CURSOR; selectedFigure = f; } drawCursor = drawCursor.getPredefinedCursor(resultcursor); setCursor(drawCursor); } } } public void mousePressed(MouseEvent e) { e.consume(); switch (mode) { case MOVE: if(selectedFigure != null && selectedFigure.contains(e.getPoint())) dragging = true; break; case SQUARE: case OVAL: selectedFigure = null; Point firstPoint = e.getPoint(); firstPointX = firstPoint.x; firstPointY = firstPoint.y; break;
107 case ACTOR: int ID = projectModel.newID(); ActorFigure actor = new ActorFigure(ID, null, e.getX(), e.getY(), 50, 50); figures.add(actor); invalidate(); repaint(); break; case RESIZE: int cursortype = drawCursor.getType(); if (cursortype != drawCursor.DEFAULT_CURSOR) dragging = true; break; case CONNECT: case TEXT: default: break; } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseReleased(MouseEvent e) { e.consume(); dragging = false; }
private Figure one = null; private Figure two = null; private int firstPointX; private int firstPointY; private Point originPoint; } SequenceDiagramWindow.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*;
108 /** * The window in which users would make sequence diagrams. * Sequence diagrams are currently not fully implemented. */ public class SequenceDiagramWindow extends DiagramWindow { public SequenceDiagramWindow(String name, ProjectModel pm) { super (name); usercanvas = new SequenceDiagramCanvas(pm); sequencetools = new SequenceToolBar(usercanvas); getContentPane().add(usercanvas); getContentPane().add(sequencetools, BorderLayout.WEST); } SequenceToolBar sequencetools; } SequenceToolBar.java import javax.swing.*; import java.awt.event.*; /** * Sets up the tools needed to create sequence diagrams. * Sequence diagrams are currently not fully implemented. */ class SequenceToolBar extends DiagramToolBar { public SequenceToolBar(DiagramCanvas target) { super(target); add(move); add(square); add(text); add(connect); add(lifeline); add(resize); } MoveButton move = new MoveButton (this.target); SquareButton square = new SquareButton (this.target, "Draw object"); TextButton text = new TextButton (this.target); ConnectButton connect = new ConnectButton(this.target, ConnectButton.sequenceimage, "Draw message"); LifelineButton lifeline = new LifelineButton(this.target); ResizeButton resize = new ResizeButton(this.target); } SquareButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * A GUI element that changes the mode in the current diagram canvas, * allowing the user to draw a square.
109 */ class SquareButton extends ToolButton implements ActionListener { public SquareButton (DiagramCanvas target, String hint) { super (target,image, hint, target.SQUARE, Cursor.CROSSHAIR_CURSOR); } private static final ImageIcon image = new ImageIcon("images/square.jpg"); } SystemRectangleFigure.java import java.awt.*; /** * A special rectangle figure that represents the current project * in the use case diagram view. */ public class SystemRectangleFigure extends RectangleFigure { public SystemRectangleFigure(int ID, String label, int x, int y, int w, int h) { super (ID, label, x, y, w, h); } public void draw(Graphics g) { int x = bounds.x, y = bounds.y, h = bounds.height, w = bounds.width; g.drawRect(x, y, w, h); Color c = g.getColor(); //g.setColor(Color.white); //g.fillRect(x+1, y+1, w - 1, h - 1); g.setColor(Color.red); if (label != null) { FontMetrics font = g.getFontMetrics(); int centerX = findMiddleX(w,label,font); g.drawString(label, x + centerX, y - 3); } g.setColor(c); if(selected) drawSelectors(g); } } TextButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * This is a GUI element that changes the mode in a particular diagram view, * so that a figure can be labeled. */ class TextButton extends ToolButton implements ActionListener { public TextButton (DiagramCanvas target) { super (target,image, "Label", target.TEXT, Cursor.TEXT_CURSOR);
110 } private static final ImageIcon image = new ImageIcon("images/label.jpg"); } ToolButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * A superclass for the buttons that are used in the various diagram views. */ class ToolButton extends JButton implements ActionListener { public ToolButton (DiagramCanvas target, ImageIcon image, String hinttext, int modename, int cursor) { super (); init(null, image); mycanvas = target; mymode = modename; mycursor = cursor; setToolTipText (hinttext); addActionListener (this); } public void actionPerformed (ActionEvent e) { mycanvas.changeMode(mymode); Cursor toolCursor = Cursor.getPredefinedCursor(mycursor); mycanvas.setCursor(toolCursor); } protected DiagramCanvas mycanvas; protected int mymode; protected int mycursor; } Update.java import java.lang.*; /** * This object encapsulates the information that is sent to all Observers * by the Observable (ProjectModel). The observers are able to determine * what kind of action to take based on this informtion. */ class Update extends Object { public Update(int location, int argID, int action, int field, Object arg) { origin = location; objectID = argID; this.action = action; this.field = field; changeObject = arg; }
111 public int getOrigin() { return origin; } public int getID() { return objectID; } public int getAction() { return action; } public int getField() { return field; } public Object getArg() { return changeObject; } public String toString() { return new String("Origin: " + origin + " ID: " + objectID + " Action: " + action); } private int origin; public static final int PROJECT = 1; public static final int USE_CASE_FORM = 2; public static final int USE_CASE_DIAGRAM = 3; public static final int CLASS_FORM = 4; public static final int CLASS_DIAGRAM = 5; public static final int SEQUENCE_DIAGRAM = 6; public static final int TREE_UC = 7; public static final int TREE_CO = 8; public static final int CODE_GENERATOR = 9; public static final int OPEN = 10; private int objectID; private Object changeObject; private int field; private int action; public static final int ADD = 1; public static final int DELETE = 2; public static final int CHANGE = 3; } UseCase.java import java.io.*; import java.lang.*; import javax.swing.text.*;
112 /** * The object that holds all the information about an individual use case. * These are stored in a vector in ProjectModel and manipulated by * UseCaseForm. */ class UseCase extends Object implements Serializable { public UseCase(int num) { IDNumber = num; } public int getID() { return IDNumber; } public String getName() { return Name; } public String getActor() { return Actor; } public String getPurpose() { return Purpose; } public String getDescription() { return Description; } public void setName(String name) { Name = name; } public void setActor(String actor) { Actor = actor; } public void setPurpose(String purpose) { Purpose = purpose; } public void setDescription(String desc) { Description = desc; } public String toString() { return new String("UseCase: " + IDNumber + " name: " + Name + " actor: " + Actor); } private int IDNumber; private String Name = null; private String Actor = null;
113 private String Purpose; private String Description; public static final int NAME = 1; public static final int ACTOR = 2; public static final int PURPOSE = 3; public static final int DESCRIPTION = 4; } UseCaseDiagramCanvas.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.io.*; /** * Handles all mouse drawing events for UseCaseDiagram view. Key events are * handled by superclass, because key events for all diagram windows can * basically be handled in the same manner. * @see DiagramCanvas */ class UseCaseDiagramCanvas extends DiagramCanvas implements MouseMotionListener, MouseListener { public UseCaseDiagramCanvas(ProjectModel pm) { super (pm); addMouseMotionListener(this); addMouseListener(this); projectObjects = projectModel.getUseCases(); projectModel.addObserver(this); } public Figure findFigure(int IDnumber) { for (int i = 0; i < figures.size(); i++) { Figure current = (Figure)figures.elementAt(i); if (current.getID() == IDnumber) return current; } return null; } /** Arrange the figures on the drawing canvas **/ public void arrange() { int actorCount = 0; int usecaseCount = 0; //count number of respective elements in vector Enumeration v = figures.elements(); while (v.hasMoreElements()) { Figure current = (Figure)v.nextElement(); if (current instanceof ActorFigure) actorCount++; else if (current instanceof OvalFigure) usecaseCount++;
114 } //set number of columns based on number of usecases int numColumns; if (usecaseCount = 2) { if (labelFigure != null) doLabelUpdate(stringBuilder.toString()); requestFocus(); stringBuilder = new StringBuffer(""); p = e.getPoint(); v = figures.elements(); labelFigure = null; firstLetter = false; stringIndex = -1; doDraw = false; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { doDraw = true; labelFigure = f; if (labelFigure.getLabel() != null) { oldLabel = labelFigure.getLabel(); firstLetter = true; } break; }
123 } /** can't label connections if (!doDraw) { v = connections.elements(); while (v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if (f.contains(p)) { doDraw = true; labelFigure = f; if (labelFigure.getLabel() != null) firstLetter = true; } } }**/ } break; } if (doDraw) repaint(); } public void mouseDragged(MouseEvent e) { e.consume(); switch (mode) { case MOVE: if(dragging) { flip(selectedFigure); selectedFigure.move(e.getPoint()); flip(selectedFigure); } break; case SQUARE: Point secondPoint = e.getPoint(); originPoint = new Point(firstPointX, firstPointY); int width = secondPoint.x - firstPointX; if (width < 0) { width = -width; originPoint.x = secondPoint.x; } int height = secondPoint.y - firstPointY; if (height < 0) { height = -height; originPoint.y = secondPoint.y; } if (selectedFigure == null) { int ID = projectModel.newID(); SystemRectangleFigure project = new SystemRectangleFigure(ID, null, originPoint.x, originPoint.y,width,height); figures.add (project); selectedFigure = project; Update newProject = new Update(Update.PROJECT, ID, Update.ADD, 0, project); projectModel.registerChange();
124 projectModel.notifyObservers(newProject); } else { selectedFigure.setLocation(originPoint); selectedFigure.setBounds(width, height); } break; case OVAL: secondPoint = e.getPoint(); originPoint = new Point(firstPointX, firstPointY); width = secondPoint.x - firstPointX; if (width < 0) { width = -width; originPoint.x = secondPoint.x; } height = secondPoint.y - firstPointY; if (height < 0) { height = -height; originPoint.y = secondPoint.y; } if (selectedFigure == null) { int ID = projectModel.newID(); OvalFigure usecase = new OvalFigure (ID, null, originPoint.x, originPoint.y,width,height); figures.add (usecase); selectedFigure = usecase; UseCase newUseCase = new UseCase(ID); projectObjects.add(newUseCase); Update useCaseUpdate = new Update(Update.USE_CASE_DIAGRAM, ID, Update.ADD, 0, newUseCase); projectModel.registerChange(); projectModel.notifyObservers(useCaseUpdate); } else { selectedFigure.setLocation(originPoint); selectedFigure.setBounds(width, height); } break; case RESIZE: if (selectedFigure instanceof ActorFigure) break; else if (dragging) { Point p = e.getPoint(); int cursortype = drawCursor.getType(); Rectangle figbounds = selectedFigure.getBounds(); int differenceX; int differenceY; switch (cursortype) { case drawCursor.N_RESIZE_CURSOR: differenceY = figbounds.y - p.y; selectedFigure.setLocation(figbounds.x, p.y); selectedFigure.setBounds(figbounds.width,
125 figbounds.height + differenceY); break; case drawCursor.S_RESIZE_CURSOR: differenceY = p.y - figbounds.y; selectedFigure.setBounds(figbounds.width, differenceY); break; case drawCursor.E_RESIZE_CURSOR: differenceX = p.x - figbounds.x; selectedFigure.setBounds(differenceX, figbounds.height); break; case drawCursor.W_RESIZE_CURSOR: differenceX = figbounds.x - p.x; selectedFigure.setLocation(p.x, figbounds.y); selectedFigure.setBounds(figbounds.width + differenceX, figbounds.height); break; case drawCursor.NW_RESIZE_CURSOR: differenceX = figbounds.x - p.x; differenceY = figbounds.y - p.y; selectedFigure.setLocation(p.x, p.y); selectedFigure.setBounds(figbounds.width + differenceX, figbounds.height + differenceY); break; case drawCursor.NE_RESIZE_CURSOR: differenceX = p.x - figbounds.x; differenceY = figbounds.y - p.y; selectedFigure.setLocation(figbounds.x, p.y); selectedFigure.setBounds(differenceX, figbounds.height + differenceY); break; case drawCursor.SE_RESIZE_CURSOR: differenceX = p.x - figbounds.x; differenceY = p.y - figbounds.y; selectedFigure.setBounds(differenceX, differenceY); break; case drawCursor.SW_RESIZE_CURSOR: differenceX = figbounds.x - p.x; differenceY = p.y - figbounds.y; selectedFigure.setLocation(p.x, figbounds.y); selectedFigure.setBounds(figbounds.width + differenceX, differenceY); break; } } break; } repaint();
126 } public void mouseMoved(MouseEvent e) { e.consume(); if (mode == RESIZE) { Point p = e.getPoint(); Enumeration v = figures.elements(); selectedFigure = null; boolean doDraw = false; int resultcursor = drawCursor.DEFAULT_CURSOR; while(v.hasMoreElements()) { Figure f = (Figure)v.nextElement(); if(f.contains(p)) { int x = f.getBounds().x; int y = f.getBounds().y; int xw = f.getBounds().x + f.getBounds().width - 1; int yh = f.getBounds().y + f.getBounds().height - 1; boolean N = false; boolean S = false; boolean E = false; boolean W = false; if (p.x == x) W = true; if (p.x == xw) E = true; if (p.y == y) N = true; if (p.y == yh) S = true; if (N && W) resultcursor = drawCursor.NW_RESIZE_CURSOR; else if (S && E) resultcursor = drawCursor.SE_RESIZE_CURSOR; else if (S && W) resultcursor = drawCursor.SW_RESIZE_CURSOR; else if (N && E) resultcursor = drawCursor.NE_RESIZE_CURSOR; else if (W) resultcursor = drawCursor.W_RESIZE_CURSOR; else if (E) resultcursor = drawCursor.E_RESIZE_CURSOR; else if (N) resultcursor = drawCursor.N_RESIZE_CURSOR; else if (S) resultcursor = drawCursor.S_RESIZE_CURSOR; selectedFigure = f; } drawCursor = drawCursor.getPredefinedCursor(resultcursor); setCursor(drawCursor); } } } public void mousePressed(MouseEvent e)
127 { e.consume(); switch (mode) { case MOVE: if(selectedFigure != null && selectedFigure.contains(e.getPoint())) dragging = true; break; case SQUARE: case OVAL: selectedFigure = null; Point firstPoint = e.getPoint(); firstPointX = firstPoint.x; firstPointY = firstPoint.y; break; case ACTOR: int ID = projectModel.newID(); ActorFigure actor = new ActorFigure(ID, null, e.getX(), e.getY(), actorWidth, actorHeight); figures.add(actor); invalidate(); repaint(); break; case RESIZE: int cursortype = drawCursor.getType(); if (cursortype != drawCursor.DEFAULT_CURSOR) dragging = true; break; case CONNECT: case TEXT: default: break; } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseReleased(MouseEvent e) { e.consume(); switch (mode) { case SQUARE: case OVAL: if (selectedFigure != null) { Rectangle bounds = selectedFigure.getBounds(); if (bounds.height < 10)
128 { selectedFigure.setBounds(bounds.x, bounds.y, bounds.width, 10); repaint(); } bounds = selectedFigure.getBounds(); if (bounds.width < 10) { selectedFigure.setBounds(bounds.x, bounds.y, 10, bounds.height); repaint(); } } break; default: break; } dragging = false; } private Figure one = null; private Figure two = null; private int firstPointX; private int firstPointY; private Point originPoint; private String oldLabel; private int actorHeight = 50; private int actorWidth = 50; private int usecaseHeight = 30; private int usecaseWidth = 60; } UseCaseDiagramWindow.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; /** * This window in which all the use case diagraming action occurs. * Sets up appropriate toolbar and drawing canvas * @see DiagramWindow */ public class UseCaseDiagramWindow extends DiagramWindow implements KeyListener { public UseCaseDiagramWindow(String name, ProjectModel pm) { super (name); usercanvas = new UseCaseDiagramCanvas(pm); usetools = new UseCaseToolBar(usercanvas); getContentPane().add(usercanvas); getContentPane().add(usetools, BorderLayout.WEST); } UseCaseToolBar usetools;
129 } UseCaseForm.java //Java-DACTL, Java Design, Analysis, and Coding TooL with UML //Anna S. Armentrout //September 1999 //Copyright (c) 1999 //Pace University import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; import javax.swing.plaf.basic.*; /** * This view window allows the user to add and revise * use cases. */ public class UseCaseForm extends JInternalFrame implements Observer { public UseCaseForm(ProjectModel pm) { super("Use Case", true, true, true, true); setDefaultCloseOperation(JInternalFrame.HIDE_ON_CLOSE); setSize(550,300); setTitle("Use Case"); projectModel = pm; projectModel.addObserver(this); getContentPane().setLayout (new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = gbc.NONE; gbc.ipady = 10; gbc.ipadx = 10; gbc.insets = new Insets (5,5,0,0); //First column gbc.gridx = 0; gbc.gridy = 0; gbc.anchor = gbc.EAST; //ID: label JLabel label = new JLabel ("ID #: "); getContentPane().add(label, gbc); //Actors: label gbc.gridy = 1; label = new JLabel("Actors: "); getContentPane().add(label,gbc); //Description: label gbc.gridy = 2; label = new JLabel("Description: "); getContentPane().add(label, gbc); //Back button gbc.gridy = 3; gbc.anchor = gbc.WEST;
130 backButton = new BackButton(); backButton.setMargin(new Insets(1,1,1,1)); getContentPane().add (backButton, gbc); //Second column gbc.gridx = 1; gbc.gridy = 0; gbc.anchor = gbc.WEST; //ID text area idText = new JTextArea (1,3); idText.setEditable(false); getContentPane().add(idText, gbc); //Actor list gbc.gridy = 1; //actorList = new Vector(); actorlistbox = new ActorComboBox(); actorlistbox.setEditable(true); actorlistbox.setPreferredSize(new Dimension(120,15)); getContentPane().add(actorlistbox, gbc); //Description text area gbc.gridy = 2; gbc.gridwidth = 4; descText = new JTextArea(4,30); JScrollPane textscroll = new JScrollPane(descText); getContentPane().add(textscroll, gbc); //Delete button gbc.gridwidth = 1; gbc.gridy = 3; deleteButton = new DeleteButton(); getContentPane().add(deleteButton, gbc); //Third column gbc.gridx = 2; gbc.gridy = 0; gbc.anchor = gbc.EAST; //Name label label = new JLabel ("Name: "); getContentPane().add(label,gbc); //Purpose label gbc.gridy = 1; label = new JLabel("Purpose: "); getContentPane().add(label, gbc); //Fourth column gbc.gridx = 3; gbc.gridy = 0; gbc.anchor = gbc.WEST; gbc.gridwidth = 2; //Use case name list //usecaseList = new Vector(); usecaselistbox = new UseCaseComboBox(); usecaselistbox.setPreferredSize(new Dimension(200,15)); usecaselistbox.setEditable(true); getContentPane().add(usecaselistbox, gbc);
131 //Purpose text area gbc.gridy = 1; purposeText = new JTextArea(3,15); textscroll = new JScrollPane(purposeText); getContentPane().add(textscroll, gbc); //New button gbc.gridy = 3; gbc.anchor = gbc.CENTER; newButton = new NewButton(); getContentPane().add(newButton, gbc); //Fifth column gbc.gridx = 4; gbc.gridy = 3; gbc.anchor = gbc.CENTER; gbc.gridwidth = 1; //Next button gbc.anchor = gbc.EAST; nextButton = new NextButton(); nextButton.setMargin(new Insets(1,1,1,1)); getContentPane().add (nextButton, gbc); useCases = projectModel.getUseCases(); currentDisplayIndex = -1; } JTextArea idText; //Vector usecaseList; UseCaseComboBox usecaselistbox; //Vector actorList; ActorComboBox actorlistbox; JTextArea purposeText; JTextArea descText; BackButton backButton; NextButton nextButton; DeleteButton deleteButton; NewButton newButton; //Save text in purpose text area if it has been revised public void savePurposeText() { if (currentDisplayIndex >=0) { Action actions[] = purposeText.getActions(); if (actions != null) { UseCase currentUC = (UseCase)useCases.elementAt(currentDisplayIndex); currentUC.setPurpose(purposeText.getText()); Update updateUC = new Update(Update.USE_CASE_FORM, currentUC.getID(), Update.CHANGE, UseCase.PURPOSE, purposeText.getText()); projectModel.registerChange(); projectModel.notifyObservers(updateUC); }
132 } } //Save text in description text area if it has been revised public void saveDescText() { if (currentDisplayIndex >=0) { Action actions[] = descText.getActions(); if (actions != null) { UseCase currentUC = (UseCase)useCases.elementAt(currentDisplayIndex); currentUC.setDescription(descText.getText()); Update updateUC = new Update(Update.USE_CASE_FORM, currentUC.getID(), Update.CHANGE, UseCase.DESCRIPTION, descText.getText()); projectModel.registerChange(); projectModel.notifyObservers(updateUC); } } } //Controls actions on the use case list box (selections, additions) class UseCaseComboBox extends JComboBox implements ActionListener { public UseCaseComboBox() { super(); addActionListener(this); } private boolean updateChange; public void setUpdate() { updateChange = true; } public boolean findItem(String item) { for (int i = 0; i < getItemCount(); i++) { String test = (String)getItemAt(i); if (item.equals(test)) return true; } return false; } public void actionPerformed (ActionEvent e) { String newItem = e.getActionCommand(); if (currentDisplayIndex >= 0) { if (newItem.equals("comboBoxChanged")) { String item = (String)getSelectedItem(); if (item != null) displayUseCase(item); } else { if (findItem(newItem)) { displayUseCase(newItem);
133 } else { if (! newItem.equals("")) { UseCase currentUC = (UseCase)useCases.elementAt(currentDisplayIndex); currentUC.setName(newItem); addItem(newItem); displayUseCase(currentDisplayIndex); if (!updateChange) { Update updateUC = new Update(Update.USE_CASE_FORM, currentUC.getID(), Update.CHANGE, UseCase.NAME, newItem); projectModel.registerChange(); projectModel.notifyObservers(updateUC); } } } } } } } //Controls actions on the actor list box (selections, additions) class ActorComboBox extends JComboBox implements ActionListener { public ActorComboBox() { super(); addActionListener(this); updateChange = false; } private boolean updateChange; public void setUpdate() { updateChange = true; } public boolean findItem(String item) { for (int i = 0; i < getItemCount(); i++) { String test = (String)getItemAt(i); if (item.equals(test)) return true; } return false; } public void actionPerformed (ActionEvent e) { String newItem = e.getActionCommand(); UseCase currentUC = null; int ID = -1; if (newItem != null)//meaningless action { //could be adding an actor with no usecases yet if (currentDisplayIndex >= 0) { currentUC = (UseCase)useCases.elementAt(currentDisplayIndex);
134 ID = currentUC.getID(); } //If comboBox is changing, new items must already have been added, //must be updating a use case if ((currentDisplayIndex >= 0) && (!updateChange) && (newItem.equals("comboBoxChanged"))) { String item = (String)getSelectedItem(); System.out.println("Selected Item:" + item +"."); if (!updateChange) { currentUC.setActor(item); Update updateUC = new Update(Update.USE_CASE_FORM, ID, Update.CHANGE, UseCase.ACTOR, item); projectModel.registerChange(); projectModel.notifyObservers(updateUC); } } else if (!(newItem.equals("comboBoxChanged"))) { if (findItem(newItem))//item is duplicate of previous item. { if (currentDisplayIndex >= 0) currentUC.setActor(newItem); if (!updateChange) { Update updateUC = new Update(Update.USE_CASE_FORM, ID, Update.CHANGE, UseCase.ACTOR, newItem); projectModel.registerChange(); projectModel.notifyObservers(updateUC); } } else //completely new item { if (! newItem.equals("")) { setUpdate(); addItem(newItem); } if (currentDisplayIndex >=0) currentUC.setActor(newItem); if (!updateChange) { Update updateUC = new Update(Update.USE_CASE_FORM, ID, Update.ADD, UseCase.ACTOR, newItem); projectModel.registerChange(); projectModel.notifyObservers(updateUC); } } } } updateChange = false; } } //Controls actions on back arrow button //scrolls back one entry class BackButton extends JButton implements ActionListener { public BackButton() { super(); init (null, back); addActionListener(this);
135 setToolTipText("Back"); } public final ImageIcon back = new ImageIcon("images/back.jpg"); public void actionPerformed(ActionEvent e) { savePurposeText(); saveDescText(); if (currentDisplayIndex > 0) displayUseCase(currentDisplayIndex - 1); } } //Controls action on next arrow button //scrolls forward one entry class NextButton extends JButton implements ActionListener { public NextButton() { super(); init(null, next); addActionListener(this); setToolTipText("Next"); } public final ImageIcon next = new ImageIcon("images/next.jpg"); public void actionPerformed(ActionEvent e) { savePurposeText(); saveDescText(); if (currentDisplayIndex >= 0) { if (!(currentDisplayIndex + 1 >= useCases.size())) displayUseCase(currentDisplayIndex + 1); } } } //Allows a use case to be deleted class DeleteButton extends JButton implements ActionListener { public DeleteButton() { super("Delete"); addActionListener(this); } public void actionPerformed(ActionEvent e) { if (currentDisplayIndex >= 0) { UseCase currentUC = (UseCase) useCases.elementAt(currentDisplayIndex); String name = currentUC.getName(); useCases.removeElementAt(currentDisplayIndex); if (name != null); { usecaselistbox.setUpdate(); usecaselistbox.removeItem(currentUC.getName()); usecaselistbox.setUpdate(); usecaselistbox.setSelectedItem(null); }
136 if (useCases.size() > 0) displayUseCase(0); else displayBlank(); projectModel.registerChange(); Update updateUC = new Update(Update.USE_CASE_FORM, currentUC.getID(), Update.DELETE, 0, null); projectModel.notifyObservers(updateUC); } } } //Allows a use case to be added class NewButton extends JButton implements ActionListener { public NewButton() { super("New"); addActionListener(this); } public void actionPerformed(ActionEvent e) { savePurposeText(); saveDescText(); int ID = projectModel.newID(); UseCase newUC = new UseCase(ID); useCases.add(newUC); Update updateUC = new Update(Update.USE_CASE_FORM, ID, Update.ADD, 0, newUC); projectModel.registerChange(); projectModel.notifyObservers(updateUC); displayUseCase(useCases.indexOf(newUC)); } }
public void update (Observable pm, Object arg) { Update useCaseUpdate = (Update) arg; if ((useCaseUpdate.getOrigin() == useCaseUpdate.USE_CASE_DIAGRAM) || (useCaseUpdate.getOrigin() == useCaseUpdate.TREE_UC)) { int act = useCaseUpdate.getAction(); switch (act) { case useCaseUpdate.ADD: if (useCaseUpdate.getField() == UseCase.ACTOR) { String newItem = (String) useCaseUpdate.getArg(); actorlistbox.setUpdate(); actorlistbox.addItem(newItem); if (currentDisplayIndex >= 0) displayUseCase(currentDisplayIndex); } else { UseCase newUC = (UseCase)useCaseUpdate.getArg(); int index = useCases.indexOf(newUC); displayUseCase(index); } break;
137 case useCaseUpdate.DELETE: if (useCaseUpdate.getField() == UseCase.ACTOR) { String deleteName = (String)useCaseUpdate.getArg(); actorlistbox.setUpdate(); actorlistbox.removeItem((String)useCaseUpdate.getArg()); if (currentDisplayIndex >= 0) displayUseCase(currentDisplayIndex); } else { String deleteItem = (String)useCaseUpdate.getArg(); if (deleteItem != null) usecaselistbox.removeItem(deleteItem); if (useCases.size() > 0) displayUseCase(0); else displayBlank(); } break; case useCaseUpdate.CHANGE: int ID = useCaseUpdate.getID(); int index = -1; if (ID >= 0) { UseCase changeField = projectModel.findUseCase(ID); index = useCases.indexOf(changeField); currentDisplayIndex = index; } if (useCaseUpdate.getArg() instanceof String) { if (useCaseUpdate.getField() == UseCase.ACTOR) { String newItem = (String)useCaseUpdate.getArg(); if (newItem != "") { actorlistbox.setUpdate(); actorlistbox.addItem(newItem); displayUseCase(currentDisplayIndex); } } else if (useCaseUpdate.getField() == UseCase.NAME) { String newItem = (String)useCaseUpdate.getArg(); if (newItem != null) { usecaselistbox.setUpdate(); usecaselistbox.addItem(newItem); displayUseCase(currentDisplayIndex); } } } else { LabelChange lc = (LabelChange)useCaseUpdate.getArg(); String oldItem = lc.getOld(); String newItem = lc.getNew(); if (newItem != null) { if (useCaseUpdate.getField() == UseCase.NAME) { usecaselistbox.setUpdate();
138 usecaselistbox.removeItem(oldItem); usecaselistbox.setUpdate(); usecaselistbox.addItem(newItem); displayUseCase(currentDisplayIndex); } else if (useCaseUpdate.getField() == UseCase.ACTOR) { actorlistbox.setUpdate(); actorlistbox.removeItem(oldItem); actorlistbox.setUpdate(); actorlistbox.addItem(newItem); if (index >= 0) displayUseCase(currentDisplayIndex); } } } break; default: break; } } else if (useCaseUpdate.getOrigin() == useCaseUpdate.OPEN) { if (! useCases.isEmpty()) { for (int index = 0; index < useCases.size(); index++) { currentDisplayIndex = index; UseCase current = (UseCase)useCases.elementAt(index); String name = current.getName(); String actor = current.getActor(); if (name != null) { usecaselistbox.setUpdate(); usecaselistbox.addItem(name); } if (actor != null) { actorlistbox.setUpdate(); actorlistbox.addItem(actor); } } displayUseCase(0); } } } //Displays the selected use case in the Use Case Form public void displayUseCase(int index) { currentDisplayIndex = index; UseCase currentUC = (UseCase)useCases.elementAt(currentDisplayIndex); Integer id = new Integer(currentUC.getID()); idText.setText(id.toString()); //usecaselistbox.setUpdate(); usecaselistbox.setSelectedItem(currentUC.getName()); String actor = currentUC.getActor(); actorlistbox.setUpdate(); actorlistbox.setSelectedItem(currentUC.getActor()); purposeText.setText(currentUC.getPurpose());
139 descText.setText(currentUC.getDescription()); repaint(); } public void displayUseCase(String name) { int index; for (index = 0; index < useCases.size(); index++) { UseCase current = (UseCase) useCases.elementAt(index); if (name.equals(current.getName())) break; } if (index < useCases.size()) displayUseCase(index); } //Displays a blank form public void displayBlank() { currentDisplayIndex = -1; idText.setText(""); usecaselistbox.setSelectedItem(null); actorlistbox.setSelectedItem(null); purposeText.setText(""); descText.setText(""); repaint(); } protected ProjectModel projectModel; protected Vector useCases; protected int currentDisplayIndex; } UseCaseToolBar.java import javax.swing.*; import java.awt.event.*; /** * The toolbar for the Use Case Diagram View. * Includes all the tools for drawing use case diagrams. * */ class UseCaseToolBar extends DiagramToolBar { public UseCaseToolBar(DiagramCanvas target) { super(target); add(move); add(square); add(oval); add(actor); add(text); add(connect); add(resize); } MoveButton move = new MoveButton (this.target);
140 SquareButton square = new SquareButton (this.target, "Draw system"); OvalButton oval = new OvalButton (this.target); TextButton text = new TextButton (this.target); ActorButton actor = new ActorButton (this.target); ConnectButton connect = new ConnectButton(this.target, ConnectButton.usecaseimage, "Draw connection"); ResizeButton resize = new ResizeButton(this.target);}