update-tree! for updating JTree #50

Open
wants to merge 2 commits into
from

Projects

None yet

2 participants

@odyssomay

Update a tree and keep expanded nodes expanded.

@daveray
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?

@odyssomay

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.

@odyssomay

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.

@daveray
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.

@daveray
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