Merge lp:~leo.robol/clinica-project/data-provider into lp:clinica-project/trunk

Proposed by Leonardo Robol
Status: Merged
Approved by: Leonardo Robol
Approved revision: 425
Merged at revision: 411
Proposed branch: lp:~leo.robol/clinica-project/data-provider
Merge into: lp:clinica-project/trunk
Diff against target: 5837 lines (+2340/-1670) (has conflicts)
64 files modified
glade/clinica.xml (+1/-3)
libclinica/Application.vala (+1/-1)
libclinica/Builder.vala (+0/-1)
libclinica/Calendar.vala (+16/-16)
libclinica/CalendarEventList.vala (+6/-6)
libclinica/CalendarToolbar.vala (+1/-2)
libclinica/CalendarWindow.vala (+1/-1)
libclinica/CoreActivatable.vala (+46/-0)
libclinica/CoreActivatableExtensionSet.c (+43/-0)
libclinica/DataProvider.vala (+241/-0)
libclinica/DateTimePicker.vala (+5/-10)
libclinica/Day.vala (+6/-7)
libclinica/Doctor.vala (+30/-98)
libclinica/DoctorEditor.vala (+6/-11)
libclinica/DoctorListStore.vala (+40/-22)
libclinica/DoctorListView.vala (+8/-18)
libclinica/EmptyVisitIterator.vala (+30/-0)
libclinica/Event.vala (+16/-135)
libclinica/EventDetail.vala (+3/-5)
libclinica/EventEditor.vala (+1/-1)
libclinica/EventIterator.vala (+44/-0)
libclinica/EventListStore.vala (+40/-20)
libclinica/FileObject.vala (+3/-3)
libclinica/FileStore.vala (+9/-10)
libclinica/FindEntry.vala (+20/-0)
libclinica/MedicineDetailDialog.vala (+19/-0)
libclinica/MedicineSearchEngine.vala (+19/-0)
libclinica/MedicineSearchPage.vala (+19/-0)
libclinica/MedicineTreeView.vala (+19/-0)
libclinica/Patient.vala (+34/-159)
libclinica/PatientEditor.vala (+5/-11)
libclinica/PatientEditorActivatable.vala (+19/-0)
libclinica/PatientListStore.vala (+20/-52)
libclinica/PatientListView.vala (+13/-10)
libclinica/PluginEngine.vala (+19/-0)
libclinica/ResourceManager.vala (+59/-228)
libclinica/Service.vala (+4/-4)
libclinica/SettingsManager.vala (+64/-0)
libclinica/SqlDataType.vala (+0/-397)
libclinica/SqliteDataProvider.vala (+754/-0)
libclinica/SqliteDoctorIterator.vala (+45/-0)
libclinica/SqlitePatientIterator.vala (+45/-0)
libclinica/SqliteVisitIterator.vala (+44/-0)
libclinica/UserInterface.vala (+3/-3)
libclinica/UserInterfaceActivatable.vala (+19/-0)
libclinica/Visit.vala (+31/-182)
libclinica/VisitActions.vala (+1/-1)
libclinica/VisitBrowser.vala (+7/-8)
libclinica/VisitDetail.vala (+1/-2)
libclinica/VisitFileManager.vala (+5/-5)
libclinica/VisitListStore.vala (+17/-44)
libclinica/VisitSchedulerDialog.vala (+4/-4)
libclinica/VisitTab.vala (+9/-14)
libclinica/VisitWindow.vala (+2/-2)
org.phcteam.clinica.gschema.xml (+9/-0)
plugins/AgenziaDelFarmaco.plugin (+2/-2)
plugins/ClinicaAndroid.plugin (+6/-0)
plugins/ClinicaAndroid.py (+130/-0)
plugins/wscript (+16/-2)
po/es.po (+24/-15)
po/it.po (+21/-13)
po/pt_BR.po (+203/-128)
po/sr.po (+6/-7)
po/tr.po (+6/-7)
Text conflict in po/es.po
Text conflict in po/it.po
Text conflict in po/pt_BR.po
To merge this branch: bzr merge lp:~leo.robol/clinica-project/data-provider
Reviewer Review Type Date Requested Status
PHC Team Pending
Review via email: mp+94458@code.launchpad.net

Description of the change

Added abstraction of data provider.

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 'glade/clinica.xml'
2--- glade/clinica.xml 2012-02-02 16:52:54 +0000
3+++ glade/clinica.xml 2012-02-23 21:39:18 +0000
4@@ -3,9 +3,7 @@
5
6 <glade-widget-classes>
7 <glade-widget-class name="ClinicaCalendarView" generic-name="clinica_calendar_view" title="Calendar View" />
8- <glade-widget-class name="ClinicaDateTimePicker" generic-name="clinica_date_time_picker" title="DateTime picker">
9- <post-create-function>clinica_date_time_picker_glade_init</post-create-function>
10- </glade-widget-class>
11+ <glade-widget-class name="ClinicaDateTimePicker" generic-name="clinica_date_time_picker" title="DateTime picker" />
12 <glade-widget-class name="ClinicaPatientEntry" generic-name="clinica_patient_entry" title="Patient Entry" />
13 </glade-widget-classes>
14
15
16=== modified file 'libclinica/Application.vala'
17--- libclinica/Application.vala 2012-01-26 17:41:05 +0000
18+++ libclinica/Application.vala 2012-02-23 21:39:18 +0000
19@@ -150,7 +150,7 @@
20 Intl.bindtextdomain("clinica", null);
21
22 /* Init resources */
23- resource_manager.initResources();
24+// resource_manager.initResources();
25 }
26
27 if (daemon_mode) {
28
29=== modified file 'libclinica/Builder.vala'
30--- libclinica/Builder.vala 2012-02-02 07:26:45 +0000
31+++ libclinica/Builder.vala 2012-02-23 21:39:18 +0000
32@@ -15,7 +15,6 @@
33 * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
34 *
35 * Authors: Leonardo Robol <leo@robol.it>
36- * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it>
37 */
38
39 using Gtk;
40
41=== modified file 'libclinica/Calendar.vala'
42--- libclinica/Calendar.vala 2011-11-24 08:14:32 +0000
43+++ libclinica/Calendar.vala 2012-02-23 21:39:18 +0000
44@@ -85,10 +85,10 @@
45 return false;
46 });
47
48- resource_manager.event_list_store.event_added.connect (on_event_added);
49- resource_manager.event_list_store.event_removed.connect (on_event_removed);
50- resource_manager.visit_list_store.visit_added.connect (on_visit_added);
51- resource_manager.visit_list_store.visit_removed.connect (on_visit_removed);
52+ resource_manager.data_provider.event_added.connect (on_event_added);
53+ resource_manager.data_provider.event_removed.connect (on_event_removed);
54+ resource_manager.data_provider.visit_added.connect (on_visit_added);
55+ resource_manager.data_provider.visit_removed.connect (on_visit_removed);
56 realize.connect (() => set_date (today));
57 }
58
59@@ -113,11 +113,11 @@
60 foreach (var day in days) {
61 /* Fill events of the day */
62 day.reset_events ();
63- foreach (var visit in Visit.for_day (resource_manager, date, false)) {
64+ foreach (var visit in resource_manager.data_provider.visits (null, date, date.add_days (1))) {
65 /* Display visits in the day */
66 day.add_visit (visit);
67 }
68- foreach (var event in Event.for_day (resource_manager, date, false)) {
69+ foreach (var event in resource_manager.data_provider.events (date, date.add_days (1))) {
70 day.add_event (event);
71 }
72
73@@ -158,15 +158,15 @@
74 * It should find the day of the event, if present in the view, and
75 * insert the events in it.
76 */
77- private void on_event_added (int event_id) {
78- update_month ();
79- }
80-
81- private void on_visit_added (int visit_id) {
82- update_month ();
83- }
84-
85- private void on_visit_removed (int visit_id) {
86+ private void on_event_added (int64 event_id) {
87+ update_month ();
88+ }
89+
90+ private void on_visit_added (int64 visit_id) {
91+ update_month ();
92+ }
93+
94+ private void on_visit_removed (int64 visit_id) {
95 update_month ();
96 }
97
98@@ -176,7 +176,7 @@
99 * It should find the day that contained the event and remove it from the
100 * view.
101 */
102- private void on_event_removed (int event_id) {
103+ private void on_event_removed (int64 event_id) {
104 update_month ();
105 }
106
107
108=== modified file 'libclinica/CalendarEventList.vala'
109--- libclinica/CalendarEventList.vala 2012-02-02 07:26:45 +0000
110+++ libclinica/CalendarEventList.vala 2012-02-23 21:39:18 +0000
111@@ -45,10 +45,10 @@
112 set_size_request (280, -1);
113
114 /* Connect event added and or removed with the reload of the day */
115- resource_manager.event_list_store.event_added.connect ((event) => set_day (this.day));
116- resource_manager.event_list_store.event_removed.connect ((event) => set_day (this.day));
117- resource_manager.visit_list_store.visit_added.connect ((visit) => set_day (this.day));
118- resource_manager.visit_list_store.visit_removed.connect ((visit) => set_day (this.day));
119+ resource_manager.data_provider.event_added.connect ((event) => set_day (this.day));
120+ resource_manager.data_provider.event_removed.connect ((event) => set_day (this.day));
121+ resource_manager.data_provider.visit_added.connect ((visit) => set_day (this.day));
122+ resource_manager.data_provider.visit_removed.connect ((visit) => set_day (this.day));
123 }
124
125 public void set_day (DateTime date) {
126@@ -75,7 +75,7 @@
127
128 /* Show all the events of the day */
129 bool no_events = true;
130- foreach (Event event in Event.for_day (resource_manager, date)) {
131+ foreach (Event event in resource_manager.data_provider.events (date, date.add_days (1))) {
132 no_events = false;
133 var event_box = new EventDetail (resource_manager, event);
134 box.pack_start (event_box, false, true);
135@@ -109,7 +109,7 @@
136
137 /* And now the visits of the day */
138 bool no_visits = true;
139- foreach (Visit visit in Visit.for_day (resource_manager, date)) {
140+ foreach (Visit visit in resource_manager.data_provider.visits (null, date, date.add_days(1))) {
141 no_visits = false;
142 var visit_detail = new VisitDetail (resource_manager, visit);
143 box.pack_start (visit_detail, false, true);
144
145=== modified file 'libclinica/CalendarToolbar.vala'
146--- libclinica/CalendarToolbar.vala 2011-11-25 15:02:16 +0000
147+++ libclinica/CalendarToolbar.vala 2012-02-23 21:39:18 +0000
148@@ -94,8 +94,7 @@
149
150 event_editor.set_transient_for (resource_manager.user_interface.calendar_window);
151 if (event_editor.run () == EventEditor.Response.SAVE) {
152- event_editor.selected_event.save ();
153- resource_manager.event_list_store.add_event (event_editor.selected_event);
154+ resource_manager.data_provider.save_event (event_editor.selected_event);
155 }
156 event_editor.destroy ();
157 }
158
159=== modified file 'libclinica/CalendarWindow.vala'
160--- libclinica/CalendarWindow.vala 2011-11-27 23:17:27 +0000
161+++ libclinica/CalendarWindow.vala 2012-02-23 21:39:18 +0000
162@@ -27,7 +27,7 @@
163 internal ResourceManager resource_manager { get; set; }
164 internal CalendarView calendar_view { get; set; }
165 internal CalendarEventList event_widget { get; set; }
166- internal CalendarToolbar toolbar { get; private set; }
167+ internal CalendarToolbar toolbar { get; private set; }
168
169 public CalendarWindow (ResourceManager resources) {
170 GLib.Object (type: WindowType.TOPLEVEL);
171
172=== added file 'libclinica/CoreActivatable.vala'
173--- libclinica/CoreActivatable.vala 1970-01-01 00:00:00 +0000
174+++ libclinica/CoreActivatable.vala 2012-02-23 21:39:18 +0000
175@@ -0,0 +1,46 @@
176+/*
177+ * This file is part of Clinica.
178+ *
179+ * Clinica is free software: you can redistribute it and/or modify
180+ * it under the terms of the GNU General Public License as published by
181+ * the Free Software Foundation, either version 3 of the License, or
182+ * (at your option) any later version.
183+ *
184+ * Clinica is distributed in the hope that it will be useful,
185+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
186+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
187+ * GNU General Public License for more details.
188+ *
189+ * You should have received a copy of the GNU General Public License
190+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
191+ *
192+ * Authors: Leonardo Robol <leo@robol.it>
193+ */
194+
195+ namespace Clinica {
196+
197+ public interface CoreActivatable : Object {
198+
199+ /**
200+ * @brief The ResourceManager used to interact with clinica.
201+ */
202+ public abstract ResourceManager resource_manager { get; set; }
203+
204+ /**
205+ * @brief Activate method that will be called when the extension
206+ * is loaded. Special hooking up to callbacks and similar can be
207+ * done here (registering as data_provider, for example).
208+ */
209+ public abstract void activate ();
210+
211+ /**
212+ * @brief Deactivation method. Here the extension should unplug itself
213+ * from the Clinica application.
214+ */
215+ public abstract void deactivate ();
216+
217+ public abstract void update_state ();
218+
219+ }
220+
221+}
222
223=== added file 'libclinica/CoreActivatableExtensionSet.c'
224--- libclinica/CoreActivatableExtensionSet.c 1970-01-01 00:00:00 +0000
225+++ libclinica/CoreActivatableExtensionSet.c 2012-02-23 21:39:18 +0000
226@@ -0,0 +1,43 @@
227+#include <libpeas/peas.h>
228+#include <clinica.h>
229+#include <stdio.h>
230+
231+static void
232+on_extension_added (PeasExtensionSet *set,
233+ PeasPluginInfo *info,
234+ ClinicaCoreActivatable *activatable)
235+{
236+ clinica_core_activatable_activate (activatable);
237+}
238+
239+static void
240+on_extension_removed (PeasExtensionSet *set,
241+ PeasPluginInfo *info,
242+ ClinicaCoreActivatable *activatable)
243+{
244+ clinica_core_activatable_deactivate (activatable);
245+}
246+
247+PeasExtensionSet*
248+clinica_resource_manager_setup_extension_set (ClinicaResourceManager *rm,
249+ PeasEngine *engine)
250+{
251+ PeasExtensionSet *set;
252+
253+ set = peas_extension_set_new (engine, CLINICA_TYPE_CORE_ACTIVATABLE,
254+ "resource_manager", rm, NULL);
255+
256+ g_signal_connect (set, "extension-added",
257+ G_CALLBACK (on_extension_added), NULL);
258+ g_signal_connect (set, "extension-removed",
259+ G_CALLBACK (on_extension_removed), NULL);
260+#ifdef HAVE_PEAS_EXTENSION_SET_FOREACH
261+ peas_extension_set_foreach (set,
262+ (PeasExtensionSetForeachFunc) on_extension_added,
263+ NULL);
264+#else
265+ peas_extension_set_call (set, "activate");
266+#endif
267+
268+ return set;
269+}
270
271=== added file 'libclinica/DataProvider.vala'
272--- libclinica/DataProvider.vala 1970-01-01 00:00:00 +0000
273+++ libclinica/DataProvider.vala 2012-02-23 21:39:18 +0000
274@@ -0,0 +1,241 @@
275+/*
276+ * This file is part of Clinica.
277+ *
278+ * Clinica is free software: you can redistribute it and/or modify
279+ * it under the terms of the GNU General Public License as published by
280+ * the Free Software Foundation, either version 3 of the License, or
281+ * (at your option) any later version.
282+ *
283+ * Clinica is distributed in the hope that it will be useful,
284+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
285+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
286+ * GNU General Public License for more details.
287+ *
288+ * You should have received a copy of the GNU General Public License
289+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
290+ *
291+ * Authors: Leonardo Robol <leo@robol.it>
292+ */
293+
294+ namespace Clinica {
295+
296+ public interface VisitIterator : Object {
297+ public abstract Visit get ();
298+ public abstract bool next ();
299+ public VisitIterator iterator () { return this; }
300+ }
301+
302+ public interface PatientIterator : Object {
303+ public abstract Patient get ();
304+ public abstract bool next ();
305+ public PatientIterator iterator () { return this; }
306+ }
307+
308+ public interface DoctorIterator : Object {
309+ public abstract Doctor get ();
310+ public abstract bool next ();
311+ public DoctorIterator iterator () { return this; }
312+ }
313+
314+ public interface EventIterator : Object {
315+ public abstract Event get ();
316+ public abstract bool next ();
317+ public EventIterator iterator () { return this; }
318+ }
319+
320+ public interface DataProvider : Object {
321+
322+ /**
323+ * @brief Get the name of the DataProvider object. This must be a unique
324+ * name since it will be used to identify it and to select the right
325+ * DataProvider on startup.
326+ */
327+ public abstract string get_name ();
328+
329+ /**
330+ * @brief Get the visit with the given id.
331+ */
332+ public abstract Visit get_visit (int64 id);
333+
334+ /**
335+ * @brief Save a Visit. If the ID associated is 0
336+ * than a new ID will be created and will be returned.
337+ */
338+ public abstract int64 save_visit (Visit visit);
339+
340+ /**
341+ * @brief Remove a Visit from the database. This routine
342+ * will return 0 on success.
343+ */
344+ public abstract int64 remove_visit (Visit visit);
345+
346+ /**
347+ * @brief Emitted when a visit changes in the Database; this means
348+ * that all Visit object with this ID around must be invalidated and
349+ * reloaded.
350+ */
351+ public signal void visit_changed (int64 id);
352+
353+ /**
354+ * @brief Emitted when a visit is removed from the database. This means
355+ * that all the Visit with this id must be removed. Please note that you
356+ * can't call get_visit () with this ID since the visit has already been
357+ * removed.
358+ */
359+ public signal void visit_removed (int64 id);
360+
361+ /**
362+ * @brief Emitted when a new visit is added to the database.
363+ */
364+ public signal void visit_added (int64 id);
365+
366+ /**
367+ * @brief Iterate on all the visits
368+ *
369+ * @param patient If not null then pick up only the visits of the given patient.
370+ * @param start If not null pick up only visits from this starting date.
371+ * @param end If not null stop iterating on visits when this date is reached.
372+ */
373+ public abstract VisitIterator visits (Patient? patient = null, DateTime? start = null, DateTime? end = null);
374+
375+ /**
376+ * @brief Get the Patient with the given id.
377+ */
378+ public abstract Patient get_patient (int64 id);
379+
380+ /**
381+ * @brief Save a Patient. If the ID associated is 0
382+ * than a new ID will be created and will be returned.
383+ */
384+ public abstract int64 save_patient (Patient patient);
385+
386+ /**
387+ * @brief Remove a Patient from the database. This routine
388+ * will return 0 on success.
389+ *
390+ * This routine must take care of removing all the patients
391+ * visits and deassociate all the events from this patient.
392+ */
393+ public abstract int64 remove_patient (Patient patient);
394+
395+ /**
396+ * @brief Emitted when a patient changes in the database; this means
397+ * that all Patient objects with this ID around must be invalidated and
398+ * reloaded.
399+ */
400+ public signal void patient_changed (int64 id);
401+
402+ /**
403+ * @brief Emitted when a patient is removed from the database. This means
404+ * that all the Patients with this id must be removed. Please note that you
405+ * can't call get_patient () with this ID since the patient has already been
406+ * removed.
407+ */
408+ public signal void patient_removed (int64 id);
409+
410+ /**
411+ * @brief Emitted when a new patient is added to the database.
412+ */
413+ public signal void patient_added (int64 id);
414+
415+ /**
416+ * @brief Iterate over all the patients in the database.
417+ *
418+ * @param doctor If doctor is not null iterate only on patients associated
419+ * on this doctor.
420+ */
421+ public abstract PatientIterator patients (Doctor? doctor = null);
422+
423+ /**
424+ * @brief Get the doctor associatied with the given id.
425+ */
426+ public abstract Doctor get_doctor (int64 id);
427+
428+ /**
429+ * @brief Save a Doctor. If the ID associated is 0
430+ * than a new ID will be created and will be returned.
431+ */
432+ public abstract int64 save_doctor (Doctor doctor);
433+
434+ /**
435+ * @brief Remove a Doctor from the database. This routine
436+ * will return 0 on success.
437+ *
438+ * This routine must take care of deassociating of the
439+ * patients of this doctor from him/her.
440+ */
441+ public abstract int64 remove_doctor (Doctor doctor);
442+
443+ /**
444+ * @brief Emitted when a doctor changes in the database; this means
445+ * that all Doctor objects with this ID around must be invalidated and
446+ * reloaded.
447+ */
448+ public signal void doctor_changed (int64 id);
449+
450+ /**
451+ * @brief Emitted when a doctor is removed from the database. This means
452+ * that all the Doctor with this id must be removed. Please note that you
453+ * can't call get_doctor () with this ID since the doctor has already been
454+ * removed.
455+ */
456+ public signal void doctor_removed (int64 id);
457+
458+ /**
459+ * @brief Emitted when a new doctor is added to the database.
460+ */
461+ public signal void doctor_added (int64 id);
462+
463+ /**
464+ * @brief Iteratate over all the doctors in the database.
465+ */
466+ public abstract DoctorIterator doctors ();
467+
468+ /**
469+ * @brief Get the event associated to the given ID.
470+ */
471+ public abstract Event get_event (int64 id);
472+
473+ /**
474+ * @brief Save an Event. If the ID associated is 0
475+ * than a new ID will be created and will be returned.
476+ */
477+ public abstract int64 save_event (Event event);
478+
479+ /**
480+ * @brief Remove the event from the database.
481+ */
482+ public abstract int64 remove_event (Event event);
483+
484+ /**
485+ * @brief Emitted when an event changes in the database; this means
486+ * that all Event objects with this ID around must be invalidated and
487+ * reloaded.
488+ */
489+ public signal void event_changed (int64 id);
490+
491+ /**
492+ * @brief Emitted when an event is removed from the database. This means
493+ * that all the Event with this id must be removed. Please note that you
494+ * can't call get_event () with this ID since the event has already been
495+ * removed.
496+ */
497+ public signal void event_removed (int64 id);
498+
499+ /**
500+ * @brief Emitted when a new event is added to the database.
501+ */
502+ public signal void event_added (int64 id);
503+
504+ /**
505+ * @brief Iterate over all the events in the database.
506+ *
507+ * @param from If from is not null then iterate only from events starting after
508+ * from.
509+ * @param to If to is not null then iterate only until events before to.
510+ */
511+ public abstract EventIterator events (DateTime? from = null, DateTime? to = null);
512+
513+ }
514+
515+ }
516
517=== modified file 'libclinica/DateTimePicker.vala'
518--- libclinica/DateTimePicker.vala 2012-02-02 17:48:45 +0000
519+++ libclinica/DateTimePicker.vala 2012-02-23 21:39:18 +0000
520@@ -20,27 +20,20 @@
521
522 namespace Clinica {
523
524- public class DateTimePicker : Gtk.EventBox, Buildable {
525+ public class DateTimePicker : Gtk.EventBox, Buildable, Gtk.Buildable {
526
527 private Gtk.Calendar calendar;
528
529 private Gtk.SpinButton hour_spinbutton;
530 private Gtk.SpinButton minute_spinbutton;
531
532- public static void glade_init (Object adaptor, DateTimePicker picker, int reason) {
533- picker.create_interface ();
534- }
535-
536 public void setup (ResourceManager resources) {
537- create_interface ();
538- show_all ();
539 }
540
541 public DateTimePicker () {
542- create_interface ();
543 }
544-
545- public void create_interface () {
546+
547+ construct {
548 var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
549
550 calendar = new Gtk.Calendar ();
551@@ -69,6 +62,8 @@
552 add (vbox);
553
554 calendar.set_margin_bottom (6);
555+
556+ show_all ();
557 }
558
559 private void on_hour_spinbutton_changed (Gtk.Editable spin) {
560
561=== modified file 'libclinica/Day.vala'
562--- libclinica/Day.vala 2011-12-19 06:28:10 +0000
563+++ libclinica/Day.vala 2012-02-23 21:39:18 +0000
564@@ -94,8 +94,7 @@
565 event_editor.set_transient_for (resource_manager.user_interface.calendar_window);
566 if (event_editor.run () == EventEditor.Response.SAVE) {
567 /* Save the event in the editor */
568- event_editor.selected_event.save ();
569- resource_manager.event_list_store.add_event (event_editor.selected_event);
570+ resource_manager.data_provider.save_event (event_editor.selected_event);
571 }
572 event_editor.destroy ();
573 return true;
574@@ -180,7 +179,7 @@
575 ctx.set_font_size (10.0);
576 double line_position = 20;
577 double line_height = 13.0;
578- Gee.LinkedList<int> displayed_patients_id = new Gee.LinkedList<int> ();
579+ Gee.LinkedList<int64?> displayed_patients_id = new Gee.LinkedList<int64?> ();
580 ctx.rectangle (0, 0, width - 4, height - 4);
581 ctx.clip ();
582
583@@ -208,9 +207,9 @@
584
585 /* Drawing performed visits */
586 foreach (var visit in visit_list) {
587- if (visit.patient.get_id () in displayed_patients_id)
588+ if (visit.patient.id in displayed_patients_id)
589 continue;
590- displayed_patients_id.add (visit.patient.get_id ());
591+ displayed_patients_id.add (visit.patient.id);
592 string text = "Visit: " + visit.patient.get_complete_name ();;
593 ctx.text_extents (text, out extents);
594 ctx.move_to (4 - extents.x_bearing,
595@@ -291,7 +290,7 @@
596 */
597 public void remove_visit (Visit visit) {
598 foreach (var v in visit_list) {
599- if (v.get_id () == visit.get_id ()) {
600+ if (v.id == visit.id) {
601 visit_list.remove (v);
602 area.queue_draw ();
603 return;
604@@ -312,7 +311,7 @@
605 */
606 public void remove_event (Event event) {
607 foreach (var e in event_list) {
608- if (e.get_id () == event.get_id ()) {
609+ if (e.id == event.id) {
610 event_list.remove (e);
611 area.queue_draw ();
612 return;
613
614=== modified file 'libclinica/Doctor.vala'
615--- libclinica/Doctor.vala 2011-09-22 19:27:52 +0000
616+++ libclinica/Doctor.vala 2012-02-23 21:39:18 +0000
617@@ -15,104 +15,36 @@
618 * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
619 *
620 * Authors: Leonardo Robol <leo@robol.it>
621- * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it>
622 */
623-
624- using Gee;
625- using Sqlite;
626-
627- namespace Clinica {
628-
629-
630- public class DoctorIterator : SqlDataIterator {
631-
632- private ResourceManager resource_manager;
633-
634- /**
635- * @brief Iterator over all the Doctors present
636- * in the database.
637- */
638- public DoctorIterator (ResourceManager resources) {
639- base (resources.db, resources.doctor_table);
640- resource_manager = resources;
641- }
642-
643- public new DoctorIterator iterator () { return this; }
644-
645- public new Doctor get () {
646- return new Doctor.with_id (resource_manager, base.get ());
647- }
648+
649+namespace Clinica {
650+
651+ public class Doctor : Object {
652+
653+ public DataProvider? provider = null;
654+
655+ public int64 id { get; set; default = 0; }
656+
657+ public string given_name { get; set; }
658+
659+ public string surname { get; set; }
660+
661+ public string phone { get; set; }
662+
663+ public string mobile { get; set; }
664+
665+ public string get_complete_name () {
666+ return string.join (" ", this.given_name, this.surname);
667+ }
668+
669+ public PatientIterator patients () {
670+ return provider.patients (this);
671+ }
672+
673+ public bool has_patients () {
674+ return (patients ().next ());
675+ }
676+
677 }
678-
679- /**
680- * @brief A doctor associated with some patients
681- */
682- public class Doctor : SqlDataType {
683-
684- public new static DoctorIterator all (ResourceManager resources) {
685- return new DoctorIterator (resources);
686- }
687-
688- /* FIELDS */
689- public string given_name {
690- get { return get_text ("given_name"); }
691- set { set_text ("given_name", value); }
692- }
693-
694- public string surname {
695- get { return get_text ("surname"); }
696- set { set_text ("surname", value); }
697- }
698-
699- public string phone {
700- get { return get_text ("phone"); }
701- set { set_text ("phone", value); }
702- }
703-
704- public string mobile {
705- get { return get_text ("mobile"); }
706- set { set_text ("mobile", value); }
707- }
708-
709- private ResourceManager resource_manager;
710-
711- public Doctor (ResourceManager resources) {
712- base (resources.db);
713- resource_manager = resources;
714- table_name = resources.doctor_table;
715- error.connect ((t,l) => resources.error_callback(t,l));
716-
717- add_text_field ("given_name");
718- add_text_field ("surname");
719- add_text_field ("phone");
720- add_text_field ("mobile");
721-
722- /* Finishing connecting the object to the database */
723- init_resources ();
724- }
725-
726- public Doctor.with_id (ResourceManager resources, int ID) {
727- this (resources);
728- load (ID);
729- }
730-
731- public string get_complete_name () {
732- return string.join(" ", given_name, surname);
733- }
734-
735- public bool has_patients () {
736- GLib.List<int> associated_ids = associated_ids(resource_manager.patient_table, "doctor");
737- return (associated_ids.length () != 0);
738- }
739-
740- public new void remove () {
741- if (has_patients ())
742- error (_("You cannot delete a doctor with associated patients. Delete his patients first."));
743- else
744- base.remove ();
745- }
746-
747-
748
749- }
750- }
751+}
752
753=== modified file 'libclinica/DoctorEditor.vala'
754--- libclinica/DoctorEditor.vala 2012-01-31 09:43:09 +0000
755+++ libclinica/DoctorEditor.vala 2012-02-23 21:39:18 +0000
756@@ -50,7 +50,7 @@
757 resource_manager = resources;
758 error.connect ((me, message) => resource_manager.error_callback (me, message));
759
760- builder = new Clinica.Builder.with_filename (resources, "doctor-editor.glade");
761+ builder = new Clinica.Builder.with_filename (resources, "doctor_editor.glade");
762 builder.load_into_dialog (this);
763
764 /* Pack buttons and content */
765@@ -85,7 +85,7 @@
766 mobile_entry.set_text (doctor.mobile);
767
768 /* Set title of edit doctor dialog, space is important! */
769- set_title (_("Edit doctor named %s").printf(doctor.get_complete_name ()));
770+ set_title (_("Edit doctor named %s").printf (doctor.get_complete_name ()));
771 }
772
773 /**
774@@ -111,7 +111,7 @@
775 if (base.run () == Response.SAVE) {
776 Doctor doc;
777 if (existing_doctor == null)
778- doc = new Doctor (resource_manager);
779+ doc = new Doctor ();
780 else
781 doc = existing_doctor;
782
783@@ -120,14 +120,9 @@
784 doc.surname = surname_entry.get_text ();
785 doc.phone = phone_entry.get_text ();
786 doc.mobile = mobile_entry.get_text ();
787- doc.save ();
788-
789- if (existing_doctor == null) {
790- created_doctor = doc;
791- resource_manager.doctor_list_store.add_doctor (doc);
792- } else {
793- resource_manager.doctor_list_store.reload_doctor (doc);
794- }
795+ int64 new_id = resource_manager.data_provider.save_doctor (doc);
796+
797+ created_doctor = resource_manager.data_provider.get_doctor (new_id);
798
799 return Response.SAVE;
800 }
801
802=== modified file 'libclinica/DoctorListStore.vala'
803--- libclinica/DoctorListStore.vala 2011-09-28 06:45:15 +0000
804+++ libclinica/DoctorListStore.vala 2012-02-23 21:39:18 +0000
805@@ -47,43 +47,61 @@
806
807 /* Asynchronous loading of doctors... */
808 Idle.add (() => {
809- foreach (Doctor doc in Doctor.all (resource_manager)) {
810- add_doctor (doc);
811+ foreach (Doctor doc in resource_manager.data_provider.doctors ()) {
812+ add_doctor (doc.id);
813 }
814
815+ /* Setup callbacks to add or remove doctors */
816+ resource_manager.data_provider.doctor_added.connect (
817+ (id) => add_doctor (id));
818+ resource_manager.data_provider.doctor_changed.connect (
819+ (id) => reload_doctor (id));
820+ resource_manager.data_provider.doctor_removed.connect (
821+ (id) => remove_doctor (id));
822+
823 /* We don't need to execute any more */
824 return false;
825 });
826 }
827
828- public void add_doctor (Doctor doc) {
829- TreeIter it;
830- append(out it);
831- set_value (it, Field.DOCTOR, doc);
832- set_value (it, Field.GIVEN_NAME, doc.given_name);
833- set_value (it, Field.SURNAME, doc.surname);
834- set_value (it, Field.COMPLETE_NAME, doc.get_complete_name ());
835- }
836-
837- public void reload_doctor (Doctor doc) {
838- TreeIter it;
839- Value doctor;
840- int this_id = doc.get_id ();
841+ private TreeIter id_to_iter (int64 id) {
842+ TreeIter it;
843+ Value doctor;
844 if (!get_iter_first (out it)) {
845 error (_("Doctors database seems corrupted."));
846 }
847 do {
848 get_value (it, Field.DOCTOR, out doctor);
849- if ((doctor as Doctor).get_id () == this_id) {
850- set_value (it, Field.DOCTOR, doc);
851- set_value (it, Field.GIVEN_NAME, doc.given_name);
852- set_value (it, Field.SURNAME, doc.surname);
853- set_value (it, Field.COMPLETE_NAME, doc.get_complete_name ());
854- return;
855+ if ((doctor as Doctor).id == id) {
856+ return it;
857 }
858 } while (iter_next (ref it));
859
860- assert_not_reached ();
861+ return it;
862+ }
863+
864+ private void add_doctor (int64 id) {
865+ Doctor doc = resource_manager.data_provider.get_doctor (id);
866+ TreeIter it;
867+ append(out it);
868+ set_value (it, Field.DOCTOR, doc);
869+ set_value (it, Field.GIVEN_NAME, doc.given_name);
870+ set_value (it, Field.SURNAME, doc.surname);
871+ set_value (it, Field.COMPLETE_NAME, doc.get_complete_name ());
872+ }
873+
874+ private void reload_doctor (int64 id) {
875+ Doctor doc = resource_manager.data_provider.get_doctor (id);
876+ TreeIter it = id_to_iter (id);
877+ set_value (it, Field.DOCTOR, doc);
878+ set_value (it, Field.GIVEN_NAME, doc.given_name);
879+ set_value (it, Field.SURNAME, doc.surname);
880+ set_value (it, Field.COMPLETE_NAME, doc.get_complete_name ());
881+ }
882+
883+ private void remove_doctor (int64 id) {
884+ TreeIter iter = id_to_iter (id);
885+ remove (iter);
886 }
887 }
888 }
889
890=== modified file 'libclinica/DoctorListView.vala'
891--- libclinica/DoctorListView.vala 2012-01-31 08:10:13 +0000
892+++ libclinica/DoctorListView.vala 2012-02-23 21:39:18 +0000
893@@ -126,7 +126,7 @@
894 * @brief Return an iter in the DoctorListStore associated
895 * with the current selection, or null
896 */
897- private TreeIter? get_selected_iter () {
898+ public TreeIter? get_selected_iter () {
899 TreeSelection selection = get_selection ();
900 TreeIter iter;
901 TreeModel model;
902@@ -184,7 +184,7 @@
903 MessageType.QUESTION, ButtonsType.YES_NO, "%s", "");
904 warning_dialog.set_markup(
905 _("The doctor that you have selected for removal has some patients associated. \n") +
906- _("It's not possible to remove it without removing all his patients.\n\n") +
907+ _("It's not possible to remove it without disassociating all his patients.\n\n") +
908 _("Do you really want to proceed?"));
909 warning_dialog.set_title (_("Doctor has associated patients"));
910 warning_dialog.set_transient_for (resource_manager.user_interface.window);
911@@ -197,18 +197,14 @@
912 warning_dialog.destroy ();
913
914 /* Get List of the patients to remove and delete them */
915- List<TreeIter?> iters = resource_manager.patient_list_store.get_patients_of (doc);
916-
917- /* This will be used to retrieve data from liststores */
918- Value value;
919+ PatientIterator patients = doc.patients ();
920
921 /* Create an array with the names oft he patients
922 * that will be deleted */
923 string [] patient_names = {};
924
925- foreach(TreeIter? it in iters) {
926- resource_manager.patient_list_store.get_value (it, 0, out value);
927- patient_names += " - <b>" + (value as Patient).get_complete_name() + "</b>";
928+ foreach(Patient p in patients) {
929+ patient_names += " - <b>" + p.get_complete_name() + "</b>";
930 }
931
932 /* Warn another time the user that these patients will be deleted and
933@@ -216,10 +212,10 @@
934 warning_dialog = new MessageDialog(null, DialogFlags.MODAL | DialogFlags.DESTROY_WITH_PARENT,
935 MessageType.QUESTION, ButtonsType.YES_NO, "%s", "");
936 warning_dialog.set_markup (
937- _("The following patients will be deleted by this action:\n") +
938+ _("The following patients will be disassociated from this doctor by this action:\n") +
939 string.joinv("\n", patient_names) + "\n" +
940 _("Do you really want to proceed?"));
941- warning_dialog.set_title (_("Confirm deletion of patients"));
942+ warning_dialog.set_title (_("Confirm disassociation of patients"));
943 warning_dialog.set_transient_for (resource_manager.user_interface.window);
944
945 if (warning_dialog.run () != ResponseType.YES) {
946@@ -229,11 +225,6 @@
947
948 /* If we got here then the user is really sure, so delete the patients */
949 warning_dialog.destroy ();
950- foreach (TreeIter? it in iters) {
951- resource_manager.patient_list_store.get_value (it, 0, out value);
952- (value as Patient).remove ();
953- resource_manager.patient_list_store.remove (it);
954- }
955 }
956 }
957 else {
958@@ -251,8 +242,7 @@
959 }
960
961 /* Proceed with the removal of the doctor */
962- doc.remove ();
963- resource_manager.doctor_list_store.remove(get_selected_iter ());
964+ resource_manager.data_provider.remove_doctor (doc);
965 }
966
967 }
968
969=== added file 'libclinica/EmptyVisitIterator.vala'
970--- libclinica/EmptyVisitIterator.vala 1970-01-01 00:00:00 +0000
971+++ libclinica/EmptyVisitIterator.vala 2012-02-23 21:39:18 +0000
972@@ -0,0 +1,30 @@
973+/*
974+ * This file is part of Clinica.
975+ *
976+ * Clinica is free software: you can redistribute it and/or modify
977+ * it under the terms of the GNU General Public License as published by
978+ * the Free Software Foundation, either version 3 of the License, or
979+ * (at your option) any later version.
980+ *
981+ * Clinica is distributed in the hope that it will be useful,
982+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
983+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
984+ * GNU General Public License for more details.
985+ *
986+ * You should have received a copy of the GNU General Public License
987+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
988+ *
989+ * Authors: Leonardo Robol <leo@robol.it>
990+ */
991+
992+ namespace Clinica {
993+
994+ public class EmptyVisitIterator : GLib.Object, VisitIterator {
995+
996+ public VisitIterator iterator () { return this; }
997+ public bool next () { return false; }
998+ public new Visit get () { return new Visit (); }
999+
1000+ }
1001+
1002+ }
1003
1004=== modified file 'libclinica/Event.vala'
1005--- libclinica/Event.vala 2011-10-10 06:54:39 +0000
1006+++ libclinica/Event.vala 2012-02-23 21:39:18 +0000
1007@@ -15,158 +15,39 @@
1008 * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1009 *
1010 * Authors: Leonardo Robol <leo@robol.it>
1011- * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it>
1012 */
1013-
1014+
1015 namespace Clinica {
1016
1017- public class EventIterator : SqlDataIterator {
1018-
1019- private ResourceManager resource_manager { get; set; }
1020-
1021- public EventIterator (ResourceManager resources) {
1022- /* Grab the resource manager and chain the SqlDataIterator constructor,
1023- * ordering by date in decreasing order. */
1024- base (resources.db, resources.events_table, "date", false);
1025- resource_manager = resources;
1026- }
1027-
1028- public EventIterator.with_day (ResourceManager resources, DateTime date, bool descending = true) {
1029- base.with_like (resources.db, resources.events_table, "date", descending,
1030- "date BETWEEN '%s' AND '%s'".printf (SqlDataType.datetime_to_string (date),
1031- SqlDataType.datetime_to_string (date.add_days (1).add_minutes(-1))));
1032- resource_manager = resources;
1033- }
1034-
1035- public new EventIterator iterator () {
1036- return this;
1037- }
1038-
1039- public new Event get () {
1040- return new Event.with_id (resource_manager, base.get ());
1041- }
1042- }
1043-
1044- public class Event : SqlDataType {
1045-
1046- private ResourceManager resource_manager { get; set; }
1047-
1048- /* Properties mapped to the database */
1049- public string title {
1050- get { return get_text ("title"); }
1051- set { set_text ("title", value); }
1052- }
1053-
1054- public string description {
1055- get { return get_text ("description"); }
1056- set { set_text ("description", value); }
1057- }
1058-
1059- public string venue {
1060- get { return get_text ("venue"); }
1061- set { set_text ("venue", value); }
1062- }
1063+ public class Event : Object {
1064+
1065+ public DataProvider? provider = null;
1066+
1067+ public int64 id { get; set; default = 0; }
1068+
1069+ public string title { get; set; }
1070+
1071+ public string description { get; set; }
1072+
1073+ public string venue { get; set; }
1074
1075 /**
1076 * @brief Patient associated to this event, if one exists,
1077 * or null otherwise
1078 */
1079- private Patient? _patient;
1080- public Patient? patient {
1081- get {
1082- int id = get_integer ("patient");
1083- if (id == 0) {
1084- return null;
1085- }
1086- else {
1087- _patient = new Patient.with_id (resource_manager, id);
1088- return _patient;
1089- }
1090- }
1091- set {
1092- if (value != null) {
1093- set_integer ("patient", value.get_id ());
1094- _patient = value;
1095- }
1096- else {
1097- set_integer ("patient", 0);
1098- }
1099- }
1100- }
1101-
1102+ public Patient? patient { get; set; }
1103
1104 /**
1105 * @brief Visit associated to this event, if one exists,
1106 * or null otherwise
1107 */
1108- private Visit? _visit;
1109- public Visit? visit {
1110- get {
1111- int id = get_integer ("visit");
1112- if (id == 0) {
1113- return null;
1114- }
1115- else {
1116- _visit = new Visit.with_id (resource_manager, id);
1117- return _visit;
1118- }
1119- }
1120- set {
1121- if (value != null) {
1122- set_integer ("visit", value.get_id ());
1123- _visit = value;
1124- }
1125- else {
1126- set_integer ("visit", 0);
1127- }
1128- }
1129- }
1130+ public Visit? visit { get; set; }
1131
1132 /**
1133 * @brief Date associated to this event.
1134 */
1135- private DateTime _date;
1136- public DateTime date {
1137- get {
1138- _date = get_date ("date");
1139- return _date;
1140- }
1141- set {
1142- _date = value;
1143- set_date ("date", _date);
1144- }
1145- }
1146+ public DateTime date { get; set; }
1147
1148- public Event (ResourceManager resources) {
1149- base (resources.db);
1150- resource_manager = resources;
1151- error.connect ((t,l) => resources.error_callback(t,l));
1152- table_name = resource_manager.events_table;
1153-
1154- add_text_field ("title");
1155- add_text_field ("description");
1156- add_text_field ("venue");
1157- add_integer_field ("patient");
1158- add_integer_field ("visit");
1159- add_date_field ("date");
1160-
1161- init_resources ();
1162-
1163- visit = null;
1164- patient = null;
1165- }
1166-
1167- public Event.with_id (ResourceManager resources, int id) {
1168- this (resources);
1169- load (id);
1170- }
1171-
1172- public static new EventIterator all (ResourceManager resources) {
1173- return new EventIterator (resources);
1174- }
1175-
1176- public static new EventIterator for_day (ResourceManager resources, DateTime date, bool descending = false) {
1177- return new EventIterator.with_day (resources, date, descending);
1178- }
1179 }
1180+
1181 }
1182
1183=== modified file 'libclinica/EventDetail.vala'
1184--- libclinica/EventDetail.vala 2012-02-02 08:38:15 +0000
1185+++ libclinica/EventDetail.vala 2012-02-23 21:39:18 +0000
1186@@ -55,6 +55,7 @@
1187 title_label.set_alignment (0.0f, 0.5f);
1188 title_label.set_size_request (120, -1);
1189 title_label.set_line_wrap (true);
1190+ title_label.set_valign (Align.START);
1191 box.pack_start (title_label);
1192
1193 /* Adding action buttons, such as edit and delete */
1194@@ -131,9 +132,7 @@
1195 var event_editor = new EventEditor (resource_manager, associated_event);
1196 event_editor.set_transient_for (resource_manager.user_interface.calendar_window);
1197 if (event_editor.run () == EventEditor.Response.SAVE) {
1198- event_editor.selected_event.save ();
1199- resource_manager.event_list_store.remove_event (event_editor.selected_event);
1200- resource_manager.event_list_store.add_event (event_editor.selected_event);
1201+ resource_manager.data_provider.save_event (event_editor.selected_event);
1202 }
1203
1204 event_editor.destroy ();
1205@@ -151,8 +150,7 @@
1206 }
1207 question.destroy ();
1208
1209- associated_event.remove ();
1210- resource_manager.event_list_store.remove_event (associated_event);
1211+ resource_manager.data_provider.remove_event (associated_event);
1212 }
1213 }
1214 }
1215
1216=== modified file 'libclinica/EventEditor.vala'
1217--- libclinica/EventEditor.vala 2011-11-12 15:14:56 +0000
1218+++ libclinica/EventEditor.vala 2012-02-23 21:39:18 +0000
1219@@ -89,7 +89,7 @@
1220 /* If the event is null, let's create a new one, otherwise
1221 * store the event passed for editing. */
1222 if (event == null) {
1223- selected_event = new Event (resource_manager);
1224+ selected_event = new Event ();
1225 set_title (_("Create a new event"));
1226 }
1227 else {
1228
1229=== added file 'libclinica/EventIterator.vala'
1230--- libclinica/EventIterator.vala 1970-01-01 00:00:00 +0000
1231+++ libclinica/EventIterator.vala 2012-02-23 21:39:18 +0000
1232@@ -0,0 +1,44 @@
1233+/*
1234+ * This file is part of Clinica.
1235+ *
1236+ * Clinica is free software: you can redistribute it and/or modify
1237+ * it under the terms of the GNU General Public License as published by
1238+ * the Free Software Foundation, either version 3 of the License, or
1239+ * (at your option) any later version.
1240+ *
1241+ * Clinica is distributed in the hope that it will be useful,
1242+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1243+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1244+ * GNU General Public License for more details.
1245+ *
1246+ * You should have received a copy of the GNU General Public License
1247+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1248+ *
1249+ * Authors: Leonardo Robol <leo@robol.it>
1250+ */
1251+
1252+using Sqlite;
1253+
1254+namespace Clinica {
1255+
1256+ public class SqliteEventIterator : Object, EventIterator {
1257+
1258+ private SqliteDataProvider provider;
1259+ private Statement stmt;
1260+
1261+ public SqliteEventIterator (SqliteDataProvider provider, string clause = "") {
1262+ this.provider = provider;
1263+ provider.db.prepare ("SELECT id from %s %s ORDER by date DESC;".printf (provider.event_table, clause),
1264+ -1, out stmt);
1265+ }
1266+
1267+ public bool next () {
1268+ return (stmt.step () == ROW);
1269+ }
1270+
1271+ public new Event get () {
1272+ int id = stmt.column_int (0);
1273+ return provider.get_event (id);
1274+ }
1275+ }
1276+}
1277
1278=== modified file 'libclinica/EventListStore.vala'
1279--- libclinica/EventListStore.vala 2011-11-26 11:40:13 +0000
1280+++ libclinica/EventListStore.vala 2012-02-23 21:39:18 +0000
1281@@ -24,9 +24,6 @@
1282
1283 public class EventListStore : ListStore {
1284
1285- public signal void event_added (int event_id);
1286- public signal void event_removed (int event_id);
1287-
1288 /**
1289 * @brief Fields present in the store, i.e. header of
1290 * the columns.
1291@@ -63,12 +60,38 @@
1292
1293 set_column_types (column_headers);
1294 GLib.Idle.add (load_events_from_db);
1295+
1296+ /* Setup callbacks to add or remove events */
1297+ resource_manager.data_provider.event_added.connect (
1298+ (id) => add_event (id));
1299+ resource_manager.data_provider.event_changed.connect (
1300+ (id) => reload_event (id));
1301+ resource_manager.data_provider.event_removed.connect (
1302+ (id) => remove_event (id));
1303+ }
1304+
1305+ /**
1306+ * @brief Reload information about an event
1307+ */
1308+ private void reload_event (int64 id) {
1309+ var event = resource_manager.data_provider.get_event (id);
1310+ TreeIter iter = id_to_iter (id);
1311+
1312+ /* Set values in the treeview */
1313+ set_value (iter, Field.EVENT, event);
1314+ set_value (iter, Field.DATE, event.date);
1315+ set_value (iter, Field.DESCRIPTION, event.description);
1316+ set_value (iter, Field.PATIENT, event.patient);
1317+ set_value (iter, Field.TITLE, event.title);
1318+ set_value (iter, Field.VENUE, event.venue);
1319+ set_value (iter, Field.VISIT, event.visit);
1320 }
1321
1322 /**
1323 * @brief Add an event to the liststore.
1324 */
1325- public void add_event (Event event) {
1326+ public void add_event (int64 id) {
1327+ var event = resource_manager.data_provider.get_event (id);
1328 TreeIter iter;
1329 append (out iter);
1330
1331@@ -80,31 +103,28 @@
1332 set_value (iter, Field.TITLE, event.title);
1333 set_value (iter, Field.VENUE, event.venue);
1334 set_value (iter, Field.VISIT, event.visit);
1335-
1336- /* Emit event_added to make calendars and other pieces of interface
1337- * using events know that they must reload their dates */
1338- event_added (event.get_id ());
1339- }
1340-
1341- public void remove_event (Event event) {
1342+ }
1343+
1344+ public void remove_event (int64 id) {
1345+ remove (id_to_iter (id));
1346+ }
1347+
1348+ private TreeIter id_to_iter (int64 id) {
1349 TreeIter iter;
1350 Value value;
1351+
1352 if (!get_iter_first (out iter)) {
1353 error (_("Events database seems corrupted. This is likely to be a bug in the application"));
1354 }
1355
1356 do {
1357 get_value (iter, Field.EVENT, out value);
1358- if ((value as Event).get_id () == event.get_id ()) {
1359- /* Delete this event from the liststore */
1360- int event_id = event.get_id ();
1361- remove (iter);
1362- event_removed (event_id);
1363- return;
1364+ if ((value as Event).id == id) {
1365+ return iter;
1366 }
1367 } while (iter_next (ref iter));
1368
1369- assert_not_reached ();
1370+ return iter;
1371 }
1372
1373 /**
1374@@ -114,8 +134,8 @@
1375 * This function is now called by default from the constructor.
1376 */
1377 private bool load_events_from_db () {
1378- foreach (var event in Event.all (resource_manager)) {
1379- add_event (event);
1380+ foreach (var event in resource_manager.data_provider.events ()) {
1381+ add_event (event.id);
1382 }
1383
1384 return false;
1385
1386=== modified file 'libclinica/FileObject.vala'
1387--- libclinica/FileObject.vala 2012-01-27 13:36:57 +0000
1388+++ libclinica/FileObject.vala 2012-02-23 21:39:18 +0000
1389@@ -38,13 +38,13 @@
1390 /**
1391 * @brief The ID of the file store where this file is saved.
1392 */
1393- int id;
1394+ int64 id;
1395
1396 /**
1397 * @brief Generate a FileObject starting from an existing file.
1398 * A copy of that filed will be stored in the FileStore specified.
1399 */
1400- public FileObject (FileStore store, int id, string filename, bool in_store = false) {
1401+ public FileObject (FileStore store, int64 id, string filename, bool in_store = false) {
1402 this.store = store;
1403 this.id = id;
1404 if (!in_store)
1405@@ -57,7 +57,7 @@
1406 * @brief Obtain the ID in the file store where the file can
1407 * be retrieved.
1408 */
1409- public int get_id () {
1410+ public int64 get_id () {
1411 return id;
1412 }
1413
1414
1415=== modified file 'libclinica/FileStore.vala'
1416--- libclinica/FileStore.vala 2012-01-29 15:44:14 +0000
1417+++ libclinica/FileStore.vala 2012-02-23 21:39:18 +0000
1418@@ -32,7 +32,7 @@
1419 * @brief Signal emitted when the FileStore changes. This invalidates
1420 * all the FileObjects around, that must be reloaded.
1421 */
1422- public signal void changed (int id);
1423+ public signal void changed (int64 id);
1424
1425 /**
1426 * @brief Signal emitted when something goes wrong :)
1427@@ -48,13 +48,13 @@
1428 * @brief List of directories that are monitored by the
1429 * GioFileMonitor, so we don't monitor the twice.
1430 */
1431- private GLib.List<int> monitored_ids;
1432+ private GLib.List<int64?> monitored_ids;
1433
1434 public FileStore (ResourceManager resources) {
1435 resource_manager = resources;
1436 error.connect ((t,l) => resource_manager.error_callback (t,l));
1437
1438- monitored_ids = new GLib.List<int> ();
1439+ monitored_ids = new GLib.List<int64?> ();
1440
1441 /* Setup some monitored folders */
1442 try {
1443@@ -63,7 +63,7 @@
1444
1445 FileInfo info;
1446 while ((info = enumerator.next_file ()) != null) {
1447- int id = int.parse (info.get_name ());
1448+ int64 id = int64.parse (info.get_name ());
1449 if (id.to_string () == info.get_name ()) {
1450 setup_monitor (id);
1451 }
1452@@ -78,7 +78,7 @@
1453 * @brief Get the path where the files related to the given ID
1454 * are stored.
1455 */
1456- internal string get_id_path (int id) {
1457+ internal string get_id_path (int64 id) {
1458 string path = Path.build_filename (resource_manager.get_filestore_dir (),
1459 id.to_string ());
1460
1461@@ -100,7 +100,7 @@
1462 * @brief Setup a FileMonitor on the given directory ID, so we
1463 * may check for files created in there.
1464 */
1465- private void setup_monitor (int id) {
1466+ private void setup_monitor (int64 id) {
1467 if (monitored_ids.find (id) != null) {
1468 return;
1469 }
1470@@ -129,7 +129,7 @@
1471 * @brief Get the list of files associated to an ID.
1472 * This may even be an empty List.
1473 */
1474- public GLib.List<FileObject> get_files (int id) {
1475+ public GLib.List<FileObject> get_files (int64 id) {
1476 // Get the local data directory
1477 string this_id_path = get_id_path (id);
1478 File d = File.new_for_path (this_id_path);
1479@@ -143,7 +143,6 @@
1480 try {
1481 FileEnumerator enumerator = d.enumerate_children (FILE_ATTRIBUTE_STANDARD_NAME, FileQueryInfoFlags.NONE);
1482
1483-
1484 FileInfo info;
1485 while ((info = enumerator.next_file ()) != null) {
1486 results.append (new FileObject (this, id,
1487@@ -159,7 +158,7 @@
1488 /**
1489 * @brief Store a filed called filename in the FileStore.
1490 */
1491- public string store_file (int id, string filename) {
1492+ public string store_file (int64 id, string filename) {
1493 // Source file
1494 File source_file = File.new_for_path (filename);
1495
1496@@ -193,7 +192,7 @@
1497 /**
1498 * @brief Remove a file from the store.
1499 */
1500- public void remove_file (int id, string filename) {
1501+ public void remove_file (int64 id, string filename) {
1502 FileUtils.remove (Path.build_filename (resource_manager.get_filestore_dir (),
1503 id.to_string (), filename));
1504
1505
1506=== modified file 'libclinica/FindEntry.vala'
1507--- libclinica/FindEntry.vala 2011-09-22 19:27:52 +0000
1508+++ libclinica/FindEntry.vala 2012-02-23 21:39:18 +0000
1509@@ -1,3 +1,23 @@
1510+/*
1511+ * This file is part of Clinica.
1512+ *
1513+ * Clinica is free software: you can redistribute it and/or modify
1514+ * it under the terms of the GNU General Public License as published by
1515+ * the Free Software Foundation, either version 3 of the License, or
1516+ * (at your option) any later version.
1517+ *
1518+ * Clinica is distributed in the hope that it will be useful,
1519+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1520+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1521+ * GNU General Public License for more details.
1522+ *
1523+ * You should have received a copy of the GNU General Public License
1524+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1525+ *
1526+ * Authors: Leonardo Robol <leo@robol.it>
1527+ * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it>
1528+ */
1529+
1530 using Gtk;
1531
1532 namespace Clinica {
1533
1534=== modified file 'libclinica/MedicineDetailDialog.vala'
1535--- libclinica/MedicineDetailDialog.vala 2011-12-19 06:28:10 +0000
1536+++ libclinica/MedicineDetailDialog.vala 2012-02-23 21:39:18 +0000
1537@@ -1,3 +1,22 @@
1538+/*
1539+ * This file is part of Clinica.
1540+ *
1541+ * Clinica is free software: you can redistribute it and/or modify
1542+ * it under the terms of the GNU General Public License as published by
1543+ * the Free Software Foundation, either version 3 of the License, or
1544+ * (at your option) any later version.
1545+ *
1546+ * Clinica is distributed in the hope that it will be useful,
1547+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1548+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1549+ * GNU General Public License for more details.
1550+ *
1551+ * You should have received a copy of the GNU General Public License
1552+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1553+ *
1554+ * Authors: Leonardo Robol <leo@robol.it>
1555+ */
1556+
1557 using Gtk;
1558
1559 namespace Clinica {
1560
1561=== modified file 'libclinica/MedicineSearchEngine.vala'
1562--- libclinica/MedicineSearchEngine.vala 2011-12-09 17:28:05 +0000
1563+++ libclinica/MedicineSearchEngine.vala 2012-02-23 21:39:18 +0000
1564@@ -1,3 +1,22 @@
1565+/*
1566+ * This file is part of Clinica.
1567+ *
1568+ * Clinica is free software: you can redistribute it and/or modify
1569+ * it under the terms of the GNU General Public License as published by
1570+ * the Free Software Foundation, either version 3 of the License, or
1571+ * (at your option) any later version.
1572+ *
1573+ * Clinica is distributed in the hope that it will be useful,
1574+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1575+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1576+ * GNU General Public License for more details.
1577+ *
1578+ * You should have received a copy of the GNU General Public License
1579+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1580+ *
1581+ * Authors: Leonardo Robol <leo@robol.it>
1582+ */
1583+
1584 namespace Clinica {
1585
1586 public interface MedicineSearchEngine : UserInterfaceActivatable {
1587
1588=== modified file 'libclinica/MedicineSearchPage.vala'
1589--- libclinica/MedicineSearchPage.vala 2012-01-29 10:39:56 +0000
1590+++ libclinica/MedicineSearchPage.vala 2012-02-23 21:39:18 +0000
1591@@ -1,3 +1,22 @@
1592+/*
1593+ * This file is part of Clinica.
1594+ *
1595+ * Clinica is free software: you can redistribute it and/or modify
1596+ * it under the terms of the GNU General Public License as published by
1597+ * the Free Software Foundation, either version 3 of the License, or
1598+ * (at your option) any later version.
1599+ *
1600+ * Clinica is distributed in the hope that it will be useful,
1601+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1602+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1603+ * GNU General Public License for more details.
1604+ *
1605+ * You should have received a copy of the GNU General Public License
1606+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1607+ *
1608+ * Authors: Leonardo Robol <leo@robol.it>
1609+ */
1610+
1611 using Gtk;
1612
1613 namespace Clinica {
1614
1615=== modified file 'libclinica/MedicineTreeView.vala'
1616--- libclinica/MedicineTreeView.vala 2011-11-28 15:39:30 +0000
1617+++ libclinica/MedicineTreeView.vala 2012-02-23 21:39:18 +0000
1618@@ -1,3 +1,22 @@
1619+/*
1620+ * This file is part of Clinica.
1621+ *
1622+ * Clinica is free software: you can redistribute it and/or modify
1623+ * it under the terms of the GNU General Public License as published by
1624+ * the Free Software Foundation, either version 3 of the License, or
1625+ * (at your option) any later version.
1626+ *
1627+ * Clinica is distributed in the hope that it will be useful,
1628+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1629+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1630+ * GNU General Public License for more details.
1631+ *
1632+ * You should have received a copy of the GNU General Public License
1633+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1634+ *
1635+ * Authors: Leonardo Robol <leo@robol.it>
1636+ */
1637+
1638 using Gtk;
1639
1640 namespace Clinica {
1641
1642=== modified file 'libclinica/Patient.vala'
1643--- libclinica/Patient.vala 2011-11-03 16:41:02 +0000
1644+++ libclinica/Patient.vala 2012-02-23 21:39:18 +0000
1645@@ -15,173 +15,48 @@
1646 * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1647 *
1648 * Authors: Leonardo Robol <leo@robol.it>
1649- * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it>
1650 */
1651-
1652- using Gee;
1653- using Sqlite;
1654-
1655- namespace Clinica {
1656+
1657+namespace Clinica {
1658
1659 public enum Gender {
1660 MALE,
1661 FEMALE,
1662 }
1663-
1664- public class PatientIterator : SqlDataIterator {
1665- private ResourceManager resource_manager;
1666- public PatientIterator (ResourceManager resources) {
1667- base (resources.db, resources.patient_table);
1668- resource_manager = resources;
1669- }
1670-
1671- public new PatientIterator iterator () { return this; }
1672-
1673- public new Patient get () {
1674- return new Patient.with_id (resource_manager, base.get ());
1675- }
1676- }
1677-
1678- /**
1679- * @brief A Patient object represent a person
1680- * whose data are stored in the database (or
1681- * are going to be stored soon).
1682- */
1683- public class Patient : SqlDataType {
1684-
1685- /**
1686- * @brief Doctor associated to this patient.
1687- */
1688- private Doctor? _doctor;
1689- public Doctor? doctor {
1690- get {
1691- /* Always reload the doctor to make edits available immediately */
1692- if (get_integer ("doctor") == -1)
1693- return null;
1694- this._doctor = new Doctor.with_id (resource_manager, get_integer ("doctor"));
1695- return this._doctor;
1696- }
1697- set {
1698- this._doctor = value;
1699- if (_doctor == null)
1700- set_integer ("doctor", -1);
1701- else
1702- set_integer("doctor", value.get_id ());
1703- }
1704- }
1705-
1706- /* FIELDS */
1707- public string given_name {
1708- get { return get_text ("given_name"); }
1709- set { set_text ("given_name", value); }
1710- }
1711-
1712- public string surname {
1713- get { return get_text ("surname"); }
1714- set { set_text ("surname", value); }
1715- }
1716-
1717- private DateTime _birth_date;
1718- public DateTime birth_date {
1719- get {
1720- _birth_date = get_date ("birth_date");
1721- return _birth_date;
1722- }
1723- set {
1724- _birth_date = value;
1725- set_date ("birth_date", _birth_date);
1726- }
1727- }
1728-
1729- public Gender gender {
1730- get {
1731- if (get_text("gender") == "MALE")
1732- return Gender.MALE;
1733- else
1734- return Gender.FEMALE;
1735- }
1736- set {
1737- if (value == Gender.MALE)
1738- set_text("gender", "MALE");
1739- else
1740- set_text("gender", "FEMALE");
1741- }
1742- }
1743-
1744- public string phone {
1745- get { return get_text ("phone"); }
1746- set { set_text ("phone", value); }
1747- }
1748-
1749- public string residence_address {
1750- get { return get_text ("residence_address"); }
1751- set { set_text ("residence_address", value); }
1752- }
1753-
1754- public string identification_code {
1755- get { return get_text ("identification_code"); }
1756- set { set_text ("identification_code", value); }
1757- }
1758-
1759-
1760- private ResourceManager resource_manager;
1761-
1762- /**
1763- * @brief Create a new patient
1764- */
1765- public Patient (ResourceManager resources, Doctor? doctor) {
1766- base (resources.db);
1767- resource_manager = resources;
1768- table_name = resources.patient_table;
1769- error.connect ((t,l) => resources.error_callback(t,l));
1770-
1771- add_text_field ("given_name");
1772- add_text_field ("surname");
1773- add_date_field ("birth_date");
1774- add_text_field ("gender");
1775- add_text_field ("phone");
1776- add_text_field ("residence_address");
1777- add_text_field ("identification_code");
1778- add_integer_field ("doctor");
1779-
1780- this.doctor = doctor;
1781-
1782- init_resources ();
1783- }
1784-
1785- public Patient.with_id (ResourceManager resources, int ID) {
1786- this (resources, null);
1787- load (ID);
1788- if (doctor != null)
1789- {
1790- doctor = new Doctor.with_id (resources, get_integer ("doctor"));
1791- }
1792- }
1793-
1794- public static new PatientIterator all (ResourceManager resources) {
1795- return new PatientIterator (resources);
1796- }
1797+
1798+ public class Patient : Object {
1799+
1800+ public DataProvider? provider = null;
1801+
1802+ public int64 id { get; set; default = 0; }
1803+
1804+ public string given_name { get; set; }
1805+
1806+ public string surname { get; set; }
1807+
1808+ public DateTime birth_date { get; set; }
1809+
1810+ public Gender gender { get; set; }
1811+
1812+ public string phone { get; set; }
1813+
1814+ public string residence_address { get; set; }
1815+
1816+ public string identification_code { get; set; }
1817+
1818+ public Doctor doctor { get; set; }
1819
1820 public string get_complete_name () {
1821 return string.join (" ", this.given_name, this.surname);
1822 }
1823-
1824- public int64 get_age () {
1825- DateTime today = new DateTime.now_utc ();
1826- var diff = today.difference (this.birth_date);
1827-
1828- /* TimeSpan seems not to work.. :( */
1829- return (diff / 31557600000000);
1830- }
1831-
1832- /**
1833- * @brief Get the visit IDs for the selected patient.
1834- * Actual visits can then be retrieved with
1835- * var visit = new Visit (ID);
1836- */
1837- public GLib.List<int> get_visit_ids () {
1838- return associated_ids (resource_manager.visits_table, "patient");
1839- }
1840+
1841+ public VisitIterator visits (DateTime? start = null, DateTime? end = null) {
1842+ if (provider == null)
1843+ return new EmptyVisitIterator ();
1844+ else
1845+ return provider.visits (this, start, end);
1846+ }
1847+
1848 }
1849-
1850- }
1851+
1852+}
1853
1854=== modified file 'libclinica/PatientEditor.vala'
1855--- libclinica/PatientEditor.vala 2012-02-02 07:26:45 +0000
1856+++ libclinica/PatientEditor.vala 2012-02-23 21:39:18 +0000
1857@@ -405,8 +405,10 @@
1858
1859 /* Save the new patient, creating a new one if this is a new patient, or
1860 * reusing the existing one if we are only modifying a patient. */
1861- if (existing_patient == null)
1862- created_patient = new Patient (resource_manager, selected_doctor);
1863+ if (existing_patient == null) {
1864+ created_patient = new Patient ();
1865+ created_patient.doctor = selected_doctor;
1866+ }
1867 else
1868 created_patient = existing_patient;
1869
1870@@ -443,15 +445,7 @@
1871 else
1872 created_patient.gender = Gender.FEMALE;
1873
1874- created_patient.save ();
1875-
1876- // If this was an existing patient we need to reload it in the patient
1877- // list store, otherwise we can just add it
1878- if (existing_patient != null) {
1879- resource_manager.patient_list_store.reload_patient (created_patient);
1880- } else {
1881- resource_manager.patient_list_store.add_patient (created_patient);
1882- }
1883+ resource_manager.data_provider.save_patient (created_patient);
1884
1885 return Response.SAVE;
1886 }
1887
1888=== modified file 'libclinica/PatientEditorActivatable.vala'
1889--- libclinica/PatientEditorActivatable.vala 2011-09-22 19:27:52 +0000
1890+++ libclinica/PatientEditorActivatable.vala 2012-02-23 21:39:18 +0000
1891@@ -1,3 +1,22 @@
1892+/*
1893+ * This file is part of Clinica.
1894+ *
1895+ * Clinica is free software: you can redistribute it and/or modify
1896+ * it under the terms of the GNU General Public License as published by
1897+ * the Free Software Foundation, either version 3 of the License, or
1898+ * (at your option) any later version.
1899+ *
1900+ * Clinica is distributed in the hope that it will be useful,
1901+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1902+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1903+ * GNU General Public License for more details.
1904+ *
1905+ * You should have received a copy of the GNU General Public License
1906+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
1907+ *
1908+ * Authors: Leonardo Robol <leo@robol.it>
1909+ */
1910+
1911 namespace Clinica {
1912
1913 /**
1914
1915=== modified file 'libclinica/PatientListStore.vala'
1916--- libclinica/PatientListStore.vala 2011-09-22 19:27:52 +0000
1917+++ libclinica/PatientListStore.vala 2012-02-23 21:39:18 +0000
1918@@ -53,10 +53,20 @@
1919
1920 /* Asynchronous loading of patients */
1921 Idle.add(() => {
1922- foreach (Patient p in Patient.all (resource_manager)) {
1923- add_patient (p);
1924+ foreach (Patient p in resource_manager.data_provider.patients ()) {
1925+ add_patient (p.id);
1926 }
1927
1928+ /* Setup callbacks to add or remove patient */
1929+ resource_manager.data_provider.patient_added.connect (
1930+ (id) => add_patient (id));
1931+ resource_manager.data_provider.patient_changed.connect (
1932+ (id) => reload_patient (id));
1933+ resource_manager.data_provider.patient_removed.connect ((id) => {
1934+ TreeIter iter = id_to_iter (id);
1935+ remove (iter);
1936+ });
1937+
1938 /* We don't need to reiterate this function any more */
1939 return false;
1940 });
1941@@ -65,10 +75,11 @@
1942 /**
1943 * @brief Append the given patient to the liststore
1944 */
1945- public void add_patient (Patient p) {
1946+ private void add_patient (int64 id) {
1947+ Patient p = resource_manager.data_provider.get_patient (id);
1948 TreeIter it;
1949 append (out it);
1950- set_value (it, Field.PATIENT, p);
1951+ set_value (it, Field.PATIENT, p);
1952 set_value (it, Field.GIVEN_NAME, p.given_name);
1953 set_value (it, Field.SURNAME, p.surname);
1954 set_value (it, Field.COMPLETE_NAME, p.get_complete_name ());
1955@@ -78,7 +89,8 @@
1956 * @brief Reload information about patient p that
1957 * should be already present in the database
1958 */
1959- public void reload_patient (Patient p) {
1960+ private void reload_patient (int64 id) {
1961+ Patient p = resource_manager.data_provider.get_patient (id);
1962 TreeIter iter;
1963 Value patient;
1964
1965@@ -88,7 +100,7 @@
1966
1967 do {
1968 get_value (iter, Field.PATIENT, out patient);
1969- if ((patient as Patient).get_id () == p.get_id ()) {
1970+ if ((patient as Patient).id == p.id) {
1971 set_value(iter, Field.PATIENT, p);
1972 set_value(iter, Field.GIVEN_NAME, p.given_name);
1973 set_value(iter, Field.SURNAME, p.surname);
1974@@ -101,63 +113,19 @@
1975 assert_not_reached ();
1976 }
1977
1978- /**
1979- * @brief Return a list of treeiters pointing to the patients
1980- * of the given doctor.
1981- */
1982- public List<TreeIter?> get_patients_of (Doctor doc) {
1983- Value value;
1984- var iters = new List<TreeIter?> ();
1985- TreeIter it;
1986- Patient p;
1987-
1988- if (!get_iter_first (out it)) {
1989- return iters;
1990- }
1991- do {
1992- get_value (it, Field.PATIENT, out value);
1993- p = value as Patient;
1994- if (p.doctor.get_id () == doc.get_id ()) {
1995- iters.append (it);
1996- }
1997- } while (iter_next(ref it));
1998-
1999- return iters;
2000- }
2001-
2002- public TreeIter patient_to_iter (Patient p) {
2003+ private TreeIter id_to_iter (int64 id) {
2004 TreeIter it;
2005 Value patient;
2006 if (!get_iter_first (out it))
2007 error(_("Patients database seems corrupted. This is likely to be a bug in the application"));
2008 do {
2009 get_value (it, Field.PATIENT, out patient);
2010- if ((patient as Patient).get_id () == p.get_id ()) {
2011+ if ((patient as Patient).id == id) {
2012 return it;
2013 }
2014 } while (iter_next (ref it));
2015
2016 assert_not_reached ();
2017 }
2018-
2019- public void remove_patient (Patient p) {
2020- TreeIter p_iter = patient_to_iter (p);
2021- remove_patient_from_iter (p_iter);
2022- }
2023-
2024- public void remove_patient_from_iter (TreeIter it) {
2025- Value patient;
2026- get_value (it, Field.PATIENT, out patient);
2027-
2028- var visits = resource_manager.visit_list_store.get_visits_of (patient as Patient);
2029-
2030- foreach (TreeIter v_it in visits) {
2031- resource_manager.visit_list_store.remove_visit_from_iter (v_it);
2032- }
2033-
2034- /* Actually remove the patient */
2035- (patient as Patient).remove ();
2036- remove (it);
2037- }
2038 }
2039 }
2040
2041=== modified file 'libclinica/PatientListView.vala'
2042--- libclinica/PatientListView.vala 2012-01-31 08:10:13 +0000
2043+++ libclinica/PatientListView.vala 2012-02-23 21:39:18 +0000
2044@@ -135,10 +135,7 @@
2045 /* Cast patient and update database data */
2046 patient = value as Patient;
2047 patient.given_name = new_text;
2048- patient.save ();
2049-
2050- /* Update UI */
2051- resource_manager.patient_list_store.reload_patient (patient);
2052+ resource_manager.data_provider.save_patient (patient);
2053 }
2054
2055 private void on_surname_cell_edited (CellRenderer renderer, string path, string new_text) {
2056@@ -155,10 +152,7 @@
2057 /* Set new data in the Patient, save and update treeview */
2058 patient = value as Patient;
2059 patient.surname = new_text;
2060- patient.save ();
2061-
2062- /* Update UI */
2063- resource_manager.patient_list_store.reload_patient (patient);
2064+ resource_manager.data_provider.save_patient (patient);
2065 }
2066
2067 /**
2068@@ -189,8 +183,17 @@
2069 TreeIter it;
2070 sortable_model.convert_iter_to_child_iter (out it, iter);
2071 filtered_store.convert_iter_to_child_iter (out iter, it);
2072- /* Delete patient from the database and from the store*/
2073- store.remove_patient_from_iter (iter);
2074+
2075+ /* Delete patient from the database */
2076+ Value value;
2077+ store.get_value (iter, PatientListStore.Field.PATIENT, out value);
2078+
2079+ /* Removing the visits associated with this patient */
2080+ foreach (Visit visit in (value as Patient).visits ()) {
2081+ resource_manager.data_provider.remove_visit (visit);
2082+ }
2083+
2084+ resource_manager.data_provider.remove_patient (value as Patient);
2085 }
2086 }
2087
2088
2089=== modified file 'libclinica/PluginEngine.vala'
2090--- libclinica/PluginEngine.vala 2011-09-22 19:27:52 +0000
2091+++ libclinica/PluginEngine.vala 2012-02-23 21:39:18 +0000
2092@@ -1,3 +1,22 @@
2093+/*
2094+ * This file is part of Clinica.
2095+ *
2096+ * Clinica is free software: you can redistribute it and/or modify
2097+ * it under the terms of the GNU General Public License as published by
2098+ * the Free Software Foundation, either version 3 of the License, or
2099+ * (at your option) any later version.
2100+ *
2101+ * Clinica is distributed in the hope that it will be useful,
2102+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2103+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2104+ * GNU General Public License for more details.
2105+ *
2106+ * You should have received a copy of the GNU General Public License
2107+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
2108+ *
2109+ * Authors: Leonardo Robol <leo@robol.it>
2110+ */
2111+
2112 namespace Clinica {
2113
2114 public class PluginEngine : Peas.Engine {
2115
2116=== modified file 'libclinica/ResourceManager.vala'
2117--- libclinica/ResourceManager.vala 2012-02-02 07:26:45 +0000
2118+++ libclinica/ResourceManager.vala 2012-02-23 21:39:18 +0000
2119@@ -78,6 +78,14 @@
2120 public EventListStore event_list_store;
2121
2122 /**
2123+ * @brief This is the object used to retrieve all the data
2124+ * about patients and which events should be connected
2125+ * to the views to make them react to changes in the database
2126+ * or whatever the data source is.
2127+ */
2128+ internal DataProvider data_provider;
2129+
2130+ /**
2131 * @brief Reference to a user interface
2132 */
2133 public UserInterface user_interface;
2134@@ -98,24 +106,13 @@
2135 * @brief Local configuration directory
2136 * obtained at runtime.
2137 */
2138- private string local_config_directory;
2139+ internal string local_config_directory;
2140
2141 /**
2142 * @brief Local data directory obtained
2143 * at runtime.
2144 */
2145- private string local_data_directory;
2146-
2147- /**
2148- * @brief Database path.
2149- */
2150- private string database_path;
2151-
2152- /**
2153- * @brief SQLite database with data and
2154- * configurations.
2155- */
2156- public Database db;
2157+ internal string local_data_directory;
2158
2159 /**
2160 * @brief The file store used to retrieve the data associated
2161@@ -135,12 +132,20 @@
2162 */
2163 internal GLib.List<unowned MedicineSearchEngine> medicine_search_engines;
2164
2165+ /**
2166+ * @brief List containing the available DataProviders that
2167+ * can be used to retrieve data in Clinica.
2168+ */
2169+ internal List<unowned DataProvider> data_providers;
2170+
2171 /**
2172 * @brief A pointer to the patient that is been dragged. Should
2173 * be set on drag_begin by the treeview and reset to null by the
2174 * drag destination handler.
2175 */
2176 internal Patient? dragging_patient = null;
2177+
2178+ private Peas.ExtensionSet core_set;
2179
2180 /**
2181 * @brief Path to the UI files directory
2182@@ -160,9 +165,8 @@
2183 /** SIGNALS **/
2184 public signal void medicine_search_engines_added (MedicineSearchEngine engine);
2185 public signal void medicine_search_engines_removed (MedicineSearchEngine engine);
2186-
2187- private const string [] supported_db_versions = { "0.1", "0.2" };
2188- private const string db_version = "0.2";
2189+ public signal void data_provider_added (DataProvider provider);
2190+ public signal void data_provider_removed (DataProvider provider);
2191
2192 public ResourceManager (Gtk.Application? application,
2193 string program_name = "clinica",
2194@@ -198,68 +202,11 @@
2195 DirUtils.create_with_parents (local_data_directory, -1);
2196 }
2197
2198- /* Set database path and check if a database exists in the old location,
2199- * if that's the case move it to the new one. */
2200- check_database_path ();
2201-
2202 /* Check if the directory for the FileStore exists */
2203 File fsd = File.new_for_path (get_filestore_dir ());
2204 if (!fsd.query_exists ())
2205 DirUtils.create_with_parents (get_filestore_dir (), -1);
2206 file_store = new FileStore (this);
2207-
2208- /* Read database version if existant, saved actual version otherwise.
2209- * This may be used in future to perform one-time upgrade of the database */
2210- var version_db_file = Path.build_filename (local_config_directory,
2211- ".clinica_db_version");
2212-
2213- if (!FileUtils.test (version_db_file, FileTest.IS_REGULAR)) {
2214- /* Create the file with the version of the database */
2215- try {
2216- FileUtils.set_contents(version_db_file, db_version);
2217- } catch (Error e) {
2218- error (_("Error creating some configuration files, check permission on %s".printf(version_db_file)));
2219- }
2220- }
2221- else {
2222- string content;
2223- try {
2224- FileUtils.get_contents(version_db_file, out content);
2225- } catch (Error e) {
2226- error (_("Error reading some configuration files, check permission on %s".printf(version_db_file)));
2227- }
2228-
2229- bool upgraded_correcty = true;
2230- if (db_version != content) {
2231- /* Ask the user if he really wants to upgrade */
2232- if (!ask_for_upgrade()) {
2233- debug ("The user doesn't want to upgrade, exiting.");
2234- Posix.exit (0);
2235- }
2236-
2237- upgraded_correcty = false;
2238- /* Try to determine if the version of the local database is supported */
2239- if (content in supported_db_versions) {
2240- if (upgrade_database (content)) {
2241- upgraded_correcty = true;
2242- try {
2243- FileUtils.set_contents (version_db_file, db_version);
2244- } catch (GLib.Error e) {
2245- error (_("Failure while settings new database version to %s").printf (db_version));
2246- }
2247- } else {
2248- error (_("Failure while upgrading database"));
2249- }
2250- }
2251- else
2252- error (_("Version of the database is not compatible"));
2253- }
2254-
2255- if (!upgraded_correcty) {
2256- debug ("Upgrade failed, exiting.");
2257- Posix.exit (1);
2258- }
2259- }
2260
2261 /* Find prefix */
2262 prefix = "/usr/local";
2263@@ -312,6 +259,11 @@
2264 /* Create configuration */
2265 settings = new Settings (this);
2266
2267+ /* SqliteDataProvider must always be the first DataProvider
2268+ * in the list */
2269+ data_providers = new List<unowned DataProvider> ();
2270+ register_data_provider (new SqliteDataProvider (this));
2271+
2272 /* Load all extensions found... this is quite ugly, but an
2273 * interface to select loaded plugins is still needed.
2274 * For now, do it in the idle cycle to allow clinica to start
2275@@ -320,64 +272,14 @@
2276 load_plugins.begin ();
2277 }
2278
2279- private bool ask_for_upgrade () {
2280- var mb = new MessageDialog (null,
2281- DialogFlags.DESTROY_WITH_PARENT |
2282- DialogFlags.MODAL,
2283- MessageType.QUESTION,
2284- ButtonsType.YES_NO,
2285- "%s", "Database upgrade");
2286- 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"));
2287- mb.set_title (_("Upgrade database"));
2288- if (mb.run () == ResponseType.YES) {
2289- mb.destroy ();
2290- return true;
2291- }
2292- else {
2293- mb.destroy ();
2294- return false;
2295- }
2296- }
2297-
2298- /**
2299- * @brief Check if the database is in the right path. If it is not there
2300- * move it and the set database_path.
2301- */
2302- private void check_database_path () {
2303- database_path = Path.build_filename (local_data_directory,
2304- "clinica.db");
2305- File db_file = File.new_for_path (database_path);
2306- if (!db_file.query_exists ()) {
2307- File old_db_file = File.new_for_path (Path.build_filename (local_config_directory,
2308- "clinica.db"));
2309- if (old_db_file.query_exists ()) {
2310-
2311- var mb = new MessageDialog (null, DialogFlags.DESTROY_WITH_PARENT | DialogFlags.MODAL,
2312- MessageType.QUESTION, ButtonsType.YES_NO, "%s", _("Database needs to be moved"));
2313- mb.format_secondary_markup (_("An older version of clinica has been detected and the old database has to be moved\nto a new location to continue.\n<b>The older version of clinica won't work anymore with this setup</b>.\nDo you still want to continue?"));
2314- if (mb.run () != Gtk.ResponseType.YES) {
2315- mb.destroy ();
2316- Posix.exit (1);
2317- }
2318-
2319- mb.destroy ();
2320-
2321- debug ("Moving old database to its new location (starting from clinica 0.2.9)");
2322- try {
2323- old_db_file.copy (db_file, FileCopyFlags.ALL_METADATA);
2324- FileUtils.remove (old_db_file.get_path ());
2325- } catch (GLib.Error e) {
2326- error (_("Error while transferring the database to the new default location for clinica >= 0.2.9"));
2327- }
2328- }
2329- }
2330- }
2331+ private extern Peas.ExtensionSet setup_extension_set (PluginEngine engine);
2332
2333 /**
2334 * @brief Instantiate the plugin engine and load
2335 * all the plugins present in the directory
2336 */
2337 public async void load_plugins () {
2338+
2339 /* Setup plugin engine */
2340 plugin_engine = new PluginEngine (this);
2341 plugin_engine.enable_loader ("python");
2342@@ -396,6 +298,34 @@
2343 debug ("Plugin %s found but disabled".printf (info.get_name ()));
2344 }
2345 }
2346+
2347+ /* Setup the CoreActivatable extension set, so new DataProviders will be available */
2348+ core_set = setup_extension_set (plugin_engine);
2349+
2350+ /* Create the store that will be attached to the data provider selected
2351+ * above */
2352+ doctor_list_store = new DoctorListStore (this);
2353+ patient_list_store = new PatientListStore (this);
2354+ visit_list_store = new VisitListStore (this);
2355+ event_list_store = new EventListStore (this);
2356+ }
2357+
2358+ public void register_data_provider (DataProvider provider) {
2359+ data_providers.append (provider);
2360+ data_provider_added (provider);
2361+
2362+ if (data_provider == null)
2363+ data_provider = provider;
2364+
2365+ if (provider.get_name () == settings.get_string ("data-provider"))
2366+ data_provider = provider;
2367+ }
2368+
2369+ public void unregister_data_provider (DataProvider provider) {
2370+ if (provider == data_provider) {
2371+ data_provider = data_providers.nth_data (0);
2372+ settings.set_string ("data-provider", "");
2373+ }
2374 }
2375
2376 public void register_medicine_search_engine (MedicineSearchEngine engine) {
2377@@ -440,6 +370,10 @@
2378 }
2379 }
2380
2381+ public string get_data_path () {
2382+ return local_data_directory;
2383+ }
2384+
2385 /**
2386 * @brief Get the directory in which the FileStore can store its files.
2387 */
2388@@ -447,109 +381,6 @@
2389 return Path.build_filename (local_data_directory, "filestore");
2390 }
2391
2392- private bool upgrade_database (string db_version) {
2393- /* Try to open the database first */
2394- if (!(Database.open (database_path, out db) == OK)) {
2395- error (_("Error upgrading database, please check your installation"));
2396- }
2397-
2398- string sql;
2399- Statement stmt;
2400- int rc;
2401-
2402- /* Performing upgrade from 0.1 */
2403- if (db_version == "0.1") {
2404- /* We need to create the new table for the events */
2405- sql = "CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY, title TEXT, description TEXT, venue TEXT, patient INTEGER, visit INTEGER, date TEXT);";
2406- db.prepare (sql, -1, out stmt, null);
2407- rc = stmt.step ();
2408-
2409- if (rc != DONE) {
2410- error (_("Error upgrading the database from version 0.1 to 0.2, sqlite exit code: %d".printf (rc)));
2411- return false;
2412- } else {
2413- db_version = "0.2";
2414- }
2415- }
2416-
2417- return true;
2418- }
2419-
2420- /**
2421- * @brief Check that all the resources needed by Clinica
2422- * are actually available, and if they are not create them.
2423- */
2424- public void initResources () {
2425- int rc;
2426- Statement stmt;
2427- string sql;
2428-
2429- /* Open database and, if it does not exists, create it */
2430- if (!(Database.open (database_path, out db) == OK)) {
2431- error ("Error opening database.");
2432- };
2433-
2434- /* Check if the required tables exists */
2435- sql = "SELECT * from sqlite_master WHERE type='table';";
2436- db.prepare (sql, -1, out stmt, null);
2437- rc = stmt.step ();
2438-
2439- if (rc == DONE) {
2440- /* That means no tables in the database */
2441- initDatabase ();
2442- }
2443-
2444- /* Load stores */
2445- doctor_list_store = new DoctorListStore (this);
2446- patient_list_store = new PatientListStore (this);
2447- visit_list_store = new VisitListStore (this);
2448- event_list_store = new EventListStore (this);
2449- }
2450-
2451-
2452- /**
2453- * @brief Init the database with the required tables
2454- */
2455- private void initDatabase () {
2456- Statement stmt;
2457- string sql;
2458- string err_msg;
2459-
2460- /* Create config table */
2461- sql = "CREATE TABLE config (id INTEGER PRIMARY KEY, " +
2462- "key TEXT, value TEXT);";
2463- db.prepare (sql, -1, out stmt, null);
2464- if (!(stmt.step () == DONE)) {
2465- err_msg = db.errmsg ();
2466- error ("Error creating config structure in the Database: "
2467- + err_msg);
2468- }
2469- }
2470-
2471- /**
2472- * @brief Return a Doctor object associated to the given ID
2473- */
2474- public Doctor getDoctor (int ID) {
2475- Doctor doctor = new Doctor.with_id (this, ID);
2476- return doctor;
2477- }
2478-
2479- /**
2480- * @brief Return a Patient object associated to the given ID
2481- */
2482- public Patient getPatient (int ID) {
2483- Patient p = new Patient.with_id (this, ID);
2484- return p;
2485- }
2486-
2487- /**
2488- * @brief Return a Visit object associated to the given ID
2489- */
2490- public Visit getVisit (int ID) {
2491- Visit visit = new Visit.with_id (this, ID);
2492- return visit;
2493- }
2494-
2495
2496 }
2497
2498
2499=== modified file 'libclinica/Service.vala'
2500--- libclinica/Service.vala 2012-01-26 17:41:05 +0000
2501+++ libclinica/Service.vala 2012-02-23 21:39:18 +0000
2502@@ -39,12 +39,12 @@
2503 * @brief Return a lists of patients id whose name
2504 * match the given string.
2505 */
2506- public int [] patients_filter (string filter) {
2507+ public int64 [] patients_filter (string filter) {
2508 string lfilter = filter.down();
2509- int [] patients = {};
2510- foreach (var patient in Patient.all (resource_manager)) {
2511+ int64 [] patients = {};
2512+ foreach (var patient in resource_manager.data_provider.patients ()) {
2513 if (lfilter in patient.get_complete_name ().down ()) {
2514- patients += patient.get_id ();
2515+ patients += patient.id;
2516 }
2517 }
2518
2519
2520=== modified file 'libclinica/SettingsManager.vala'
2521--- libclinica/SettingsManager.vala 2012-01-29 10:39:56 +0000
2522+++ libclinica/SettingsManager.vala 2012-02-23 21:39:18 +0000
2523@@ -69,6 +69,9 @@
2524 var mse_selector = new MedicineSearchEngineSelector (resource_manager);
2525 structure_vbox.pack_start (mse_selector, false);
2526
2527+ var dp_selector = new DataProviderSelector (resource_manager);
2528+ structure_vbox.pack_start (dp_selector, false);
2529+
2530 /* Add structure vbox to the first page of the Notebook */
2531 var sv_alignment = new Alignment (0.5F, 0.5F, 1.0F, 1.0F);
2532 sv_alignment.set_padding (6,6,6,6);
2533@@ -166,4 +169,65 @@
2534 }
2535 }
2536 }
2537+
2538+
2539+ public class DataProviderSelector : HBox {
2540+
2541+ private ResourceManager resource_manager { get; set; }
2542+ private ComboBoxText data_provider_selector;
2543+
2544+ public DataProviderSelector (ResourceManager resources) {
2545+ GLib.Object (homogeneous: false, spacing: 6);
2546+ resource_manager = resources;
2547+ var label = new Label (_("Select the data provider\nused to retrieve data"));
2548+ label.set_alignment (0.0F, 0.5F);
2549+ pack_start (label);
2550+
2551+ /* Create the combobox and keep a track of its position in the array. */
2552+ data_provider_selector = new ComboBoxText ();
2553+ refresh_provider_list ();
2554+ resource_manager.data_provider_added.connect ((provider) => refresh_provider_list ());
2555+ resource_manager.data_provider_removed.connect ((provider) => refresh_provider_list ());
2556+ pack_start (data_provider_selector, false, true);
2557+ data_provider_selector.changed.connect (on_data_provider_selector_changed);
2558+ }
2559+
2560+ private void on_data_provider_selector_changed () {
2561+ string? active_id = data_provider_selector.get_active_id ();
2562+ if (active_id == null)
2563+ return;
2564+ var index = int.parse (active_id);
2565+ resource_manager.data_provider =
2566+ resource_manager.data_providers.nth_data (index);
2567+ resource_manager.settings.set_string ("data-provider",
2568+ resource_manager.data_provider.get_name ());
2569+ }
2570+
2571+ private void refresh_provider_list () {
2572+ int i = 0;
2573+ data_provider_selector.remove_all ();
2574+
2575+ /* If no preference is set set the first engine as selected */
2576+ if (resource_manager.settings.get_string ("data-provider") == "") {
2577+ if (resource_manager.data_providers.length () != 0) {
2578+ resource_manager.data_provider =
2579+ resource_manager.data_providers.nth_data (0);
2580+ resource_manager.settings.set_string ("data-provider",
2581+ resource_manager.data_provider.get_name ());
2582+ }
2583+ }
2584+
2585+ /* Load engines in the liststore */
2586+ foreach (var provider in resource_manager.data_providers) {
2587+ data_provider_selector.append ("%d".printf (i++), provider.get_name ());
2588+ if (resource_manager.settings.get_string ("data-provider") == provider.get_name ()) {
2589+ debug ("Loading data provider: %s", provider.get_name ());
2590+ resource_manager.data_provider = provider;
2591+ }
2592+ if (provider == resource_manager.data_provider) {
2593+ data_provider_selector.set_active (i - 1);
2594+ }
2595+ }
2596+ }
2597+ }
2598 }
2599
2600=== removed file 'libclinica/SqlDataType.vala'
2601--- libclinica/SqlDataType.vala 2011-10-04 12:15:09 +0000
2602+++ libclinica/SqlDataType.vala 1970-01-01 00:00:00 +0000
2603@@ -1,397 +0,0 @@
2604-/*
2605- * This file is part of Clinica.
2606- *
2607- * Clinica is free software: you can redistribute it and/or modify
2608- * it under the terms of the GNU General Public License as published by
2609- * the Free Software Foundation, either version 3 of the License, or
2610- * (at your option) any later version.
2611- *
2612- * Clinica is distributed in the hope that it will be useful,
2613- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2614- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2615- * GNU General Public License for more details.
2616- *
2617- * You should have received a copy of the GNU General Public License
2618- * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
2619- *
2620- * Authors: Leonardo Robol <leo@robol.it>
2621- * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it>
2622- */
2623-
2624-using Sqlite;
2625-using Gee;
2626-
2627-namespace Clinica {
2628-
2629- /**
2630- * @brief Struct representing a column in the database.
2631- */
2632- public class SqlColumn {
2633- public string type;
2634- public string v;
2635-
2636- public SqlColumn (string type) {
2637- this.type = type;
2638- }
2639- }
2640-
2641- public class SqlDataIterator : GLib.Object {
2642-
2643- protected unowned Database db;
2644- protected Statement stmt;
2645-
2646- public SqlDataIterator (Database db, string table_name, string? order_by = null, bool desc = false) {
2647- this.db = db;
2648- if (order_by == null)
2649- db.prepare (@"SELECT ID FROM $(table_name);", -1, out stmt, null);
2650- else {
2651- if (desc)
2652- db.prepare (@"SELECT ID FROM $(table_name) ORDER by $(order_by) DESC;", -1, out stmt, null);
2653- else
2654- db.prepare (@"SELECT ID FROM $(table_name) ORDER by $(order_by);", -1, out stmt, null);
2655- }
2656- }
2657-
2658- public SqlDataIterator.with_like (Database db, string table_name, string? order_by = null,
2659- bool desc = false, string where_stmt) {
2660- this.db = db;
2661-
2662- if (order_by == null)
2663- db.prepare (@"SELECT ID FROM $(table_name) WHERE $(where_stmt);", -1, out stmt, null);
2664- else {
2665- if (desc)
2666- db.prepare (@"SELECT ID FROM $(table_name) WHERE $(where_stmt) ORDER by $(order_by) DESC;", -1, out stmt, null);
2667- else
2668- db.prepare (@"SELECT ID FROM $(table_name) WHERE $(where_stmt) ORDER by $(order_by);", -1, out stmt, null);
2669- }
2670- }
2671-
2672- public SqlDataIterator iterator () {
2673- return this;
2674- }
2675-
2676- public bool next () {
2677- return (stmt.step () == ROW);
2678- }
2679-
2680- public new int get () {
2681- return stmt.column_int (0);
2682- }
2683- }
2684-
2685- /**
2686- * @brief Interface representing an abstract data
2687- * type interfaced to a SQLite database.
2688- */
2689- public class SqlDataType : GLib.Object {
2690-
2691- /**
2692- * @brief Signal emitted when an error eris
2693- * encountered
2694- */
2695- public signal void error (string message);
2696-
2697- /**
2698- * @brief The table name in the database. Must be set
2699- * by the class implementing this interface.
2700- */
2701- public string table_name;
2702-
2703- /**
2704- * @brief The database object used to interact with
2705- * the sqlite database. It must be opened by the
2706- * class implementing this interface.
2707- */
2708- public unowned Database db;
2709-
2710- /**
2711- * @brief Hash mapping column_name -> type, value.
2712- */
2713- public HashMap<string, SqlColumn?> columns;
2714-
2715- public SqlDataType (Database db) {
2716- this.db = db;
2717- columns = new HashMap<string, SqlColumn> ();
2718- this.columns.set ("ID", new SqlColumn ("INTEGER PRIMARY KEY"));
2719- set_integer ("ID", 0);
2720- }
2721-
2722- public SqlDataType.with_id (Database db, int ID) {
2723- this (db);
2724- load (ID);
2725- }
2726-
2727- protected void add_text_field (string name) {
2728- this.columns.set (name, new SqlColumn ("TEXT"));
2729- }
2730-
2731- protected void add_integer_field (string name) {
2732- this.columns.set (name, new SqlColumn ("INTEGER"));
2733- }
2734-
2735- protected void add_date_field (string name) {
2736- this.columns.set (name, new SqlColumn ("TEXT"));
2737- }
2738-
2739- /**
2740- * @brief Escape a string and surround it with
2741- * double quotes ready to be inserted in the
2742- * database.
2743- */
2744- protected string quote (string str) {
2745- return "\"" + str.escape ("") + "\"";
2746- }
2747-
2748- /**
2749- * @brief Initialize resource, i.e. open the database
2750- * and check for missing tables.
2751- */
2752- protected void init_resources () {
2753- lock (db) {
2754- Statement stmt;
2755-
2756- /* Check if the table is present in the database and if it's
2757- * not, create it */
2758- db.prepare (@"SELECT * from sqlite_master WHERE name='$(table_name)';",
2759- -1, out stmt, null);
2760-
2761- if (stmt.step () == DONE) {
2762- init_database ();
2763- }
2764- }
2765- }
2766-
2767- /**
2768- * @brief Create table structure in the database.
2769- */
2770- protected void init_database () {
2771- Statement stmt;
2772- string sql = @"CREATE TABLE $(table_name) (";
2773- foreach (Map.Entry<string, SqlColumn> e in columns.entries) {
2774- sql += @"$(e.key) $(e.value.type), ";
2775- }
2776-
2777- /* Remove last 2 characters ", " and add ); */
2778- sql = sql[0:-2];
2779- sql += ");";
2780-
2781- /* Execute query */
2782- db.prepare (sql, -1, out stmt, null);
2783-
2784- if (stmt.step () != DONE) {
2785- error (@"Error creating $(table_name) table in the database.");
2786- }
2787- }
2788-
2789- public string get_db_table_name () {
2790- return this.table_name;
2791- }
2792-
2793- public void set_text (string field, string val) {
2794- if (!columns.has_key (field)) {
2795- error (@"Error saving to field $(field) from table $(table_name)\n" +
2796- "Selected field is not present in database");
2797- return;
2798- }
2799- SqlColumn col = columns.get (field);
2800- col.v = val;
2801- columns.set (field, col);
2802- }
2803-
2804- public unowned string get_text (string field) {
2805- if (!columns.has_key (field)) {
2806- error (@"Error loading from field $(field) from table $(table_name)\n" +
2807- "Selected field is not present in database");
2808- return "";
2809- }
2810- SqlColumn col = columns.get (field);
2811- if (col.v != null)
2812- return col.v;
2813- else
2814- return "";
2815- }
2816-
2817- public unowned int get_integer (string field) {
2818- if (!columns.has_key (field)) {
2819- error (@"Error loading from field $(field) from table $(table_name)\n" +
2820- "Selected field is not present in database");
2821- return 0;
2822- }
2823- SqlColumn col = columns.get (field);
2824- return int.parse (col.v);
2825- }
2826-
2827- public DateTime get_date (string field) {
2828- if (!columns.has_key (field)) {
2829- error (@"Error loading from field $(field) from table $(table_name)\n" +
2830- "Selected field is not present in database");
2831- return new DateTime.now_utc ();
2832- }
2833- SqlColumn col = columns.get (field);
2834- string [] fields = col.v.split(" ");
2835-
2836- int year = int.parse (fields[0]);
2837- int month = int.parse (fields[1]);
2838- int day = int.parse (fields[2]);
2839- int hour = int.parse (fields[3]);
2840- int minute = int.parse (fields[4]);
2841- int seconds = int.parse (fields[5]);
2842-
2843- if (year < 1 || year > 9999 ||
2844- month < 1 || month > 12 ||
2845- day < 1 || day > 31 ||
2846- minute < 0 || minute > 59 ||
2847- seconds < 0 || seconds > 59)
2848- return new DateTime.now_local ();
2849-
2850- return new DateTime.local (year, month, day, hour, minute, seconds);
2851- }
2852-
2853- public void set_date (string field, DateTime date) {
2854- if (!columns.has_key (field)) {
2855- error (@"Error saving tofield $(field) from table $(table_name)\n" +
2856- "Selected field is not present in database");
2857- return;
2858- }
2859- SqlColumn col = columns.get (field);
2860- col.v = datetime_to_string (date);
2861- }
2862-
2863- public static string datetime_to_string (DateTime date) {
2864- return string.join(" ",
2865- date.get_year ().to_string (),
2866- "%.2d".printf (date.get_month ()),
2867- "%.2d".printf (date.get_day_of_month()),
2868- "%.2d".printf (date.get_hour ()),
2869- "%.2d".printf (date.get_minute ()),
2870- "%.2d".printf (date.get_second ()));
2871- }
2872-
2873- public int get_id () {
2874- return get_integer ("ID");
2875- }
2876-
2877- public void set_integer (string field, int64 val) {
2878- if (!columns.has_key (field)) {
2879- error (@"Error saving tofield $(field) from table $(table_name)\n" +
2880- "Selected field is not present in database");
2881- return;
2882- }
2883- SqlColumn col = columns.get (field);
2884- if (field == "ID" && val == 0)
2885- col.v = "NULL";
2886- else
2887- col.v = val.to_string ();
2888- columns.set (field, col);
2889- }
2890-
2891- public new string get (string field) {
2892- return get_text (field);
2893- }
2894-
2895- public new void set (string field, string value) {
2896- set_text (field, value);
2897- }
2898-
2899- /**
2900- * @brief Save changes permanently in the database
2901- */
2902- public void save () {
2903- Statement stmt;
2904- string sql = @"INSERT OR REPLACE INTO $(table_name) (";
2905- foreach (Map.Entry<string, SqlColumn> e in columns.entries) {
2906- sql += @"$(e.key), ";
2907- }
2908-
2909- sql = sql[0:-2];
2910- sql += ") VALUES (";
2911-
2912- foreach (Map.Entry<string, SqlColumn> e in columns.entries) {
2913- if (e.value.v != null) {
2914- if (e.value.type == "TEXT")
2915- sql += @"$(quote(e.value.v)), ";
2916- else
2917- sql += @"$(e.value.v), ";
2918- }
2919- else {
2920- sql += ", ";
2921- }
2922- }
2923-
2924- sql = sql[0:-2]; sql += ");";
2925- db.prepare (sql, -1, out stmt, null);
2926- if (stmt.step () != DONE) {
2927- error (@"Error inserting values in the database $(table_name)\n Error $(db.errcode()): $(db.errmsg ())");
2928- }
2929-
2930- /* If we save with ID set to 0 then the ID will be autodetermined
2931- * by sqlite so we should get it back */
2932- if (get_id () == 0) {
2933- set_integer("ID", db.last_insert_rowid());
2934- }
2935- }
2936-
2937- /**
2938- * @brief Load data from database, overwriting local
2939- * variables.
2940- */
2941- public void load (int ID = 0) {
2942- if (ID == 0)
2943- ID = get_integer ("ID");
2944-
2945- Statement stmt;
2946- string sql = "SELECT ";
2947- foreach (Map.Entry<string, SqlColumn> e in columns.entries) {
2948- sql += @"$(e.key), ";
2949- }
2950-
2951- sql = sql[0:-2];
2952- sql += @" FROM $(table_name) WHERE ID=$(ID);";
2953-
2954- db.prepare (sql, -1, out stmt, null);
2955- if (stmt.step () !=ROW) {
2956- error (@"Error loading data from table $(table_name).");
2957- return;
2958- }
2959-
2960- int i = 0;
2961- foreach (Map.Entry<string, SqlColumn> e in columns.entries) {
2962- if (e.value.type == "TEXT")
2963- e.value.v = stmt.column_text (i).compress ();
2964- else
2965- e.value.v = stmt.column_text (i);
2966- i++;
2967- }
2968- }
2969-
2970- /**
2971- * @brief Delete this item permanently from the database.
2972- */
2973- public void remove () {
2974- Statement stmt;
2975- string sql = @"DELETE from $(table_name) WHERE ID=$(get_id ());";
2976-
2977- db.prepare (sql, -1, out stmt, null);
2978- if (stmt.step () != DONE) {
2979- error (@"Error deleting item from the database $(table_name)");
2980- }
2981- }
2982-
2983- /**
2984- * @brief Find IDs of elements in ex_table (that is assumed to be a table
2985- * associateed to another SqlDataType object and return a vector
2986- * containing their IDs.
2987- */
2988- public GLib.List<int> associated_ids (string ex_table, string foreign_key) {
2989- var ids = new GLib.List<int> ();
2990- Statement stmt;
2991- string sql = @"SELECT ID from $(ex_table) WHERE $(foreign_key)=$(get_id());";
2992-
2993- db.prepare (sql, -1, out stmt, null);
2994- while (stmt.step () == ROW) {
2995- ids.append (stmt.column_int (0));
2996- }
2997- return ids;
2998- }
2999- }
3000-}
3001
3002=== added file 'libclinica/SqliteDataProvider.vala'
3003--- libclinica/SqliteDataProvider.vala 1970-01-01 00:00:00 +0000
3004+++ libclinica/SqliteDataProvider.vala 2012-02-23 21:39:18 +0000
3005@@ -0,0 +1,754 @@
3006+/*
3007+ * This file is part of Clinica.
3008+ *
3009+ * Clinica is free software: you can redistribute it and/or modify
3010+ * it under the terms of the GNU General Public License as published by
3011+ * the Free Software Foundation, either version 3 of the License, or
3012+ * (at your option) any later version.
3013+ *
3014+ * Clinica is distributed in the hope that it will be useful,
3015+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3016+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3017+ * GNU General Public License for more details.
3018+ *
3019+ * You should have received a copy of the GNU General Public License
3020+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
3021+ *
3022+ * Authors: Leonardo Robol <leo@robol.it>
3023+ */
3024+
3025+using Sqlite;
3026+using Gtk;
3027+
3028+namespace Clinica {
3029+
3030+ public class SqliteDataProvider : Object, DataProvider {
3031+
3032+ public signal void error (string message);
3033+
3034+ /**
3035+ * @brief Name of the table in the database where the visits
3036+ * will be stored. Please note that changing this will require
3037+ * a database upgrade, so should be handled correctly.
3038+ */
3039+ internal string visit_table = "visits";
3040+
3041+ /**
3042+ * @brief Name of the table in the database where the patients
3043+ * will be stored. Please note that changing this will require
3044+ * a database upgrade, so should be handled correctly.
3045+ */
3046+ internal string patient_table = "patients";
3047+
3048+ /**
3049+ * @brief Name of the table in the database where the doctors
3050+ * will be stored. Please note that changing this will require
3051+ * a database upgrade, so should be handled correctly.
3052+ */
3053+ internal string doctor_table = "doctors";
3054+
3055+ /**
3056+ * @brief Name of the table in the database where the events
3057+ * will be stored. Please note that changing this will require
3058+ * a database upgrade, so should be handled correctly.
3059+ */
3060+ internal string event_table = "events";
3061+
3062+ /**
3063+ * @brief The absolute path of the database (typically on Linux systems
3064+ * will be ~/.local/share/clinica/clinica.db.
3065+ */
3066+ private string database_path;
3067+
3068+ /**
3069+ * @brief The ResourceManager of this instance of the Clinica Application.
3070+ */
3071+ private ResourceManager resource_manager { get; set; }
3072+
3073+ /**
3074+ * @brief The Sqlite.Database object - this is used to interact with the database
3075+ * by the SqliteDataProvider and all the Sqlite*Iterator classes that are generated
3076+ * from here.
3077+ */
3078+ internal Database db;
3079+
3080+ /**
3081+ * @brief An array containing the supported versione of the db. This should
3082+ * contain the value db_version and means that this SqliteProvider is capable
3083+ * of Database migration from any of these old version to the most recent one.
3084+ */
3085+ private const string [] supported_db_versions = { "0.1", "0.2" };
3086+
3087+ /**
3088+ * @brief The version of the database that is in use now, or that should
3089+ * be used to compatbile with this SqliteDataProvider.
3090+ *
3091+ * Please note that Database version are not the same of Clinica versions.
3092+ * Typically the same clinica versions will use the same Database version,
3093+ * but the other way is not always true.
3094+ */
3095+ private const string db_version = "0.2";
3096+
3097+
3098+ public SqliteDataProvider (ResourceManager resources) {
3099+ resource_manager = resources;
3100+ error.connect ((t,l) => resource_manager.error_callback (t,l));
3101+
3102+ /* Find the database in all the possible paths for the various
3103+ * versions of Clinica, and then possibly do un upgrade, querying
3104+ * the user if necessary. */
3105+ check_database_path ();
3106+ check_updates ();
3107+
3108+ /* This is used to create the tables if they do not exists */
3109+ init_resources ();
3110+ }
3111+
3112+ /**
3113+ * @brief Get the identifier for this DataProvider to be displayed
3114+ * to the user.
3115+ *
3116+ * It has not to be translated since it will be used to detect which
3117+ * will be used on startup.
3118+ */
3119+ public string get_name () { return "Local database"; }
3120+
3121+ /**
3122+ * @brief Check if there is the need to upgrade the database from on of
3123+ * the supported version to the most recent one.
3124+ */
3125+ private void check_updates () {
3126+ /* Read database version if existant, saved actual version otherwise.
3127+ * This may be used in future to perform one-time upgrade of the database */
3128+ var version_db_file = Path.build_filename (resource_manager.local_config_directory,
3129+ ".clinica_db_version");
3130+
3131+ if (!FileUtils.test (version_db_file, FileTest.IS_REGULAR)) {
3132+ /* Create the file with the version of the database */
3133+ try {
3134+ FileUtils.set_contents(version_db_file, db_version);
3135+ } catch (Error e) {
3136+ error (_("Error creating some configuration files, check permission on %s").printf (version_db_file));
3137+ }
3138+ }
3139+ else {
3140+ string content;
3141+ try {
3142+ FileUtils.get_contents(version_db_file, out content);
3143+ } catch (Error e) {
3144+ error (_("Error reading some configuration files, check permission on %s".printf(version_db_file)));
3145+ }
3146+
3147+ bool upgraded_correcty = true;
3148+ if (db_version != content) {
3149+ /* Ask the user if he really wants to upgrade */
3150+ if (!ask_for_upgrade()) {
3151+ debug ("The user doesn't want to upgrade, exiting.");
3152+ Posix.exit (0);
3153+ }
3154+
3155+ upgraded_correcty = false;
3156+ /* Try to determine if the version of the local database is supported */
3157+ if (content in supported_db_versions) {
3158+ if (upgrade_database (content)) {
3159+ upgraded_correcty = true;
3160+ try {
3161+ FileUtils.set_contents (version_db_file, db_version);
3162+ } catch (GLib.Error e) {
3163+ error (_("Failure while settings new database version to %s").printf (db_version));
3164+ }
3165+ } else {
3166+ error (_("Failure while upgrading database"));
3167+ }
3168+ }
3169+ else
3170+ error (_("Version of the database is not compatible"));
3171+ }
3172+
3173+ if (!upgraded_correcty) {
3174+ debug ("Upgrade failed, exiting.");
3175+ Posix.exit (1);
3176+ }
3177+ }
3178+ }
3179+
3180+ /**
3181+ * @brief This routine is used to ask confirmation to the user for the database
3182+ * upgrade. Since the upgrade will make the older version of clinica unusable, we
3183+ * should always ask before performing one.
3184+ */
3185+ private bool ask_for_upgrade () {
3186+ var mb = new MessageDialog (null,
3187+ DialogFlags.DESTROY_WITH_PARENT |
3188+ DialogFlags.MODAL,
3189+ MessageType.QUESTION,
3190+ ButtonsType.YES_NO,
3191+ "%s", "Database upgrade");
3192+ 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"));
3193+ mb.set_title (_("Upgrade database"));
3194+ if (mb.run () == ResponseType.YES) {
3195+ mb.destroy ();
3196+ return true;
3197+ }
3198+ else {
3199+ mb.destroy ();
3200+ return false;
3201+ }
3202+ }
3203+
3204+ /**
3205+ * @brief Check if the database is in the right path. If it is not there
3206+ * move it and the set database_path.
3207+ */
3208+ private void check_database_path () {
3209+ database_path = Path.build_filename (resource_manager.local_data_directory,
3210+ "clinica.db");
3211+ File db_file = File.new_for_path (database_path);
3212+ if (!db_file.query_exists ()) {
3213+ File old_db_file = File.new_for_path (Path.build_filename (resource_manager.local_config_directory,
3214+ "clinica.db"));
3215+ if (old_db_file.query_exists ()) {
3216+
3217+ var mb = new MessageDialog (null, DialogFlags.DESTROY_WITH_PARENT | DialogFlags.MODAL,
3218+ MessageType.QUESTION, ButtonsType.YES_NO, "%s", _("Database needs to be moved"));
3219+ mb.format_secondary_markup (_("An older version of clinica has been detected and the old database has to be moved\nto a new location to continue.\n<b>The older version of clinica won't work anymore with this setup</b>.\nDo you still want to continue?"));
3220+ if (mb.run () != Gtk.ResponseType.YES) {
3221+ mb.destroy ();
3222+ Posix.exit (1);
3223+ }
3224+
3225+ mb.destroy ();
3226+
3227+ debug ("Moving old database to its new location (starting from clinica 0.2.9)");
3228+ try {
3229+ old_db_file.copy (db_file, FileCopyFlags.ALL_METADATA);
3230+ FileUtils.remove (old_db_file.get_path ());
3231+ } catch (GLib.Error e) {
3232+ error (_("Error while transferring the database to the new default location for clinica >= 0.2.9"));
3233+ }
3234+ }
3235+ }
3236+ }
3237+
3238+ /**
3239+ * @brief Do upgrade the database starting from db_version.
3240+ */
3241+ private bool upgrade_database (string db_version) {
3242+ /* Try to open the database first */
3243+ if (!(Database.open (database_path, out db) == OK)) {
3244+ error (_("Error upgrading database, please check your installation"));
3245+ }
3246+
3247+ string sql;
3248+ Statement stmt;
3249+ int64 rc;
3250+
3251+ /* Performing upgrade from 0.1 */
3252+ if (db_version == "0.1") {
3253+ /* We need to create the new table for the events */
3254+ sql = "CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY, title TEXT, description TEXT, venue TEXT, patient INTEGER, visit INTEGER, date TEXT);";
3255+ db.prepare (sql, -1, out stmt, null);
3256+ rc = stmt.step ();
3257+
3258+ if (rc != DONE) {
3259+ error (_("Error upgrading the database from version 0.1 to 0.2, sqlite exit code: %I64d".printf (rc)));
3260+ return false;
3261+ } else {
3262+ db_version = "0.2";
3263+ }
3264+ }
3265+
3266+ return true;
3267+ }
3268+
3269+ /**
3270+ * @brief Check that all the resources needed by Clinica
3271+ * are actually available, and if they are not create them.
3272+ */
3273+ public void init_resources () {
3274+ int64 rc;
3275+ Statement stmt;
3276+ string sql;
3277+
3278+ /* Open database and, if it does not exists, create it */
3279+ if (!(Database.open (database_path, out db) == OK)) {
3280+ error ("Error opening database.");
3281+ };
3282+
3283+ /* Check if the required tables exists */
3284+ sql = "SELECT * from sqlite_master WHERE type='table';";
3285+ db.prepare (sql, -1, out stmt, null);
3286+ rc = stmt.step ();
3287+
3288+ if (rc == DONE) {
3289+ /* That means no tables in the database */
3290+ init_database ();
3291+ }
3292+ }
3293+
3294+
3295+ /**
3296+ * @brief Init the database with the required tables
3297+ */
3298+ private void init_database () {
3299+
3300+ if (db.exec ("CREATE TABLE IF NOT EXISTS doctors (surname TEXT, ID INTEGER PRIMARY KEY, phone TEXT, mobile TEXT, given_name TEXT)") != 0)
3301+ error ("Error creating the doctors table");
3302+ if (db.exec ("CREATE TABLE IF NOT EXISTS patients (gender TEXT, doctor INTEGER, surname TEXT, ID INTEGER PRIMARY KEY, identification_code TEXT, phone TEXT, given_name TEXT, birth_date TEXT, residence_address TEXT)") != 0)
3303+ error ("Error creating the patients table");
3304+ if (db.exec ("CREATE TABLE IF NOT EXISTS visits (subsequent_checks TEXT, systemic_therapy TEXT, ID INTEGER PRIMARY KEY, laboratory_exam TEXT, diagnosis TEXT, histopathology TEXT, anamnesis TEXT, date TEXT, patient INTEGER, physical_examination TEXT, topical_therapy TEXT)") != 0)
3305+ error ("Error creating the visits table");
3306+ if (db.exec ("CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY, title TEXT, description TEXT, venue TEXT, patient INTEGER, visit INTEGER, date TEXT)") != 0)
3307+ error ("Error creating the events table");
3308+
3309+ }
3310+
3311+ /**
3312+ * @brief Internal routine used to convert DateTime objects
3313+ * to strings that are to be saved in the database.
3314+ */
3315+ private static string datetime_to_string (DateTime date) {
3316+ return string.join(" ",
3317+ date.get_year ().to_string (),
3318+ "%.2d".printf (date.get_month ()),
3319+ "%.2d".printf (date.get_day_of_month()),
3320+ "%.2d".printf (date.get_hour ()),
3321+ "%.2d".printf (date.get_minute ()),
3322+ "%.2d".printf (date.get_second ()));
3323+ }
3324+
3325+ /**
3326+ * @brief Convert strings encoded with datetime_to_string () back
3327+ * to DateTime objects.
3328+ */
3329+ private static DateTime string_to_datetime (string input) {
3330+ string [] fields = input.split(" ");
3331+
3332+ int year = int.parse (fields[0]);
3333+ int month = int.parse (fields[1]);
3334+ int day = int.parse (fields[2]);
3335+ int hour = int.parse (fields[3]);
3336+ int minute = int.parse (fields[4]);
3337+ int seconds = int.parse (fields[5]);
3338+
3339+ if (year < 1 || year > 9999 ||
3340+ month < 1 || month > 12 ||
3341+ day < 1 || day > 31 ||
3342+ minute < 0 || minute > 59 ||
3343+ seconds < 0 || seconds > 59)
3344+ return new DateTime.now_local ();
3345+
3346+ return new DateTime.local (year, month, day, hour, minute, seconds);
3347+ }
3348+
3349+ /* IMPLEMENTATION OF THE ABSTRACT INTERFACES OF DataProvider */
3350+
3351+ public Doctor get_doctor (int64 id) {
3352+ var doc = new Doctor ();
3353+ Statement stmt;
3354+ db.prepare (@"SELECT given_name, surname, phone, mobile FROM $(doctor_table) WHERE id=$(id);", -1,
3355+ out stmt, null);
3356+ if (!(stmt.step () == ROW)) {
3357+ error (_("Error while retrieving the doctor with id = %I64d").printf (id, db.errmsg ()));
3358+ }
3359+
3360+ /* Load data from the database into the fields */
3361+ doc.id = id;
3362+ doc.given_name = stmt.column_text (0).compress ();
3363+ doc.surname = stmt.column_text (1).compress ();
3364+ doc.phone = stmt.column_text (2).compress ();
3365+ doc.mobile = stmt.column_text (3).compress ();
3366+
3367+ doc.provider = this;
3368+
3369+ return doc;
3370+ }
3371+
3372+ public int64 save_doctor (Doctor doctor) {
3373+ Statement stmt;
3374+
3375+ if (doctor.id != 0)
3376+ db.prepare ("""INSERT OR REPLACE INTO %s (id, given_name, surname, phone, mobile)
3377+ VALUES (:id, :given_name, :surname, :phone, :mobile);""".printf (doctor_table),
3378+ -1, out stmt);
3379+ else
3380+ db.prepare ("""INSERT OR REPLACE INTO %s (given_name, surname, phone, mobile)
3381+ VALUES (:given_name, :surname, :phone, :mobile);""".printf (doctor_table),
3382+ -1, out stmt);
3383+
3384+
3385+
3386+ /* Bind values present in doctor in the SQL statement */
3387+ int i = 1;
3388+ if (doctor.id != 0)
3389+ stmt.bind_int64 (i++, doctor.id);
3390+ stmt.bind_text (i++, doctor.given_name);
3391+ stmt.bind_text (i++, doctor.surname);
3392+ stmt.bind_text (i++, doctor.phone);
3393+ stmt.bind_text (i++, doctor.mobile);
3394+
3395+ if (stmt.step () != DONE) {
3396+ error (_("An error occurred while saving the doctor with id %d: %s").printf (doctor.id, db.errmsg ()));
3397+ return -1;
3398+ }
3399+
3400+ if (doctor.id == 0) {
3401+ doctor.id = db.last_insert_rowid ();
3402+ doctor_added (doctor.id);
3403+ }
3404+ else
3405+ doctor_changed (doctor.id);
3406+
3407+ return doctor.id;
3408+ }
3409+
3410+ public int64 remove_doctor (Doctor doctor) {
3411+ Statement stmt;
3412+
3413+ /* Keep a list of the patient ID we need to notify */
3414+ var patients = new List<int64?> ();
3415+ foreach (var patient in doctor.patients ()) {
3416+ patients.append (patient.id);
3417+ }
3418+
3419+ /* Wrap all this in a transaction so the DB doesn't change until
3420+ * we commit */
3421+ db.exec ("BEGIN TRANSACTION");
3422+
3423+ string sql = @"DELETE from $(doctor_table) WHERE ID=$(doctor.id);";
3424+
3425+ db.prepare (sql, -1, out stmt, null);
3426+ if (stmt.step () != DONE) {
3427+ error (@"Error deleting doctor with id $(doctor.id)");
3428+ db.exec ("ROLLBACK TRANSACTION");
3429+ return -1;
3430+ }
3431+
3432+ /* Now we need to deassociate its patients from him/her */
3433+ if (db.exec (@"UPDATE $(patient_table) SET doctor = 0 WHERE doctor = $(doctor.id);") != 0) {
3434+ error (@"Error deassociating the patients from the doctor with ID = $(doctor.id)");
3435+ db.exec ("ROLLBACK TRANSACTION");
3436+ return -1;
3437+ }
3438+
3439+ db.exec ("COMMIT TRANSACTION");
3440+
3441+ doctor_removed (doctor.id);
3442+
3443+ /* Notify changes on the patients */
3444+ foreach (var patient_id in patients) {
3445+ patient_changed (patient_id);
3446+ }
3447+ return 0;
3448+ }
3449+
3450+ public PatientIterator patients (Doctor? doctor = null) {
3451+ return new SqlitePatientIterator (this, (doctor == null) ? "" : @"WHERE doctor = $(doctor.id)");
3452+ }
3453+
3454+ public DoctorIterator doctors () {
3455+ return new SqliteDoctorIterator (this);
3456+ }
3457+
3458+ public Patient get_patient (int64 id) {
3459+ var patient = new Patient ();
3460+ Statement stmt;
3461+ db.prepare ("""SELECT given_name, surname, birth_date, gender, phone, residence_address,
3462+ identification_code, doctor FROM %s WHERE id=%I64d;""".printf (patient_table, id),
3463+ -1, out stmt, null);
3464+ if (!(stmt.step () == ROW)) {
3465+ error (_("Error while retrieving the patient with id = %I64d").printf (id, db.errmsg ()));
3466+ }
3467+
3468+ /* Load data from the database into the fields */
3469+ patient.id = id;
3470+ patient.given_name = stmt.column_text (0).compress ();
3471+ patient.surname = stmt.column_text (1).compress ();
3472+ patient.birth_date = string_to_datetime (stmt.column_text (2).compress ());
3473+ patient.gender = (stmt.column_text (3) == "MALE") ? Gender.MALE : Gender.FEMALE;
3474+ patient.phone = stmt.column_text (4).compress ();
3475+ patient.residence_address = stmt.column_text (5).compress ();
3476+ patient.identification_code = stmt.column_text (6).compress ();
3477+ patient.doctor = (stmt.column_int64 (7) == 0) ? null : get_doctor (stmt.column_int64 (7));
3478+
3479+ patient.provider = this;
3480+
3481+ return patient;
3482+ }
3483+
3484+ public int64 save_patient (Patient patient) {
3485+ Statement stmt;
3486+
3487+ if (patient.id != 0)
3488+ db.prepare ("""INSERT OR REPLACE INTO %s
3489+ (ID, given_name, surname, birth_date, gender, phone, residence_address, identification_code, doctor)
3490+ VALUES (:id, :given_name, :surname, :birth_date, :gender, :phone, :residence_address, :identification_code, :doctor);""".printf (patient_table),
3491+ -1, out stmt);
3492+ else
3493+ db.prepare ("""INSERT OR REPLACE INTO %s
3494+ (given_name, surname, birth_date, gender, phone, residence_address, identification_code, doctor)
3495+ VALUES (:given_name, :surname, :birth_date, :gender, :phone, :residence_address, :identification_code, :doctor);""".printf (patient_table),
3496+ -1, out stmt);
3497+
3498+
3499+ /* Bind values present in doctor in the SQL statement */
3500+ int i = 1;
3501+ if (patient.id != 0)
3502+ stmt.bind_int64 (i++, patient.id);
3503+ stmt.bind_text (i++, patient.given_name);
3504+ stmt.bind_text (i++, patient.surname);
3505+ stmt.bind_text (i++, datetime_to_string (patient.birth_date));
3506+ stmt.bind_text (i++, (patient.gender == Gender.MALE) ? "MALE" : "FEMALE");
3507+ stmt.bind_text (i++, patient.phone);
3508+ stmt.bind_text (i++, patient.residence_address);
3509+ stmt.bind_text (i++, patient.identification_code);
3510+ stmt.bind_int64 (i++, (patient.doctor == null) ? 0 : patient.doctor.id);
3511+
3512+ if (stmt.step () != DONE) {
3513+ error (_("An error occurred while saving the doctor with id %I64d: %s").printf (patient.id, db.errmsg ()));
3514+ return -1;
3515+ }
3516+
3517+ if (patient.id == 0) {
3518+ patient.id = db.last_insert_rowid ();
3519+ patient_added (patient.id);
3520+ }
3521+ else
3522+ patient_changed (patient.id);
3523+
3524+ return patient.id;
3525+ }
3526+
3527+ public int64 remove_patient (Patient patient) {
3528+
3529+ db.exec ("BEGIN TRANSACTION");
3530+
3531+ if (db.exec (@"DELETE from $(patient_table) WHERE ID=$(patient.id)") != 0) {
3532+ error (@"Error deleting patient with id $(patient.id)");
3533+ db.exec ("ROLLBACK TRANSACTION");
3534+ return -1;
3535+ }
3536+
3537+ /* Try to remove all the visits of the patient */
3538+ if (db.exec (@"DELETE FROM $(visit_table) WHERE patient=$(patient.id)") != 0) {
3539+ error (@"Error deleting the visits associated to the patient");
3540+ db.exec ("ROLLBACK TRANSACTION");
3541+ return -1;
3542+ }
3543+
3544+ /* Deassoociate all the events associated with this patient */
3545+ if (db.exec (@"UPDATE $(event_table) SET patient=0 WHERE patient=$(patient.id)") != 0) {
3546+ error (@"Error deassociating the events from the deleted patient");
3547+ db.exec ("ROLLBACK TRANSACTION");
3548+ return -1;
3549+ }
3550+
3551+ db.exec ("COMMIT TRANSACTION");
3552+
3553+ patient_removed (patient.id);
3554+ return 0;
3555+ }
3556+
3557+ public VisitIterator visits (Patient? patient, DateTime? start = null, DateTime? end = null) {
3558+ string sql_clause = (patient == null && start == null && end == null) ? "" : "WHERE";
3559+
3560+ if (patient != null) {
3561+ sql_clause += @" patient = $(patient.id)";
3562+ if (start != null || end != null)
3563+ sql_clause += " AND ";
3564+ }
3565+
3566+ if (start == null && end == null)
3567+ return new SqliteVisitIterator (this, sql_clause);
3568+ else if (start != null && end == null)
3569+ return new SqliteVisitIterator (this, sql_clause + @" date >= '$(datetime_to_string (start))'");
3570+ else if (start == null && end != null)
3571+ return new SqliteVisitIterator (this, sql_clause + @" date < '$(datetime_to_string (end))'");
3572+ else
3573+ return new SqliteVisitIterator (this, sql_clause + @" date BETWEEN " +
3574+ @"'$(datetime_to_string (start))' AND '$(datetime_to_string (end))'");
3575+ }
3576+
3577+ public Visit get_visit (int64 id) {
3578+ var visit = new Visit ();
3579+ Statement stmt;
3580+ db.prepare ("""SELECT anamnesis, physical_examination, laboratory_exam, histopathology, diagnosis,
3581+ topical_therapy, systemic_therapy, subsequent_checks, date, patient
3582+ FROM %s WHERE id=%I64d;""".printf (visit_table, id), -1,
3583+ out stmt, null);
3584+ if (!(stmt.step () == ROW)) {
3585+ error (_("Error while retrieving the visit with id = %I64d").printf (id, db.errmsg ()));
3586+ }
3587+
3588+ /* Load data from the database into the fields */
3589+ visit.id = id;
3590+ visit.anamnesis = stmt.column_text (0).compress ();
3591+ visit.physical_examination = stmt.column_text (1).compress ();
3592+ visit.laboratory_exam = stmt.column_text (2).compress ();
3593+ visit.histopathology = stmt.column_text (3).compress ();
3594+ visit.diagnosis = stmt.column_text (4).compress ();
3595+ visit.topical_therapy = stmt.column_text (5).compress ();
3596+ visit.systemic_therapy = stmt.column_text (6).compress ();
3597+ visit.subsequent_checks = stmt.column_text (7).compress ();
3598+ visit.date = string_to_datetime (stmt.column_text (8).compress ());
3599+ visit.patient = get_patient (stmt.column_int64 (9));
3600+
3601+ visit.provider = this;
3602+
3603+ return visit;
3604+ }
3605+
3606+ public int64 save_visit (Visit visit) {
3607+ Statement stmt;
3608+ if (visit.id != 0)
3609+ db.prepare ("""INSERT OR REPLACE INTO %s
3610+ (id, anamnesis, physical_examination, laboratory_exam, histopathology, diagnosis,
3611+ topical_therapy, systemic_therapy, subsequent_checks, date, patient)
3612+ VALUES (:id, :anamnesis, :physical_examination, :laboratory_exam, :histopathology, :diagnosis,
3613+ :topical_therapy, :systemic_therapy, :subsequent_checks, :date, :patient);""".printf (visit_table),
3614+ -1, out stmt);
3615+ else
3616+ db.prepare ("""INSERT OR REPLACE INTO %s
3617+ (anamnesis, physical_examination, laboratory_exam, histopathology, diagnosis,
3618+ topical_therapy, systemic_therapy, subsequent_checks, date, patient)
3619+ VALUES (:anamnesis, :physical_examination, :laboratory_exam, :histopathology, :diagnosis,
3620+ :topical_therapy, :systemic_therapy, :subsequent_checks, :date, :patient);""".printf (visit_table),
3621+ -1, out stmt);
3622+
3623+ /* Bind values present in doctor in the SQL statement */
3624+ int i = 1;
3625+ if (visit.id != 0)
3626+ stmt.bind_int64 (i++, visit.id);
3627+ stmt.bind_text (i++, visit.anamnesis);
3628+ stmt.bind_text (i++, visit.physical_examination);
3629+ stmt.bind_text (i++, visit.laboratory_exam);
3630+ stmt.bind_text (i++, visit.histopathology);
3631+ stmt.bind_text (i++, visit.diagnosis);
3632+ stmt.bind_text (i++, visit.topical_therapy);
3633+ stmt.bind_text (i++, visit.systemic_therapy);
3634+ stmt.bind_text (i++, visit.subsequent_checks);
3635+ stmt.bind_text (i++, datetime_to_string (visit.date));
3636+ stmt.bind_int64 (i++, visit.patient.id);
3637+
3638+ if (stmt.step () != DONE) {
3639+ error (_("An error occurred while saving the doctor with id %I64d: %s").printf (visit.id, db.errmsg ()));
3640+ return -1;
3641+ }
3642+
3643+ if (visit.id == 0) {
3644+ visit.id = db.last_insert_rowid ();
3645+ visit_added (visit.id);
3646+ }
3647+ else
3648+ visit_changed (visit.id);
3649+
3650+ return visit.id;
3651+ }
3652+
3653+ public int64 remove_visit (Visit visit) {
3654+ Statement stmt;
3655+ string sql = @"DELETE from $(visit_table) WHERE ID=$(visit.id);";
3656+
3657+ db.prepare (sql, -1, out stmt, null);
3658+ if (stmt.step () != DONE) {
3659+ error (@"Error deleting visit with id $(visit.id)");
3660+ return -1;
3661+ }
3662+
3663+ visit_removed (visit.id);
3664+ return 0;
3665+ }
3666+
3667+ public Event get_event (int64 id) {
3668+ var event = new Event ();
3669+ Statement stmt;
3670+ db.prepare (@"SELECT title, description, venue, patient, visit, date FROM $(event_table) WHERE id=$(id);", -1,
3671+ out stmt, null);
3672+ if (!(stmt.step () == ROW)) {
3673+ error (_("Error while retrieving the event with id = %d").printf (id, db.errmsg ()));
3674+ }
3675+
3676+ /* Load data from the database into the fields */
3677+ event.id = id;
3678+ event.title = stmt.column_text (0).compress ();
3679+ event.description = stmt.column_text (1).compress ();
3680+ event.venue = stmt.column_text (2).compress ();
3681+ event.patient = (stmt.column_int64 (3) != 0) ? get_patient (stmt.column_int64 (3)) : null;
3682+ event.visit = (stmt.column_int64 (4) != 0) ? get_visit (stmt.column_int64 (4)) : null;
3683+ event.date = string_to_datetime (stmt.column_text (5).compress ());
3684+
3685+ event.provider = this;
3686+
3687+ return event;
3688+ }
3689+
3690+ public int64 save_event (Event event) {
3691+ Statement stmt;
3692+
3693+ if (event.id != 0)
3694+ db.prepare ("""INSERT OR REPLACE INTO %s (id, title, description, venue, patient, visit, date)
3695+ VALUES (:id, :title, :description, :venue, :patient, :visit, :date);""".printf (event_table),
3696+ -1, out stmt);
3697+ else
3698+ db.prepare ("""INSERT OR REPLACE INTO %s (title, description, venue, patient, visit, date)
3699+ VALUES (:title, :description, :venue, :patient, :visit, :date);""".printf (event_table),
3700+ -1, out stmt);
3701+
3702+ /* Bind values present in doctor in the SQL statement */
3703+ int i = 1;
3704+ if (event.id != 0)
3705+ stmt.bind_int64 (i++, event.id);
3706+ stmt.bind_text (i++, event.title);
3707+ stmt.bind_text (i++, event.description);
3708+ stmt.bind_text (i++, event.venue);
3709+ stmt.bind_int64 (i++, (event.patient == null) ? 0 : event.patient.id);
3710+ stmt.bind_int64 (i++, (event.visit == null) ? 0 : event.visit.id);
3711+ stmt.bind_text (i++, datetime_to_string (event.date));
3712+
3713+ if (stmt.step () != DONE) {
3714+ error (_("An error occurred while saving the event with id %I64d: %s").printf (event.id, db.errmsg ()));
3715+ return -1;
3716+ }
3717+
3718+ if (event.id == 0) {
3719+ event.id = db.last_insert_rowid ();
3720+ event_added (event.id);
3721+ }
3722+ else
3723+ event_changed (event.id);
3724+
3725+ return event.id;
3726+ }
3727+
3728+
3729+ public int64 remove_event (Event event) {
3730+ Statement stmt;
3731+ string sql = @"DELETE from $(event_table) WHERE ID=$(event.id);";
3732+
3733+ db.prepare (sql, -1, out stmt, null);
3734+ if (stmt.step () != DONE) {
3735+ error (@"Error deleting event with id $(event.id)");
3736+ return -1;
3737+ }
3738+
3739+ event_removed (event.id);
3740+ return 0;
3741+ }
3742+
3743+ public EventIterator events (DateTime? start = null, DateTime? end = null) {
3744+ string sql_clause = "";
3745+
3746+ if (start == null && end == null)
3747+ return new SqliteEventIterator (this, sql_clause);
3748+ else if (start != null && end == null)
3749+ return new SqliteEventIterator (this, sql_clause + @" WHERE date >= '$(datetime_to_string (start))'");
3750+ else if (start == null && end != null)
3751+ return new SqliteEventIterator (this, sql_clause + @" WHERE date < '$(datetime_to_string (end))'");
3752+ else
3753+ return new SqliteEventIterator (this, sql_clause + @" WHERE date BETWEEN " +
3754+ @"'$(datetime_to_string (start))' AND '$(datetime_to_string (end))'");
3755+ }
3756+
3757+ }
3758+
3759+}
3760
3761=== added file 'libclinica/SqliteDoctorIterator.vala'
3762--- libclinica/SqliteDoctorIterator.vala 1970-01-01 00:00:00 +0000
3763+++ libclinica/SqliteDoctorIterator.vala 2012-02-23 21:39:18 +0000
3764@@ -0,0 +1,45 @@
3765+/*
3766+ * This file is part of Clinica.
3767+ *
3768+ * Clinica is free software: you can redistribute it and/or modify
3769+ * it under the terms of the GNU General Public License as published by
3770+ * the Free Software Foundation, either version 3 of the License, or
3771+ * (at your option) any later version.
3772+ *
3773+ * Clinica is distributed in the hope that it will be useful,
3774+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3775+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3776+ * GNU General Public License for more details.
3777+ *
3778+ * You should have received a copy of the GNU General Public License
3779+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
3780+ *
3781+ * Authors: Leonardo Robol <leo@robol.it>
3782+ */
3783+
3784+using Sqlite;
3785+
3786+namespace Clinica {
3787+
3788+ public class SqliteDoctorIterator : Object, DoctorIterator {
3789+
3790+ private SqliteDataProvider provider;
3791+ private Statement stmt;
3792+
3793+ public SqliteDoctorIterator (SqliteDataProvider provider, string clause = "") {
3794+ this.provider = provider;
3795+ provider.db.prepare ("SELECT id from %s %s;".printf (provider.doctor_table, clause),
3796+ -1, out stmt);
3797+ }
3798+
3799+ public bool next () {
3800+ return (stmt.step () == ROW);
3801+ }
3802+
3803+ public new Doctor get () {
3804+ int id = stmt.column_int (0);
3805+ return provider.get_doctor (id);
3806+ }
3807+ }
3808+
3809+}
3810
3811=== added file 'libclinica/SqlitePatientIterator.vala'
3812--- libclinica/SqlitePatientIterator.vala 1970-01-01 00:00:00 +0000
3813+++ libclinica/SqlitePatientIterator.vala 2012-02-23 21:39:18 +0000
3814@@ -0,0 +1,45 @@
3815+/*
3816+ * This file is part of Clinica.
3817+ *
3818+ * Clinica is free software: you can redistribute it and/or modify
3819+ * it under the terms of the GNU General Public License as published by
3820+ * the Free Software Foundation, either version 3 of the License, or
3821+ * (at your option) any later version.
3822+ *
3823+ * Clinica is distributed in the hope that it will be useful,
3824+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3825+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3826+ * GNU General Public License for more details.
3827+ *
3828+ * You should have received a copy of the GNU General Public License
3829+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
3830+ *
3831+ * Authors: Leonardo Robol <leo@robol.it>
3832+ */
3833+
3834+using Sqlite;
3835+
3836+namespace Clinica {
3837+
3838+ public class SqlitePatientIterator : Object, PatientIterator {
3839+
3840+ private SqliteDataProvider provider;
3841+ private Statement stmt;
3842+
3843+ public SqlitePatientIterator (SqliteDataProvider provider, string clause = "") {
3844+ this.provider = provider;
3845+ provider.db.prepare ("SELECT id from %s %s;".printf (provider.patient_table, clause),
3846+ -1, out stmt);
3847+ }
3848+
3849+ public bool next () {
3850+ return (stmt.step () == ROW);
3851+ }
3852+
3853+ public new Patient get () {
3854+ int id = stmt.column_int (0);
3855+ return provider.get_patient (id);
3856+ }
3857+ }
3858+
3859+}
3860
3861=== added file 'libclinica/SqliteVisitIterator.vala'
3862--- libclinica/SqliteVisitIterator.vala 1970-01-01 00:00:00 +0000
3863+++ libclinica/SqliteVisitIterator.vala 2012-02-23 21:39:18 +0000
3864@@ -0,0 +1,44 @@
3865+/*
3866+ * This file is part of Clinica.
3867+ *
3868+ * Clinica is free software: you can redistribute it and/or modify
3869+ * it under the terms of the GNU General Public License as published by
3870+ * the Free Software Foundation, either version 3 of the License, or
3871+ * (at your option) any later version.
3872+ *
3873+ * Clinica is distributed in the hope that it will be useful,
3874+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3875+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3876+ * GNU General Public License for more details.
3877+ *
3878+ * You should have received a copy of the GNU General Public License
3879+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
3880+ *
3881+ * Authors: Leonardo Robol <leo@robol.it>
3882+ */
3883+
3884+using Sqlite;
3885+
3886+namespace Clinica {
3887+
3888+ public class SqliteVisitIterator : GLib.Object, VisitIterator {
3889+
3890+ private SqliteDataProvider provider;
3891+ private Statement stmt;
3892+
3893+ public SqliteVisitIterator (SqliteDataProvider provider, string clause = "") {
3894+ this.provider = provider;
3895+ provider.db.prepare ("SELECT id from %s %s ORDER by date DESC;".printf (provider.visit_table, clause),
3896+ -1, out stmt);
3897+ }
3898+
3899+ public bool next () {
3900+ return (stmt.step () == ROW);
3901+ }
3902+
3903+ public new Visit get () {
3904+ int id = stmt.column_int (0);
3905+ return provider.get_visit (id);
3906+ }
3907+ }
3908+}
3909
3910=== modified file 'libclinica/UserInterface.vala'
3911--- libclinica/UserInterface.vala 2012-01-31 09:44:59 +0000
3912+++ libclinica/UserInterface.vala 2012-02-23 21:39:18 +0000
3913@@ -45,7 +45,7 @@
3914 /* Windows */
3915 internal SettingsManager? settings_manager = null;
3916 internal CalendarWindow? calendar_window = null;
3917- internal GLib.HashTable<int, VisitWindow> visit_windows;
3918+ internal GLib.HashTable<int64?, VisitWindow> visit_windows;
3919
3920 private extern Peas.ExtensionSet setup_extension_set (ResourceManager resources, Peas.Engine engine);
3921 internal Peas.ExtensionSet extension_set;
3922@@ -78,7 +78,7 @@
3923 }
3924
3925 /* Create an empty HashTable to store the Visit windows */
3926- visit_windows = new HashTable<int, VisitWindow> (null, null);
3927+ visit_windows = new HashTable<int64?, VisitWindow> (null, null);
3928
3929 /* Load pages and connect callbacks with errors */
3930 start_page = new StartPage (resource_manager);
3931@@ -181,7 +181,7 @@
3932 * is already open than bring it on top.
3933 */
3934 public VisitWindow show_visit_window (Patient p) {
3935- int p_id = p.get_id ();
3936+ int64 p_id = p.id;
3937
3938 VisitWindow? win = visit_windows.lookup (p_id);
3939 if (win == null) {
3940
3941=== modified file 'libclinica/UserInterfaceActivatable.vala'
3942--- libclinica/UserInterfaceActivatable.vala 2011-09-22 19:27:52 +0000
3943+++ libclinica/UserInterfaceActivatable.vala 2012-02-23 21:39:18 +0000
3944@@ -1,3 +1,22 @@
3945+/*
3946+ * This file is part of Clinica.
3947+ *
3948+ * Clinica is free software: you can redistribute it and/or modify
3949+ * it under the terms of the GNU General Public License as published by
3950+ * the Free Software Foundation, either version 3 of the License, or
3951+ * (at your option) any later version.
3952+ *
3953+ * Clinica is distributed in the hope that it will be useful,
3954+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3955+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3956+ * GNU General Public License for more details.
3957+ *
3958+ * You should have received a copy of the GNU General Public License
3959+ * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
3960+ *
3961+ * Authors: Leonardo Robol <leo@robol.it>
3962+ */
3963+
3964 namespace Clinica {
3965
3966 /**
3967
3968=== modified file 'libclinica/Visit.vala'
3969--- libclinica/Visit.vala 2012-02-02 07:26:45 +0000
3970+++ libclinica/Visit.vala 2012-02-23 21:39:18 +0000
3971@@ -15,187 +15,36 @@
3972 * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
3973 *
3974 * Authors: Leonardo Robol <leo@robol.it>
3975- * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it>
3976 */
3977
3978- using Gee;
3979- using Sqlite;
3980-
3981- namespace Clinica {
3982-
3983- public class VisitIterator : SqlDataIterator {
3984-
3985-
3986- private ResourceManager resource_manager;
3987-
3988- public VisitIterator (ResourceManager resources) {
3989- base (resources.db, resources.visits_table, "date", true);
3990- resource_manager = resources;
3991- }
3992-
3993- public VisitIterator.with_day (ResourceManager resources, DateTime day, bool descending = true) {
3994- DateTime day_after = day.add_days (1).add_minutes (-1);
3995- base.with_like (resources.db, resources.visits_table, "date", descending,
3996- "date BETWEEN '%s' AND '%s'".printf (SqlDataType.datetime_to_string (day),
3997- SqlDataType.datetime_to_string (day_after)));
3998- resource_manager = resources;
3999- }
4000-
4001- public VisitIterator.with_patient (ResourceManager resources, Patient p, bool descending = true,
4002- DateTime? from = null, DateTime? to = null) {
4003-
4004- string base_like;
4005- if (from == null && to == null) {
4006- base_like = "patient = %d".printf (p.get_id ());
4007- }
4008- else if (from != null && to == null) {
4009- base_like = "patient = %d AND date >= '%s'".printf (p.get_id (), SqlDataType.datetime_to_string (from));
4010- }
4011- else if (from == null && to != null) {
4012- base_like = "patient = %d AND date < '%s'".printf (p.get_id (), SqlDataType.datetime_to_string (to));
4013- }
4014- else {
4015- base_like = "patient = %d AND date BETWEEN '%s' AND '%s'".printf (p.get_id (),
4016- SqlDataType.datetime_to_string (from),
4017- SqlDataType.datetime_to_string (to));
4018- }
4019-
4020- base.with_like (resources.db, resources.visits_table, "date", descending, base_like);
4021- resource_manager = resources;
4022- }
4023-
4024- public new VisitIterator iterator () { return this; }
4025-
4026- public new Visit get () {
4027- return new Visit.with_id (resource_manager, base.get ());
4028- }
4029- }
4030-
4031- public class Visit : SqlDataType {
4032-
4033- /* FIELDS */
4034- public string anamnesis {
4035- get { return get_text ("anamnesis"); }
4036- set { set_text ("anamnesis", value); }
4037- }
4038-
4039- public string physical_examination {
4040- get { return get_text ("physical_examination"); }
4041- set { set_text ("physical_examination", value); }
4042- }
4043-
4044- public string laboratory_exam {
4045- get { return get_text ("laboratory_exam"); }
4046- set { set_text ("laboratory_exam", value); }
4047- }
4048-
4049- public string histopathology {
4050- get { return get_text ("histopathology"); }
4051- set { set_text ("histopathology", value); }
4052- }
4053-
4054- public string diagnosis {
4055- get { return get_text ("diagnosis"); }
4056- set { set_text ("diagnosis", value); }
4057- }
4058-
4059- public string topical_therapy {
4060- get { return get_text ("topical_therapy"); }
4061- set { set_text ("topical_therapy", value); }
4062- }
4063-
4064- public string systemic_therapy {
4065- get { return get_text ("systemic_therapy"); }
4066- set { set_text ("systemic_therapy", value); }
4067- }
4068-
4069- public string subsequent_checks {
4070- get { return get_text ("subsequent_checks"); }
4071- set { set_text ("subsequent_checks", value); }
4072- }
4073-
4074- private DateTime _date;
4075- public DateTime date {
4076- get {
4077- _date = get_date ("date");
4078- return _date;
4079- }
4080- set {
4081- _date = value;
4082- set_date ("date", _date);
4083- }
4084- }
4085-
4086- private Patient _patient;
4087- public Patient patient {
4088- get {
4089- _patient = new Patient.with_id (resource_manager, get_integer ("patient"));
4090- return _patient;
4091- }
4092- set {
4093- this._patient = value;
4094- set_integer("patient", value.get_id ());
4095- }
4096- }
4097-
4098- private ResourceManager resource_manager;
4099-
4100- /**
4101- * @brief Create a new visit to
4102- * the passed patient.
4103- * @param patient The patient that has been
4104- * visited
4105- */
4106- public Visit (ResourceManager resources, Patient? patient) {
4107- base (resources.db);
4108- resource_manager = resources;
4109- table_name = resources.visits_table;
4110- error.connect ((t,l) => resources.error_callback(t,l));
4111- table_name = "visits";
4112-
4113- add_text_field ("anamnesis");
4114- add_text_field ("physical_examination");
4115- add_text_field ("laboratory_exam");
4116- add_text_field ("histopathology");
4117- add_text_field ("diagnosis");
4118- add_text_field ("topical_therapy");
4119- add_text_field ("systemic_therapy");
4120- add_text_field ("subsequent_checks");
4121- add_date_field ("date");
4122-
4123- add_integer_field ("patient");
4124-
4125- if (patient != null) {
4126- this.patient = patient;
4127- }
4128-
4129- anamnesis = "";
4130- physical_examination = "";
4131- laboratory_exam = "";
4132- histopathology = "";
4133- diagnosis = "";
4134- topical_therapy = "";
4135- systemic_therapy = "";
4136- subsequent_checks = "";
4137-
4138- init_resources ();
4139- }
4140-
4141- public Visit.with_id (ResourceManager resources, int ID) {
4142- this (resources, null);
4143- load (ID);
4144- this.patient = new Patient.with_id (resources, get_integer ("patient"));
4145- }
4146-
4147- public static new VisitIterator all (ResourceManager resources) {
4148- return new VisitIterator (resources);
4149- }
4150-
4151- public static new VisitIterator for_day (ResourceManager resources, DateTime date, bool descending = false) {
4152- return new VisitIterator.with_day (resources, date, descending);
4153- }
4154-
4155- }
4156-
4157-
4158- }
4159+namespace Clinica {
4160+
4161+ public class Visit : Object {
4162+
4163+ public DataProvider? provider = null;
4164+
4165+ public int64 id { get; set; default = 0; }
4166+
4167+ public string anamnesis { get; set; default = ""; }
4168+
4169+ public string physical_examination { get; set; default = ""; }
4170+
4171+ public string laboratory_exam { get; set; default = ""; }
4172+
4173+ public string histopathology { get; set; default = ""; }
4174+
4175+ public string diagnosis { get; set; default = ""; }
4176+
4177+ public string topical_therapy { get; set; default = ""; }
4178+
4179+ public string systemic_therapy { get; set; default = ""; }
4180+
4181+ public string subsequent_checks { get; set; default = ""; }
4182+
4183+ public DateTime date { get; set; }
4184+
4185+ public Patient patient { get; set; default = null; }
4186+
4187+ }
4188+
4189+}
4190
4191=== modified file 'libclinica/VisitActions.vala'
4192--- libclinica/VisitActions.vala 2011-11-23 17:53:36 +0000
4193+++ libclinica/VisitActions.vala 2012-02-23 21:39:18 +0000
4194@@ -95,7 +95,7 @@
4195 * visit. */
4196 this.visit_tab = visittab;
4197 visit_connection_id = visit_tab.saved.connect ((visit) => delete_button.set_sensitive (true));
4198- if (visit_tab.visit.get_id () != 0)
4199+ if (visit_tab.visit.id != 0)
4200 delete_button.set_sensitive (true);
4201 else
4202 delete_button.set_sensitive (false);
4203
4204=== modified file 'libclinica/VisitBrowser.vala'
4205--- libclinica/VisitBrowser.vala 2012-02-02 08:11:46 +0000
4206+++ libclinica/VisitBrowser.vala 2012-02-23 21:39:18 +0000
4207@@ -15,7 +15,6 @@
4208 * along with Clinica. If not, see <http://www.gnu.org/licenses/>.
4209 *
4210 * Authors: Leonardo Robol <leo@robol.it>
4211- * Gianmarco Brocchi <brocchi@poisson.phc.unipi.it>
4212 */
4213
4214 using Gtk;
4215@@ -63,7 +62,7 @@
4216 Label l;
4217
4218 /* Put in future visits */
4219- foreach (Visit v in new VisitIterator.with_patient (resource_manager, p, true, new DateTime.now_local ())) {
4220+ foreach (Visit v in p.visits (new DateTime.now_local ())) {
4221 l = new Label(v.date.format ("%F"));
4222 append_page (new VisitTab (resource_manager, visit_window, v, l), l);
4223 old_pages++;
4224@@ -78,12 +77,12 @@
4225 new_tab_saved_connection_id = new_page.saved.connect (on_new_page_saved);
4226
4227 /* And then load all visits for the patient */
4228- foreach (Visit v in new VisitIterator.with_patient (resource_manager, p, true, null, new DateTime.now_local ())) {
4229+ foreach (Visit v in p.visits (null, new DateTime.now_local ())) {
4230 l = new Label(v.date.format ("%F"));
4231 append_page (new VisitTab (resource_manager, visit_window, v, l), l);
4232 }
4233
4234- store.visit_added.connect (on_visit_list_store_visit_added);
4235+ resource_manager.data_provider.visit_added.connect (on_visit_added);
4236 }
4237
4238 public void save_focused_visit () {
4239@@ -102,9 +101,9 @@
4240 * @brief This callback gets called when a visit is added, probably
4241 * in another VisitBrowser.
4242 */
4243- private void on_visit_list_store_visit_added (int visit_id) {
4244+ private void on_visit_added (int64 visit_id) {
4245 /* Get the new visit */
4246- Visit new_visit = new Visit.with_id (resource_manager, visit_id);
4247+ Visit new_visit = resource_manager.data_provider.get_visit (visit_id);
4248
4249 /* We may be the VisitBrowser that added the visit, or not.
4250 * Let's find out traversing the tabs */
4251@@ -113,7 +112,7 @@
4252
4253 for (i = 0; i < n_pages; i++) {
4254 VisitTab tab = get_nth_page (i) as VisitTab;
4255- int visit_tab_id = tab.visit.get_id ();
4256+ int64 visit_tab_id = tab.visit.id;
4257
4258 if (visit_tab_id == visit_id) {
4259 return;
4260@@ -147,7 +146,7 @@
4261
4262 /* Check if the visit is already in db. If it is, save it, otherwise
4263 * ask the user to do it, since it may not be what he desires */
4264- if (tab.visit.get_id () <= 0) {
4265+ if (tab.visit.id <= 0) {
4266 Gtk.MessageDialog dialog = new MessageDialog.with_markup (null,
4267 DialogFlags.MODAL, MessageType.QUESTION, ButtonsType.YES_NO,
4268 _("A visit need to be saved in order to be exported as PDF.\nDo you want to save the visit now?"));
4269
4270=== modified file 'libclinica/VisitDetail.vala'
4271--- libclinica/VisitDetail.vala 2012-02-02 08:38:15 +0000
4272+++ libclinica/VisitDetail.vala 2012-02-23 21:39:18 +0000
4273@@ -124,8 +124,7 @@
4274 MessageType.QUESTION, ButtonsType.YES_NO, "%s",
4275 _("Deleting a visit will cause all its data to be lost.\nDo you really want to continue?"));
4276 if (dialog.run () == ResponseType.YES) {
4277- associated_visit.remove ();
4278- resource_manager.visit_list_store.remove_visit (associated_visit);
4279+ resource_manager.data_provider.remove_visit (associated_visit);
4280 }
4281
4282 dialog.destroy ();
4283
4284=== modified file 'libclinica/VisitFileManager.vala'
4285--- libclinica/VisitFileManager.vala 2012-01-29 15:44:14 +0000
4286+++ libclinica/VisitFileManager.vala 2012-02-23 21:39:18 +0000
4287@@ -96,7 +96,7 @@
4288 Gtk.Stock.SAVE, Gtk.ResponseType.ACCEPT);
4289 fd.set_transient_for (visit_window);
4290 if (fd.run () == Gtk.ResponseType.ACCEPT) {
4291- resource_manager.file_store.store_file (visit.get_id (), fd.get_filename ());
4292+ resource_manager.file_store.store_file (visit.id, fd.get_filename ());
4293 }
4294
4295 fd.destroy ();
4296@@ -108,7 +108,7 @@
4297 */
4298 private void on_browse_button_clicked (Button button) {
4299 try {
4300- string path = resource_manager.file_store.get_id_path (visit.get_id ());
4301+ string path = resource_manager.file_store.get_id_path (visit.id);
4302 Gtk.show_uri (null, "file://" + path, Gdk.CURRENT_TIME);
4303 } catch (GLib.Error e) {
4304 warning (_("Unable to open the browser on the filestore position"));
4305@@ -120,8 +120,8 @@
4306 * reload the files if the file changed were the ones that
4307 * belong to this visit.
4308 */
4309- private void on_file_store_changed (int id) {
4310- if (visit != null && id == visit.get_id ())
4311+ private void on_file_store_changed (int64 id) {
4312+ if (visit != null && id == visit.id)
4313 reload_file_list ();
4314 }
4315
4316@@ -148,7 +148,7 @@
4317 (attach_button.get_child () as Label).set_text (_("Attach files"));
4318 }
4319
4320- foreach (FileObject obj in resource_manager.file_store.get_files (visit.get_id ())) {
4321+ foreach (FileObject obj in resource_manager.file_store.get_files (visit.id)) {
4322 var file_detail = new FileDetail (resource_manager, visit_window, obj);
4323 pack_start (file_detail, false, true);
4324 file_detail.show_all ();
4325
4326=== modified file 'libclinica/VisitListStore.vala'
4327--- libclinica/VisitListStore.vala 2012-01-26 17:41:05 +0000
4328+++ libclinica/VisitListStore.vala 2012-02-23 21:39:18 +0000
4329@@ -24,9 +24,6 @@
4330
4331 public class VisitListStore : ListStore {
4332
4333- public signal void visit_added (int visit_id);
4334- public signal void visit_removed (int visit_id);
4335-
4336 enum Field {
4337 VISIT,
4338 DATE,
4339@@ -48,64 +45,49 @@
4340
4341 /* Fill liststore asynchronously */
4342 Idle.add(() => {
4343- foreach (Visit v in Visit.all (resource_manager)) {
4344- add_visit (v);
4345+ foreach (Visit v in resource_manager.data_provider.visits ()) {
4346+ add_visit (v.id);
4347 }
4348
4349+ /* Setup callbacks to add or remove doctors */
4350+ resource_manager.data_provider.visit_added.connect (
4351+ (id) => add_visit (id));
4352+ resource_manager.data_provider.visit_changed.connect (
4353+ (id) => reload_visit (id));
4354+ resource_manager.data_provider.visit_removed.connect (
4355+ (id) => remove_visit (id));
4356+
4357 /* We don't need to execute any more */
4358 return false;
4359 });
4360 }
4361
4362- public void add_visit (Visit v) {
4363+ private void add_visit (int64 id) {
4364+ Visit v = resource_manager.data_provider.get_visit (id);
4365 TreeIter iter;
4366 append (out iter);
4367 set_value (iter, Field.VISIT, v);
4368 set_value (iter, Field.DATE, "");
4369-
4370- visit_added (v.get_id ());
4371 }
4372
4373- public void reload_visit (Visit v) {
4374+ private void reload_visit (int64 id) {
4375+ Visit v = resource_manager.data_provider.get_visit (id);
4376 TreeIter iter = visit_to_iter (v);
4377 set_value (iter, Field.VISIT, v);
4378 set_value (iter, Field.DATE, "");
4379 }
4380
4381- /** @brief Get visits of the given patient */
4382- public List<TreeIter?> get_visits_of (Patient p) {
4383- Value value;
4384- var iters = new List<TreeIter?> ();
4385-
4386- TreeIter it;
4387- Visit v;
4388-
4389- if (!get_iter_first (out it)) {
4390- return iters;
4391- }
4392- do {
4393- get_value (it, Field.VISIT, out value);
4394- v = value as Visit;
4395- if (p.get_id () == v.patient.get_id ()) {
4396- iters.append (it);
4397- }
4398- } while (iter_next (ref it));
4399- return iters;
4400- }
4401-
4402- public void remove_visit (Visit v) {
4403+ private void remove_visit (int64 id) {
4404 TreeIter it;
4405 Value visit;
4406- int this_id = v.get_id ();
4407
4408 if (!get_iter_first (out it)) {
4409 error(_("Visit database seems corrupted. This is likely to be a bug in the application"));
4410 }
4411 do {
4412 get_value (it, Field.VISIT, out visit);
4413- if ((visit as Visit).get_id () == this_id) {
4414+ if ((visit as Visit).id == id) {
4415 remove (it);
4416- visit_removed (this_id);
4417 return;
4418 }
4419 } while (iter_next (ref it));
4420@@ -113,15 +95,6 @@
4421 assert_not_reached ();
4422 }
4423
4424- public void remove_visit_from_iter (TreeIter it) {
4425- Value visit;
4426- get_value (it, Field.VISIT, out visit);
4427- int this_id = (visit as Visit).get_id ();
4428- (visit as Visit).remove ();
4429- remove (it);
4430- visit_removed (this_id);
4431- }
4432-
4433 public Visit iter_to_visit (TreeIter it) {
4434 Value visit;
4435 get_value (it, Field.VISIT, out visit);
4436@@ -135,7 +108,7 @@
4437 assert_not_reached ();
4438 do {
4439 get_value (iter, Field.VISIT, out visit);
4440- if ((visit as Visit).get_id () == v.get_id ()) {
4441+ if ((visit as Visit).id == v.id) {
4442 return iter;
4443 }
4444 } while (iter_next (ref iter));
4445
4446=== modified file 'libclinica/VisitSchedulerDialog.vala'
4447--- libclinica/VisitSchedulerDialog.vala 2012-02-02 17:00:18 +0000
4448+++ libclinica/VisitSchedulerDialog.vala 2012-02-23 21:39:18 +0000
4449@@ -84,12 +84,12 @@
4450
4451 if (base.run () == Response.SAVE) {
4452 /* Saving the new visit in the database */
4453- Visit visit = new Visit (resource_manager, p_entry.get_patient ());
4454+ Visit visit = new Visit ();
4455+ visit.patient = p_entry.get_patient ();
4456 visit.date = picker.get_datetime ();
4457
4458- /* And finally save the visit in the database AND the ListStore */
4459- visit.save ();
4460- resource_manager.visit_list_store.add_visit (visit);
4461+ /* And finally save the visit in the database */
4462+ resource_manager.data_provider.save_visit (visit);
4463 }
4464
4465 return Response.CANCEL;
4466
4467=== modified file 'libclinica/VisitTab.vala'
4468--- libclinica/VisitTab.vala 2012-02-02 08:38:15 +0000
4469+++ libclinica/VisitTab.vala 2012-02-23 21:39:18 +0000
4470@@ -176,27 +176,28 @@
4471 fill_data ();
4472
4473 /* Connect callbacks */
4474- store.visit_removed.connect (on_visit_list_store_visit_removed);
4475+ resource_manager.data_provider.visit_removed.connect (on_visit_removed);
4476 }
4477
4478 public VisitTab.with_patient (ResourceManager resources, VisitWindow window, Patient p, Label title) {
4479 this (resources, window, null, title);
4480- visit = new Visit (resource_manager, p);
4481+ visit = new Visit ();
4482+ visit.patient = p;
4483 }
4484
4485 /**
4486 * @brief Get the visit id.
4487 */
4488- public int get_visit_id () {
4489- return visit.get_id ();
4490+ public int64 get_visit_id () {
4491+ return visit.id;
4492 }
4493
4494 /**
4495 * @brief Callback to the visit_removed event in the liststore.
4496 */
4497- private void on_visit_list_store_visit_removed (int visit_id) {
4498+ private void on_visit_removed (int64 visit_id) {
4499 VisitBrowser parent = this.parent as VisitBrowser;
4500- if (visit_id == visit.get_id ())
4501+ if (visit_id == visit.id)
4502 parent.remove_page (parent.page_num (this));
4503 }
4504
4505@@ -241,12 +242,7 @@
4506 /* ..and then actually store that data in the database, changing
4507 * the label of the tab to reflect the change... */
4508 label.set_text (visit.date.format ("%F"));
4509- visit.save ();
4510-
4511- if (new_visit)
4512- store.add_visit (visit);
4513- else
4514- store.reload_visit (visit);
4515+ resource_manager.data_provider.save_visit (visit);
4516
4517 file_manager.update_visit (visit);
4518
4519@@ -264,8 +260,7 @@
4520 MessageType.QUESTION, ButtonsType.YES_NO, "%s",
4521 _("Deleting a visit will cause all its data to be lost.\nDo you really want to continue?"));
4522 if (dialog.run () == ResponseType.YES) {
4523- store.remove_visit (visit);
4524- visit.remove ();
4525+ resource_manager.data_provider.remove_visit (visit);
4526
4527 /* Emit deleted() signal */
4528 deleted();
4529
4530=== modified file 'libclinica/VisitWindow.vala'
4531--- libclinica/VisitWindow.vala 2012-01-27 07:27:43 +0000
4532+++ libclinica/VisitWindow.vala 2012-02-23 21:39:18 +0000
4533@@ -70,7 +70,7 @@
4534 * to deattach it from the user_interface visit_window hashtable.
4535 */
4536 public void on_visit_window_destroy (Widget me) {
4537- resource_manager.user_interface.visit_windows.remove (patient.get_id ());
4538+ resource_manager.user_interface.visit_windows.remove (patient.id);
4539 resource_manager.application.remove_window (this);
4540 }
4541
4542@@ -81,7 +81,7 @@
4543 int i;
4544 for (i = 0; i < visit_browser.get_n_pages (); i++) {
4545 VisitTab nth_visit_tab = visit_browser.get_nth_page (i) as VisitTab;
4546- if (nth_visit_tab.get_visit_id () == visit.get_id ()) {
4547+ if (nth_visit_tab.get_visit_id () == visit.id) {
4548 visit_browser.set_current_page (i);
4549 return;
4550 }
4551
4552=== modified file 'org.phcteam.clinica.gschema.xml'
4553--- org.phcteam.clinica.gschema.xml 2012-01-29 10:39:56 +0000
4554+++ org.phcteam.clinica.gschema.xml 2012-02-23 21:39:18 +0000
4555@@ -16,9 +16,18 @@
4556 <summary>Selected medicine search engine</summary>
4557 <description>The name of the search engine that the user wants to lookup medicines.</description>
4558 </key>
4559+ <key name="data-provider" type="s">
4560+ <default>""</default>
4561+ <summary>Selected data provider</summary>
4562+ <description>The name of the data provider used to retrieve the data in Clinica.</description>
4563+ </key>
4564 <key name="show-visit-file-manager" type="b">
4565 <default>true</default>
4566 <summary>Show "Open file browser" button in the visit window</summary>
4567 </key>
4568+ <key name="password" type="s">
4569+ <default>"password"</default>
4570+ <summary>The password used to sync with the clinica instance via wireless</summary>
4571+ </key>
4572 </schema>
4573 </schemalist>
4574
4575=== modified file 'plugins/AgenziaDelFarmaco.plugin'
4576--- plugins/AgenziaDelFarmaco.plugin 2011-09-21 16:46:53 +0000
4577+++ plugins/AgenziaDelFarmaco.plugin 2012-02-23 21:39:18 +0000
4578@@ -2,8 +2,8 @@
4579 Loader=python
4580 Module=AgenziaDelFarmaco
4581 IAge=3
4582-Name=Search for medicine on agenziadelfarmaco.it
4583-Description=Search for medical products on the italian "Agenzia del Farmaco"
4584+Name=Agenzia del Farmaco
4585+Description=Search for medical products on the italian database of agenziadelfarmaco.it
4586 Authors=Leonardo Robol
4587 Copyright=2011 Leonardo Robol
4588 Website=
4589
4590=== added file 'plugins/ClinicaAndroid.plugin'
4591--- plugins/ClinicaAndroid.plugin 1970-01-01 00:00:00 +0000
4592+++ plugins/ClinicaAndroid.plugin 2012-02-23 21:39:18 +0000
4593@@ -0,0 +1,6 @@
4594+[Plugin]
4595+Module = ClinicaAndroid
4596+Loader = python
4597+Name = Clinica for Android
4598+Description = Server to sync Android phones with Clinica
4599+Author = Leonardo Robol
4600
4601=== added file 'plugins/ClinicaAndroid.py'
4602--- plugins/ClinicaAndroid.py 1970-01-01 00:00:00 +0000
4603+++ plugins/ClinicaAndroid.py 2012-02-23 21:39:18 +0000
4604@@ -0,0 +1,130 @@
4605+#!/usr/bin/env python
4606+# -*- coding: utf-8 -*-
4607+
4608+import SocketServer, md5, threading, os
4609+from gi.repository import Clinica, GObject, Gtk, PeasGtk, Gio
4610+from socket import gethostname
4611+
4612+authenticated_clients = []
4613+
4614+class ClinicaAndroid (GObject.GObject, Clinica.UserInterfaceActivatable, PeasGtk.Configurable):
4615+
4616+ resource_manager = GObject.property (type = Clinica.ResourceManager)
4617+ user_interface = GObject.property (type = Clinica.UserInterface)
4618+
4619+ __gtype_name__ = "ClinicaAndroid"
4620+
4621+ server = None
4622+
4623+ def __init__(self):
4624+ GObject.GObject.__init__(self)
4625+
4626+ def do_activate (self):
4627+ self.clinica_db = os.path.join (self.resource_manager.get_data_path (),
4628+ "clinica.db")
4629+
4630+ self.server = ClinicaServer (self.clinica_db)
4631+ self.server_thread = threading.Thread (target = self.server.serve_forever)
4632+ self.server_thread.start ()
4633+
4634+ self.tcpserver = ClinicaTCPServer (self.clinica_db)
4635+ self.tcpserver_thread = threading.Thread (target = self.tcpserver.serve_forever)
4636+ self.tcpserver_thread.start ()
4637+
4638+ def do_deactivate (self):
4639+ self.server.shutdown ()
4640+ self.server_thread.join ()
4641+ self.tcpserver.shutdown ()
4642+ self.tcpserver_thread.join ()
4643+
4644+ def do_create_configure_widget (self):
4645+ settings = Gio.Settings.new ("org.phcteam.clinica")
4646+ box = Gtk.Box.new (Gtk.Orientation.HORIZONTAL, 6)
4647+
4648+ label = Gtk.Label ("Password")
4649+ entry = Gtk.Entry ()
4650+
4651+ box.pack_start (label, 6, False, True)
4652+ box.pack_start (entry, 6, True, True)
4653+
4654+ settings.bind ("password", entry, "text", Gio.SettingsBindFlags.DEFAULT)
4655+
4656+ return box
4657+
4658+ def on_name_entry_changed (self, entry):
4659+ self.server.set_name (entry.get_text ())
4660+
4661+ def do_update_state (self):
4662+ pass
4663+
4664+
4665+class ClinicaRequestHandler (SocketServer.BaseRequestHandler):
4666+
4667+ def handle (self):
4668+ password = self.server.settings.get_value ("password").get_string ()
4669+
4670+ data = self.request[0].strip ()
4671+ socket = self.request[1]
4672+
4673+ if data == "GetInfo":
4674+ socket.sendto ("ServerName: %s\n" % self.server.name, self.client_address)
4675+
4676+ elif data.startswith ("Authenticate:"):
4677+ pw = data.split(":")[1].strip ()
4678+
4679+ if self.client_address[0] in authenticated_clients:
4680+ socket.sendto ("Authentication performed\n", self.client_address)
4681+ else:
4682+ if password == pw:
4683+ authenticated_clients.append (self.client_address[0])
4684+ socket.sendto ("Authentication performed\n", self.client_address)
4685+ else:
4686+ socket.sendto ("Authentication failed\n", self.client_address)
4687+
4688+ elif data == "GetDB":
4689+ if self.client_address[0] in authenticated_clients:
4690+ try:
4691+ with open (self.server.db_path) as h : db_content = h.read ()
4692+ socket.sendto (db_content, self.client_address)
4693+ except Exception, e:
4694+ socket.sendto ("Sending DB failed : %s" % e, self.client_address)
4695+ else:
4696+ socket.sendto ("Autenticati, scemo\n", self.client_address)
4697+
4698+class ClinicaTCPRequestHandler (SocketServer.BaseRequestHandler):
4699+
4700+ def handle (self):
4701+ data = self.request.recv(1024).strip()
4702+ if data == "GetDB":
4703+ if self.client_address[0] in authenticated_clients:
4704+ with open (self.server.db_path) as h : db_content = h.read ()
4705+ self.request.sendall (db_content)
4706+
4707+
4708+class ClinicaTCPServer (SocketServer.ThreadingTCPServer):
4709+
4710+ allow_reuse_address = True
4711+
4712+ def __init__(self, db_path, port = 20802):
4713+ SocketServer.ThreadingTCPServer.__init__(self, ('', port), ClinicaTCPRequestHandler)
4714+
4715+ self.db_path = db_path
4716+ self.name = gethostname()
4717+
4718+class ClinicaServer (SocketServer.ThreadingUDPServer):
4719+
4720+ allow_reuse_address = True
4721+
4722+ def __init__ (self, db_path, port = 20801):
4723+ SocketServer.ThreadingUDPServer.__init__ (self, ('', port), ClinicaRequestHandler)
4724+ self.db_path = db_path
4725+ self.name = gethostname()
4726+ self.settings = Gio.Settings.new ("org.phcteam.clinica")
4727+
4728+
4729+if __name__ == "__main__":
4730+
4731+ udp_server = ClinicaServer ("Ciao")
4732+ tcp_server = ClinicaTCPServer ("Ciao")
4733+
4734+ server.serve_forever ()
4735
4736=== modified file 'plugins/wscript'
4737--- plugins/wscript 2012-01-24 09:36:22 +0000
4738+++ plugins/wscript 2012-02-23 21:39:18 +0000
4739@@ -1,8 +1,12 @@
4740 #!/usr/bin/env python
4741 #
4742
4743+import os
4744+
4745 plugins_install_path = "${PREFIX}/lib/clinica/plugins"
4746
4747+plugins = []
4748+
4749 def build (ctx):
4750 ctx.set_group ("clinica")
4751
4752@@ -29,11 +33,21 @@
4753 ctx.install_files (plugins_install_path, [ "AgenziaDelFarmaco.py",
4754 "AgenziaDelFarmaco.plugin" ])
4755
4756+ # Add plugins
4757+ add_plugin ("AgenziaDelFarmaco")
4758+ add_plugin ("DummyDataProvider")
4759+ # add_plugin ("GPGEncryption")
4760+ add_plugin ("CodiceFiscale")
4761+ add_plugin ("ClinicaAndroid")
4762+
4763 # Push plugins on the build directory so we can run
4764 # clinica in the local dir
4765- for plugin in [ 'AgenziaDelFarmaco.plugin', 'CodiceFiscale.plugin', 'AgenziaDelFarmaco.py',
4766- ]:
4767+ for plugin in plugins:
4768 push_plugin (ctx, plugin)
4769+
4770+def add_plugin (plugin_name):
4771+ plugins_files = filter (lambda x : x.startswith (plugin_name), os.listdir ("plugins"))
4772+ plugins.extend (plugins_files)
4773
4774
4775 def push_plugin (ctx, plugin_file):
4776
4777=== modified file 'po/es.po'
4778--- po/es.po 2012-02-08 08:06:57 +0000
4779+++ po/es.po 2012-02-23 21:39:18 +0000
4780@@ -11,12 +11,18 @@
4781 "PO-Revision-Date: 2012-02-07 13:41+0000\n"
4782 "Last-Translator: Fitoschido <fitoschido@gmail.com>\n"
4783 "Language-Team: Spanish <es@li.org>\n"
4784+"Language: es\n"
4785 "MIME-Version: 1.0\n"
4786 "Content-Type: text/plain; charset=UTF-8\n"
4787 "Content-Transfer-Encoding: 8bit\n"
4788+<<<<<<< TREE
4789 "X-Launchpad-Export-Date: 2012-02-08 08:06+0000\n"
4790 "X-Generator: Launchpad (build 14747)\n"
4791 "Language: es\n"
4792+=======
4793+"X-Launchpad-Export-Date: 2012-01-31 07:02+0000\n"
4794+"X-Generator: Launchpad (build 14734)\n"
4795+>>>>>>> MERGE-SOURCE
4796
4797 #: ../libclinica/Doctor.vala:110
4798 msgid ""
4799@@ -259,8 +265,13 @@
4800 msgstr "Visitas realizadas"
4801
4802 #: ../libclinica/CalendarEventList.vala:102
4803+#, fuzzy
4804 msgid "Visits scheduled"
4805+<<<<<<< TREE
4806 msgstr "Visitas agendadas"
4807+=======
4808+msgstr "Eventos agendados"
4809+>>>>>>> MERGE-SOURCE
4810
4811 #: ../libclinica/CalendarEventList.vala:123
4812 msgid "No visits performed on this day"
4813@@ -329,8 +340,8 @@
4814
4815 #: ../libclinica/DoctorListView.vala:186
4816 msgid ""
4817-"The doctor that you have selected for removal has some patients associated. "
4818-"\n"
4819+"The doctor that you have selected for removal has some patients "
4820+"associated. \n"
4821 msgstr ""
4822 "El doctor que ha elegido para ser eliminado tiene algunos pacientes "
4823 "asignados. \n"
4824@@ -360,8 +371,7 @@
4825 msgstr "Confirmar la eliminación de pacientes"
4826
4827 #: ../libclinica/DoctorListView.vala:244
4828-msgid ""
4829-"Really delete this doctor? All information about him/her will be lost."
4830+msgid "Really delete this doctor? All information about him/her will be lost."
4831 msgstr ""
4832 "¿Seguro de eliminar este médico? Toda la información del médico será perdida."
4833
4834@@ -713,25 +723,24 @@
4835 msgid "Mobile:"
4836 msgstr "Móvil:"
4837
4838+#~ msgid "Error loading patient_editor.glade."
4839+#~ msgstr "Error al cargar patient_editor.glade"
4840+
4841+#~ msgid ""
4842+#~ "\n"
4843+#~ "Launchpad contributions: \n"
4844+#~ msgstr ""
4845+#~ "\n"
4846+#~ "Contribuciones de Launchpad: \n"
4847+
4848 #~ msgid "Create a new patient"
4849 #~ msgstr "Crear un nuevo paciente"
4850
4851 #~ msgid "Create a new doctor"
4852 #~ msgstr "Crear un nuevo médico"
4853
4854-#, c-format
4855 #~ msgid "Clinica %s\n"
4856 #~ msgstr "Clínica %s\n"
4857
4858 #~ msgid "Back"
4859 #~ msgstr "Atrás"
4860-
4861-#~ msgid "Error loading patient_editor.glade."
4862-#~ msgstr "Error al cargar patient_editor.glade"
4863-
4864-#~ msgid ""
4865-#~ "\n"
4866-#~ "Launchpad contributions: \n"
4867-#~ msgstr ""
4868-#~ "\n"
4869-#~ "Contribuciones de Launchpad: \n"
4870
4871=== modified file 'po/it.po'
4872--- po/it.po 2012-02-14 06:40:10 +0000
4873+++ po/it.po 2012-02-23 21:39:18 +0000
4874@@ -10,12 +10,18 @@
4875 "PO-Revision-Date: 2012-02-13 15:15+0000\n"
4876 "Last-Translator: Gianmarco Brocchi <Unknown>\n"
4877 "Language-Team: Clinica Development team\n"
4878+"Language: \n"
4879 "MIME-Version: 1.0\n"
4880 "Content-Type: text/plain; charset=UTF-8\n"
4881 "Content-Transfer-Encoding: 8bit\n"
4882+<<<<<<< TREE
4883 "X-Launchpad-Export-Date: 2012-02-14 06:40+0000\n"
4884 "X-Generator: Launchpad (build 14781)\n"
4885 "Language: \n"
4886+=======
4887+"X-Launchpad-Export-Date: 2012-01-31 07:02+0000\n"
4888+"X-Generator: Launchpad (build 14734)\n"
4889+>>>>>>> MERGE-SOURCE
4890
4891 #: ../libclinica/Doctor.vala:110
4892 msgid ""
4893@@ -117,8 +123,7 @@
4894
4895 #: ../libclinica/PatientEditor.vala:436
4896 msgid "Date inserted is invalid, aborting patient editing"
4897-msgstr ""
4898-"La data inserita non è valida: non è possibile modificare il paziente"
4899+msgstr "La data inserita non è valida: non è possibile modificare il paziente"
4900
4901 #. Set title according to the patient that we have loaded and connect
4902 #. * show startup signal to the focusing of the first field in the visit
4903@@ -257,8 +262,13 @@
4904 msgstr "Visite effettuate"
4905
4906 #: ../libclinica/CalendarEventList.vala:102
4907+#, fuzzy
4908 msgid "Visits scheduled"
4909+<<<<<<< TREE
4910 msgstr "Visita programmata"
4911+=======
4912+msgstr "Eventi in programma"
4913+>>>>>>> MERGE-SOURCE
4914
4915 #: ../libclinica/CalendarEventList.vala:123
4916 msgid "No visits performed on this day"
4917@@ -327,8 +337,8 @@
4918
4919 #: ../libclinica/DoctorListView.vala:186
4920 msgid ""
4921-"The doctor that you have selected for removal has some patients associated. "
4922-"\n"
4923+"The doctor that you have selected for removal has some patients "
4924+"associated. \n"
4925 msgstr ""
4926 "Il dottore che è stato selezionato per la rimozione è associato a dei "
4927 "pazienti. \n"
4928@@ -360,8 +370,7 @@
4929 msgstr "Conferma la rimozione dei pazienti"
4930
4931 #: ../libclinica/DoctorListView.vala:244
4932-msgid ""
4933-"Really delete this doctor? All information about him/her will be lost."
4934+msgid "Really delete this doctor? All information about him/her will be lost."
4935 msgstr ""
4936 "Si è sicuri di voler rimuovere il medico? Tutte le informazioni su di lui o "
4937 "lei saranno perse."
4938@@ -714,12 +723,6 @@
4939 msgid "Mobile:"
4940 msgstr "Telefono cellulare:"
4941
4942-#~ msgid "Create a new patient"
4943-#~ msgstr "Crea un nuovo paziente"
4944-
4945-#~ msgid "Create a new doctor"
4946-#~ msgstr "Crea un nuovo medico"
4947-
4948 #~ msgid "Error loading patient_editor.glade."
4949 #~ msgstr "Errore durante il caricamento di patient_editor.glade."
4950
4951@@ -730,7 +733,12 @@
4952 #~ "\n"
4953 #~ "Contributi su Launchpad: \n"
4954
4955-#, c-format
4956+#~ msgid "Create a new patient"
4957+#~ msgstr "Crea un nuovo paziente"
4958+
4959+#~ msgid "Create a new doctor"
4960+#~ msgstr "Crea un nuovo medico"
4961+
4962 #~ msgid "Clinica %s\n"
4963 #~ msgstr "Clinica %s\n"
4964
4965
4966=== modified file 'po/pt_BR.po'
4967--- po/pt_BR.po 2012-02-06 05:08:51 +0000
4968+++ po/pt_BR.po 2012-02-23 21:39:18 +0000
4969@@ -7,43 +7,52 @@
4970 msgstr ""
4971 "Project-Id-Version: clinica-project\n"
4972 "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
4973+<<<<<<< TREE
4974 "POT-Creation-Date: 2012-02-02 18:49+0100\n"
4975 "PO-Revision-Date: 2012-02-05 15:24+0000\n"
4976 "Last-Translator: Marco <marcodefreitas@gmail.com>\n"
4977+=======
4978+"POT-Creation-Date: 2012-01-29 11:43+0100\n"
4979+"PO-Revision-Date: 2012-02-02 05:16+0000\n"
4980+"Last-Translator: Marco <marcodefreitas@gmail.com>\n"
4981+>>>>>>> MERGE-SOURCE
4982 "Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
4983 "MIME-Version: 1.0\n"
4984 "Content-Type: text/plain; charset=UTF-8\n"
4985 "Content-Transfer-Encoding: 8bit\n"
4986+<<<<<<< TREE
4987 "X-Launchpad-Export-Date: 2012-02-06 05:08+0000\n"
4988 "X-Generator: Launchpad (build 14747)\n"
4989+=======
4990+"X-Launchpad-Export-Date: 2012-02-02 06:29+0000\n"
4991+"X-Generator: Launchpad (build 14738)\n"
4992+>>>>>>> MERGE-SOURCE
4993
4994 #: ../libclinica/Doctor.vala:110
4995 msgid ""
4996 "You cannot delete a doctor with associated patients. Delete his patients "
4997 "first."
4998 msgstr ""
4999+<<<<<<< TREE
5000 "Você não pode excluir um médico com pacientes associados. Exclua seus "
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: