/* * Copyright (c) 2009 The Jackson Laboratory * * This software was developed by Gary Churchill's Lab at The Jackson * Laboratory (see http://research.jax.org/faculty/churchill). * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software. If not, see <http://www.gnu.org/licenses/>. */ package org.jax.r.gui; import java.awt.Rectangle; import java.util.logging.Logger; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JMenuBar; import javax.swing.JOptionPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.StyledDocument; import org.jax.r.jriutilities.RInterface; import org.jax.r.project.ProjectAwareDocumentWritingRInterfaceListener; import org.jax.util.TextWrapper; import org.jax.util.concurrent.MultiTaskProgressPanel; import org.jax.util.project.ProjectManager; /** * The main frame class for the J/qtl application. * @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A> */ public class ApplicationFrame extends javax.swing.JFrame { /** * every {@link java.io.Serializable} is supposed to have one of these */ private static final long serialVersionUID = -4657115227288438478L; private final RInterface rInterface; private final JMenuBar menuBar; private final JDesktopPane desktop; private final JTree projectTree; private static final Logger LOG = Logger.getLogger( ApplicationFrame.class.getName()); private MultiTaskProgressPanel taskProgressPanel = new MultiTaskProgressPanel(); private final ProjectManager projectManager; /** * Constructor * @param title * the application title * @param rInterface * the R interface to attach to * @param menuBar * the menu bar to use * @param desktop * the main desktop pane * @param projectTree * the project tree * @param projectManager * the project manager */ public ApplicationFrame( String title, RInterface rInterface, JMenuBar menuBar, JDesktopPane desktop, JTree projectTree, ProjectManager projectManager) { super(title); this.rInterface = rInterface; this.menuBar = menuBar; this.desktop = desktop; this.projectTree = projectTree; this.projectManager = projectManager; this.initComponents(); this.postGuiInit(); } /** * Getter for the task progress panel * @return the task progress panel */ public MultiTaskProgressPanel getTaskProgressPanel() { return this.taskProgressPanel; } /** * take care of the initialization that isn't handled by the GUI builder */ private void postGuiInit() { StyledDocument terminalDocument = this.terminalTextPane.getStyledDocument(); terminalDocument.addDocumentListener(new DocumentListener() { /** * {@inheritDoc} */ public void changedUpdate(DocumentEvent e) { // Don't care } /** * {@inheritDoc} */ public void insertUpdate(DocumentEvent e) { SwingUtilities.invokeLater(new Runnable() { /** * {@inheritDoc} */ public void run() { ApplicationFrame.this.terminalTextPane.scrollRectToVisible(new Rectangle( 0, ApplicationFrame.this.terminalTextPane.getHeight(), 0, 0)); } }); } /** * {@inheritDoc} */ public void removeUpdate(DocumentEvent e) { // Don't care } }); this.dataTreeScrollPane.setViewportView(this.projectTree); this.rInterface.addRInterfaceListener( new ProjectAwareDocumentWritingRInterfaceListener( terminalDocument, this.projectManager)); this.setExtendedState(JFrame.MAXIMIZED_BOTH); this.taskProgressPanel.addTaskToTrack(this.rInterface); } /** * Ask the user to enter a command */ private void insertUserCommand() { String commandString = (String)JOptionPane.showInputDialog( this, TextWrapper.wrapText( "Text will be interpreted as a comment if it starts " + "with a '#' character. Otherwise it is executed as an " + "R command. Please use care when entering a command since no " + "effort is made to ensure that the command is valid " + "or that the project data structures will be unaffected " + "before the command is executed.", TextWrapper.DEFAULT_DIALOG_COLUMN_COUNT), "User Defined R Comment or Command", JOptionPane.PLAIN_MESSAGE, null, null, "# "); if((commandString != null) && (commandString.trim().length() > 0)) { String trimmedCommandString = commandString.trim(); if(trimmedCommandString.startsWith("#")) { LOG.fine("inserting user defined comment"); this.rInterface.insertCommentVerbatim(commandString + "\n"); } else { LOG.info("evaluating user entered command: " + commandString); this.rInterface.insertComment("evaluating user entered command"); this.rInterface.evaluateCommandNoReturn(commandString.trim()); LOG.fine( "notifying active project of a potential change " + "to the data structures"); this.projectManager.refreshProjectDataStructures(); this.projectManager.notifyActiveProjectModified(); } } else { LOG.info("User entered command canceled"); } } /** * Close the application after checking if there are any unsaved project * changes. */ public void closeApplication() { if(this.projectManager.isActiveProjectModified()) { String message = "The current project contains unsaved modifications. Exiting the " + "application before saving will cause these modifications to be lost. " + "Would you like to exit without saving?"; int response = JOptionPane.showConfirmDialog( this, TextWrapper.wrapText( message, TextWrapper.DEFAULT_DIALOG_COLUMN_COUNT), "Unsaved Project Modifications", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if(response == JOptionPane.CLOSED_OPTION || response == JOptionPane.CANCEL_OPTION) { return; } } // we're OK to quit System.exit(0); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("all") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; javax.swing.JSplitPane outerSplitPane = new javax.swing.JSplitPane(); javax.swing.JSplitPane innerSplitPane = new javax.swing.JSplitPane(); dataTreeScrollPane = new javax.swing.JScrollPane(); javax.swing.JDesktopPane desktopPane = desktop; javax.swing.JPanel terminalPanel = new javax.swing.JPanel(); javax.swing.JPanel terminalHeaderPanel = new javax.swing.JPanel(); terminalToolBar = new javax.swing.JToolBar(); javax.swing.JButton insertCommandButton = new javax.swing.JButton(); javax.swing.JPanel taskTrackerPanelDowncast = taskProgressPanel; javax.swing.JScrollPane terminalScrollPane = new javax.swing.JScrollPane(); terminalTextPane = new javax.swing.JTextPane(); javax.swing.JMenuBar mainMenu = menuBar; setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { formWindowClosing(evt); } }); outerSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); outerSplitPane.setResizeWeight(0.7); outerSplitPane.setOneTouchExpandable(true); innerSplitPane.setResizeWeight(0.2); innerSplitPane.setOneTouchExpandable(true); innerSplitPane.setLeftComponent(dataTreeScrollPane); innerSplitPane.setRightComponent(desktopPane); outerSplitPane.setTopComponent(innerSplitPane); terminalPanel.setLayout(new java.awt.BorderLayout()); terminalHeaderPanel.setLayout(new java.awt.GridBagLayout()); terminalToolBar.setFloatable(false); terminalToolBar.setRollover(true); insertCommandButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/terminal-16x16.png"))); // NOI18N insertCommandButton.setText("Insert Comment or Command ..."); insertCommandButton.setFocusable(false); insertCommandButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); insertCommandButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { insertCommandButtonActionPerformed(evt); } }); terminalToolBar.add(insertCommandButton); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; terminalHeaderPanel.add(terminalToolBar, gridBagConstraints); terminalHeaderPanel.add(taskTrackerPanelDowncast, new java.awt.GridBagConstraints()); terminalPanel.add(terminalHeaderPanel, java.awt.BorderLayout.PAGE_START); terminalTextPane.setEditable(false); terminalTextPane.setDragEnabled(false); terminalScrollPane.setViewportView(terminalTextPane); terminalPanel.add(terminalScrollPane, java.awt.BorderLayout.CENTER); outerSplitPane.setRightComponent(terminalPanel); getContentPane().add(outerSplitPane, java.awt.BorderLayout.CENTER); setJMenuBar(mainMenu); pack(); }// </editor-fold>//GEN-END:initComponents private void insertCommandButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_insertCommandButtonActionPerformed this.insertUserCommand(); }//GEN-LAST:event_insertCommandButtonActionPerformed private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing this.closeApplication(); }//GEN-LAST:event_formWindowClosing // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane dataTreeScrollPane; private javax.swing.JTextPane terminalTextPane; private javax.swing.JToolBar terminalToolBar; // End of variables declaration//GEN-END:variables }