diff src/clojure/inspector.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/clojure/inspector.clj	Sat Aug 21 06:25:44 2010 -0400
     1.3 @@ -0,0 +1,185 @@
     1.4 +;   Copyright (c) Rich Hickey. All rights reserved.
     1.5 +;   The use and distribution terms for this software are covered by the
     1.6 +;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
     1.7 +;   which can be found in the file epl-v10.html at the root of this distribution.
     1.8 +;   By using this software in any fashion, you are agreeing to be bound by
     1.9 +;   the terms of this license.
    1.10 +;   You must not remove this notice, or any other, from this software.
    1.11 +
    1.12 +(ns ^{:doc "Graphical object inspector for Clojure data structures."
    1.13 +       :author "Rich Hickey"}
    1.14 +    clojure.inspector
    1.15 +    (:import
    1.16 +     (java.awt BorderLayout)
    1.17 +     (java.awt.event ActionEvent ActionListener)
    1.18 +     (javax.swing.tree TreeModel)
    1.19 +     (javax.swing.table TableModel AbstractTableModel)
    1.20 +     (javax.swing JPanel JTree JTable JScrollPane JFrame JToolBar JButton SwingUtilities)))
    1.21 +
    1.22 +(defn atom? [x]
    1.23 +  (not (coll? x)))
    1.24 +
    1.25 +(defn collection-tag [x]
    1.26 +  (cond 
    1.27 +   (instance? java.util.Map$Entry x) :entry
    1.28 +   (instance? java.util.Map x) :map
    1.29 +   (sequential? x) :seq
    1.30 +   :else :atom))
    1.31 +
    1.32 +(defmulti is-leaf collection-tag)
    1.33 +(defmulti get-child (fn [parent index] (collection-tag parent)))
    1.34 +(defmulti get-child-count collection-tag)
    1.35 +
    1.36 +(defmethod is-leaf :default [node]
    1.37 +  (atom? node))
    1.38 +(defmethod get-child :default [parent index]
    1.39 +  (nth parent index))
    1.40 +(defmethod get-child-count :default [parent]
    1.41 +  (count parent))
    1.42 +
    1.43 +(defmethod is-leaf :entry [e]
    1.44 +  (is-leaf (val e)))
    1.45 +(defmethod get-child :entry [e index]
    1.46 +  (get-child (val e) index))
    1.47 +(defmethod get-child-count :entry [e]
    1.48 +  (count (val e)))
    1.49 +
    1.50 +(defmethod is-leaf :map [m]
    1.51 +  false)
    1.52 +(defmethod get-child :map [m index]
    1.53 +  (nth (seq m) index))
    1.54 +
    1.55 +(defn tree-model [data]
    1.56 +  (proxy [TreeModel] []
    1.57 +    (getRoot [] data)
    1.58 +    (addTreeModelListener [treeModelListener])
    1.59 +    (getChild [parent index]
    1.60 +      (get-child parent index))
    1.61 +    (getChildCount [parent]
    1.62 +       (get-child-count parent))
    1.63 +    (isLeaf [node]
    1.64 +      (is-leaf node))
    1.65 +    (valueForPathChanged [path newValue])
    1.66 +    (getIndexOfChild [parent child]
    1.67 +      -1)
    1.68 +    (removeTreeModelListener [treeModelListener])))
    1.69 +
    1.70 +
    1.71 +(defn old-table-model [data]
    1.72 +  (let [row1 (first data)
    1.73 +	colcnt (count row1)
    1.74 +	cnt (count data)
    1.75 +	vals (if (map? row1) vals identity)]
    1.76 +    (proxy [TableModel] []
    1.77 +      (addTableModelListener [tableModelListener])
    1.78 +      (getColumnClass [columnIndex] Object)
    1.79 +      (getColumnCount [] colcnt)
    1.80 +      (getColumnName [columnIndex]
    1.81 +	(if (map? row1)
    1.82 +	  (name (nth (keys row1) columnIndex))
    1.83 +	  (str columnIndex)))
    1.84 +      (getRowCount [] cnt)
    1.85 +      (getValueAt [rowIndex columnIndex]
    1.86 +	(nth (vals (nth data rowIndex)) columnIndex))
    1.87 +      (isCellEditable [rowIndex columnIndex] false)
    1.88 +      (removeTableModelListener [tableModelListener]))))
    1.89 +      
    1.90 +(defn inspect-tree 
    1.91 +  "creates a graphical (Swing) inspector on the supplied hierarchical data"
    1.92 +  {:added "1.0"}
    1.93 +  [data]
    1.94 +  (doto (JFrame. "Clojure Inspector")
    1.95 +    (.add (JScrollPane. (JTree. (tree-model data))))
    1.96 +    (.setSize 400 600)
    1.97 +    (.setVisible true)))
    1.98 +
    1.99 +(defn inspect-table 
   1.100 +  "creates a graphical (Swing) inspector on the supplied regular
   1.101 +  data, which must be a sequential data structure of data structures
   1.102 +  of equal length"
   1.103 +  {:added "1.0"}
   1.104 +    [data]
   1.105 +  (doto (JFrame. "Clojure Inspector")
   1.106 +    (.add (JScrollPane. (JTable. (old-table-model data))))
   1.107 +    (.setSize 400 600)
   1.108 +    (.setVisible true)))
   1.109 +
   1.110 +
   1.111 +(defmulti list-provider class)
   1.112 +
   1.113 +(defmethod list-provider :default [x]
   1.114 +  {:nrows 1 :get-value (fn [i] x) :get-label (fn [i] (.getName (class x)))})
   1.115 +
   1.116 +(defmethod list-provider java.util.List [c]
   1.117 +  (let [v (if (vector? c) c (vec c))]
   1.118 +    {:nrows (count v) 
   1.119 +     :get-value (fn [i] (v i)) 
   1.120 +     :get-label (fn [i] i)}))
   1.121 +
   1.122 +(defmethod list-provider java.util.Map [c]
   1.123 +  (let [v (vec (sort (map (fn [[k v]] (vector k v)) c)))]
   1.124 +    {:nrows (count v) 
   1.125 +     :get-value (fn [i] ((v i) 1)) 
   1.126 +     :get-label (fn [i] ((v i) 0))}))
   1.127 +
   1.128 +(defn list-model [provider]
   1.129 +  (let [{:keys [nrows get-value get-label]} provider]
   1.130 +    (proxy [AbstractTableModel] []
   1.131 +      (getColumnCount [] 2)
   1.132 +      (getRowCount [] nrows)
   1.133 +      (getValueAt [rowIndex columnIndex]
   1.134 +        (cond 
   1.135 +         (= 0 columnIndex) (get-label rowIndex)
   1.136 +         (= 1 columnIndex) (print-str (get-value rowIndex)))))))
   1.137 +
   1.138 +(defmulti table-model class)
   1.139 +
   1.140 +(defmethod table-model :default [x]
   1.141 +  (proxy [AbstractTableModel] []
   1.142 +    (getColumnCount [] 2)
   1.143 +    (getRowCount [] 1)
   1.144 +    (getValueAt [rowIndex columnIndex]
   1.145 +      (if (zero? columnIndex)
   1.146 +        (class x)
   1.147 +        x))))
   1.148 +
   1.149 +;(defn make-inspector [x]
   1.150 +;  (agent {:frame frame :data x :parent nil :index 0}))
   1.151 +
   1.152 +
   1.153 +(defn inspect
   1.154 +  "creates a graphical (Swing) inspector on the supplied object"
   1.155 +  {:added "1.0"}
   1.156 +  [x]
   1.157 +  (doto (JFrame. "Clojure Inspector")
   1.158 +    (.add
   1.159 +      (doto (JPanel. (BorderLayout.))
   1.160 +        (.add (doto (JToolBar.)
   1.161 +                (.add (JButton. "Back"))
   1.162 +                (.addSeparator)
   1.163 +                (.add (JButton. "List"))
   1.164 +                (.add (JButton. "Table"))
   1.165 +                (.add (JButton. "Bean"))
   1.166 +                (.add (JButton. "Line"))
   1.167 +                (.add (JButton. "Bar"))
   1.168 +                (.addSeparator)
   1.169 +                (.add (JButton. "Prev"))
   1.170 +                (.add (JButton. "Next")))
   1.171 +              BorderLayout/NORTH)
   1.172 +        (.add
   1.173 +          (JScrollPane. 
   1.174 +            (doto (JTable. (list-model (list-provider x)))
   1.175 +              (.setAutoResizeMode JTable/AUTO_RESIZE_LAST_COLUMN)))
   1.176 +          BorderLayout/CENTER)))
   1.177 +    (.setSize 400 400)
   1.178 +    (.setVisible true)))
   1.179 +
   1.180 +
   1.181 +(comment
   1.182 +
   1.183 +(load-file "src/inspector.clj")
   1.184 +(refer 'inspector)
   1.185 +(inspect-tree {:a 1 :b 2 :c [1 2 3 {:d 4 :e 5 :f [6 7 8]}]})
   1.186 +(inspect-table [[1 2 3][4 5 6][7 8 9][10 11 12]])
   1.187 +
   1.188 +)