Skip to content
This repository

update-tree! for updating JTree #50

Open
wants to merge 2 commits into from

2 participants

Jonathan Fischer Friberg Dave Ray
Jonathan Fischer Friberg

Update a tree and keep expanded nodes expanded.

Dave Ray
Owner

Hey. Thanks. A couple issues and then an idea I'd like your opinion on:

  • Most clojure code I've seen uses "-" instead of "_" in symbols. Not a huge deal, but it looks a little odd to me.
  • I think that the proper way to refresh the tree (or any widget) is to use (seesaw.core/repaint!). updateUI is meant to refresh the tree when the look and feel changes. Also, ideally, if the tree model is being used correctly, the tree should repaint automatically as it's changed and rarely require a manual repaint.

Now for the idea. It seems like this function is doing at least a couple things that could be broken out. The most important capability is the expansion state maintenance. What do you think about splitting that out into it's own function? Something like:

(defn with-expansion-state* [tree f & args]
  (... store expanded paths ...)
  (apply f args)
  (... restore expanded paths ...)
  return tree)

and then a companion macro with which you could do what update-tree! does:

(with-expansion-state tree
    (config! tree :model new-model))

or

(with-expansion-state tree
    (repaint! tree))

This nicely encapsulates the expansion pattern and makes it reusable in other places as well.

Thoughts?

Jonathan Fischer Friberg

First: (if model model (.getModel tree)) is a relic, and should definitely not be there.

When it comes to the underscores, this is an oddity of my style. I started using underscores because I wanted a clear distinction between global symbols and local. (I'll try to use '-' if I commit again)

I'm sure you're right about the updateUI, it just happened to be the function I know for refreshing a component (I have seen it being recommended when switching the content of a panel with layout). Also, when I test repaint! it doesn't update the tree (but updateUI does).

I noticed now that updateUI has the problem of removing tree 'lines'.

I'll get back to you.

Jonathan Fischer Friberg

How about something like this (untested, but the 'idea' is used in hafni):

(defprotocol UpdatableTreeModel_p
  (update [this] ))

(defrecord UpdatableTreeModel [listeners branch? children root]
  javax.swing.tree.TreeModel
  (getRoot [this] root)
  (getChildCount [this parent] (count (children parent)))
  (getChild [this parent index] (nth (children parent) index))
  (getIndexOfChild [this parent child] 
                   (first (keep-indexed #(when (= %2 child) %1) (children parent))))
  (isLeaf [this node] (not (branch? node)))
  (addTreeModelListener [this listener] (swap! listeners conj listener))
  (removeTreeModelListener [this listener] (swap! listeners remove (partial = listener)))
  (valueForPathChanged [this path newValue] )
  UpdatableTreeModel_p
  (update [this]
          (let [e (javax.swing.event.TreeModelEvent. root (into-array [root]))]
            (doseq [listener @listeners]
              (.treeStructureChanged listener e)))))

(defn tree-model
  [branch? children root]
  (UpdatableTreeModel. (atom ()) branch? children root))

(defn update-tree!
  {:arglists '([model] [tree] [tree model])}
  ([target]
   (condp #(isa? %1 (class %2)) target
    javax.swing.JTree (recur (.getModel target))
    seesaw.tree.UpdatableTreeModel (.update target)))
  ([tree model]
   (.setModel tree model)))

and then we'll add with-expansion-state on top of it.

Dave Ray
Owner

I think this is a good extension of what's there already. I'll won't be able to try it out until this evening though.

Dave Ray
Owner

Haven't forgotten about this, just still thinking about it. It seems like for with-expansion-state, there are a few different approaches, each applicable to different situations. See the comments here: http://www.javalobby.org/java/forums/t19857.html

JTree and JTable never fail to give me a headache.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 2 unique commits by 1 author.

Jul 28, 2011
Jonathan Fischer Friberg update-tree! 0c780ed
Jonathan Fischer Friberg tests for update-tree! 202b885
This page is out of date. Refresh to see the latest.
19  src/seesaw/tree.clj
@@ -25,3 +25,22 @@
25 25
     (removeTreeModelListener [this listener])
26 26
     (valueForPathChanged [this path newValue])))
27 27
 
  28
+(defn update-tree! 
  29
+  "Update a tree.
  30
+  The model is optional, if not supplied this function refreshes 
  31
+  the tree (useful for e.g. file trees).
  32
+  
  33
+  Expanded nodes will still be expanded after update, given that
  34
+  the expanded node didn't change.
  35
+  "
  36
+  {:arglists '([tree model?])}
  37
+  [tree & [model]]
  38
+  (if model
  39
+    (let [visible_paths (doall
  40
+                          (for [row (range (.getRowCount tree))]
  41
+                            (.getPathForRow tree row)))]
  42
+      (.setModel tree (if model model (.getModel tree)))
  43
+      (doseq [path visible_paths]
  44
+        (.makeVisible tree path)))
  45
+    (.updateUI tree))
  46
+  tree)
17  test/seesaw/test/tree.clj
@@ -10,7 +10,7 @@
10 10
 
11 11
 (ns seesaw.test.tree
12 12
   (:use seesaw.tree)
13  
-  (:use [lazytest.describe :only (describe it testing given)]
  13
+  (:use [lazytest.describe :only (describe do-it it testing given)]
14 14
         [lazytest.expect :only (expect)]))
15 15
 
16 16
 (describe simple-tree-model
@@ -32,4 +32,17 @@
32 32
     (it "should retrieve the index of a child"
33 33
       (= [0 1 2] (map #(.getIndexOfChild m "dir" %) [1 2 3])))))
34 34
 
35  
-
  35
+(describe update-tree!
  36
+  (given [tree (javax.swing.JTree. (simple-tree-model (constantly true) #(range (inc %)) 1))
  37
+          path (javax.swing.tree.TreePath. (into-array [1 1 1 1]))]
  38
+    (do-it "expand path"
  39
+      (.makeVisible tree path))
  40
+    (it "should be visible before update"
  41
+      (.isVisible tree path))
  42
+    (do-it "update tree"
  43
+      (update-tree! tree (simple-tree-model (constantly true) #(range (+ % 2)) 1)))
  44
+    (it "should update the tree"
  45
+        (= [1 2]
  46
+           (vec (.getPath (.getPathForRow tree (dec (.getRowCount tree)))))))
  47
+    (it "should retain expanded paths after update"
  48
+      (.isVisible tree path))))
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.