Coverage Report - uk.co.javagear.JavaGearFrame
 
Classes in this File Line Coverage Branch Coverage Complexity
JavaGearFrame
0% 
0% 
8.444
 
 1  
 /*
 2  
  * JavaGearFrame.java
 3  
  *
 4  
  * This file is part of JavaGear.
 5  
  *
 6  
  * JavaGear is free software; you can redistribute it and/or modify
 7  
  * it under the terms of the GNU General Public License as published by
 8  
  * the Free Software Foundation; either version 2 of the License, or
 9  
  * (at your option) any later version.
 10  
  *
 11  
  * JavaGear is distributed in the hope that it will be useful,
 12  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  
  * GNU General Public License for more details.
 15  
  *
 16  
  * You should have received a copy of the GNU General Public License
 17  
  * along with JavaGear; if not, write to the Free Software
 18  
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 19  
  */
 20  
 
 21  
 package uk.co.javagear;
 22  
 
 23  
 import java.awt.Dimension;
 24  
 import java.awt.Graphics;
 25  
 import java.awt.Image;
 26  
 import java.awt.MediaTracker;
 27  
 import java.awt.Toolkit;
 28  
 import java.awt.event.ActionEvent;
 29  
 import java.awt.event.ActionListener;
 30  
 import java.awt.event.WindowAdapter;
 31  
 import java.awt.event.WindowEvent;
 32  
 import java.io.File;
 33  
 import java.io.IOException;
 34  
 import java.net.MalformedURLException;
 35  
 import java.net.URL;
 36  
 import javax.swing.ButtonGroup;
 37  
 import javax.swing.JCheckBoxMenuItem;
 38  
 import javax.swing.JFileChooser;
 39  
 import javax.swing.JFrame;
 40  
 import javax.swing.JMenu;
 41  
 import javax.swing.JMenuBar;
 42  
 import javax.swing.JMenuItem;
 43  
 import javax.swing.JPopupMenu;
 44  
 import javax.swing.JRadioButtonMenuItem;
 45  
 import org.apache.log4j.Logger;
 46  
 
 47  
 /**
 48  
  * JavaGear application user interface.
 49  
  *
 50  
  * @author Copyright (C) 2002-2003 Chris White
 51  
  * @version 18th January 2003
 52  
  * @see "JavaGear Final Project Report"
 53  
  */
 54  
 public final class JavaGearFrame extends JFrame implements ActionListener {
 55  
     
 56  
     /**
 57  
      * Memory and paging emulation.
 58  
      */
 59  
     private Memory mem;
 60  
     
 61  
     /**
 62  
      * SN76596 Emulation.
 63  
      */
 64  
     private SN76496 sn76496;
 65  
     
 66  
     /**
 67  
      * Port emulation.
 68  
      */
 69  
     private Ports port;
 70  
     
 71  
     /**
 72  
      * Z80 CPU emulation.
 73  
      */
 74  
     private Z80 z80cpu;
 75  
     
 76  
     /**
 77  
      * Controller emulation.
 78  
      */
 79  
     private Controllers controllers;
 80  
     
 81  
     /**
 82  
      * Main emulation loop.
 83  
      */
 84  
     private EmulateLoop emulateLoop;
 85  
     
 86  
     /**
 87  
      * VDP emulation.
 88  
      */
 89  
     private Vdp vdp;
 90  
     
 91  
     /**
 92  
      * Java screen display.
 93  
      */
 94  
     private Screen screenpanel;
 95  
     
 96  
     /**
 97  
      * Show FPS counter.
 98  
      */
 99  
     private boolean showFps;
 100  
     
 101  
     /**
 102  
      * Keyboard configuration frame.
 103  
      */
 104  
     private KeyFrame keyFrame;
 105  
     
 106  
     /**
 107  
      * Debugger frame.
 108  
      */
 109  
     private JFrame debugger;
 110  
     
 111  
     /**
 112  
      * VDP debugger frame.
 113  
      */
 114  
     private VdpDebugFrame vdpDebugFrame;
 115  
     
 116  
     /**
 117  
      * Pointer to general parameters.
 118  
      */
 119  
     private Setup setup;
 120  
     
 121  
     /**
 122  
      * Directory for ROMs.
 123  
      */
 124  0
     private String directory = ".";
 125  
     
 126  
     /**
 127  
      * Has a cartridge been loaded.
 128  
      */
 129  
     private boolean cartLoaded;
 130  
     
 131  
     /**
 132  
      * Game Gear image.
 133  
      */
 134  
     private Image gameGear;
 135  
     
 136  
     /**
 137  
      * Splash image.
 138  
      */
 139  
     private Image splash;
 140  
     
 141  
     /**
 142  
      * Global, as must be selected for Game Gear.
 143  
      */
 144  
     private JRadioButtonMenuItem ntscItem;
 145  
     
 146  
     
 147  
     /**
 148  
      * JavaGearFrame constructor.
 149  
      */
 150  0
     public JavaGearFrame() {
 151  
         // Load Images
 152  0
         URL imageURL = JavaGear.class.getResource("/images/gamegear.jpg");
 153  0
         gameGear = Toolkit.getDefaultToolkit().getImage(imageURL);
 154  0
         imageURL = JavaGear.class.getResource("/images/icon.gif");
 155  0
         Image icon = Toolkit.getDefaultToolkit().getImage(imageURL);
 156  0
         imageURL = JavaGear.class.getResource("/images/splash.jpg");
 157  0
         splash = Toolkit.getDefaultToolkit().getImage(imageURL);
 158  
         
 159  
         // Wait for images to load
 160  0
         MediaTracker tracker = new MediaTracker(this);
 161  0
         tracker.addImage(gameGear, 0);
 162  0
         tracker.addImage(icon, 1);
 163  0
         tracker.addImage(splash, 2);
 164  
         try {
 165  0
             tracker.waitForAll();
 166  0
         } catch (InterruptedException ie) {
 167  0
             Logger.getLogger(this.getClass()).error("Error waiting for images to load.", ie);
 168  0
         }
 169  
         
 170  
         // Create pointer to general options
 171  0
         setup = new Setup();
 172  
         
 173  
         // Initialise Objects
 174  0
         controllers = new Controllers(setup);
 175  0
         InterruptLine irq = new InterruptLine();
 176  0
         mem  = new Memory(setup);
 177  0
         vdp = new Vdp(setup, irq);
 178  0
         screenpanel = new Screen(setup, vdp);
 179  0
         sn76496 = new SN76496(111860.78125, 11025); // Clock Rate, Sample Rate
 180  0
         port = new Ports(vdp, controllers, sn76496);
 181  0
         z80cpu = new Z80(mem, port, irq);
 182  0
         debugger = new Debug(z80cpu, vdp, screenpanel);
 183  0
         emulateLoop = new EmulateLoop(z80cpu, mem, vdp, sn76496, screenpanel, setup);
 184  
         
 185  
         // Setup Frame
 186  0
         setTitle("JavaGear");
 187  0
         setIconImage(icon);
 188  
         
 189  
         // Ensure menus display over the emulation pane
 190  0
         JPopupMenu.setDefaultLightWeightPopupEnabled(false);
 191  
         
 192  
         // Create Menu Bar
 193  0
         JMenuBar menuBar = new JMenuBar();
 194  0
         menuBar.add(makeMenu("File",
 195  
                 new Object[]
 196  
         {
 197  
             "Open",
 198  
             "Close",
 199  
             null,
 200  
             "Exit"
 201  
         }, this));
 202  
         
 203  0
         ButtonGroup regionGroup = new ButtonGroup();
 204  0
         JRadioButtonMenuItem usItem = new JRadioButtonMenuItem("US/Europe");
 205  0
         JRadioButtonMenuItem japItem = new JRadioButtonMenuItem("Japan");
 206  0
         usItem.setSelected(true);
 207  0
         regionGroup.add(usItem); regionGroup.add(japItem);
 208  
         
 209  0
         ButtonGroup tvGroup = new ButtonGroup();
 210  0
         ntscItem = new JRadioButtonMenuItem("NTSC");
 211  0
         JRadioButtonMenuItem palItem = new JRadioButtonMenuItem("PAL");
 212  0
         ntscItem.setSelected(true);
 213  0
         tvGroup.add(ntscItem); tvGroup.add(palItem);
 214  
         
 215  0
         ButtonGroup fskipGroup = new ButtonGroup();
 216  0
         JRadioButtonMenuItem fs0 = new JRadioButtonMenuItem("1:1");
 217  0
         JRadioButtonMenuItem fs1 = new JRadioButtonMenuItem("1:2");
 218  0
         JRadioButtonMenuItem fs2 = new JRadioButtonMenuItem("1:3");
 219  0
         fs0.setSelected(true);
 220  0
         fskipGroup.add(fs0); fskipGroup.add(fs1); fskipGroup.add(fs2);
 221  
         
 222  0
         ButtonGroup zoomGroup = new ButtonGroup();
 223  0
         JRadioButtonMenuItem x1 = new JRadioButtonMenuItem("x 1");
 224  0
         JRadioButtonMenuItem x2 = new JRadioButtonMenuItem("x 2");
 225  0
         JRadioButtonMenuItem x3 = new JRadioButtonMenuItem("x 3");
 226  0
         x1.setSelected(true);
 227  0
         zoomGroup.add(x1); zoomGroup.add(x2); zoomGroup.add(x3);
 228  
         
 229  0
         menuBar.add(makeMenu("System",
 230  
                 new Object[]
 231  
         {
 232  
             "Controls",
 233  
             null,
 234  
             "Soft Reset",
 235  
             "Hard Reset",
 236  
             null,
 237  
             makeMenu("Region",
 238  
                     new Object[]
 239  
             {
 240  
                 usItem,
 241  
                 japItem
 242  
             }, this),
 243  
             makeMenu("TV Type",
 244  
                     new Object[]
 245  
             {
 246  
                 ntscItem,
 247  
                 palItem
 248  
             }, this)
 249  
         }, this));
 250  
         
 251  0
         menuBar.add(makeMenu("Video",
 252  
                 new Object[]
 253  
         {
 254  
             new JCheckBoxMenuItem("Show FPS", false),
 255  
             makeMenu("Frameskip",
 256  
                     new Object[]
 257  
             {
 258  
                 fs0,
 259  
                 fs1,
 260  
                 fs2
 261  
             }, this),
 262  
             makeMenu("Screen Size",
 263  
                     new Object[]
 264  
             {
 265  
                 x1,
 266  
                 x2,
 267  
                 x3,
 268  
             }, this),
 269  
             null,
 270  
             makeMenu("Layers",
 271  
                     new Object[]
 272  
             {
 273  
                 new JCheckBoxMenuItem("Background", true),
 274  
                 new JCheckBoxMenuItem("Sprites", true),
 275  
             }, this),
 276  
         }, this));
 277  
         
 278  0
         menuBar.add(makeMenu("Sound",
 279  
                 new Object[]
 280  
         {
 281  
             new JCheckBoxMenuItem("Enable Sound", true),
 282  
             new JCheckBoxMenuItem("Record Sound", false),
 283  
             makeMenu("Channels",
 284  
                     new Object[]
 285  
             {
 286  
                 new JCheckBoxMenuItem("Tone Generator 1", true),
 287  
                 new JCheckBoxMenuItem("Tone Generator 2", true),
 288  
                 new JCheckBoxMenuItem("Tone Generator 3", true),
 289  
                 new JCheckBoxMenuItem("Noise Generator " , true),
 290  
             }, this),
 291  
             
 292  
         }, this));
 293  
         
 294  0
         menuBar.add(makeMenu("Debug",
 295  
                 new Object[]
 296  
         {
 297  
             "Z80",
 298  
             "VDP",
 299  
         }, this));
 300  0
         setJMenuBar(menuBar);
 301  
         
 302  
         // Set Window Size
 303  0
         setup.setScreenSize(1);
 304  0
         screenpanel.setSize(new Dimension(setup.getHEndScaled(), setup.getVEndScaled()));
 305  
         
 306  
         // Get Current Screen Size
 307  0
         Toolkit tk = Toolkit.getDefaultToolkit();
 308  0
         Dimension d = tk.getScreenSize();
 309  
         // Set Window in middle
 310  0
         setLocation(d.width / 4, d.height / 4);
 311  
         
 312  
         // Add Window Listener
 313  0
         addWindowListener(new WindowAdapter() {
 314  
             public void windowClosing(WindowEvent e) {
 315  0
                 terminate();
 316  0
             }
 317  
         });
 318  
         
 319  
         
 320  
         // Setup Emulation Defaults
 321  0
         port.setEurope(true); // Default to a domestic system
 322  0
         setup.setSystem(Setup.System.SMS); // Default to SMS mode
 323  
         
 324  
         // Add Keyboard Support
 325  0
         addKeyListener(controllers);
 326  
         
 327  
         // Add Display Window
 328  0
         getContentPane().add(screenpanel);
 329  
         
 330  0
         pack();
 331  0
         setResizable(false);
 332  0
         requestFocus();
 333  0
     }
 334  
     
 335  
     
 336  
     /**
 337  
      * Paint splash screen and Game Gear image.
 338  
      *
 339  
      * @param g The graphics context to use for painting.
 340  
      */
 341  
     public void paint(Graphics g) {
 342  0
         super.paint(g);
 343  
         
 344  
         // Paint Game Gear Graphic
 345  0
         if (cartLoaded) {
 346  0
             if (setup.getSystem() == Setup.System.GG) {
 347  0
                 Dimension d = screenpanel.getSize();
 348  0
                 screenpanel.getGraphics().drawImage(gameGear, 0, 0, d.width, d.height, this);
 349  0
                 screenpanel.forceUpdate();
 350  
             }
 351  0
             if (debugger.isVisible()) {
 352  0
                 screenpanel.refresh(); //fix for gg - chris
 353  
             }
 354  
         } else { // Paint Splash Screen
 355  0
             Dimension d = screenpanel.getSize();
 356  0
             screenpanel.getGraphics().drawImage(splash, 0, 0, d.width, d.height, this);
 357  
         }
 358  0
     }
 359  
     
 360  
     
 361  
     /**
 362  
      * Open cartridge and start emulation.
 363  
      *
 364  
      * @param filename URL of cartridge image.
 365  
      */
 366  
     public void openCart(URL filename) {
 367  0
         mem.reset();
 368  
         
 369  
         try {
 370  0
             mem.readCart(filename);
 371  0
             cartLoaded = true;
 372  0
             emulateLoop.stopThread();
 373  
             // Set NTSC Timing if GameGear
 374  0
             if (setup.getSystem() == Setup.System.GG) {
 375  0
                 emulateLoop.setNTSC();
 376  0
                 ntscItem.setSelected(true);
 377  
             } else {
 378  0
                 if (ntscItem.isSelected()) {
 379  0
                     emulateLoop.setNTSC();
 380  
                 } else {
 381  0
                     emulateLoop.setPAL();
 382  
                 }
 383  
             }
 384  
             
 385  0
             if (!debugger.isVisible()) {
 386  0
                 emulateLoop.startThread();
 387  
             } else {
 388  0
                 emulateLoop.reset();
 389  
             }
 390  0
         } catch (IOException ioe) {
 391  0
             Logger.getLogger(this.getClass()).error("Error opening ROM file: " + filename, ioe);
 392  0
             cartLoaded = false;
 393  0
         } catch (IllegalArgumentException iae) {
 394  0
             Logger.getLogger(this.getClass()).error("Error opening ROM file: " + filename, iae);
 395  0
             cartLoaded = false;
 396  
         } finally {
 397  0
             repaint(); // repaint this window
 398  0
         }
 399  0
     }
 400  
     
 401  
     
 402  
     /**
 403  
      * Invoke Dialog to select cartridge image.
 404  
      *
 405  
      * @return URL of chosen cartridge
 406  
      */
 407  
     public URL openDialog() {
 408  0
         URL filename = null;
 409  
         
 410  
         // Create Frame for File Chooser
 411  0
         JFrame openFrame = new JFrame("Open");
 412  
         
 413  
         // Create new File Chooser
 414  0
         JFileChooser chooser = new JFileChooser();
 415  
         
 416  
         // Set Directory
 417  0
         chooser.setCurrentDirectory(new File(directory));
 418  
         
 419  
         // Set FileFilters
 420  0
         chooser.addChoosableFileFilter(new GGFilter());
 421  0
         chooser.addChoosableFileFilter(new SMSFilter());
 422  0
         chooser.setFileFilter(new RomFilter());
 423  0
         chooser.setAcceptAllFileFilterUsed(false); // turn off *.* filter
 424  
         
 425  
         // This call does not return until a file is selected
 426  0
         int result = chooser.showOpenDialog(openFrame);
 427  
         
 428  
         // Get the Filename
 429  0
         File selectedFile = chooser.getSelectedFile();
 430  
         
 431  0
         if (selectedFile != null) {
 432  0
             directory = selectedFile.getAbsolutePath();
 433  
             try {
 434  0
                 filename = selectedFile.toURI().toURL();
 435  0
             } catch (MalformedURLException mue) {
 436  0
                 Logger.getLogger(this.getClass()).error("Unable to get the file's path.", mue);
 437  0
             }
 438  
             
 439  0
             return filename;
 440  
         } else {
 441  0
             return null;
 442  
         }
 443  
     }
 444  
     
 445  
     
 446  
     /**
 447  
      * Invoked when a menu item is selected.
 448  
      *
 449  
      * @param evt an <code>ActionEvent</code> for one of the <code>JMenuItem</code>s.
 450  
      */
 451  
     public void actionPerformed(ActionEvent evt) {
 452  0
         if (evt.getSource() instanceof JMenuItem) {
 453  0
             String arg = evt.getActionCommand();
 454  
             
 455  
             // FILE MENU
 456  0
             if (arg.equals("Open")) {
 457  0
                 if (!debugger.isVisible()) {
 458  0
                     emulateLoop.suspendThread();
 459  
                 }
 460  
                 
 461  
                 // Get URL of file
 462  0
                 URL filename = openDialog();
 463  
                 
 464  
                 // Pass URL to openCart Method
 465  0
                 if  (filename != null) {
 466  0
                     openCart(filename);
 467  0
                 } else if (cartLoaded) {
 468  0
                     screenpanel.disposeGraphics();
 469  0
                     emulateLoop.resumeThread();
 470  
                 }
 471  0
             } else if (arg.equals("Close")) {
 472  0
                 emulateLoop.stopThread();
 473  0
                 mem.reset();
 474  0
                 cartLoaded = false;
 475  0
             } else if (arg.equals("Exit")) {
 476  0
                 terminate();
 477  0
             } else if (arg.equals("Record Sound")) { // SOUND MENU
 478  0
                 sn76496.setRecord();
 479  0
             } else if (arg.equals("Enable Sound")) {
 480  0
                 sn76496.setEnabled();
 481  0
             } else if (arg.equals("Tone Generator 1")) {
 482  0
                 sn76496.setChannelEnabled(0);
 483  0
             } else if (arg.equals("Tone Generator 2")) {
 484  0
                 sn76496.setChannelEnabled(1);
 485  0
             } else if (arg.equals("Tone Generator 3")) {
 486  0
                 sn76496.setChannelEnabled(2);
 487  0
             } else if (arg.equals("Noise Generator ")) {
 488  0
                 sn76496.setChannelEnabled(3);
 489  0
             } else if (arg.equals("Controls")) { // SYSTEM MENU
 490  0
                 if (keyFrame == null) {
 491  0
                     keyFrame = new KeyFrame(controllers);
 492  
                 }
 493  0
                 keyFrame.setVisible(true);
 494  0
             } else if (arg.equals("Hard Reset")) {
 495  0
                 if (cartLoaded) {
 496  0
                     if (!debugger.isVisible()) {
 497  0
                         emulateLoop.stopThread();
 498  
                     }
 499  0
                     emulateLoop.reset();
 500  0
                     if (!debugger.isVisible()) {
 501  0
                         emulateLoop.startThread();
 502  
                     }
 503  
                 }
 504  0
             } else if (arg.equals("Soft Reset")) {
 505  0
                 if (Setup.System.SMS == setup.getSystem()) {
 506  0
                     controllers.setReset();
 507  
                 }
 508  0
             } else if (arg.equals("Show FPS")) {
 509  0
                 if (!showFps) {
 510  0
                     showFps = true;
 511  0
                     screenpanel.paintFPS(true);
 512  
                 } else {
 513  0
                     showFps = false;
 514  0
                     screenpanel.paintFPS(false);
 515  
                 }
 516  0
             } else if (arg.equals("1:1")) { // VIDEO MENU
 517  0
                 Throttle.setFrameSkip(0);
 518  0
             } else if (arg.equals("1:2")) {
 519  0
                 Throttle.setFrameSkip(1);
 520  0
             } else if (arg.equals("1:3")) {
 521  0
                 Throttle.setFrameSkip(2);
 522  0
             } else if (arg.equals("Background")) {
 523  0
                 vdp.setBackgroundLayer();
 524  0
             } else if (arg.equals("Sprites")) {
 525  0
                 vdp.setSpriteLayer();
 526  0
             } else if (arg.equals("x 1")) {
 527  0
                 emulateLoop.suspendThread();
 528  0
                 setup.setScreenSize(1);
 529  0
                 screenpanel.disposeGraphics();
 530  0
                 screenpanel.setSize(new Dimension(setup.getHEndScaled(), setup.getVEndScaled()));
 531  0
                 pack();
 532  0
                 if (cartLoaded) {
 533  0
                     emulateLoop.resumeThread();
 534  
                 }
 535  0
             } else if (arg.equals("x 2")) {
 536  0
                 emulateLoop.suspendThread();
 537  0
                 setup.setScreenSize(2);
 538  0
                 screenpanel.disposeGraphics();
 539  0
                 screenpanel.setSize(new Dimension(setup.getHEndScaled(), setup.getVEndScaled()));
 540  0
                 pack();
 541  0
                 if (cartLoaded) {
 542  0
                     emulateLoop.resumeThread();
 543  
                 }
 544  0
             } else if (arg.equals("x 3")) {
 545  0
                 emulateLoop.suspendThread();
 546  0
                 setup.setScreenSize(3);
 547  0
                 screenpanel.disposeGraphics();
 548  0
                 screenpanel.setSize(new Dimension(setup.getHEndScaled(), setup.getVEndScaled()));
 549  0
                 pack();
 550  0
                 if (cartLoaded) {
 551  0
                     emulateLoop.resumeThread();
 552  
                 }
 553  0
             } else if (arg.equals("US/Europe")) {
 554  0
                 port.setEurope(true);
 555  0
             } else if (arg.equals("Japan")) {
 556  0
                 port.setEurope(false);
 557  0
             } else if (arg.equals("NTSC")) {
 558  0
                 emulateLoop.suspendThread();
 559  0
                 emulateLoop.setNTSC();
 560  0
                 if (cartLoaded) {
 561  0
                     emulateLoop.resumeThread();
 562  
                 }
 563  0
             } else if (arg.equals("PAL")) {
 564  0
                 if (Setup.System.SMS == setup.getSystem()) {
 565  0
                     emulateLoop.suspendThread();
 566  0
                     emulateLoop.setPAL();
 567  0
                     if (cartLoaded) {
 568  0
                         emulateLoop.resumeThread();
 569  
                     }
 570  
                 } else {
 571  0
                     ntscItem.setSelected(true);
 572  
                 }
 573  0
             } else if (arg.equals("Z80")) { // DEBUG MENU
 574  0
                 if (cartLoaded) {
 575  0
                     emulateLoop.stopThread();
 576  
                 }
 577  0
                 if (debugger == null) {
 578  0
                     debugger = new Debug(z80cpu, vdp, screenpanel);
 579  
                 }
 580  0
                 debugger.setVisible(true);
 581  0
             } else if (arg.equals("VDP")) {
 582  0
                 if (vdpDebugFrame == null) {
 583  0
                     vdpDebugFrame = new VdpDebugFrame(vdp);
 584  
                 }
 585  0
                 vdpDebugFrame.setVisible(true);
 586  
             }
 587  
         }
 588  0
     }
 589  
     
 590  
     
 591  
     /**
 592  
      * Terminate JavaGear.
 593  
      */
 594  
     public void terminate() {
 595  0
         System.out.print("Closing      ... ");
 596  0
         sn76496.stopRecording(); // Close sound recording
 597  
         
 598  0
         System.out.println("Done");
 599  0
         System.gc();
 600  0
         System.exit(0);
 601  0
     }
 602  
     
 603  
     /**
 604  
      * Building Menu Method.<br/>
 605  
      * From: Core Java Volume 1 (1999 Sun Microsystems) P 489.<br/>
 606  
      * Builds a <code>JMenu</code> with the items and listener specified. The parent may be a
 607  
      * <code>String</code> or <code>JMenu</code>. If it is a <code>String</code>, then 
 608  
      * the <code>JMenu</code> is built for you, otherwise the instance passed is used. Similarly,
 609  
      * the <code>items</code> array may contain <code>JMenuItem</code>s or <code>Strings</code>.
 610  
      * <code>null</code> items are replaced by <code>JSeparator</code>s.
 611  
      *
 612  
      * @param parent either an instance of <code>String</code> or <code>JMenu</code>.
 613  
      * @param items an array of <code>String</code>s or <code>JMenuItem</code>s.
 614  
      * @param listener an <code>ActionListener</code> to register in the <code>JMenuItem</code>s.
 615  
      *    May be <code>null</code>.
 616  
      * @return a <code>JMenu</code> that contains all the items specified.
 617  
      */
 618  
     private static JMenu makeMenu(Object parent, Object[] items, ActionListener listener) {
 619  0
         JMenu m = null;
 620  0
         if (parent instanceof JMenu) {
 621  0
             m = (JMenu) parent;
 622  0
         } else if (parent instanceof String) {
 623  0
             m = new JMenu((String) parent);
 624  
         } else {
 625  0
             return null;
 626  
         }
 627  0
         for (int i = 0; i < items.length; i++) {
 628  0
             if (items[i] == null) {
 629  0
                 m.addSeparator();
 630  
             } else {
 631  0
                 m.add(makeMenuItem(items[i], listener));
 632  
             }
 633  
         }
 634  0
         return m;
 635  
     }
 636  
     
 637  
     /**
 638  
      * Building Menu Method.<br/>
 639  
      * From: Core Java Volume 1 (1999 Sun Microsystems) P 489<br/>
 640  
      * Builds a <code>JMenuItem</code> with the listener specified. The item may be a
 641  
      * <code>String</code> or <code>JMenuItem</code>. If it is a <code>String</code>, then 
 642  
      * the <code>JMenuItem</code> is built for you, otherwise the instance passed is used.
 643  
      *
 644  
      * @param item either an instance of <code>String</code> or <code>JMenu</code>.
 645  
      * @param listener the <code>ActionListener</code> to add to the <code>JMenuItem</code>.
 646  
      *     May be <code>null</code>.
 647  
      * @return a <code>JMenuItem</code> with the specified <code>ActionListener</code>.
 648  
      */
 649  
     private static JMenuItem makeMenuItem(Object item, ActionListener listener) {
 650  0
         JMenuItem r = null;
 651  0
         if (item instanceof String) {
 652  0
             r = new JMenuItem((String) item);
 653  0
         } else if (item instanceof JMenuItem) {
 654  0
             r = (JMenuItem) item;
 655  
         } else {
 656  0
             return null;
 657  
         }
 658  
         
 659  0
         if (listener != null) {
 660  0
             r.addActionListener(listener);
 661  
         }
 662  0
         return r;
 663  
     }
 664  
     
 665  
 }