mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
working on change detection
This commit is contained in:
@@ -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.<br>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.<br>" +
|
||||
"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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user