Commits

Anonymous committed 05dcd8a

First version of neman.cells library added.

Comments (0)

Files changed (2)

             <arg value='net.ksojat.neman.xml'/>
             <arg value='net.ksojat.neman.storage'/>
             <arg value='net.ksojat.neman.textile'/>
+            <arg value='net.ksojat.neman.css'/>
+            <arg value='net.ksojat.neman.cells'/>
         </java>
 
         <jar destfile='${build.jar}'>

src/net/ksojat/neman/cells.clj

+;; Copyright (c) 2009 Krešimir Šojat. All rights reserved.  The use and
+;; distribution terms for this software are covered by the Common
+;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
+;; which can be found in the file CPL.TXT at the root of this
+;; distribution.  By using this software in any fashion, you are
+;; agreeing to be bound by the terms of this license.  You must not
+;; remove this notice, or any other, from this software.
+
+(ns net.ksojat.neman.cells
+  (:use clojure.set))
+
+;;
+;; Cell class
+;;
+
+(gen-class
+  :name        net.ksojat.neman.cells.Cell
+  :implements  [clojure.lang.IRef]
+  :state        state
+  :init         Cell-init
+  :constructors {[clojure.lang.IPersistentMap] []})
+
+(defn -Cell-init [init]
+  [[] (ref (merge {:value nil :parents {}} init))])
+
+(defn -get [this]
+  (get @(.state this) :value))
+
+(defn -setValidator [this validator-fn]
+  (.. this state (setValidator validator-fn)))
+
+(defn -getValidator [this]
+  (.. this state getValidator))
+
+;;
+;; Listeners
+
+(defmulti add-listener
+  (fn [object property callback] [(class object) property]))
+
+(defmulti remove-listener
+  (fn [object listener] [(class object) (class listener)]))
+
+(import '(javax.swing JTextField)
+        '(java.awt.event ActionListener ActionEvent))
+
+(defmethod add-listener [JTextField :Text] [object _ callback]
+  (let [listener (proxy [ActionListener] []
+                   (actionPerformed [#^ActionEvent e]
+                     (callback (.getText object))))]
+    (.addActionListener object listener)
+    listener))
+
+(defmethod remove-listener [JTextField ActionListener] [object listener]
+  (.removeActionListener object listener))
+
+;;
+;; Cell macros
+;;
+
+(defmacro alter-cell [cell parents bindings expr]
+  `(let [cell#  ~cell
+         old-p# (:parents @(.state cell#))
+         new-p# (into {} (map (fn [p#] [p# (agent nil)]) ~parents))
+         f#     (fn []
+                  (let ~(vec (interleave bindings (map #(do `(deref ~%)) parents)))
+                  ~expr))]
+     ; Update cell state
+     (dosync
+       (alter (.state cell#) assoc :value (f#) :parents new-p#))
+
+     ; Remove watchers from old parents
+     (doseq [[r# w#] old-p#] (remove-watcher r# w#))
+
+     ; Add watchers to new parents
+     (doseq [[r# w#] new-p#]
+       (add-watcher r# :send w#
+         (fn [& _#]
+           (let [ov# (deref cell#), nv# (f#)]
+             (when (not= ov# nv#)
+               (dosync (alter (.state cell#) assoc :value nv#)))))))
+
+     cell#))
+
+(defmacro cell [parents bindings expr]
+  `(alter-cell (net.ksojat.neman.cells.Cell. {}) ~parents ~bindings ~expr))