Skip to content
This repository
Browse code

Split to-widget into two parts, to-widget for conversion and make-wid…

…get for construction.
  • Loading branch information...
commit 42ced87f22d4fd3002d064b959f7261d32da6eee 1 parent 075ecef
Dave Ray authored
91 src/seesaw/core.clj
@@ -143,12 +143,13 @@
143 143 ;*******************************************************************************
144 144 ; Widget coercion prototcol
145 145
146   -(defn ^java.awt.Component to-widget
147   - "Try to convert the input argument to a widget based on the following rules:
148   -
  146 +(defn ^java.awt.Component make-widget
  147 + "Try to create a new widget based on the following rules:
  148 +
149 149 nil -> nil
150   - java.awt.Component -> return argument unchanged
151   - java.util.EventObject -> return the event source
  150 + java.awt.Component -> return argument unchanged (like to-widget)
  151 + java.util.EventObject -> return the event source (like to-widget)
  152 +
152 153 java.awt.Dimension -> return Box/createRigidArea
153 154 java.swing.Action -> return a button using the action
154 155 :separator -> create a horizontal JSeparator
@@ -157,18 +158,22 @@
157 158 [:fill-h n] -> Box/createHorizontalStrut with width n
158 159 [:fill-v n] -> Box/createVerticalStrut with height n
159 160 [width :by height] -> create rigid area with given dimensions
160   - A java.net.URL -> a label with the image located at the url
  161 + java.net.URL -> a label with the image located at the url
161 162 Anything else -> a label with the text from passing the object through str
  163 + "
  164 + ([v] (when v (make-widget* v))))
  165 +
  166 +(defn ^java.awt.Component to-widget
  167 + "Try to convert the input argument to a widget based on the following rules:
162 168
163   - If create? is false, will return nil for all rules (see above) that
164   - would create a new widget. The default value for create? is false
165   - to avoid inadvertently creating widgets all over the place.
  169 + nil -> nil
  170 + java.awt.Component -> return argument unchanged
  171 + java.util.EventObject -> return the event source
166 172
167 173 See:
168 174 (seeseaw.to-widget)
169 175 "
170   - ([v] (to-widget v false))
171   - ([v create?] (when v (to-widget* v create?))))
  176 + ([v] (when v (to-widget* v))))
172 177
173 178 ;*******************************************************************************
174 179 ; Widget construction stuff
@@ -467,7 +472,7 @@
467 472 (defn- add-widget
468 473 ([c w] (add-widget c w nil))
469 474 ([^java.awt.Container c w constraint]
470   - (let [w* (to-widget w true)]
  475 + (let [w* (make-widget w)]
471 476 (check-args (not (nil? w*)) (str "Can't add nil widget. Original was (" w ")"))
472 477 (.add c w* constraint)
473 478 w*)))
@@ -674,7 +679,7 @@
674 679
675 680 (extend-protocol ConfigureWidget
676 681 java.util.EventObject
677   - (config* [target args] (config* (to-widget target false) args))
  682 + (config* [target args] (config* (to-widget target) args))
678 683
679 684 java.awt.Component
680 685 (config* [target args] (reapply-options target args default-options))
@@ -769,11 +774,11 @@
769 774 "Create a panel with a border layout. In addition to the usual options,
770 775 supports:
771 776
772   - :north widget for north position (passed through to-widget)
773   - :south widget for south position (passed through to-widget)
774   - :east widget for east position (passed through to-widget)
775   - :west widget for west position (passed through to-widget)
776   - :center widget for center position (passed through to-widget)
  777 + :north widget for north position (passed through make-widget)
  778 + :south widget for south position (passed through make-widget)
  779 + :east widget for east position (passed through make-widget)
  780 + :west widget for west position (passed through make-widget)
  781 + :center widget for center position (passed through make-widget)
777 782
778 783 :hgap horizontal gap between widgets
779 784 :vgap vertical gap between widgets
@@ -853,7 +858,7 @@
853 858 (defn flow-panel
854 859 "Create a panel with a flow layout. Options:
855 860
856   - :items List of widgets (passed through to-widget)
  861 + :items List of widgets (passed through make-widget)
857 862 :hgap horizontal gap between widgets
858 863 :vgap vertical gap between widgets
859 864 :align :left, :right, :leading, :trailing, :center
@@ -881,7 +886,7 @@
881 886 (defn horizontal-panel
882 887 "Create a panel where widgets are arranged horizontally. Options:
883 888
884   - :items List of widgets (passed through to-widget)
  889 + :items List of widgets (passed through make-widget)
885 890
886 891 See http://download.oracle.com/javase/6/docs/api/javax/swing/BoxLayout.html
887 892 "
@@ -891,7 +896,7 @@
891 896 (defn vertical-panel
892 897 "Create a panel where widgets are arranged vertically Options:
893 898
894   - :items List of widgets (passed through to-widget)
  899 + :items List of widgets (passed through make-widget)
895 900
896 901 See http://download.oracle.com/javase/6/docs/api/javax/swing/BoxLayout.html
897 902 "
@@ -911,7 +916,7 @@
911 916
912 917 :rows Number of rows, defaults to 0, i.e. unspecified.
913 918 :columns Number of columns.
914   - :items List of widgets (passed through to-widget)
  919 + :items List of widgets (passed through make-widget)
915 920 :hgap horizontal gap between widgets
916 921 :vgap vertical gap between widgets
917 922
@@ -1075,7 +1080,7 @@
1075 1080 radio buttons, toggle-able menus, etc. Takes the following options:
1076 1081
1077 1082 :buttons A sequence of buttons to include in the group. They are *not*
1078   - passed through (to-widget), i.e. they must be button or menu
  1083 + passed through (make-widget), i.e. they must be button or menu
1079 1084 instances.
1080 1085
1081 1086 The mutual exclusion of the buttons in the group will be maintained automatically.
@@ -1562,20 +1567,20 @@
1562 1567 })
1563 1568
1564 1569 (defn- set-scrollable-corner [k ^JScrollPane w v]
1565   - (.setCorner w (scrollable-corner-constants k) (to-widget v true)))
  1570 + (.setCorner w (scrollable-corner-constants k) (make-widget v)))
1566 1571
1567 1572 (def ^{:private true} scrollable-options (merge {
1568 1573 :hscroll #(.setHorizontalScrollBarPolicy ^JScrollPane %1 (hscroll-table %2))
1569 1574 :vscroll #(.setVerticalScrollBarPolicy ^JScrollPane %1 (vscroll-table %2))
1570 1575 :row-header
1571 1576 (fn [^JScrollPane w v]
1572   - (let [v (to-widget v true)]
  1577 + (let [v (make-widget v)]
1573 1578 (if (instance? javax.swing.JViewport v)
1574 1579 (.setRowHeader w v)
1575 1580 (.setRowHeaderView w v))))
1576 1581 :column-header
1577 1582 (fn [^JScrollPane w v]
1578   - (let [v (to-widget v true)]
  1583 + (let [v (make-widget v)]
1579 1584 (if (instance? javax.swing.JViewport v)
1580 1585 (.setColumnHeader w v)
1581 1586 (.setColumnHeaderView w v))))
@@ -1617,7 +1622,7 @@
1617 1622 "
1618 1623 [target & opts]
1619 1624 (let [^JScrollPane sp (construct JScrollPane opts)]
1620   - (.setViewportView sp (to-widget target true))
  1625 + (.setViewportView sp (make-widget target))
1621 1626 (apply-options sp opts (merge default-options scrollable-options))))
1622 1627
1623 1628 ;*******************************************************************************
@@ -1698,8 +1703,8 @@
1698 1703 (doto ^JSplitPane (construct JSplitPane opts)
1699 1704 (.setOrientation (dir {:left-right JSplitPane/HORIZONTAL_SPLIT
1700 1705 :top-bottom JSplitPane/VERTICAL_SPLIT}))
1701   - (.setLeftComponent (to-widget left true))
1702   - (.setRightComponent (to-widget right true)))
  1706 + (.setLeftComponent (make-widget left))
  1707 + (.setRightComponent (make-widget right)))
1703 1708 opts
1704 1709 (merge default-options splitter-options)))
1705 1710
@@ -1782,7 +1787,7 @@
1782 1787 (.add menu menu-item)
1783 1788 (if (= :separator item)
1784 1789 (.addSeparator menu)
1785   - (.add menu (to-widget item true))))))
  1790 + (.add menu (make-widget item))))))
1786 1791 })
1787 1792
1788 1793 (defn menu
@@ -1807,7 +1812,7 @@
1807 1812 (.add menu menu-item)
1808 1813 (if (= :separator item)
1809 1814 (.addSeparator menu)
1810   - (.add menu (to-widget item true))))))
  1815 + (.add menu (make-widget item))))))
1811 1816 })
1812 1817
1813 1818 (defn popup
@@ -1916,7 +1921,7 @@
1916 1921 (let [title-cmp (try-cast Component title)
1917 1922 index (.getTabCount tp)]
1918 1923 (cond-doto tp
1919   - true (.addTab (when-not title-cmp (str title)) (make-icon icon) (to-widget content true) (str tip))
  1924 + true (.addTab (when-not title-cmp (str title)) (make-icon icon) (make-widget content) (str tip))
1920 1925 title-cmp (.setTabComponentAt index title-cmp))))
1921 1926 tp)
1922 1927
@@ -1938,7 +1943,7 @@
1938 1943 :title Title of the tab or a component to be displayed.
1939 1944 :tip Tab's tooltip text
1940 1945 :icon Tab's icon, passed through (icon)
1941   - :content The content of the tab, passed through (to-widget) as usual.
  1946 + :content The content of the tab, passed through (make-widget) as usual.
1942 1947
1943 1948 Returns the new JTabbedPane.
1944 1949
@@ -2078,7 +2083,7 @@
2078 2083 :id seesaw.selector/id-of!
2079 2084 :class seesaw.selector/class-of!
2080 2085 :on-close #(.setDefaultCloseOperation ^javax.swing.JFrame %1 (frame-on-close-map %2))
2081   - :content #(.setContentPane ^javax.swing.JFrame %1 (to-widget %2 true))
  2086 + :content #(.setContentPane ^javax.swing.JFrame %1 (make-widget %2))
2082 2087 :menubar #(.setJMenuBar ^javax.swing.JFrame %1 %2)
2083 2088
2084 2089 :title #(.setTitle ^java.awt.Frame %1 (str %2))
@@ -2098,7 +2103,7 @@
2098 2103 :height initial height. Note that calling (pack!) will negate this setting
2099 2104 :size initial size. Note that calling (pack!) will negate this setting
2100 2105 :minimum-size minimum size of frame, e.g. [640 :by 480]
2101   - :content passed through (to-widget) and used as the frame's content-pane
  2106 + :content passed through (make-widget) and used as the frame's content-pane
2102 2107 :visible? whether frame should be initially visible (default false)
2103 2108 :resizable? whether the frame can be resized (default true)
2104 2109 :on-close default close behavior. One of :exit, :hide, :dispose, :nothing
@@ -2186,7 +2191,7 @@
2186 2191
2187 2192 ; These two override frame-options for purposes of type hinting and reflection
2188 2193 :on-close #(.setDefaultCloseOperation ^javax.swing.JDialog %1 (frame-on-close-map %2))
2189   - :content #(.setContentPane ^javax.swing.JDialog %1 (to-widget %2 true))
  2194 + :content #(.setContentPane ^javax.swing.JDialog %1 (make-widget %2))
2190 2195 :menubar #(.setJMenuBar ^javax.swing.JDialog %1 %2)
2191 2196
2192 2197 ; Ditto here. Avoid reflection
@@ -2440,7 +2445,7 @@
2440 2445 :type The type of the dialog. One of :warning, :error, :info, :plain, or :question.
2441 2446
2442 2447 :options Custom buttons/options can be provided using this argument.
2443   - It must be a seq of \"to-widget\"'able objects which will be
  2448 + It must be a seq of \"make-widget\"'able objects which will be
2444 2449 displayed as options the user can choose from. Note that in this
2445 2450 case, :success-fn, :cancel-fn & :no-fn will *not* be called.
2446 2451 Use the handlers on those buttons & RETURN-FROM-DIALOG to close
@@ -2498,7 +2503,7 @@
2498 2503 (dialog-option-type-map option-type)
2499 2504 nil ;icon
2500 2505 (when options
2501   - (into-array (map #(to-widget % true) options)))
  2506 + (into-array (map make-widget options)))
2502 2507 (or default-option (first options))) ; default selection
2503 2508 remaining-opts (apply dissoc opts :visible? (keys dialog-defaults))
2504 2509 dlg (apply custom-dialog :visible? false :content pane (reduce concat remaining-opts))]
@@ -2801,10 +2806,10 @@
2801 2806 container))
2802 2807
2803 2808 (defn replace!
2804   - "Replace old-widget with new-widget from container. container and each widget
2805   - are passed through (to-widget) as usual. Note that the layout constraints of
2806   - old-widget are retained for the new widget. This is different from the behavior
2807   - you'd get with just remove/add in Swing.
  2809 + "Replace old-widget with new-widget from container. container and old-widget
  2810 + are passed through (to-widget). new-widget is passed through make-widget.
  2811 + Note that the layout constraints of old-widget are retained for the new widget.
  2812 + This is different from the behavior you'd get with just remove/add in Swing.
2808 2813
2809 2814 The container is properly revalidated and repainted after replacement.
2810 2815
@@ -2819,5 +2824,5 @@
2819 2824 "
2820 2825 [container old-widget new-widget]
2821 2826 (handle-structure-change
2822   - (replace!-impl (to-widget container) (to-widget old-widget) (to-widget new-widget true))))
  2827 + (replace!-impl (to-widget container) (to-widget old-widget) (make-widget new-widget))))
2823 2828
21 src/seesaw/examples/to_widget.clj
@@ -19,18 +19,17 @@
19 19
20 20 (defn name-field [person field]
21 21 (text :columns 15 :text (field person)))
22   -; Now implement ToWidget to create an editor for that type
  22 +; Now implement MakeWidget to create an editor for that type
23 23 (extend-type Person
24   - ToWidget
25   - (to-widget* [person create?]
26   - (when create?
27   - (mig-panel :constraints ["", "[][grow]"]
28   - :border [(line-border :thickness 1) 5]
29   - :items [
30   - [ "First Name" "gap 10"]
31   - [ (name-field person :first-name) "growx, wrap"]
32   - [ "Last Name" "gap 10"]
33   - [ (name-field person :last-name) "growx"]]))))
  24 + MakeWidget
  25 + (make-widget* [person]
  26 + (mig-panel :constraints ["", "[][grow]"]
  27 + :border [(line-border :thickness 1) 5]
  28 + :items [
  29 + [ "First Name" "gap 10"]
  30 + [ (name-field person :first-name) "growx, wrap"]
  31 + [ "Last Name" "gap 10"]
  32 + [ (name-field person :last-name) "growx"]])))
34 33
35 34
36 35 ; Make some people
4 src/seesaw/forms.clj
@@ -24,7 +24,7 @@
24 24 (extend-protocol ComponentSpec
25 25 Object
26 26 (append [this builder]
27   - (.append builder (seesaw.core/to-widget this true)))
  27 + (.append builder (seesaw.core/make-widget this)))
28 28 String
29 29 (append [this builder]
30 30 (.append builder this)))
@@ -35,7 +35,7 @@
35 35 (reify
36 36 ComponentSpec
37 37 (append [this builder]
38   - (.append builder (seesaw.core/to-widget component true) column-span))))
  38 + (.append builder (seesaw.core/make-widget component) column-span))))
39 39
40 40 (defn next-line
41 41 "Continue with the nth next line in the builder."
39 src/seesaw/to_widget.clj
@@ -13,53 +13,60 @@
13 13 (:import [java.awt Dimension]
14 14 [javax.swing Box JLabel JButton]))
15 15
16   -(defprotocol ToWidget (to-widget* [v create?]))
  16 +(defprotocol ToWidget
  17 + (to-widget* [v]))
  18 +
  19 +(defprotocol MakeWidget
  20 + (make-widget* [v]))
17 21
18 22 ; A couple macros to make definining the ToWidget protocol a little less
19 23 ; tedious. Mostly just for fun...
20 24
21   -(defmacro ^{:private true} def-widget-coercion [t b & forms]
  25 +(defmacro ^{:private true} def-to-widget [t b & forms]
22 26 `(extend-type
23 27 ~t
24 28 ToWidget
25   - (~'to-widget* [~(first b) create?#] ~@forms)))
  29 + (~'to-widget* ~b ~@forms)))
26 30
27   -(defmacro ^{:private true} def-widget-creational-coercion [t b & forms]
  31 +(defmacro ^{:private true} def-make-widget [t b & forms]
28 32 `(extend-type
29 33 ~t
30   - ToWidget
31   - (~'to-widget* [~(first b) create?#] (when create?# ~@forms))))
  34 + MakeWidget
  35 + (~'make-widget* ~b ~@forms)))
32 36
33   -; ... for example, a component coerces to itself.
34   -(def-widget-coercion java.awt.Component [c] c)
  37 +(def-to-widget Object [c] nil)
35 38
36   -(def-widget-coercion java.util.EventObject
  39 +(def-to-widget java.awt.Component [c] c)
  40 +
  41 +(def-to-widget java.util.EventObject
37 42 [v]
38 43 (try-cast java.awt.Component (.getSource v)))
39 44
40   -(def-widget-creational-coercion java.awt.Dimension [v] (Box/createRigidArea v))
  45 +(def-make-widget java.awt.Component [c] c)
  46 +
  47 +(def-make-widget java.awt.Dimension [v] (Box/createRigidArea v))
41 48
42   -(def-widget-creational-coercion javax.swing.Action [v] (JButton. v))
  49 +(def-make-widget javax.swing.Action [v] (JButton. v))
43 50
44   -(def-widget-creational-coercion clojure.lang.Keyword
  51 +(def-make-widget clojure.lang.Keyword
45 52 [v]
46 53 (condp = v
47 54 :separator (javax.swing.JSeparator.)
48 55 :fill-h (Box/createHorizontalGlue)
49 56 :fill-v (Box/createVerticalGlue)))
50 57
51   -(def-widget-creational-coercion clojure.lang.IPersistentVector
  58 +(def-make-widget clojure.lang.IPersistentVector
52 59 [[v0 v1 v2]]
53 60 (cond
54 61 (= :fill-h v0) (Box/createHorizontalStrut v1)
55 62 (= :fill-v v0) (Box/createVerticalStrut v1)
56 63 (= :by v1) (Box/createRigidArea (Dimension. v0 v2))))
57 64
58   -(def-widget-creational-coercion Object
  65 +(def-make-widget String
59 66 [v]
60   - (JLabel. (str v)))
  67 + (JLabel. v))
61 68
62   -(def-widget-creational-coercion java.net.URL
  69 +(def-make-widget java.net.URL
63 70 [v]
64 71 (JLabel. (icon v)))
65 72
52 test/seesaw/test/core.clj
@@ -201,61 +201,73 @@
201 201 (it "hides a widget and returns it"
202 202 (not (.isVisible (hide! (doto (JPanel.) (.setVisible true)))))))
203 203
204   -(describe to-widget
  204 +(describe make-widget
  205 + (it "throws an exception for unsupported arguments"
  206 + (try (make-widget 99) false (catch Exception e true)))
205 207 (it "returns nil if input is nil"
206   - (= nil (to-widget nil)))
  208 + (= nil (make-widget nil)))
207 209 (it "returns input if it's already a widget"
208 210 (let [c (JPanel.)]
209   - (expect (= c (to-widget c)))))
  211 + (expect (= c (make-widget c)))))
210 212 (it "returns input if it's a JFrame"
211 213 (let [c (JFrame.)]
212   - (expect (= c (to-widget c)))))
213   - (it "does not create a new widget if create? param is false"
214   - (expect (nil? (to-widget "HI" false))))
215   - (it "returns a label for text input"
216   - (let [c (to-widget "TEST" true)]
  214 + (expect (= c (make-widget c)))))
  215 + (it "returns a label for string input"
  216 + (let [c (make-widget "TEST")]
217 217 (expect (= "TEST" (.getText c)))))
218 218 (it "returns a button if input is an Action"
219 219 (let [a (action :handler #(println "HI") :name "Test")
220   - c (to-widget a true)]
  220 + c (make-widget a)]
221 221 (expect (isa? (class c) javax.swing.JButton))
222 222 (expect (= "Test" (.getText c)))))
223 223 (it "creates a separator for :separator"
224   - (expect (= javax.swing.JSeparator (class (to-widget :separator true)))))
  224 + (expect (= javax.swing.JSeparator (class (make-widget :separator)))))
225 225 (it "creates horizontal glue for :fill-h"
226   - (let [c (to-widget :fill-h true)]
  226 + (let [c (make-widget :fill-h)]
227 227 (expect (isa? (class c) javax.swing.Box$Filler ))
228 228 (expect (= 32767 (.. c getMaximumSize getWidth)))))
229 229 (it "creates vertical glue for :fill-v"
230   - (let [c (to-widget :fill-v true)]
  230 + (let [c (make-widget :fill-v)]
231 231 (expect (isa? (class c) javax.swing.Box$Filler))
232 232 (expect (= 32767 (.. c getMaximumSize getHeight)))))
233 233 (it "creates a vertical strut for [:fill-v N]"
234   - (let [c (to-widget [:fill-v 99] true)]
  234 + (let [c (make-widget [:fill-v 99])]
235 235 (expect (isa? (class c) javax.swing.Box$Filler))
236 236 (expect (= 32767 (.. c getMaximumSize getWidth)))
237 237 (expect (= 99 (.. c getMaximumSize getHeight)))
238 238 (expect (= 99 (.. c getPreferredSize getHeight)))))
239 239 (it "creates a horizontal strut for [:fill-h N]"
240   - (let [c (to-widget [:fill-h 88] true)]
  240 + (let [c (make-widget [:fill-h 88])]
241 241 (expect (isa? (class c) javax.swing.Box$Filler))
242 242 (expect (= 32767 (.. c getMaximumSize getHeight)))
243 243 (expect (= 88 (.. c getMaximumSize getWidth)))
244 244 (expect (= 88 (.. c getPreferredSize getWidth)))))
245 245 (it "creates a rigid area for a Dimension"
246   - (let [c (to-widget (Dimension. 12 34) true)]
  246 + (let [c (make-widget (Dimension. 12 34))]
247 247 (expect (isa? (class c) javax.swing.Box$Filler))
248 248 (expect (= 12 (.. c getMaximumSize getWidth)))
249 249 (expect (= 34 (.. c getMaximumSize getHeight)))
250 250 (expect (= 12 (.. c getPreferredSize getWidth)))
251 251 (expect (= 34 (.. c getPreferredSize getHeight)))))
252 252 (it "creates a rigid area for a [N :by N]"
253   - (let [c (to-widget [12 :by 34] true)]
  253 + (let [c (make-widget [12 :by 34])]
254 254 (expect (isa? (class c) javax.swing.Box$Filler))
255 255 (expect (= 12 (.. c getMaximumSize getWidth)))
256 256 (expect (= 34 (.. c getMaximumSize getHeight)))
257 257 (expect (= 12 (.. c getPreferredSize getWidth)))
258   - (expect (= 34 (.. c getPreferredSize getHeight)))))
  258 + (expect (= 34 (.. c getPreferredSize getHeight))))))
  259 +
  260 +(describe to-widget
  261 + (it "returns nil for unknown inputs"
  262 + (= nil (to-widget "a string")))
  263 + (it "returns nil if input is nil"
  264 + (= nil (to-widget nil)))
  265 + (it "returns input if it's already a widget"
  266 + (let [c (JPanel.)]
  267 + (expect (= c (to-widget c)))))
  268 + (it "returns input if it's a JFrame"
  269 + (let [c (JFrame.)]
  270 + (expect (= c (to-widget c)))))
259 271 (it "converts an event to its source"
260 272 (let [b (button)
261 273 e (ActionEvent. b 0 "hi")]
@@ -993,10 +1005,10 @@
993 1005 (let [dlg (dialog :content "Nothing" :modal? false)]
994 1006 (expect (= (test-dlg-blocking dlg) dlg))))
995 1007 (testing "return-from-dialog"
996   - (let [ok (to-widget (action :name "Ok" :handler (fn [e] (return-from-dialog e :ok))) true)
997   - cancel (to-widget (action :name "Cancel" :handler (fn [e] (return-from-dialog e :cancel))) true)
  1008 + (let [ok (make-widget (action :name "Ok" :handler (fn [e] (return-from-dialog e :ok))))
  1009 + cancel (make-widget (action :name "Cancel" :handler (fn [e] (return-from-dialog e :cancel))))
998 1010 dlg (dialog :content "Nothing"
999   - :options (map #(to-widget % true) [ok cancel]))]
  1011 + :options (map make-widget [ok cancel]))]
1000 1012 (it "should return value passed to RETURN-FROM-DIALOG from clicking on ok button"
1001 1013 (expect (= (test-dlg-blocking
1002 1014 dlg

0 comments on commit 42ced87

Please sign in to comment.
Something went wrong with that request. Please try again.