001 package org.LiveGraph.gui; 002 003 import java.awt.BorderLayout; 004 import java.awt.Dimension; 005 import java.awt.Toolkit; 006 007 import javax.swing.Box; 008 import javax.swing.JFileChooser; 009 import javax.swing.JFrame; 010 import javax.swing.JOptionPane; 011 import javax.swing.JScrollBar; 012 import javax.swing.JTextArea; 013 import javax.swing.JMenu; 014 import javax.swing.JMenuBar; 015 import javax.swing.JMenuItem; 016 import javax.swing.WindowConstants; 017 import javax.swing.JScrollPane; 018 import javax.swing.JCheckBoxMenuItem; 019 import javax.swing.filechooser.FileFilter; 020 021 import org.LiveGraph.LiveGraph; 022 import org.LiveGraph.settings.DataFileSettings; 023 import org.LiveGraph.settings.DataSeriesSettings; 024 import org.LiveGraph.settings.ErrorWhileSettingHasChangedProcessingException; 025 import org.LiveGraph.settings.GraphSettings; 026 027 028 import java.awt.Font; 029 import java.awt.event.ActionEvent; 030 import java.awt.event.ActionListener; 031 import java.awt.event.WindowAdapter; 032 import java.awt.event.WindowEvent; 033 import java.io.File; 034 import java.text.DateFormat; 035 import java.text.SimpleDateFormat; 036 import java.util.Date; 037 038 /** 039 * This is the main window of the application. 040 * 041 * <p style="font-size:smaller;">This product includes software developed by the 042 * <strong>LiveGraph</strong> project and its contributors.<br /> 043 * (<a href="http://www.live-graph.org" target="_blank">http://www.live-graph.org</a>)<br /> 044 * Copyright (c) 2007 G. Paperin.<br /> 045 * All rights reserved. 046 * </p> 047 * <p style="font-size:smaller;">File: MainWindow.java</p> 048 * <p style="font-size:smaller;">Redistribution and use in source and binary forms, with or 049 * without modification, are permitted provided that the following terms and conditions are met: 050 * </p> 051 * <p style="font-size:smaller;">1. Redistributions of source code must retain the above 052 * acknowledgement of the LiveGraph project and its web-site, the above copyright notice, 053 * this list of conditions and the following disclaimer.<br /> 054 * 2. Redistributions in binary form must reproduce the above acknowledgement of the 055 * LiveGraph project and its web-site, the above copyright notice, this list of conditions 056 * and the following disclaimer in the documentation and/or other materials provided with 057 * the distribution.<br /> 058 * 3. All advertising materials mentioning features or use of this software or any derived 059 * software must display the following acknowledgement:<br /> 060 * <em>This product includes software developed by the LiveGraph project and its 061 * contributors.<br />(http://www.live-graph.org)</em><br /> 062 * 4. All advertising materials distributed in form of HTML pages or any other technology 063 * permitting active hyper-links that mention features or use of this software or any 064 * derived software must display the acknowledgment specified in condition 3 of this 065 * agreement, and in addition, include a visible and working hyper-link to the LiveGraph 066 * homepage (http://www.live-graph.org). 067 * </p> 068 * <p style="font-size:smaller;">THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY 069 * OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 070 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 071 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 072 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 073 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 074 * </p> 075 * 076 * @author Greg Paperin (<a href="http://www.paperin.org" target="_blank">http://www.paperin.org</a>) 077 * @version {@value org.LiveGraph.LiveGraph#version} 078 */ 079 public class MainWindow extends JFrame { 080 081 private static final DateFormat logTimestampFormat = new SimpleDateFormat("HH:mm:ss"); 082 083 private JTextArea messageArea = null; 084 private JCheckBoxMenuItem dataFileSettingsDisplayMenuItem = null; 085 private JCheckBoxMenuItem graphSettingsDisplayMenuItem = null; 086 private JCheckBoxMenuItem seriesSettingsDisplayMenuItem = null; 087 private JCheckBoxMenuItem plotDisplayMenuItem = null; 088 089 /** 090 * This is the default constructor. 091 */ 092 public MainWindow() { 093 super(); 094 initialize(); 095 } 096 097 098 /** 099 * This method initializes the main window. 100 */ 101 private void initialize() { 102 103 // Main window size and position: 104 final int WIN_WIDTH = 600; 105 final int WIN_HEIGHT = 200; 106 Dimension scr = Toolkit.getDefaultToolkit().getScreenSize(); 107 this.setBounds((scr.width - WIN_WIDTH) / 2, (scr.height - WIN_HEIGHT) / 2, WIN_WIDTH, WIN_HEIGHT); 108 109 // Other main settings: 110 final MainWindow MAIN_WIN = this; 111 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 112 this.setTitle("LiveGraph"); 113 getContentPane().setLayout(new BorderLayout()); 114 115 // CLosing handler: 116 this.addWindowListener(new WindowAdapter() { 117 @Override public void windowClosing(WindowEvent e) { 118 LiveGraph.application().disposeGUIAndExit(); 119 } 120 }); 121 122 // Message area in the centre: 123 JScrollPane centreScrollPane = new JScrollPane(); 124 getContentPane().add(centreScrollPane, BorderLayout.CENTER); 125 messageArea = new JTextArea(); 126 messageArea.setEditable(false); 127 messageArea.setFont(new Font("Courier New", Font.PLAIN, 12)); 128 centreScrollPane.setViewportView(messageArea); 129 130 // Menu: 131 JMenuBar menuBar = new JMenuBar(); 132 this.setJMenuBar(menuBar); 133 JMenu menu = null; 134 JMenuItem mItem = null; 135 136 menu = new JMenu("Data file"); 137 final JFileChooser dataFileSettingsFileDlg = new JFileChooser(); 138 dataFileSettingsFileDlg.setFileFilter(new FileFilter() { 139 @Override public boolean accept(File f) { 140 if (null == f) return false; 141 if (f.isDirectory()) return true; 142 int p = f.getName().lastIndexOf("."); 143 return p < 0 144 ? false 145 : f.getName().substring(p).equalsIgnoreCase(DataFileSettings.preferredFileExtension); 146 } 147 @Override public String getDescription() { 148 return "LiveGraph data file settings (*" + DataFileSettings.preferredFileExtension + ")"; 149 } 150 }); 151 dataFileSettingsFileDlg.setCurrentDirectory(new File(System.getProperty("user.dir"))); 152 mItem = new JMenuItem("Load data file settings..."); 153 mItem.addActionListener(new ActionListener() { 154 public void actionPerformed(ActionEvent e) { 155 if (JFileChooser.APPROVE_OPTION != dataFileSettingsFileDlg.showOpenDialog(MAIN_WIN)) 156 return; 157 File selFile = dataFileSettingsFileDlg.getSelectedFile(); 158 if (!selFile.exists()) 159 return; 160 161 try { 162 if (LiveGraph.application().getDataFileSettings().load(selFile.getAbsolutePath())) 163 LiveGraph.application().logSuccessLn("Data file settings loaded from " + selFile.getName() + "."); 164 else 165 LiveGraph.application().logErrorLn("Error while loading data file settings from " + selFile.getName() + "."); 166 167 } catch (ErrorWhileSettingHasChangedProcessingException ex) { 168 logErrorLn("There was a problem while loading data file settings: \n" 169 + " " + (null != ex.getCause() ? ex.getCause().getMessage() : ex.getMessage()) + "."); 170 } 171 } 172 }); 173 menu.add(mItem); 174 mItem = new JMenuItem("Save data file settings..."); 175 menu.add(mItem); 176 mItem.addActionListener(new ActionListener() { 177 public void actionPerformed(ActionEvent e) { 178 if (JFileChooser.APPROVE_OPTION != dataFileSettingsFileDlg.showSaveDialog(MAIN_WIN)) 179 return; 180 File selFile = dataFileSettingsFileDlg.getSelectedFile(); 181 if (!selFile.getParentFile().exists()) 182 return; 183 if (!selFile.getName().contains(".")) 184 selFile = new File(selFile.getAbsolutePath() + DataFileSettings.preferredFileExtension); 185 if (LiveGraph.application().getDataFileSettings().save(selFile.getAbsolutePath())) 186 LiveGraph.application().logSuccessLn("Data file settings saved to " + selFile.getName() + "."); 187 else 188 LiveGraph.application().logErrorLn("Error while saving data file settings to " + selFile.getName() + "."); 189 } 190 }); 191 menu.addSeparator(); 192 dataFileSettingsDisplayMenuItem = new JCheckBoxMenuItem("Display data file settings"); 193 dataFileSettingsDisplayMenuItem.addActionListener(new ActionListener() { 194 public void actionPerformed(ActionEvent e) { 195 LiveGraph.application().setDisplayDataFileSettingsWindow(dataFileSettingsDisplayMenuItem.getState()); 196 } 197 }); 198 menu.add(dataFileSettingsDisplayMenuItem); 199 menuBar.add(menu); 200 201 menu = new JMenu("Graph settings"); 202 final JFileChooser graphSettingsFileDlg = new JFileChooser(); 203 graphSettingsFileDlg.setFileFilter(new FileFilter() { 204 @Override public boolean accept(File f) { 205 if (null == f) return false; 206 if (f.isDirectory()) return true; 207 int p = f.getName().lastIndexOf("."); 208 return p < 0 209 ? false 210 : f.getName().substring(p).equalsIgnoreCase(GraphSettings.preferredFileExtension); 211 } 212 @Override public String getDescription() { 213 return "LiveGraph graph settings (*" + GraphSettings.preferredFileExtension + ")"; 214 } 215 }); 216 graphSettingsFileDlg.setCurrentDirectory(new File(System.getProperty("user.dir"))); 217 mItem = new JMenuItem("Load graph settings..."); 218 mItem.addActionListener(new ActionListener() { 219 public void actionPerformed(ActionEvent e) { 220 if (JFileChooser.APPROVE_OPTION != graphSettingsFileDlg.showOpenDialog(MAIN_WIN)) 221 return; 222 File selFile = graphSettingsFileDlg.getSelectedFile(); 223 if (!selFile.exists()) 224 return; 225 226 try { 227 if (LiveGraph.application().getGraphSettings().load(selFile.getAbsolutePath())) 228 LiveGraph.application().logSuccessLn("Graph settings loaded from " + selFile.getName() + "."); 229 else 230 LiveGraph.application().logErrorLn("Error while loading graph settings from " + selFile.getName() + "."); 231 232 } catch (ErrorWhileSettingHasChangedProcessingException ex) { 233 logErrorLn("There was a problem while loading graph settings: \n" 234 + " " + (null != ex.getCause() ? ex.getCause().getMessage() : ex.getMessage()) + "."); 235 } 236 } 237 }); 238 menu.add(mItem); 239 mItem = new JMenuItem("Save graph settings..."); 240 mItem.addActionListener(new ActionListener() { 241 public void actionPerformed(ActionEvent e) { 242 if (JFileChooser.APPROVE_OPTION != graphSettingsFileDlg.showSaveDialog(MAIN_WIN)) 243 return; 244 File selFile = graphSettingsFileDlg.getSelectedFile(); 245 if (!selFile.getParentFile().exists()) 246 return; 247 if (!selFile.getName().contains(".")) 248 selFile = new File(selFile.getAbsolutePath() + GraphSettings.preferredFileExtension); 249 if (LiveGraph.application().getGraphSettings().save(selFile.getAbsolutePath())) 250 LiveGraph.application().logSuccessLn("Graph settings saved to " + selFile.getName() + "."); 251 else 252 LiveGraph.application().logErrorLn("Error while saving graph settings to " + selFile.getName() + "."); 253 } 254 }); 255 menu.add(mItem); 256 menu.addSeparator(); 257 graphSettingsDisplayMenuItem = new JCheckBoxMenuItem("Display graph settings"); 258 graphSettingsDisplayMenuItem.addActionListener(new ActionListener() { 259 public void actionPerformed(ActionEvent e) { 260 LiveGraph.application().setDisplayGraphSettingsWindow(graphSettingsDisplayMenuItem.getState()); 261 } 262 }); 263 menu.add(graphSettingsDisplayMenuItem); 264 menuBar.add(menu); 265 266 menu = new JMenu("Data series"); 267 final JFileChooser seriesSettingsFileDlg = new JFileChooser(); 268 seriesSettingsFileDlg.setFileFilter(new FileFilter() { 269 @Override public boolean accept(File f) { 270 if (null == f) return false; 271 if (f.isDirectory()) return true; 272 int p = f.getName().lastIndexOf("."); 273 return p < 0 274 ? false 275 : f.getName().substring(p).equalsIgnoreCase(DataSeriesSettings.preferredFileExtension); 276 } 277 @Override public String getDescription() { 278 return "LiveGraph data series settings (*" + DataSeriesSettings.preferredFileExtension + ")"; 279 } 280 }); 281 seriesSettingsFileDlg.setCurrentDirectory(new File(System.getProperty("user.dir"))); 282 mItem = new JMenuItem("Load data series settings..."); 283 mItem.addActionListener(new ActionListener() { 284 public void actionPerformed(ActionEvent e) { 285 if (JFileChooser.APPROVE_OPTION != seriesSettingsFileDlg.showOpenDialog(MAIN_WIN)) 286 return; 287 File selFile = seriesSettingsFileDlg.getSelectedFile(); 288 if (!selFile.exists()) 289 return; 290 291 try { 292 if (LiveGraph.application().getDataSeriesSettings().load(selFile.getAbsolutePath())) 293 LiveGraph.application().logSuccessLn("Data series settings loaded from " + selFile.getName() + "."); 294 else 295 LiveGraph.application().logErrorLn("Error while loading data series settings from " + selFile.getName() + "."); 296 297 } catch (ErrorWhileSettingHasChangedProcessingException ex) { 298 logErrorLn("There was a problem while loading data series settings: \n" 299 + " " + (null != ex.getCause() ? ex.getCause().getMessage() : ex.getMessage()) + "."); 300 } 301 } 302 }); 303 menu.add(mItem); 304 mItem = new JMenuItem("Save data series settings..."); 305 mItem.addActionListener(new ActionListener() { 306 public void actionPerformed(ActionEvent e) { 307 if (JFileChooser.APPROVE_OPTION != seriesSettingsFileDlg.showSaveDialog(MAIN_WIN)) 308 return; 309 File selFile = seriesSettingsFileDlg.getSelectedFile(); 310 if (!selFile.getParentFile().exists()) 311 return; 312 if (!selFile.getName().contains(".")) 313 selFile = new File(selFile.getAbsolutePath() + DataSeriesSettings.preferredFileExtension); 314 if (LiveGraph.application().getDataSeriesSettings().save(selFile.getAbsolutePath())) 315 LiveGraph.application().logSuccessLn("Data series settings saved to " + selFile.getName() + "."); 316 else 317 LiveGraph.application().logErrorLn("Error while saving data series settings to " + selFile.getName() + "."); 318 } 319 }); 320 menu.add(mItem); 321 menu.addSeparator(); 322 seriesSettingsDisplayMenuItem = new JCheckBoxMenuItem("Display data series settings"); 323 seriesSettingsDisplayMenuItem.addActionListener(new ActionListener() { 324 public void actionPerformed(ActionEvent e) { 325 LiveGraph.application().setDisplaySeriesSettingsWindow(seriesSettingsDisplayMenuItem.getState()); 326 } 327 }); 328 menu.add(seriesSettingsDisplayMenuItem); 329 menuBar.add(menu); 330 331 menu = new JMenu("Plot"); 332 mItem = new JMenuItem("Export graph to image..."); 333 mItem.addActionListener(new ActionListener() { 334 public void actionPerformed(ActionEvent e) { 335 LiveGraph.application().getGraphExporter().exportGraph(); 336 } 337 }); 338 menu.add(mItem); 339 menu.addSeparator(); 340 plotDisplayMenuItem = new JCheckBoxMenuItem("Display plot window"); 341 plotDisplayMenuItem.addActionListener(new ActionListener() { 342 public void actionPerformed(ActionEvent e) { 343 LiveGraph.application().setDisplayPlotWindow(plotDisplayMenuItem.getState()); 344 } 345 }); 346 menu.add(plotDisplayMenuItem); 347 menuBar.add(menu); 348 349 menuBar.add(Box.createHorizontalGlue()); 350 menu = new JMenu("Help"); 351 mItem = new JMenuItem("Support..."); 352 mItem.addActionListener(new ActionListener() { 353 public void actionPerformed(ActionEvent e) { 354 JOptionPane.showMessageDialog(MAIN_WIN, 355 "For help using LiveGraph " + LiveGraph.version + " please refer to the user manual at:\n" + 356 "http://www.live-graph.org/userManual.html\n\n" + 357 "In addition you can visit our support forums at:\n" + 358 "http://sourceforge.net/forum/?group_id=191061\n\n" + 359 "For further information browse the LiveGraph website at:\n" + 360 "http://www.live-graph.org\n ", 361 "Help", 362 JOptionPane.INFORMATION_MESSAGE); 363 } 364 }); 365 menu.add(mItem); 366 mItem = new JMenuItem("Info..."); 367 mItem.addActionListener(new ActionListener() { 368 public void actionPerformed(ActionEvent e) { 369 JOptionPane.showMessageDialog(MAIN_WIN, 370 "LiveGraph\nVersion " + LiveGraph.version + "\n" + 371 "http://www.live-graph.org\n\n" + 372 "Developed by Greg Paperin\n(http://www.paperin.org)\n" + 373 "at Monash University\n ", 374 "LiveGraph " + LiveGraph.version + " credits", 375 JOptionPane.INFORMATION_MESSAGE); 376 } 377 }); 378 menu.add(mItem); 379 menuBar.add(menu); 380 } 381 382 /** 383 * Displays a log message. 384 * @param s A message. 385 */ 386 private void logLn(String s) { 387 messageArea.append(s); 388 JScrollBar sb = ((JScrollPane) messageArea.getParent().getParent()).getVerticalScrollBar(); 389 if (null != sb) 390 sb.setValue(sb.getMaximum()); 391 messageArea.append("\n"); 392 } 393 394 /** 395 * Displays an info message. 396 * @param s A message 397 */ 398 public void logInfoLn(String s) { 399 StringBuffer b = new StringBuffer(); 400 b.append("[INFO]("); 401 b.append(logTimestampFormat.format(new Date())); 402 b.append("): "); 403 b.append(s); 404 logLn(b.toString()); 405 } 406 407 /** 408 * Displays an error message. 409 * @param s A message 410 */ 411 public void logErrorLn(String s) { 412 StringBuffer b = new StringBuffer(); 413 b.append("[ERR ]("); 414 b.append(logTimestampFormat.format(new Date())); 415 b.append("): "); 416 b.append(s); 417 logLn(b.toString()); 418 } 419 420 /** 421 * Displays an success message. 422 * @param s A message 423 */ 424 public void logSuccessLn(String s) { 425 StringBuffer b = new StringBuffer(); 426 b.append("[SUCC]("); 427 b.append(logTimestampFormat.format(new Date())); 428 b.append("): "); 429 b.append(s); 430 logLn(b.toString()); 431 } 432 433 /** 434 * Update the menu state of {@link #dataFileSettingsDisplayMenuItem}. 435 * @param state New state. 436 */ 437 public void fileSettingsDisplayStateChanged(boolean state) { 438 dataFileSettingsDisplayMenuItem.setState(state); 439 } 440 441 /** 442 * Update the menu state of {@link #graphSettingsDisplayMenuItem}. 443 * @param state New state. 444 */ 445 public void graphSettingsDisplayStateChanged(boolean state) { 446 graphSettingsDisplayMenuItem.setState(state); 447 } 448 449 /** 450 * Update the menu state of {@link #seriesSettingsDisplayMenuItem}. 451 * @param state New state. 452 */ 453 public void seriesSettingsDisplayStateChanged(boolean state) { 454 seriesSettingsDisplayMenuItem.setState(state); 455 } 456 457 /** 458 * Update the menu state of {@link #plotDisplayMenuItem}. 459 * @param state New state. 460 */ 461 public void plotDisplayStateChanged(boolean state) { 462 plotDisplayMenuItem.setState(state); 463 } 464 465 }