001 /* 002 * CRIMSON 003 * Copyright (c) 2006, Stephen Fisher, Susan Davidson, and Junhyong Kim, 004 * University of Pennsylvania. 005 * 006 * This program is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU General Public License as 008 * published by the Free Software Foundation; either version 2 of the 009 * License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, but 012 * WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 * 02110-1301 USA. 020 * 021 * @(#)Root.java 022 */ 023 024 package edu.upenn.crimson.gui; 025 026 import edu.upenn.crimson.*; 027 import java.awt.*; 028 import java.awt.event.*; 029 import javax.swing.*; 030 import java.net.URL; 031 import java.net.MalformedURLException; 032 033 /** 034 * Base window for GUI. 035 * 036 * @author Stephen Fisher 037 * @version $Id: Root.java,v 1.46 2007/10/09 20:14:16 fisher Exp $ 038 */ 039 040 public class Root { 041 private static RootFrame rootFrame = null; 042 043 /** 044 * This will contain all error and warning messages. This output 045 * panel can be disabled by setting the 'showMessages' flag to 046 * false. When disabled, all messages printed will be displayed 047 * in the console. 048 */ 049 public static JTextArea messages = new JTextArea(20, 90); 050 051 /** 052 * This will be used to display the progress during importing and 053 * exporting of trees. 054 */ 055 public static JProgressBar progressBar = new JProgressBar(); 056 057 /** 058 * Flag whether to display messages in the 'messages' panel. If 059 * false, then print the messages in the console. If true, then 060 * messages will only go to the messages panel and not the console. 061 */ 062 public static boolean showMessages = true; 063 064 /** 065 * This will contain all commands that the GUI generates and sends 066 * to the console to be run. The text in this panel can be copied 067 * and pasted into a python file to run directly in the console. 068 */ 069 public static JTextArea history = new JTextArea(10, 90); 070 071 public static JLabel statusBar; 072 073 public static JFrame show() { 074 // only allow one instance of rootFrame 075 if (rootFrame == null) rootFrame = new RootFrame(); 076 rootFrame.setVisible(true); 077 return rootFrame; 078 } 079 080 /** 081 * This will add the String to the history and then run the 082 * command through the console. 083 */ 084 public static void runCommand(String msg) { 085 runCommand(msg, true); 086 } 087 088 /** 089 * This will add the String to the history and if 'toConsole', 090 * then run the command through the console. 091 */ 092 public static void runCommand(String msg, boolean toConsole) { 093 history.append(msg + "\n"); 094 if (toConsole) CrimsonMain.console.exec("print; " + msg); 095 } 096 097 /** 098 * This will turn on the progress bar. 099 * @XXX For some reason this doesn't work. I think 'exec()' is 100 * blocking the gui. 101 */ 102 public static void startProgressBar(String msg) { 103 progressBar.setString(msg); 104 progressBar.setStringPainted(true); 105 progressBar.setIndeterminate(true); 106 107 if (rootFrame != null) rootFrame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 108 } 109 110 /** This will turn off the progress bar. */ 111 public static void stopProgressBar() { 112 progressBar.setString(""); 113 progressBar.setStringPainted(false); 114 progressBar.setIndeterminate(false); 115 116 if (rootFrame != null) rootFrame.setCursor(null); 117 } 118 119 public static boolean isVisible() { 120 if ((rootFrame != null) && (rootFrame.isVisible())) return true; 121 else return false; 122 } 123 124 private static class RootFrame extends JFrame implements ActionListener { 125 // file menu 126 private JMenuItem setDBType; 127 private JMenuItem openDB; 128 private JMenuItem closeDB; 129 // private JMenuItem reopenDB; 130 private JMenuItem testDB; 131 private JMenuItem quit; 132 133 // edit menu 134 private JMenuItem copyHistory; 135 private JMenuItem clearHistory; 136 private JMenuItem selectHistory; 137 private JCheckBoxMenuItem toggleShowMessages; 138 private JMenuItem clearMessages; 139 140 // tree menu 141 private JMenuItem loadTree; 142 private JMenuItem appendTree; 143 private JMenuItem exportTree; 144 private JMenuItem statsTree; 145 private JMenuItem newickTree; 146 private JMenuItem view3DTree; 147 private JMenuItem refreshTree; 148 private JMenuItem manageTree; 149 private JMenuItem deleteTree; 150 151 // model menu 152 private JMenuItem newModel; 153 private JMenuItem refreshModel; 154 private JMenuItem viewModel; 155 private JMenuItem manageModel; 156 private JMenuItem deleteModel; 157 158 // query menu 159 private JMenuItem newQuery; 160 private JMenuItem loadQuery; 161 private JMenuItem loadAllQuery; 162 private JMenuItem publishQuery; 163 private JMenuItem importQuery; 164 private JMenuItem exportQuery; 165 private JMenuItem viewQuery; 166 private JMenuItem manageQuery; 167 /* private JMenuItem runQuery; */ 168 private JMenuItem deleteQuery; 169 170 // help menu 171 private JMenuItem helpTopics; 172 private JMenuItem viewAPI; 173 private JMenuItem about; 174 175 private JTextArea messages = Root.messages; 176 private JTextArea history = Root.history; 177 private JLabel statusBar = Root.statusBar; 178 private JProgressBar progressBar = Root.progressBar; 179 180 public RootFrame() { 181 super("CRIMSON"); 182 183 // this will cause all warnings to be sent here instead of to 184 // the console 185 CrimsonUtils.guiMessages = messages; 186 187 // setDefaultCloseOperation(DISPOSE_ON_CLOSE); 188 setDefaultCloseOperation(EXIT_ON_CLOSE); 189 190 // addWindowListener(new WindowAdapter() { 191 // public void windowClosing(WindowEvent e) { System.exit(0); } 192 // }); 193 194 /**** FILE MENU ****/ 195 JMenu fileMenu = new JMenu("File"); 196 fileMenu.setMnemonic(KeyEvent.VK_F); 197 198 setDBType = addMenuItem(setDBType, fileMenu, "Set Database Type", KeyEvent.VK_S, new ImageIcon("icons/connect_m.png")); 199 openDB = addMenuItem(openDB, fileMenu, "Open Database...", KeyEvent.VK_O, new ImageIcon("icons/connect_m.png")); 200 // reopenDB = addMenuItem(reopenDB, fileMenu, "Re-open Database", KeyEvent.VK_R, new ImageIcon("icons/refresh_m.png")); 201 closeDB = addMenuItem(closeDB, fileMenu, "Close Database", KeyEvent.VK_C, new ImageIcon("icons/disconnect_m.png")); 202 fileMenu.addSeparator(); 203 testDB = addMenuItem(testDB, fileMenu, "Test Database Connection", -1, new ImageIcon("icons/test_m.png")); 204 fileMenu.addSeparator(); 205 quit = addMenuItem(quit, fileMenu, "Quit", -1, new ImageIcon("icons/quit_m.png")); 206 quit.setMnemonic(KeyEvent.VK_Q); 207 208 /**** EDIT MENU ****/ 209 JMenu editMenu = new JMenu("Edit"); 210 editMenu.setMnemonic(KeyEvent.VK_E); 211 copyHistory = addMenuItem(copyHistory, editMenu, "Copy History", -1, new ImageIcon("icons/copy_m.png")); 212 copyHistory.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK)); 213 clearHistory = addMenuItem(clearHistory, editMenu, "Clear History", -1, new ImageIcon("icons/clear_m.png")); 214 clearHistory.setMnemonic(KeyEvent.VK_C); 215 selectHistory = addMenuItem(selectHistory, editMenu, "Select All History", -1, new ImageIcon("")); 216 selectHistory.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.CTRL_MASK)); 217 editMenu.addSeparator(); 218 toggleShowMessages = new JCheckBoxMenuItem("Enable Message Window"); 219 toggleShowMessages.addActionListener(this); 220 toggleShowMessages.setSelected(Root.showMessages); 221 editMenu.add(toggleShowMessages); 222 clearMessages = addMenuItem(clearMessages, editMenu, "Clear Messages", -1, new ImageIcon("icons/clear_m.png")); 223 224 /**** TREE MENU ****/ 225 JMenu treeMenu = new JMenu("Tree"); 226 treeMenu.setMnemonic(KeyEvent.VK_T); 227 loadTree = addMenuItem(loadTree, treeMenu, "Load...", KeyEvent.VK_L, new ImageIcon("icons/load_m.png")); 228 appendTree = addMenuItem(appendTree, treeMenu, "Append...", -1, new ImageIcon("icons/append_m.png")); 229 appendTree.setMnemonic(KeyEvent.VK_A); 230 exportTree = addMenuItem(exportTree, treeMenu, "Export Tree...", -1, new ImageIcon("icons/export_m.png")); 231 exportTree.setMnemonic(KeyEvent.VK_S); 232 treeMenu.addSeparator(); 233 statsTree = addMenuItem(statsTree, treeMenu, "Stats Tree...", -1, null); 234 statsTree.setMnemonic(KeyEvent.VK_V); 235 newickTree = addMenuItem(newickTree, treeMenu, "View Tree...", -1, null); 236 newickTree.setMnemonic(KeyEvent.VK_N); 237 if (CrimsonMain.WALRUS) { 238 view3DTree = addMenuItem(view3DTree, treeMenu, "3D View Tree...", -1, new ImageIcon("icons/view_m.png")); 239 view3DTree.setMnemonic(KeyEvent.VK_3); 240 } 241 treeMenu.addSeparator(); 242 refreshTree = addMenuItem(refreshTree, treeMenu, "Refresh Tree List", -1, new ImageIcon("icons/refresh_m.png")); 243 refreshTree.setMnemonic(KeyEvent.VK_R); 244 manageTree = addMenuItem(manageTree, treeMenu, "Manage", -1, new ImageIcon("icons/browse_m.png")); 245 manageTree.setMnemonic(KeyEvent.VK_M); 246 treeMenu.addSeparator(); 247 deleteTree = addMenuItem(deleteTree, treeMenu, "Delete", -1, new ImageIcon("icons/delete_m.png")); 248 deleteTree.setMnemonic(KeyEvent.VK_D); 249 250 /**** MODEL MENU ****/ 251 JMenu modelMenu = new JMenu("Model"); 252 modelMenu.setMnemonic(KeyEvent.VK_M); 253 newModel = addMenuItem(newModel, modelMenu, "New...", -1, new ImageIcon("icons/new_m.png")); 254 newModel.setMnemonic(KeyEvent.VK_N); 255 modelMenu.addSeparator(); 256 refreshModel = addMenuItem(refreshModel, modelMenu, "Refresh Model List", -1, new ImageIcon("icons/refresh_m.png")); 257 refreshModel.setMnemonic(KeyEvent.VK_R); 258 viewModel = addMenuItem(viewModel, modelMenu, "View", -1, new ImageIcon("icons/view_m.png")); 259 viewModel.setMnemonic(KeyEvent.VK_V); 260 manageModel = addMenuItem(manageModel, modelMenu, "Manage", -1, new ImageIcon("icons/browse_m.png")); 261 manageModel.setMnemonic(KeyEvent.VK_M); 262 modelMenu.addSeparator(); 263 deleteModel = addMenuItem(deleteModel, modelMenu, "Delete", -1, new ImageIcon("icons/delete_m.png")); 264 deleteModel.setMnemonic(KeyEvent.VK_D); 265 266 /**** QUERY MENU ****/ 267 JMenu queryMenu = new JMenu("Query"); 268 queryMenu.setMnemonic(KeyEvent.VK_Q); 269 newQuery = addMenuItem(newQuery, queryMenu, "New...", -1, new ImageIcon("icons/new_m.png")); 270 newQuery.setMnemonic(KeyEvent.VK_N); 271 loadQuery = addMenuItem(loadQuery, queryMenu, "Load From DB", -1, new ImageIcon("icons/load_m.png")); 272 loadQuery.setMnemonic(KeyEvent.VK_L); 273 loadAllQuery = addMenuItem(loadAllQuery, queryMenu, "Load All From DB", -1, new ImageIcon("icons/refresh_m.png")); 274 loadAllQuery.setMnemonic(KeyEvent.VK_A); 275 publishQuery = addMenuItem(publishQuery, queryMenu, "Publish To DB...", -1, new ImageIcon("icons/publish_m.png")); 276 publishQuery.setMnemonic(KeyEvent.VK_S); 277 queryMenu.addSeparator(); 278 importQuery = addMenuItem(importQuery, queryMenu, "Import...", -1, new ImageIcon("icons/import_m.png")); 279 importQuery.setMnemonic(KeyEvent.VK_L); 280 exportQuery = addMenuItem(exportQuery, queryMenu, "Export...", -1, new ImageIcon("icons/export_m.png")); 281 exportQuery.setMnemonic(KeyEvent.VK_E); 282 queryMenu.addSeparator(); 283 viewQuery = addMenuItem(viewQuery, queryMenu, "View", -1, new ImageIcon("icons/view_m.png")); 284 viewQuery.setMnemonic(KeyEvent.VK_V); 285 manageQuery = addMenuItem(manageQuery, queryMenu, "Manage", -1, new ImageIcon("icons/browse_m.png")); 286 manageQuery.setMnemonic(KeyEvent.VK_M); 287 /* 288 runQuery = addMenuItem(runQuery, queryMenu, "Run", KeyEvent.VK_G, new ImageIcon("icons/search_m.png")); 289 */ 290 queryMenu.addSeparator(); 291 deleteQuery = addMenuItem(deleteQuery, queryMenu, "Delete", -1, new ImageIcon("icons/delete_m.png")); 292 deleteQuery.setMnemonic(KeyEvent.VK_D); 293 294 /**** HELP MENU ****/ 295 JMenu helpMenu = new JMenu("Help"); 296 helpMenu.setMnemonic(KeyEvent.VK_H); 297 helpTopics = addMenuItem(helpTopics, helpMenu, "Script Commands", -1, new ImageIcon("icons/help_m.png")); 298 viewAPI = addMenuItem(viewAPI, helpMenu, "API Documentation", -1, new ImageIcon("icons/info_m.png")); 299 helpMenu.addSeparator(); 300 about = addMenuItem(about, helpMenu, "About", -1, new ImageIcon("icons/info_m.png")); 301 302 // put menu together and add to root pane 303 JMenuBar menuBar = new JMenuBar(); 304 menuBar.add(fileMenu); 305 menuBar.add(editMenu); 306 menuBar.add(treeMenu); 307 menuBar.add(modelMenu); 308 menuBar.add(queryMenu); 309 // push help menu to the right side 310 menuBar.add(Box.createHorizontalGlue()); 311 menuBar.add(helpMenu); 312 getRootPane().setJMenuBar(menuBar); 313 314 // add messages as a scrolled text area. 315 messages.setEditable(false); 316 JScrollPane messagesSP = new JScrollPane(messages); 317 messagesSP.setBorder(BorderFactory.createLoweredBevelBorder()); 318 JPanel messagesP = new JPanel(false); 319 messagesP.setLayout(new BorderLayout()); 320 messagesP.add(new JLabel(" Messages:"), BorderLayout.NORTH); 321 messagesP.add(messagesSP, BorderLayout.CENTER); 322 323 // add history as a scrolled text area. 324 history.setEditable(false); 325 JScrollPane historySP = new JScrollPane(history); 326 historySP.setBorder(BorderFactory.createLoweredBevelBorder()); 327 JPanel historyP = new JPanel(false); 328 historyP.setLayout(new BorderLayout()); 329 historyP.add(new JLabel(" History:"), BorderLayout.NORTH); 330 historyP.add(historySP, BorderLayout.CENTER); 331 332 // setup main JPanel for window 333 JPanel mainPane = new JPanel(false); 334 mainPane.setLayout(new BorderLayout()); 335 JSplitPane mainSplitP = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 336 messagesP, historyP); 337 mainSplitP.setOneTouchExpandable(true); 338 // provide minimum sizes for the two components in the split pane 339 messagesP.setMinimumSize(new Dimension(700, 400)); 340 historyP.setMinimumSize(new Dimension(700, 200)); 341 // provide a preferred size for the split pane 342 mainSplitP.setPreferredSize(new Dimension(700, 600)); 343 // resize upper panel by 50% more that lower when the window 344 // is expended 345 mainSplitP.setResizeWeight(0.75); 346 mainPane.add(mainSplitP, BorderLayout.CENTER); 347 348 // add status bar at bottom of window. Use a 'spacer' so that 349 // anything added to statusBar later won't be crammed into the 350 // left margin. 351 statusBar = new JLabel(" "); 352 JPanel statusBarP = new JPanel(false); 353 statusBarP.setBorder(BorderFactory.createLoweredBevelBorder()); 354 statusBarP.setLayout(new BorderLayout()); 355 statusBarP.add(new JLabel(" "), BorderLayout.WEST); 356 statusBarP.add(statusBar, BorderLayout.CENTER); 357 JPanel progressBarP = new JPanel(false); 358 progressBarP.setLayout(new BorderLayout()); 359 progressBarP.add(new JLabel("Progress: "), BorderLayout.WEST); 360 progressBarP.add(progressBar, BorderLayout.CENTER); 361 statusBarP.add(progressBarP, BorderLayout.EAST); 362 mainPane.add(statusBarP, BorderLayout.SOUTH); 363 getContentPane().add(mainPane); 364 pack(); 365 366 // set the default window size 367 // setSize(getSize().width + 300, getSize().height + 200); 368 369 // display the window 370 setVisible(true); 371 } 372 373 //-------------------------------------------------------------------------- 374 // Miscellaneous Methods 375 376 /** Handle menu items. */ 377 public void actionPerformed(ActionEvent e) { 378 // history.append("Event source: " + ((JMenuItem) e.getSource()).getText() + "\n"); 379 380 // erase status bar whenever there is an ActionEvent. 381 statusBar.setText(""); 382 383 if (e.getSource() instanceof JMenuItem) { 384 JMenuItem source = (JMenuItem) e.getSource(); 385 386 if (source == setDBType) { 387 GUIUtils.setDBType(); 388 } else if (source == openDB) { 389 GUIUtils.openDatabase(); 390 } else if (source == closeDB) { 391 Root.runCommand("closeDatabase()"); 392 } else if (source == testDB) { 393 Root.runCommand("testConnection()"); 394 } else if (source == quit) { 395 System.exit(0); 396 397 } else if (source == copyHistory) { 398 history.copy(); 399 // exit here so the 'history' routines below don't undo this 400 return; 401 } else if (source == clearHistory) { 402 history.selectAll(); 403 history.replaceSelection(""); 404 return; 405 } else if (source == selectHistory) { 406 history.selectAll(); 407 // exit here so the 'history' routines below don't undo this 408 return; 409 } else if (source == toggleShowMessages) { 410 Root.showMessages = toggleShowMessages.isSelected(); 411 412 if (Root.showMessages) CrimsonUtils.guiMessages = messages; 413 else CrimsonUtils.guiMessages = null; 414 return; 415 } else if (source == clearMessages) { 416 messages.selectAll(); 417 messages.replaceSelection(""); 418 return; 419 420 } else if (source == loadTree) { 421 TreeUtils.loadTree(); 422 } else if (source == appendTree) { 423 TreeUtils.appendTree(""); 424 } else if (source == exportTree) { 425 TreeUtils.exportTree(""); 426 } else if (source == statsTree) { 427 TreeUtils.statsTree(""); 428 } else if (source == newickTree) { 429 TreeUtils.newickTree(""); 430 } else if ((source == view3DTree) && CrimsonMain.WALRUS) { 431 TreeUtils.view3DTree(""); 432 } else if (source == refreshTree) { 433 Root.runCommand("loadAllTrees()"); 434 } else if (source == manageTree) { 435 Root.runCommand("treeManager()"); 436 } else if (source == deleteTree) { 437 TreeUtils.deleteTree(""); 438 439 } else if (source == newModel) { 440 Root.runCommand("newModel()"); 441 } else if (source == refreshTree) { 442 Root.runCommand("loadAllModels()"); 443 } else if (source == viewModel) { 444 Root.runCommand("viewModel()"); 445 } else if (source == manageModel) { 446 Root.runCommand("modelManager()"); 447 } else if (source == deleteModel) { 448 ModelUtils.deleteModel(""); 449 450 } else if (source == newQuery) { 451 QueryUtils.newQuery(); 452 } else if (source == loadQuery) { 453 QueryUtils.loadQuery(); 454 } else if (source == loadAllQuery) { 455 Root.runCommand("loadAllQueries()"); 456 } else if (source == publishQuery) { 457 QueryUtils.publishQuery(""); 458 } else if (source == importQuery) { 459 QueryUtils.importQuery(); 460 } else if (source == exportQuery) { 461 QueryUtils.exportQuery(""); 462 } else if (source == viewQuery) { 463 Root.runCommand("viewQuery()"); 464 } else if (source == manageQuery) { 465 Root.runCommand("queryManager()"); 466 } else if (source == deleteQuery) { 467 QueryUtils.deleteQuery(""); 468 469 } else if (source == helpTopics) { 470 Root.runCommand("help()"); 471 } else if (source == viewAPI) { 472 try { 473 URL url = new URL("file:documentation/index.html"); 474 new ViewHTML(url); 475 Root.runCommand("viewAPI()", false); 476 } catch (MalformedURLException urlException) { 477 CrimsonUtils.printMsg("API documentation not found.", CrimsonUtils.ERROR); 478 } 479 } else if (source == about) { 480 Root.runCommand("about()"); 481 } else { 482 statusBar.setText("Menu item not yet available."); 483 CrimsonUtils.printMsg("Menu item not yet available."); 484 } 485 486 history.setCaretPosition(history.getDocument().getLength()); 487 } 488 } 489 490 /** Add specified item to specified menu. */ 491 private JMenuItem addMenuItem(JMenuItem item, JMenu menu, String label, int mnemonic, ImageIcon image) { 492 JMenuItem out; 493 if (image == null) { 494 out = new JMenuItem(label); 495 } else { 496 out = new JMenuItem(label, image); 497 } 498 if (mnemonic != -1) { 499 out.setMnemonic(mnemonic); 500 out.setAccelerator(KeyStroke.getKeyStroke(mnemonic, ActionEvent.ALT_MASK)); 501 } 502 out.addActionListener(this); 503 menu.add(out); 504 return out; 505 } 506 507 } // Root.java 508 }