diff --git a/app/lib/apple.jar b/app/lib/apple.jar index d1aa7851d..6659a81c6 100644 Binary files a/app/lib/apple.jar and b/app/lib/apple.jar differ diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index dabffc585..82eace575 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -22,6 +22,7 @@ package processing.app; +import cc.arduino.contributions.DownloadableContributionVersionComparator; import cc.arduino.contributions.VersionHelper; import cc.arduino.contributions.libraries.ContributedLibrary; import cc.arduino.contributions.libraries.LibrariesIndexer; @@ -30,7 +31,6 @@ import cc.arduino.contributions.libraries.ui.LibraryManagerUI; import cc.arduino.contributions.packages.ContributedPlatform; import cc.arduino.contributions.packages.ContributionInstaller; import cc.arduino.contributions.packages.ContributionsIndexer; -import cc.arduino.contributions.DownloadableContributionVersionComparator; import cc.arduino.contributions.packages.ui.ContributionManagerUI; import cc.arduino.files.DeleteFilesOnShutdown; import cc.arduino.packages.DiscoveryManager; @@ -79,7 +79,9 @@ public class Base { } }; - static private boolean commandLine; + private static boolean commandLine; + public static volatile Base INSTANCE; + public static SplashScreenHelper splashScreenHelper = new SplashScreenHelper(SplashScreen.getSplashScreen()); // A single instance of the preferences window @@ -104,7 +106,7 @@ public class Base { // p5 icon for the window // static Image icon; -// int editorCount; + // int editorCount; List editors = Collections.synchronizedList(new ArrayList()); Editor activeEditor; @@ -119,6 +121,10 @@ public class Base { splashScreenHelper.splashText(_("Loading configuration...")); + if (OSUtils.isMacOS()) { + ThinkDifferent.init(); + } + try { guardedMain(args); } catch (Throwable e) { @@ -126,12 +132,12 @@ public class Base { System.exit(255); } } - + static public void guardedMain(String args[]) throws Exception { Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE)); BaseNoGui.initLogger(); - + BaseNoGui.notifier = new GUIUserNotifier(); initPlatform(); @@ -207,7 +213,7 @@ public class Base { untitledFolder = createTempFolder("untitled"); DeleteFilesOnShutdown.add(untitledFolder); - new Base(args); + INSTANCE = new Base(args); } @@ -231,9 +237,9 @@ public class Base { Class.forName("com.sun.jdi.VirtualMachine"); } catch (ClassNotFoundException cnfe) { showError(_("Please install JDK 1.5 or later"), - _("Arduino requires a full JDK (not just a JRE)\n" + - "to run. Please install JDK 1.5 or later.\n" + - "More information can be found in the reference."), cnfe); + _("Arduino requires a full JDK (not just a JRE)\n" + + "to run. Please install JDK 1.5 or later.\n" + + "More information can be found in the reference."), cnfe); } } @@ -247,8 +253,6 @@ public class Base { public Base(String[] args) throws Exception { getPlatform().init(); - if (OSUtils.isMacOS()) - ThinkDifferent.init(this); String sketchbookPath = BaseNoGui.getSketchbookPath(); @@ -268,13 +272,13 @@ public class Base { BaseNoGui.initPackages(); splashScreenHelper.splashText(_("Preparing boards...")); rebuildBoardsMenu(); - + // Setup board-dependent variables. onBoardOrPortChange(); CommandlineParser parser = CommandlineParser.newCommandlineParser(args); - for (String path: parser.getFilenames()) { + for (String path : parser.getFilenames()) { // Correctly resolve relative paths File file = absoluteFile(path); @@ -312,6 +316,7 @@ public class Base { ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder()); ContributionInstaller installer = new ContributionInstaller(indexer) { private String lastStatus = ""; + @Override protected void onProgress(Progress progress) { if (!lastStatus.equals(progress.getStatus())) { @@ -357,6 +362,7 @@ public class Base { LibrariesIndexer indexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder()); LibraryInstaller installer = new LibraryInstaller(indexer) { private String lastStatus = ""; + @Override protected void onProgress(Progress progress) { if (!lastStatus.equals(progress.getStatus())) { @@ -374,7 +380,7 @@ public class Base { for (String library : parser.getLibraryToInstall().split(",")) { String[] libraryToInstallParts = library.split(":"); - ContributedLibrary selected=null; + ContributedLibrary selected = null; if (libraryToInstallParts.length == 2) { selected = indexer.getIndex().find(libraryToInstallParts[0], VersionHelper.valueOf(libraryToInstallParts[1]).toString()); } else if (libraryToInstallParts.length == 1) { @@ -400,63 +406,60 @@ public class Base { System.exit(0); } else if (parser.isVerifyOrUploadMode()) { - splashScreenHelper.close(); - // Set verbosity for command line build - Preferences.set("build.verbose", "" + parser.isDoVerboseBuild()); - Preferences.set("upload.verbose", "" + parser.isDoVerboseUpload()); - Preferences.set("runtime.preserve.temp.files", Boolean.toString(parser.isPreserveTempFiles())); + splashScreenHelper.close(); + // Set verbosity for command line build + Preferences.set("build.verbose", "" + parser.isDoVerboseBuild()); + Preferences.set("upload.verbose", "" + parser.isDoVerboseUpload()); + Preferences.set("runtime.preserve.temp.files", Boolean.toString(parser.isPreserveTempFiles())); - // Make sure these verbosity preferences are only for the - // current session - Preferences.setDoSave(false); + // Make sure these verbosity preferences are only for the + // current session + Preferences.setDoSave(false); - Editor editor = editors.get(0); + Editor editor = editors.get(0); - if (parser.isUploadMode()) { - splashScreenHelper.splashText(_("Verifying and uploading...")); - editor.exportHandler.run(); - } else { - splashScreenHelper.splashText(_("Verifying...")); - editor.runHandler.run(); - } + if (parser.isUploadMode()) { + splashScreenHelper.splashText(_("Verifying and uploading...")); + editor.exportHandler.run(); + } else { + splashScreenHelper.splashText(_("Verifying...")); + editor.runHandler.run(); + } - // Error during build or upload - int res = editor.status.mode; - if (res == EditorStatus.ERR) - System.exit(1); + // Error during build or upload + int res = editor.status.mode; + if (res == EditorStatus.ERR) + System.exit(1); - // No errors exit gracefully + // No errors exit gracefully + System.exit(0); + } else if (parser.isGuiMode()) { + splashScreenHelper.splashText(_("Starting...")); + + // Check if there were previously opened sketches to be restored + restoreSketches(); + + // Create a new empty window (will be replaced with any files to be opened) + if (editors.isEmpty()) { + handleNew(); + } + + // Check for updates + if (Preferences.getBoolean("update.check")) { + new UpdateCheck(this); + } + } else if (parser.isNoOpMode()) { + // Do nothing (intended for only changing preferences) + System.exit(0); + } else if (parser.isGetPrefMode()) { + String value = Preferences.get(parser.getGetPref(), null); + if (value != null) { + System.out.println(value); System.exit(0); + } else { + System.exit(4); } - else if (parser.isGuiMode()) { - splashScreenHelper.splashText(_("Starting...")); - - // Check if there were previously opened sketches to be restored - restoreSketches(); - - // Create a new empty window (will be replaced with any files to be opened) - if (editors.isEmpty()) { - handleNew(); - } - - // Check for updates - if (Preferences.getBoolean("update.check")) { - new UpdateCheck(this); - } - } - else if (parser.isNoOpMode()) { - // Do nothing (intended for only changing preferences) - System.exit(0); - } - else if (parser.isGetPrefMode()) { - String value = Preferences.get(parser.getGetPref(), null); - if (value != null) { - System.out.println(value); - System.exit(0); - } else { - System.exit(4); - } - } + } } /** @@ -464,7 +467,8 @@ public class Base { * sketch that was used (if any), and restores other Editor settings. * The complement to "storePreferences", this is called when the * application is first launched. - * @throws Exception + * + * @throws Exception */ protected boolean restoreSketches() throws Exception { // figure out window placement @@ -544,7 +548,7 @@ public class Base { // In case of a crash, save untitled sketches if they contain changes. // (Added this for release 0158, may not be a good idea.) if (path.startsWith(untitledPath) && - !editor.getSketch().isModified()) { + !editor.getSketch().isModified()) { continue; } if (BaseNoGui.getPortableFolder() != null) { @@ -570,8 +574,7 @@ public class Base { String untitledPath = untitledFolder.getAbsolutePath(); if (path.startsWith(untitledPath)) { path = ""; - } else - if (BaseNoGui.getPortableFolder() != null) { + } else if (BaseNoGui.getPortableFolder() != null) { path = FileUtils.relativePath(BaseNoGui.getPortableFolder().toString(), path); if (path == null) path = ""; @@ -621,10 +624,10 @@ public class Base { if (activeEditor == null) { Rectangle screen = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds(); // If no current active editor, use default placement - return new int[] { - (screen.width - defaultWidth) / 2, - (screen.height - defaultHeight) / 2, - defaultWidth, defaultHeight, 0 + return new int[]{ + (screen.width - defaultWidth) / 2, + (screen.height - defaultHeight) / 2, + defaultWidth, defaultHeight, 0 }; } else { @@ -643,14 +646,14 @@ public class Base { location[1] += OVER; if (location[0] == OVER || - location[2] == OVER || - location[0] + location[2] > screen.width || - location[1] + location[3] > screen.height) { + location[2] == OVER || + location[0] + location[2] > screen.width || + location[1] + location[3] > screen.height) { // Warp the next window to a randomish location on screen. - return new int[] { - (int) (Math.random() * (screen.width - defaultWidth)), - (int) (Math.random() * (screen.height - defaultHeight)), - defaultWidth, defaultHeight, 0 + return new int[]{ + (int) (Math.random() * (screen.width - defaultWidth)), + (int) (Math.random() * (screen.height - defaultHeight)), + defaultWidth, defaultHeight, 0 }; } @@ -665,14 +668,15 @@ public class Base { boolean breakTime = false; String[] months = { - "jan", "feb", "mar", "apr", "may", "jun", - "jul", "aug", "sep", "oct", "nov", "dec" + "jan", "feb", "mar", "apr", "may", "jun", + "jul", "aug", "sep", "oct", "nov", "dec" }; /** * Handle creating a sketch folder, return its base .pde file * or null if the operation was canceled. - * @param shift whether shift is pressed, which will invert prompt setting + * + * @param shift whether shift is pressed, which will invert prompt setting * @param noPrompt disable prompt, no matter the setting */ protected File createNewUntitled() throws IOException { @@ -698,12 +702,12 @@ public class Base { // In 0159, avoid running past z by sending people outdoors. if (!breakTime) { showWarning(_("Time for a Break"), - _("You've reached the limit for auto naming of new sketches\n" + - "for the day. How about going for a walk instead?"), null); + _("You've reached the limit for auto naming of new sketches\n" + + "for the day. How about going for a walk instead?"), null); breakTime = true; } else { showWarning(_("Sunshine"), - _("No really, time for some fresh air for you."), null); + _("No really, time for some fresh air for you."), null); } return null; } @@ -728,7 +732,8 @@ public class Base { /** * Create a new untitled document in a new sketch window. - * @throws Exception + * + * @throws Exception */ public void handleNew() throws Exception { try { @@ -779,9 +784,11 @@ public class Base { /** * Open a sketch, replacing the sketch in the current window. + * * @param path Location of the primary pde file for the sketch. */ public void handleOpenReplace(File file) { + System.out.println("handleOpenReplace"); if (!activeEditor.checkModified()) { return; // sketch was modified, and user canceled } @@ -798,7 +805,8 @@ public class Base { /** * Prompt for a sketch to open, and open it in a new window. - * @throws Exception + * + * @throws Exception */ public void handleOpenPrompt() throws Exception { // get the frontmost window frame for placing file dialog @@ -834,10 +842,11 @@ public class Base { /** * Open a sketch in a new window. + * * @param file File to open * @return the Editor object, so that properties (like 'untitled') - * can be set by the caller - * @throws Exception + * can be set by the caller + * @throws Exception */ public Editor handleOpen(File file) throws Exception { return handleOpen(file, nextEditorLocation(), true); @@ -923,6 +932,7 @@ public class Base { /** * Close a sketch as specified by its editor window. + * * @param editor Editor object of the sketch to be closed. * @return true if succeeded in closing, false if canceled. */ @@ -942,26 +952,26 @@ public class Base { // if (Preferences.getBoolean("sketchbook.closing_last_window_quits") || // (editor.untitled && !editor.getSketch().isModified())) { if (OSUtils.isMacOS()) { - Object[] options = { "OK", "Cancel" }; + Object[] options = {"OK", "Cancel"}; String prompt = - _(" " + - " " + - "Are you sure you want to Quit?" + - "

Closing the last open sketch will quit Arduino."); + _(" " + + " " + + "Are you sure you want to Quit?" + + "

Closing the last open sketch will quit Arduino."); int result = JOptionPane.showOptionDialog(editor, - prompt, - _("Quit"), - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE, - null, - options, - options[0]); + prompt, + _("Quit"), + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[0]); if (result == JOptionPane.NO_OPTION || - result == JOptionPane.CLOSED_OPTION) { + result == JOptionPane.CLOSED_OPTION) { return false; } } @@ -1004,9 +1014,11 @@ public class Base { /** * Handler for File → Quit. + * * @return false if canceled, true otherwise. */ public boolean handleQuit() { + System.out.println("handleQuit"); // If quit is canceled, this will be replaced anyway // by a later handleQuit() that is not canceled. storeSketches(); @@ -1037,6 +1049,7 @@ public class Base { /** * Attempt to close each open sketch in preparation for quitting. + * * @return false if canceled along the way */ protected boolean handleQuitEach() { @@ -1084,14 +1097,14 @@ public class Base { // Add the single "Open" item item = Editor.newJMenuItem(_("Open..."), 'O'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - try { - handleOpenPrompt(); - } catch (Exception e1) { - e1.printStackTrace(); - } + public void actionPerformed(ActionEvent e) { + try { + handleOpenPrompt(); + } catch (Exception e1) { + e1.printStackTrace(); } - }); + } + }); menu.add(item); menu.addSeparator(); @@ -1117,7 +1130,7 @@ public class Base { //System.out.println("rebuilding sketchbook menu"); //new Exception().printStackTrace(); try { - menu.removeAll(); + menu.removeAll(); addSketches(menu, getSketchbookFolder(), false); //addSketches(menu, getSketchbookFolder()); } catch (IOException e) { @@ -1165,7 +1178,7 @@ public class Base { // Split between user supplied libraries and IDE libraries TargetPlatform targetPlatform = getTargetPlatform(); - + if (targetPlatform != null) { LibraryList ideLibs = getIDELibs(); LibraryList userLibs = getUserLibs(); @@ -1215,7 +1228,7 @@ public class Base { addSketchesSubmenu(menu, lib, false); LibraryList userLibs = getUserLibs(); - if (userLibs.size()>0) { + if (userLibs.size() > 0) { menu.addSeparator(); userLibs.sort(); for (UserLibrary lib : userLibs) @@ -1249,7 +1262,7 @@ public class Base { managerUI.setIndexer(BaseNoGui.librariesIndexer); managerUI.setVisible(true); // Manager dialog is modal, waits here until closed - + //handleAddLibrary(); onBoardOrPortChange(); rebuildImportMenu(Editor.importMenu); @@ -1302,7 +1315,7 @@ public class Base { // If there are no platforms installed we are done if (BaseNoGui.packages.size() == 0) return; - + // Separate "Install boards..." command from installed boards boardMenu.add(new JSeparator()); @@ -1346,8 +1359,8 @@ public class Base { // Cycle through all boards of this platform for (TargetBoard board : targetPlatform.getBoards().values()) { JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, menuItemsToClickAfterStartup, - buttonGroupsMap, - board, targetPlatform, targetPackage); + buttonGroupsMap, + board, targetPlatform, targetPackage); boardMenu.add(item); boardsButtonGroup.add(item); } @@ -1368,7 +1381,7 @@ public class Base { final List boardsCustomMenus, List menuItemsToClickAfterStartup, Map buttonGroupsMap, TargetBoard board, TargetPlatform targetPlatform, TargetPackage targetPackage) - throws Exception { + throws Exception { String selPackage = Preferences.get("target_package"); String selPlatform = Preferences.get("target_platform"); String selBoard = Preferences.get("board"); @@ -1376,13 +1389,13 @@ public class Base { String boardId = board.getId(); String packageName = targetPackage.getId(); String platformName = targetPlatform.getId(); - + // Setup a menu item for the current board @SuppressWarnings("serial") Action action = new AbstractAction(board.getName()) { public void actionPerformed(ActionEvent actionevent) { - selectBoard((TargetBoard)getValue("b")); - filterVisibilityOfSubsequentBoardMenus(boardsCustomMenus, (TargetBoard)getValue("b"), 1); + selectBoard((TargetBoard) getValue("b")); + filterVisibilityOfSubsequentBoardMenus(boardsCustomMenus, (TargetBoard) getValue("b"), 1); onBoardOrPortChange(); rebuildImportMenu(Editor.importMenu); @@ -1394,7 +1407,7 @@ public class Base { JRadioButtonMenuItem item = new JRadioButtonMenuItem(action); if (selBoard.equals(boardId) && selPackage.equals(packageName) - && selPlatform.equals(platformName)) { + && selPlatform.equals(platformName)) { menuItemsToClickAfterStartup.add(item); } @@ -1402,14 +1415,14 @@ public class Base { for (final String menuId : customMenus.keySet()) { String title = customMenus.get(menuId); JMenu menu = getBoardCustomMenu(_(title)); - + if (board.hasMenu(menuId)) { PreferencesMap boardCustomMenu = board.getMenuLabels(menuId); for (String customMenuOption : boardCustomMenu.keySet()) { @SuppressWarnings("serial") Action subAction = new AbstractAction(_(boardCustomMenu.get(customMenuOption))) { public void actionPerformed(ActionEvent e) { - Preferences.set("custom_" + menuId, ((TargetBoard)getValue("board")).getId() + "_" + getValue("custom_menu_option")); + Preferences.set("custom_" + menuId, ((TargetBoard) getValue("board")).getId() + "_" + getValue("custom_menu_option")); onBoardOrPortChange(); } }; @@ -1431,7 +1444,7 @@ public class Base { } } } - + return item; } @@ -1523,7 +1536,7 @@ public class Base { @SuppressWarnings("serial") AbstractAction action = new AbstractAction(targetPlatform - .getProgrammer(programmer).get("name")) { + .getProgrammer(programmer).get("name")) { public void actionPerformed(ActionEvent actionevent) { Preferences.set("programmer", "" + getValue("id")); } @@ -1582,13 +1595,13 @@ public class Base { private boolean addSketchesSubmenu(JMenu menu, UserLibrary lib, boolean replaceExisting) - throws IOException { + throws IOException { return addSketchesSubmenu(menu, lib.getName(), lib.getInstalledFolder(), - replaceExisting); + replaceExisting); } private boolean addSketchesSubmenu(JMenu menu, String name, File folder, - final boolean replaceExisting) throws IOException { + final boolean replaceExisting) throws IOException { ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -1610,7 +1623,7 @@ public class Base { } } else { showWarning(_("Sketch Does Not Exist"), - _("The selected sketch no longer exists.\n" + _("The selected sketch no longer exists.\n" + "You may need to restart Arduino to update\n" + "the sketchbook menu."), null); } @@ -1627,13 +1640,13 @@ public class Base { if (!BaseNoGui.isSanitaryName(name)) { if (!builtOnce) { String complaining = I18n - .format( - _("The sketch \"{0}\" cannot be used.\n" - + "Sketch names must contain only basic letters and numbers\n" - + "(ASCII-only with no spaces, " - + "and it cannot start with a number).\n" - + "To get rid of this message, remove the sketch from\n" - + "{1}"), name, entry.getAbsolutePath()); + .format( + _("The sketch \"{0}\" cannot be used.\n" + + "Sketch names must contain only basic letters and numbers\n" + + "(ASCII-only with no spaces, " + + "and it cannot start with a number).\n" + + "To get rid of this message, remove the sketch from\n" + + "{1}"), name, entry.getAbsolutePath()); showMessage(_("Ignoring sketch with bad name"), complaining); } return false; @@ -1778,8 +1791,6 @@ public class Base { // return PConstants.OTHER; // } // } - - static public Platform getPlatform() { return BaseNoGui.getPlatform(); } @@ -1815,6 +1826,7 @@ public class Base { * Convenience method to get a File object for the specified filename inside * the settings folder. * For now, only used by Preferences to get the preferences.txt file. + * * @param filename A file inside the settings folder. * @return filename wrapped as a File object inside the settings folder */ @@ -1872,7 +1884,7 @@ public class Base { //Get the core libraries static public File getCoreLibraries(String path) { - return getContentFile(path); + return getContentFile(path); } static public String getHardwarePath() { @@ -1973,8 +1985,8 @@ public class Base { if (!result) { showError(_("You forgot your sketchbook"), - _("Arduino cannot run because it could not\n" + - "create a folder to store your sketchbook."), null); + _("Arduino cannot run because it could not\n" + + "create a folder to store your sketchbook."), null); } return sketchbookFolder; @@ -2018,13 +2030,14 @@ public class Base { } catch (Exception e) { showWarning(_("Problem Opening URL"), - I18n.format(_("Could not open the URL\n{0}"), url), e); + I18n.format(_("Could not open the URL\n{0}"), url), e); } } /** * Used to determine whether to disable the "Show Sketch Folder" option. + * * @return true If a means of opening a folder is known to be available. */ static protected boolean openFolderAvailable() { @@ -2042,7 +2055,7 @@ public class Base { } catch (Exception e) { showWarning(_("Problem Opening Folder"), - I18n.format(_("Could not open the folder\n{0}"), file.getAbsolutePath()), e); + I18n.format(_("Could not open the folder\n{0}"), file.getAbsolutePath()), e); } } @@ -2109,12 +2122,12 @@ public class Base { ActionListener disposer) { KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); root.registerKeyboardAction(disposer, stroke, - JComponent.WHEN_IN_FOCUSED_WINDOW); + JComponent.WHEN_IN_FOCUSED_WINDOW); int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); stroke = KeyStroke.getKeyStroke('W', modifiers); root.registerKeyboardAction(disposer, stroke, - JComponent.WHEN_IN_FOCUSED_WINDOW); + JComponent.WHEN_IN_FOCUSED_WINDOW); } @@ -2208,15 +2221,14 @@ public class Base { // ................................................................... - // incomplete static public int showYesNoCancelQuestion(Editor editor, String title, String primary, String secondary) { if (!OSUtils.isMacOS()) { int result = - JOptionPane.showConfirmDialog(null, primary + "\n" + secondary, title, - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE); + JOptionPane.showConfirmDialog(null, primary + "\n" + secondary, title, + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); return result; // if (result == JOptionPane.YES_OPTION) { // @@ -2234,18 +2246,18 @@ public class Base { // Pane formatting adapted from the Quaqua guide // http://www.randelshofer.ch/quaqua/guide/joptionpane.html JOptionPane pane = - new JOptionPane(" " + - " " + - "Do you want to save changes to this sketch
" + - " before closing?
" + - "

If you don't save, your changes will be lost.", - JOptionPane.QUESTION_MESSAGE); + new JOptionPane(" " + + " " + + "Do you want to save changes to this sketch
" + + " before closing?
" + + "

If you don't save, your changes will be lost.", + JOptionPane.QUESTION_MESSAGE); - String[] options = new String[] { - "Save", "Cancel", "Don't Save" + String[] options = new String[]{ + "Save", "Cancel", "Don't Save" }; pane.setOptions(options); @@ -2255,7 +2267,7 @@ public class Base { // on macosx, setting the destructive property places this option // away from the others at the lefthand side pane.putClientProperty("Quaqua.OptionPane.destructiveOption", - new Integer(2)); + new Integer(2)); JDialog dialog = pane.createDialog(editor, null); dialog.setVisible(true); @@ -2287,29 +2299,29 @@ public class Base { // } static public int showYesNoQuestion(Frame editor, String title, - String primary, String secondary) { + String primary, String secondary) { if (!OSUtils.isMacOS()) { return JOptionPane.showConfirmDialog(editor, - "" + - "" + primary + "" + - "
" + secondary, title, - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE); + "" + + "" + primary + "" + + "
" + secondary, title, + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE); } else { // Pane formatting adapted from the Quaqua guide // http://www.randelshofer.ch/quaqua/guide/joptionpane.html JOptionPane pane = - new JOptionPane(" " + - " " + - "" + primary + "" + - "

" + secondary + "

", - JOptionPane.QUESTION_MESSAGE); + new JOptionPane(" " + + " " + + "" + primary + "" + + "

" + secondary + "

", + JOptionPane.QUESTION_MESSAGE); - String[] options = new String[] { - "Yes", "No" + String[] options = new String[]{ + "Yes", "No" }; pane.setOptions(options); @@ -2367,7 +2379,6 @@ public class Base { return null; } */ - static public File getContentFile(String name) { return BaseNoGui.getContentFile(name); } @@ -2393,7 +2404,8 @@ public class Base { tracker.addImage(image, 0); try { tracker.waitForAll(); - } catch (InterruptedException e) { } + } catch (InterruptedException e) { + } return image; } @@ -2427,7 +2439,7 @@ public class Base { byte buffer[] = new byte[size]; int offset = 0; int bytesRead; - while ((bytesRead = input.read(buffer, offset, size-offset)) != -1) { + while ((bytesRead = input.read(buffer, offset, size - offset)) != -1) { offset += bytesRead; if (bytesRead == 0) break; } @@ -2437,20 +2449,19 @@ public class Base { } - /** * Read from a file with a bunch of attribute/value pairs * that are separated by = and ignore comments with #. */ - static public HashMap readSettings(File inputFile) { - HashMap outgoing = new HashMap(); + static public HashMap readSettings(File inputFile) { + HashMap outgoing = new HashMap(); if (!inputFile.exists()) return outgoing; // return empty hash String lines[] = PApplet.loadStrings(inputFile); for (int i = 0; i < lines.length; i++) { int hash = lines[i].indexOf('#'); String line = (hash == -1) ? - lines[i].trim() : lines[i].substring(0, hash).trim(); + lines[i].trim() : lines[i].substring(0, hash).trim(); if (line.length() == 0) continue; int equals = line.indexOf('='); @@ -2470,9 +2481,9 @@ public class Base { static public void copyFile(File sourceFile, File targetFile) throws IOException { InputStream from = - new BufferedInputStream(new FileInputStream(sourceFile)); + new BufferedInputStream(new FileInputStream(sourceFile)); OutputStream to = - new BufferedOutputStream(new FileOutputStream(targetFile)); + new BufferedOutputStream(new FileOutputStream(targetFile)); byte[] buffer = new byte[16 * 1024]; int bytesRead; while ((bytesRead = from.read(buffer)) != -1) { @@ -2563,7 +2574,7 @@ public class Base { for (int i = 0; i < files.length; i++) { if (files[i].equals(".") || (files[i].equals("..")) || - files[i].equals(".DS_Store")) continue; + files[i].equals(".DS_Store")) continue; File fella = new File(folder, files[i]); if (fella.isDirectory()) { size += calcFolderSize(fella); @@ -2657,9 +2668,9 @@ public class Base { String libName = libFolder.getName(); if (!BaseNoGui.isSanitaryName(libName)) { String mess = I18n.format(_("The library \"{0}\" cannot be used.\n" - + "Library names must contain only basic letters and numbers.\n" - + "(ASCII only and no spaces, and it cannot start with a number)"), - libName); + + "Library names must contain only basic letters and numbers.\n" + + "(ASCII only and no spaces, and it cannot start with a number)"), + libName); activeEditor.statusError(mess); return; } @@ -2686,4 +2697,12 @@ public class Base { public static DiscoveryManager getDiscoveryManager() { return BaseNoGui.getDiscoveryManager(); } + + public Editor getActiveEditor() { + return activeEditor; + } + + public List getEditors() { + return new LinkedList(editors); + } } diff --git a/app/src/processing/app/macosx/ThinkDifferent.java b/app/src/processing/app/macosx/ThinkDifferent.java index e14770a9b..1f243a8d4 100644 --- a/app/src/processing/app/macosx/ThinkDifferent.java +++ b/app/src/processing/app/macosx/ThinkDifferent.java @@ -22,113 +22,95 @@ package processing.app.macosx; -import processing.app.Base; - import com.apple.eawt.*; +import processing.app.Base; +import processing.app.Editor; import java.io.File; +import java.util.List; /** * Deal with issues related to thinking different. This handles the basic * Mac OS X menu commands (and apple events) for open, about, prefs, etc. - * + *

* Based on OSXAdapter.java from Apple DTS. - * - * As of 0140, this code need not be built on platforms other than OS X, + *

+ * As of 0140, this code need not be built on platforms other than OS X, * because of the new platform structure which isolates through reflection. */ -public class ThinkDifferent implements ApplicationListener { +public class ThinkDifferent { - // pseudo-singleton model; no point in making multiple instances - // of the EAWT application or our adapter - private static ThinkDifferent adapter; - // http://developer.apple.com/documentation/Java/Reference/1.4.2/appledoc/api/com/apple/eawt/Application.html - private static Application application; + private static final int MAX_WAIT_FOR_BASE = 10000; - // reference to the app where the existing quit, about, prefs code is - private Base base; + static public void init() { + Application application = Application.getApplication(); + application.setAboutHandler(new AboutHandler() { + @Override + public void handleAbout(AppEvent.AboutEvent aboutEvent) { + if (waitForBase()) { + Base.INSTANCE.handleAbout(); + } + } + }); + application.setPreferencesHandler(new PreferencesHandler() { + @Override + public void handlePreferences(AppEvent.PreferencesEvent preferencesEvent) { + if (waitForBase()) { + Base.INSTANCE.handlePrefs(); + } + } + }); + application.setOpenFileHandler(new OpenFilesHandler() { + @Override + public void openFiles(final AppEvent.OpenFilesEvent openFilesEvent) { + if (waitForBase()) { + for (File file : openFilesEvent.getFiles()) { + try { + Base.INSTANCE.handleOpen(file); + List editors = Base.INSTANCE.getEditors(); + if (editors.size() == 2 && editors.get(0).getSketch().isUntitled()) { + Base.INSTANCE.handleClose(editors.get(0)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + }); + application.setQuitHandler(new QuitHandler() { + @Override + public void handleQuitRequestWith(AppEvent.QuitEvent quitEvent, QuitResponse quitResponse) { + if (waitForBase()) { + if (Base.INSTANCE.handleClose(Base.INSTANCE.getActiveEditor())) { + quitResponse.performQuit(); + } else { + quitResponse.cancelQuit(); + } + } + } + }); + } - - static public void init(Base base) { - if (application == null) { - //application = new com.apple.eawt.Application(); - application = com.apple.eawt.Application.getApplication(); - } - if (adapter == null) { - adapter = new ThinkDifferent(base); - } - application.addApplicationListener(adapter); - application.setEnabledAboutMenu(true); - application.setEnabledPreferencesMenu(true); - } - - - public ThinkDifferent(Base base) { - this.base = base; - } - - - // implemented handler methods. These are basically hooks into existing - // functionality from the main app, as if it came over from another platform. - public void handleAbout(ApplicationEvent ae) { - if (base != null) { - ae.setHandled(true); - base.handleAbout(); - } else { - throw new IllegalStateException("handleAbout: Base instance detached from listener"); - } - } - - - public void handlePreferences(ApplicationEvent ae) { - if (base != null) { - base.handlePrefs(); - ae.setHandled(true); - } else { - throw new IllegalStateException("handlePreferences: Base instance detached from listener"); + private static boolean waitForBase() { + int slept = 0; + while (Base.INSTANCE == null) { + if (slept >= MAX_WAIT_FOR_BASE) { + return false; + } + sleep(100); + slept += 100; } + return true; } - - public void handleOpenApplication(ApplicationEvent ae) { - } - - - public void handleOpenFile(ApplicationEvent ae) { -// System.out.println("got open file event " + ae.getFilename()); - String filename = ae.getFilename(); + private static void sleep(int millis) { try { - base.handleOpen(new File(filename)); - } catch (Exception e) { - e.printStackTrace(); - } - ae.setHandled(true); - } - - - public void handlePrintFile(ApplicationEvent ae) { - // TODO implement os x print handler here (open app, call handlePrint, quit) - } - - - public void handleQuit(ApplicationEvent ae) { - if (base != null) { - /* - / You MUST setHandled(false) if you want to delay or cancel the quit. - / This is important for cross-platform development -- have a universal quit - / routine that chooses whether or not to quit, so the functionality is identical - / on all platforms. This example simply cancels the AppleEvent-based quit and - / defers to that universal method. - */ - boolean result = base.handleQuit(); - ae.setHandled(result); - } else { - throw new IllegalStateException("handleQuit: Base instance detached from listener"); + Thread.sleep(100); + } catch (InterruptedException e) { + //ignore } } - - - public void handleReOpenApplication(ApplicationEvent arg0) { - } + } \ No newline at end of file diff --git a/build/build.xml b/build/build.xml index 894b2027a..a99486e57 100644 --- a/build/build.xml +++ b/build/build.xml @@ -324,7 +324,7 @@ + role="Editor" ispackage="false">