From a26c155b430c569a63e622010d7dbc4f26c415e2 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Fri, 19 May 2017 13:49:28 +0200 Subject: [PATCH 1/4] Run change detector on EDT --- app/src/processing/app/ui/ChangeDetector.java | 189 ++++++++---------- 1 file changed, 83 insertions(+), 106 deletions(-) diff --git a/app/src/processing/app/ui/ChangeDetector.java b/app/src/processing/app/ui/ChangeDetector.java index 7554abf4e..a5efd8dda 100644 --- a/app/src/processing/app/ui/ChangeDetector.java +++ b/app/src/processing/app/ui/ChangeDetector.java @@ -1,11 +1,9 @@ package processing.app.ui; -import java.awt.EventQueue; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -13,13 +11,10 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; -import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; -import java.util.stream.Stream; import processing.app.Language; import processing.app.Messages; -import processing.app.Platform; import processing.app.Preferences; import processing.app.Sketch; import processing.app.SketchCode; @@ -59,12 +54,7 @@ public class ChangeDetector implements WindowFocusListener { // if it does not, it will be re-saved, and no changes will be detected sketch.ensureExistence(); // <- touches UI, stay on EDT - // TODO: Not sure if we even need to run this async. Usually takes - // just a few ms and we probably want to prevent any changes from - // users until the external changes are sorted out. [jv 2016-12-05] - - // Run task in common pool, starting threads directly is so Java 6 - ForkJoinPool.commonPool().execute(this::checkFiles); + checkFiles(); } } } @@ -77,8 +67,7 @@ public class ChangeDetector implements WindowFocusListener { } - // Synchronize, we are running async and touching fields - private synchronized void checkFiles() { + private void checkFiles() { List filenames = new ArrayList<>(); List extensions = new ArrayList<>(); sketch.getSketchCodeFiles(filenames, extensions); @@ -166,113 +155,101 @@ public class ChangeDetector implements WindowFocusListener { } - // This has to happen in one go and also touches UI everywhere. It has to - // run on EDT, otherwise windowGainedFocus callback runs again right after - // dismissing the prompt and we get another prompt before we even finished. - try { - // Wait for EDT to finish its business - // We need to stay in synchronized scope because of ignore lists - EventQueue.invokeAndWait(() -> { - // No prompt yet. - if (changes) { - for (int i = 0; i < filenames.size(); i++) { - for (String addedTab : addedFilenames) { - if (filenames.get(i).equals(addedTab)) { - sketch.loadNewTab(filenames.get(i), extensions.get(i), true); - } - } + // No prompt yet. + if (changes) { + for (int i = 0; i < filenames.size(); i++) { + for (String addedTab : addedFilenames) { + if (filenames.get(i).equals(addedTab)) { + sketch.loadNewTab(filenames.get(i), extensions.get(i), true); } - for (SketchCode modifiedCode : modifiedCodesFinal) { - if (!mergeConflicts.contains(modifiedCode)) { - sketch.loadNewTab(modifiedCode.getFileName(), - modifiedCode.getExtension(), false); - } - } - - // Destructive actions, so prompt. - if (ask) { - sketch.updateSketchCodes(); - - showReloadPrompt(mergeConflicts, removedCodesFinal, - scReload -> { - try { - File file = scReload.getFile(); - File autosave = File.createTempFile(scReload.getPrettyName(), - ".autosave", file.getParentFile()); - scReload.copyTo(autosave); - } catch (IOException e) { - Messages.showWarning("Could not autosave modified tab", - "Your changes to " + scReload.getPrettyName() + - " have not been saved, so we won't load the new version.", e); - scReload.setModified(true); // So we'll have another go at saving - // it later, - ignoredModifications.add(scReload); // but not create a loop. - return; - } - sketch.loadNewTab(scReload.getFileName(), scReload.getExtension(), false); - }, - scKeep -> { - scKeep.setLastModified(); - scKeep.setModified(true); - }, - scDelete -> sketch.removeCode(scDelete), - scResave -> { - try { - scResave.save(); - } catch (IOException e) { - if (sketch.getCode(0).equals(scResave)) { - // Not a fatal error; the sketch has to stay open if - // they're going to save the code that's in it. - Messages.showWarning( - scResave.getFileName() + " deleted and not re-saved", - "Your main tab was deleted, and Processing couldn't " + - "resave it.\nYour sketch won't work without the " + - "main tab.", e); - } else { - Messages.showWarning("Could not re-save deleted tab", - "Your copy of " + scResave.getPrettyName() + - " will stay in the editor.", e); - } - ignoredRemovals.add(scResave); - scResave.setModified(true); // So we'll have another go at - // saving it later. - } - } - ); - } - editor.rebuildHeader(); - sketch.handleNextCode(); - sketch.handlePrevCode(); - editor.repaintHeader(); - - // Sketch was reloaded, clear ignore lists - //ignoredAdditions.clear(); - //ignoredRemovals.clear(); - - return; } + } + for (SketchCode modifiedCode : modifiedCodesFinal) { + if (!mergeConflicts.contains(modifiedCode)) { + sketch.loadNewTab(modifiedCode.getFileName(), + modifiedCode.getExtension(), false); + } + } - // If something changed, set modified flags and modification times - if (!removedCodes.isEmpty() || !modifiedCodesFinal.isEmpty()) { + // Destructive actions, so prompt. + if (ask) { + sketch.updateSketchCodes(); + + showReloadPrompt(mergeConflicts, removedCodesFinal, + scReload -> { + try { + File file = scReload.getFile(); + File autosave = File.createTempFile(scReload.getPrettyName(), + ".autosave", file.getParentFile()); + scReload.copyTo(autosave); + } catch (IOException e) { + Messages.showWarning("Could not autosave modified tab", + "Your changes to " + scReload.getPrettyName() + + " have not been saved, so we won't load the new version.", e); + scReload.setModified(true); // So we'll have another go at saving + // it later, + ignoredModifications.add(scReload); // but not create a loop. + return; + } + sketch.loadNewTab(scReload.getFileName(), scReload.getExtension(), false); + }, + scKeep -> { + scKeep.setLastModified(); + scKeep.setModified(true); + }, + scDelete -> sketch.removeCode(scDelete), + scResave -> { + try { + scResave.save(); + } catch (IOException e) { + if (sketch.getCode(0).equals(scResave)) { + // Not a fatal error; the sketch has to stay open if + // they're going to save the code that's in it. + Messages.showWarning( + scResave.getFileName() + " deleted and not re-saved", + "Your main tab was deleted, and Processing couldn't " + + "resave it.\nYour sketch won't work without the " + + "main tab.", e); + } else { + Messages.showWarning("Could not re-save deleted tab", + "Your copy of " + scResave.getPrettyName() + + " will stay in the editor.", e); + } + ignoredRemovals.add(scResave); + scResave.setModified(true); // So we'll have another go at + // saving it later. + } + } + ); + } + editor.rebuildHeader(); + sketch.handleNextCode(); + sketch.handlePrevCode(); + editor.repaintHeader(); + + // Sketch was reloaded, clear ignore lists + //ignoredAdditions.clear(); + //ignoredRemovals.clear(); + + return; + } + + // If something changed, set modified flags and modification times + if (!removedCodes.isEmpty() || !modifiedCodesFinal.isEmpty()) { // Stream.concat(removedCodes.stream(), modifiedCodesFinal.stream()) // .forEach(code -> { // code.setModified(true); // code.setLastModified(); // }); - // Not sure if this is needed - editor.rebuildHeader(); - } - }); - } catch (InterruptedException ignore) { - } catch (InvocationTargetException e) { - Messages.loge("exception in ChangeDetector", e); + // Not sure if this is needed + editor.rebuildHeader(); } } /** - * Prompt the user what do do about each tab. Passes the tab to the user's + * Prompt the user what to do about each tab. Passes the tab to the user's * choice of Consumer. Won't let you delete the main tab. */ private void showReloadPrompt( From 382d23f97e127b29b127fa704edb352774e4ea49 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Fri, 19 May 2017 17:01:59 +0200 Subject: [PATCH 2/4] Remove old code from change detector --- app/src/processing/app/ui/ChangeDetector.java | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/app/src/processing/app/ui/ChangeDetector.java b/app/src/processing/app/ui/ChangeDetector.java index a5efd8dda..be48d66e0 100644 --- a/app/src/processing/app/ui/ChangeDetector.java +++ b/app/src/processing/app/ui/ChangeDetector.java @@ -24,7 +24,6 @@ public class ChangeDetector implements WindowFocusListener { private final Sketch sketch; private final Editor editor; - //private List ignoredAdditions = new ArrayList<>(); private List ignoredRemovals = new ArrayList<>(); private List ignoredModifications = new ArrayList<>(); @@ -52,7 +51,7 @@ public class ChangeDetector implements WindowFocusListener { if (sketch != null) { // 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(); // <- touches UI, stay on EDT + sketch.ensureExistence(); checkFiles(); } @@ -90,11 +89,6 @@ public class ChangeDetector implements WindowFocusListener { .filter(f -> !codeFilenames.contains(f)) .collect(Collectors.toList()); - // Added files that are actually candidates for a new tab - //List addedTabsFinal = addedFilenames.stream() - // .filter(f -> !ignoredAdditions.contains(f)) - // .collect(Collectors.toList()); - // Take action if there are any added files which were not previously ignored boolean added = !addedFilenames.isEmpty(); @@ -147,8 +141,6 @@ public class ChangeDetector implements WindowFocusListener { System.out.println("ask: " + ask + "\n" + "merge conflicts: " + mergeConflicts + ",\n" + "added filenames: " + addedFilenames + ",\n" + - // "added final: " + addedTabsFinal + ",\n" + - // "ignored added: " + ignoredAdditions + ",\n" + "removed codes: " + removedCodes + ",\n" + "ignored removed: " + ignoredRemovals + ",\n" + "modified codes: " + modifiedCodesFinal + "\n"); @@ -226,25 +218,8 @@ public class ChangeDetector implements WindowFocusListener { sketch.handleNextCode(); sketch.handlePrevCode(); editor.repaintHeader(); - - // Sketch was reloaded, clear ignore lists - //ignoredAdditions.clear(); - //ignoredRemovals.clear(); - - return; } - // If something changed, set modified flags and modification times - if (!removedCodes.isEmpty() || !modifiedCodesFinal.isEmpty()) { -// Stream.concat(removedCodes.stream(), modifiedCodesFinal.stream()) -// .forEach(code -> { -// code.setModified(true); -// code.setLastModified(); -// }); - - // Not sure if this is needed - editor.rebuildHeader(); - } } From 9c2352fa0314e9c9b8c8455e6fa35ab03100e8f9 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Fri, 19 May 2017 17:33:40 +0200 Subject: [PATCH 3/4] Notify Editor from Change Detector to run error check --- app/src/processing/app/ui/ChangeDetector.java | 2 ++ app/src/processing/app/ui/Editor.java | 2 ++ java/src/processing/mode/java/JavaEditor.java | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/app/src/processing/app/ui/ChangeDetector.java b/app/src/processing/app/ui/ChangeDetector.java index be48d66e0..2bad61f80 100644 --- a/app/src/processing/app/ui/ChangeDetector.java +++ b/app/src/processing/app/ui/ChangeDetector.java @@ -218,6 +218,8 @@ public class ChangeDetector implements WindowFocusListener { sketch.handleNextCode(); sketch.handlePrevCode(); editor.repaintHeader(); + + editor.sketchChanged(); } } diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java index 262ff8903..4cdc9817a 100644 --- a/app/src/processing/app/ui/Editor.java +++ b/app/src/processing/app/ui/Editor.java @@ -1125,6 +1125,8 @@ public abstract class Editor extends JFrame implements RunnerListener { public void codeFolderChanged() { } + public void sketchChanged() { } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index e340ee7ac..562efca8a 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -1274,6 +1274,12 @@ public class JavaEditor extends Editor { } + @Override + public void sketchChanged() { + preprocessingService.notifySketchChanged(); + } + + public void statusError(String what) { super.statusError(what); // new Exception("deactivating RUN").printStackTrace(); From 17b9a6480d3403ddb4b16be4b0539bd3d208eefd Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Fri, 19 May 2017 17:34:49 +0200 Subject: [PATCH 4/4] PPS: fall back to sketchcode.program if sketchcode.document is null --- .../mode/java/pdex/PreprocessingService.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/java/src/processing/mode/java/pdex/PreprocessingService.java b/java/src/processing/mode/java/pdex/PreprocessingService.java index 0827e3ffe..5e9d3f0bf 100644 --- a/java/src/processing/mode/java/pdex/PreprocessingService.java +++ b/java/src/processing/mode/java/pdex/PreprocessingService.java @@ -274,10 +274,14 @@ public class PreprocessingService { for (SketchCode sc : sketch.getCode()) { if (sc.isExtension("pde")) { tabStartsList.append(workBuffer.length()); - try { - workBuffer.append(sc.getDocumentText()); - } catch (BadLocationException e) { - e.printStackTrace(); + if (sc.getDocument() != null) { + try { + workBuffer.append(sc.getDocumentText()); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } else { + workBuffer.append(sc.getProgram()); } workBuffer.append('\n'); }