PaperToolkit.java

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                         // Add Aliases Here (for more concise XML)
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                         // JGoodies Look and Feel
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                         // the 0 args branch will run the Paper Toolkit GUI, which helps designers learn what you
00296                         // can do with this toolkit. It integrates with the documentation and stuff too!
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 /* no handwriting */);
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                 // Start the local server up whenever the paper toolkit is initialized.
00521                 // the either flag can override the other. They will both need to be TRUE to actually load
00522                 // it.
00523                 if (useHandwriting && useHandwritingRecognitionServer) {
00524                         HandwritingRecognitionService.getInstance();
00525                 }
00526 
00527                 // whether or not to show the app manager GUI when an application is loaded
00528                 // the idea is that one can load multiple applications (TODO)!
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                                         // this region has a real mapping! NEXT!
00561                                         continue;
00562                                 }
00563 
00564                                 // the menu item for invoking the runtime binding
00565                                 // We need to update the text later...
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                                                 // Runtime Pattern to Region Binding
00575                                                 // adds a listener for trashed events in the Event Engine
00576                                                 eventEngine.addEventHandlerForUnmappedEvents(new StrokeHandler() {
00577                                                         @Override
00578                                                         public void strokeArrived(PenEvent e) {
00579                                                                 Rectangle2D bounds = getStroke().getBounds();
00580                                                                 // determine the bounds of the region in pattern space
00581                                                                 // this information was provided by the user
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                                                                 // tie the pattern bounds to this region object
00588                                                                 map.setPatternInformationOfRegion(r, //
00589                                                                                 new PatternDots(tlX), new PatternDots(tlY), // 
00590                                                                                 new PatternDots(width), new PatternDots(height));
00591 
00592                                                                 // unregister myself...
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                                                                 // additionally... write this out to a file on the desktop
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 /* cols */);
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                 // stop all apps and then exit the application manager
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                                                 // show a list of sheets
00818                                                 final List<Sheet> thisAppsSheets = selectedApp.getSheets();
00819                                                 StringBuilder sb = new StringBuilder();
00820                                                 for (Sheet s : thisAppsSheets) {
00821                                                         // use the longer, more descriptive string
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)) { // loaded, but not running
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)) { // loaded, but not running
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                 // add it to the list, so we can invoke them later!
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                         // this is the icon that sits in our tray...
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                                                         // Buggy for some reason... Can stop the shutdown =\
01007                                                         // if (trayIcon != null) {
01008                                                         // SystemTray.getSystemTray().remove(trayIcon);
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                         // exit the application
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                 // show the app manager
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("-")); // separator
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                 // also check for a custom PaperToolkit.xml in the run directory of the application
01096                 // properties in that file will override the ones we just loaded from the default location
01097                 // alternatively, you can just edit the default PaperToolkit.xml, located in
01098                 // data/config/PaperToolkit.xml
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                 // Implement this...
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) { // user approved
01140                                         // an endless progress bar
01141                                         progress = new EndlessProgressDialog(appManager, "Creating the PDF",
01142                                                         "Please wait while your PDF is generated.");
01143                                         // start rendering
01144                                         selectedApp.renderToPDF(folderToSavePDFs, selectedApp.getName());
01145                                         DebugUtils.println("Done Rendering.");
01146 
01147                                         // open the folder in explorer! =)
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                 // run any initializers that need to happen before we begin
01173                 paperApp.initializeBeforeStarting();
01174 
01175                 // get all the pens and start them in live mode...
01176                 // we assume we have decided where each pen server will run
01177                 // start live mode will connect to that pen server.
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                 // add all the live pens to the eventEngine
01187                 for (PenInput pen : pens) {
01188                         pen.startLiveMode(); // starts live mode at the pen's default place
01189                         if (pen.isLive()) {
01190                                 eventEngine.register(pen);
01191                         }
01192                 }
01193 
01194                 // keep track of the pattern assigned to different sheets and regions
01195                 final Collection<PatternLocationToSheetLocationMapping> patternMappings = paperApp.getPatternMaps();
01196                 eventEngine.registerPatternMapsForEventHandling(patternMappings);
01197                 batchServer.registerBatchEventHandlers(paperApp.getBatchEventHandlers());
01198 
01199                 // will populate the system tray with a feature for runtime binding of regions... =)
01200                 checkPatternMapsForUninitializedRegions(patternMappings);
01201 
01202                 // XXX
01203                 // Here, we should pass the event engine over...
01204                 // When the Batch Server gets in the data, it will translate it to streaming event
01205                 // coordinates
01206                 // And then pass it to the Event Engine
01207                 // It will essentially "replay" the events as if it were through event save/replay
01208 
01209                 DebugUtils.println("Starting Application: " + paperApp.getName());
01210                 runningApplications.add(paperApp);
01211                 getListOfApps().repaint();
01212 
01213                 // provides access back to the toolkit object
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                                 // stop the pen from listening!
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 }

Generated on Sat Apr 14 18:21:36 2007 for R3 Paper Toolkit by  doxygen 1.4.7