Merge lp:~frankencode/ubuntu-calendar-app/data-service into lp:ubuntu-calendar-app

Proposed by Frank Mertens
Status: Merged
Merged at revision: 11
Proposed branch: lp:~frankencode/ubuntu-calendar-app/data-service
Merge into: lp:ubuntu-calendar-app
Diff against target: 907 lines (+729/-50) (has conflicts)
8 files modified
DiaryView.qml (+82/-0)
EventListModel.qml (+26/-0)
EventView.qml (+19/-13)
MonthView.qml (+9/-3)
calendar.qml (+26/-34)
calendarTests.qml (+14/-0)
dataService.js (+361/-0)
dataServiceTests.js (+192/-0)
Text conflict in MonthView.qml
To merge this branch: bzr merge lp:~frankencode/ubuntu-calendar-app/data-service
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Needs Fixing
Frank Mertens Pending
Review via email: mp+154240@code.launchpad.net

Commit message

Added a data model for the local store, some simulation data and thin API on top, which is called DataService.

Description of the change

Added a data model for the local store, some simulation data and thin API on top, which is called DataService. The idea behind: abstract away the access to events, contacts and places. Especially the last two will be delivered by some system service in a later version. For now this is only simulated. But the user of the DataService API shouldn't need to worry about.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
11. By Frank Mertens

Added more complex test case in preparation for integration of the diary view.

To run the tests and load the test data run 'qmlscene calendarTest.qml' once.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
12. By Frank Mertens

Use singleton pattern to improve startup performance

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
13. By Frank Mertens

Extended the database model by an events category and added a basic diary view.

The events category allows to use section headers.
The basic diary view uses the standard Ubuntu component ListItem.Standard to show
the events of the current day.

14. By Frank Mertens

Removed testing icon and added new icons needed for the diary view.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
15. By Frank Mertens

Missing file.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
16. By Frank Mertens

Allow proper interactions with the compressed event view.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'DiaryView.qml'
2--- DiaryView.qml 1970-01-01 00:00:00 +0000
3+++ DiaryView.qml 2013-03-27 23:13:20 +0000
4@@ -0,0 +1,82 @@
5+import QtQuick 2.0
6+import Ubuntu.Components 0.1
7+import Ubuntu.Components.ListItems 0.1 as ListItem
8+import "dateExt.js" as DateExt
9+import "colorUtils.js" as Color
10+
11+ListView {
12+ id: diaryView
13+
14+ property var dayStart: new Date()
15+
16+ property bool expanded: false
17+
18+ property bool expanding: false
19+ property bool compressing: false
20+
21+ signal expand()
22+ signal compress()
23+
24+ clip: true
25+
26+ model: EventListModel {
27+ termStart: dayStart
28+ termLength: Date.msPerDay
29+ }
30+
31+ section {
32+ property: "category"
33+ // labelPositioning: ViewSection.CurrentLabelAtStart // FIXME, unreliable
34+ delegate: ListItem.Header {
35+ text: i18n.tr(section)
36+ MouseArea {
37+ anchors.fill: parent
38+ onClicked: {
39+ if (expanded)
40+ compress()
41+ else
42+ expand()
43+ }
44+ }
45+ }
46+ }
47+
48+ delegate: ListItem.Standard {
49+ text: startTime.toLocaleTimeString(Qt.locale(i18n.language), Locale.ShortFormat) + " " + title
50+ }
51+
52+ footer: ListItem.Standard {
53+ text: i18n.tr("(+) New Event / Todo")
54+ }
55+
56+ onContentYChanged: {
57+ // console.log(expanded, expanding, compressing, dragging, flicking, moving, contentY)
58+ if (expanding || compressing || !dragging) return
59+
60+ if (expanded) {
61+ if (contentY < -units.gu(0.5)) {
62+ compressing = true
63+ expanding = false
64+ }
65+ }
66+ else {
67+ if (contentY < -units.gu(0.5)) {
68+ expanding = true
69+ compressing = false
70+ }
71+ }
72+ }
73+
74+ onDraggingChanged: {
75+ if (dragging) return
76+
77+ if (expanding) {
78+ expanding = false
79+ expand()
80+ }
81+ else if (compressing) {
82+ compressing = false
83+ compress()
84+ }
85+ }
86+}
87
88=== added file 'EventListModel.qml'
89--- EventListModel.qml 1970-01-01 00:00:00 +0000
90+++ EventListModel.qml 2013-03-27 23:13:20 +0000
91@@ -0,0 +1,26 @@
92+import QtQuick 2.0
93+import "dateExt.js" as DateExt
94+import "dataService.js" as DataService
95+
96+ListModel {
97+ id: model
98+
99+ property var termStart: new Date()
100+ property var termLength: Date.msPerDay
101+
102+ signal reload
103+
104+ onReload: {
105+ var t0 = termStart.getTime()
106+ var t1 = t0 + termLength
107+ model.clear()
108+ DataService.getEvents(t0, t1, model)
109+ // for (var i = 0; i < model.count; ++i)
110+ // DataService.printEvent(model.get(i))
111+ }
112+ Component.onCompleted: {
113+ reload()
114+ DataService.eventsNotifier().dataChanged.connect(reload)
115+ termStartChanged.connect(reload)
116+ }
117+}
118
119=== modified file 'EventView.qml'
120--- EventView.qml 2013-03-07 00:13:06 +0000
121+++ EventView.qml 2013-03-27 23:13:20 +0000
122@@ -1,6 +1,6 @@
123 import QtQuick 2.0
124 import Ubuntu.Components 0.1
125-import "DateLib.js" as DateLib
126+import "dateExt.js" as DateExt
127
128 PathView {
129 id: eventView
130@@ -10,6 +10,11 @@
131 signal incrementCurrentDay
132 signal decrementCurrentDay
133
134+ property bool expanded: false
135+
136+ signal compress()
137+ signal expand()
138+
139 readonly property real visibleHeight: parent.height - y
140
141 QtObject {
142@@ -43,7 +48,7 @@
143
144 path: Path {
145 startX: -eventView.width; startY: eventView.height / 2
146- PathLine { relativeX: eventView.width; relativeY: 0 }
147+ PathLine { relativeX: eventView.width; relativeY: 0 }
148 PathLine { relativeX: eventView.width; relativeY: 0 }
149 PathLine { relativeX: eventView.width; relativeY: 0 }
150 }
151@@ -52,21 +57,22 @@
152
153 model: 3
154
155- delegate: Rectangle {
156- property var dayStart: {
157+ delegate: DiaryView {
158+ id: diaryView
159+
160+ width: eventView.width
161+ height: eventView.height
162+
163+ dayStart: {
164 if (index == intern.currentIndex) return intern.currentDayStart
165 var previousIndex = intern.currentIndex > 0 ? intern.currentIndex - 1 : 2
166 if (index == previousIndex) return intern.currentDayStart.addDays(-1)
167 return intern.currentDayStart.addDays(1)
168 }
169- width: eventView.width
170- height: eventView.height
171- color: index == 0 ? "#FFFFFF" : index == 1 ? "#EEEEEE" : "#DDDDDD"
172- Label {
173- anchors.horizontalCenter: parent.horizontalCenter
174- y: units.gu(4)
175- text: i18n.tr("No events for") + "\n" + Qt.formatDate(dayStart)
176- fontSize: "large"
177- }
178+
179+ expanded: eventView.expanded
180+
181+ onExpand: eventView.expand()
182+ onCompress: eventView.compress()
183 }
184 }
185
186=== modified file 'MonthView.qml'
187--- MonthView.qml 2013-03-18 20:39:06 +0000
188+++ MonthView.qml 2013-03-27 23:13:20 +0000
189@@ -1,6 +1,6 @@
190 import QtQuick 2.0
191 import Ubuntu.Components 0.1
192-import "DateLib.js" as DateLib
193+import "dateExt.js" as DateExt
194 import "colorUtils.js" as Color
195
196 ListView {
197@@ -11,7 +11,8 @@
198 readonly property var currentDayStart: intern.currentDayStart
199
200 property bool compressed: false
201- property real compressedHeight: intern.squareUnit + intern.verticalMargin * 2
202+ readonly property real compressedHeight: intern.squareUnit + intern.verticalMargin * 2
203+ readonly property real expandedHeight: intern.squareUnit * 6 + intern.verticalMargin * 2
204
205 signal incrementCurrentDay
206 signal decrementCurrentDay
207@@ -90,7 +91,7 @@
208
209 property int squareUnit: monthView.width / 8
210 property int verticalMargin: units.gu(1)
211- property int weekstartDay: Qt.locale().firstDayOfWeek
212+ property int weekstartDay: Qt.locale(i18n.language).firstDayOfWeek
213 property int monthCount: 49 // months for +-2 years
214
215 property var today: (new Date()).midnight() // TODO: update at midnight
216@@ -99,8 +100,13 @@
217 property var monthStart0: today.monthStart()
218 }
219
220+<<<<<<< TREE
221 width: parent.width > 0 ? parent.width : 1
222 height: intern.squareUnit * 6 + intern.verticalMargin * 2
223+=======
224+ width: parent.width
225+ height: compressed ? compressedHeight : expandedHeight
226+>>>>>>> MERGE-SOURCE
227
228 interactive: !compressed
229 clip: true
230
231=== added file 'avatar@8.png'
232Binary files avatar@8.png 1970-01-01 00:00:00 +0000 and avatar@8.png 2013-03-27 23:13:20 +0000 differ
233=== removed file 'avatar@8.png'
234Binary files avatar@8.png 2013-02-12 16:18:48 +0000 and avatar@8.png 1970-01-01 00:00:00 +0000 differ
235=== modified file 'calendar.qml'
236--- calendar.qml 2013-03-18 11:39:23 +0000
237+++ calendar.qml 2013-03-27 23:13:20 +0000
238@@ -31,55 +31,47 @@
239 onSelectedTabIndexChanged: monthView.gotoNextMonth(selectedTabIndex)
240 }
241
242+ Rectangle {
243+ anchors.fill: monthView
244+ color: "white"
245+ }
246+
247 MonthView {
248 id: monthView
249 onMonthStartChanged: tabs.selectedTabIndex = monthStart.getMonth()
250 y: pageArea.y
251+ onMovementEnded: eventView.currentDayStart = currentDayStart
252+ onCurrentDayStartChanged: if (!(dragging || flicking)) eventView.currentDayStart = currentDayStart
253+ Component.onCompleted: eventView.currentDayStart = currentDayStart
254 }
255
256 EventView {
257 id: eventView
258+
259 property real minY: pageArea.y + monthView.compressedHeight
260- property real maxY: pageArea.y + monthView.height
261+ property real maxY: pageArea.y + monthView.expandedHeight
262+
263 y: maxY
264 width: mainView.width
265- height: parent.height - monthView.compressedHeight
266- currentDayStart: monthView.currentDayStart
267+ height: parent.height - y
268+
269+ expanded: monthView.compressed
270+
271 Component.onCompleted: {
272 incrementCurrentDay.connect(monthView.incrementCurrentDay)
273 decrementCurrentDay.connect(monthView.decrementCurrentDay)
274 }
275- MouseArea {
276- id: drawer
277- property bool compression: true
278- anchors.fill: parent
279- drag {
280- axis: Drag.YAxis
281- target: eventView
282- minimumY: monthView.y + monthView.compressedHeight
283- maximumY: monthView.y + monthView.height
284- onActiveChanged: {
285- if (compression) {
286- if (drag.active) {
287- monthView.compressed = true
288- }
289- else {
290- yBehavior.enabled = true
291- eventView.y = Qt.binding(function() { return eventView.minY })
292- compression = false
293- }
294- }
295- else {
296- if (drag.active) {}
297- else{
298- eventView.y = Qt.binding(function() { return eventView.maxY })
299- monthView.compressed = false
300- compression = true
301- }
302- }
303- }
304- }
305- }
306+
307+ onExpand: {
308+ monthView.compressed = true
309+ yBehavior.enabled = true
310+ y = minY
311+ }
312+ onCompress: {
313+ monthView.compressed = false
314+ y = maxY
315+ }
316+
317 Behavior on y {
318 id: yBehavior
319 enabled: false
320
321=== added file 'calendarTests.qml'
322--- calendarTests.qml 1970-01-01 00:00:00 +0000
323+++ calendarTests.qml 2013-03-27 23:13:20 +0000
324@@ -0,0 +1,14 @@
325+import QtQuick 2.0
326+import Ubuntu.Components 0.1
327+import "dataServiceTests.js" as DataServiceTests
328+
329+MainView {
330+ width: units.gu(20)
331+ height: units.gu(20)
332+ Button {
333+ anchors.fill: parent
334+ anchors.margins: units.gu(5)
335+ text: "Close"
336+ onClicked: Qt.quit()
337+ }
338+}
339
340=== added file 'dataService.js'
341--- dataService.js 1970-01-01 00:00:00 +0000
342+++ dataService.js 2013-03-27 23:13:20 +0000
343@@ -0,0 +1,361 @@
344+.pragma library
345+
346+.import QtQuick.LocalStorage 2.0 as LS
347+
348+Array.prototype.append = function(x) { this.push(x) }
349+
350+var CATEGORY_EVENT = 0
351+var CATEGORY_TODO = 1
352+
353+function getEvents(termStart, termEnd, events)
354+{
355+ var result = null
356+
357+ db().readTransaction(
358+ function(tx) {
359+ result = tx.executeSql('\
360+select * from Event \
361+where (? <= startTime and startTime < ?) or \
362+ (? < endTime and endTime <= ?) or \
363+ (startTime <= ? and ? <= endTime) \
364+order by startTime',
365+ [ termStart, termEnd, termStart, termEnd, termStart, termEnd ]
366+ )
367+ }
368+ )
369+
370+ events = events || []
371+
372+ for (var i = 0; i < result.rows.length; ++i) {
373+ var e = result.rows.item(i)
374+ e.startTime = new Date(e.startTime)
375+ e.endTime = new Date(e.endTime)
376+ events.append(e)
377+ }
378+
379+ return events
380+}
381+
382+function getAttendees(event, attendees)
383+{
384+ var result = null;
385+
386+ db().readTransaction(
387+ function(tx) {
388+ result = tx.executeSql('\
389+select c.* from Attendance a, Contact c \
390+where a.eventId = ? and a.contactId = c.id \
391+order by c.name',
392+ [ event.id ]
393+ )
394+ }
395+ )
396+
397+ attendees = attendees || []
398+
399+ for (var i = 0; i < result.rows.length; ++i)
400+ attendees.append(result.rows.item(i))
401+
402+ return attendees
403+}
404+
405+function addEvent(event)
406+{
407+ var result = null
408+
409+ db().transaction(
410+ function(tx) {
411+ result = tx.executeSql('\
412+insert into Event(title, message, startTime, endTime) \
413+values (?, ?, ?, ?)',
414+ [ event.title, event.message, event.startTime, event.endTime ]
415+ )
416+ }
417+ )
418+
419+ event.id = result.insertId
420+
421+ eventsNotifier().dataChanged()
422+
423+ return event
424+}
425+
426+function removeEvent(event)
427+{
428+ db().transaction(
429+ function(tx) {
430+ tx.executeSql(
431+ 'delete from Event where id = ?',
432+ [ event.id ]
433+ )
434+ tx.executeSql(
435+ 'delete from Attendance where eventId = ?',
436+ [ event.id ]
437+ )
438+ tx.executeSql(
439+ 'delete from Venue where eventId = ?',
440+ [ event.id ]
441+ )
442+ }
443+ )
444+
445+ delete event.id
446+
447+ eventsNotifier().dataChanged()
448+}
449+
450+function getContacts(contacts)
451+{
452+ var result = null
453+
454+ db().readTransaction(
455+ function(tx) {
456+ result = tx.executeSql('select * from Contact order by name')
457+ }
458+ )
459+
460+ contacts = contacts || []
461+
462+ for (var i = 0; i < result.rows.length; ++i)
463+ contacts.append(result.rows.item(i))
464+
465+ return contacts
466+}
467+
468+function addAttendee(event, contact)
469+{
470+ db().transaction(
471+ function(tx) {
472+ tx.executeSql(
473+ 'insert into Attendance(eventId, contactId) values (?, ?)',
474+ [ event.id, contact.id ]
475+ )
476+ }
477+ )
478+}
479+
480+function removeAttendee(event, contact)
481+{
482+ db().transaction(
483+ function(tx) {
484+ tx.executeSql(
485+ 'delete from Attendance where eventId = ? and contactId = ?',
486+ [ event.id, contact.id ]
487+ )
488+ }
489+ )
490+}
491+
492+function getPlaces(places)
493+{
494+ var result = null
495+
496+ db().readTransaction(
497+ function(tx) {
498+ result = tx.executeSql('select * from Place')
499+ }
500+ )
501+
502+ places = places || []
503+
504+ for (var i = 0; i < result.rows.length; ++i)
505+ places.append(result.rows.item(i))
506+
507+ return places
508+}
509+
510+function addPlace(place)
511+{
512+ var result = null
513+
514+ if (typeof place.address == 'undefined') place.address = null
515+ if (typeof place.latitude == 'undefined') place.latitude = null
516+ if (typeof place.longitude == 'undefined') place.longitude = null
517+
518+ db().transaction(
519+ function(tx) {
520+ result = tx.executeSql(
521+ 'insert into Place(name, address, latitude, longitude) values(?, ?, ?, ?)',
522+ [ place.name, place.address, place.latitude, place.longitude ]
523+ )
524+ }
525+ )
526+
527+ place.id = result.insertId
528+
529+ return place
530+}
531+
532+function removePlace(place)
533+{
534+ db().transaction(
535+ function(tx) {
536+ tx.executeSql(
537+ 'delete from Place where id = ?',
538+ [ place.id ]
539+ )
540+ tx.executeSql(
541+ 'delete from Venue where placeId = ?',
542+ [ place.id ]
543+ )
544+ }
545+ )
546+
547+ delete place.id
548+}
549+
550+function addVenue(event, place)
551+{
552+ db().transaction(
553+ function(tx) {
554+ tx.executeSql(
555+ 'insert into Venue(eventId, placeId) values(?, ?)',
556+ [ event.id, place.id ]
557+ )
558+ }
559+ )
560+}
561+
562+function removeVenue(event, place)
563+{
564+ db().transaction(
565+ function(tx) {
566+ tx.executeSql(
567+ 'delete from Venue where eventId = ? and placeId = ?',
568+ [ event.id, place.id ]
569+ )
570+ }
571+ )
572+}
573+
574+function getVenues(event, venues)
575+{
576+ var result = null
577+
578+ db().readTransaction(
579+ function(tx) {
580+ result = tx.executeSql('\
581+select p.* \
582+from Venue v, Place p \
583+where v.eventId = ? and p.id = v.placeId \
584+order by p.name',
585+ [ event.id ]
586+ )
587+ }
588+ )
589+
590+ venues = venues || []
591+
592+ for (var i = 0; i < result.rows.length; ++i)
593+ venues.append(result.rows.item(i))
594+
595+ return venues
596+}
597+
598+function printEvent(event)
599+{
600+ console.log('Event', event)
601+ console.log(' id:', event.id)
602+ console.log(' title:', event.title)
603+ console.log(' message:', event.message)
604+ console.log(' startTime:', new Date(event.startTime).toLocaleString())
605+ console.log(' endTime:', new Date(event.endTime).toLocaleString())
606+
607+ var attendees = []
608+ var venues = []
609+ getAttendees(event, attendees)
610+ getVenues(event, venues)
611+ for (var j = 0; j < attendees.length; ++j)
612+ printContact(attendees[j])
613+ for (var j = 0; j < venues.length; ++j)
614+ printPlace(venues[j])
615+ console.log('')
616+}
617+
618+function printContact(contact)
619+{
620+ console.log('Contact', contact)
621+ console.log(' id:', contact.id)
622+ console.log(' name:', contact.name)
623+ console.log(' surname:', contact.surname)
624+ console.log(' avatar:', contact.avatar)
625+}
626+
627+function printPlace(place)
628+{
629+ console.log('Place', place)
630+ console.log(' name:', place.name)
631+ console.log(' address:', place.address)
632+ console.log(' latitude:', place.latitude)
633+ console.log(' longitude:', place.longitude)
634+}
635+
636+function __createFirstTime(tx)
637+{
638+ var schema = '\
639+create table Event(\
640+ id integer primary key,\
641+ title text,\
642+ message text,\
643+ startTime integer,\
644+ endTime integer,\
645+ category text default "Events"\
646+);\
647+\
648+create index EventStartTimeIndex on Event(startTime);\
649+create index EventEndTimeIndex on Event(endTime);\
650+\
651+create table Place(\
652+ id integer primary key,\
653+ name text,\
654+ address text,\
655+ latitude real,\
656+ longitude real\
657+);\
658+\
659+create table Contact(\
660+ id integer primary key,\
661+ name text,\
662+ surname text,\
663+ avatar text\
664+);\
665+\
666+create table Attendance(\
667+ id integer primary key,\
668+ eventId integer references Event(id) on delete cascade,\
669+ contactId integer references Contact(id) on delete cascade,\
670+ placeId integer references Place(id) on delete set null\
671+);\
672+\
673+create table Venue(\
674+ id integer primary key,\
675+ eventId integer references Event(id) on delete cascade,\
676+ placeId integer references Place(id) on delete cascade\
677+);\
678+\
679+'.split(';')
680+
681+ for (var i = 0; i < schema.length; ++i) {
682+ var sql = schema[i]
683+ if (sql != "") {
684+ console.log(sql)
685+ tx.executeSql(sql)
686+ }
687+ }
688+}
689+
690+function eventsNotifier()
691+{
692+ if (!eventsNotifier.hasOwnProperty("instance"))
693+ eventsNotifier.instance = Qt.createQmlObject('import QtQuick 2.0; QtObject { signal dataChanged }', Qt.application, 'DataService.eventsNotifier()')
694+ return eventsNotifier.instance
695+}
696+
697+function db()
698+{
699+ if (!db.hasOwnProperty("instance")) {
700+ db.instance = LS.LocalStorage.openDatabaseSync("Calendar", "", "Offline Calendar", 100000)
701+ if (db.instance.version == "") db.instance.changeVersion("", "0.1", __createFirstTime)
702+ }
703+ return db.instance
704+}
705
706=== added file 'dataServiceTests.js'
707--- dataServiceTests.js 1970-01-01 00:00:00 +0000
708+++ dataServiceTests.js 2013-03-27 23:13:20 +0000
709@@ -0,0 +1,192 @@
710+.pragma library
711+.import "dateExt.js" as DateExt
712+.import "dataService.js" as DataService
713+
714+function clearData(tx) {
715+ var deletes = '\
716+delete from Event;\
717+delete from Place;\
718+delete from Contact;\
719+delete from Attendance;\
720+delete from Venue\
721+'.split(';')
722+ for (var i = 0; i < deletes.length; ++i)
723+ tx.executeSql(deletes[i])
724+}
725+
726+function loadTestDataSimple(tx)
727+{
728+ clearData(tx)
729+
730+ var inserts = '\
731+insert into Contact(id, name, surname) values (1, "John", "Smith");\
732+insert into Contact(id, name, surname) values (2, "Jane", "Smith");\
733+insert into Contact(id, name, surname, avatar) values (3, "Frank", "Mertens", "http://www.gravatar.com/avatar/6d96fd4a98bba7b8779661d5db391ab6");\
734+insert into Contact(id, name, surname) values (4, "Kunal", "Parmar");\
735+insert into Contact(id, name, surname) values (5, "Mario", "Boikov");\
736+insert into Place(id, name, address) values (1, "Quan Sen", "Pasing Arcaden, München");\
737+insert into Place(id, name, address) values (2, "Jashan", "Landsberger Straße 84, 82110 Germering");\
738+insert into Place(id, name, latitude, longitude) values (3, "Café Moskau", 52.521339, 13.42279);\
739+insert into Place(id, name, address) values (4, "Santa Clara Marriott", "2700 Mission College Boulevard, Santa Clara, California");\
740+insert into Place(id, name, address) values (5, "embeddedworld", "Messezentrum, 90471 Nürnberg");\
741+insert into Event(id, title, message, startTime, endTime) values (1, "Team Meeting", "Bring your gear...", 1364648400000, 1364650200000);\
742+insert into Event(id, title, message, startTime, endTime) values (2, "Jane\'s Birthday Party", "this year: southern wine", 1364061600000, 1364068800000);\
743+insert into Event(id, title, startTime, endTime) values (3, "embeddedworld 2013", 1361836800000, 1362009600000);\
744+insert into Attendance(eventId, contactId, placeId) values (1, 1, 1);\
745+insert into Attendance(eventId, contactId, placeId) values (1, 2, 1);\
746+insert into Attendance(eventId, contactId, placeId) values (1, 3, 1);\
747+insert into Attendance(eventId, contactId, placeId) values (1, 4, 3);\
748+insert into Attendance(eventId, contactId, placeId) values (1, 5, 3);\
749+insert into Attendance(eventId, contactId) values (2, 1);\
750+insert into Attendance(eventId, contactId) values (2, 2);\
751+insert into Attendance(eventId, contactId) values (2, 3);\
752+insert into Venue(eventId, placeId) values (2, 3);\
753+insert into Venue(eventId, placeId) values (3, 5)\
754+'.split(';')
755+
756+ for (var i = 0; i < inserts.length; ++i) {
757+ var sql = inserts[i]
758+ if (sql != "") {
759+ console.log(sql)
760+ tx.executeSql(sql)
761+ }
762+ }
763+}
764+
765+function loadTestDataComplex(tx)
766+{
767+ clearData(tx)
768+
769+ function t(d, h, m) {
770+ if (typeof t.today == "undefined") t.today = new Date().midnight()
771+ return t.today.addDays(d).setHours(h, m)
772+ }
773+
774+ var places = [
775+ { id: 1, name: "Moskau A" },
776+ { id: 2, name: "Moskau B" },
777+ { id: 3, name: "Bischkek" },
778+ { id: 4, name: "Asgabat A" },
779+ { id: 5, name: "Asgabat B" },
780+ { id: 6, name: "Vilnius" },
781+ { id: 7, name: "Riga" }
782+ ]
783+
784+ var speaker = [
785+ { id: 1, name: "Sean", surname: "Harmer" },
786+ { id: 2, name: "Marc", surname: "Lutz" },
787+ { id: 3, name: "David", surname: "Faure" },
788+ { id: 4, name: "Volker", surname: "Krause" },
789+ { id: 5, name: "Kevin", surname: "Krammer" },
790+ { id: 6, name: "Tobias", surname: "Nätterlund" },
791+ { id: 7, name: "Steffen", surname: "Hansen" },
792+ { id: 8, name: "Tommi", surname: "Laitinen" },
793+ { id: 9, name: "Lars", surname: "Knoll" },
794+ { id: 10, name: "Roland", surname: "Krause" },
795+ { id: 11, name: "Jens", surname: "Bache-Wiig" },
796+ { id: 12, name: "Michael", surname: "Wagner" },
797+ { id: 13, name: "Helmut", surname: "Sedding" },
798+ { id: 14, name: "Jeff", surname: "Tranter" },
799+ { id: 15, name: "Simon", surname: "Hausmann" },
800+ { id: 16, name: "Stephen", surname: "Kelly" },
801+ { id: 17, name: "Tam", surname: "Hanna" },
802+ { id: 18, name: "Mirko", surname: "Boehm" },
803+ { id: 19, name: "Till", surname: "Adam" },
804+ { id: 20, name: "Thomas", surname: "Senyk" }
805+ ]
806+
807+ var events = [
808+ { id: 1, room: 1, speaker: [ 1 ], title: "Modern OpenGL with Qt5", message: "hands-on training", startTime: t(0, 10, 00), endTime: t(0, 12 ,00) },
809+ { id: 2, room: 2, speaker: [ 2 ], title: "What's new in C++11", message: "focus on Qt5", startTime: t(0, 13, 00), endTime: t(0, 14, 30) },
810+ { id: 3, room: 3, speaker: [ 3 ], title: "Model/view Programming using Qt", message: "hands-on training", startTime: t(0, 14, 45), endTime: t(0, 16, 15) },
811+ { id: 4, room: 4, speaker: [ 4 ], title: "Introduction to Qt Quick", message: "hands-on training", startTime: t(0, 16, 30), endTime: t(0, 17, 45) },
812+ { id: 5, room: 1, speaker: [ 8 ], title: "Keynote: Qt – Gearing up for the Future", message: "", startTime: t(1, 9, 15), endTime: t(1, 9, 30) },
813+ { id: 6, room: 1, speaker: [ 9 ], title: "Keynote: Qt 5 Roadmap", message: "", startTime: t(1, 9, 30), endTime: t(1, 10, 30) },
814+ { id: 7, room: 3, speaker: [ 10 ], title: "Qt and the Google APIs", message: "", startTime: t(1, 10, 45), endTime: t(1, 11, 45) },
815+ { id: 8, room: 7, speaker: [ 11 ], title: "Desktop Components for QtQuick", message: "", startTime: t(1, 10, 45), endTime: t(1, 11, 45) },
816+ { id: 9, room: 2, speaker: [ 9 ], title: "The Future of Qt on Embedded Linux", message: "", startTime: t(1, 12, 45), endTime: t(1, 13, 45) },
817+ { id: 10, room: 7, speaker: [ 12, 13 ], title: "QML for desktop apps", message: "", startTime: t(1, 12, 45), endTime: t(1, 13, 34) },
818+ { id: 11, room: 2, speaker: [ 14 ], title: "Qt on Raspberry Pi", message: "", startTime: t(1, 14, 00), endTime: t(1, 15, 00) },
819+ { id: 12, room: 3, speaker: [ 15 ], title: "What's new in QtWebKit in 5.0", message: "", startTime: t(1, 14, 00), endTime: t(1, 15, 00) },
820+ { id: 13, room: 1, speaker: [ 16 ], title: "In Depth – QMetaType and QMetaObject", message: "", startTime: t(1, 15, 30), endTime: t(1, 16, 30) },
821+ { id: 14, room: 2, speaker: [ 17 ], title: "Using Qt as mobile cross-platform system", message: "", startTime: t(1, 15, 30), endTime: t(1, 16, 30) },
822+ { id: 15, room: 1, speaker: [ 18, 19 ], title: "Intentions good, warranty void: Using Qt in unexpected ways", message: "", startTime: t(1, 16, 45), endTime: t(1, 17, 45) },
823+ { id: 16, room: 2, speaker: [ 20 ], title: "Porting Qt 5 to embedded hardware", message: "", startTime: t(1, 16, 45), endTime: t(1, 17, 45) }
824+ ]
825+
826+ for (var i = 0; i < places.length; ++i) {
827+ var p = places[i]
828+ tx.executeSql(
829+ 'insert into Place(id, name, address) values (?, ?, ?)',
830+ [ p.id, p.name, "Cafe Moskau, Berlin, Germany" ]
831+ )
832+ }
833+
834+ for (var i = 0; i < speaker.length; ++i) {
835+ var s = speaker[i]
836+ tx.executeSql(
837+ 'insert into Contact(id, name, surname) values (?, ?, ?)',
838+ [ s.id, s.name, s.surname ]
839+ )
840+ }
841+
842+ for (var i = 0; i < events.length; ++i) {
843+ var e = events[i]
844+ tx.executeSql(
845+ 'insert into Event(id, title, message, startTime, endTime) values (?, ?, ?, ?, ?)',
846+ [ e.id, e.title, e.message, e.startTime, e.endTime ]
847+ )
848+ tx.executeSql(
849+ 'insert into Venue(eventId, placeId) values (?, ?)',
850+ [ e.id, e.room ]
851+ )
852+ for (var j = 0; j < e.speaker.length; ++j) {
853+ tx.executeSql(
854+ 'insert into Attendance(eventId, contactId) values (?, ?)',
855+ [ e.id, e.speaker[j] ]
856+ )
857+ }
858+ }
859+}
860+
861+function runTestSimple(tx)
862+{
863+ loadTestDataSimple(tx)
864+
865+ var contacts = []
866+ DataService.getContacts(contacts)
867+ for (var i = 0; i < contacts.length; ++i)
868+ DataService.printContact(contacts[i])
869+ console.log('')
870+
871+ var testEvent = DataService.addEvent({
872+ title: 'Critical Review',
873+ message: '',
874+ startTime: new Date(2013, 2, 30, 10, 00).getTime(),
875+ endTime: new Date(2013, 2, 30, 10, 30).getTime()
876+ })
877+ DataService.addAttendee(testEvent, contacts[1])
878+ DataService.addAttendee(testEvent, contacts[2])
879+ DataService.addAttendee(testEvent, contacts[0])
880+ DataService.removeAttendee(testEvent, contacts[0])
881+ var testPlace = DataService.addPlace({ name: 'Jane\'s bar' })
882+ DataService.addVenue(testEvent, testPlace)
883+ console.log('Added new event with id', testEvent.id)
884+ console.log('')
885+
886+ var events = []
887+ var dayStart = new Date(2013, 2, 30)
888+ DataService.getEvents(dayStart.getTime(), dayStart.addDays(1).getTime(), events)
889+ for (var i = 0; i < events.length; ++i)
890+ DataService.printEvent(events[i])
891+
892+ DataService.removeEvent(testEvent)
893+ DataService.removePlace(testPlace)
894+}
895+
896+DataService.db().transaction(
897+ function (tx) {
898+ runTestSimple(tx)
899+ loadTestDataComplex(tx)
900+ }
901+)
902
903=== renamed file 'DateLib.js' => 'dateExt.js'
904=== added file 'icon-contacts@8.png'
905Binary files icon-contacts@8.png 1970-01-01 00:00:00 +0000 and icon-contacts@8.png 2013-03-27 23:13:20 +0000 differ
906=== added file 'icon-location@18.png'
907Binary files icon-location@18.png 1970-01-01 00:00:00 +0000 and icon-location@18.png 2013-03-27 23:13:20 +0000 differ

Subscribers

People subscribed via source and target branches

to status/vote changes: