Merge lp:~phcteam/clinica-project/dnd into lp:clinica-project/trunk
- dnd
- Merge into master
Proposed by
Leonardo Robol
Status: | Merged |
---|---|
Approved by: | Leonardo Robol |
Approved revision: | 322 |
Merged at revision: | 299 |
Proposed branch: | lp:~phcteam/clinica-project/dnd |
Merge into: | lp:clinica-project/trunk |
Diff against target: |
2117 lines (+1303/-123) (has conflicts) 24 files modified
clinica/Clinica.vala (+1/-1) clinica/wscript (+0/-3) libclinica/Calendar.vala (+45/-9) libclinica/CalendarEventList.vala (+49/-0) libclinica/CalendarToolbar.vala (+35/-8) libclinica/CalendarView.vala (+13/-9) libclinica/CalendarWindow.vala (+63/-0) libclinica/DateHandler.vala (+0/-1) libclinica/Day.vala (+172/-18) libclinica/DoctorListStore.vala (+1/-1) libclinica/Event.vala (+172/-0) libclinica/EventEditor.vala (+224/-0) libclinica/EventListStore.vala (+123/-0) libclinica/PatientEditor.vala (+30/-15) libclinica/PatientEntry.vala (+168/-0) libclinica/PatientListView.vala (+7/-0) libclinica/ResourceManager.vala (+110/-10) libclinica/SqlDataType.vala (+43/-10) libclinica/UserInterface.vala (+6/-1) libclinica/Visit.vala (+17/-4) libclinica/wscript (+2/-2) ui/patient_editor.glade (+11/-25) ui/window.glade (+1/-1) wscript (+10/-5) Text conflict in wscript |
To merge this branch: | bzr merge lp:~phcteam/clinica-project/dnd |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PHC Team | Pending | ||
Review via email: mp+78359@code.launchpad.net |
Commit message
Description of the change
Added basilare event support, with drag and dropping from patients.
Small cleanup even in the database upgrade.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'clinica/Clinica.vala' |
2 | --- clinica/Clinica.vala 2011-09-22 19:27:52 +0000 |
3 | +++ clinica/Clinica.vala 2011-10-06 07:06:24 +0000 |
4 | @@ -60,6 +60,7 @@ |
5 | |
6 | /* Init resource manager and connect error function |
7 | * to a message display for the user */ |
8 | + Gdk.threads_enter (); |
9 | var resources = new ResourceManager (args[0], Utils.show_error_message); |
10 | |
11 | /* Init gettext translation system */ |
12 | @@ -83,7 +84,6 @@ |
13 | var user_interface = new UserInterface (resources); |
14 | |
15 | /* Actually start the application */ |
16 | - Gdk.threads_enter (); |
17 | user_interface.start (); |
18 | Gdk.threads_leave (); |
19 | |
20 | |
21 | === modified file 'clinica/wscript' |
22 | --- clinica/wscript 2011-09-22 23:25:12 +0000 |
23 | +++ clinica/wscript 2011-10-06 07:06:24 +0000 |
24 | @@ -24,6 +24,3 @@ |
25 | |
26 | # Extra includes |
27 | prog.includes = [ '.', '../libclinica' ] |
28 | - |
29 | - # Enable threading |
30 | - prog.threading = True |
31 | |
32 | === modified file 'libclinica/Calendar.vala' |
33 | --- libclinica/Calendar.vala 2011-09-22 19:27:52 +0000 |
34 | +++ libclinica/Calendar.vala 2011-10-06 07:06:24 +0000 |
35 | @@ -25,6 +25,7 @@ |
36 | |
37 | public DateHandler handler { get; private set; } |
38 | private CalendarView calendar_view; |
39 | + private ResourceManager resource_manager { get; set; } |
40 | |
41 | internal Day[] days; |
42 | |
43 | @@ -35,12 +36,13 @@ |
44 | } |
45 | } |
46 | |
47 | - public Calendar (CalendarView view) { |
48 | + public Calendar (ResourceManager resources, CalendarView view) { |
49 | + this.resource_manager = resources; |
50 | this.calendar_view = view; |
51 | |
52 | handler = new DateHandler (); |
53 | |
54 | - // Gtk.Table properties |
55 | + /* Gtk.Table properties */ |
56 | n_rows = 6; |
57 | n_columns = 7; |
58 | column_spacing = 0; |
59 | @@ -57,10 +59,10 @@ |
60 | } |
61 | update_month (); |
62 | |
63 | - // Signals and handlers |
64 | + /* Signals and handlers */ |
65 | handler.changed.connect (update_month); |
66 | |
67 | - // Change today when it changes |
68 | + /* Change today when it changes */ |
69 | var today = new DateTime.now_local (); |
70 | var tomorrow = today.add_full (0, 0, 1, -today.get_hour (), -today.get_minute (), -today.get_second ()); |
71 | var difference = tomorrow.to_unix() - today.to_unix(); |
72 | @@ -83,6 +85,8 @@ |
73 | return false; |
74 | }); |
75 | |
76 | + resource_manager.event_list_store.event_added.connect (on_event_added); |
77 | + resource_manager.event_list_store.event_removed.connect (on_event_removed); |
78 | realize.connect (() => set_date (today)); |
79 | } |
80 | |
81 | @@ -91,15 +95,13 @@ |
82 | } |
83 | |
84 | public void set_date (DateTime date) { |
85 | - |
86 | if (handler.current_month != date.get_month () || handler.current_year != date.get_year ()) |
87 | handler.add_full_offset (date.get_month () - handler.current_month, date.get_year () - handler.current_year); |
88 | |
89 | days[date_to_index (date.get_day_of_month ())].grab_focus (); |
90 | } |
91 | |
92 | - private void update_month () { |
93 | - |
94 | + internal void update_month () { |
95 | var today = new DateTime.now_local (); |
96 | int month = handler.current_month; |
97 | int year = handler.current_year; |
98 | @@ -107,6 +109,16 @@ |
99 | var date = new DateTime.local (year, month, 1, 0, 0, 0).add_days (-days_to_prepend); |
100 | |
101 | foreach (var day in days) { |
102 | + /* Fill events of the day */ |
103 | + day.reset_events (); |
104 | + foreach (var visit in Visit.for_day (resource_manager, date)) { |
105 | + /* Display visits in the day */ |
106 | + day.add_visit (visit); |
107 | + } |
108 | + foreach (var event in Event.for_day (resource_manager, date)) { |
109 | + day.add_event (event); |
110 | + } |
111 | + |
112 | if (date.get_day_of_year () == today.get_day_of_year () && date.get_year () == today.get_year ()) { |
113 | day.name = "today"; |
114 | day.can_focus = true; |
115 | @@ -126,12 +138,36 @@ |
116 | } |
117 | } |
118 | |
119 | - |
120 | - |
121 | private int date_to_index (int day_of_month) { |
122 | return days_to_prepend + day_of_month - 1; |
123 | } |
124 | |
125 | + /** |
126 | + * @brief Callback called when an event is pushed to the EventListStore |
127 | + * |
128 | + * It should find the day of the event, if present in the view, and |
129 | + * insert the events in it. |
130 | + */ |
131 | + private void on_event_added (Event event) { |
132 | + DateTime event_date = event.date; |
133 | + if (event_date.get_month () != handler.current_month) |
134 | + return; |
135 | + if (event_date.get_year () != handler.current_year) |
136 | + return; |
137 | + |
138 | + /* Otherwise add the event to the right */ |
139 | + days[date_to_index (event_date.get_day_of_month ())].add_event (event); |
140 | + } |
141 | + |
142 | + /** |
143 | + * @brief Callback called when an event is removed from the EventListStore |
144 | + * |
145 | + * It should find the day that contained the event and remove it from the |
146 | + * view. |
147 | + */ |
148 | + private void on_event_removed (Event event) { |
149 | + } |
150 | + |
151 | } |
152 | |
153 | } |
154 | |
155 | === added file 'libclinica/CalendarEventList.vala' |
156 | --- libclinica/CalendarEventList.vala 1970-01-01 00:00:00 +0000 |
157 | +++ libclinica/CalendarEventList.vala 2011-10-06 07:06:24 +0000 |
158 | @@ -0,0 +1,49 @@ |
159 | +/* |
160 | + * This file is part of Clinica. |
161 | + * |
162 | + * Clinica is free software: you can redistribute it and/or modify |
163 | + * it under the terms of the GNU General Public License as published by |
164 | + * the Free Software Foundation, either version 3 of the License, or |
165 | + * (at your option) any later version. |
166 | + * |
167 | + * Clinica is distributed in the hope that it will be useful, |
168 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
169 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
170 | + * GNU General Public License for more details. |
171 | + * |
172 | + * You should have received a copy of the GNU General Public License |
173 | + * along with Clinica. If not, see <http://www.gnu.org/licenses/>. |
174 | + * |
175 | + * Authors: Leonardo Robol <leo@robol.it> |
176 | + * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it> |
177 | + */ |
178 | + |
179 | + using Gtk; |
180 | + |
181 | + namespace Clinica { |
182 | + |
183 | + public class CalendarEventList : Alignment { |
184 | + |
185 | + private ResourceManager resource_manager { get; private set; } |
186 | + |
187 | + public CalendarEventList (ResourceManager resources) { |
188 | + resource_manager = resources; |
189 | + |
190 | + /* Set the right padding, according to what is set in |
191 | + * the resource_manager */ |
192 | + set_padding (resource_manager.PADDING, resource_manager.PADDING, |
193 | + resource_manager.PADDING, resource_manager.PADDING); |
194 | + |
195 | + /* Create a header for the event list */ |
196 | + var title = new Label (""); |
197 | + title.set_markup (_("<b>What's next:</b>")); |
198 | + |
199 | + /* Pack all the widgets together */ |
200 | + var box = new VBox (false, 0); |
201 | + box.pack_start (title, false); |
202 | + add (box); |
203 | + |
204 | + set_size_request (250, -1); |
205 | + } |
206 | + } |
207 | + } |
208 | |
209 | === modified file 'libclinica/CalendarToolbar.vala' |
210 | --- libclinica/CalendarToolbar.vala 2011-09-22 19:27:52 +0000 |
211 | +++ libclinica/CalendarToolbar.vala 2011-10-06 07:06:24 +0000 |
212 | @@ -25,15 +25,30 @@ |
213 | |
214 | public class CalendarToolbar : Gtk.Toolbar { |
215 | |
216 | + /** |
217 | + * @brief Switcher for the months |
218 | + */ |
219 | internal DateSwitcher month_switcher; |
220 | + |
221 | + /** |
222 | + * @brief Switcher for the years. |
223 | + */ |
224 | internal DateSwitcher year_switcher; |
225 | - private CalendarView calendar_view; |
226 | - |
227 | - public CalendarToolbar (CalendarView view) { |
228 | - this.calendar_view = view; |
229 | + |
230 | + internal Button add_event_button; |
231 | + |
232 | + private ResourceManager resource_manager; |
233 | + |
234 | + public CalendarToolbar (ResourceManager resources) { |
235 | + resource_manager = resources; |
236 | |
237 | /* Get the look of Ubuntu and elementaries toolbars */ |
238 | get_style_context ().add_class ("primary-toolbar"); |
239 | + |
240 | + add_event_button = new Button.from_stock (Stock.ADD); |
241 | + var add_item = new ToolItem (); |
242 | + add_item.add (add_event_button); |
243 | + add_event_button.clicked.connect (on_add_button_clicked); |
244 | |
245 | /* Request a decent width for the month switcher so it's likely |
246 | * not to resize on month name change */ |
247 | @@ -45,22 +60,34 @@ |
248 | var year_toolitem = new ToolItem (); |
249 | year_toolitem.add (year_switcher); |
250 | |
251 | + /* The add button first */ |
252 | + insert (add_item, 0); |
253 | + |
254 | /* Insert a spacer before and after the month and |
255 | * year switcher so they don't end in a corner */ |
256 | var left_spacer = new ToolItem (); |
257 | left_spacer.set_expand (true); |
258 | - insert (left_spacer, 0); |
259 | + insert (left_spacer, 1); |
260 | + insert (month_toolitem, 2); |
261 | |
262 | - insert (month_toolitem, 1); |
263 | /* Even some margin between the two selectors */ |
264 | month_toolitem.set_margin_right (10); |
265 | - insert (year_toolitem, 2); |
266 | + insert (year_toolitem, 3); |
267 | |
268 | /* The right spacer that keep our control buttons |
269 | * centered in the toolbar */ |
270 | var right_spacer = new ToolItem (); |
271 | right_spacer.set_expand (true); |
272 | - insert (right_spacer, 3); |
273 | + insert (right_spacer, 4); |
274 | + } |
275 | + |
276 | + public void on_add_button_clicked (Button button) { |
277 | + var event_editor = new EventEditor (resource_manager); |
278 | + if (event_editor.run () == EventEditor.Response.SAVE) { |
279 | + event_editor.selected_event.save (); |
280 | + resource_manager.event_list_store.add_event (event_editor.selected_event); |
281 | + } |
282 | + event_editor.destroy (); |
283 | } |
284 | } |
285 | } |
286 | |
287 | === modified file 'libclinica/CalendarView.vala' |
288 | --- libclinica/CalendarView.vala 2011-09-22 19:27:52 +0000 |
289 | +++ libclinica/CalendarView.vala 2011-10-06 07:06:24 +0000 |
290 | @@ -61,11 +61,14 @@ |
291 | |
292 | public CalendarHeader header { get; private set; } |
293 | public Calendar calendar { get; private set; } |
294 | - public CalendarToolbar toolbar { get; private set; } |
295 | public CssProvider style_context { get; private set; } |
296 | + public CalendarToolbar toolbar { get; set; } |
297 | + internal ResourceManager resource_manager { get; private set; } |
298 | |
299 | - public CalendarView () { |
300 | + public CalendarView (ResourceManager resources, CalendarToolbar toolbar) { |
301 | GLib.Object (spacing: 0, homogeneous: false); |
302 | + resource_manager = resources; |
303 | + this.toolbar = toolbar; |
304 | |
305 | /* Create CssProvider */ |
306 | style_context = new CssProvider (); |
307 | @@ -76,11 +79,9 @@ |
308 | } |
309 | |
310 | /* Create elements of the calendar view */ |
311 | - toolbar = new CalendarToolbar (this); |
312 | header = new CalendarHeader (this); |
313 | - calendar = new Calendar (this); |
314 | + calendar = new Calendar (resource_manager, this); |
315 | |
316 | - pack_start (toolbar, false, false, 0); |
317 | pack_start (header, false, false, 0); |
318 | pack_end (calendar, true, true, 0); |
319 | |
320 | @@ -103,10 +104,6 @@ |
321 | |
322 | var date = new DateTime.local (year, month, 1, 0, 0, 0).add_days (-calendar.days_to_prepend); |
323 | |
324 | - // Update switcher text |
325 | - toolbar.month_switcher.text = calendar.handler.format ("%B"); |
326 | - toolbar.year_switcher.text = calendar.handler.format ("%Y"); |
327 | - |
328 | foreach (var day in calendar.days) { |
329 | if (date.get_day_of_year () == today.get_day_of_year () && date.get_year () == today.get_year ()) { |
330 | day.name = "today"; |
331 | @@ -125,6 +122,13 @@ |
332 | day.date = date; |
333 | date = date.add_days (1); |
334 | } |
335 | + |
336 | + /* Update events displayed in the calendar */ |
337 | + calendar.update_month (); |
338 | + |
339 | + /* Update switcher text */ |
340 | + toolbar.month_switcher.text = calendar.handler.format ("%B"); |
341 | + toolbar.year_switcher.text = calendar.handler.format ("%Y"); |
342 | } |
343 | |
344 | } |
345 | |
346 | === added file 'libclinica/CalendarWindow.vala' |
347 | --- libclinica/CalendarWindow.vala 1970-01-01 00:00:00 +0000 |
348 | +++ libclinica/CalendarWindow.vala 2011-10-06 07:06:24 +0000 |
349 | @@ -0,0 +1,63 @@ |
350 | +/* |
351 | + * This file is part of Clinica. |
352 | + * |
353 | + * Clinica is free software: you can redistribute it and/or modify |
354 | + * it under the terms of the GNU General Public License as published by |
355 | + * the Free Software Foundation, either version 3 of the License, or |
356 | + * (at your option) any later version. |
357 | + * |
358 | + * Clinica is distributed in the hope that it will be useful, |
359 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
360 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
361 | + * GNU General Public License for more details. |
362 | + * |
363 | + * You should have received a copy of the GNU General Public License |
364 | + * along with Clinica. If not, see <http://www.gnu.org/licenses/>. |
365 | + * |
366 | + * Authors: Leonardo Robol <leo@robol.it> |
367 | + * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it> |
368 | + */ |
369 | + |
370 | + using Gtk; |
371 | + |
372 | + namespace Clinica { |
373 | + |
374 | + public class CalendarWindow : Gtk.Window { |
375 | + |
376 | + private ResourceManager resource_manager { get; set; } |
377 | + private CalendarView calendar_view { get; set; } |
378 | + private CalendarEventList event_widget { get; set; } |
379 | + public CalendarToolbar toolbar { get; private set; } |
380 | + |
381 | + public CalendarWindow (ResourceManager resources) { |
382 | + GLib.Object (type: WindowType.TOPLEVEL); |
383 | + resource_manager = resources; |
384 | + |
385 | + set_title (_("Clinica calendar")); |
386 | + |
387 | + /* The Toolbar used to switch */ |
388 | + toolbar = new CalendarToolbar (resource_manager); |
389 | + |
390 | + /* Create the calendar view */ |
391 | + calendar_view = new CalendarView (resource_manager, toolbar); |
392 | + |
393 | + /* And the widget that display the events present in the calendar. |
394 | + * This is a label that does nothing for the moment being. */ |
395 | + event_widget = new CalendarEventList (resource_manager); |
396 | + |
397 | + /* Pack widgets in the box */ |
398 | + var main_table = new Table (2, 2, false); |
399 | + main_table.attach (toolbar, 0, 2, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, |
400 | + AttachOptions.FILL, 0, 0); |
401 | + main_table.attach (calendar_view, 0, 1, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, |
402 | + AttachOptions.EXPAND | AttachOptions.FILL, 0, 0); |
403 | + main_table.attach (event_widget, 1, 2, 1, 2, AttachOptions.FILL, |
404 | + AttachOptions.EXPAND | AttachOptions.FILL, 0, 0); |
405 | + |
406 | + /* Create an alignment to set the right padding of the window */ |
407 | + var alignment = new Alignment (0.5F, 0.5F, 1.0F, 1.0F); |
408 | + alignment.add (main_table); |
409 | + add (alignment); |
410 | + } |
411 | + } |
412 | + } |
413 | |
414 | === modified file 'libclinica/DateHandler.vala' |
415 | --- libclinica/DateHandler.vala 2011-09-22 19:27:52 +0000 |
416 | +++ libclinica/DateHandler.vala 2011-10-06 07:06:24 +0000 |
417 | @@ -54,7 +54,6 @@ |
418 | } |
419 | |
420 | public DateHandler () { |
421 | - |
422 | date = new DateTime.now_local (); |
423 | } |
424 | |
425 | |
426 | === modified file 'libclinica/Day.vala' |
427 | --- libclinica/Day.vala 2011-09-22 19:27:52 +0000 |
428 | +++ libclinica/Day.vala 2011-10-06 07:06:24 +0000 |
429 | @@ -32,48 +32,92 @@ |
430 | private DrawingArea area; |
431 | |
432 | public DateTime date { get; set; } |
433 | - private CalendarView calendar_view; |
434 | + private CalendarView calendar_view { get; set; } |
435 | + private ResourceManager resource_manager { get; set; } |
436 | + |
437 | + private double highlight_level = 0; |
438 | + |
439 | + private GLib.List<Visit> visit_list; |
440 | + private GLib.List<Event> event_list; |
441 | |
442 | public Day (CalendarView view) { |
443 | this.calendar_view = view; |
444 | + this.resource_manager = view.resource_manager; |
445 | |
446 | /* vbox = new VBox (false, 0); |
447 | label = new Label (""); */ |
448 | area = new DrawingArea (); |
449 | |
450 | - // EventBox Properties |
451 | + /* EventBox Properties */ |
452 | can_focus = true; |
453 | set_visible_window (true); |
454 | events |= EventMask.BUTTON_PRESS_MASK; |
455 | |
456 | get_style_context ().add_provider (calendar_view.style_context, 600); |
457 | get_style_context ().add_class ("cell"); |
458 | - set_size_request (70,70); |
459 | - |
460 | - /* label.halign = Align.END; |
461 | - label.get_style_context ().add_provider (calendar_view.style_context, 600); |
462 | - label.name = "date"; |
463 | - vbox.pack_start (label, false, false, 0); */ |
464 | - |
465 | - /* vbox.margin_bottom = vbox.margin_top = vbox.margin_left = vbox.margin_right = 3; */ |
466 | + set_size_request (90, 90); |
467 | + |
468 | area.draw.connect (on_area_draw); |
469 | add (area); |
470 | |
471 | - // Signals and handlers |
472 | + /* Signals and handlers */ |
473 | button_press_event.connect (on_button_press); |
474 | focus_in_event.connect (on_focus_in); |
475 | focus_out_event.connect (on_focus_out); |
476 | draw.connect (on_draw); |
477 | |
478 | - // notify["date"].connect (() => label.label = date.get_day_of_month ().to_string ()); |
479 | notify["date"].connect (on_date_changed); |
480 | + |
481 | + /* Drag and drop support */ |
482 | + TargetEntry patient_target = { "PATIENT", 0, 1 }; |
483 | + drag_dest_set (this, DestDefaults.ALL | DestDefaults.HIGHLIGHT , |
484 | + { patient_target }, DragAction.COPY); |
485 | + drag_drop.connect (on_drag_drop); |
486 | + drag_motion.connect (on_drag_motion); |
487 | + drag_leave.connect ((context, time) => { highlight_level = 0.0; queue_draw (); }); |
488 | + } |
489 | + |
490 | + private bool on_drag_drop (Widget widget, Gdk.DragContext context, int x, int y, uint time) |
491 | + { |
492 | + var patient = resource_manager.dragging_patient; |
493 | + if (patient == null) { |
494 | + debug ("Not doing drag and drop since resource_manager.dragging_patient is null"); |
495 | + return false; |
496 | + } |
497 | + debug ("You dropped patient: %s on day %s", patient.get_complete_name (), |
498 | + date.format ("%F")); |
499 | + drag_finish (context, true, false, time); |
500 | + resource_manager.dragging_patient = null; |
501 | + |
502 | + var event_editor = new EventEditor.with_date (resource_manager, date); |
503 | + event_editor.select_patient (patient); |
504 | + if (event_editor.run () == EventEditor.Response.SAVE) { |
505 | + /* Save the event in the editor */ |
506 | + event_editor.selected_event.save (); |
507 | + resource_manager.event_list_store.add_event (event_editor.selected_event); |
508 | + } |
509 | + event_editor.destroy (); |
510 | + return true; |
511 | + } |
512 | + |
513 | + private bool on_drag_motion (Widget widget, Gdk.DragContext context, int x, int y, uint time) { |
514 | + int height = widget.get_allocated_height(); |
515 | + int width = widget.get_allocated_width (); |
516 | + highlight_level = 16.0 * (1.0 * width - x) * x * y * (height - y) / (width*width) / (height * height); |
517 | + queue_draw (); |
518 | + return false; |
519 | } |
520 | |
521 | private void on_date_changed () { |
522 | - |
523 | + if (calendar_view.calendar == null) |
524 | + return; |
525 | + if (date.get_month () != calendar_view.calendar.handler.current_month) |
526 | + can_focus = false; |
527 | } |
528 | |
529 | private bool on_area_draw (Widget w, Context ctx) { |
530 | + TextExtents extents; |
531 | + |
532 | /* Get allocation */ |
533 | var height = w.get_allocated_height (); |
534 | var width = w.get_allocated_width (); |
535 | @@ -89,19 +133,83 @@ |
536 | ctx.set_source_rgba (0.1, 0.1, 0.1, 0.2); |
537 | ctx.rectangle (0, 0, width, height); |
538 | ctx.fill (); |
539 | + } else { |
540 | + ctx.set_source_rgba (0.1, 0.1, 0.1, 0.07); |
541 | + ctx.rectangle (0, 0, width, height); |
542 | + ctx.fill (); |
543 | } |
544 | |
545 | + /* Draw the background if dragging over this, red if it is |
546 | + * saturday or sunday, blue otherwise! */ |
547 | + if (highlight_level != 0 && can_focus) { |
548 | + if (date.get_day_of_week () > 5) { |
549 | + ctx.set_source_rgba (0.5 + 0.5 * highlight_level, 0, 0, 0.2 + 0.5 * highlight_level); |
550 | + } |
551 | + else { |
552 | + ctx.set_source_rgba (0, 0, 0.5 * (1 + highlight_level), 0.2 + 0.5 * highlight_level); |
553 | + } |
554 | + ctx.rectangle (0, 0, width, height); |
555 | + ctx.fill (); |
556 | + } |
557 | + |
558 | /* If we have the focus draw the light :) */ |
559 | if (has_focus) { |
560 | - ctx.set_source_rgba (0.1, 0.1, 1, 0.2); |
561 | + ctx.set_source_rgba (0.1 + 0.9 * highlight_level, 0.1, 1, 0.2); |
562 | ctx.rectangle (0, 0, width, height); |
563 | ctx.fill (); |
564 | } |
565 | |
566 | + /* Draw another green layer if there are events on this day, we should |
567 | + * also render events in the calendar */ |
568 | + var event_number = visit_list.length () + event_list.length (); |
569 | + if (can_focus && event_number > 0) { |
570 | + |
571 | + /* Set the color of the day according to how much is busy */ |
572 | + if (event_number < 2) |
573 | + ctx.set_source_rgba (0.2, 1.0, 0.2, 0.3); |
574 | + else if (event_number < 4) |
575 | + ctx.set_source_rgba (1.0, 0.55, 0.0, 0.3); |
576 | + else |
577 | + ctx.set_source_rgba (1.0, 0.2 , 0.2, 0.3); |
578 | + |
579 | + ctx.rectangle (0, 0, width, height); |
580 | + ctx.fill (); |
581 | + |
582 | + ctx.set_source_rgba (0.1, 0.1, 0.1, 0.7); |
583 | + ctx.set_font_size (12.0); |
584 | + double line_position = 12; |
585 | + double line_height = 15.0; |
586 | + Gee.LinkedList<int> displayed_patients_id = new Gee.LinkedList<int> (); |
587 | + ctx.rectangle (0, 0, width - 8, height - 8); |
588 | + ctx.clip (); |
589 | + foreach (var visit in visit_list) { |
590 | + if (visit.patient.get_id () in displayed_patients_id) |
591 | + continue; |
592 | + displayed_patients_id.add (visit.patient.get_id ()); |
593 | + string text = visit.patient.get_complete_name ();; |
594 | + ctx.text_extents (text, out extents); |
595 | + ctx.move_to (8 - extents.x_bearing, |
596 | + line_position + line_height / 2 - extents.y_bearing); |
597 | + line_position += line_height; |
598 | + ctx.show_text (text); |
599 | + } |
600 | + |
601 | + foreach (var event in event_list) { |
602 | + string text = event.title; |
603 | + ctx.text_extents (text, out extents); |
604 | + ctx.move_to (8 - extents.x_bearing, |
605 | + line_position + line_height / 2 - extents.y_bearing); |
606 | + line_position += line_height; |
607 | + ctx.show_text (text); |
608 | + } |
609 | + |
610 | + /* Undo the clipping to make the whole day drawable */ |
611 | + ctx.restore (); |
612 | + } |
613 | + |
614 | /* Draw number with the date with the usual switch on can_focus |
615 | - * to render properly hiddent date (of the past and future month). */ |
616 | + * to render properly hidden date (of the past and future month). */ |
617 | string date = date.get_day_of_month ().to_string (); |
618 | - TextExtents extents; |
619 | ctx.set_font_size (12.0); |
620 | if (can_focus) |
621 | ctx.set_source_rgba (0.1, 0.1, 0.1, 0.7); |
622 | @@ -143,14 +251,60 @@ |
623 | cr.set_antialias (Antialias.NONE); |
624 | cr.stroke (); |
625 | |
626 | - // Draw inner highlight stroke |
627 | + cr.set_source_rgba (1.0, 1.0, 1.0, 0.2); |
628 | cr.rectangle (1.5, 1.5, size.width - 1.5, size.height - 1.5); |
629 | - cr.set_source_rgba (1.0, 1.0, 1.0, 0.2); |
630 | cr.stroke (); |
631 | |
632 | return false; |
633 | } |
634 | |
635 | + /** |
636 | + * @brief Add a new visit for this day |
637 | + */ |
638 | + public void add_visit (Visit visit) { |
639 | + visit_list.append (visit); |
640 | + area.queue_draw (); |
641 | + } |
642 | + |
643 | + /** |
644 | + * @brief Remove a visit from the list |
645 | + */ |
646 | + public void remove_visit (Visit visit) { |
647 | + foreach (var v in visit_list) { |
648 | + if (v.get_id () == visit.get_id ()) { |
649 | + visit_list.remove (v); |
650 | + area.queue_draw (); |
651 | + return; |
652 | + } |
653 | + } |
654 | + } |
655 | + |
656 | + /** |
657 | + * @brief Add a new event for this day |
658 | + */ |
659 | + public void add_event (Event event) { |
660 | + event_list.append (event); |
661 | + area.queue_draw (); |
662 | + } |
663 | + |
664 | + /** |
665 | + * @brief Remove an event in the list. |
666 | + */ |
667 | + public void remove_event (Event event) { |
668 | + foreach (var e in event_list) { |
669 | + if (e.get_id () == event.get_id ()) { |
670 | + event_list.remove (e); |
671 | + area.queue_draw (); |
672 | + return; |
673 | + } |
674 | + } |
675 | + } |
676 | + |
677 | + public void reset_events () { |
678 | + event_list = new List<Event> (); |
679 | + visit_list = new List<Visit> (); |
680 | + } |
681 | + |
682 | } |
683 | |
684 | } |
685 | |
686 | === modified file 'libclinica/DoctorListStore.vala' |
687 | --- libclinica/DoctorListStore.vala 2011-09-22 19:27:52 +0000 |
688 | +++ libclinica/DoctorListStore.vala 2011-10-06 07:06:24 +0000 |
689 | @@ -33,7 +33,7 @@ |
690 | |
691 | public signal void error (string message); |
692 | |
693 | - private ResourceManager resource_manager; |
694 | + private ResourceManager resource_manager { get; set; } |
695 | |
696 | public class DoctorListStore (ResourceManager resources) { |
697 | resource_manager = resources; |
698 | |
699 | === added file 'libclinica/Event.vala' |
700 | --- libclinica/Event.vala 1970-01-01 00:00:00 +0000 |
701 | +++ libclinica/Event.vala 2011-10-06 07:06:24 +0000 |
702 | @@ -0,0 +1,172 @@ |
703 | +/* |
704 | + * This file is part of Clinica. |
705 | + * |
706 | + * Clinica is free software: you can redistribute it and/or modify |
707 | + * it under the terms of the GNU General Public License as published by |
708 | + * the Free Software Foundation, either version 3 of the License, or |
709 | + * (at your option) any later version. |
710 | + * |
711 | + * Clinica is distributed in the hope that it will be useful, |
712 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
713 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
714 | + * GNU General Public License for more details. |
715 | + * |
716 | + * You should have received a copy of the GNU General Public License |
717 | + * along with Clinica. If not, see <http://www.gnu.org/licenses/>. |
718 | + * |
719 | + * Authors: Leonardo Robol <leo@robol.it> |
720 | + * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it> |
721 | + */ |
722 | + |
723 | +namespace Clinica { |
724 | + |
725 | + public class EventIterator : SqlDataIterator { |
726 | + |
727 | + private ResourceManager resource_manager { get; set; } |
728 | + |
729 | + public EventIterator (ResourceManager resources) { |
730 | + /* Grab the resource manager and chain the SqlDataIterator constructor, |
731 | + * ordering by date in decreasing order. */ |
732 | + base (resources.db, resources.events_table, "date", true); |
733 | + resource_manager = resources; |
734 | + } |
735 | + |
736 | + public EventIterator.with_day (ResourceManager resources, DateTime date) { |
737 | + base.with_like (resources.db, resources.events_table, "date", true, |
738 | + "date BETWEEN '%s' AND '%s'".printf (SqlDataType.datetime_to_string (date), |
739 | + SqlDataType.datetime_to_string (date.add_days (1).add_minutes(-1)))); |
740 | + resource_manager = resources; |
741 | + } |
742 | + |
743 | + public new EventIterator iterator () { |
744 | + return this; |
745 | + } |
746 | + |
747 | + public new Event get () { |
748 | + return new Event.with_id (resource_manager, base.get ()); |
749 | + } |
750 | + } |
751 | + |
752 | + public class Event : SqlDataType { |
753 | + |
754 | + private ResourceManager resource_manager { get; set; } |
755 | + |
756 | + /* Properties mapped to the database */ |
757 | + public string title { |
758 | + get { return get_text ("title"); } |
759 | + set { set_text ("title", value); } |
760 | + } |
761 | + |
762 | + public string description { |
763 | + get { return get_text ("description"); } |
764 | + set { set_text ("description", value); } |
765 | + } |
766 | + |
767 | + public string venue { |
768 | + get { return get_text ("venue"); } |
769 | + set { set_text ("venue", value); } |
770 | + } |
771 | + |
772 | + /** |
773 | + * @brief Patient associated to this event, if one exists, |
774 | + * or null otherwise |
775 | + */ |
776 | + private Patient? _patient; |
777 | + public Patient? patient { |
778 | + get { |
779 | + int id = get_integer ("patient"); |
780 | + if (id == 0) { |
781 | + return null; |
782 | + } |
783 | + else { |
784 | + _patient = new Patient.with_id (resource_manager, id); |
785 | + return _patient; |
786 | + } |
787 | + } |
788 | + set { |
789 | + if (value != null) { |
790 | + set_integer ("patient", value.get_id ()); |
791 | + _patient = value; |
792 | + } |
793 | + else { |
794 | + set_integer ("patient", 0); |
795 | + } |
796 | + } |
797 | + } |
798 | + |
799 | + |
800 | + /** |
801 | + * @brief Visit associated to this event, if one exists, |
802 | + * or null otherwise |
803 | + */ |
804 | + private Visit? _visit; |
805 | + public Visit? visit { |
806 | + get { |
807 | + int id = get_integer ("visit"); |
808 | + if (id == 0) { |
809 | + return null; |
810 | + } |
811 | + else { |
812 | + _visit = new Visit.with_id (resource_manager, id); |
813 | + return _visit; |
814 | + } |
815 | + } |
816 | + set { |
817 | + if (value != null) { |
818 | + set_integer ("visit", value.get_id ()); |
819 | + _visit = value; |
820 | + } |
821 | + else { |
822 | + set_integer ("visit", 0); |
823 | + } |
824 | + } |
825 | + } |
826 | + |
827 | + /** |
828 | + * @brief Date associated to this event. |
829 | + */ |
830 | + private DateTime _date; |
831 | + public DateTime date { |
832 | + get { |
833 | + _date = get_date ("date"); |
834 | + return _date; |
835 | + } |
836 | + set { |
837 | + _date = value; |
838 | + set_date ("date", _date); |
839 | + } |
840 | + } |
841 | + |
842 | + public Event (ResourceManager resources) { |
843 | + base (resources.db); |
844 | + resource_manager = resources; |
845 | + error.connect ((t,l) => resources.error_callback(t,l)); |
846 | + table_name = resource_manager.events_table; |
847 | + |
848 | + add_text_field ("title"); |
849 | + add_text_field ("description"); |
850 | + add_text_field ("venue"); |
851 | + add_integer_field ("patient"); |
852 | + add_integer_field ("visit"); |
853 | + add_date_field ("date"); |
854 | + |
855 | + init_resources (); |
856 | + |
857 | + visit = null; |
858 | + patient = null; |
859 | + } |
860 | + |
861 | + public Event.with_id (ResourceManager resources, int id) { |
862 | + this (resources); |
863 | + load (id); |
864 | + } |
865 | + |
866 | + public static new EventIterator all (ResourceManager resources) { |
867 | + return new EventIterator (resources); |
868 | + } |
869 | + |
870 | + public static new EventIterator for_day (ResourceManager resources, DateTime date) { |
871 | + return new EventIterator.with_day (resources, date); |
872 | + } |
873 | + } |
874 | +} |
875 | |
876 | === added file 'libclinica/EventEditor.vala' |
877 | --- libclinica/EventEditor.vala 1970-01-01 00:00:00 +0000 |
878 | +++ libclinica/EventEditor.vala 2011-10-06 07:06:24 +0000 |
879 | @@ -0,0 +1,224 @@ |
880 | +/* |
881 | + * This file is part of Clinica. |
882 | + * |
883 | + * Clinica is free software: you can redistribute it and/or modify |
884 | + * it under the terms of the GNU General Public License as published by |
885 | + * the Free Software Foundation, either version 3 of the License, or |
886 | + * (at your option) any later version. |
887 | + * |
888 | + * Clinica is distributed in the hope that it will be useful, |
889 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
890 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
891 | + * GNU General Public License for more details. |
892 | + * |
893 | + * You should have received a copy of the GNU General Public License |
894 | + * along with Clinica. If not, see <http://www.gnu.org/licenses/>. |
895 | + * |
896 | + * Authors: Leonardo Robol <leo@robol.it> |
897 | + * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it> |
898 | + */ |
899 | + |
900 | + using Gtk; |
901 | + |
902 | + namespace Clinica { |
903 | + |
904 | + public class EventEditor : Dialog { |
905 | + |
906 | + enum Response { |
907 | + CANCEL, |
908 | + SAVE, |
909 | + } |
910 | + |
911 | + /** |
912 | + * @brief Resource Manager used to access clinica |
913 | + * resources. |
914 | + */ |
915 | + private ResourceManager resource_manager { get; set; } |
916 | + |
917 | + /** |
918 | + * @brief event that is being edited by the EventEditor |
919 | + */ |
920 | + internal Event selected_event { get; private set; } |
921 | + |
922 | + /** |
923 | + * @brief Entry for the title of the event. |
924 | + */ |
925 | + private Entry title_entry; |
926 | + |
927 | + /** |
928 | + * @brief Entry for the venue. |
929 | + */ |
930 | + private Entry venue_entry; |
931 | + |
932 | + /** |
933 | + * @brief Calendar used in the dialog to select the data of the event |
934 | + */ |
935 | + private Gtk.Calendar calendar; |
936 | + |
937 | + /** |
938 | + * @brief Multiline editor for the desription of the event |
939 | + */ |
940 | + private TextView description_textview; |
941 | + |
942 | + /** |
943 | + * @brief Boolean value that tells if the user has filled the buffer |
944 | + * of the description, or if it is left with its default hint. |
945 | + * |
946 | + * In the first case the description should be saved, in the latter ignored. |
947 | + */ |
948 | + private bool description_inserted = false; |
949 | + |
950 | + /** |
951 | + * @brief Entry used by the user to select the patient |
952 | + */ |
953 | + private PatientEntry patient_entry; |
954 | + |
955 | + public EventEditor (ResourceManager resources, Event? event = null) { |
956 | + resource_manager = resources; |
957 | + |
958 | + /* If the event is null, let's create a new one, otherwise |
959 | + * store the event passed for editing. */ |
960 | + if (event == null) { |
961 | + selected_event = new Event (resource_manager); |
962 | + set_title (_("Create a new event")); |
963 | + } |
964 | + else { |
965 | + selected_event = event; |
966 | + set_title (_("Editing event: %s").printf (event.title)); |
967 | + } |
968 | + |
969 | + /* Add Save and Cancel buttons */ |
970 | + add_buttons (Stock.CANCEL, Response.CANCEL, |
971 | + Stock.SAVE, Response.SAVE); |
972 | + |
973 | + /* A vertical box to contain all the widgets */ |
974 | + var structure_box = new VBox (false, resource_manager.PADDING); |
975 | + |
976 | + /* The header, with a picture representing an event and title |
977 | + * and venue. */ |
978 | + var event_picture = new Image.from_file (resource_manager.get_image_file ("calendar.svg")); |
979 | + var header_box = new HBox (false, resource_manager.PADDING); |
980 | + header_box.pack_start (event_picture, false); |
981 | + |
982 | + /* Create the entry for title of the event and venue */ |
983 | + var title_label = new Label (_("Title")); |
984 | + var venue_label = new Label (_("Venue")); |
985 | + |
986 | + title_entry = new Entry (); |
987 | + venue_entry = new Entry (); |
988 | + |
989 | + /* Packing them near the image */ |
990 | + var table = new Table (2, 2, false); |
991 | + table.attach (title_label, 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, |
992 | + resource_manager.PADDING / 2, resource_manager.PADDING / 2); |
993 | + table.attach (venue_label, 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, |
994 | + resource_manager.PADDING / 2, resource_manager.PADDING / 2); |
995 | + table.attach (title_entry, 1, 2, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, |
996 | + AttachOptions.FILL, resource_manager.PADDING / 2, resource_manager.PADDING / 2); |
997 | + table.attach (venue_entry, 1, 2, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, |
998 | + AttachOptions.FILL, resource_manager.PADDING / 2, resource_manager.PADDING / 2); |
999 | + |
1000 | + header_box.pack_start (table); |
1001 | + structure_box.pack_start (header_box, false); |
1002 | + |
1003 | + /* Box for calendar and description */ |
1004 | + var cal_desc_box = new HBox (false, resource_manager.PADDING); |
1005 | + |
1006 | + /* Create the calendar used to select the date */ |
1007 | + calendar = new Gtk.Calendar (); |
1008 | + cal_desc_box.pack_start (calendar, false); |
1009 | + |
1010 | + /* Create the field for the description */ |
1011 | + description_textview = new TextView (); |
1012 | + var scroll_w = new ScrolledWindow (null, null); |
1013 | + scroll_w.add_with_viewport (description_textview); |
1014 | + scroll_w.set_shadow_type (ShadowType.ETCHED_OUT); |
1015 | + cal_desc_box.pack_start (scroll_w); |
1016 | + description_textview.get_buffer ().set_text (_("Insert the description here...")); |
1017 | + |
1018 | + /* Make the description view gray until the user select it, then reset |
1019 | + * the text in the textview and let the user fill the description. |
1020 | + * |
1021 | + * FIXME: We are assuming here that the default backgroun color is black, and |
1022 | + * that's not always the case. I don't get why vala doesn't allow reset_color |
1023 | + * to be null that, following Gtk documentation, should reset the color to |
1024 | + * its default value. |
1025 | + */ |
1026 | + Gdk.RGBA hint_color = Gdk.RGBA (); |
1027 | + hint_color.parse ("#bcbcbc"); |
1028 | + description_textview.override_color (StateFlags.NORMAL, hint_color); |
1029 | + description_textview.focus_in_event.connect ((widget, event) => { |
1030 | + Gdk.RGBA reset_color = Gdk.RGBA (); |
1031 | + reset_color.parse ("#000000"); |
1032 | + description_textview.override_color (StateFlags.NORMAL, reset_color); |
1033 | + description_textview.get_buffer ().set_text (""); |
1034 | + description_inserted = true; |
1035 | + return false; |
1036 | + }); |
1037 | + |
1038 | + structure_box.pack_start (cal_desc_box); |
1039 | + |
1040 | + /* Adding entries to select the patient and the visit */ |
1041 | + var patient_visit_box = new Table (2, 2, false); |
1042 | + |
1043 | + var patient_label = new Label(_("Patient")); |
1044 | + patient_entry = new PatientEntry (resource_manager); |
1045 | + patient_visit_box.attach (patient_label, 0, 1, 0, 1, AttachOptions.FILL, |
1046 | + AttachOptions.FILL | AttachOptions.EXPAND, 0, 0); |
1047 | + patient_visit_box.attach (patient_entry, 1, 2, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, |
1048 | + AttachOptions.FILL | AttachOptions.EXPAND, 0, 0); |
1049 | + patient_entry.margin_left = resource_manager.PADDING;; |
1050 | + structure_box.pack_start (patient_visit_box); |
1051 | + |
1052 | + /* Pack the table in the dialog, with some alignment */ |
1053 | + var alignment = new Alignment (0.5F, 0.5F, 1.0F, 1.0F); |
1054 | + alignment.set_padding (resource_manager.PADDING, resource_manager.PADDING, |
1055 | + resource_manager.PADDING, resource_manager.PADDING); |
1056 | + alignment.add (structure_box); |
1057 | + (get_content_area () as Container).add (alignment); |
1058 | + alignment.show_all (); |
1059 | + |
1060 | + set_size_request (520, -1); |
1061 | + |
1062 | + response.connect (on_response); |
1063 | + } |
1064 | + |
1065 | + /** |
1066 | + * @brief Create a new event editor with a preselected date in the calendar. |
1067 | + */ |
1068 | + public EventEditor.with_date (ResourceManager resources, DateTime date) { |
1069 | + this (resources); |
1070 | + calendar.select_month (date.get_month () - 1, date.get_year ()); |
1071 | + calendar.select_day (date.get_day_of_month ()); |
1072 | + } |
1073 | + |
1074 | + /** |
1075 | + * @brief Change selection to the given patient |
1076 | + */ |
1077 | + public void select_patient (Patient patient) { |
1078 | + patient_entry.select_patient (patient); |
1079 | + } |
1080 | + |
1081 | + private void on_response () { |
1082 | + selected_event.title = title_entry.get_text (); |
1083 | + selected_event.venue = venue_entry.get_text (); |
1084 | + |
1085 | + TextIter start, end; |
1086 | + TextBuffer buffer = description_textview.get_buffer (); |
1087 | + buffer.get_start_iter (out start); |
1088 | + buffer.get_end_iter (out end); |
1089 | + if (description_inserted) |
1090 | + selected_event.description = buffer.get_text (start, end, false); |
1091 | + else |
1092 | + selected_event.description = ""; |
1093 | + |
1094 | + /* Select patient if is valid */ |
1095 | + if (patient_entry.is_valid () && patient_entry.get_patient () != null) { |
1096 | + selected_event.patient = patient_entry.get_patient (); |
1097 | + } |
1098 | + |
1099 | + selected_event.date = new DateTime.local (calendar.year, calendar.month + 1, |
1100 | + calendar.day, 0, 0, 0); |
1101 | + } |
1102 | + } |
1103 | + } |
1104 | |
1105 | === added file 'libclinica/EventListStore.vala' |
1106 | --- libclinica/EventListStore.vala 1970-01-01 00:00:00 +0000 |
1107 | +++ libclinica/EventListStore.vala 2011-10-06 07:06:24 +0000 |
1108 | @@ -0,0 +1,123 @@ |
1109 | +/* |
1110 | + * This file is part of Clinica. |
1111 | + * |
1112 | + * Clinica is free software: you can redistribute it and/or modify |
1113 | + * it under the terms of the GNU General Public License as published by |
1114 | + * the Free Software Foundation, either version 3 of the License, or |
1115 | + * (at your option) any later version. |
1116 | + * |
1117 | + * Clinica is distributed in the hope that it will be useful, |
1118 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1119 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1120 | + * GNU General Public License for more details. |
1121 | + * |
1122 | + * You should have received a copy of the GNU General Public License |
1123 | + * along with Clinica. If not, see <http://www.gnu.org/licenses/>. |
1124 | + * |
1125 | + * Authors: Leonardo Robol <leo@robol.it> |
1126 | + * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it> |
1127 | + */ |
1128 | + |
1129 | + using Gtk; |
1130 | + |
1131 | + namespace Clinica { |
1132 | + |
1133 | + public class EventListStore : ListStore { |
1134 | + |
1135 | + public signal void event_added (Event event); |
1136 | + public signal void event_removed (Event event); |
1137 | + |
1138 | + /** |
1139 | + * @brief Fields present in the store, i.e. header of |
1140 | + * the columns. |
1141 | + */ |
1142 | + enum Field { |
1143 | + EVENT, |
1144 | + TITLE, |
1145 | + DESCRIPTION, |
1146 | + VENUE, |
1147 | + PATIENT, |
1148 | + VISIT, |
1149 | + DATE, |
1150 | + } |
1151 | + |
1152 | + /** |
1153 | + * @brief This signal is emitted if an error occur in the |
1154 | + * list_store |
1155 | + */ |
1156 | + public signal void error (string message); |
1157 | + |
1158 | + /** |
1159 | + * @brief ResourceManager associated to this clinica application |
1160 | + * that will be used to retrieve various informationa about the |
1161 | + * other components running |
1162 | + */ |
1163 | + private ResourceManager resource_manager { get; set; } |
1164 | + |
1165 | + public EventListStore (ResourceManager resources) { |
1166 | + resource_manager = resources; |
1167 | + error.connect ((widget, message) => resource_manager.error_callback (widget, message)); |
1168 | + |
1169 | + Type [] column_headers = { typeof (Event), typeof (string), typeof (string), |
1170 | + typeof (string), typeof (Patient?), typeof (Visit?), typeof (DateTime) }; |
1171 | + |
1172 | + set_column_types (column_headers); |
1173 | + GLib.Idle.add (load_events_from_db); |
1174 | + } |
1175 | + |
1176 | + /** |
1177 | + * @brief Add an event to the liststore. |
1178 | + */ |
1179 | + public void add_event (Event event) { |
1180 | + TreeIter iter; |
1181 | + append (out iter); |
1182 | + |
1183 | + /* Set values in the treeview */ |
1184 | + set_value (iter, Field.EVENT, event); |
1185 | + set_value (iter, Field.DATE, event.date); |
1186 | + set_value (iter, Field.DESCRIPTION, event.description); |
1187 | + set_value (iter, Field.PATIENT, event.patient); |
1188 | + set_value (iter, Field.TITLE, event.title); |
1189 | + set_value (iter, Field.VENUE, event.venue); |
1190 | + set_value (iter, Field.VISIT, event.visit); |
1191 | + |
1192 | + /* Emit event_added to make calendars and other pieces of interface |
1193 | + * using events know that they must reload their dates */ |
1194 | + event_added (event); |
1195 | + } |
1196 | + |
1197 | + public void remove_event (Event event) { |
1198 | + TreeIter iter; |
1199 | + Value value; |
1200 | + if (!get_iter_first (out iter)) { |
1201 | + error (_("Events database seems corrupted. This is likely to be a bug in the application")); |
1202 | + } |
1203 | + |
1204 | + do { |
1205 | + get_value (iter, Field.EVENT, out value); |
1206 | + if ((value as Event).get_id () == event.get_id ()) { |
1207 | + /* Delete this event from the liststore */ |
1208 | + remove (iter); |
1209 | + event_removed (event); |
1210 | + return; |
1211 | + } |
1212 | + } while (iter_next (ref iter)); |
1213 | + |
1214 | + assert_not_reached (); |
1215 | + } |
1216 | + |
1217 | + /** |
1218 | + * @brief Function to be schedule with GLib.Idle_add () when loading of |
1219 | + * the events from the db is needed at the start of the application. |
1220 | + * |
1221 | + * This function is now called by default from the constructor. |
1222 | + */ |
1223 | + private bool load_events_from_db () { |
1224 | + foreach (var event in Event.all (resource_manager)) { |
1225 | + add_event (event); |
1226 | + } |
1227 | + |
1228 | + return false; |
1229 | + } |
1230 | + } |
1231 | + } |
1232 | |
1233 | === modified file 'libclinica/PatientEditor.vala' |
1234 | --- libclinica/PatientEditor.vala 2011-09-22 19:27:52 +0000 |
1235 | +++ libclinica/PatientEditor.vala 2011-10-06 07:06:24 +0000 |
1236 | @@ -60,7 +60,7 @@ |
1237 | |
1238 | /* Set to a patient that is the existing object for the |
1239 | * one represented here. */ |
1240 | - private Patient? existing_patient = null; |
1241 | + private Patient? existing_patient { get; set; default = null; } |
1242 | |
1243 | /* Dialog opened to select data of the new patient */ |
1244 | public Dialog dialog; |
1245 | @@ -88,6 +88,8 @@ |
1246 | public Gdk.Color alert_color; |
1247 | |
1248 | private ResourceManager resource_manager; |
1249 | + |
1250 | + internal Patient created_patient; |
1251 | |
1252 | public PatientEditor (ResourceManager resources) { |
1253 | resource_manager = resources; |
1254 | @@ -102,6 +104,9 @@ |
1255 | |
1256 | /* Fill the dialog with the pieces from the gtk builder file */ |
1257 | dialog = builder.get_object("patient_editor") as Dialog; |
1258 | + |
1259 | + /* Prepare for drag and drop if the patient is changed */ |
1260 | + notify["existing_patient"].connect (update_draggable_patient_status); |
1261 | |
1262 | /* Load entries into local object */ |
1263 | doctor_entry = builder.get_object ("doctor_entry") as Entry; |
1264 | @@ -150,6 +155,16 @@ |
1265 | extensions = setup_extension_set (resource_manager.plugin_engine); |
1266 | } |
1267 | |
1268 | + private void update_draggable_patient_status () { |
1269 | + /* Enable drag and drop on the patient icon */ |
1270 | + if (existing_patient == null) |
1271 | + return; |
1272 | + var patient_eventbox = builder.get_object ("patient_eventbox") as EventBox; |
1273 | + TargetEntry patient_target = { "PATIENT", 0, 1 }; |
1274 | + Gtk.drag_source_set (patient_eventbox, Gdk.ModifierType.BUTTON1_MASK, { patient_target }, Gdk.DragAction.COPY); |
1275 | + patient_eventbox.drag_begin.connect ((widget, context) => resource_manager.dragging_patient = existing_patient); |
1276 | + } |
1277 | + |
1278 | private void on_doctor_entry_changed (Editable editable) { |
1279 | Entry entry = (editable as Entry); |
1280 | string doc_name = entry.get_text (); |
1281 | @@ -252,6 +267,7 @@ |
1282 | // Load doctors and existing patient |
1283 | selected_doctor = p.doctor; |
1284 | existing_patient = p; |
1285 | + update_draggable_patient_status (); |
1286 | doctor_entry.set_text (p.doctor.get_complete_name ()); |
1287 | |
1288 | // Pre fill the fields in the interface |
1289 | @@ -383,17 +399,16 @@ |
1290 | |
1291 | /* Save the new patient, creating a new one if this is a new patient, or |
1292 | * reusing the existing one if we are only modifying a patient. */ |
1293 | - Patient patient; |
1294 | if (existing_patient == null) |
1295 | - patient = new Patient (resource_manager, selected_doctor); |
1296 | + created_patient = new Patient (resource_manager, selected_doctor); |
1297 | else |
1298 | - patient = existing_patient; |
1299 | + created_patient = existing_patient; |
1300 | |
1301 | - patient.given_name = given_name_entry.get_text (); |
1302 | - patient.surname = surname_entry.get_text (); |
1303 | - patient.phone = phone_entry.get_text (); |
1304 | - patient.identification_code = identification_code_entry.get_text (); |
1305 | - patient.residence_address = residence_address_entry.get_text (); |
1306 | + created_patient.given_name = given_name_entry.get_text (); |
1307 | + created_patient.surname = surname_entry.get_text (); |
1308 | + created_patient.phone = phone_entry.get_text (); |
1309 | + created_patient.identification_code = identification_code_entry.get_text (); |
1310 | + created_patient.residence_address = residence_address_entry.get_text (); |
1311 | |
1312 | /* Create new DateTime */ |
1313 | int year = int.parse (year_entry.get_text ()); |
1314 | @@ -406,7 +421,7 @@ |
1315 | (1 <= day) && (day <= 31)) |
1316 | { |
1317 | t = new DateTime (new TimeZone.utc (), year, month, day, 0, 0, 0); |
1318 | - patient.birth_date = t; |
1319 | + created_patient.birth_date = t; |
1320 | } |
1321 | else |
1322 | { |
1323 | @@ -417,18 +432,18 @@ |
1324 | |
1325 | /* Set gender here */ |
1326 | if (gender_combobox.get_active () == 0) |
1327 | - patient.gender = Gender.MALE; |
1328 | + created_patient.gender = Gender.MALE; |
1329 | else |
1330 | - patient.gender = Gender.FEMALE; |
1331 | + created_patient.gender = Gender.FEMALE; |
1332 | |
1333 | - patient.save (); |
1334 | + created_patient.save (); |
1335 | |
1336 | // If this was an existing patient we need to reload it in the patient |
1337 | // list store, otherwise we can just add it |
1338 | if (existing_patient != null) { |
1339 | - resource_manager.patient_list_store.reload_patient (patient); |
1340 | + resource_manager.patient_list_store.reload_patient (created_patient); |
1341 | } else { |
1342 | - resource_manager.patient_list_store.add_patient (patient); |
1343 | + resource_manager.patient_list_store.add_patient (created_patient); |
1344 | } |
1345 | |
1346 | return Response.SAVE; |
1347 | |
1348 | === added file 'libclinica/PatientEntry.vala' |
1349 | --- libclinica/PatientEntry.vala 1970-01-01 00:00:00 +0000 |
1350 | +++ libclinica/PatientEntry.vala 2011-10-06 07:06:24 +0000 |
1351 | @@ -0,0 +1,168 @@ |
1352 | +/* |
1353 | + * This file is part of Clinica. |
1354 | + * |
1355 | + * Clinica is free software: you can redistribute it and/or modify |
1356 | + * it under the terms of the GNU General Public License as published by |
1357 | + * the Free Software Foundation, either version 3 of the License, or |
1358 | + * (at your option) any later version. |
1359 | + * |
1360 | + * Clinica is distributed in the hope that it will be useful, |
1361 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1362 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1363 | + * GNU General Public License for more details. |
1364 | + * |
1365 | + * You should have received a copy of the GNU General Public License |
1366 | + * along with Clinica. If not, see <http://www.gnu.org/licenses/>. |
1367 | + * |
1368 | + * Authors: Leonardo Robol <leo@robol.it> |
1369 | + * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it> |
1370 | + */ |
1371 | + |
1372 | + using Gtk; |
1373 | + |
1374 | + namespace Clinica { |
1375 | + |
1376 | + /** |
1377 | + * @brief Extension of GtkEntry with autocompletion on patients |
1378 | + * |
1379 | + * The selected patient, or null, if there is no selected patient, |
1380 | + * can be retrieved git the get_patient () method. |
1381 | + */ |
1382 | + public class PatientEntry : Entry { |
1383 | + |
1384 | + public signal void selection_changed (); |
1385 | + |
1386 | + enum PatientCompletionAction { |
1387 | + CREATE_NEW = 0, |
1388 | + } |
1389 | + |
1390 | + /** |
1391 | + * @brief The reference to the resource manager |
1392 | + */ |
1393 | + private ResourceManager resource_manager { get; set; } |
1394 | + |
1395 | + /** |
1396 | + * @brief The reference to the selected patient |
1397 | + */ |
1398 | + private Patient? selected_patient = null; |
1399 | + |
1400 | + /** |
1401 | + * @brief Completion for the patients |
1402 | + */ |
1403 | + private new EntryCompletion completion; |
1404 | + |
1405 | + public PatientEntry (ResourceManager resources) { |
1406 | + resource_manager = resources; |
1407 | + |
1408 | + /* Init the completion */ |
1409 | + completion = new EntryCompletion (); |
1410 | + completion.set_model (resource_manager.patient_list_store); |
1411 | + completion.set_text_column (PatientListStore.Field.COMPLETE_NAME); |
1412 | + completion.set_match_func (completion_match_function); |
1413 | + completion.insert_action_text (PatientCompletionAction.CREATE_NEW, "Create a new patient"); |
1414 | + |
1415 | + /* Callback that stores the selected patient */ |
1416 | + completion.match_selected.connect (on_match_selected); |
1417 | + |
1418 | + /* Callback for action selected */ |
1419 | + completion.action_activated.connect (on_action_activated); |
1420 | + |
1421 | + /* Activate completion */ |
1422 | + set_completion (completion); |
1423 | + changed.connect (on_changed); |
1424 | + } |
1425 | + |
1426 | + /** |
1427 | + * Change selection to the given patient |
1428 | + */ |
1429 | + public void select_patient (Patient patient) { |
1430 | + selected_patient = patient; |
1431 | + set_text (patient.get_complete_name ()); |
1432 | + } |
1433 | + |
1434 | + public Patient get_patient () { |
1435 | + return selected_patient; |
1436 | + } |
1437 | + |
1438 | + /** |
1439 | + * @brief Return true if this entry has a valid selection. |
1440 | + */ |
1441 | + public bool is_valid () { |
1442 | + /* If no patient is selected the entry should be empty */ |
1443 | + if (selected_patient == null) { |
1444 | + if (get_text () != "") |
1445 | + return false; |
1446 | + else |
1447 | + return true; |
1448 | + } |
1449 | + |
1450 | + return (get_text () == selected_patient.get_complete_name ()); |
1451 | + } |
1452 | + |
1453 | + /** |
1454 | + * @brief Callback function for the patient selection that matches the doctor |
1455 | + * if the key is a substring of its complete name. |
1456 | + */ |
1457 | + private bool completion_match_function (EntryCompletion compl, string key, TreeIter iter) { |
1458 | + Value value; |
1459 | + resource_manager.patient_list_store.get_value(iter, 0, out value); |
1460 | + Patient pat = value as Patient; |
1461 | + if (pat == null) |
1462 | + return false; |
1463 | + return (key.up () in pat.get_complete_name ().up ()); |
1464 | + } |
1465 | + |
1466 | + /** |
1467 | + * @brief Callback called when the user select a patient |
1468 | + */ |
1469 | + private bool on_match_selected (EntryCompletion compl, TreeModel model, TreeIter iter) { |
1470 | + /* Get doctor associated with the selected completion */ |
1471 | + Value value; |
1472 | + model.get_value (iter, PatientListStore.Field.COMPLETE_NAME, out value); |
1473 | + set_text (value as string); |
1474 | + model.get_value (iter, PatientListStore.Field.PATIENT, out value); |
1475 | + |
1476 | + /* Set selected doctor in this object to use it later */ |
1477 | + selected_patient = value as Patient; |
1478 | + |
1479 | + return true; |
1480 | + } |
1481 | + |
1482 | + /** |
1483 | + * @brief Create a new doctor on the fly with the name specifed in the |
1484 | + * doctor_entry |
1485 | + */ |
1486 | + private void on_action_activated (EntryCompletion editable, int action) { |
1487 | + if (action != PatientCompletionAction.CREATE_NEW) |
1488 | + return; |
1489 | + |
1490 | + /* Create a new dialog precompiled with the user input until now */ |
1491 | + string name = get_text (); |
1492 | + var dialog = new PatientEditor.with_name (resource_manager, Utils.capitalize (name)); |
1493 | + if (dialog.run () == PatientEditor.Response.CANCEL) { |
1494 | + dialog.destroy (); |
1495 | + return; |
1496 | + } |
1497 | + |
1498 | + /* Set the newly created doctor as selected doctor */ |
1499 | + selected_patient = dialog.created_patient; |
1500 | + set_text (selected_patient.get_complete_name ()); |
1501 | + |
1502 | + /* Destroy the dialog */ |
1503 | + dialog.destroy (); |
1504 | + } |
1505 | + |
1506 | + private void on_changed (Editable editable) { |
1507 | + string patient_name = get_text (); |
1508 | + |
1509 | + /* Replace action */ |
1510 | + completion.delete_action (PatientCompletionAction.CREATE_NEW); |
1511 | + if (patient_name != "") |
1512 | + completion.insert_action_text (PatientCompletionAction.CREATE_NEW, |
1513 | + @"Create a new patient named $(Utils.capitalize (patient_name))"); |
1514 | + else |
1515 | + completion.insert_action_text (PatientCompletionAction.CREATE_NEW, |
1516 | + @"Create a new patient"); |
1517 | + } |
1518 | + } |
1519 | + } |
1520 | |
1521 | === modified file 'libclinica/PatientListView.vala' |
1522 | --- libclinica/PatientListView.vala 2011-09-22 19:27:52 +0000 |
1523 | +++ libclinica/PatientListView.vala 2011-10-06 07:06:24 +0000 |
1524 | @@ -87,6 +87,13 @@ |
1525 | |
1526 | /* Some styling, row in alternating colors */ |
1527 | set_rules_hint (true); |
1528 | + |
1529 | + /* Drag and drop support */ |
1530 | + TargetEntry patient_target = { "PATIENT", 0, 1 }; |
1531 | + enable_model_drag_source (Gdk.ModifierType.BUTTON1_MASK, { patient_target }, Gdk.DragAction.COPY); |
1532 | + drag_begin.connect ((context) => { |
1533 | + resource_manager.dragging_patient = get_selected_patient (); |
1534 | + }); |
1535 | } |
1536 | |
1537 | private void on_name_cell_edited (CellRenderer renderer, string path, string new_text) { |
1538 | |
1539 | === modified file 'libclinica/ResourceManager.vala' |
1540 | --- libclinica/ResourceManager.vala 2011-09-23 13:24:03 +0000 |
1541 | +++ libclinica/ResourceManager.vala 2011-10-06 07:06:24 +0000 |
1542 | @@ -23,7 +23,6 @@ |
1543 | using Gtk; |
1544 | |
1545 | namespace Clinica { |
1546 | - |
1547 | |
1548 | /** |
1549 | * @brief Type representing the callback for the error |
1550 | @@ -38,6 +37,12 @@ |
1551 | public class ResourceManager : GLib.Object { |
1552 | |
1553 | /** |
1554 | + * @brief The padding the should be used in windows |
1555 | + * in Clinica. |
1556 | + */ |
1557 | + public const int PADDING = 6; |
1558 | + |
1559 | + /** |
1560 | * @brief Callback that manages errors |
1561 | * notification to the end user. |
1562 | */ |
1563 | @@ -61,6 +66,15 @@ |
1564 | */ |
1565 | public VisitListStore visit_list_store; |
1566 | |
1567 | + /** |
1568 | + * @brief EventListStore that holds the list of |
1569 | + * the events scheduled in clinica. |
1570 | + */ |
1571 | + public EventListStore event_list_store; |
1572 | + |
1573 | + /** |
1574 | + * @brief Reference to a user interface |
1575 | + */ |
1576 | public UserInterface user_interface; |
1577 | |
1578 | /** |
1579 | @@ -105,6 +119,13 @@ |
1580 | internal GLib.List<unowned MedicineSearchEngine> medicine_search_engines; |
1581 | |
1582 | /** |
1583 | + * @brief A pointer to the patient that is been dragged. Should |
1584 | + * be set on drag_begin by the treeview and reset to null by the |
1585 | + * drag destination handler. |
1586 | + */ |
1587 | + internal Patient? dragging_patient = null; |
1588 | + |
1589 | + /** |
1590 | * @brief Path to the UI files directory |
1591 | */ |
1592 | private string ui_files_path; |
1593 | @@ -114,13 +135,17 @@ |
1594 | |
1595 | private bool is_local = false; |
1596 | |
1597 | - public string doctor_table = "doctors"; |
1598 | - public string patient_table = "patients"; |
1599 | - public string visits_table = "visits"; |
1600 | + public const string doctor_table = "doctors"; |
1601 | + public const string patient_table = "patients"; |
1602 | + public const string visits_table = "visits"; |
1603 | + public const string events_table = "events"; |
1604 | |
1605 | /** SIGNALS **/ |
1606 | public signal void medicine_search_engines_added (MedicineSearchEngine engine); |
1607 | public signal void medicine_search_engines_removed (MedicineSearchEngine engine); |
1608 | + |
1609 | + private const string [] supported_db_versions = { "0.1", "0.2" }; |
1610 | + private const string db_version = "0.2"; |
1611 | |
1612 | public ResourceManager (string program_name = "clinica", ErrorCallback? callback = null) { |
1613 | if (callback != null) |
1614 | @@ -150,11 +175,11 @@ |
1615 | * This may be used in future to perform one-time upgrade of the database */ |
1616 | var version_db_file = Path.build_filename (local_config_directory, |
1617 | ".clinica_db_version"); |
1618 | - |
1619 | + |
1620 | if (!FileUtils.test (version_db_file, FileTest.IS_REGULAR)) { |
1621 | /* Create the file with the version of the database */ |
1622 | try { |
1623 | - FileUtils.set_contents(version_db_file, "0.1"); |
1624 | + FileUtils.set_contents(version_db_file, db_version); |
1625 | } catch (Error e) { |
1626 | error (_("Error creating some configuration files, check permission on %s".printf(version_db_file))); |
1627 | } |
1628 | @@ -166,8 +191,36 @@ |
1629 | } catch (Error e) { |
1630 | error (_("Error reading some configuration files, check permission on %s".printf(version_db_file))); |
1631 | } |
1632 | - if ("0.1" != content) { |
1633 | - error (_("Version of the database is not compatible")); |
1634 | + |
1635 | + bool upgraded_correcty = true; |
1636 | + if (db_version != content) { |
1637 | + /* Ask the user if he really wants to upgrade */ |
1638 | + if (!ask_for_upgrade()) { |
1639 | + debug ("The user doesn't want to upgrade, exiting."); |
1640 | + Posix.exit (0); |
1641 | + } |
1642 | + |
1643 | + upgraded_correcty = false; |
1644 | + /* Try to determine if the version of the local database is supported */ |
1645 | + if (content in supported_db_versions) { |
1646 | + if (upgrade_database (content)) { |
1647 | + upgraded_correcty = true; |
1648 | + try { |
1649 | + FileUtils.set_contents (version_db_file, db_version); |
1650 | + } catch (GLib.Error e) { |
1651 | + error (_("Failure while settings new database version to %s").printf (db_version)); |
1652 | + } |
1653 | + } else { |
1654 | + error (_("Failure while upgrading database")); |
1655 | + } |
1656 | + } |
1657 | + else |
1658 | + error (_("Version of the database is not compatible")); |
1659 | + } |
1660 | + |
1661 | + if (!upgraded_correcty) { |
1662 | + debug ("Upgrade failed, exiting."); |
1663 | + Posix.exit (1); |
1664 | } |
1665 | } |
1666 | |
1667 | @@ -207,7 +260,7 @@ |
1668 | * use local schema file */ |
1669 | if (is_local) { |
1670 | debug ("Trying to compile my own gsettings schema"); |
1671 | - try { |
1672 | + try { |
1673 | Process.spawn_sync (null, {Environment.find_program_in_path ("glib-compile-schemas"), |
1674 | src_base}, |
1675 | null, GLib.SpawnFlags.STDERR_TO_DEV_NULL, null); |
1676 | @@ -217,7 +270,6 @@ |
1677 | Environment.set_variable ("GSETTINGS_SCHEMA_DIR", src_base, true); |
1678 | Environment.set_variable ("GI_TYPELIB_PATH", |
1679 | Path.build_filename (src_base, "_build_", "libclinica"), true); |
1680 | - debug (Environment.get_variable ("GI_TYPELIB_PATH")); |
1681 | } |
1682 | |
1683 | /* Create configuration */ |
1684 | @@ -231,6 +283,25 @@ |
1685 | load_plugins.begin (); |
1686 | } |
1687 | |
1688 | + private bool ask_for_upgrade () { |
1689 | + var mb = new MessageDialog (null, |
1690 | + DialogFlags.DESTROY_WITH_PARENT | |
1691 | + DialogFlags.MODAL, |
1692 | + MessageType.QUESTION, |
1693 | + ButtonsType.YES_NO, |
1694 | + "%s", "Database upgrade"); |
1695 | + mb.format_secondary_markup (_("This is a version of Clinica newer than the one that created the\npatients database installed on the system.\nUsing this version requires upgrading the database, and\n<b>the old version will not be able to use it anymore</b>.\nDo you wish to perform this one-time upgrade?\n")); |
1696 | + mb.set_title (_("Upgrade database")); |
1697 | + if (mb.run () == ResponseType.YES) { |
1698 | + mb.destroy (); |
1699 | + return true; |
1700 | + } |
1701 | + else { |
1702 | + mb.destroy (); |
1703 | + return false; |
1704 | + } |
1705 | + } |
1706 | + |
1707 | /** |
1708 | * @brief Instantiate the plugin engine and load |
1709 | * all the plugins present in the directory |
1710 | @@ -298,6 +369,34 @@ |
1711 | } |
1712 | } |
1713 | |
1714 | + private bool upgrade_database (string db_version) { |
1715 | + /* Try to open the database first */ |
1716 | + if (!(Database.open (database_path, out db) == OK)) { |
1717 | + error (_("Error upgrading database, please check your installation")); |
1718 | + } |
1719 | + |
1720 | + string sql; |
1721 | + Statement stmt; |
1722 | + int rc; |
1723 | + |
1724 | + /* Performing upgrade from 0.1 */ |
1725 | + if (db_version == "0.1") { |
1726 | + /* We need to create the new table for the events */ |
1727 | + sql = "CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY, title TEXT, description TEXT, venue TEXT, patient INTEGER, visit INTEGER, date TEXT);"; |
1728 | + db.prepare (sql, -1, out stmt, null); |
1729 | + rc = stmt.step (); |
1730 | + |
1731 | + if (rc != DONE) { |
1732 | + error (_("Error upgrading the database from version 0.1 to 0.2, sqlite exit code: %d".printf (rc))); |
1733 | + return false; |
1734 | + } else { |
1735 | + db_version = "0.2"; |
1736 | + } |
1737 | + } |
1738 | + |
1739 | + return true; |
1740 | + } |
1741 | + |
1742 | /** |
1743 | * @brief Check that all the resources needed by Clinica |
1744 | * are actually available, and if they are not create them. |
1745 | @@ -326,6 +425,7 @@ |
1746 | doctor_list_store = new DoctorListStore (this); |
1747 | patient_list_store = new PatientListStore (this); |
1748 | visit_list_store = new VisitListStore (this); |
1749 | + event_list_store = new EventListStore (this); |
1750 | } |
1751 | |
1752 | |
1753 | |
1754 | === modified file 'libclinica/SqlDataType.vala' |
1755 | --- libclinica/SqlDataType.vala 2011-09-22 19:27:52 +0000 |
1756 | +++ libclinica/SqlDataType.vala 2011-10-06 07:06:24 +0000 |
1757 | @@ -40,9 +40,30 @@ |
1758 | protected unowned Database db; |
1759 | protected Statement stmt; |
1760 | |
1761 | - public SqlDataIterator (Database db, string table_name) { |
1762 | - this.db = db; |
1763 | - db.prepare (@"SELECT ID FROM $(table_name);", -1, out stmt, null); |
1764 | + public SqlDataIterator (Database db, string table_name, string? order_by = null, bool desc = false) { |
1765 | + this.db = db; |
1766 | + if (order_by == null) |
1767 | + db.prepare (@"SELECT ID FROM $(table_name);", -1, out stmt, null); |
1768 | + else { |
1769 | + if (desc) |
1770 | + db.prepare (@"SELECT ID FROM $(table_name) ORDER by $(order_by) DESC;", -1, out stmt, null); |
1771 | + else |
1772 | + db.prepare (@"SELECT ID FROM $(table_name) ORDER by $(order_by);", -1, out stmt, null); |
1773 | + } |
1774 | + } |
1775 | + |
1776 | + public SqlDataIterator.with_like (Database db, string table_name, string? order_by = null, |
1777 | + bool desc = false, string where_stmt) { |
1778 | + this.db = db; |
1779 | + |
1780 | + if (order_by == null) |
1781 | + db.prepare (@"SELECT ID FROM $(table_name) WHERE $(where_stmt);", -1, out stmt, null); |
1782 | + else { |
1783 | + if (desc) |
1784 | + db.prepare (@"SELECT ID FROM $(table_name) WHERE $(where_stmt) ORDER by $(order_by) DESC;", -1, out stmt, null); |
1785 | + else |
1786 | + db.prepare (@"SELECT ID FROM $(table_name) WHERE $(where_stmt) ORDER by $(order_by);", -1, out stmt, null); |
1787 | + } |
1788 | } |
1789 | |
1790 | public SqlDataIterator iterator () { |
1791 | @@ -184,7 +205,10 @@ |
1792 | return ""; |
1793 | } |
1794 | SqlColumn col = columns.get (field); |
1795 | - return col.v; |
1796 | + if (col.v != null) |
1797 | + return col.v; |
1798 | + else |
1799 | + return ""; |
1800 | } |
1801 | |
1802 | public unowned int get_integer (string field) { |
1803 | @@ -230,7 +254,11 @@ |
1804 | return; |
1805 | } |
1806 | SqlColumn col = columns.get (field); |
1807 | - col.v = string.join(" ", |
1808 | + col.v = datetime_to_string (date); |
1809 | + } |
1810 | + |
1811 | + public static string datetime_to_string (DateTime date) { |
1812 | + return string.join(" ", |
1813 | date.get_year ().to_string (), |
1814 | "%.2d".printf (date.get_month ()), |
1815 | "%.2d".printf (date.get_day_of_month()), |
1816 | @@ -279,16 +307,21 @@ |
1817 | sql += ") VALUES ("; |
1818 | |
1819 | foreach (Map.Entry<string, SqlColumn> e in columns.entries) { |
1820 | - if (e.value.type == "TEXT") |
1821 | - sql += @"$(quote(e.value.v)), "; |
1822 | - else |
1823 | - sql += @"$(e.value.v), "; |
1824 | + if (e.value.v != null) { |
1825 | + if (e.value.type == "TEXT") |
1826 | + sql += @"$(quote(e.value.v)), "; |
1827 | + else |
1828 | + sql += @"$(e.value.v), "; |
1829 | + } |
1830 | + else { |
1831 | + sql += ", "; |
1832 | + } |
1833 | } |
1834 | |
1835 | sql = sql[0:-2]; sql += ");"; |
1836 | db.prepare (sql, -1, out stmt, null); |
1837 | if (stmt.step () != DONE) { |
1838 | - error (@"Error inserting values in the database $(table_name)"); |
1839 | + error (@"Error inserting values in the database $(table_name)\n Error $(db.errcode()): $(db.errmsg ())"); |
1840 | } |
1841 | |
1842 | /* If we save with ID set to 0 then the ID will be autodetermined |
1843 | |
1844 | === modified file 'libclinica/UserInterface.vala' |
1845 | --- libclinica/UserInterface.vala 2011-09-22 19:27:52 +0000 |
1846 | +++ libclinica/UserInterface.vala 2011-10-06 07:06:24 +0000 |
1847 | @@ -45,6 +45,7 @@ |
1848 | |
1849 | /* Windows */ |
1850 | private SettingsManager? settings_manager = null; |
1851 | + private CalendarWindow? calendar_window = null; |
1852 | |
1853 | private extern Peas.ExtensionSet setup_extension_set (ResourceManager resources, Peas.Engine engine); |
1854 | internal Peas.ExtensionSet extension_set; |
1855 | @@ -160,7 +161,11 @@ |
1856 | */ |
1857 | [CCode (instance_pos = -1)] |
1858 | public void show_calendar_window (GLib.Object? source = null) { |
1859 | - debug ("Calendar is not available yet"); |
1860 | + if (calendar_window == null) { |
1861 | + calendar_window = new CalendarWindow (resource_manager); |
1862 | + calendar_window.destroy.connect ((cw) => calendar_window = null); |
1863 | + } |
1864 | + calendar_window.show_all (); |
1865 | } |
1866 | |
1867 | /* CALLBACKS */ |
1868 | |
1869 | === modified file 'libclinica/Visit.vala' |
1870 | --- libclinica/Visit.vala 2011-09-22 19:27:52 +0000 |
1871 | +++ libclinica/Visit.vala 2011-10-06 07:06:24 +0000 |
1872 | @@ -29,11 +29,20 @@ |
1873 | private ResourceManager resource_manager; |
1874 | |
1875 | public VisitIterator (ResourceManager resources) { |
1876 | - base (resources.db, resources.visits_table); |
1877 | - resource_manager = resources; |
1878 | - db.prepare (@"SELECT ID FROM $(resources.visits_table) ORDER by date DESC;", -1, out stmt, null); |
1879 | - } |
1880 | + base (resources.db, resources.visits_table, "date", true); |
1881 | + resource_manager = resources; |
1882 | + } |
1883 | + |
1884 | + public VisitIterator.with_day (ResourceManager resources, DateTime day) { |
1885 | + DateTime day_after = day.add_days (1).add_minutes (-1); |
1886 | + base.with_like (resources.db, resources.visits_table, "date", true, |
1887 | + "date BETWEEN '%s' AND '%s'".printf (SqlDataType.datetime_to_string (day), |
1888 | + SqlDataType.datetime_to_string (day_after))); |
1889 | + resource_manager = resources; |
1890 | + } |
1891 | + |
1892 | public new VisitIterator iterator () { return this; } |
1893 | + |
1894 | public new Visit get () { |
1895 | return new Visit.with_id (resource_manager, base.get ()); |
1896 | } |
1897 | @@ -149,6 +158,10 @@ |
1898 | public static new VisitIterator all (ResourceManager resources) { |
1899 | return new VisitIterator (resources); |
1900 | } |
1901 | + |
1902 | + public static new VisitIterator for_day (ResourceManager resources, DateTime date) { |
1903 | + return new VisitIterator.with_day (resources, date); |
1904 | + } |
1905 | |
1906 | } |
1907 | |
1908 | |
1909 | === modified file 'libclinica/wscript' |
1910 | --- libclinica/wscript 2011-09-25 09:49:30 +0000 |
1911 | +++ libclinica/wscript 2011-10-06 07:06:24 +0000 |
1912 | @@ -5,7 +5,7 @@ |
1913 | |
1914 | def build(bld): |
1915 | bld.add_group ("libclinica") |
1916 | - prog = bld(features = 'c cshlib glib2') |
1917 | + prog = bld(features = 'c cshlib glib2', valaflags=[ "-g" ]) |
1918 | bld.set_group ("libclinica") |
1919 | |
1920 | # Symbolic name used to reference this object |
1921 | @@ -26,7 +26,7 @@ |
1922 | prog.uselib = 'GOBJECT PEAS GTK+ GEE SQLITE PEASGTK' |
1923 | |
1924 | # Vala packages to use |
1925 | - prog.packages = 'gtk+-3.0 Peas-1.0 PeasGtk-1.0 sqlite3 gee-1.0 config' |
1926 | + prog.packages = 'gtk+-3.0 Peas-1.0 PeasGtk-1.0 sqlite3 gee-1.0 config posix' |
1927 | prog.vapi = 'clinica-0.2' |
1928 | |
1929 | # Extra vapi dirs |
1930 | |
1931 | === modified file 'ui/patient_editor.glade' |
1932 | --- ui/patient_editor.glade 2011-07-24 17:22:39 +0000 |
1933 | +++ ui/patient_editor.glade 2011-10-06 07:06:24 +0000 |
1934 | @@ -1,7 +1,6 @@ |
1935 | <?xml version="1.0" encoding="UTF-8"?> |
1936 | <interface> |
1937 | <requires lib="gtk+" version="2.24"/> |
1938 | - <!-- interface-naming-policy project-wide --> |
1939 | <object class="GtkListStore" id="gender_store"> |
1940 | <columns> |
1941 | <!-- column-name gender --> |
1942 | @@ -22,12 +21,12 @@ |
1943 | <property name="title" translatable="yes">Create a new patient</property> |
1944 | <property name="type_hint">dialog</property> |
1945 | <child internal-child="vbox"> |
1946 | - <object class="GtkVBox" id="dialog-vbox1"> |
1947 | + <object class="GtkBox" id="dialog-vbox1"> |
1948 | <property name="visible">True</property> |
1949 | <property name="can_focus">False</property> |
1950 | <property name="spacing">2</property> |
1951 | <child internal-child="action_area"> |
1952 | - <object class="GtkHButtonBox" id="dialog-action_area1"> |
1953 | + <object class="GtkButtonBox" id="dialog-action_area1"> |
1954 | <property name="visible">True</property> |
1955 | <property name="can_focus">False</property> |
1956 | <property name="layout_style">end</property> |
1957 | @@ -75,15 +74,20 @@ |
1958 | <property name="can_focus">False</property> |
1959 | <property name="spacing">5</property> |
1960 | <child> |
1961 | - <object class="GtkImage" id="image1"> |
1962 | + <object class="GtkEventBox" id="patient_eventbox"> |
1963 | <property name="visible">True</property> |
1964 | <property name="can_focus">False</property> |
1965 | - <property name="pixbuf">icons/patient.svg</property> |
1966 | + <child> |
1967 | + <object class="GtkImage" id="patient_image"> |
1968 | + <property name="visible">True</property> |
1969 | + <property name="can_focus">False</property> |
1970 | + <property name="pixbuf">icons/patient.svg</property> |
1971 | + </object> |
1972 | + </child> |
1973 | </object> |
1974 | <packing> |
1975 | - <property name="expand">False</property> |
1976 | + <property name="expand">True</property> |
1977 | <property name="fill">True</property> |
1978 | - <property name="padding">10</property> |
1979 | <property name="position">0</property> |
1980 | </packing> |
1981 | </child> |
1982 | @@ -109,8 +113,6 @@ |
1983 | <property name="invisible_char_set">True</property> |
1984 | <property name="primary_icon_activatable">False</property> |
1985 | <property name="secondary_icon_activatable">False</property> |
1986 | - <property name="primary_icon_sensitive">True</property> |
1987 | - <property name="secondary_icon_sensitive">True</property> |
1988 | <signal name="focus-out-event" handler="clinica_patient_editor_on_name_focus_out_event" swapped="no"/> |
1989 | </object> |
1990 | <packing> |
1991 | @@ -128,8 +130,6 @@ |
1992 | <property name="invisible_char_set">True</property> |
1993 | <property name="primary_icon_activatable">False</property> |
1994 | <property name="secondary_icon_activatable">False</property> |
1995 | - <property name="primary_icon_sensitive">True</property> |
1996 | - <property name="secondary_icon_sensitive">True</property> |
1997 | <signal name="focus-out-event" handler="clinica_patient_editor_on_surname_focus_out_event" swapped="no"/> |
1998 | </object> |
1999 | <packing> |
2000 | @@ -221,8 +221,6 @@ |
2001 | <property name="invisible_char_set">True</property> |
2002 | <property name="primary_icon_activatable">False</property> |
2003 | <property name="secondary_icon_activatable">False</property> |
2004 | - <property name="primary_icon_sensitive">True</property> |
2005 | - <property name="secondary_icon_sensitive">True</property> |
2006 | </object> |
2007 | <packing> |
2008 | <property name="expand">True</property> |
2009 | @@ -253,8 +251,6 @@ |
2010 | <property name="invisible_char_set">True</property> |
2011 | <property name="primary_icon_activatable">False</property> |
2012 | <property name="secondary_icon_activatable">False</property> |
2013 | - <property name="primary_icon_sensitive">True</property> |
2014 | - <property name="secondary_icon_sensitive">True</property> |
2015 | </object> |
2016 | <packing> |
2017 | <property name="expand">True</property> |
2018 | @@ -285,8 +281,6 @@ |
2019 | <property name="invisible_char_set">True</property> |
2020 | <property name="primary_icon_activatable">False</property> |
2021 | <property name="secondary_icon_activatable">False</property> |
2022 | - <property name="primary_icon_sensitive">True</property> |
2023 | - <property name="secondary_icon_sensitive">True</property> |
2024 | </object> |
2025 | <packing> |
2026 | <property name="expand">True</property> |
2027 | @@ -308,8 +302,6 @@ |
2028 | <property name="invisible_char_set">True</property> |
2029 | <property name="primary_icon_activatable">False</property> |
2030 | <property name="secondary_icon_activatable">False</property> |
2031 | - <property name="primary_icon_sensitive">True</property> |
2032 | - <property name="secondary_icon_sensitive">True</property> |
2033 | </object> |
2034 | <packing> |
2035 | <property name="left_attach">1</property> |
2036 | @@ -354,8 +346,6 @@ |
2037 | <property name="invisible_char_set">True</property> |
2038 | <property name="primary_icon_activatable">False</property> |
2039 | <property name="secondary_icon_activatable">False</property> |
2040 | - <property name="primary_icon_sensitive">True</property> |
2041 | - <property name="secondary_icon_sensitive">True</property> |
2042 | </object> |
2043 | <packing> |
2044 | <property name="left_attach">3</property> |
2045 | @@ -385,8 +375,6 @@ |
2046 | <property name="invisible_char_set">True</property> |
2047 | <property name="primary_icon_activatable">False</property> |
2048 | <property name="secondary_icon_activatable">False</property> |
2049 | - <property name="primary_icon_sensitive">True</property> |
2050 | - <property name="secondary_icon_sensitive">True</property> |
2051 | </object> |
2052 | <packing> |
2053 | <property name="left_attach">1</property> |
2054 | @@ -403,8 +391,6 @@ |
2055 | <property name="invisible_char_set">True</property> |
2056 | <property name="primary_icon_activatable">False</property> |
2057 | <property name="secondary_icon_activatable">False</property> |
2058 | - <property name="primary_icon_sensitive">True</property> |
2059 | - <property name="secondary_icon_sensitive">True</property> |
2060 | </object> |
2061 | <packing> |
2062 | <property name="left_attach">1</property> |
2063 | |
2064 | === modified file 'ui/window.glade' |
2065 | --- ui/window.glade 2011-09-27 21:50:27 +0000 |
2066 | +++ ui/window.glade 2011-10-06 07:06:24 +0000 |
2067 | @@ -26,7 +26,7 @@ |
2068 | <property name="title" translatable="yes">Clinica</property> |
2069 | <property name="window_position">center</property> |
2070 | <property name="default_width">700</property> |
2071 | - <property name="default_height">500</property> |
2072 | + <property name="default_height">400</property> |
2073 | <signal name="destroy" handler="clinica_user_interface_on_window_destroy" swapped="no"/> |
2074 | <child> |
2075 | <object class="GtkVBox" id="vbox1"> |
2076 | |
2077 | === modified file 'wscript' |
2078 | --- wscript 2011-10-03 16:31:06 +0000 |
2079 | +++ wscript 2011-10-06 07:06:24 +0000 |
2080 | @@ -13,10 +13,6 @@ |
2081 | |
2082 | def options (opt): |
2083 | opt.load ('compiler_cc glib2 gnu_dirs') |
2084 | - # opt.add_option ('--destdir', action='store', default='', |
2085 | - # help = 'Install project in a different root', |
2086 | - # 1;2802;0c dest = 'destdir') |
2087 | - |
2088 | |
2089 | def put_config_h_in (ctx, destination): |
2090 | |
2091 | @@ -56,11 +52,13 @@ |
2092 | ctx.find_program ('glib-compile-schemas', var='GLIB_COMPILE_SCHEMAS') |
2093 | ctx.find_program ('g-ir-compiler', var = 'G_IR_COMPILER') |
2094 | |
2095 | + ctx.env.append_value ('VALAFLAGS', '-g') |
2096 | + |
2097 | put_config_h_in (ctx, "libclinica") |
2098 | put_config_h_in (ctx, "clinica") |
2099 | put_config_h_in (ctx, "plugins") |
2100 | |
2101 | - ctx.env.append_value ('CFLAGS', '-DHAVE_CONFIG_H -include config.h'.split ()) |
2102 | + ctx.env.append_value ('CFLAGS', '-g -DHAVE_CONFIG_H -include config.h'.split ()) |
2103 | |
2104 | def build(bld): |
2105 | bld.add_subdirs('libclinica') |
2106 | @@ -100,4 +98,11 @@ |
2107 | |
2108 | |
2109 | def run(ctx): |
2110 | +<<<<<<< TREE |
2111 | ctx.exec_command ("LD_LIBRARY_PATH=./_build_/libclinica GI_TYPELIB_PATH=./_build_/libclinica ./_build_/clinica/clinica") |
2112 | +======= |
2113 | + ctx.exec_command ("LD_LIBRARY_PATH=./_build_/libclinica ./_build_/clinica/clinica") |
2114 | + |
2115 | +def debug (ctx): |
2116 | + ctx.exec_command ("LD_LIBRARY_PATH=./_build_/libclinica gdb --args ./_build_/clinica/clinica") |
2117 | +>>>>>>> MERGE-SOURCE |