1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-01-29 18:52:13 +01:00

MacOSX: double click on a .ino file works again. Fixes #2888

This commit is contained in:
Federico Fissore 2015-04-29 09:10:26 +02:00
parent 0e93798455
commit 74dea286a7
4 changed files with 284 additions and 283 deletions

Binary file not shown.

View File

@ -22,6 +22,7 @@
package processing.app; package processing.app;
import cc.arduino.contributions.DownloadableContributionVersionComparator;
import cc.arduino.contributions.VersionHelper; import cc.arduino.contributions.VersionHelper;
import cc.arduino.contributions.libraries.ContributedLibrary; import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.LibrariesIndexer; 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.ContributedPlatform;
import cc.arduino.contributions.packages.ContributionInstaller; import cc.arduino.contributions.packages.ContributionInstaller;
import cc.arduino.contributions.packages.ContributionsIndexer; import cc.arduino.contributions.packages.ContributionsIndexer;
import cc.arduino.contributions.DownloadableContributionVersionComparator;
import cc.arduino.contributions.packages.ui.ContributionManagerUI; import cc.arduino.contributions.packages.ui.ContributionManagerUI;
import cc.arduino.files.DeleteFilesOnShutdown; import cc.arduino.files.DeleteFilesOnShutdown;
import cc.arduino.packages.DiscoveryManager; 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()); public static SplashScreenHelper splashScreenHelper = new SplashScreenHelper(SplashScreen.getSplashScreen());
// A single instance of the preferences window // A single instance of the preferences window
@ -119,6 +121,10 @@ public class Base {
splashScreenHelper.splashText(_("Loading configuration...")); splashScreenHelper.splashText(_("Loading configuration..."));
if (OSUtils.isMacOS()) {
ThinkDifferent.init();
}
try { try {
guardedMain(args); guardedMain(args);
} catch (Throwable e) { } catch (Throwable e) {
@ -207,7 +213,7 @@ public class Base {
untitledFolder = createTempFolder("untitled"); untitledFolder = createTempFolder("untitled");
DeleteFilesOnShutdown.add(untitledFolder); DeleteFilesOnShutdown.add(untitledFolder);
new Base(args); INSTANCE = new Base(args);
} }
@ -247,8 +253,6 @@ public class Base {
public Base(String[] args) throws Exception { public Base(String[] args) throws Exception {
getPlatform().init(); getPlatform().init();
if (OSUtils.isMacOS())
ThinkDifferent.init(this);
String sketchbookPath = BaseNoGui.getSketchbookPath(); String sketchbookPath = BaseNoGui.getSketchbookPath();
@ -312,6 +316,7 @@ public class Base {
ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder()); ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder());
ContributionInstaller installer = new ContributionInstaller(indexer) { ContributionInstaller installer = new ContributionInstaller(indexer) {
private String lastStatus = ""; private String lastStatus = "";
@Override @Override
protected void onProgress(Progress progress) { protected void onProgress(Progress progress) {
if (!lastStatus.equals(progress.getStatus())) { if (!lastStatus.equals(progress.getStatus())) {
@ -357,6 +362,7 @@ public class Base {
LibrariesIndexer indexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder()); LibrariesIndexer indexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder());
LibraryInstaller installer = new LibraryInstaller(indexer) { LibraryInstaller installer = new LibraryInstaller(indexer) {
private String lastStatus = ""; private String lastStatus = "";
@Override @Override
protected void onProgress(Progress progress) { protected void onProgress(Progress progress) {
if (!lastStatus.equals(progress.getStatus())) { if (!lastStatus.equals(progress.getStatus())) {
@ -427,8 +433,7 @@ public class Base {
// No errors exit gracefully // No errors exit gracefully
System.exit(0); System.exit(0);
} } else if (parser.isGuiMode()) {
else if (parser.isGuiMode()) {
splashScreenHelper.splashText(_("Starting...")); splashScreenHelper.splashText(_("Starting..."));
// Check if there were previously opened sketches to be restored // Check if there were previously opened sketches to be restored
@ -443,12 +448,10 @@ public class Base {
if (Preferences.getBoolean("update.check")) { if (Preferences.getBoolean("update.check")) {
new UpdateCheck(this); new UpdateCheck(this);
} }
} } else if (parser.isNoOpMode()) {
else if (parser.isNoOpMode()) {
// Do nothing (intended for only changing preferences) // Do nothing (intended for only changing preferences)
System.exit(0); System.exit(0);
} } else if (parser.isGetPrefMode()) {
else if (parser.isGetPrefMode()) {
String value = Preferences.get(parser.getGetPref(), null); String value = Preferences.get(parser.getGetPref(), null);
if (value != null) { if (value != null) {
System.out.println(value); System.out.println(value);
@ -464,6 +467,7 @@ public class Base {
* sketch that was used (if any), and restores other Editor settings. * sketch that was used (if any), and restores other Editor settings.
* The complement to "storePreferences", this is called when the * The complement to "storePreferences", this is called when the
* application is first launched. * application is first launched.
*
* @throws Exception * @throws Exception
*/ */
protected boolean restoreSketches() throws Exception { protected boolean restoreSketches() throws Exception {
@ -570,8 +574,7 @@ public class Base {
String untitledPath = untitledFolder.getAbsolutePath(); String untitledPath = untitledFolder.getAbsolutePath();
if (path.startsWith(untitledPath)) { if (path.startsWith(untitledPath)) {
path = ""; path = "";
} else } else if (BaseNoGui.getPortableFolder() != null) {
if (BaseNoGui.getPortableFolder() != null) {
path = FileUtils.relativePath(BaseNoGui.getPortableFolder().toString(), path); path = FileUtils.relativePath(BaseNoGui.getPortableFolder().toString(), path);
if (path == null) if (path == null)
path = ""; path = "";
@ -672,6 +675,7 @@ public class Base {
/** /**
* Handle creating a sketch folder, return its base .pde file * Handle creating a sketch folder, return its base .pde file
* or null if the operation was canceled. * 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 * @param noPrompt disable prompt, no matter the setting
*/ */
@ -728,6 +732,7 @@ public class Base {
/** /**
* Create a new untitled document in a new sketch window. * Create a new untitled document in a new sketch window.
*
* @throws Exception * @throws Exception
*/ */
public void handleNew() throws Exception { public void handleNew() throws Exception {
@ -779,9 +784,11 @@ public class Base {
/** /**
* Open a sketch, replacing the sketch in the current window. * Open a sketch, replacing the sketch in the current window.
*
* @param path Location of the primary pde file for the sketch. * @param path Location of the primary pde file for the sketch.
*/ */
public void handleOpenReplace(File file) { public void handleOpenReplace(File file) {
System.out.println("handleOpenReplace");
if (!activeEditor.checkModified()) { if (!activeEditor.checkModified()) {
return; // sketch was modified, and user canceled return; // sketch was modified, and user canceled
} }
@ -798,6 +805,7 @@ public class Base {
/** /**
* Prompt for a sketch to open, and open it in a new window. * Prompt for a sketch to open, and open it in a new window.
*
* @throws Exception * @throws Exception
*/ */
public void handleOpenPrompt() throws Exception { public void handleOpenPrompt() throws Exception {
@ -834,6 +842,7 @@ public class Base {
/** /**
* Open a sketch in a new window. * Open a sketch in a new window.
*
* @param file File to open * @param file File to open
* @return the Editor object, so that properties (like 'untitled') * @return the Editor object, so that properties (like 'untitled')
* can be set by the caller * can be set by the caller
@ -923,6 +932,7 @@ public class Base {
/** /**
* Close a sketch as specified by its editor window. * Close a sketch as specified by its editor window.
*
* @param editor Editor object of the sketch to be closed. * @param editor Editor object of the sketch to be closed.
* @return true if succeeded in closing, false if canceled. * @return true if succeeded in closing, false if canceled.
*/ */
@ -1004,9 +1014,11 @@ public class Base {
/** /**
* Handler for File → Quit. * Handler for File → Quit.
*
* @return false if canceled, true otherwise. * @return false if canceled, true otherwise.
*/ */
public boolean handleQuit() { public boolean handleQuit() {
System.out.println("handleQuit");
// If quit is canceled, this will be replaced anyway // If quit is canceled, this will be replaced anyway
// by a later handleQuit() that is not canceled. // by a later handleQuit() that is not canceled.
storeSketches(); storeSketches();
@ -1037,6 +1049,7 @@ public class Base {
/** /**
* Attempt to close each open sketch in preparation for quitting. * Attempt to close each open sketch in preparation for quitting.
*
* @return false if canceled along the way * @return false if canceled along the way
*/ */
protected boolean handleQuitEach() { protected boolean handleQuitEach() {
@ -1778,8 +1791,6 @@ public class Base {
// return PConstants.OTHER; // return PConstants.OTHER;
// } // }
// } // }
static public Platform getPlatform() { static public Platform getPlatform() {
return BaseNoGui.getPlatform(); return BaseNoGui.getPlatform();
} }
@ -1815,6 +1826,7 @@ public class Base {
* Convenience method to get a File object for the specified filename inside * Convenience method to get a File object for the specified filename inside
* the settings folder. * the settings folder.
* For now, only used by Preferences to get the preferences.txt file. * For now, only used by Preferences to get the preferences.txt file.
*
* @param filename A file inside the settings folder. * @param filename A file inside the settings folder.
* @return filename wrapped as a File object inside the settings folder * @return filename wrapped as a File object inside the settings folder
*/ */
@ -2025,6 +2037,7 @@ public class Base {
/** /**
* Used to determine whether to disable the "Show Sketch Folder" option. * 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. * @return true If a means of opening a folder is known to be available.
*/ */
static protected boolean openFolderAvailable() { static protected boolean openFolderAvailable() {
@ -2208,7 +2221,6 @@ public class Base {
// ................................................................... // ...................................................................
// incomplete // incomplete
static public int showYesNoCancelQuestion(Editor editor, String title, static public int showYesNoCancelQuestion(Editor editor, String title,
String primary, String secondary) { String primary, String secondary) {
@ -2367,7 +2379,6 @@ public class Base {
return null; return null;
} }
*/ */
static public File getContentFile(String name) { static public File getContentFile(String name) {
return BaseNoGui.getContentFile(name); return BaseNoGui.getContentFile(name);
} }
@ -2393,7 +2404,8 @@ public class Base {
tracker.addImage(image, 0); tracker.addImage(image, 0);
try { try {
tracker.waitForAll(); tracker.waitForAll();
} catch (InterruptedException e) { } } catch (InterruptedException e) {
}
return image; return image;
} }
@ -2437,7 +2449,6 @@ public class Base {
} }
/** /**
* Read from a file with a bunch of attribute/value pairs * Read from a file with a bunch of attribute/value pairs
* that are separated by = and ignore comments with #. * that are separated by = and ignore comments with #.
@ -2686,4 +2697,12 @@ public class Base {
public static DiscoveryManager getDiscoveryManager() { public static DiscoveryManager getDiscoveryManager() {
return BaseNoGui.getDiscoveryManager(); return BaseNoGui.getDiscoveryManager();
} }
public Editor getActiveEditor() {
return activeEditor;
}
public List<Editor> getEditors() {
return new LinkedList<Editor>(editors);
}
} }

View File

@ -22,113 +22,95 @@
package processing.app.macosx; package processing.app.macosx;
import processing.app.Base;
import com.apple.eawt.*; import com.apple.eawt.*;
import processing.app.Base;
import processing.app.Editor;
import java.io.File; import java.io.File;
import java.util.List;
/** /**
* Deal with issues related to thinking different. This handles the basic * Deal with issues related to thinking different. This handles the basic
* Mac OS X menu commands (and apple events) for open, about, prefs, etc. * Mac OS X menu commands (and apple events) for open, about, prefs, etc.
* * <p/>
* Based on OSXAdapter.java from Apple DTS. * Based on OSXAdapter.java from Apple DTS.
* * <p/>
* 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. * 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 private static final int MAX_WAIT_FOR_BASE = 10000;
// 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;
// reference to the app where the existing quit, about, prefs code is static public void init() {
private Base base; Application application = Application.getApplication();
application.setAboutHandler(new AboutHandler() {
@Override
static public void init(Base base) { public void handleAbout(AppEvent.AboutEvent aboutEvent) {
if (application == null) { if (waitForBase()) {
//application = new com.apple.eawt.Application(); Base.INSTANCE.handleAbout();
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");
} }
} }
});
application.setPreferencesHandler(new PreferencesHandler() {
public void handlePreferences(ApplicationEvent ae) { @Override
if (base != null) { public void handlePreferences(AppEvent.PreferencesEvent preferencesEvent) {
base.handlePrefs(); if (waitForBase()) {
ae.setHandled(true); Base.INSTANCE.handlePrefs();
} else {
throw new IllegalStateException("handlePreferences: Base instance detached from listener");
} }
} }
});
application.setOpenFileHandler(new OpenFilesHandler() {
public void handleOpenApplication(ApplicationEvent ae) { @Override
} public void openFiles(final AppEvent.OpenFilesEvent openFilesEvent) {
if (waitForBase()) {
for (File file : openFilesEvent.getFiles()) {
public void handleOpenFile(ApplicationEvent ae) {
// System.out.println("got open file event " + ae.getFilename());
String filename = ae.getFilename();
try { try {
base.handleOpen(new File(filename)); Base.INSTANCE.handleOpen(file);
List<Editor> editors = Base.INSTANCE.getEditors();
if (editors.size() == 2 && editors.get(0).getSketch().isUntitled()) {
Base.INSTANCE.handleClose(editors.get(0));
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throw new RuntimeException(e);
} }
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) { application.setQuitHandler(new QuitHandler() {
if (base != null) { @Override
/* public void handleQuitRequestWith(AppEvent.QuitEvent quitEvent, QuitResponse quitResponse) {
/ You MUST setHandled(false) if you want to delay or cancel the quit. if (waitForBase()) {
/ This is important for cross-platform development -- have a universal quit if (Base.INSTANCE.handleClose(Base.INSTANCE.getActiveEditor())) {
/ routine that chooses whether or not to quit, so the functionality is identical quitResponse.performQuit();
/ 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 { } else {
throw new IllegalStateException("handleQuit: Base instance detached from listener"); quitResponse.cancelQuit();
}
}
}
});
}
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;
}
private static void sleep(int millis) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
//ignore
} }
} }
public void handleReOpenApplication(ApplicationEvent arg0) {
}
} }

View File

@ -324,7 +324,7 @@
<bundledocument extensions="ino,c,cpp,h" <bundledocument extensions="ino,c,cpp,h"
icon="macosx/template.app/Contents/Resources/pde.icns" icon="macosx/template.app/Contents/Resources/pde.icns"
name="Arduino Source File" name="Arduino Source File"
role="Editor"> role="Editor" ispackage="false">
</bundledocument> </bundledocument>
</bundleapp> </bundleapp>