From 4ef5c7aa935012231fd7f299f6d0f1b114a83161 Mon Sep 17 00:00:00 2001 From: benfry Date: Sun, 6 Mar 2011 22:48:54 +0000 Subject: [PATCH] examples window implementation --- app/src/processing/app/Base.java | 79 +++++++ app/src/processing/app/Mode.java | 204 +++++++++++++++++- app/src/processing/app/SketchReference.java | 25 +++ .../processing/app/macosx/ThinkDifferent.java | 10 +- app/src/processing/mode/java/JavaMode.java | 11 + todo.txt | 7 +- 6 files changed, 323 insertions(+), 13 deletions(-) create mode 100644 app/src/processing/app/SketchReference.java diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index e83ea4ba8..d92774b97 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -30,6 +30,7 @@ import java.util.*; import java.util.zip.*; import javax.swing.*; +import javax.swing.tree.*; import processing.core.*; import processing.mode.android.AndroidMode; @@ -1192,6 +1193,84 @@ public class Base { } return found; // actually ignored, but.. } + + + protected boolean addSketches(DefaultMutableTreeNode node, File folder) throws IOException { + // skip .DS_Store files, etc (this shouldn't actually be necessary) + if (!folder.isDirectory()) { + return false; + } + + if (folder.getName().equals("libraries")) { + return false; // let's not go there + } + + String[] list = folder.list(); + // If a bad folder or unreadable or whatever, this will come back null + if (list == null) { + return false; + } + + // Alphabetize the list, since it's not always alpha order + Arrays.sort(list, String.CASE_INSENSITIVE_ORDER); + +// ActionListener listener = new ActionListener() { +// public void actionPerformed(ActionEvent e) { +// String path = e.getActionCommand(); +// if (new File(path).exists()) { +// handleOpen(path); +// } else { +// showWarning("Sketch Disappeared", +// "The selected sketch no longer exists.\n" + +// "You may need to restart Processing to update\n" + +// "the sketchbook menu.", null); +// } +// } +// }; + // offers no speed improvement + //menu.addActionListener(listener); + + boolean found = false; + + for (String name : list) { + if (name.charAt(0) == '.') { + continue; + } + +// JTree tree = null; +// TreePath[] a = tree.getSelectionPaths(); +// for (TreePath path : a) { +// Object[] o = path.getPath(); +// } + + File subfolder = new File(folder, name); + if (subfolder.isDirectory()) { + File entry = checkSketchFolder(subfolder, name); + if (entry != null) { +// DefaultMutableTreeNode item = new DefaultMutableTreeNode(name); + DefaultMutableTreeNode item = + new DefaultMutableTreeNode(new SketchReference(name, entry)); +// item.addActionListener(listener); +// item.setActionCommand(entry.getAbsolutePath()); +// menu.add(item); + node.add(item); + found = true; + + } else { + // not a sketch folder, but maybe a subfolder containing sketches +// JMenu submenu = new JMenu(name); + DefaultMutableTreeNode subnode = new DefaultMutableTreeNode(name); + // needs to be separate var otherwise would set ifound to false + boolean anything = addSketches(subnode, subfolder); + if (anything) { + node.add(subnode); + found = true; + } + } + } + } + return found; + } /** diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java index 35985f9a4..93c4d04fc 100644 --- a/app/src/processing/app/Mode.java +++ b/app/src/processing/app/Mode.java @@ -6,6 +6,8 @@ import java.io.*; import java.util.*; import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.tree.*; import processing.app.syntax.*; //import processing.app.tools.Tool; @@ -31,6 +33,9 @@ public abstract class Mode { protected JMenu examplesMenu; // this is for the menubar, not the toolbar protected JMenu importMenu; +// protected JTree examplesTree; + protected JFrame examplesFrame; + // popup menu used for the toolbar protected JMenu toolbarMenu; @@ -159,9 +164,16 @@ public abstract class Mode { }); toolbarMenu.add(item); - JMenu examplesMenu = new JMenu("Examples"); - rebuildExamplesMenu(examplesMenu, true); - toolbarMenu.add(examplesMenu); +// JMenu examplesMenu = new JMenu("Examples"); +// rebuildExamplesMenu(examplesMenu, true); + item = new JMenuItem("Examples..."); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + showExamplesFrame(); + } + }); + toolbarMenu.add(item); +// toolbarMenu.add(examplesMenu); toolbarMenu.addSeparator(); @@ -253,11 +265,8 @@ public abstract class Mode { public void rebuildExamplesMenu(JMenu menu, boolean replace) { try { // break down the examples folder for examples - File[] subfolders = examplesFolder.listFiles(new FilenameFilter() { - public boolean accept(File dir, String name) { - return dir.isDirectory() && name.charAt(0) != '.'; - } - }); + File[] subfolders = getExampleCategoryFolders(); + for (File sub : subfolders) { Base.addDisabledItem(menu, sub.getName()); // JMenuItem categoryItem = new JMenuItem(sub.getName()); @@ -305,6 +314,185 @@ public abstract class Mode { } + + /** + * Override this to control the order of the first set of example folders + * and how they appear in the examples window. + */ + protected File[] getExampleCategoryFolders() { + return examplesFolder.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return dir.isDirectory() && name.charAt(0) != '.'; + } + }); + } + + + public JTree buildExamplesTree() { + DefaultMutableTreeNode node = new DefaultMutableTreeNode("Examples"); + + JTree examplesTree = new JTree(node); +// rebuildExamplesTree(node); +// } + + //DefaultTreeCellRenderer renderer = tree. +// TreeCellRenderer tcr = examplesTree.getCellRenderer(); + + // +// +// public void rebuildExamplesTree(DefaultMutableTreeNode node) { + try { + // break down the examples folder for examples +// File[] subfolders = examplesFolder.listFiles(new FilenameFilter() { +// public boolean accept(File dir, String name) { +// return dir.isDirectory() && name.charAt(0) != '.'; +// } +// }); + File[] subfolders = getExampleCategoryFolders(); + +// DefaultMutableTreeNode examplesParent = new DefaultMutableTreeNode("Examples"); + for (File sub : subfolders) { + DefaultMutableTreeNode subNode = new DefaultMutableTreeNode(sub.getName()); + if (base.addSketches(subNode, sub)) { +// examplesParent.add(subNode); + node.add(subNode); + } + } +// node.add(examplesParent); +// examplesTree.expandPath(new TreePath(examplesParent)); + + // get library examples + DefaultMutableTreeNode libParent = new DefaultMutableTreeNode("Libraries"); + for (Library lib : coreLibraries) { + if (lib.hasExamples()) { +// JMenu libMenu = new JMenu(lib.getName()); + DefaultMutableTreeNode libNode = new DefaultMutableTreeNode(lib.getName()); +// base.addSketches(libMenu, lib.getExamplesFolder(), replace); + base.addSketches(libNode, lib.getExamplesFolder()); +// menu.add(libMenu); + libParent.add(libNode); + } + } + node.add(libParent); + + // get contrib library examples + boolean any = false; + for (Library lib : contribLibraries) { + if (lib.hasExamples()) { + any = true; + } + } + if (any) { +// menu.addSeparator(); + DefaultMutableTreeNode contribParent = new DefaultMutableTreeNode("Contributed Libraries"); +// Base.addDisabledItem(menu, "Contributed"); + for (Library lib : contribLibraries) { + if (lib.hasExamples()) { +// JMenu libMenu = new JMenu(lib.getName()); + DefaultMutableTreeNode libNode = new DefaultMutableTreeNode(lib.getName()); +// base.addSketches(libMenu, lib.getExamplesFolder(), replace); + base.addSketches(libNode, lib.getExamplesFolder()); +// menu.add(libMenu); + contribParent.add(libNode); + } + } + node.add(contribParent); + } + } catch (IOException e) { + e.printStackTrace(); + } + return examplesTree; + } + + + public void showExamplesFrame() { + if (examplesFrame == null) { + examplesFrame = new JFrame("Examples"); + final JTree tree = buildExamplesTree(); + + tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + tree.setShowsRootHandles(true); + // expand the root + tree.expandRow(0); + // now hide the root + tree.setRootVisible(false); + // now expand the other folks + for (int row = tree.getRowCount()-1; row >= 0; --row) { + tree.expandRow(row); + } + + /* + tree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) + tree.getLastSelectedPathComponent(); + + if (node != null) { + Object nodeInfo = node.getUserObject(); + if (node.isLeaf()) { + System.out.println(node + " user obj: " + nodeInfo); + // BookInfo book = (BookInfo)nodeInfo; + // displayURL(book.bookURL); + } + } + } + }); + */ + tree.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 1) { + DefaultMutableTreeNode node = + (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + if (node != null && node.isLeaf()) { +// File sketch = (File) node.getUserObject(); + +// base.handleOpen(sketch.getAbsolutePath()); +// System.out.println(node + " user obj: " + node.getUserObject()); + + SketchReference sketch = (SketchReference) node.getUserObject(); + base.handleOpen(sketch.getPath()); + } + } + } + }); + tree.addKeyListener(new KeyAdapter() { + public void keyTyped(KeyEvent e) { +// System.out.println(e); + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + DefaultMutableTreeNode node = + (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + if (node != null && node.isLeaf()) { +// System.out.println(node + " user obj: " + node.getUserObject()); +// File sketch = (File) node.getUserObject(); +// base.handleOpen(sketch.getAbsolutePath()); + +// Object[] obj = (Object[]) node.getUserObject(); +// base.handleOpen(((File) obj[1]).getAbsolutePath()); + SketchReference sketch = (SketchReference) node.getUserObject(); + base.handleOpen(sketch.getPath()); + } + } else if (e.getKeyChar() == KeyEvent.VK_ESCAPE) { + examplesFrame.setVisible(false); + } + } + }); + + tree.setBorder(new EmptyBorder(5, 5, 5, 5)); + JScrollPane treeView = new JScrollPane(tree); + treeView.setPreferredSize(new Dimension(250, 450)); + examplesFrame.add(treeView); + examplesFrame.pack(); + } + if (base.activeEditor != null) { + Point p = base.activeEditor.getLocation(); + examplesFrame.setLocation(p.x - examplesFrame.getWidth() - 20, p.y); + } else { + examplesFrame.setLocationRelativeTo(null); + } + examplesFrame.setVisible(true); + } + + // public void handleActivated(Editor editor) { // //// re-add the sub-menus that are shared by all windows // fileMenu.insert(Base.sketchbookMenu, 2); diff --git a/app/src/processing/app/SketchReference.java b/app/src/processing/app/SketchReference.java new file mode 100644 index 000000000..7e55f2321 --- /dev/null +++ b/app/src/processing/app/SketchReference.java @@ -0,0 +1,25 @@ +package processing.app; + +import java.io.File; + + +public class SketchReference { + String name; + File pde; + + + public SketchReference(String name, File pde) { + this.name = name; + this.pde = pde; + } + + + public String getPath() { + return pde.getAbsolutePath(); + } + + + public String toString() { + return name; + } +} \ No newline at end of file diff --git a/app/src/processing/app/macosx/ThinkDifferent.java b/app/src/processing/app/macosx/ThinkDifferent.java index b0e2cee5c..9f1774e40 100644 --- a/app/src/processing/app/macosx/ThinkDifferent.java +++ b/app/src/processing/app/macosx/ThinkDifferent.java @@ -124,7 +124,15 @@ public class ThinkDifferent implements ApplicationListener { fileMenu.add(item); fileMenu.add(base.getSketchbookMenu()); - fileMenu.add(base.nextEditorMode().getExamplesMenu()); + +// fileMenu.add(base.nextEditorMode().getExamplesMenu()); + item = new JMenuItem("Examples..."); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + base.nextEditorMode().showExamplesFrame(); + } + }); + fileMenu.add(item); return fileMenu; } diff --git a/app/src/processing/mode/java/JavaMode.java b/app/src/processing/mode/java/JavaMode.java index 441d9ceb1..1375318e3 100644 --- a/app/src/processing/mode/java/JavaMode.java +++ b/app/src/processing/mode/java/JavaMode.java @@ -139,6 +139,17 @@ public class JavaMode extends Mode { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + protected File[] getExampleCategoryFolders() { + // Basics, Topics, 3D, Books + return new File[] { + new File(examplesFolder, "Basics"), + new File(examplesFolder, "Topics"), + new File(examplesFolder, "3D"), + new File(examplesFolder, "Books") + }; + } + + public String getDefaultExtension() { return "pde"; } diff --git a/todo.txt b/todo.txt index bafcf77ce..d8bdca77c 100644 --- a/todo.txt +++ b/todo.txt @@ -13,6 +13,8 @@ X move compiler to mode.java.* instead of runner X fix the encoding on OS X for the "Fix Encoding and Reload" function X broken link on ye olde' http://processing.org/bugs/bugzilla X http://code.google.com/p/processing/issues/detail?id=528 +X hex value from color picker does not start with # +X http://code.google.com/p/processing/issues/detail?id=529 fixed in 0192 J auto-format screws up if/else/else if blocks @@ -92,8 +94,8 @@ X Basics, Topics, 3D, Books, Libraries, Contributed Libraries X 'book' examples will be another category X i'll add vida examples, can offer to others if they want X should be "Getting Started" not GettingStarted +X window that opens and contains list of examples _ examples button on toolbar? -_ window that opens and contains list of examples _ also, move open to a submenu? _ then we'd have open / recent / sketchbook @@ -147,9 +149,6 @@ _ http://www.cert.org/blogs/vuls/2008/06/signed_java_security_worse_tha.html _ strange window flicker when first opened -_ hex value from color picker does not start with # -_ http://code.google.com/p/processing/issues/detail?id=529 - http://stackoverflow.com/questions/1611357/how-to-make-a-jar-file-that-include-dll-files _ p5 assets need to be licensed differently from the source