diff --git a/app/.classpath b/app/.classpath
index e12f72e7e..00411841a 100644
--- a/app/.classpath
+++ b/app/.classpath
@@ -6,7 +6,6 @@
-
@@ -19,5 +18,6 @@
+
diff --git a/app/src/processing/app/ChangeDetector.java b/app/src/processing/app/ChangeDetector.java
new file mode 100644
index 000000000..0d18574d4
--- /dev/null
+++ b/app/src/processing/app/ChangeDetector.java
@@ -0,0 +1,161 @@
+package processing.app;
+
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowFocusListener;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+
+public class ChangeDetector implements WindowFocusListener {
+ private Sketch sketch;
+
+ private Editor editor;
+
+ 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;
+ }
+ checkFileChange();
+ }
+
+ private void checkFileChange() {
+ //check that the content of each of the files in sketch matches what is in memory
+ if (sketch == null) {
+ return;
+ }
+
+ //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
+ @Override
+ public boolean accept(File dir, String name) {
+ for (String s : editor.getMode().getExtensions()) {
+ if (name.endsWith(s)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }).length;
+
+ if (fileCount != sketch.getCodeCount()) {
+ reloadSketch(null);
+ if (fileCount < 1) {
+ try {
+ //make a blank file
+ sketch.getMainFile().createNewFile();
+ } catch (Exception e1) {
+ //if that didn't work, tell them it's un-recoverable
+ Base.showError("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;
+ return;
+ }
+ //it's okay to do this without confirmation, because they already confirmed to deleting the unsaved changes above
+ sketch.reload();
+ editor.header.rebuild();
+ Base
+ .showWarning("Modified Reload",
+ "You cannot delete the last code file in a sketch.\n"
+ + "A new blank sketch file has been generated for you.");
+
+ }
+ return;
+ }
+
+ SketchCode[] codes = sketch.getCode();
+ for (SketchCode sc : codes) {
+ String inMemory = sc.getProgram();
+ String onDisk = null;
+ 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;
+ }
+ try {
+ onDisk = Base.loadFile(sketchFile);
+ } catch (IOException e1) {
+ Base
+ .showWarningTiered("File Change Detection Failed",
+ "Checking for changed files for this sketch has failed.",
+ "The file change detector will be disabled.", e1);
+ enabled = false;
+ return;
+ }
+ if (onDisk == null) {
+ //failed
+ } else if (!inMemory.equals(onDisk)) {
+ 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 void reloadSketch(SketchCode changed) {
+ int response = Base
+ .showYesNoQuestion(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
+
+ sketch.reload();
+ editor.header.rebuild();
+
+ } 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
+ }
+ editor.header.rebuild();
+ skip = true;
+ return;
+ }
+ return;
+ }
+
+ @Override
+ public void windowLostFocus(WindowEvent e) {
+ //shouldn't need to do anything here
+ }
+
+}
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index 1b22f95cb..9b706a202 100644
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -33,7 +33,8 @@ import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.print.*;
import java.io.*;
-import java.nio.file.*;
+//REMOVE
+//import java.nio.file.*;
import java.util.*;
import java.util.List;
import java.util.Timer;
@@ -286,6 +287,12 @@ public abstract class Editor extends JFrame implements RunnerListener {
if (!loaded) {
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));
+ }
+
}
@@ -2459,10 +2466,6 @@ public abstract class Editor extends JFrame implements RunnerListener {
Base.showWarning("Error", "Could not create the sketch.", e);
return false;
}
- // Disabling for 3.0a4
- if (false && Preferences.getBoolean("editor.watcher")) {
- initFileChangeListener();
- }
header.rebuild();
updateTitle();
@@ -2483,134 +2486,6 @@ public abstract class Editor extends JFrame implements RunnerListener {
// return false;
// }
}
-
- //used to prevent the fileChangeListener from asking for reloads after internal changes
- public void setWatcherSave() {
- watcherSave = true;
- }
-
- //set to true when the sketch is saved from inside processing
- private boolean watcherSave;
-
- //the key which is being used to poll the fs for changes
- private WatchKey watcherKey = null;
-
- private void initFileChangeListener() {
- try {
- WatchService watchService = FileSystems.getDefault().newWatchService();
- Path sp = sketch.getFolder().toPath();
- watcherKey = sp.register(watchService,
- StandardWatchEventKinds.ENTRY_CREATE,
- StandardWatchEventKinds.ENTRY_DELETE,
- StandardWatchEventKinds.ENTRY_MODIFY);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- final WatchKey finKey = watcherKey;
-
- //if the key is null for some reason, don't bother attaching a listener to it
- if (finKey != null) {
- // the key can now be polled for changes in the files
- addWindowFocusListener(new WindowFocusListener() {
- @Override
- public void windowGainedFocus(WindowEvent arg0) {
- //we switched locations (saveAs), ignore old things
- if (watcherKey != finKey) {
- return;
- }
- // check preference here for enabled or not?
-
- //if the directory was deleted, then don't scan
- if (finKey.isValid()) {
- List> events = finKey.pollEvents();
- if (!watcherSave) {
- processFileEvents(events);
- }
- }
-
- List> events = finKey.pollEvents();
- if (!watcherSave)
- processFileEvents(events);
- }
-
- @Override
- public void windowLostFocus(WindowEvent arg0) {
- //we switched locations (saveAs), ignore old things
- if (watcherKey != finKey) {
- return;
- }
- List> events = finKey.pollEvents();
- //don't ask to reload a file we saved
- if (!watcherSave) {
- processFileEvents(events);
- }
- watcherSave = false;
- }
- });
- }
- }
-
-
- /**
- * Called when a file is changed.
- * @param events the list of events that have occured in the sketch folder
- */
- private void processFileEvents(List> events) {
- for (WatchEvent> e : events) {
- boolean sketchFile = false;
- Path file = ((Path) e.context()).getFileName();
- System.out.println(file);
- for (String s : getMode().getExtensions()) {
- // if it is a change to a file with a known extension
- if (file.toString().endsWith(s)) {
- sketchFile = true;
- break;
- }
- }
- //if the file is not a known type, then go the the next event
- if (!sketchFile) {
- continue;
- }
-
- int response =
- Base.showYesNoQuestion(Editor.this,
- "File Modified",
- "Your sketch has been modified externally",
- "Would you like to reload the sketch?");
- if (response == 0) {
- //grab the 'main' code in case this reload tries to delete everything
- File sc = sketch.getMainFile();
- //reload the sketch
- try {
- sketch.reload();
- header.rebuild();
- } catch (Exception f) {
- if (sketch.getCodeCount() < 1) {
- Base.showWarning("Canceling Reload",
- "You cannot delete the last code file in a sketch.");
- //if they deleted the last file, re-save the SketchCode
- try {
- //make a blank file
- sc.createNewFile();
- } catch (IOException e1) {
- //if that didn't work, tell them it's un-recoverable
- Base.showError("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
- break;
- }
- //don't ask for another reload after this save
- watcherSave = true;
- return;
- }
- }
- //now that we've reloaded once, don't try to reload again
- break;
- }
- }
- watcherSave = false;
- }
/**
* Set the title of the PDE window based on the current sketch, i.e.
@@ -2641,8 +2516,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
*/
public boolean handleSave(boolean immediately) {
// handleStop(); // 0136
-
- setWatcherSave();
+
if (sketch.isUntitled()) {
return handleSaveAs();
// need to get the name, user might also cancel here
@@ -2686,13 +2560,6 @@ public abstract class Editor extends JFrame implements RunnerListener {
statusNotice(Language.text("editor.status.saving"));
try {
if (sketch.saveAs()) {
- // Disabling for 3.0a4
- if (false && Preferences.getBoolean("editor.watcher")) {
- // "Save As" moves where the files are, so a listener must be
- // attached to the new location.
- // TODO shouldn't this remove the old listener?
- initFileChangeListener();
- }
// statusNotice("Done Saving.");
// status is now printed from Sketch so that "Done Saving."
// is only printed after Save As when progress bar is shown.
@@ -3040,7 +2907,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
cutItem.setEnabled(active);
copyItem.setEnabled(active);
discourseItem.setEnabled(active);
-
+
referenceItem.setEnabled(referenceCheck(false) != null);
super.show(component, x, y);
}
diff --git a/app/src/processing/app/EditorHeader.java b/app/src/processing/app/EditorHeader.java
index 94e7c50f7..3b4183195 100644
--- a/app/src/processing/app/EditorHeader.java
+++ b/app/src/processing/app/EditorHeader.java
@@ -516,7 +516,6 @@ public class EditorHeader extends JComponent {
@Override
public void actionPerformed(ActionEvent e) {
editor.getSketch().handleNewCode();
- editor.setWatcherSave();
}
};
mapKey = "editor.header.new_tab";
@@ -554,7 +553,6 @@ public class EditorHeader extends JComponent {
Language.text("editor.header.delete.warning.text"), null);
} else {
editor.getSketch().handleDeleteCode();
- editor.setWatcherSave();
}
}
};
diff --git a/core/src/processing/core/PSurfaceAWT.java b/core/src/processing/core/PSurfaceAWT.java
index 35c405b07..c5c6c0c23 100644
--- a/core/src/processing/core/PSurfaceAWT.java
+++ b/core/src/processing/core/PSurfaceAWT.java
@@ -831,10 +831,9 @@ public class PSurfaceAWT implements PSurface {
// canvas.setSize(wide, high);
// frame.setSize(wide, high);
- if (frame != null) { // canvas only
- setFrameSize(); //wide, high);
- }
+ setFrameSize(); //wide, high);
setCanvasSize();
+ frame.setLocationRelativeTo(null);
// if (frame != null) {
// frame.setLocationRelativeTo(null);
// }