001    /*
002     * Copyright 2007, 2012 Stephen Fisher and Junhyong Kim, University of
003     * Pennsylvania.
004     *
005     * This file is part of Glo-DB.
006     * 
007     * Glo-DB is free software: you can redistribute it and/or modify it
008     * under the terms of the GNU General Public License as published by
009     * the Free Software Foundation, either version 3 of the License, or
010     * (at your option) any later version.
011     * 
012     * Glo-DB is distributed in the hope that it will be useful, but
013     * WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015     * General Public License for more details.
016     * 
017     * You should have received a copy of the GNU General Public License
018     * along with Glo-DB. If not, see <http://www.gnu.org/licenses/>.
019     *
020     * @(#)Root.java
021     */
022    
023    package edu.upenn.gloDB.gui;
024    
025    import edu.upenn.gloDB.*;
026    import java.awt.*;
027    import java.awt.event.*;
028    import javax.swing.*;
029    import java.net.URL;
030    import java.net.MalformedURLException;
031    
032    /**
033     * Base window for GUI.
034     *
035     * @author  Stephen Fisher
036     * @version $Id: Root.java,v 1.35.2.28 2007/03/01 21:17:33 fisher Exp $
037     */
038    
039    public class Root  {
040             private static RootFrame rootFrame = null;
041    
042             /**
043              * This will contain all error and warning messages.  This output
044              * panel can be disabled by setting the 'showMessages' flag to
045              * false.  When disabled, all messages printed will be displayed
046              * in the console.
047              */
048             public static JTextArea messages = new JTextArea(20, 90);
049    
050             /** 
051              * Flag whether to display messages in the 'messages' panel.  If
052              * false, then print the messages in the console.  If true, then
053              * messages will only go to the messages panel and not the console.
054              */
055             public static boolean showMessages = true;
056    
057             /**
058              * This will contain all commands that the GUI generates and sends
059              * to the console to be run.  The text in this panel can be copied
060              * and pasted into a python file to run directly in the console.
061              */
062             public static JTextArea history = new JTextArea(10, 90);
063    
064             public static JLabel statusBar;
065    
066             public static JFrame show() {
067                      // only allow one instance of rootFrame
068                      if (rootFrame == null) rootFrame = new RootFrame();
069                      rootFrame.show();
070                      return rootFrame;
071             }
072                      
073             /** 
074              * This will add the String to the history and if 'toConsole',
075              * then run the command through the console.
076              */
077             public static void runCommand(String msg, boolean toConsole) {
078                      history.append(msg + "\n");
079                      if (toConsole) GloDBMain.console.exec("print; " + msg);
080             }
081    
082             private static class RootFrame extends JFrame implements ActionListener {
083                      private JMenuItem loadTrack;
084                      private JMenuItem saveTrack;
085                      private JMenuItem newSequence;
086                      private JMenuItem loadSequence;
087                      private JMenuItem saveSequence;
088                      private JMenuItem quit;
089                      
090                      private JMenuItem copyHistory;
091                      private JMenuItem clearHistory;
092                      private JMenuItem selectHistory;
093                      private JCheckBoxMenuItem toggleShowMessages;
094                      private JMenuItem clearMessages;
095                      private JMenuItem queryTracks;
096                      //     private JMenuItem updateTracks;
097                      
098                      private JMenuItem browseTracks;
099                      private JMenuItem browseSequences;
100                      private JMenuItem displayTrack;
101                      private JMenuItem displaySequence;
102                      
103                      private JMenuItem helpTopics;
104                      private JMenuItem viewAPI;
105                      private JMenuItem parserDefs;
106                      private JMenuItem about;
107                      
108                      private JTextArea messages = Root.messages;
109                      private JTextArea history = Root.history;
110                      private JLabel statusBar = Root.statusBar;
111                      
112                      public RootFrame() {
113                                    super("GLO-DB");
114                                    
115                                    // this will cause all warnings to be sent here instead of to
116                                    // the console
117                                    GloDBUtils.guiMessages = messages;
118                                    
119                                    //                setDefaultCloseOperation(DISPOSE_ON_CLOSE);
120                                    setDefaultCloseOperation(EXIT_ON_CLOSE);
121                                    
122                                    //                addWindowListener(new WindowAdapter() {
123                                    //                                       public void windowClosing(WindowEvent e) { System.exit(0); }
124                                    //                              });
125                                    
126                                    /**** FILE MENU ****/
127                                    JMenu fileMenu = new JMenu("File");
128                                    fileMenu.setMnemonic(KeyEvent.VK_F);
129                                    
130                                    loadTrack = addMenuItem(loadTrack, fileMenu, "Load Track", KeyEvent.VK_L, new ImageIcon("icons/load_m.png"));
131                                    saveTrack = addMenuItem(saveTrack, fileMenu, "Save Track", -1, new ImageIcon("icons/save_m.png"));
132                                    saveTrack.setMnemonic(KeyEvent.VK_S);
133                                    fileMenu.addSeparator();
134                                    newSequence = addMenuItem(newSequence, fileMenu, "New Sequence", -1, new ImageIcon("icons/new_m.png"));
135                                    newSequence.setMnemonic(KeyEvent.VK_N);
136                                    loadSequence = addMenuItem(loadSequence, fileMenu, "Load Sequence", -1, new ImageIcon("icons/load_m.png"));
137                                    //                              saveSequence = addMenuItem(saveSequence, fileMenu, "Save Sequence", -1, new ImageIcon("icons/save_m.png"));
138                                    fileMenu.addSeparator();
139                                    quit = addMenuItem(quit, fileMenu, "Quit", KeyEvent.VK_Q, new ImageIcon("icons/quit_m.png"));
140                                    
141                                    /**** EDIT MENU ****/
142                                    JMenu editMenu = new JMenu("Edit");
143                                    editMenu.setMnemonic(KeyEvent.VK_E);
144                                    copyHistory = addMenuItem(copyHistory, editMenu, "Copy History", -1, new ImageIcon("icons/copy_m.png"));
145                                    copyHistory.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
146                                    clearHistory = addMenuItem(clearHistory, editMenu, "Clear History", -1, new ImageIcon("icons/clear_m.png"));
147                                    clearHistory.setMnemonic(KeyEvent.VK_C);
148                                    selectHistory = addMenuItem(selectHistory, editMenu, "Select All History", -1, new ImageIcon(""));
149                                    selectHistory.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.CTRL_MASK));
150                                    editMenu.addSeparator();
151                                    toggleShowMessages = new JCheckBoxMenuItem("Enable Message Window");
152                                    toggleShowMessages.addActionListener(this);
153                                    toggleShowMessages.setSelected(Root.showMessages);
154                                    toggleShowMessages.setToolTipText("Disabling the Message Window will cause messagaes to be sent to the command line.");
155                                    editMenu.add(toggleShowMessages);
156                                    clearMessages = addMenuItem(clearMessages, editMenu, "Clear Messages", -1, new ImageIcon("icons/clear_m.png"));
157                                    editMenu.addSeparator();
158                                    queryTracks = addMenuItem(queryTracks, editMenu, "Query Tracks", KeyEvent.VK_G, new ImageIcon("icons/search_m.png"));
159                                    //                updateTracks = addMenuItem(updateTracks, editMenu, "Update Tracks", -1, null);
160                                    
161                                    /**** VIEW MENU ****/
162                                    JMenu viewMenu = new JMenu("View");
163                                    viewMenu.setMnemonic(KeyEvent.VK_V);
164                                    browseTracks = addMenuItem(browseTracks, viewMenu, "Browse Tracks", -1, new ImageIcon("icons/browse_m.png"));
165                                    browseSequences = addMenuItem(browseSequences, viewMenu, "Browse Sequences", -1, new ImageIcon("icons/browse_m.png"));
166                                    viewMenu.addSeparator();
167                                    displayTrack = addMenuItem(displayTrack, viewMenu, "Display Track", -1, new ImageIcon("icons/graph_m.png"));
168                                    displaySequence = addMenuItem(displaySequence, viewMenu, "Display Sequence", -1, new ImageIcon("icons/graph_m.png"));
169                                    
170                                    /**** HELP MENU ****/
171                                    JMenu helpMenu = new JMenu("Help");
172                                    helpMenu.setMnemonic(KeyEvent.VK_H);
173                                    helpTopics = addMenuItem(helpTopics, helpMenu, "Help Topics", -1, new ImageIcon("icons/help_m.png"));
174                                    viewAPI = addMenuItem(viewAPI, helpMenu, "API Documentation", -1, null);
175                                    parserDefs = addMenuItem(parserDefs, helpMenu, "Parser Definitions", -1, null);
176                                    helpMenu.addSeparator();
177                                    about = addMenuItem(about, helpMenu, "About", -1, new ImageIcon("icons/info_m.png"));
178                                    
179                                    // put menu together and add to root pane
180                                    JMenuBar menuBar = new JMenuBar();
181                                    menuBar.add(fileMenu);
182                                    menuBar.add(editMenu);
183                                    menuBar.add(viewMenu);
184                                    // push help menu to the right side
185                                    menuBar.add(Box.createHorizontalGlue());
186                                    menuBar.add(helpMenu);
187                                    getRootPane().setJMenuBar(menuBar);
188                                    
189                                    // add messages as a scrolled text area.
190                                    messages.setEditable(false);
191                                    JScrollPane messagesSP = new JScrollPane(messages);
192                                    messagesSP.setBorder(BorderFactory.createLoweredBevelBorder());
193                                    JPanel messagesP = new JPanel(false);
194                                    messagesP.setLayout(new BorderLayout());
195                                    messagesP.add(new JLabel(" Messages:"), BorderLayout.NORTH);
196                                    messagesP.add(messagesSP, BorderLayout.CENTER);
197                                    
198                                    // add history as a scrolled text area.
199                                    history.setEditable(false);
200                                    JScrollPane historySP = new JScrollPane(history);
201                                    historySP.setBorder(BorderFactory.createLoweredBevelBorder());
202                                    JPanel historyP = new JPanel(false);
203                                    historyP.setLayout(new BorderLayout());
204                                    historyP.add(new JLabel(" History:"), BorderLayout.NORTH);
205                                    historyP.add(historySP, BorderLayout.CENTER);
206                                    
207                                    // setup main JPanel for window
208                                    JPanel mainPane = new JPanel(false);
209                                    mainPane.setLayout(new BorderLayout());
210                                    JSplitPane mainSplitP = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 
211                                                                                                                                            messagesP, historyP);
212                                    mainSplitP.setOneTouchExpandable(true);
213                                    // provide minimum sizes for the two components in the split pane
214                                    messagesP.setMinimumSize(new Dimension(700, 400));
215                                    historyP.setMinimumSize(new Dimension(700, 200));
216                                    // provide a preferred size for the split pane
217                                    mainSplitP.setPreferredSize(new Dimension(700, 600));
218                                    // resize upper panel by 50% more that lower when the window
219                                    // is expended
220                                    mainSplitP.setResizeWeight(0.75);
221                                    mainPane.add(mainSplitP, BorderLayout.CENTER);
222                                    
223                                    // add status bar at bottom of window.  Use a 'spacer' so that
224                                    // anything added to statusBar later won't be crammed into the
225                                    // left margin.
226                                    statusBar = new JLabel(" ");
227                                    JPanel statusBarP = new JPanel(false);
228                                    statusBarP.setBorder(BorderFactory.createLoweredBevelBorder());
229                                    statusBarP.setLayout(new BorderLayout());
230                                    statusBarP.add(new JLabel(" "), BorderLayout.WEST);
231                                    statusBarP.add(statusBar, BorderLayout.CENTER);
232                                    mainPane.add(statusBarP, BorderLayout.SOUTH);
233                                    
234                                    getContentPane().add(mainPane);
235                                    pack();
236                                    
237                                    // set the default window size
238                                    //                setSize(getSize().width + 300, getSize().height + 200);
239                                    
240                                    // display the window
241                                    //                setVisible(true);
242                                    show();
243                      }
244                      
245                      //--------------------------------------------------------------------------
246                      // Miscellaneous Methods
247                      
248                      /** Handle menu items. */
249                      public void actionPerformed(ActionEvent e) {
250                                    //                history.append("Event source: " + ((JMenuItem) e.getSource()).getText() + "\n");
251                                    
252                                    // erase status bar whenever there is an ActionEvent.
253                                    statusBar.setText("");
254                                    
255                                    if (e.getSource() instanceof JMenuItem) {
256                                             JMenuItem source = (JMenuItem) e.getSource();
257                                             
258                                             if (source == loadTrack) {
259                                                      GUITrackIO.loadTrack();
260                                             } else if (source == saveTrack) {
261                                                      String track = GUIUtils.trackSelector();
262                                                      if (track.length() == 0) return;
263                                                      GUITrackIO.saveTrack(track);
264                                             } else if (source == loadSequence) {
265                                                      GUISequenceIO.loadSequence();
266                                             } else if (source == newSequence) {
267                                                      GUISequenceIO.newSequence();
268                                             } else if (source == quit) {
269                                                      System.exit(0);
270                                             } else if (source == copyHistory) {
271                                                      history.copy();
272                                                      // exit here so the 'history' routines below don't undo this
273                                                      return;
274                                             } else if (source == clearHistory) {
275                                                      history.selectAll();
276                                                      history.replaceSelection("");
277                                                      return;
278                                             } else if (source == selectHistory) {
279                                                      history.selectAll();
280                                                      // exit here so the 'history' routines below don't undo this
281                                                      return;
282                                             } else if (source == toggleShowMessages) {
283                                                      Root.showMessages = toggleShowMessages.isSelected();
284                                                      
285                                                      if (Root.showMessages) GloDBUtils.guiMessages = messages;
286                                                      else GloDBUtils.guiMessages = null;
287                                                      //                                     GloDBUtils.printMsg("Value of showMessages: " + Boolean.toString(Root.showMessages));
288                                                      return;
289                                             } else if (source == clearMessages) {
290                                                      messages.selectAll();
291                                                      messages.replaceSelection("");
292                                                      return;
293                                             } else if (source == queryTracks) {
294                                                      new QueryBuilder();
295                                                      Root.runCommand("QueryBuilder()", false);
296                                             } else if (source == displayTrack) {
297                                                      // the following doesn't work because Root() doesn't
298                                                      // get redrawn while waiting on GenomeBrowser()
299                                                      /*
300                                                      // run command here so can change cursor to "wait"
301                                                      // while getting communicating with Genome Browser
302                                                      String track = GUIUtils.trackSelector();
303                                                      if (track.length() > 0) {
304                                                      this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
305                                                      this.repaint();
306                                                      new ViewHTML(GenomeBrowser.viewTrack(track));
307                                                      Root.runCommand("genomeBrowserTrack(\"" + track + "\")", false); 
308                                                      this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
309                                                      }
310                                                      */
311                                                      Root.runCommand("viewTrackGenomeBrowser()", true); 
312                                             } else if (source == browseSequences) {
313                                                      Root.runCommand("sequenceBrowser()", true);
314                                             } else if (source == browseTracks) {
315                                                      Root.runCommand("trackBrowser()", true);
316                                             } else if (source == helpTopics) {
317                                                      Root.runCommand("help()", true);
318                                             } else if (source == viewAPI) {
319                                                      try {
320                                                                    URL url = new URL("file:documentation/index.html");
321                                                                    new ViewHTML(url);
322                                                                    Root.runCommand("viewAPI()", false);
323                                                      } catch (MalformedURLException urlException) {
324                                                                    GloDBUtils.printError("API documentation not found.");
325                                                      }
326                                             } else if (source == parserDefs) {
327                                                      new ViewParserDefs();
328                                                      Root.runCommand("parserDefs()", false);
329                                             } else if (source == about) {
330                                                      Root.runCommand("about()", true);
331                                             } else {
332                                                      statusBar.setText("Menu item not yet available.");
333                                                      GloDBUtils.printMsg("Menu item not yet available.");
334                                             }
335                                             
336                                             history.setCaretPosition(history.getDocument().getLength());
337                                    }
338                      }
339                      
340                      /** Add specified item to specified menu. */
341                      private JMenuItem addMenuItem(JMenuItem item, JMenu menu, String label, int mnemonic, ImageIcon image) {
342                                    JMenuItem out;
343                                    if (image == null) {
344                                             out = new JMenuItem(label);
345                                    } else {
346                                             out = new JMenuItem(label, image);
347                                    }
348                                    if (mnemonic != -1) { 
349                                             out.setMnemonic(mnemonic);
350                                             out.setAccelerator(KeyStroke.getKeyStroke(mnemonic, ActionEvent.ALT_MASK));
351                                    }
352                                    out.addActionListener(this);
353                                    menu.add(out);
354                                    return out;
355                      }
356                      
357             } // Root.java
358    }