Skip to content

Commit a23b459

Browse files
committed
working on change detection
1 parent 2be03ac commit a23b459

3 files changed

Lines changed: 155 additions & 136 deletions

File tree

app/src/processing/app/ChangeDetector.java

Lines changed: 140 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -8,109 +8,36 @@
88
import java.io.FilenameFilter;
99
import java.lang.reflect.InvocationTargetException;
1010

11+
import javax.swing.JOptionPane;
12+
13+
1114
public class ChangeDetector implements WindowFocusListener {
1215
private Sketch sketch;
13-
1416
private Editor editor;
1517

16-
// private boolean enabled = true;
17-
private boolean enabled = true; // broken on OS X (possibly fixed? tested and it seems to work)
18-
18+
private boolean enabled = true;
1919
private boolean skip = false;
2020

21+
2122
public ChangeDetector(Editor editor) {
2223
this.sketch = editor.sketch;
2324
this.editor = editor;
2425
}
2526

26-
@Override
27-
public void windowGainedFocus(WindowEvent e) {
28-
//remove the detector from main if it is disabled during runtime (due to an error?)
29-
if (!enabled || !Preferences.getBoolean("editor.watcher")) {
30-
editor.removeWindowFocusListener(this);
31-
return;
32-
}
33-
//if they selected no, skip the next focus event
34-
if (skip) {
35-
skip = false;
36-
return;
37-
}
38-
checkFileChangeAsync();
39-
}
40-
41-
private void checkFileChangeAsync() {
42-
Thread th = new Thread(new Runnable() {
43-
@Override
44-
public void run() {
45-
checkFileChange();
46-
}
47-
});
48-
th.start();
49-
}
50-
51-
private void showErrorAsync(final String title, final String message,
52-
final Exception e) {
53-
EventQueue.invokeLater(new Runnable() {
54-
@Override
55-
public void run() {
56-
Base.showError(title, message, e);
57-
}
58-
});
59-
}
60-
61-
private void showWarningAsync(final String title, final String message) {
62-
EventQueue.invokeLater(new Runnable() {
63-
@Override
64-
public void run() {
65-
Base.showWarning(title, message);
66-
}
67-
});
68-
}
69-
70-
private int showYesNoQuestionAsync(final Frame editor, final String title,
71-
final String message1,
72-
final String message2) {
73-
final int[] res = { -1 };
74-
try {
75-
//have to wait for a response on this one
76-
EventQueue.invokeAndWait(new Runnable() {
77-
@Override
78-
public void run() {
79-
res[0] = Base.showYesNoQuestion(editor, title, message1, message2);
80-
}
81-
});
82-
} catch (InvocationTargetException e) {
83-
//occurs if Base.showYesNoQuestion throws an error, so, shouldn't happen
84-
e.printStackTrace();
85-
} catch (InterruptedException e) {
86-
//occurs if the EDT is interrupted, so, shouldn't happen
87-
e.printStackTrace();
88-
}
89-
return res[0];
90-
}
91-
92-
private void rebuildHeaderAsync() {
93-
EventQueue.invokeLater(new Runnable() {
94-
@Override
95-
public void run() {
96-
editor.header.rebuild();
97-
}
98-
});
99-
}
10027

10128
private void checkFileChange() {
10229
//check that the content of each of the files in sketch matches what is in memory
10330
if (sketch == null) {
10431
return;
10532
}
10633

107-
//make sure the sketch folder exists at all. if it does not, it will be re-saved, and no changes will be detected
108-
//
34+
// make sure the sketch folder exists at all.
35+
// if it does not, it will be re-saved, and no changes will be detected
10936
sketch.ensureExistence();
110-
//check file count first
37+
38+
// check file count first
11139
File sketchFolder = sketch.getFolder();
112-
int fileCount = sketchFolder.list(new FilenameFilter() {
113-
//return true if the file is a code file for this mode
40+
File[] sketchFiles = sketchFolder.listFiles(new FilenameFilter() {
11441
@Override
11542
public boolean accept(File dir, String name) {
11643
for (String s : editor.getMode().getExtensions()) {
@@ -120,28 +47,28 @@ public boolean accept(File dir, String name) {
12047
}
12148
return false;
12249
}
123-
}).length;
50+
});
51+
int fileCount = sketchFiles.length;
12452

12553
if (fileCount != sketch.getCodeCount()) {
126-
//if they chose to reload and there aren't any files left
54+
// if they chose to reload and there aren't any files left
12755
if (reloadSketch(null) && fileCount < 1) {
12856
try {
12957
//make a blank file
13058
sketch.getMainFile().createNewFile();
13159
} catch (Exception e1) {
13260
//if that didn't work, tell them it's un-recoverable
133-
showErrorAsync("Reload failed", "The sketch contains no code files.",
134-
e1);
61+
showErrorEDT("Reload failed", "The sketch contains no code files.", e1);
13562
//don't try to reload again after the double fail
13663
//this editor is probably trashed by this point, but a save-as might be possible
13764
skip = true;
13865
return;
13966
}
14067
//it's okay to do this without confirmation, because they already confirmed to deleting the unsaved changes above
14168
sketch.reload();
142-
showWarningAsync("Modified Reload",
143-
"You cannot delete the last code file in a sketch.\n"
144-
+ "A new blank sketch file has been generated for you.");
69+
showWarningEDT("Modified Reload",
70+
"You cannot delete the last code file in a sketch.\n" +
71+
"A new blank sketch file has been generated for you.");
14572

14673
}
14774
return;
@@ -150,62 +77,152 @@ public boolean accept(File dir, String name) {
15077
SketchCode[] codes = sketch.getCode();
15178
for (SketchCode sc : codes) {
15279
File sketchFile = sc.getFile();
153-
if (!sketchFile.exists()) {
154-
//if a file in the sketch was not found, then it must have been deleted externally
155-
//so reload the sketch
156-
reloadSketch(sc);
157-
return;
158-
}
159-
//if a file's tab was saved before the file was
160-
if (sketchFile.lastModified() > sc.lastModified()) {
80+
if (sketchFile.exists()) {
81+
long diff = sketchFile.lastModified() - sc.lastModified();
82+
if (diff != 0) {
83+
if (Base.isMacOS() && diff == 1000L) {
84+
// Mac OS X has a one second difference. Not sure if it's a Java bug
85+
// or something else about how OS X is writing files.
86+
continue;
87+
}
88+
System.out.println(sketchFile.getName() + " " + diff);
89+
reloadSketch(sc);
90+
return;
91+
}
92+
} else {
93+
// If a file in the sketch was not found, then it must have been
94+
// deleted externally, so reload the sketch.
16195
reloadSketch(sc);
16296
return;
16397
}
16498
}
16599
}
166100

101+
167102
private void setSketchCodeModified(SketchCode sc) {
168103
sc.setModified(true);
169104
sketch.setModified(true);
170105
}
171106

172-
//returns true if the files in the sketch have been reloaded
173-
private boolean reloadSketch(SketchCode changed) {
174-
//new Exception().printStackTrace(System.out);
175-
int response = showYesNoQuestionAsync(editor,
176-
"File Modified",
177-
"Your sketch has been modified externally.<br>Would you like to reload the sketch?",
178-
"If you reload the sketch, any unsaved changes will be lost!");
179-
if (response == 0) {
180-
//reload the sketch
181107

108+
/**
109+
* @param changed The file that was known to be modified
110+
* @return true if the files in the sketch have been reloaded
111+
*/
112+
private boolean reloadSketch(SketchCode changed) {
113+
int response = blockingYesNoPrompt(editor,
114+
"File Modified",
115+
"Your sketch has been modified externally.<br>" +
116+
"Would you like to reload the sketch?",
117+
"If you reload the sketch, any unsaved changes will be lost.");
118+
if (response == JOptionPane.YES_OPTION) {
182119
sketch.reload();
183-
rebuildHeaderAsync();
120+
rebuildHeaderEDT();
184121
return true;
122+
}
123+
124+
// they said no (or canceled), make it possible to stop the msgs by saving
125+
if (changed != null) {
126+
//set it to be modified so that it will actually save to disk when the user saves from inside processing
127+
setSketchCodeModified(changed);
128+
185129
} else {
186-
//they said no, make it possible for them to stop the errors by saving
187-
if (changed != null) {
188-
//set it to be modified so that it will actually save to disk when the user saves from inside processing
189-
setSketchCodeModified(changed);
190-
} else {
191-
//the number of files changed, so they may be working with a file that doesn't exist any more
192-
//find the files that are missing, and mark them as modified
193-
for (SketchCode sc : sketch.getCode()) {
194-
if (!sc.getFile().exists()) {
195-
setSketchCodeModified(sc);
196-
}
130+
// Because the number of files changed, they may be working with a file
131+
// that doesn't exist any more. So find the files that are missing,
132+
// and mark them as modified so that the next "Save" will write them.
133+
for (SketchCode sc : sketch.getCode()) {
134+
if (!sc.getFile().exists()) {
135+
setSketchCodeModified(sc);
197136
}
198-
//if files were simply added, then nothing needs done
199137
}
200-
rebuildHeaderAsync();
201-
skip = true;
202-
return false;
138+
// If files were simply added, then nothing needs done
203139
}
140+
rebuildHeaderEDT();
141+
skip = true;
142+
return false;
204143
}
205144

145+
206146
@Override
207147
public void windowLostFocus(WindowEvent e) {
208148
//shouldn't need to do anything here
209149
}
210150

151+
152+
@Override
153+
public void windowGainedFocus(WindowEvent e) {
154+
if (enabled) {
155+
//remove the detector from main if it is disabled during runtime (due to an error?)
156+
//if (!enabled || !Preferences.getBoolean("editor.watcher")) {
157+
//editor.removeWindowFocusListener(this);
158+
//} else if (skip) {
159+
160+
// if they selected no, skip the next focus event
161+
if (skip) {
162+
skip = false;
163+
164+
} else {
165+
new Thread(new Runnable() {
166+
@Override
167+
public void run() {
168+
checkFileChange();
169+
}
170+
}).start();
171+
}
172+
}
173+
}
174+
175+
176+
private void showErrorEDT(final String title, final String message,
177+
final Exception e) {
178+
EventQueue.invokeLater(new Runnable() {
179+
@Override
180+
public void run() {
181+
Base.showError(title, message, e);
182+
}
183+
});
184+
}
185+
186+
187+
private void showWarningEDT(final String title, final String message) {
188+
EventQueue.invokeLater(new Runnable() {
189+
@Override
190+
public void run() {
191+
Base.showWarning(title, message);
192+
}
193+
});
194+
}
195+
196+
197+
private int blockingYesNoPrompt(final Frame editor, final String title,
198+
final String message1,
199+
final String message2) {
200+
final int[] result = { -1 }; // yuck
201+
try {
202+
//have to wait for a response on this one
203+
EventQueue.invokeAndWait(new Runnable() {
204+
@Override
205+
public void run() {
206+
result[0] = Base.showYesNoQuestion(editor, title, message1, message2);
207+
}
208+
});
209+
} catch (InvocationTargetException e) {
210+
//occurs if Base.showYesNoQuestion throws an error, so, shouldn't happen
211+
e.getTargetException().printStackTrace();
212+
} catch (InterruptedException e) {
213+
//occurs if the EDT is interrupted, so, shouldn't happen
214+
e.printStackTrace();
215+
}
216+
return result[0];
217+
}
218+
219+
220+
private void rebuildHeaderEDT() {
221+
EventQueue.invokeLater(new Runnable() {
222+
@Override
223+
public void run() {
224+
editor.header.rebuild();
225+
}
226+
});
227+
}
211228
}

app/src/processing/app/Editor.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,8 @@ public void windowGainedFocus(WindowEvent e) {
360360
sketch = null;
361361
}
362362

363-
//add a window listener to watch for changes to the files in the sketch
364-
if (Preferences.getBoolean("editor.watcher")) {
365-
addWindowFocusListener(new ChangeDetector(this));
366-
}
367-
363+
// Add a window listener to watch for changes to the files in the sketch
364+
addWindowFocusListener(new ChangeDetector(this));
368365
}
369366

370367

0 commit comments

Comments
 (0)