diff --git a/app/src/processing/app/ChangeDetector.java b/app/src/processing/app/ChangeDetector.java
index 8b5abfebd..024c7a10b 100644
--- a/app/src/processing/app/ChangeDetector.java
+++ b/app/src/processing/app/ChangeDetector.java
@@ -8,95 +8,22 @@ import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.InvocationTargetException;
+import javax.swing.JOptionPane;
+
+
public class ChangeDetector implements WindowFocusListener {
private Sketch sketch;
-
private Editor editor;
-// private boolean enabled = true;
- private boolean enabled = true; // broken on OS X (possibly fixed? tested and it seems to work)
-
+ private boolean enabled = true;
private boolean skip = false;
+
public ChangeDetector(Editor editor) {
this.sketch = editor.sketch;
this.editor = editor;
}
- @Override
- public void windowGainedFocus(WindowEvent e) {
- //remove the detector from main if it is disabled during runtime (due to an error?)
- if (!enabled || !Preferences.getBoolean("editor.watcher")) {
- editor.removeWindowFocusListener(this);
- return;
- }
- //if they selected no, skip the next focus event
- if (skip) {
- skip = false;
- return;
- }
- checkFileChangeAsync();
- }
-
- private void checkFileChangeAsync() {
- Thread th = new Thread(new Runnable() {
- @Override
- public void run() {
- checkFileChange();
- }
- });
- th.start();
- }
-
- private void showErrorAsync(final String title, final String message,
- final Exception e) {
- EventQueue.invokeLater(new Runnable() {
- @Override
- public void run() {
- Base.showError(title, message, e);
- }
- });
- }
-
- private void showWarningAsync(final String title, final String message) {
- EventQueue.invokeLater(new Runnable() {
- @Override
- public void run() {
- Base.showWarning(title, message);
- }
- });
- }
-
- private int showYesNoQuestionAsync(final Frame editor, final String title,
- final String message1,
- final String message2) {
- final int[] res = { -1 };
- try {
- //have to wait for a response on this one
- EventQueue.invokeAndWait(new Runnable() {
- @Override
- public void run() {
- res[0] = Base.showYesNoQuestion(editor, title, message1, message2);
- }
- });
- } catch (InvocationTargetException e) {
- //occurs if Base.showYesNoQuestion throws an error, so, shouldn't happen
- e.printStackTrace();
- } catch (InterruptedException e) {
- //occurs if the EDT is interrupted, so, shouldn't happen
- e.printStackTrace();
- }
- return res[0];
- }
-
- private void rebuildHeaderAsync() {
- EventQueue.invokeLater(new Runnable() {
- @Override
- public void run() {
- editor.header.rebuild();
- }
- });
- }
private void checkFileChange() {
//check that the content of each of the files in sketch matches what is in memory
@@ -104,13 +31,13 @@ public class ChangeDetector implements WindowFocusListener {
return;
}
- //make sure the sketch folder exists at all. if it does not, it will be re-saved, and no changes will be detected
- //
+ // make sure the sketch folder exists at all.
+ // if it does not, it will be re-saved, and no changes will be detected
sketch.ensureExistence();
- //check file count first
+
+ // check file count first
File sketchFolder = sketch.getFolder();
- int fileCount = sketchFolder.list(new FilenameFilter() {
- //return true if the file is a code file for this mode
+ File[] sketchFiles = sketchFolder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
for (String s : editor.getMode().getExtensions()) {
@@ -120,18 +47,18 @@ public class ChangeDetector implements WindowFocusListener {
}
return false;
}
- }).length;
+ });
+ int fileCount = sketchFiles.length;
if (fileCount != sketch.getCodeCount()) {
- //if they chose to reload and there aren't any files left
+ // if they chose to reload and there aren't any files left
if (reloadSketch(null) && fileCount < 1) {
try {
//make a blank file
sketch.getMainFile().createNewFile();
} catch (Exception e1) {
//if that didn't work, tell them it's un-recoverable
- showErrorAsync("Reload failed", "The sketch contains no code files.",
- e1);
+ showErrorEDT("Reload failed", "The sketch contains no code files.", e1);
//don't try to reload again after the double fail
//this editor is probably trashed by this point, but a save-as might be possible
skip = true;
@@ -139,9 +66,9 @@ public class ChangeDetector implements WindowFocusListener {
}
//it's okay to do this without confirmation, because they already confirmed to deleting the unsaved changes above
sketch.reload();
- showWarningAsync("Modified Reload",
- "You cannot delete the last code file in a sketch.\n"
- + "A new blank sketch file has been generated for you.");
+ showWarningEDT("Modified Reload",
+ "You cannot delete the last code file in a sketch.\n" +
+ "A new blank sketch file has been generated for you.");
}
return;
@@ -150,62 +77,152 @@ public class ChangeDetector implements WindowFocusListener {
SketchCode[] codes = sketch.getCode();
for (SketchCode sc : codes) {
File sketchFile = sc.getFile();
- if (!sketchFile.exists()) {
- //if a file in the sketch was not found, then it must have been deleted externally
- //so reload the sketch
- reloadSketch(sc);
- return;
- }
- //if a file's tab was saved before the file was
- if (sketchFile.lastModified() > sc.lastModified()) {
+ if (sketchFile.exists()) {
+ long diff = sketchFile.lastModified() - sc.lastModified();
+ if (diff != 0) {
+ if (Base.isMacOS() && diff == 1000L) {
+ // Mac OS X has a one second difference. Not sure if it's a Java bug
+ // or something else about how OS X is writing files.
+ continue;
+ }
+ System.out.println(sketchFile.getName() + " " + diff);
+ reloadSketch(sc);
+ return;
+ }
+ } else {
+ // If a file in the sketch was not found, then it must have been
+ // deleted externally, so reload the sketch.
reloadSketch(sc);
return;
}
}
}
+
private void setSketchCodeModified(SketchCode sc) {
sc.setModified(true);
sketch.setModified(true);
}
- //returns true if the files in the sketch have been reloaded
- private boolean reloadSketch(SketchCode changed) {
- //new Exception().printStackTrace(System.out);
- int response = showYesNoQuestionAsync(editor,
- "File Modified",
- "Your sketch has been modified externally.
Would you like to reload the sketch?",
- "If you reload the sketch, any unsaved changes will be lost!");
- if (response == 0) {
- //reload the sketch
+ /**
+ * @param changed The file that was known to be modified
+ * @return true if the files in the sketch have been reloaded
+ */
+ private boolean reloadSketch(SketchCode changed) {
+ int response = blockingYesNoPrompt(editor,
+ "File Modified",
+ "Your sketch has been modified externally.
" +
+ "Would you like to reload the sketch?",
+ "If you reload the sketch, any unsaved changes will be lost.");
+ if (response == JOptionPane.YES_OPTION) {
sketch.reload();
- rebuildHeaderAsync();
+ rebuildHeaderEDT();
return true;
- } else {
- //they said no, make it possible for them to stop the errors by saving
- if (changed != null) {
- //set it to be modified so that it will actually save to disk when the user saves from inside processing
- setSketchCodeModified(changed);
- } else {
- //the number of files changed, so they may be working with a file that doesn't exist any more
- //find the files that are missing, and mark them as modified
- for (SketchCode sc : sketch.getCode()) {
- if (!sc.getFile().exists()) {
- setSketchCodeModified(sc);
- }
- }
- //if files were simply added, then nothing needs done
- }
- rebuildHeaderAsync();
- skip = true;
- return false;
}
+
+ // they said no (or canceled), make it possible to stop the msgs by saving
+ if (changed != null) {
+ //set it to be modified so that it will actually save to disk when the user saves from inside processing
+ setSketchCodeModified(changed);
+
+ } else {
+ // Because the number of files changed, they may be working with a file
+ // that doesn't exist any more. So find the files that are missing,
+ // and mark them as modified so that the next "Save" will write them.
+ for (SketchCode sc : sketch.getCode()) {
+ if (!sc.getFile().exists()) {
+ setSketchCodeModified(sc);
+ }
+ }
+ // If files were simply added, then nothing needs done
+ }
+ rebuildHeaderEDT();
+ skip = true;
+ return false;
}
+
@Override
public void windowLostFocus(WindowEvent e) {
//shouldn't need to do anything here
}
+
+ @Override
+ public void windowGainedFocus(WindowEvent e) {
+ if (enabled) {
+ //remove the detector from main if it is disabled during runtime (due to an error?)
+ //if (!enabled || !Preferences.getBoolean("editor.watcher")) {
+ //editor.removeWindowFocusListener(this);
+ //} else if (skip) {
+
+ // if they selected no, skip the next focus event
+ if (skip) {
+ skip = false;
+
+ } else {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ checkFileChange();
+ }
+ }).start();
+ }
+ }
+ }
+
+
+ private void showErrorEDT(final String title, final String message,
+ final Exception e) {
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ Base.showError(title, message, e);
+ }
+ });
+ }
+
+
+ private void showWarningEDT(final String title, final String message) {
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ Base.showWarning(title, message);
+ }
+ });
+ }
+
+
+ private int blockingYesNoPrompt(final Frame editor, final String title,
+ final String message1,
+ final String message2) {
+ final int[] result = { -1 }; // yuck
+ try {
+ //have to wait for a response on this one
+ EventQueue.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ result[0] = Base.showYesNoQuestion(editor, title, message1, message2);
+ }
+ });
+ } catch (InvocationTargetException e) {
+ //occurs if Base.showYesNoQuestion throws an error, so, shouldn't happen
+ e.getTargetException().printStackTrace();
+ } catch (InterruptedException e) {
+ //occurs if the EDT is interrupted, so, shouldn't happen
+ e.printStackTrace();
+ }
+ return result[0];
+ }
+
+
+ private void rebuildHeaderEDT() {
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ editor.header.rebuild();
+ }
+ });
+ }
}
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index 535d9dd4d..0653b575d 100755
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -360,11 +360,8 @@ public abstract class Editor extends JFrame implements RunnerListener {
sketch = null;
}
- //add a window listener to watch for changes to the files in the sketch
- if (Preferences.getBoolean("editor.watcher")) {
- addWindowFocusListener(new ChangeDetector(this));
- }
-
+ // Add a window listener to watch for changes to the files in the sketch
+ addWindowFocusListener(new ChangeDetector(this));
}
diff --git a/todo.txt b/todo.txt
index 38cc2af24..a60a9c4e7 100644
--- a/todo.txt
+++ b/todo.txt
@@ -30,9 +30,9 @@ X the .macosx, .linux, etc prefs should be stripped
X only use them on first load, and merge into preferences.txt
X auto-insert after antlr @SuppressWarnings({ "unused", "unchecked", "cast" })
+_ editor window draws in stages (at least on OS X) on first view
+_ "sketch modified" message still happening
_ is debug turned on? lots of "export.txt" complaints
-_ sketchbook window is completely empty w/ no sketches
-_ requires restart of p5 before it updates
_ install/remove buttons not working in the managers
_ https://github.com/processing/processing/issues/3172
_ search the source for 'applet' references (i.e. SVG docs)
@@ -215,8 +215,6 @@ _ https://github.com/processing/processing/issues/2953
_ don't return here, allow contrib types to fail:
_ https://github.com/processing/processing/blob/master/app/src/processing/app/contrib/ContributionListing.java#L509
-_ need to handle the 2.x to 3.x sketchbook transition
-
_ Linux throwing IllegalStateException: Buffers have not been created
_ in render() (called from blit) PSurfaceAWT:301
@@ -301,8 +299,6 @@ _ might be something with libraries (native or otherwise)
_ move the language stuff to the settings folder
_ that way people can modify and test w/o recompiling
_ https://github.com/processing/processing/issues/2938
-_ sketchbook window doesn't update when sketches are added, renamed, etc
-_ https://github.com/processing/processing/issues/2944
pending
@@ -318,6 +314,17 @@ _ clean out the repo
_ https://github.com/processing/processing/issues/1898
+sketchbook
+_ need to handle the 2.x to 3.x sketchbook transition
+_ "Save As" is reloading the whole sketchbook, argh
+_ sketchbook window is completely empty w/ no sketches
+_ requires restart of p5 before it updates
+_ sketchbook window doesn't update when sketches are added, renamed, etc
+_ https://github.com/processing/processing/issues/2944
+_ improve start time by populating sketchbook/libraries on threads
+_ https://github.com/processing/processing/issues/2945
+
+
help me
_ "String index out of range" error
_ https://github.com/processing/processing/issues/1940
@@ -334,8 +341,6 @@ _ http://stackoverflow.com/questions/4933677/detecting-windows-ie-proxy-settin
_ http://www.java2s.com/Code/Java/Network-Protocol/DetectProxySettingsforInternetConnection.htm
_ problems with non-US keyboards and some shortcuts
_ https://github.com/processing/processing/issues/2199
-_ improve start time by populating sketchbook/libraries on threads
-_ https://github.com/processing/processing/issues/2945
_ clean up 'ant doc' target to remove warnings
_ https://github.com/processing/processing/issues/1492
_ fix encodings, line endings, and mime types in the repo