00001 package edu.stanford.hci.r3;
00002
00003 import java.awt.AWTException;
00004 import java.awt.BorderLayout;
00005 import java.awt.Color;
00006 import java.awt.Component;
00007 import java.awt.Desktop;
00008 import java.awt.Font;
00009 import java.awt.MenuItem;
00010 import java.awt.PopupMenu;
00011 import java.awt.SystemTray;
00012 import java.awt.TrayIcon;
00013 import java.awt.event.ActionEvent;
00014 import java.awt.event.ActionListener;
00015 import java.awt.geom.Rectangle2D;
00016 import java.io.File;
00017 import java.io.FileInputStream;
00018 import java.io.FileNotFoundException;
00019 import java.io.FileOutputStream;
00020 import java.io.IOException;
00021 import java.io.OutputStream;
00022 import java.net.URISyntaxException;
00023 import java.net.URL;
00024 import java.util.ArrayList;
00025 import java.util.Collection;
00026 import java.util.InvalidPropertiesFormatException;
00027 import java.util.List;
00028 import java.util.Map;
00029 import java.util.Properties;
00030
00031 import javax.swing.AbstractListModel;
00032 import javax.swing.BorderFactory;
00033 import javax.swing.Box;
00034 import javax.swing.DefaultListCellRenderer;
00035 import javax.swing.ImageIcon;
00036 import javax.swing.JButton;
00037 import javax.swing.JFrame;
00038 import javax.swing.JLabel;
00039 import javax.swing.JList;
00040 import javax.swing.JPanel;
00041 import javax.swing.JScrollPane;
00042 import javax.swing.JTextArea;
00043 import javax.swing.ListModel;
00044 import javax.swing.ListSelectionModel;
00045 import javax.swing.UIManager;
00046 import javax.swing.WindowConstants;
00047 import javax.swing.event.ListSelectionEvent;
00048 import javax.swing.event.ListSelectionListener;
00049 import javax.swing.filechooser.FileSystemView;
00050
00051 import org.jdesktop.swingx.JXList;
00052 import org.jdesktop.swingx.decorator.ComponentAdapter;
00053 import org.jdesktop.swingx.decorator.ConditionalHighlighter;
00054
00055 import com.jgoodies.looks.plastic.PlasticLookAndFeel;
00056 import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
00057 import com.jgoodies.looks.plastic.theme.DarkStar;
00058 import com.thoughtworks.xstream.XStream;
00059
00060 import edu.stanford.hci.r3.actions.remote.ActionReceiverTrayApp;
00061 import edu.stanford.hci.r3.config.Configuration;
00062 import edu.stanford.hci.r3.events.EventEngine;
00063 import edu.stanford.hci.r3.events.PenEvent;
00064 import edu.stanford.hci.r3.events.handlers.StrokeHandler;
00065 import edu.stanford.hci.r3.events.replay.EventBrowser;
00066 import edu.stanford.hci.r3.paper.Region;
00067 import edu.stanford.hci.r3.paper.Sheet;
00068 import edu.stanford.hci.r3.pattern.coordinates.PatternLocationToSheetLocationMapping;
00069 import edu.stanford.hci.r3.pattern.coordinates.RegionID;
00070 import edu.stanford.hci.r3.pattern.coordinates.conversion.PatternCoordinateConverter;
00071 import edu.stanford.hci.r3.pattern.coordinates.conversion.TiledPatternCoordinateConverter;
00072 import edu.stanford.hci.r3.pen.Pen;
00073 import edu.stanford.hci.r3.pen.PenInput;
00074 import edu.stanford.hci.r3.pen.batch.BatchServer;
00075 import edu.stanford.hci.r3.pen.handwriting.HandwritingRecognitionService;
00076 import edu.stanford.hci.r3.pen.streaming.PenServerTrayApp;
00077 import edu.stanford.hci.r3.tools.ToolExplorer;
00078 import edu.stanford.hci.r3.tools.debug.DebuggingEnvironment;
00079 import edu.stanford.hci.r3.tools.design.acrobat.AcrobatDesignerLauncher;
00080 import edu.stanford.hci.r3.tools.design.acrobat.RegionConfiguration;
00081 import edu.stanford.hci.r3.tools.design.swing.SheetFrame;
00082 import edu.stanford.hci.r3.units.Centimeters;
00083 import edu.stanford.hci.r3.units.Inches;
00084 import edu.stanford.hci.r3.units.PatternDots;
00085 import edu.stanford.hci.r3.units.Pixels;
00086 import edu.stanford.hci.r3.units.Points;
00087 import edu.stanford.hci.r3.util.DebugUtils;
00088 import edu.stanford.hci.r3.util.StringUtils;
00089 import edu.stanford.hci.r3.util.WindowUtils;
00090 import edu.stanford.hci.r3.util.components.EndlessProgressDialog;
00091 import edu.stanford.hci.r3.util.files.FileUtils;
00092 import edu.stanford.hci.r3.util.graphics.ImageCache;
00093 import edu.stanford.hci.r3.util.layout.StackedLayout;
00094
00111 public class PaperToolkit {
00112
00116 private static final Font APP_MANAGER_FONT = new Font("Trebuchet MS", Font.PLAIN, 18);
00117
00118 public static final String CONFIG_FILE_KEY = "papertoolkit.startupinformation";
00119
00120 public static final String CONFIG_FILE_VALUE = "/config/PaperToolkit.xml";
00121
00122 public static final String CONFIG_PATTERN_PATH_KEY = "tiledpatterngenerator.patternpath";
00123
00124 public static final String CONFIG_PATTERN_PATH_VALUE = "/pattern/";
00125
00126 private static final String HW_REC_KEY = "handwritingRecognition";
00127
00131 private static boolean lookAndFeelInitialized = false;
00132
00136 public static final File PATTERN_PATH = getPatternPath();
00137
00138 private static PaperToolkit toolkitInstance;
00139
00154 private static String versionString = "0.5";
00155
00159 private static XStream xmlEngine;
00160
00164 static {
00165 printInitializationMessages();
00166 }
00167
00174 public static Object fromXML(File xmlFile) {
00175 Object o = null;
00176 try {
00177 o = getXMLEngine().fromXML(new FileInputStream(xmlFile));
00178 } catch (FileNotFoundException e) {
00179 e.printStackTrace();
00180 }
00181 return o;
00182 }
00183
00187 public static File getPatternPath() {
00188 return Configuration.getConfigFile(CONFIG_PATTERN_PATH_KEY);
00189 }
00190
00194 public static File getPenSynchDataPath() {
00195 return new File(getToolkitRootPath(), "penSynch/data/XML/");
00196 }
00197
00204 public static File getResourceFile(String resourcePath) {
00205 try {
00206 File f = new File(PaperToolkit.class.getResource(resourcePath).toURI());
00207 return f;
00208 } catch (URISyntaxException e) {
00209 e.printStackTrace();
00210 }
00211 return null;
00212 }
00213
00221 public static File getToolkitRootPath() {
00222 File file = null;
00223 try {
00224 URL resource = PaperToolkit.class.getResource("/config");
00225 file = new File(resource.toURI()).getParentFile();
00226 } catch (URISyntaxException e) {
00227 e.printStackTrace();
00228 }
00229 if (file == null) {
00230 return null;
00231 } else {
00232 return file.getParentFile();
00233 }
00234 }
00235
00239 private static synchronized XStream getXMLEngine() {
00240 if (xmlEngine == null) {
00241 xmlEngine = new XStream();
00242
00243
00244 xmlEngine.alias("Sheet", Sheet.class);
00245 xmlEngine.alias("Inches", Inches.class);
00246 xmlEngine.alias("Centimeters", Centimeters.class);
00247 xmlEngine.alias("Pixels", Pixels.class);
00248 xmlEngine.alias("Points", Points.class);
00249 xmlEngine.alias("RegionConfiguration", RegionConfiguration.class);
00250 xmlEngine.alias("Region", Region.class);
00251 xmlEngine.alias("Rectangle2DDouble", Rectangle2D.Double.class);
00252 xmlEngine.alias("TiledPatternCoordinateConverter", TiledPatternCoordinateConverter.class);
00253 xmlEngine.alias("RegionID", RegionID.class);
00254 xmlEngine.alias("PenEvent", PenEvent.class);
00255
00256 }
00257 return xmlEngine;
00258 }
00259
00265 public static void initializeLookAndFeel() {
00266 if (!lookAndFeelInitialized) {
00267
00268 try {
00269 final DarkStar theme = new DarkStar();
00270 PlasticLookAndFeel.setPlasticTheme(theme);
00271 UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
00272 } catch (Exception e) {
00273 }
00274 lookAndFeelInitialized = true;
00275 }
00276 }
00277
00281 public static void initializeNativeLookAndFeel() {
00282 if (!lookAndFeelInitialized) {
00283 WindowUtils.setNativeLookAndFeel();
00284 }
00285 lookAndFeelInitialized = true;
00286 }
00287
00293 public static void main(String[] args) {
00294 if (args.length == 0) {
00295
00296
00297 printUsage();
00298 new ToolExplorer();
00299 } else if (args[0].startsWith("-actions")) {
00300 ActionReceiverTrayApp.main(new String[] {});
00301 } else if (args[0].startsWith("-pen")) {
00302 PenServerTrayApp.main(new String[] {});
00303 }
00304 }
00305
00309 private static void printInitializationMessages() {
00310 final String dashes = StringUtils.repeat("-", versionString.length());
00311 System.out.println("-----------------------------------------------------------" + dashes);
00312 System.out.println("Reduce/Reuse/Recycle: A Paper Applications Toolkit ver. " + versionString);
00313 System.out.println("-----------------------------------------------------------" + dashes);
00314 }
00315
00319 private static void printUsage() {
00320 System.out
00321 .println("Without any arguments, we run the PaperToolkit Explorer. You can also run Papertoolkit with one argument: ");
00322 System.out.println(" -actions // runs the action receiver");
00323 System.out.println(" -pen // runs the pen server");
00324 System.out
00325 .println("Thank you for using R3! Feel free to send feedback (good & bad) to ronyeh@cs.stanford.edu.");
00326 }
00327
00333 public static synchronized void runApplication(Application paperApp) {
00334 if (toolkitInstance == null) {
00335 toolkitInstance = new PaperToolkit();
00336 }
00337 toolkitInstance.startApplication(paperApp);
00338 }
00339
00343 public static void startAcrobatDesigner() {
00344 AcrobatDesignerLauncher.start();
00345 }
00346
00351 public static String toXML(Object obj) {
00352 return getXMLEngine().toXML(obj);
00353 }
00354
00359 public static void toXML(Object object, File outputFile) {
00360 try {
00361 FileOutputStream fos = new FileOutputStream(outputFile);
00362 toXML(object, fos);
00363 fos.close();
00364 } catch (FileNotFoundException e) {
00365 e.printStackTrace();
00366 } catch (IOException e) {
00367 e.printStackTrace();
00368 }
00369 }
00370
00376 public static void toXML(Object object, OutputStream stream) {
00377 getXMLEngine().toXML(object, stream);
00378 try {
00379 stream.close();
00380 } catch (IOException e) {
00381 e.printStackTrace();
00382 }
00383 }
00384
00389 public static String toXMLNoLineBreaks(Object o) {
00390 return toXML(o).replace("\n", "");
00391 }
00392
00393 private JTextArea appDetailsPanel;
00394
00395 private JScrollPane appDetailsScrollPane;
00396
00400 private JFrame appManager;
00401
00402 private JPanel appsInspectorPanel;
00403
00407 private BatchServer batchServer;
00408
00409 private JPanel controls;
00410
00411 private JButton designSheetsButton;
00412
00413 private EventBrowser eventBrowser;
00414
00415 private JButton eventBrowserButton;
00416
00421 private EventEngine eventEngine;
00422
00426 private JButton exitAppManagerButton;
00427
00428 private List<ActionListener> listenersToLoadRecentPatternMappings = new ArrayList<ActionListener>();
00429
00433 private JXList listOfApps;
00434
00438 private List<Application> loadedApplications = new ArrayList<Application>();
00439
00444 private final Properties localProperties = new Properties();
00445
00449 private JLabel mainMessage;
00450
00451 private PopupMenu popupMenu;
00452
00456 private JButton printSheetsButton;
00457
00461 private EndlessProgressDialog progress;
00462
00466 private List<Application> runningApplications = new ArrayList<Application>();
00467
00471 private JButton startAppButton;
00472
00476 private JButton stopAppButton;
00477
00478 private TrayIcon trayIcon;
00479
00484 private boolean useAppManager = false;
00485
00489 private boolean useHandwriting;
00490
00496 public PaperToolkit() {
00497 this(false);
00498 }
00499
00503 public PaperToolkit(boolean useAppManager) {
00504 this(true, useAppManager, false );
00505 }
00506
00510 public PaperToolkit(boolean useLookAndFeel, boolean useAppManager, boolean useHandwritingRecognitionServer) {
00511 loadStartupConfiguration();
00512
00513 if (useLookAndFeel) {
00514 initializeLookAndFeel();
00515 }
00516
00517 eventEngine = new EventEngine();
00518 batchServer = new BatchServer(eventEngine);
00519
00520
00521
00522
00523 if (useHandwriting && useHandwritingRecognitionServer) {
00524 HandwritingRecognitionService.getInstance();
00525 }
00526
00527
00528
00529 useApplicationManager(useAppManager);
00530 }
00531
00538 private void checkPatternMapsForUninitializedRegions(
00539 Collection<PatternLocationToSheetLocationMapping> mappings) {
00540
00541 if (trayIcon == null) {
00542 DebugUtils
00543 .println("No need to check for uninitialized pattern maps, as we're not using the system tray.");
00544 return;
00545 }
00546
00547 for (final PatternLocationToSheetLocationMapping map : mappings) {
00548
00549 final MenuItem loadMappingItem = new MenuItem("Load most recent Pattern Mappings");
00550 loadMappingItem.addActionListener(getLoadRecentPatternMappingsActionListener(map));
00551 getTrayPopupMenu().add(loadMappingItem);
00552
00553 Map<Region, PatternCoordinateConverter> regionToPatternMapping = map.getRegionToPatternMapping();
00554
00555 for (final Region r : regionToPatternMapping.keySet()) {
00556 PatternCoordinateConverter patternCoordinateConverter = regionToPatternMapping.get(r);
00557 double area = patternCoordinateConverter.getArea();
00558 DebugUtils.println("Area: " + area);
00559 if (area > 0) {
00560
00561 continue;
00562 }
00563
00564
00565
00566 final MenuItem bindPatternToRegionItem = new MenuItem("Add Pattern Binding For ["
00567 + r.getName() + "]");
00568
00569 bindPatternToRegionItem.addActionListener(new ActionListener() {
00570 @Override
00571 public void actionPerformed(ActionEvent arg0) {
00572 DebugUtils.println("Binding " + r);
00573
00574
00575
00576 eventEngine.addEventHandlerForUnmappedEvents(new StrokeHandler() {
00577 @Override
00578 public void strokeArrived(PenEvent e) {
00579 Rectangle2D bounds = getStroke().getBounds();
00580
00581
00582 final double tlX = bounds.getX();
00583 final double tlY = bounds.getY();
00584 final double width = bounds.getWidth();
00585 final double height = bounds.getHeight();
00586
00587
00588 map.setPatternInformationOfRegion(r,
00589 new PatternDots(tlX), new PatternDots(tlY),
00590 new PatternDots(width), new PatternDots(height));
00591
00592
00593 eventEngine.removeEventHandlerForUnmappedEvents(this);
00594
00595 DebugUtils.println("Bound the region [" + r.getName() + "] to Pattern "
00596 + bounds);
00597 bindPatternToRegionItem.setLabel("Change Binding for " + r.getName()
00598 + ". Currently set to " + bounds);
00599
00600
00601 File destFile = getLastRunPatternInfoFile();
00602 map.saveConfigurationToXML(destFile);
00603 }
00604
00605 });
00606 }
00607 });
00608 getTrayPopupMenu().add(bindPatternToRegionItem);
00609 }
00610 }
00611 }
00612
00616 private Component getAppDetailsPane() {
00617 if (appDetailsScrollPane == null) {
00618 appDetailsScrollPane = new JScrollPane(getAppDetailsTextArea());
00619 }
00620 return appDetailsScrollPane;
00621 }
00622
00626 private JTextArea getAppDetailsTextArea() {
00627 if (appDetailsPanel == null) {
00628 appDetailsPanel = new JTextArea(8, 50 );
00629 appDetailsPanel.setBackground(new Color(240, 240, 240));
00630 appDetailsPanel.setEditable(false);
00631 }
00632 return appDetailsPanel;
00633 }
00634
00640 public JFrame getApplicationManager() {
00641 if (appManager == null) {
00642 appManager = new JFrame("R3 Applications");
00643
00644 appManager.setLayout(new BorderLayout());
00645 appManager.add(getMainMessage(), BorderLayout.NORTH);
00646 appManager.add(getAppsInspectorPanel(), BorderLayout.CENTER);
00647 appManager.add(getExitAppManagerButton(), BorderLayout.SOUTH);
00648 appManager.add(getControls(), BorderLayout.EAST);
00649
00650 appManager.setSize(640, 480);
00651 appManager.setLocation(WindowUtils.getWindowOrigin(appManager, WindowUtils.DESKTOP_CENTER));
00652 appManager.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
00653 appManager.setVisible(true);
00654 }
00655 return appManager;
00656 }
00657
00661 private Component getAppsInspectorPanel() {
00662 if (appsInspectorPanel == null) {
00663 appsInspectorPanel = new JPanel();
00664 appsInspectorPanel.setLayout(new BorderLayout());
00665 appsInspectorPanel.add(getListOfApps(), BorderLayout.CENTER);
00666 appsInspectorPanel.add(getAppDetailsPane(), BorderLayout.SOUTH);
00667 }
00668 return appsInspectorPanel;
00669 }
00670
00674 private Component getControls() {
00675 if (controls == null) {
00676 controls = new JPanel();
00677 controls.setLayout(new StackedLayout(StackedLayout.VERTICAL));
00678 controls.add(getDesignSheetsButton(), "TopWide");
00679 controls.add(getRenderSheetsButton(), "TopWide");
00680 controls.add(Box.createVerticalStrut(10), "TopWide");
00681 controls.add(getStartApplicationButton(), "TopWide");
00682 controls.add(getEventBrowserButton(), "TopWide");
00683 controls.add(getStopApplicationButton(), "TopWide");
00684 }
00685 return controls;
00686 }
00687
00695 private ActionListener getDebugListener(final Application app) {
00696 return new ActionListener() {
00697 @Override
00698 public void actionPerformed(ActionEvent arg0) {
00699 DebuggingEnvironment debuggingEnvironment = app.getDebuggingEnvironment();
00700 if (debuggingEnvironment == null) {
00701 DebugUtils.println("Starting Debugging...");
00702 debuggingEnvironment = new DebuggingEnvironment(app);
00703 app.setDebuggingEnvironment(debuggingEnvironment);
00704 } else {
00705 debuggingEnvironment.showFlashView();
00706 }
00707 }
00708 };
00709 }
00710
00714 private Component getDesignSheetsButton() {
00715 if (designSheetsButton == null) {
00716 designSheetsButton = new JButton("Design Sheets");
00717 designSheetsButton.addActionListener(new ActionListener() {
00718 public void actionPerformed(ActionEvent ae) {
00719 JFrame frame = AcrobatDesignerLauncher.start();
00720 frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
00721 }
00722 });
00723 }
00724 return designSheetsButton;
00725 }
00726
00731 private Component getEventBrowserButton() {
00732 if (eventBrowserButton == null) {
00733 eventBrowserButton = new JButton("View/Replay Events");
00734 eventBrowserButton.addActionListener(new ActionListener() {
00735 public void actionPerformed(ActionEvent ae) {
00736 if (eventBrowser == null) {
00737 eventBrowser = new EventBrowser(eventEngine.getEventReplayManager());
00738 }
00739 eventBrowser.setVisible(true);
00740 }
00741 });
00742 }
00743 return eventBrowserButton;
00744 }
00745
00751 public EventEngine getEventEngine() {
00752 return eventEngine;
00753 }
00754
00758 private Component getExitAppManagerButton() {
00759
00760 if (exitAppManagerButton == null) {
00761 exitAppManagerButton = new JButton("Exit App Manager");
00762 exitAppManagerButton.addActionListener(new ActionListener() {
00763 public void actionPerformed(ActionEvent ae) {
00764 System.out.println("Stopping all Applications...");
00765 Object[] objects = runningApplications.toArray();
00766 for (Object o : objects) {
00767 stopApplication((Application) o);
00768 }
00769 System.out.println("Exiting the Paper Toolkit Application Manager...");
00770 System.exit(0);
00771 }
00772 });
00773 }
00774 return exitAppManagerButton;
00775 }
00776
00777 private ActionListener getExitListener() {
00778 return new ActionListener() {
00779 public void actionPerformed(ActionEvent ae) {
00780 System.out.println("Exiting the Paper Toolkit...");
00781 if (trayIcon != null) {
00782 TrayIcon iconToRemove = trayIcon;
00783 trayIcon = null;
00784 SystemTray.getSystemTray().remove(iconToRemove);
00785 }
00786 System.exit(0);
00787 }
00788 };
00789 }
00790
00794 private File getFolderToSavePDFs() {
00795 return FileUtils.showDirectoryChooser(appManager, "Choose a Directory for your PDFs");
00796 }
00797
00801 private File getLastRunPatternInfoFile() {
00802 File homeDir = FileSystemView.getFileSystemView().getHomeDirectory();
00803 File destFile = new File(homeDir, "PaperToolkitLastRun.patternInfo.xml");
00804 return destFile;
00805 }
00806
00810 private JXList getListOfApps() {
00811 if (listOfApps == null) {
00812 listOfApps = new JXList();
00813 listOfApps.addListSelectionListener(new ListSelectionListener() {
00814 public void valueChanged(ListSelectionEvent event) {
00815 Application selectedApp = (Application) listOfApps.getSelectedValue();
00816 if (selectedApp != null) {
00817
00818 final List<Sheet> thisAppsSheets = selectedApp.getSheets();
00819 StringBuilder sb = new StringBuilder();
00820 for (Sheet s : thisAppsSheets) {
00821
00822 sb.append(s.toDetailedString());
00823 }
00824 getAppDetailsTextArea().setText(sb.toString());
00825 }
00826 }
00827 });
00828
00829 listOfApps.addHighlighter(new ConditionalHighlighter(Color.WHITE, Color.LIGHT_GRAY, 0, -1) {
00830 @Override
00831 protected boolean test(ComponentAdapter c) {
00832 if (c.getValue() instanceof Application) {
00833 Application app = (Application) c.getValue();
00834 if (!runningApplications.contains(app)) {
00835 return true;
00836 }
00837 }
00838 return false;
00839 }
00840 });
00841 listOfApps.setCellRenderer(new DefaultListCellRenderer() {
00842 public Component getListCellRendererComponent(JList list, Object value, int index,
00843 boolean isSelected, boolean cellHasFocus) {
00844 String appDescription = value.toString();
00845 if (value instanceof Application) {
00846 Application app = (Application) value;
00847 if (runningApplications.contains(app)) {
00848 appDescription = appDescription + " [running]";
00849 } else {
00850 appDescription = appDescription + " [stopped]";
00851 }
00852 }
00853 return super.getListCellRendererComponent(list, appDescription, index, isSelected,
00854 cellHasFocus);
00855 }
00856 });
00857 listOfApps.setBorder(BorderFactory.createEmptyBorder(20, 5, 20, 5));
00858 listOfApps.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
00859 listOfApps.setFont(APP_MANAGER_FONT);
00860 updateListOfApps();
00861 }
00862 return listOfApps;
00863 }
00864
00869 private ActionListener getLoadRecentPatternMappingsActionListener(
00870 final PatternLocationToSheetLocationMapping map) {
00871
00872 ActionListener actionListener = new ActionListener() {
00873 @Override
00874 public void actionPerformed(ActionEvent nullActionEvent) {
00875 map.loadConfigurationFromXML(getLastRunPatternInfoFile());
00876 }
00877 };
00878 listenersToLoadRecentPatternMappings.add(actionListener);
00879
00880 return actionListener;
00881 }
00882
00886 private Component getMainMessage() {
00887 if (mainMessage == null) {
00888 mainMessage = new JLabel("<html>Manage your applications here.<br/>"
00889 + "Closing this App Manager will stop <b>all</b> running applications.</html>");
00890 mainMessage.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
00891 mainMessage.setFont(APP_MANAGER_FONT);
00892 }
00893 return mainMessage;
00894 }
00895
00896 private ListModel getModel() {
00897 final ListModel model = new AbstractListModel() {
00898 public Object getElementAt(int appIndex) {
00899 return loadedApplications.get(appIndex);
00900 }
00901
00902 public int getSize() {
00903 return loadedApplications.size();
00904 }
00905 };
00906 return model;
00907 }
00908
00909 public String getProperty(String propertyKey) {
00910 return localProperties.getProperty(propertyKey);
00911 }
00912
00917 private ActionListener getRenderListener(final Application app) {
00918 return new ActionListener() {
00919 @Override
00920 public void actionPerformed(ActionEvent arg0) {
00921 app.renderToPDF();
00922 }
00923 };
00924 }
00925
00929 private Component getRenderSheetsButton() {
00930 if (printSheetsButton == null) {
00931 printSheetsButton = new JButton("Make PDFs", new ImageIcon(PaperToolkit.class
00932 .getResource("/icons/pdfIcon32x32.png")));
00933 printSheetsButton.addActionListener(new ActionListener() {
00934 public void actionPerformed(ActionEvent arg0) {
00935 final Application selectedApp = (Application) listOfApps.getSelectedValue();
00936 if (selectedApp != null) {
00937 if (selectedApp.isUserChoosingDestinationForPDF()) {
00938 renderToSpecificFolder(selectedApp);
00939 } else {
00940 selectedApp.renderToPDF();
00941 }
00942 listOfApps.repaint();
00943 }
00944 }
00945
00946 });
00947 }
00948 return printSheetsButton;
00949 }
00950
00954 private Component getStartApplicationButton() {
00955 if (startAppButton == null) {
00956 startAppButton = new JButton("Start Selected Application");
00957 startAppButton.addActionListener(new ActionListener() {
00958 public void actionPerformed(ActionEvent ae) {
00959 Application selectedApp = (Application) listOfApps.getSelectedValue();
00960 if (selectedApp != null) {
00961 startApplication(selectedApp);
00962 listOfApps.repaint();
00963 }
00964 }
00965 });
00966 }
00967 return startAppButton;
00968 }
00969
00973 private Component getStopApplicationButton() {
00974 if (stopAppButton == null) {
00975 stopAppButton = new JButton("Stop Selected Application");
00976 stopAppButton.addActionListener(new ActionListener() {
00977 public void actionPerformed(ActionEvent ae) {
00978 Application selectedApp = (Application) listOfApps.getSelectedValue();
00979 if (selectedApp != null) {
00980 stopApplication(selectedApp);
00981 listOfApps.repaint();
00982 }
00983 }
00984 });
00985 }
00986 return stopAppButton;
00987 }
00988
00992 private void getSystemTrayIcon() {
00993 if (trayIcon == null) {
00994
00995 trayIcon = new TrayIcon(ImageCache.loadBufferedImage(PaperToolkit.class
00996 .getResource("/icons/glue.png")), "Paper Toolkit", getTrayPopupMenu());
00997 trayIcon.setImageAutoSize(true);
00998 try {
00999 if (SystemTray.isSupported()) {
01000 SystemTray.getSystemTray().add(trayIcon);
01001
01002 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
01003 @Override
01004 public void run() {
01005 DebugUtils.println("Running Shutdown Services...");
01006
01007
01008
01009
01010 DebugUtils.println("Done with Shutdown!");
01011 }
01012 }));
01013 }
01014 } catch (AWTException e) {
01015 e.printStackTrace();
01016 }
01017 }
01018 }
01019
01023 private PopupMenu getTrayPopupMenu() {
01024 if (popupMenu == null) {
01025 popupMenu = new PopupMenu("Paper Toolkit Options");
01026
01027
01028 final MenuItem exitItem = new MenuItem("Exit");
01029 exitItem.addActionListener(getExitListener());
01030
01031 popupMenu.add(exitItem);
01032 }
01033
01034 return popupMenu;
01035 }
01036
01042 public void loadApplication(Application app) {
01043 DebugUtils.println("Loading " + app.getName());
01044 loadedApplications.add(app);
01045
01046 if (useAppManager) {
01047 DebugUtils.println("Using the Application Manager. We will hide the System Tray Icon.");
01048 getApplicationManager();
01049 updateListOfApps();
01050 } else {
01051 DebugUtils
01052 .println("Not using the Application Manager. "
01053 + "If you would like to use the GUI launcher, "
01054 + "call PaperToolkit.useAppManager(true)");
01055 DebugUtils.println("We will use the System Tray icon instead.");
01056 getSystemTrayIcon();
01057
01058 popupMenu.add(new MenuItem("-"));
01059 final MenuItem debugItem = new MenuItem("Debug [" + app.getName() + "]");
01060 debugItem.addActionListener(getDebugListener(app));
01061
01062 final MenuItem renderItem = new MenuItem("Render Sheets for [" + app.getName() + "]");
01063 renderItem.addActionListener(getRenderListener(app));
01064
01065 getTrayPopupMenu().add(debugItem);
01066 getTrayPopupMenu().add(renderItem);
01067
01068 for (final Sheet s : app.getSheets()) {
01069 MenuItem item = new MenuItem("Open JFrame for sheet [" + s.getName() + "]");
01070 item.addActionListener(new ActionListener() {
01071 public void actionPerformed(ActionEvent e) {
01072 SheetFrame sf = new SheetFrame(s, 640, 480);
01073 sf.setVisible(true);
01074 }
01075 });
01076 getTrayPopupMenu().add(item);
01077 }
01078 }
01079 }
01080
01081 public void loadMostRecentPatternMappings() {
01082 DebugUtils.println("Loading most recent Pattern Mappings...");
01083 for (ActionListener l : listenersToLoadRecentPatternMappings) {
01084 l.actionPerformed(null);
01085 }
01086 }
01087
01091 private void loadStartupConfiguration() {
01092 final Properties props = Configuration.getPropertiesFromConfigFile(CONFIG_FILE_KEY);
01093 useHandwriting = Boolean.parseBoolean(props.getProperty(HW_REC_KEY));
01094
01095
01096
01097
01098
01099 File localPropsFile = new File("PaperToolkit.xml");
01100 if (localPropsFile.exists()) {
01101 DebugUtils.println("Local Properties File Exists. Overriding Properties: ");
01102 try {
01103 localProperties.loadFromXML(new FileInputStream(localPropsFile));
01104 } catch (InvalidPropertiesFormatException e) {
01105 e.printStackTrace();
01106 } catch (FileNotFoundException e) {
01107 e.printStackTrace();
01108 } catch (IOException e) {
01109 e.printStackTrace();
01110 }
01111 if (localProperties.containsKey(HW_REC_KEY)) {
01112 String newProp = localProperties.getProperty(HW_REC_KEY);
01113 DebugUtils
01114 .println(HW_REC_KEY + " was: [" + useHandwriting + "] and is now [" + newProp + "]");
01115 useHandwriting = Boolean.parseBoolean(newProp);
01116 }
01117 } else {
01118 DebugUtils.println("Local Properties File Does Not Exist");
01119 }
01120 }
01121
01127 public void print(Sheet sheet) {
01128
01129 DebugUtils.println("Unimplemented Method");
01130 }
01131
01135 private void renderToSpecificFolder(final Application selectedApp) {
01136 new Thread(new Runnable() {
01137 public void run() {
01138 final File folderToSavePDFs = getFolderToSavePDFs();
01139 if (folderToSavePDFs != null) {
01140
01141 progress = new EndlessProgressDialog(appManager, "Creating the PDF",
01142 "Please wait while your PDF is generated.");
01143
01144 selectedApp.renderToPDF(folderToSavePDFs, selectedApp.getName());
01145 DebugUtils.println("Done Rendering.");
01146
01147
01148 try {
01149 Desktop.getDesktop().open(folderToSavePDFs);
01150 } catch (IOException e) {
01151 e.printStackTrace();
01152 }
01153
01154 progress.setVisible(false);
01155 progress = null;
01156 }
01157 }
01158 }).start();
01159 }
01160
01167 public void startApplication(Application paperApp) {
01168 if (!loadedApplications.contains(paperApp)) {
01169 loadApplication(paperApp);
01170 }
01171
01172
01173 paperApp.initializeBeforeStarting();
01174
01175
01176
01177
01178 if (paperApp.getPenInputDevices().size() == 0) {
01179 DebugUtils.println(paperApp.getName()
01180 + " does not have any pens! We will add a single streaming pen for you.");
01181 final Pen aPen = new Pen();
01182 paperApp.addPenInput(aPen);
01183 }
01184
01185 final List<PenInput> pens = paperApp.getPenInputDevices();
01186
01187 for (PenInput pen : pens) {
01188 pen.startLiveMode();
01189 if (pen.isLive()) {
01190 eventEngine.register(pen);
01191 }
01192 }
01193
01194
01195 final Collection<PatternLocationToSheetLocationMapping> patternMappings = paperApp.getPatternMaps();
01196 eventEngine.registerPatternMapsForEventHandling(patternMappings);
01197 batchServer.registerBatchEventHandlers(paperApp.getBatchEventHandlers());
01198
01199
01200 checkPatternMapsForUninitializedRegions(patternMappings);
01201
01202
01203
01204
01205
01206
01207
01208
01209 DebugUtils.println("Starting Application: " + paperApp.getName());
01210 runningApplications.add(paperApp);
01211 getListOfApps().repaint();
01212
01213
01214 paperApp.setHostToolkit(this);
01215 }
01216
01222 public void stopApplication(Application paperApp) {
01223 final List<PenInput> pens = paperApp.getPenInputDevices();
01224 for (PenInput pen : pens) {
01225 if (pen.isLive()) {
01226 eventEngine.unregisterPen(pen);
01227
01228 pen.stopLiveMode();
01229 }
01230 }
01231
01232 eventEngine.unregisterPatternMapsForEventHandling(paperApp.getPatternMaps());
01233 batchServer.unregisterBatchEventHandlers(paperApp.getBatchEventHandlers());
01234
01235 DebugUtils.println("Stopping Application: " + paperApp.getName());
01236 runningApplications.remove(paperApp);
01237 getListOfApps().repaint();
01238
01239 paperApp.setHostToolkit(null);
01240 }
01241
01245 public void unloadApplication(Application app) {
01246 loadedApplications.remove(app);
01247 }
01248
01252 private void updateListOfApps() {
01253 listOfApps.setModel(getModel());
01254 if (getModel().getSize() > 0) {
01255 listOfApps.setSelectedIndex(0);
01256 }
01257 }
01258
01263 public void useApplicationManager(boolean flag) {
01264 useAppManager = flag;
01265 }
01266 }