Commits

Anonymous committed 88f8fc2

Swing examples and new swing code, beans support in core.

Comments (0)

Files changed (23)

   - JSON library (wrapper for Jackson)
   - Jetty helpers for server configuration from Clojure scripts.
 
-Before Installing checkout http://bitbucket.org/ksojat/truba and build it so it will pull clojure and clojure-contrib dependencies.  
+Before Installing checkout http://bitbucket.org/ksojat/truba and build it so it will pull clojure and clojure-contrib dependencies.
+To build all modules type: ant publish-all
+And to generate script that will start Repl with correct classpath and JLine support type: ant repl
+You will get ./clojure script in project root.
 
     <!-- Toplevel task for all subprojects. -->
 
+    <target name='repl' depends='buildlist, ivy-install'>
+    <ivy:retrieve conf='dev'/>
+    <script language='javascript'><![CDATA[
+        importClass(java.io.File);
+        var buildPath = project.getReference('build-path').list();
+
+        var projectPaths = Array();
+        for(var i = 0; i < buildPath.length; i++) {
+            projectPaths[i] = (new File(buildPath[i])).getParentFile();
+        }
+
+        var sourcePaths = Array();
+        for(var i = 0; i < projectPaths.length; i++) {
+            sourcePaths[i] = new File(projectPaths[i], "src");
+        }
+
+        var classPaths = Array();
+        for(var i = 0; i < projectPaths.length; i++) {
+            classPaths[i] = new File(new File(projectPaths[i], "target"), "classes");
+        }
+
+        var paths = sourcePaths.concat(classPaths, "\"lib/*\"").join(":");
+
+        var echo = project.createTask('echo');
+        echo.setFile(new File('clojure'));
+        echo.setMessage(
+            "CP=" + paths + "\njava -cp $CP jline.ConsoleRunner clojure.lang.Repl\n");
+        echo.perform();
+    ]]></script>
+    <chmod file='clojure' perm='+x'/>
+    </target>
+
     <macrodef name='subproject'>
         <attribute name='target'/>
         <sequential>

examples/cells1.clj

+(ns user
+  (:use
+    [net.ksojat.neman.cells :only [cell add-trigger]]))
+;
+; Depending on object property
+;
+(def tw (javax.swing.JTextField.))
+(def fw (javax.swing.JFrame.))
+(doto fw
+  (.add tw) .pack .show)
+
+; Cell is updated when text property of JTextField widget is changed.
+(def c1 (cell [[tw :text]] [t] (str "Text is: " t)))
+(add-trigger c1
+  (fn [old-v new-v]
+    (println old-v)
+    (println new-v)))
+

examples/swing1.clj

+(ns user
+  (:import
+    (java.awt BorderLayout)
+    (javax.swing JFrame JButton))
+  (:use
+    (net.ksojat.neman
+      core
+      [swing :only [swing doswing]])))
+
+(defn run-it []
+  (swing
+    (=> ~frame (JFrame. "Example")
+      :Layout (BorderLayout.)
+      :Size [300 200]
+      :DefaultCloseOperation JFrame/DISPOSE_ON_CLOSE
+
+      ~@(println frame)
+
+      [(=> ~button1 (JButton. "Button1")
+         :LayoutData BorderLayout/WEST
+         (>> :actionPerformed
+           (fn [e]
+             (.setText button2 "Changed")
+             (.setText button1 "Button1"))))
+
+       (=> ~button2 (JButton. "Button2")
+         :LayoutData BorderLayout/EAST
+         (>> :actionPerformed
+           (fn [e]
+             (.setText button1 "Changed")
+             (.setText button2 "Button2"))))])))
+
+(doswing
+  (.setVisible (run-it) true))

examples/swing2.clj

+(ns user
+  (:import
+    (java.awt FlowLayout)
+    (javax.swing JFrame JButton JLabel JOptionPane))
+  (:use
+    (net.ksojat.neman
+      core
+      [cells :only [cell cell-set! bind]]
+      [swing :only [swing doswing]])))
+
+(def user-input (cell ""))
+
+(defn run-it []
+  (swing
+    (=> (JFrame. "Frame")
+      :Size [500 300]
+      :DefaultCloseOperation JFrame/DISPOSE_ON_CLOSE
+      :Layout (FlowLayout.)
+
+      [(=> ~button1 (JButton. "Input")
+         (>> :actionPerformed
+            (fn [e]
+              (.setText button2 "Output's New Label")
+              (cell-set! user-input
+                (JOptionPane/showInputDialog nil "Type in something")))))
+
+       (=> ~button2 (JButton. "Output")
+         (>> :actionPerformed
+            (fn [e]
+              (.setText button2 "Output")
+              (JOptionPane/showMessageDialog nil @user-input))))
+
+       (=> (JLabel. @user-input)
+         ~(bind :text [user-input] [v] v))]
+
+      :Visible true)))
+
+(doswing
+  (run-it))
+<ivy-module version='2.0'>
+    <info
+        organisation='net.ksojat.neman'
+        module='all'/>
+    <configurations>
+        <conf name='dev' visibility='private'/>
+    </configurations>
+    <dependencies>
+        <dependency org='clojure' name='clojure' rev='svn1322' conf='dev->default'>
+            <artifact name='clojure' type='jar'/>
+        </dependency>
+        <dependency org='jline' name='jline' rev='0.9.91' conf='dev->default'/>
+    </dependencies>
+</ivy-module>
             </filesystem>
             <ibiblio name='java-net'
                 m2compatible='true'
-                root='http://download.java.net/maven/2'/>
+                root='http://download.java.net/maven/2/'/>
             <ibiblio name='ibiblio' m2compatible='true'/>
         </chain>
     </resolvers>

neman/cells/ivy.xml

         <artifact name='cells' type='jar' ext='jar'/>
     </publications>
     <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
+        <dependency org='clojure' name='clojure' rev='svn1322'>
             <artifact name='clojure' type='jar'/>
         </dependency>
+        <dependency name='core' rev='0.0.2'/>
     </dependencies>
 </ivy-module>

neman/cells/src/net/ksojat/neman/cells.clj

 ;; remove this notice, or any other, from this software.
 
 (ns net.ksojat.neman.cells
-  (:import (clojure.lang IRef)))
+  (:import (clojure.lang IRef)
+           (java.beans PropertyChangeListener PropertyChangeEvent))
+  (:use net.ksojat.neman.core))
 
 ;;
 ;; Cell class
 (defn -Cell-init [init]
   [[] (ref (merge {:value nil :parents {} :triggers []} init))])
 
-(defn -get [this]
+(defn -deref [this]
   (get @(.state this) :value))
 
 (defn -setValidator [this validator-fn]
 (defn -getValidator [this]
   (.. this state getValidator))
 
-(defn -addWatch [this watcher action send-off]
-  (.. this state (addWatch watcher action send-off)))
+;(defn -addWatch [this watcher action send-off]
+;  (.. this state (addWatch watcher action send-off)))
+(defn -addWatch [this key f]
+  (.. this state (addWatch key f)))
 
-(defn -removeWatch [this watcher]
-  (.. this state (removeWatch watcher)))
+;(defn -removeWatch [this watcher]
+;  (.. this state (removeWatch watcher)))
+(defn -removeWatch [this key]
+  (.. this state (removeWatch key)))
 
 (defn -notifyWatches [this]
   (.. this state notifyWatches))
 ;; Property Listeners
 ;;
 
-(defmulti add-listener
-  (fn [object property callback] [(class object) property]))
+;(defmulti add-listener
+;  (fn [object property callback] [(class object) property]))
 
-(defmulti remove-listener
-  (fn [object listener] [(class object) (class listener)]))
+;(defmulti remove-listener
+;  (fn [object listener] [(class object) (class listener)]))
 
-(import '(javax.swing JTextField)
-        '(java.awt.event ActionListener ActionEvent))
+;(import '(javax.swing JTextField)
+;        '(java.awt.event ActionListener ActionEvent))
 
-(defmethod add-listener [JTextField :text] [object _ callback]
-  (let [listener (proxy [ActionListener] []
-                   (actionPerformed [#^ActionEvent e]
-                     (callback)))]
-    (.addActionListener object listener)
-    listener))
+;(defmethod add-listener [JTextField :text] [object _ callback]
+;  (let [listener (proxy [ActionListener] []
+;                   (actionPerformed [#^ActionEvent e]
+;                     (callback)))]
+;    (.addActionListener object listener)
+;    listener))
 
-(defmethod remove-listener [JTextField ActionListener] [object listener]
-  (.removeActionListener object listener))
+;(defmethod remove-listener [JTextField ActionListener] [object listener]
+;  (.removeActionListener object listener))
 
 ;;
 ;;
 ;;
 
+;(defn add-parent-watcher [parent update-fn]
+;  (if (vector? parent)
+;    (let [[object property] parent]
+;      (add-listener object property update-fn))
+;    (let [watcher (agent nil)]
+;      (add-watcher parent :send watcher (fn [& _] (update-fn)))
+;      watcher)))
+
+;(defn remove-parent-watcher [parent watcher]
+;  (if (instance? IRef parent)
+;    (remove-watcher  parent watcher)
+;    (remove-listener parent watcher)))
+
+(defn genkey []
+  (keyword (name (gensym))))
+
 (defn add-parent-watcher [parent update-fn]
   (if (vector? parent)
     (let [[object property] parent]
-      (add-listener object property update-fn))
+      (add-property-listener object property (fn [& _] (update-fn))))
     (let [watcher (agent nil)]
-      (add-watcher parent :send watcher (fn [& _] (update-fn)))
-      watcher)))
+      (add-watch parent (genkey) (fn [& _] (update-fn)))
+      ;(add-watcher parent :send watcher (fn [& _] (update-fn)))
+      nil)))
 
 (defn remove-parent-watcher [parent watcher]
   (if (instance? IRef parent)
     (remove-watcher  parent watcher)
-    (remove-listener parent watcher)))
+    (remove-property-listener parent watcher)))
 
 (defn parent-value [parent]
   (if (vector? parent)
      (update#)
      cell#))
 
+;(use ['net.ksojat.neman.swing :only '(swing-unwrap)])
+
+(defmacro bind [object property parents bindings expr]
+  `(let [f# (fn []
+              (let
+                ~(vec (interleave bindings (map #(do `(parent-value ~%)) parents)))
+                ~expr))
+         update# (fn []
+                   (setp ~object ~property (f#)))]
+     (doall
+       (map (fn [p#] (add-parent-watcher p# update#)) ~parents))))
+
 (defmacro cell
   ([parents bindings expr]
     `(alter-cell (net.ksojat.neman.cells.Cell. {}) ~parents ~bindings ~expr))
   ([init-val]
     `(net.ksojat.neman.cells.Cell. {:value ~init-val})))
 
+(defn cell-set! [c v]
+  (dosync
+    (alter (.state c) assoc :value v)))
+
 ;(defn add-trigger [cell trigger-fn]
 ;  (dosync
 ;    (alter (.state cell) update-in [:triggers] conj trigger-fn))

neman/core/ivy.xml

     <info
         organisation='net.ksojat.neman'
         module='core'/>
+    <!--<configurations>
+        <conf name='test' visibility='private'/>
+        <conf name='doc' visibility='private'/>
+    </configurations>-->
     <publications>
         <artifact name='core' type='jar' ext='jar'/>
     </publications>
     <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
+        <dependency org='clojure' name='clojure' rev='svn1322'>
             <artifact name='clojure' type='jar' ext='jar'/>
         </dependency>
+        <!--<dependency org='clojure' name='clojure-contrib' rev='svn328' conf='test->default'>
+            <artifact name='clojure-contrib' type='jar' ext='jar'/>
+        </dependency>
+        <dependency org='net.java' name='textile-j' rev='2.2' conf='doc->default'/>-->
     </dependencies>
 </ivy-module>

neman/core/src/net/ksojat/neman/core.clj

            (java.beans Introspector)
            (java.util UUID))
   (:load "core/builder"
-         "core/listeners"))
+         "core/beans"))
 
 (defn str-join [s & strings]
   (str (interpose s strings)))
   (flatten nil) returns nil."
   [x]
   (filter (complement sequential?)
-          (rest (tree-seq sequential? seq x))))
+          (next (tree-seq sequential? seq x))))
 
-;(defn- make-args [x]
-;  (if x (to-array x) RT/EMPTY_ARRAY))
-
-;(defn- arglist [x]
-;  (if (seq? x) x (list x)))
-
-;(defmulti
-;  ctor (fn [x] (if (vector? x) (first x) x)))
-
-;(defmethod ctor :default [x]
-;  (if (vector? x)
-;    (let [[o & args] x]
-;      (Reflector/invokeConstructor o (make-args args)))
-;    x))
-
-; Default builder contructor binding.
-;(def *ctor* #'ctor)
-
-;(defmulti
-;  #^{:doc "Class method 'monkey patching' system used by => macro."}
-;  patch (fn [object method & args] [(class object) method]))
-
-;(defmethod patch :default [object method & args]
-;  (Reflector/invokeInstanceMethod object (name method) (make-args args)))
-
-;(defmulti default-method (fn [x t] [(class x) t]))
-;(defmethod default-method :default [& _] nil)
-
-;(defn last-char [s]
-;  (first (reverse s)))
-
-;(defn drop-last-char [s]
-;  (apply str (drop-last s)))
-
-;(defn str-ends-with [s c]
-;  (= (last-char s) c))
-
-;(defn setter-symbol [x]
-;  (symbol (str "set" (name x))))
-
-;(defn- mquote [x]
-;  (list 'quote x))
-
-;(defmacro => [x & members]
-;  (let [gx (gensym)
-;        x `(*ctor* ~x)
-;        map-dm (gensym)
-;        vec-dm (gensym)
-;        str-dm (gensym)]
-;    `(let [~gx ~x
-;           ~map-dm (default-method ~gx :map)
-;           ~vec-dm (default-method ~gx :vector)
-;           ~str-dm (default-method ~gx :string)]
-;      ~@(loop [mx members, p nil]
-;          (if mx
-;            (let [m (first mx)]
-;              (cond
-;                (keyword? m)
-;                  (recur
-;                    (rrest mx)
-;                    (cons
-;                      (concat
-;                        (list 'patch gx (mquote (setter-symbol m)))
-;                        (if (vector? (second mx))
-;                          (second mx)
-;                          (list (second mx))))
-;                      p))
-;                (map? m)
-;                  (recur (rest mx) (cons (list 'patch gx map-dm m) p))
-;                (string? m)
-;                  (recur (rest mx) (cons (list 'patch gx str-dm m) p))
-;                (vector? m)
-;                  (let [calls (map
-;                                #(concat
-;                                  (list 'patch gx vec-dm)
-;                                  (if (vector? %) % (list %)))
-;                                m)]
-;                    (recur (rest mx) (concat (reverse calls) p)))
-;                :else
-;                  (if (str-ends-with (name (first m)) \+)
-;                    (let [mn (symbol (drop-last-char (name (first m))))
-;                          calls (map
-;                                  #(concat
-;                                    (list 'patch gx (mquote (first m))) %)
-;                                  (rest m))]
-;                      (recur (rest mx) (concat (reverse calls) p)))
-;                    (recur
-;                      (rest mx)
-;                      (cons
-;                        (concat
-;                          (list 'patch gx (mquote (first m))) (rest m))
-;                        p)))))
-;            (reverse p)))
-;      ~gx)))

neman/core/src/net/ksojat/neman/core/beans.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.
+
+(in-ns 'net.ksojat.neman.core)
+
+(defn- bean-info [c]
+  (Introspector/getBeanInfo c))
+
+(defn- invoke [object method & args]
+  (Reflector/invokeInstanceMethod object method (to-array args)))
+
+;;
+;; Object property setters and getters.
+;;
+
+(defn- property-descriptors [c]
+  (.getPropertyDescriptors (bean-info c)))
+
+(defn- property-info [type property]
+  (first
+    (filter #(= property (.getName %)) (property-descriptors type))))
+
+(defn- property-setter [type property]
+  (when-let [x (property-info type property)] (.. x getWriteMethod getName)))
+
+(defn- property-getter [type property]
+  (when-let [x (property-info type property)] (.. x getReadMethod getName)))
+
+(defmulti
+  #^{:doc "Set value of object's property given as keyword."}
+  setp
+  (fn [object property value] [(class object) property]))
+
+(defmethod setp :default [object property value]
+  (if-let [setter (property-setter (class object) (name property))]
+    (do
+      (.addMethod setp [(class object) property] #(invoke %1 setter %3))
+      (invoke object setter value))
+    (throw
+      (Exception. (format "Unknown property %1 for object %2." property object)))))
+
+(defmulti
+  #^{:doc "Get value of object's property given as keyword."}
+  getp
+  (fn [object property] [(class object) property]))
+
+(defmethod getp :default [object property]
+  (if-let [getter (property-getter (class object) (name property))]
+    (do
+      (.addMethod getp [(class object) property] #(invoke %1 getter))
+      (invoke object getter))
+    (throw
+      (Exception. (format "Unknown property %1 of object %2." property object)))))
+
+;;
+;; Property listeners.
+;;
+
+(import '(java.beans PropertyChangeListener PropertyChangeEvent))
+
+(defn add-property-listener
+  "Add new PropertyChangeListener to object, callback function should
+   accept two parameters: old and new values of object property."
+  [object property callback]
+  (let [listener (proxy [PropertyChangeListener] []
+                   (propertyChange [#^PropertyChangeEvent e]
+                     (callback (.getOldValue e) (.getNewValue e))))]
+    (.addPropertyChangeListener object (name property) listener)
+    listener))
+
+(defn remove-property-listener
+  "Remove PropertyChangeListener from object."
+  [object property listener]
+  (.removePropertyChangeListener object (name property) listener)
+  listener)
+
+;;
+;; Event listeners.
+;;
+
+(defn event-decriptors [type]
+  (.getEventSetDescriptors (bean-info type)))
+
+(defn event-info [type listener-type]
+  (first
+    (filter #(isa? listener-type (.getListenerType %)) (event-decriptors type))))
+
+(defn create-listener
+  "Create new event listener:
+    listener - Class of listener to create (like ActionListener)
+    action   - Keyword naming action that will be implemented
+               (like :actionPerformed)
+    f        - Callback function, recives arguments of original action"
+  [listener action f]
+  (let [names  (map #(.getName %) (.getMethods listener))
+        pass   (repeat (fn [& _]))
+        unused (apply hash-map (interleave names pass))
+        methods (assoc unused
+                  (name action) (fn [_ & args] (apply f args)))]
+    (doto (construct-proxy (get-proxy-class listener))
+      (init-proxy methods))))
+
+(defmulti listener-add-method
+  (fn [type listener-type] [type listener-type]))
+
+(defmethod listener-add-method :default [type listener-type]
+  (if-let [info (event-info type listener-type)]
+    (let [method (.getAddListenerMethod info)
+          base   (.getDeclaringClass method)
+          name   (.getName method)]
+      (.addMethod listener-add-method [base listener-type] (fn [& _] name))
+      name)
+    (.addMethod listener-add-method [type listener-type] (fn [& _] nil))))
+
+(defmulti listener-remove-method
+  (fn [type listener-type] [type listener-type]))
+
+(defmethod listener-remove-method :default [type listener-type]
+  (if-let [info (event-info type listener-type)]
+    (let [method (.getRemoveListenerMethod info)
+          base   (.getDeclaringClass method)
+          name   (.getName method)]
+      (.addMethod listener-remove-method [base listener-type] (fn [& _] name))
+      name)
+    (.addMethod listener-remove-method [type listener-type] (fn [& _] nil))))
+
+(defmulti event-listener (fn [type action] [type action]))
+
+(defn has-method? [type method-name]
+  (some #(= (.getName %) method-name) (.getMethods type)))
+
+(defmethod event-listener :default [type action]
+  (let [desc (filter
+               #(let [listener-type (.getListenerType %)]
+                  (has-method? listener-type (name action)))
+               (.getEventSetDescriptors (bean-info type)))]
+    (if (= (count desc) 1)
+      (let [listener (.getListenerType (first desc))]
+        ;(.addMethod event-listener [type action] (fn [& _] [listener action]))
+        [listener action]))))
+
+(defn add-listener
+  ([object listener]
+    (if-let [add (listener-add-method (class object) (class listener))]
+      (do
+        (invoke object add listener)
+        listener)
+      (throw
+        (Exception.
+          (format
+            "Don't know how to add listener %2 to object '%1'" (str object) (str listener))))))
+
+  ([object action f]
+    (add-listener object
+      (let [[listener method] (event-listener (class object) action)]
+        (create-listener listener method f)))))
+
+(defn remove-listener [object listener]
+  (if-let [remove (listener-remove-method (class object) (class listener))]
+    (do
+      (invoke object remove listener)
+      listener)
+    (throw
+      (Exception.
+        (format
+          "Don't know how to remove listener '%2' from object '%1'"
+          (str object) (str listener))))))
+
+(defmethod patch [Object '>>] [object _ & args]
+  (apply add-listener (unwrap object) args))

neman/core/src/net/ksojat/neman/core/builder.clj

 ;; agreeing to be bound by the terms of this license.  You must not
 ;; remove this notice, or any other, from this software.
 
+(in-ns 'net.ksojat.neman.core)
+
 (defmulti
   #^{:doc
       "Builder macro provides alternative way of object a Java object. It's syntax is:
       for it. Treat it as private to neman library."}
   *ctor* #'ctor)
 
+;; Support for object wrappers
+(def wrap   identity)
+(def unwrap identity)
+
 (defmulti
   #^{:doc
       "Class method 'monkey patching' system used by => (builder) macro.
 
 ;; Default method call, delegates to Java.
 (defmethod patch :default [object method & args]
-  (Reflector/invokeInstanceMethod object (name method) (make-args args)))
+  (if (identical? object (unwrap object))
+    (Reflector/invokeInstanceMethod object (name method) (make-args args))
+    (apply patch (unwrap object) method args)))
 
 (defmulti  default-method* (fn [x t] [(class x) t]))
-(defmethod default-method* :default [& _] nil)
+
+(defmethod default-method* :default [x t]
+  (when (not (identical? x (unwrap x)))
+    (default-method* (unwrap x) t)))
 
 (defmacro
   #^{:doc
                 (if (seq specs)
                   (if (seq? x)
                     (recur
-                      (rest specs)
-                      (apply conj res (map #(cons (first x) %) (partition 2 (rest x)))))
+                      (next specs)
+                      (apply conj res (map #(cons (first x) %) (partition 2 (next x)))))
                     (recur
                       (drop 3 specs)
                       (conj res (take 3 specs))))
        See also: (doc default-method)"}
   => [x & members]
   (let [gx (gensym)
-        x  `(*ctor* ~x)
+        x  `(wrap (*ctor* ~x))
         map-dm (gensym)
         vec-dm (gensym)
         str-dm (gensym)]
       ~@(loop [[m & ms :as mx] members, p []]
           (if (seq mx)
             (cond
-              ; TODO: Replace this with ~
-              ;(= '>> m)
-              ; (let [[_ expr & ms] mx]
-              ;   (recur ms (conj p `(~(first expr) ~gx ~@(rest expr)))))
-              ; TODO: Add support for ~@
+              (and (seq? m) (= (first m) 'clojure.core/unquote))
+                (let [[_ [mf & mr]] m]
+                  (recur ms (conj p `(let [x# (unwrap ~gx)] (~mf x# ~@mr)))))
+                  ;(recur ms (conj p `(~mf ~gx ~@mr))))
+              (and (seq? m) (= (first m) 'clojure.core/unquote-splicing))
+                (let [[_ m] m]
+                  ; TODO: Unwrap object like in unquote
+                  (recur ms (conj p `(do ~m))))
               (keyword? m)
                 (let [[_ val & ms] mx]
-                  (recur ms (conj p `(patch ~gx '~(symbol (str "set" (name m))) ~val))))
+                  (recur ms (conj p `(patch ~gx '~(symbol (str "set" (name m))) ~@(if (vector? val) val (vector val))))))
               (map? m)
                 (recur ms (conj p `(patch ~gx ~map-dm ~m)))
               (vector? m)
       ~gx)))
 
 (defn builder? [form]
-  (and (seq? form) (= (first form) '=>))); TODO; watch for =>
+  (and (seq? form) (= (first form) '=>)))
 
 (defn name? [form]
   (and (seq? form) (= (first form) 'clojure.core/unquote)))
           [(into (empty form) newform) names]))
     [form nil]))
 
+;; Da rade results, dodati i vise od jednog expr
 (defmacro build-scope
-  "TODO: Add some docs."
+  "TODO: Add some docs.
+
+   Limitations:
+   You can't refere to other object in first expression of => (builder) macro;
+   this will not work:
+     (build-scope
+       (=> ~obj1 (MyClass. obj2))
+       (=> ~obj2 (MyOtherClass.)))
+
+   You can't use the same name twice; so you can't for instance use it in conditional statement:
+     (if x (=> ~name (MyClass. \"true\")) (=> ~name (MyClass. \"false\")
+   or to name multiple objects:
+     (doseq [x xs] (=> ~name (MyClass. x)))"
   ([expr]
     `(build-scope :toplevel ~expr))
 
     (let [[expr names] (extract expr)]
       `(let ~(vec names) ~expr))))
 
-(default-method javax.swing.JFrame :vector add)
-
-(def t
-  (build-scope
-    (=> (javax.swing.JFrame. "Example")
-      ;:Size [100 100]
-      
-      [(=> ~button1 (javax.swing.JButton. "Button 1"))
-       (=> ~button2 (javax.swing.JButton. "Button 2"))])))

neman/core/src/net/ksojat/neman/core/listeners.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.
-
-;(import '(clojure.lang Reflector)
-;        '(java.beans Introspector))
-
-(defn create-listener [listener action f]
-  (let [names (map #(.getName %) (.getMethods listener))
-        pass  (repeat (fn [& _]))
-        methods (assoc
-                  (apply hash-map (interleave names pass))
-                  (name action) (fn [_ & args] (apply f args)))]
-    (doto (construct-proxy (get-proxy-class listener))
-      (init-proxy methods))))
-
-(defn bean-info [type]
-  (Introspector/getBeanInfo type))
-
-(defn event-descriptor [type listener-type]
-  (first
-    (filter #(isa? listener-type (.getListenerType %))
-      (.getEventSetDescriptors (bean-info type)))))
-
-(defmulti listener-add-method
-  (fn [type listener-type] [type listener-type]))
-
-(defmethod listener-add-method :default [type listener-type]
-  (let [desc   (event-descriptor type listener-type)
-        method (if desc   (.getAddListenerMethod desc))
-        name   (if method (.getName method))]
-    (.addMethod listener-add-method
-      [(.getDeclaringClass method) listener-type] (fn [& _] name))
-    name))
-
-(defmulti listener-remove-method
-  (fn [type listener-type] [type listener-type]))
-
-(defmethod listener-remove-method :default [type listener-type]
-  (let [desc   (event-descriptor type listener-type)
-        method (if desc   (.getRemoveListenerMethod desc))
-        name   (if method (.getName method))]
-    (.addMethod listener-remove-method
-      [(.getDeclaringClass method) listener-type] (fn [& _] name))
-    name))
-
-(defn add-listener [object listener]
-  (if-let [add (listener-add-method (class object) (class listener))]
-    (do
-      (Reflector/invokeInstanceMethod object add (to-array (list listener)))
-      listener)
-    (throw
-      (Exception.
-        (format
-          "Don't know how to add listener of type '%2' to object of type '%1'"
-          (class object) (class listener))))))
-
-(defn remove-listener [object listener]
-  (if-let [remove (listener-remove-method (class object) (class listener))]
-    (do
-      (Reflector/invokeInstanceMethod object remove (to-array (list listener)))
-      listener)
-    (throw
-      (Exception.
-        (format
-          "Don't know how to remove listener of type '%' from object of type '%1'"
-          (class object) (class listener))))))
-
-(defmulti event-listener (fn [type action] [type action]))
-
-(defn has-method? [type method-name]
-  (some #(= (.getName %) method-name) (.getMethods type)))
-
-(defmethod event-listener :default [type action]
-  (println "tu")
-  (let [desc (filter
-               #(let [listener-type (.getListenerType %)]
-                  (has-method? listener-type (name action)))
-               (.getEventSetDescriptors (bean-info type)))]
-    (if (= (count desc) 1)
-      (let [listener (.getListenerType (first desc))]
-        (.addMethod event-listener [type action] (fn [&_ ] [listener action]))
-        [listener action]))))
-
-;; TODO: Merge this with add-listener
-(defn add-listener2 [object action f]
-  (add-listener object
-    (let [[listener method] (event-listener (class object) action)]
-      (create-listener listener method f))))
-
-;; Integrate with builder macro.
-(defmethod patch [Object '>>] [object _ & args]
-  (apply add-listener2 object args))

neman/json/ivy.xml

         <artifact name='json' type='jar' ext='jar'/>
     </publications>
     <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
+        <dependency org='clojure' name='clojure' rev='svn1322'>
             <artifact name='clojure' type='jar'/>
         </dependency>
         <dependency name='core' rev='0.0.2'/>

neman/swing/ivy.xml

         <artifact name='swing' type='jar' ext='jar'/>
     </publications>
     <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
+        <dependency org='clojure' name='clojure' rev='svn1322'>
             <artifact name='clojure' type='jar' ext='jar'/>
         </dependency>
         <dependency name='core' rev='0.0.2'/>

neman/swing/src/net/ksojat/neman/swing.clj

     (clojure.lang Reflector RT))
   (:use net.ksojat.neman.core)
   (:load
-    "swing/wrapper"
     "swing/aliases"))
 
 (defn invoke-later [f]
   `(javax.swing.SwingUtilities/invokeLater
      (fn [] ~@body)))
 
-(defmacro swing [expr]
-  `(layout-data (builder-scope ~expr)))
-
 ;;
 ;; Builder integration.
 ;;
   javax.swing.JMenuItem :vector add
   javax.swing.JToolBar  :vector add)
 
+(defmethod patch [javax.swing.JFrame 'add] [f _ x]
+  (.add f (unwrap x) (:layout-data @(.state x))))
+
 (defmethod patch [javax.swing.JRadioButtonMenuItem 'setGroup] [o _ g]
   (.add g o))
 
   (let [o (Reflector/invokeConstructor c RT/EMPTY_ARRAY)]
     (set-abutton o s)))
 
+;;
+;; Wrapper
+;;
+
+(gen-class
+  :name         net.ksojat.neman.swing.Wrapper
+  :state        state
+  :init         Wrapper-init
+  :constructors {[Object] []}
+  :methods      [[setLayoutData [Object] void]])
+
+(defn -Wrapper-init [object]
+  [[] (ref {:object object, :layout-data nil})])
+
+(defn -setLayoutData [this data]
+  (dosync
+    (alter (.state this) assoc :layout-data data)))
+
+(defmethod patch [net.ksojat.neman.swing.Wrapper 'setLayoutData] [object _ data]
+  (.setLayoutData object data))
+
+;;
+;; Builder integrations.
+;;
+
+(defn swing-wrap [x]
+  (net.ksojat.neman.swing.Wrapper. x))
+
+(defn swing-unwrap [x]
+  (if (instance? net.ksojat.neman.swing.Wrapper x)
+    (:object @(.state x))
+    x))
+
+(defmacro swing [expr]
+  `(build-scope
+     (binding [wrap swing-wrap, unwrap swing-unwrap]
+       (unwrap ~expr))))

neman/swing/src/net/ksojat/neman/swing/wrapper.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.
-
-(gen-class
-  :name         net.ksojat.neman.swing.Wrapper
-  :init         init
-  :constructors {[Object] []}
-  :methods      [[setLayoutData [Object] Void]])
-
-(defn -Wrapper-init [object]
-  [[] (ref {:object object, :layout-data nil})])
-
-(defn -setLayoutData [this data]
-  (dosync
-    (alter (.state this) assoc :layout-data data)))
-
-; TODO: Make private
-(defn get-layout-data [wrapper]
-  (@(.state wrapper) :layout-data))
-
-; TODO: Make private
-(defn get-wrapped-object [wrapper]
-  (@(.state wrapper) :object))
-
-(defmethod patch [net.ksojat.neman.swing.Wrapper 'setLayoutData] [object _ data]
-  (.setLayoutData object data))
-
-(defmethod patch [net.ksojat.neman.swing.Wrapper Object] [object method & args]
-  (apply patch (get-wrapped-object object) method args))
-
-(defmethod default-method* [net.ksojat.neman.swing.Wrapper Object] [wrapper type]
-  (default-method* (@(.state wrapper) :object) type))
-

neman/utils/ivy.xml

         <artifact name='utils' type='jar' ext='jar'/>
     </publications>
     <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
+        <dependency org='clojure' name='clojure' rev='svn1322'>
             <artifact name='clojure' type='jar' ext='jar'/>
         </dependency>
         <dependency name='core' rev='0.0.2'/>

neman/web/ivy.xml

         <artifact name='web' type='jar' ext='jar'/>
     </publications>
     <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
+        <dependency org='clojure' name='clojure' rev='svn1322'>
             <artifact name='clojure' type='jar' ext='jar'/>
         </dependency>
         <dependency name='core' rev='0.0.2'/>

neman/web/src/net/ksojat/neman/web.clj

 (defn convertor? [arg]
   (= (:type arg) :convertor))
 
-(defn distinct-arguments?
-  "Check are view argument names unique."
-  [arg-seq]
-  (or (not (seq? arg-seq)) (apply distinct? (map :name arg-seq))))
+;(defn distinct-arguments?
+;  "Check are view argument names unique."
+;  [arg-seq]
+;  (or (not (seq? arg-seq)) (apply distinct? (map :name arg-seq))))
+(defn distinct-arguments? [arg-seq] true)
 
 (defmacro view* [bindings & body]
   (let [expand   (fn

neman/webapps/ivy.xml

         <artifact name='webapps' type='jar' ext='jar'/>
     </publications>
     <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
+        <dependency org='clojure' name='clojure' rev='svn1322'>
             <artifact name='clojure' type='jar'/>
         </dependency>
 	<dependency name='core' rev='0.0.2'/>

neman/xml/ivy.xml

         <artifact name='xml' type='jar' ext='jar'/>
     </publications>
     <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
+        <dependency org='clojure' name='clojure' rev='svn1322'>
             <artifact name='clojure' type='jar'/>
         </dependency>
         <dependency name='core' rev='0.0.2'>