root/trunk/projects/bos/web/allocation-area-handlers.lisp

Revision 3671, 11.4 kB (checked in by ksprotte, 4 months ago)

again whitespace cleanup + removed tabs

Line 
1 (in-package :bos.web)
2
3 (enable-interpol-syntax)
4
5 (defclass allocation-area-handler (admin-only-handler edit-object-handler)
6   ())
7
8 (defmethod handle-object-form ((handler allocation-area-handler) action (allocation-area (eql nil)))
9   (with-bos-cms-page (:title "Allocation Areas")
10     (html
11      (:h2 "Defined allocation areas")
12      ((:table :border "1")
13       (:tr (:th "ID")
14            (:th "active?")
15            (:th "total")
16            (:th "free")
17            (:th "%used")
18            (:th "Google Earth view"))
19       (loop for allocation-area in (all-allocation-areas)
20          do (html
21              (:tr
22               (:td (cmslink (format nil "allocation-area/~D" (store-object-id allocation-area))
23                      (:princ-safe (store-object-id allocation-area))))
24               (:td (if (allocation-area-active-p allocation-area) (html "yes") (html "no")))
25               (:td (:princ-safe (allocation-area-total-m2s allocation-area)))
26               (:td (:princ-safe (allocation-area-free-m2s allocation-area)))
27               (:td (:princ-safe (round (allocation-area-percent-used allocation-area))) "%")
28               (:td (cmslink (format nil "look-at-allocation-area/~D" (store-object-id allocation-area))
29                      "fly to view"))))))
30      (:p (cmslink "create-allocation-area" "Create new allocation area")))))
31
32 (defmethod handle-object-form ((handler allocation-area-handler) action allocation-area)
33   (with-bos-cms-page (:title "Allocation Area")
34     (with-slots (active-p left top width height) allocation-area
35       (html
36        ((:table :border "1")
37         (:tr
38          (:td "id")
39          (:td (:princ-safe (store-object-id allocation-area))))
40         (:tr
41          (:td "active?")
42          (:td (if active-p (html "yes") (html "no"))))
43         (:tr
44          (:td "usage")
45          (:td (:princ-safe (round (allocation-area-percent-used allocation-area))) "%"))
46         (:tr
47          (:td "x")
48          (:td (:princ-safe left)))
49         (:tr
50          (:td "y")
51          (:td (:princ-safe top)))
52         (:tr
53          (:td "width")
54          (:td (:princ-safe width)))
55         (:tr
56          (:td "height")
57          (:td (:princ-safe height)))
58         (:tr
59          (:td "total number of sqms")
60          (:td (:princ-safe (allocation-area-total-m2s allocation-area))))
61         (:tr
62          (:td "number of free sqms")
63          (:td (:princ-safe (allocation-area-free-m2s allocation-area))))
64         (:tr
65          (:td "number of contracts")
66          (:td (:princ-safe (length (allocation-area-contracts allocation-area))))))
67        (:p
68         ((:form :method "post")
69          (submit-button "delete" "delete" :confirm "Really delete the allocation area?")
70          (if active-p
71              (submit-button "deactivate" "deactivate" :confirm "Really deactivate the allocation area?")
72              (submit-button "activate" "activate" :confirm "Really activate the allocation area?"))))
73        (:h2 "Allocation Graphics")
74        ((:table :cellspacing "0" :cellpadding "0" :border "0")
75         (loop for y from (floor top 90) below (ceiling (+ top height) 90)
76            do (html (:tr
77                      (loop for x from (floor left 90) below (ceiling (+ left width) 90)
78                         for tile-x = (* 90 x)
79                         for tile-y = (* 90 y)
80                         do (html (:td ((:a :href #?"/enlarge-overview/$(tile-x)/$(tile-y)")
81                                        ((:img :width "90" :height "90" :border "0" :src #?"/overview/$(tile-x)/$(tile-y)"))))))))))))))
82
83 (defmethod handle-object-form ((handler allocation-area-handler) (action (eql :delete)) allocation-area)
84   (delete-object allocation-area)
85   (with-bos-cms-page (:title "Allocation area has been deleted")
86     (:h2 "The allocation area has been deleted")))
87
88 (defmethod handle-object-form ((handler allocation-area-handler) (action (eql :activate)) allocation-area)
89   (bos.m2::activate-allocation-area allocation-area)
90   (with-bos-cms-page (:title "Allocation area has been activated")
91     (:h2 "The allocation area has been activated")))
92
93 (defmethod handle-object-form ((handler allocation-area-handler) (action (eql :deactivate)) allocation-area)
94   (bos.m2::deactivate-allocation-area allocation-area)
95   (with-bos-cms-page (:title "Allocation area has been deactivated")
96     (:h2 "The allocation area has been deactivated")))
97
98 (defclass create-allocation-area-handler (admin-only-handler form-handler)
99   ())
100
101 (defmethod handle-form ((handler create-allocation-area-handler) action)
102   (with-query-params (x y left top)
103     (cond
104       ((and x y left top)
105        (destructuring-bind (x y left top) (mapcar #'parse-integer (list x y left top))
106          (if (or (some (complement #'plusp) (list x y left top))
107                  (<= x left)
108                  (<= y top))
109              (with-bos-cms-page (:title "Invalid area selected")
110                (:h2 "Choose upper left corner first, then lower-right corner"))
111              (redirect (format nil "/allocation-area/~D" (store-object-id
112                                                           (make-allocation-rectangle left top (- x left) (- y top))))))))
113       ((and x y)
114        (redirect (format nil "/map-browser/~A/~A?heading=~A&chosen-url=~A&"
115                          x y
116                          (encode-urlencoded "Choose lower right point of allocation area")
117                          (encode-urlencoded (format nil "~A?left=~A&top=~A&"
118                                                     (hunchentoot:request-uri*)
119                                                     x y)))))
120       (t
121        (with-bos-cms-page (:title "Create allocation area")
122          ((:form :method "POST" :enctype "multipart/form-data"))
123          ((:table :border "0")
124           (:tr ((:td :colspan "2")
125                 (:h2 "Create from list of UTM coordinates")))
126           (:tr (:td "File: ") (:td ((:input :type "file" :name "text-file" :value "*.txt"))))
127           (:tr (:td (submit-button "upload" "upload")))
128           (:tr ((:td :colspan "2")
129                 (:h2 "Create by choosing rectangular area")))
130           (:tr (:td "Start-X") (:td (text-field "start-x" :value 0 :size 5)))
131           (:tr (:td "Start-Y") (:td (text-field "start-y" :value 0 :size 5)))
132           (:tr (:td (submit-button "rectangle" "rectangle")))))))))
133
134 (defmethod handle-form ((handler create-allocation-area-handler) (action (eql :rectangle)))
135   (with-query-params (start-x start-y)
136     (redirect (format nil "/map-browser/~A/~A?heading=~A&chosen-url=~A&"
137                       start-x start-y
138                       (encode-urlencoded "Choose upper left point of allocation area")
139                       (encode-urlencoded (format nil "~A?" (hunchentoot:request-uri*)))))))
140
141 (defmethod handle-form ((handler create-allocation-area-handler) (action (eql :upload)))
142   (let ((uploaded-text-file (request-uploaded-file "text-file")))
143     (cond
144       ((not uploaded-text-file)
145        (with-bos-cms-page (:title "No Text file uploaded")
146          (:h2 "File not uploaded")
147          (:p "Please upload your text file containing the allocation polygon UTM coordinates")))
148       (t
149        (with-bos-cms-page (:title #?"Importing allocation polygons from uploaded text file")
150          (handler-case
151              (let* ((vertices (polygon-from-text-file (upload-pathname uploaded-text-file)))
152                     (existing-area (find (coerce vertices 'list)
153                                          (class-instances 'allocation-area)
154                                          :key #'(lambda (area) (coerce (allocation-area-vertices area) 'list))
155                                          :test #'equal)))
156                (if existing-area
157                    (html (:p (:h2 "Polygon already imported")
158                              "The polygon " (:princ-safe vertices) " has already been "
159                              "imported as "
160                              (cmslink (format nil "allocation-area/~D" (store-object-id existing-area))
161                                "allocation area " (:princ-safe (store-object-id existing-area)))))
162                    (let ((allocation-area (make-allocation-area vertices)))
163                      (html (:p (:h2 "Successfully imported new allocation area")
164                                "The polygon "
165                                (cmslink (format nil "allocation-area/~D" (store-object-id allocation-area))
166                                  (:princ-safe (store-object-id allocation-area)))
167                                " has been successfully imported")))))
168            (error (e)
169              (html
170               (:h2 "Error reading the text file")
171               (:p "Please make sure that the uploaded file only contains a simple path.")
172               (:p "The error encountered is:")
173               (:pre (:princ-safe e))))))))))
174
175 (defun ensure-line (file regex &key skip)
176   (handler-case
177       (loop for line = (read-line file)
178          when (scan regex line)
179          do (return-from ensure-line)
180          when (not skip)
181          do (error "expected ~A but read ~A from file ~A" regex line file))
182     (error (e)
183       (error "error ~A on file ~A while waiting for ~A" e file regex))))
184
185 (defun ensure-float (x)
186   (typecase x
187     (float t)
188     (integer t)
189     (t (error "invalid number ~S" x))))
190
191 (defun scale-coordinate (name min x)
192   (unless (and (>= x min)
193                (<= x (+ min +width+)))
194     (error "invalid ~A coordinate ~A (must be between ~A and ~A)" name x min (+ min +width+)))
195   (round (- x min)))
196
197 (defun parse-point (line)
198   (let ((line (string-right-trim '(#\Return) line)))
199     (unless (ppcre:scan line "^\\s*$")
200       (destructuring-bind (x y) (read-from-string (format nil "(~A)" line))
201         (cons (scale-coordinate 'x +nw-utm-x+ x)
202               (- +width+ (scale-coordinate 'y (- +nw-utm-y+ +width+) y)))))))
203
204 (defun polygon-from-text-file (filename)
205   (coerce (with-open-file (input-file filename)
206             (loop
207                with last-point
208                for line-number from 1
209                for line = (read-line input-file nil)
210                while line
211                for point = (handler-case
212                                (parse-point line)
213                              (error (e)
214                                (error "Problem with text file in line ~A '~A': ~A in " line-number line e)))
215                when (and point (not (equal point last-point)))
216                collect (setq last-point point)))
217           'vector))
218
219 (defun parse-illustrator-point (line)
220   (destructuring-bind (x y type &rest foo) (split " " line)
221     (declare (ignore foo))
222     (unless (scan #?r"^[lm]$" type)
223       (html "Could not parse line from illustrator file:"
224             (:pre (:princ-safe line))))
225     (cons (round (read-from-string x))
226           (round (- 10800 (read-from-string y))))))
227
228 (defun polygons-from-illustrator-file (filename)
229   ;; convert from mac line endings to dos line endings
230   (with-open-file (input-file filename)
231     (with-input-from-string (file (regex-replace-all #?r"\r" (read-line input-file) #?"\n"))
232       (ensure-line file #?r"^%!PS-Adobe-2.0")
233       (ensure-line file #?r"^%AI3_Cropmarks: 0 0 10800 10800" :skip t)
234       (ensure-line file #?r"^%%Note:" :skip t)
235       (let (polygons)
236         (loop for polygon = (loop for line = (read-line file)
237                                until (scan #?r"^n" line)
238                                collect (parse-illustrator-point line))
239            do (when (equal (first polygon)
240                            (first (last polygon)))
241                 (setf polygon (cdr polygon)))
242            do (push (coerce polygon 'vector) polygons)
243            until (equal #\% (peek-char nil file)))
244         (ensure-line file #?r"^%%EOF" :skip t)
245         polygons))))
Note: See TracBrowser for help on using the browser.