diff --git a/processing/app/PdeBase.java b/processing/app/PdeBase.java index a3de374a7..ba8e4f1a5 100644 --- a/processing/app/PdeBase.java +++ b/processing/app/PdeBase.java @@ -1,9 +1,10 @@ import java.awt.*; -import java.applet.Applet; +import java.awt.event.*; +//import java.applet.Applet; import java.io.*; import java.net.*; import java.util.*; -import java.awt.event.*; +import java.util.zip.*; public class PdeBase implements ActionListener { @@ -20,6 +21,15 @@ public class PdeBase implements ActionListener { File sketchbookFolder; String sketchbookPath; + boolean recordingHistory; + Menu historyMenu; + ActionListener historyMenuListener = + new ActionListener() { + public void actionPerformed(ActionEvent e) { + editor.retrieveHistory(e.getActionCommand()); + } + }; + static final String WINDOW_TITLE = "Proce55ing"; // the platforms @@ -163,6 +173,24 @@ public class PdeBase implements ActionListener { menu.add(new MenuItem("Present", new MenuShortcut('P'))); menu.add(new MenuItem("Stop")); menu.addSeparator(); + + recordingHistory = getBoolean("history.recording", true); + if (recordingHistory) { + historyMenu = new Menu("History"); + menu.add(historyMenu); + item = new MenuItem("Clear History"); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (!editor.historyFile.delete()) { + System.err.println("couldn't erase history"); + } + rebuildHistoryMenu(historyMenu, editor.historyFile.getPath()); + } + }); + menu.add(item); + menu.addSeparator(); + } + item = new MenuItem("Beautify", new MenuShortcut('B')); item.setEnabled(false); menu.add(item); @@ -235,7 +263,6 @@ public class PdeBase implements ActionListener { } } - public void rebuildSketchbookMenu() { rebuildSketchbookMenu(sketchbookMenu); } @@ -334,6 +361,88 @@ public class PdeBase implements ActionListener { } + /* + class HistoryMenuListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + editor.selectHistory(e.getActionCommand); + } + } + */ + + public void rebuildHistoryMenu(String path) { + rebuildHistoryMenu(historyMenu, path); + } + + public void rebuildHistoryMenu(Menu menu, String path) { + if (!recordingHistory) return; + + menu.removeAll(); + File hfile = new File(path); + if (!hfile.exists()) return; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(path)))); + String line = null; + + int historyCount = 0; + String historyList[] = new String[100]; + + try { + while ((line = reader.readLine()) != null) { + //while (line = reader.readLine()) { + //while (true) { line = reader.readLine(); + //if (line == null) continue; + //System.out.println("line: " + line); + if (line.equals(PdeEditor.HISTORY_SEPARATOR)) { + // next line is the good stuff + line = reader.readLine(); + int version = + Integer.parseInt(line.substring(0, line.indexOf(' '))); + if (version == 1) { + String whysub = line.substring(2); // after "1 " + String why = whysub.substring(0, whysub.indexOf(" -")); + //System.out.println("'" + why + "'"); + + String readable = line.substring(line.lastIndexOf("-") + 2); + if (historyList.length == historyCount) { + String temp[] = new String[historyCount*2]; + System.arraycopy(historyList, 0, temp, 0, historyCount); + historyList = temp; + } + historyList[historyCount++] = why + " - " + readable; + + } // otherwise don't know what to do + } + } + //System.out.println(line); + } catch (IOException e) { + e.printStackTrace(); + } + + // add the items to the menu in reverse order + /* + ActionListener historyMenuListener = + new ActionListener() { + public void actionPerformed(ActionEvent e) { + editor.retrieveHistory(e.getActionCommand()); + } + }; + */ + + for (int i = historyCount-1; i >= 0; --i) { + MenuItem mi = new MenuItem(historyList[i]); + mi.addActionListener(historyMenuListener); + menu.add(mi); + } + + reader.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void actionPerformed(ActionEvent event) { String command = event.getActionCommand(); //System.out.println(command); diff --git a/processing/app/PdeEditor.java b/processing/app/PdeEditor.java index ef0f48ec4..81c6fe08c 100644 --- a/processing/app/PdeEditor.java +++ b/processing/app/PdeEditor.java @@ -18,6 +18,9 @@ public class PdeEditor extends Panel { // set to blank, it's preferredSize() will be fukered static final String EMPTY = " "; + static final String HISTORY_SEPARATOR = + "#################################################"; + static final int SK_NEW = 1; static final int SK_OPEN = 2; static final int DO_OPEN = 3; @@ -26,6 +29,10 @@ public class PdeEditor extends Panel { String openingPath; String openingName; + static final int RUN = 5; // for history + static final int SAVE = 6; + static final int AUTO = 7; + PdeEditorButtons buttons; PdeEditorHeader header; PdeEditorStatus status; @@ -39,6 +46,11 @@ public class PdeEditor extends Panel { File sketchDir; // if a sketchbook project, the parent dir boolean sketchModified; + File historyFile; + //OutputStream historyStream; + //PrintWriter historyWriter; + String historyLast; + //String lastDirectory; //String lastFile; @@ -178,6 +190,144 @@ public class PdeEditor extends Panel { } + // mode is RUN, SAVE or AUTO + public void makeHistory(String program, int mode) { + if (!base.recordingHistory) return; + + if (historyLast.equals(program)) return; + + String modeStr = (mode == RUN) ? "run" : ((mode == SAVE) ? "save" : "autosave"); + + try { + //PrintWriter historyWriter = new PrintWriter(new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(historyFile.getPath(), true)))); + ByteArrayOutputStream old = null; + if (historyFile.exists()) { + InputStream oldStream = new GZIPInputStream(new BufferedInputStream(new FileInputStream(historyFile))); + old = new ByteArrayOutputStream(); + + int c = oldStream.read(); + while (c != -1) { + old.write(c); + c = oldStream.read(); + } + //return out.toByteArray(); + oldStream.close(); + } + + OutputStream historyStream = + new GZIPOutputStream(new FileOutputStream(historyFile)); + //byte[] buffer = new byte[16384]; + //int bytesRead; + //while ((bytesRead = oldStream.read(buffer)) != -1) { + //historyStream.write(buffer, 0, bytesRead); + //} + if (old != null) { + historyStream.write(old.toByteArray()); + } + PrintWriter historyWriter = + new PrintWriter(new OutputStreamWriter(historyStream)); + //PrintWriter historyWriter = new PrintWriter(new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(historyFile.getPath(), true)))); + + historyWriter.println(); + historyWriter.println(HISTORY_SEPARATOR); + + Calendar now = Calendar.getInstance(); + // 2002 06 18 11 43 29 + // when listing, study for descrepancies.. if all are + // 2002, then don't list the year and soforth. + // for the other end, if all minutes are unique, + // then don't show seconds + int year = now.get(Calendar.YEAR); + int month = now.get(Calendar.MONTH) + 1; + int day = now.get(Calendar.DAY_OF_MONTH); + int hour = now.get(Calendar.HOUR_OF_DAY); + int minute = now.get(Calendar.MINUTE); + int second = now.get(Calendar.SECOND); + String parseDate = year + " " + month + " " + day + " " + + hour + " " + minute + " " + second; + + String readableDate = now.getTime().toString(); + + // increment this so sketchbook won't be mangled + // each time this format has to change + String historyVersion = "1"; + //Date date = new Date(); + //String datestamp = date.toString(); + + historyWriter.println(historyVersion + " " + modeStr + " - " + + parseDate + " - " + readableDate); + historyWriter.println(); + historyWriter.println(program); + historyWriter.flush(); // ?? + historyLast = program; + + MenuItem menuItem = new MenuItem(modeStr + " - " + readableDate); + menuItem.addActionListener(base.historyMenuListener); + base.historyMenu.insert(menuItem, 0); + + historyWriter.flush(); + historyWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + + public void retrieveHistory(String selection) { + //System.out.println("sel '" + selection + "'"); + String readableDate = + selection.substring(selection.indexOf("-") + 2); + + // make history for the current guy + makeHistory(textarea.getText(), AUTO); + // mark editor text as having been edited + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(historyFile)))); + String line = null; + + int historyCount = 0; + String historyList[] = new String[100]; + + try { + boolean found = false; + while ((line = reader.readLine()) != null) { + //System.out.println("->" + line); + if (line.equals(PdeEditor.HISTORY_SEPARATOR)) { + line = reader.readLine(); + if (line.indexOf(readableDate) != -1) { // this is the one + found = true; + break; + } + } + } + if (found) { + // read lines until the next separator + textarea.setText(""); + line = reader.readLine(); // ignored + String sep = System.getProperty("line.separator"); + while ((line = reader.readLine()) != null) { + if (line.equals(PdeEditor.HISTORY_SEPARATOR)) break; + textarea.append(line + sep); + //System.out.println("'" + line + "'"); + } + historyLast = textarea.getText(); + setSketchModified(false); + + } else { + System.err.println("couldn't find history entry for " + + "'" + readableDate + "'"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void doRun(boolean presentation) { //doStop(); doClose(); @@ -189,6 +339,8 @@ public class PdeEditor extends Panel { try { String program = textarea.getText(); + makeHistory(program, RUN); + //if (program.length() != 0) { String buildPath = "lib" + File.separator + "build"; // TEMPORARY File buildDir = new File(buildPath); @@ -594,6 +746,7 @@ public class PdeEditor extends Panel { FileInputStream input = new FileInputStream(isketchFile); int length = (int) isketchFile.length(); + String program = ""; if (length != 0) { byte data[] = new byte[length]; @@ -611,7 +764,9 @@ public class PdeEditor extends Panel { //textarea.setText(app.languageEncode(data)); // what the hell was i thinking when i wrote this code //if (app.encoding == null) - textarea.setText(new String(data)); + program = new String(data); + //textarea.setText(new String(data)); + textarea.setText(program); //System.out.println(" loading program = " + new String(data)); //else //textarea.setText(new String(data, app.encoding)); @@ -625,6 +780,17 @@ public class PdeEditor extends Panel { sketchDir = isketchDir; setSketchModified(false); + historyFile = new File(sketchFile.getParent(), "history.gz"); + base.rebuildHistoryMenu(historyFile.getPath()); + + //if (historyFile.exists()) { + //int vlength = (int) historyFile.length(); + //historyWriter = new PrintWriter(new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(historyFile.getPath(), true)))); + //historyWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(historyFile.getPath(), true))); + historyLast = program; + //System.out.println("history is at " + historyFile.getPath()); + //} + //header.setProject(file.getName(), projectDir); header.reset(); @@ -644,6 +810,7 @@ public class PdeEditor extends Panel { public void doSave() { // true if lastfile not set, otherwise false, meaning no prompt //handleSave(lastFile == null); + // actually, this will always be false... handleSave(sketchName == null); } @@ -674,6 +841,7 @@ public class PdeEditor extends Panel { return; // user cancelled } } + makeHistory(s, SAVE); File file = new File(directory, filename); try { FileWriter writer = new FileWriter(file); diff --git a/processing/todo.txt b/processing/todo.txt index a2dc8ecd0..848738741 100644 --- a/processing/todo.txt +++ b/processing/todo.txt @@ -15,6 +15,29 @@ X changed error color slightly for console to fit status error X size() not being called in setup is gonna cause lots of headaches X hack: put exception handler around setup and re-call if necessary X linefeeds were wrong in BApplet +X for people visiting site, what os are they using? +X saving to gzipped 'versions' file +X autosave every few minutes, also on each compile, also on save +X mark each as 'save', 'autosave', 'failed' or 'successful' compile +X also include a timestamp +X if a selection is made from the menu: +X autosave, replace text, mark as edited +X if there have been no edits, and last thing was hist change, +X should *not* do another autosave +X ensure this by historyLast being set on change.. heh. nice. + +dammit we need a text editor. +i'm gonna get sick of people bitching about it. +also an interesting possibility--> + use terminal emulator, and run iostream from process + use pooterm stuff for the emulation window + key commands would conflict + but could use emacs under osx, linux + use nano (maybe emacs?) under windows + and nothing for macos9 + +class unloading, or "full java mode" will be beta + or only be allowed under the 'use external editor' scenario bagel a _ do some serial testing @@ -25,10 +48,6 @@ a _ breaks on every 2nd run when using serial apps (or others?) a _ try calling gc on stop as well pde -a _ saving to gzipped 'versions' file -a _ autosave every few minutes, also on each compile, also on save -a _ mark each as 'save', 'autosave', 'failed' or 'successful' compile -a _ also include a timestamp a _ make scrollbar for console a _ remove projects if created but nothing happens to them a _ option to delete current project