← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~renatofilho/ubuntu-calendar-app/optimize into lp:ubuntu-calendar-app

 

Renato Araujo Oliveira Filho has proposed merging lp:~renatofilho/ubuntu-calendar-app/optimize into lp:ubuntu-calendar-app with lp:~renatofilho/ubuntu-calendar-app/optimize-page-load as a prerequisite.

Commit message:
Optimize Application;
Rewrite event layout functions;
Fixed several bugs;

Requested reviews:
  Jenkins Bot (ubuntu-core-apps-jenkins-bot): continuous-integration
  Kunal Parmar (pkunal-parmar)
  Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot): continuous-integration

For more details, see:
https://code.launchpad.net/~renatofilho/ubuntu-calendar-app/optimize/+merge/283858
-- 
Your team Ubuntu Calendar Developers is subscribed to branch lp:ubuntu-calendar-app.
=== modified file 'AgendaView.qml'
--- AgendaView.qml	2016-02-03 08:06:25 +0000
+++ AgendaView.qml	2016-03-03 21:42:32 +0000
@@ -23,16 +23,14 @@
 import "dateExt.js" as DateExt
 import "./3rd-party/lunar.js" as Lunar
 
-Page{
+PageWithBottomEdge {
     id: root
     objectName: "AgendaView"
 
-    property var currentDay: new Date()
+    property var anchorDate: new Date()
 
     signal dateSelected(var date);
 
-    Keys.forwardTo: [eventList]
-
     function goToBeginning() {
         eventList.positionViewAtBeginning();
     }
@@ -45,13 +43,17 @@
         return !!enabled_calendars.length;
     }
 
+
+    Keys.forwardTo: [eventList]
+    createEventAt: anchorDate
+
     Action {
         id: calendarTodayAction
         objectName:"todaybutton"
         iconName: "calendar-today"
         text: i18n.tr("Today")
         onTriggered: {
-            currentDay = new Date()
+            anchorDate = new Date()
             goToBeginning()
         }
     }
@@ -63,7 +65,6 @@
         leadingActionBar.actions: tabs.tabsAction
         trailingActionBar.actions: [
             calendarTodayAction,
-            commonHeaderActions.newEventAction,
             commonHeaderActions.showCalendarAction,
             commonHeaderActions.reloadAction,
             commonHeaderActions.syncCalendarAction,
@@ -74,9 +75,9 @@
 
     EventListModel {
         id: eventListModel
-        startPeriod: currentDay.midnight();
-        endPeriod: currentDay.addDays(7).endOfDay()
-        filter: eventModel.filter
+        startPeriod: anchorDate.midnight();
+        endPeriod: anchorDate.addDays(7).endOfDay()
+        filter: model.filter
 
         sortOrders: [
             SortOrder{
@@ -106,7 +107,7 @@
 
             return default_title;
         }
-        visible: (eventListModel.count === 0) && !eventListModel.isLoading
+        visible: (eventList.count === 0) && !eventListModel.isLoading
         anchors.centerIn: parent
     }
 
@@ -119,12 +120,12 @@
         color: UbuntuColors.orange
 
         onClicked: {
-            pageStack.push(Qt.resolvedUrl("CalendarChoicePopup.qml"),{"model":eventModel});
-            pageStack.currentPage.collectionUpdated.connect(eventModel.delayedApplyFilter);
+            pageStack.push(Qt.resolvedUrl("CalendarChoicePopup.qml"),{"model": model});
+            pageStack.currentPage.collectionUpdated.connect(model.delayedApplyFilter);
         }
     }
 
-    ListView{
+    ListView {
         id: eventList
         objectName: "eventList"
         model: eventListModel

=== modified file 'AllDayEventComponent.qml'
--- AllDayEventComponent.qml	2016-02-03 08:06:25 +0000
+++ AllDayEventComponent.qml	2016-03-03 21:42:32 +0000
@@ -31,12 +31,14 @@
     property var allDayEvents;
     property var model;
 
+    signal pressAndHold(var date)
+
     width: parent.width
     height: units.gu(5)
 
     function getAllDayEvents(startDate, endDate) {
         var map = {};
-        var items = model.getItems(startDate,endDate);
+        var items = model.itemsByTimePeriod(startDate,endDate);
         for(var i = 0 ; i < items.length ; ++i) {
             var event = items[(i)];
             if( event && event.allDay ) {
@@ -62,6 +64,10 @@
     }
 
     Repeater{
+        id: repeater
+
+        readonly property bool compactView: (root.width  / repeater.count) < units.gu(15)
+
         model: type == ViewType.ViewTypeWeek ? 7 : 1
         delegate: Item {
             id: allDayButton
@@ -71,29 +77,86 @@
             height: units.gu(5)
             width: parent.width / (type == ViewType.ViewTypeWeek ? 7 : 1)
 
+            Rectangle {
+                id: temporaryEvent
+
+                anchors.fill: parent
+                visible: mouseArea.mouseHold
+                Label {
+                    anchors.fill: parent
+                    verticalAlignment: Text.AlignVCenter
+                    horizontalAlignment: Text.AlignHCenter
+                    text:  i18n.tr("New event")
+                }
+                z: 100
+            }
+
             MouseArea {
+                id: mouseArea
+
+                property bool mouseHold: false
+
+                preventStealing: mouseHold
                 anchors.fill: parent
                 onClicked: {
                     if(!allDayButton.events || allDayButton.events.length === 0) {
                         return;
                     }
 
-                    if(type == ViewType.ViewTypeWeek) {
-                        PopupUtils.open(popoverComponent, root,{"events": allDayButton.events})
+                    if(repeater.compactView) {
+                        PopupUtils.open(popoverComponent, allDayButton,{"events": allDayButton.events})
                     } else {
                         if( allDayButton.events.length > 1 ) {
-                            PopupUtils.open(popoverComponent, root,{"events": allDayButton.events})
+                            PopupUtils.open(popoverComponent, allDayButton,{"events": allDayButton.events})
                         } else {
                             pageStack.push(Qt.resolvedUrl("EventDetails.qml"),{"event":allDayButton.events[0],"model": root.model});
                         }
                     }
                 }
+
+                onReleased: {
+                    if (mouseHold && containsMouse) {
+                        root.pressAndHold(startDay.midnight().addDays(index))
+                    }
+                    mouseHold = false
+                }
+
+
+                onPressAndHold: {
+                    mouseHold = true
+                    Haptics.play()
+                }
             }
 
-            Loader {
-                id: eventLabelLoader
-                anchors.fill: parent
-                sourceComponent : !allDayButton.events || allDayButton.events.length === 0 ? undefined : eventComponent
+            Label {
+                id: eventLabel
+                anchors {
+                    fill: parent
+                    margins: units.gu(0.5)
+                }
+                verticalAlignment: Text.AlignVCenter
+                horizontalAlignment: Text.AlignHCenter
+                elide: Text.ElideRight
+                text: {
+                    if(!events || events.length === 0) {
+                        return "";
+                    }
+
+                    if(repeater.compactView) {
+                        // TRANSLATORS: the first parameter refers to the number of all-day events
+                        // on a given day. "Ev." is short form for "Events".
+                        // Please keep the translation of "Ev." to 3 characters only, as the week view
+                        // where it's shown has limited space
+                        return i18n.tr("%1 ev.").arg(events.length)
+                    } else {
+                        if( events.length > 1) {
+                           // TRANSLATORS: the argument refers to the number of all day events
+                           return i18n.tr("%1 all day event", "%1 all day events", events.length).arg(events.length)
+                        } else {
+                            return events[0].displayLabel;
+                        }
+                    }
+                }
             }
 
             Loader{
@@ -110,39 +173,11 @@
                     sd = sd.addDays(index);
                     var key  = Qt.formatDateTime(sd, "dd-MMM-yyyy");
                     events = allDayEvents[key];
-
-                    if(!events || events.length === 0) {
-                        return;
-                    }
-
-                    if(type == ViewType.ViewTypeWeek) {
-                        // TRANSLATORS: the first parameter refers to the number of all-day events
-                        // on a given day. "Ev." is short form for "Events".
-                        // Please keep the translation of "Ev." to 3 characters only, as the week view
-                        // where it's shown has limited space
-                        eventLabelLoader.item.text =  i18n.tr("%1 ev.").arg(events.length)
-                    } else {
-                        if( events.length > 1) {
-                           // TRANSLATORS: the argument refers to the number of all day events
-                           eventLabelLoader.item.text = i18n.tr("%1 all day event", "%1 all day events", events.length).arg(events.length)
-                        } else {
-                            eventLabelLoader.item.text = events[0].displayLabel;
-                        }
-                    }
                 }
             }
         }
     }
 
-
-    Component{
-        id: eventComponent
-        Label {
-            verticalAlignment: Text.AlignVCenter
-            horizontalAlignment: Text.AlignHCenter
-        }
-    }
-
     Component {
         id: dividerComponent
         SimpleDivider{

=== modified file 'ContactChoicePopup.qml'
--- ContactChoicePopup.qml	2016-01-29 14:35:14 +0000
+++ ContactChoicePopup.qml	2016-03-03 21:42:32 +0000
@@ -17,7 +17,7 @@
  */
 import QtQuick 2.4
 import Ubuntu.Components 1.3
-import Ubuntu.Components.Popups 1.0
+import Ubuntu.Components.Popups 1.3
 import Ubuntu.Components.ListItems 1.0
 import Ubuntu.Components.Themes.Ambiance 1.0
 import QtOrganizer 5.0
@@ -29,7 +29,7 @@
     id: root
     objectName: "contactPopover"
 
-    signal contactSelected(var contact);
+    signal contactSelected(var contact, string emailAddress);
 
     Label {
         id: noContact
@@ -40,24 +40,27 @@
 
     UnionFilter {
         id: filter
+
+        property string searchString: ""
+
         filters: [
             DetailFilter{
                 detail: ContactDetail.Name
                 field: Name.FirstName
                 matchFlags: Filter.MatchContains
-                value: searchBox.text
+                value: filter.searchString
             },
             DetailFilter{
                 detail: ContactDetail.Name
                 field: Name.LastName
                 matchFlags: Filter.MatchContains
-                value: searchBox.text
+                value: filter.searchString
             },
             DetailFilter{
                 detail: ContactDetail.DisplayLabel
                 field: DisplayLabel.Label
                 matchFlags: Filter.MatchContains
-                value: searchBox.text
+                value: filter.searchString
             }
         ]
     }
@@ -69,6 +72,16 @@
         autoUpdate: true
     }
 
+    Timer {
+        id: idleSearch
+
+        interval: 500
+        repeat: false
+        onTriggered: {
+            filter.searchString = searchBox.text
+        }
+    }
+
     Column {
         anchors.top: parent.top
         anchors.left: parent.left
@@ -81,12 +94,16 @@
             focus: true
             width: parent.width
             placeholderText: i18n.tr("Search contact")
+            inputMethodHints: Qt.ImhNoPredictiveText
             primaryItem: Icon {
                  height: parent.height*0.5
                  width: parent.height*0.5
                  anchors.verticalCenter: parent.verticalCenter
                  name:"find"
-             }
+            }
+            onTextChanged: {
+                idleSearch.restart()
+            }
         }
 
         ListView {
@@ -96,17 +113,42 @@
             model: contactModel
             height: units.gu(15)
             clip: true
-            delegate: Standard{
-                objectName: "contactPopoverList%1".arg(index)
-                property var item: contactModel.contacts[index]
-                height: units.gu(4)
-                text: item ? item.displayLabel.label : ""
-
-                onClicked: {
-                    root.contactSelected(item);
-                    onClicked: PopupUtils.close(root)
+            focus: false
+            delegate: Column {
+                width: contactList.width
+                Repeater {
+                    anchors {
+                        left: parent.left
+                        right: parent.right
+                    }
+                    height: childrenRect.height
+
+                    model: Math.max(1, contact.emails.length)
+                    delegate: ListItem {
+                        property string emailAddress: contact.emails.length > index ? contact.emails[index].emailAddress : ""
+
+                        activeFocusOnPress: false
+                        opacity: emailAddress.length > 0 ? 1.0 : 0.3
+                        width: contactList.width
+                        objectName: "contactPopoverList%1".arg(index)
+                        ListItemLayout {
+                            title.text: contact.displayLabel.label
+                            subtitle.text: emailAddress
+                        }
+                        MouseArea {
+                            anchors.fill: parent
+                            onClicked: {
+                                if (emailAddress.length > 0) {
+                                    root.contactSelected(contact, emailAddress);
+                                    PopupUtils.close(root)
+                                }
+                            }
+                        }
+                    }
                 }
             }
         }
     }
+
+    Component.onCompleted: searchBox.forceActiveFocus()
 }

=== modified file 'DayView.qml'
--- DayView.qml	2016-02-03 08:06:25 +0000
+++ DayView.qml	2016-03-03 21:42:32 +0000
@@ -18,21 +18,51 @@
 
 import QtQuick 2.4
 import Ubuntu.Components 1.3
+
 import "dateExt.js" as DateExt
 import "ViewType.js" as ViewType
 import "./3rd-party/lunar.js" as Lunar
 
-Page{
+PageWithBottomEdge {
     id: dayViewPage
     objectName: "dayViewPage"
 
-    property var currentDay: new Date()
-    property bool isCurrentPage: false
+
+    property var anchorDate: new Date()
+    readonly property var currentDate: dayViewPath.currentItem.startDay
 
     signal dateSelected(var date);
+    signal pressAndHoldAt(var date, bool allDay)
+
+    function delayScrollToDate(date, scrollTime) {
+        idleScroll.scrollToTime = scrollTime != undefined ? scrollTime : true
+        idleScroll.scrollToDate = new Date(date)
+        idleScroll.restart()
+    }
 
     Keys.forwardTo: [dayViewPath]
-    flickable: null
+
+    createEventAt: currentDate
+    onAnchorDateChanged: {
+        dayViewPath.scrollToBegginer()
+    }
+
+    onEventCreated: {
+        var scrollDate = new Date(event.startDateTime)
+        var needScroll = false
+        if ((currentDate.getFullYear() !== scrollDate.getFullYear()) ||
+            (currentDate.getMonth() !== scrollDate.getMonth()) ||
+            (currentDate.getDate() !== scrollDate.getDate())) {
+            anchorDate = new Date(scrollDate)
+            needScroll = true
+        } else if (!dayViewPath.currentItem.timeIsVisible(scrollDate)) {
+            needScroll = true
+        }
+
+        if (needScroll) {
+            delayScrollToDate(scrollDate, !event.allDay)
+        }
+    }
 
     Action {
         id: calendarTodayAction
@@ -40,17 +70,38 @@
         iconName: "calendar-today"
         text: i18n.tr("Today")
         onTriggered: {
-            currentDay = new Date()
+            anchorDate = new Date()
+            delayScrollToDate(anchorDate)
+        }
+    }
+
+
+    Timer {
+        id: idleScroll
+
+        property var scrollToDate: null
+        property bool scrollToTime: true
+
+        interval: 200
+        repeat:false
+        onTriggered: {
+            if (scrollToDate && scrollToTime) {
+                dayViewPath.currentItem.scrollToTime(scrollToDate)
+            } else {
+                dayViewPath.currentItem.scrollToBegin()
+            }
+            scrollToDate = null
+            scrollToTime = true
         }
     }
 
     header: PageHeader {
         id: pageHeader
 
+        flickable: null
         leadingActionBar.actions: tabs.tabsAction
         trailingActionBar.actions: [
             calendarTodayAction,
-            commonHeaderActions.newEventAction,
             commonHeaderActions.showCalendarAction,
             commonHeaderActions.reloadAction,
             commonHeaderActions.syncCalendarAction,
@@ -61,87 +112,82 @@
             // TRANSLATORS: this is a time formatting string,
             // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
             // It's used in the header of the month and week views
-            var monthName = currentDay.toLocaleString(Qt.locale(),i18n.tr("MMMM yyyy"))
+            var monthName = currentDate.toLocaleString(Qt.locale(),i18n.tr("MMMM yyyy"))
             return monthName[0].toUpperCase() + monthName.substr(1, monthName.length - 1)
         }
+    }
 
+    onBottomEdgeCommitStarted: {
+        var eventAt = new Date()
+        if (dayViewPath.currentItem) {
+            eventAt.setFullYear(currentDate.getFullYear())
+            eventAt.setMonth(currentDate.getMonth())
+            eventAt.setDate(currentDate.getDate())
+        }
+        createEventAt = eventAt
     }
 
     PathViewBase{
         id: dayViewPath
         objectName: "dayViewPath"
 
-        property var startDay: currentDay
+        property var startDay: currentDate
         //This is used to scroll all view together when currentItem scrolls
-        property var childContentY;
+        property real childContentY;
 
         anchors {
             fill: parent
             topMargin: header.height
         }
 
-        onNextItemHighlighted: {
-            //next day
-            currentDay = currentDay.addDays(1);
-        }
-
-        onPreviousItemHighlighted: {
-            //previous day
-            currentDay = currentDay.addDays(-1);
-        }
-
-        delegate: Loader {
+        delegate: TimeLineBaseComponent {
+            id: timeLineView
+            objectName: "DayComponent-"+index
+
             width: parent.width
             height: parent.height
-            asynchronous: !dayViewPath.isCurrentItem
-            sourceComponent: delegateComponent
-
-            Component {
-                id: delegateComponent
-
-                TimeLineBaseComponent {
-                    id: timeLineView
-                    objectName: "DayComponent-"+index
-
-                    type: ViewType.ViewTypeDay
-                    anchors.fill: parent
-
-                    isActive: parent.PathView.isCurrentItem
-                    contentInteractive: parent.PathView.isCurrentItem
-                    startDay: dayViewPath.startDay.addDays(dayViewPath.indexType(index))
-                    keyboardEventProvider: dayViewPath
-
-                    Component.onCompleted: {
-                        if(dayViewPage.isCurrentPage){
-                            timeLineView.scrollToCurrentTime();
-                        }
-                    }
-
-                    Connections{
-                        target: dayViewPage
-                        onIsCurrentPageChanged:{
-                            if(dayViewPage.isCurrentPage){
-                                timeLineView.scrollToCurrentTime();
-                            }
-                        }
-                    }
-
-                    //get contentY value from PathView, if its not current Item
-                    Binding{
-                        target: timeLineView
-                        property: "contentY"
-                        value: dayViewPath.childContentY;
-                        when: !parent.PathView.isCurrentItem
-                    }
-
-                    //set PathView's contentY property, if its current item
-                    Binding{
-                        target: dayViewPath
-                        property: "childContentY"
-                        value: contentY
-                        when: parent.PathView.isCurrentItem
-                    }
-                }
+
+            type: ViewType.ViewTypeDay
+            isCurrentItem: PathView.isCurrentItem
+            isActive: !dayViewPath.moving && !dayViewPath.flicking
+            contentInteractive: PathView.isCurrentItem
+            startDay: anchorDate.addDays(dayViewPath.loopCurrentIndex + dayViewPath.indexType(index))
+            keyboardEventProvider: dayViewPath
+            modelFilter: dayViewPage.model ? dayViewPage.model.filter : null
+
+            onPressAndHoldAt: {
+                dayViewPage.pressAndHoldAt(date, allDay)
+            }
+
+            Component.onCompleted: {
+                if(dayViewPage.tabSelected){
+                    idleScroll.restart()
+                }
+            }
+
+            Connections{
+                target: dayViewPage
+                onTabSelectedChanged: {
+                    if(tabSelected){
+                        timeLineView.scrollToTime(new Date());
+                    }
+                }
+            }
+
+            //get contentY value from PathView, if its not current Item
+            Binding{
+                target: timeLineView
+                property: "contentY"
+                value: dayViewPath.childContentY;
+                when: !timeLineView.isCurrentItem
+            }
+
+            //set PathView's contentY property, if its current item
+            Binding{
+                target: dayViewPath
+                property: "childContentY"
+                value: timeLineView.contentY
+                when: timeLineView.isCurrentItem
             }
         }
     }

=== modified file 'EventActions.qml'
--- EventActions.qml	2016-02-01 19:49:33 +0000
+++ EventActions.qml	2016-03-03 21:42:32 +0000
@@ -23,7 +23,6 @@
 Item {
     id: actionPool
 
-    property alias newEventAction: _newEventAction
     property alias showCalendarAction: _showCalendarAction
     property alias syncCalendarAction: _syncCalendarAction
     property alias settingsAction: _settingsAction
@@ -44,17 +43,6 @@
         id: syncMonitor
     }
 
-    Action {
-        id: _newEventAction
-        objectName: "neweventbutton"
-        name: "neweventbutton"
-        iconName: "new-event"
-        text: i18n.tr("New Event")
-        onTriggered: {
-            pageStack.push(Qt.resolvedUrl("NewEvent.qml"),{"date":tabs.currentDay,"model":eventModel});
-        }
-    }
-
     Action{
         id: _showCalendarAction
         objectName: "calendarsbutton"

=== modified file 'EventBubble.qml'
--- EventBubble.qml	2016-01-29 14:35:14 +0000
+++ EventBubble.qml	2016-03-03 21:42:32 +0000
@@ -20,56 +20,34 @@
 import Ubuntu.Components 1.3
 import QtOrganizer 5.0
 
+import "calendar_canvas.js" as CanlendarCanvas
+
 Item{
     id: infoBubble
 
+    property var anchorDate;
     property var event;
     property var model;
-
+    property int depthInRow: 0
+    property real sizeOfRow:0.0
+    property real minuteHeight: 1.0
     property int type: narrowType
     property int wideType: 1;
     property int narrowType: 2;
-
-    property int depthInRow: 0;
-    property int sizeOfRow:0
-
     property bool isLiveEditing: false
-
     property Flickable flickable;
+    property bool isEventBubble: true
 
     readonly property int minimumHeight: type == wideType
                                          ? detailsItems.timeLabelHeight + /*top-bottom margin*/ units.gu(2)
                                          : units.gu(2)
 
-    z: depthInRow
+    readonly property real startTimeInMinutes: event ? CanlendarCanvas.minutesSince(infoBubble.anchorDate, event.startDateTime) : 0.0
+    readonly property real endTimeInMinutes: event ? CanlendarCanvas.minutesSince(infoBubble.anchorDate, event.endDateTime) : 0.0
+    readonly property real durationInMinutes: endTimeInMinutes - startTimeInMinutes
 
     signal clicked(var event);
 
-    Rectangle{
-        id: bg
-        anchors.fill: parent
-        border.color: isLiveEditing ? "red" : "white"
-    }
-
-    function resize() {
-        var offset = parent.width/sizeOfRow;
-        x = (depthInRow) * offset;
-        width = parent.width - x;
-    }
-
-    Connections{
-        target: parent
-        onWidthChanged:{
-            resize();
-        }
-    }
-
-    onEventChanged: {
-        resize();
-        assingnBgColor();
-        setDetails();
-    }
-
     function assingnBgColor() {
         if (model && event ) {
             var collection = model.collection( event.collectionId );
@@ -102,20 +80,6 @@
         }
     }
 
-    function layoutBubbleDetails() {
-        if( !flickable || flickable === undefined ) {
-            return;
-        }
-
-        if( infoBubble.y < flickable.contentY && infoBubble.height > flickable.height) {
-            var y = (flickable.contentY - infoBubble.y) * 1.2;
-            if( ( y + detailsItems.height + units.gu(2)) > infoBubble.height) {
-                y = infoBubble.height - detailsItems.height - units.gu(2);
-            }
-            detailsItems.y = y;
-        }
-    }
-
     function setDetails() {
         if(event === null || event === undefined) {
             return;
@@ -153,8 +117,38 @@
             timeLabel.horizontalAlignment = Text.AlignHCenter
             timeLabel.wrapMode = Text.WrapAtWordBoundaryOrAnywhere
         }
-
-        layoutBubbleDetails();
+    }
+
+    function resize()
+    {
+        width = parent ? parent.width * sizeOfRow : 0
+        x = depthInRow * width
+        z = depthInRow
+        height = Math.max(30, (durationInMinutes * parent.minuteHeight))
+    }
+
+    onEventChanged: {
+        assingnBgColor();
+        setDetails();
+        resize()
+    }
+
+    Connections {
+        target: parent
+        onWidthChanged: resize()
+    }
+
+    Binding {
+        target: infoBubble
+        property: "y"
+        value: (startTimeInMinutes * parent.minuteHeight)
+        when: !infoBubble.isLiveEditing
+    }
+
+    Rectangle{
+        id: bg
+        anchors.fill: parent
+        border.color: isLiveEditing ? "red" : "white"
     }
 
     Item {
@@ -193,25 +187,6 @@
                 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
             }
         }
-
-        onHeightChanged: {
-            layoutBubbleDetails();
-        }
-
-        Connections {
-            target: infoBubble
-            onFlickableChanged: {
-                if (flickable && infoBubble.height > flickable.height) {
-                    flickable.onContentYChanged.connect(layoutBubbleDetails);
-                }
-            }
-
-            onHeightChanged: {
-                if(flickable && infoBubble.height > flickable.height) {
-                    flickable.onContentYChanged.connect(layoutBubbleDetails);
-                }
-            }
-        }
     }
 
     Drag.active: dragArea.drag.active
@@ -219,11 +194,19 @@
     MouseArea {
         id: dragArea
         anchors.fill: parent
-        drag.target: isLiveEditing ? infoBubble : null
-        drag.axis: Drag.YAxis
-        drag.minimumY: flickable ? flickable.y : 0
-        drag.maximumY: flickable ? flickable.contentHeight - infoBubble.height : infoBubble.height
-        onReleased: parent.Drag.drop()
+        drag {
+            target: isLiveEditing ? infoBubble : null
+            axis: Drag.YAxis
+            minimumY: flickable ? flickable.y : 0
+            maximumY: flickable ? flickable.contentHeight - infoBubble.height : infoBubble.height
+        }
+        onReleased: {
+            if (isLiveEditing) {
+                isLiveEditing = false;
+                infoBubble.z -= 1;
+            }
+            parent.Drag.drop()
+        }
         onClicked: {
             if( isLiveEditing ) {
                 isLiveEditing = false;

=== removed file 'EventLayoutHelper.js'
--- EventLayoutHelper.js	2015-11-27 01:34:46 +0000
+++ EventLayoutHelper.js	1970-01-01 00:00:00 +0000
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2013-2014 Canonical Ltd
- *
- * This file is part of Ubuntu Calendar App
- *
- * Ubuntu Calendar App is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Ubuntu Calendar App is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-WorkerScript.onMessage = function(events) {
-
-    //returns sorted array of schedules
-    //schedule is start time and duration
-    var allSchs = processEvents(events);
-
-    while( allSchs.length > 0) {
-        var sch = allSchs.shift();
-
-        //finds all schedules overlapping with current schedule and remove from original array
-        var schs = findOverlappingSchedules(sch, allSchs);
-
-        //insert original schedule first, so array remain sorted
-        schs.unshift(sch);
-
-        //assign position to schedules with respest to their duration and  start time
-        var array = [];
-        var maxDepth = assignDepth(schs, array);
-        WorkerScript.sendMessage({ 'schedules': array,"maxDepth":maxDepth});
-    }
-}
-
-function processEvents(events) {
-    var array = [];
-    for( var i = 0; i < events.length ; ++i) {
-        var event = events[i]
-        var sch = {};
-        sch["start"] = event.startDateTime.getTime()
-        sch["duration"] = event.endDateTime - event.startDateTime
-        sch["id"] = event.id;
-        sch["depth"] = 0;
-        sortedInsert(array,sch);
-    }
-    return array;
-}
-
-//insert in to array using insertion sort
-function sortedInsert(array, sch) {
-    for(var i = array.length-1; i >=0 ; --i) {
-        var temp = array[i];
-        if( sch.duration < array[i].duration) {
-            array.splice(i+1,0,sch);
-            return;
-        }
-    }
-    array.push(sch);
-}
-
-//find all overlapping schedules respect to provided schedule
-function findOverlappingSchedules( sch, schs) {
-    var array = [];
-    var i = 0;
-    while( i < schs.length && schs.length > 0) {
-        var otherSch = schs[i];
-        if( doesOverlap(sch, otherSch) ) {
-            schs.splice(i,1);
-            array.push(otherSch);
-            sch = mergeSchedules(sch,otherSch);
-        } else {
-            i++;
-        }
-    }
-    return array;
-}
-
-//merges tow schedules and creates a schedule which is long engouth to contain both the of them
-function mergeSchedules(sch1,sch2) {
-    var sch = {};
-    sch["start"] = Math.min(sch1.start,sch2.start);
-    sch["duration"] = Math.max(sch1.duration,sch2.duration);
-    sch["depth"] = 1;
-    sch["id"] = "DUMMY";
-    return sch;
-}
-
-
-//check if two schedules overlap each other
-//is start time of one schedule is between
-//start and end time of other schedule then it's considered as overlap
-function doesOverlap( sch1, sch2) {
-    if( sch1.start >= sch2.start && sch1.start < sch2.start + sch2.duration ) {
-        return true;
-    }
-
-    if( sch2.start >= sch1.start && sch2.start < sch1.start + sch1.duration ) {
-        return true;
-    }
-
-    return false;
-}
-
-//assign depth(position) of schedule with respect to other
-function assignDepth(schs, array) {
-    var maxDepth = 0;
-    while( schs.length > 0 ) {
-        var sch = schs.shift()
-        array.push(sch);
-        var depth = findDepth(sch, schs);
-        maxDepth = Math.max(maxDepth,depth);
-    }
-    return maxDepth;
-}
-
-function findDepth( sch, schs) {
-    var maxDepth = 0;
-    for( var i = 0; i < schs.length ; ++i) {
-        var otherSch = schs[i];
-        if( doesOverlap(sch, otherSch) ) {
-            otherSch.depth ++;
-            maxDepth = Math.max(maxDepth,otherSch.depth);
-            sch = mergeSchedules(sch,otherSch);
-        }
-    }
-    return maxDepth;
-}

=== modified file 'EventListModel.qml'
--- EventListModel.qml	2016-01-25 13:20:32 +0000
+++ EventListModel.qml	2016-03-03 21:42:32 +0000
@@ -80,7 +80,6 @@
         var collections = eventModel.collections;
         for(var i = 0 ; i < collections.length ; ++i) {
             var cal = collections[i];
-            print(cal.name + " ---- " + cal.extendedMetaData("collection-readonly"));
             if( cal.extendedMetaData("collection-type") === "Calendar" &&
                     cal.extendedMetaData("collection-readonly") === false ) {
                 cals.push(cal);
@@ -90,16 +89,21 @@
     }
 
     function getDefaultCollection() {
+        var defaultCol = defaultCollection();
+        if (defaultCol.extendedMetaData("collection-selected") === true) {
+            return defaultCol
+        }
+
         var cals = getCollections();
-         for(var i = 0 ; i < cals.length ; ++i) {
+        for(var i = 0 ; i < cals.length ; ++i) {
             var cal = cals[i]
-            var val = cal.extendedMetaData("X-CAL-DEFAULT-CALENDAR")
-            if( val ) {
+            var val = cal.extendedMetaData("collection-selected")
+            if (val === true) {
                 return cal;
             }
         }
 
-        return defaultCollection();
+        return cals[0]
     }
 
     function setDefaultCollection( collectionId ) {

=== modified file 'KeyboardRectangle.qml'
--- KeyboardRectangle.qml	2016-01-25 13:20:32 +0000
+++ KeyboardRectangle.qml	2016-03-03 21:42:32 +0000
@@ -20,18 +20,12 @@
 
 Item {
     id: keyboardRect
+
     anchors.left: parent.left
     anchors.right: parent.right
     anchors.bottom: parent.bottom
     height: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
 
-    Behavior on height {
-        NumberAnimation {
-            duration: 300
-            easing.type: Easing.InOutQuad
-        }
-    }
-
     states: [
         State {
             name: "hidden"

=== modified file 'MonthComponent.qml'
--- MonthComponent.qml	2016-02-03 08:06:25 +0000
+++ MonthComponent.qml	2016-03-03 21:42:32 +0000
@@ -17,78 +17,45 @@
  */
 import QtQuick 2.4
 import Ubuntu.Components 1.3
+
 import "dateExt.js" as DateExt
 import "colorUtils.js" as Color
+import "./3rd-party/lunar.js" as Lunar
 
 Item{
     id: root
     objectName: "MonthComponent"
 
     property bool isCurrentItem;
-
-    property bool showEvents: false
-
-    property var currentMonth;
+    property int currentYear;
+    property int currentMonth;
+
     property var isYearView;
-    property var selectedDay;
-    property bool displayWeekNumber:false;
-    property bool displayLunarCalendar: false;
-
-    property string subLabelFontSize: "small"
+    property var highlightedDate;
+    property bool displayWeekNumber:false
+    property bool displayLunarCalendar: false
+
+    property alias dayLabelDelegate : dayLabelRepeater.delegate
+    property alias dateLabelDelegate : dateLabelRepeater.delegate
+    readonly property alias monthStartDate: intern.monthStart
+
     property string dayLabelFontSize: "medium"
     property string dateLabelFontSize: "large"
     property string monthLabelFontSize: "large"
     property string yearLabelFontSize: "large"
 
-    property alias dayLabelDelegate : dayLabelRepeater.delegate
-    property alias dateLabelDelegate : dateLabelRepeater.delegate
-
     signal monthSelected(var date);
     signal dateSelected(var date);
     signal dateHighlighted(var date);
 
-    //creatng timer only if we need to show events in month
-    Loader {
-        id: timerLoader
-        sourceComponent: showEvents ? timerComp : undefined
-    }
-
-    // Timer to delay creation of Model, There seems some problem fetching events if we create Model immediatly
-    Component {
-        id: timerComp
-        Timer{
-           interval: 200; running: true; repeat: false
-           onTriggered: {
-                modelLoader.sourceComponent = modelComponent
-           }
-        }
-    }
-
-    Loader{
-        id: modelLoader
-    }
-
-    Component{
-        id: modelComponent
-        EventListModel {
-            id: mainModel
-            startPeriod: intern.monthStart.midnight();
-            endPeriod: intern.monthStart.addDays((/*monthGrid.rows * cols */ 42 )-1).endOfDay()
-            filter: eventModel.filter
-            onModelChanged: {
-                intern.eventStatus = Qt.binding(function() { return mainModel.containsItems(startPeriod, endPeriod, 86400/*24*60*60*/)});
-            }
-        }
+    function updateEvents(events) {
+        intern.eventStatus = events
     }
 
     QtObject{
         id: intern
 
-        property var eventStatus;
-
-        property int curMonthDate: currentMonth.getDate()
-        property int curMonth: currentMonth.getMonth()
-        property int curMonthYear: currentMonth.getFullYear()
+        property var eventStatus: new Array(42)
 
         property var today: DateExt.today()
         property int todayDate: today.getDate()
@@ -96,36 +63,42 @@
         property int todayYear: today.getFullYear()
 
         //date from month will start, this date might be from previous month
-        property var monthStart: currentMonth.weekStart( Qt.locale().firstDayOfWeek )
+        property var currentDate: new Date(root.currentYear, root.currentMonth, 1, 0, 0, 0, 0)
+        property var monthStart: currentDate.weekStart( Qt.locale().firstDayOfWeek )
         property int monthStartDate: monthStart.getDate()
         property int monthStartMonth: monthStart.getMonth()
         property int monthStartYear: monthStart.getFullYear()
-
-        property int daysInStartMonth: Date.daysInMonth(monthStartYear, monthStartMonth)
-        property int daysInCurMonth:  Date.daysInMonth(curMonthYear,curMonth)
+        readonly property int daysInStartMonth: Date.daysInMonth(monthStartYear, monthStartMonth)
 
         //check if current month is start month
-        property bool isCurMonthStartMonth: curMonthDate === monthStartDate
-                                            && curMonth === monthStartMonth
-                                            && curMonthYear === monthStartYear
+        property bool isCurMonthStartMonth: root.currentMonth === monthStartMonth &&
+                                            root.currentYear === monthStartYear
 
         //check current month is same as today's month
-        property bool isCurMonthTodayMonth: todayYear === curMonthYear && todayMonth == curMonth
+        property bool isCurMonthTodayMonth: todayYear === root.currentYear &&
+                                            todayMonth == root.currentMonth
         //offset from current month's first date to start date of current month
         property int offset: isCurMonthStartMonth ? -1 : (daysInStartMonth - monthStartDate)
 
         property int dateFontSize: FontUtils.sizeToPixels(root.dateLabelFontSize)
         property int dayFontSize: FontUtils.sizeToPixels(root.dayLabelFontSize)
 
-        property int selectedIndex: -1
+        property int highlightedIndex: root.isCurrentItem &&
+                                       root.highlightedDate ?
+                                           intern.indexByDate(root.highlightedDate) : -1
+        property int todayIndex: root.isCurrentItem &&
+                                 isCurMonthTodayMonth ?
+                                     intern.indexByDate(intern.today) : -1
 
-        function findSelectedDayIndex(){
-            if(!selectedDay) {
+        function indexByDate(date){
+            if (!date) {
                 return -1;
             }
 
-            if( todayMonth === selectedDay.getMonth() && selectedDay.getFullYear() === todayYear){
-                return selectedDay.getDate() +
+            if ((root.currentMonth === date.getMonth()) &&
+                (root.currentYear === date.getFullYear())) {
+
+                return date.getDate() +
                        (Date.daysInMonth(monthStartYear, monthStartMonth) - monthStartDate);
             } else {
                 return -1;
@@ -133,14 +106,40 @@
         }
     }
 
-    onSelectedDayChanged: {
-        if( isCurrentItem ) {
-            intern.selectedIndex = intern.findSelectedDayIndex();
+    UbuntuShape{
+        id: todayShape
+
+        visible: (monthGrid.todayItem != null)
+        color: (monthGrid.highlightedItem === monthGrid.todayItem) ? UbuntuColors.darkGrey : UbuntuColors.orange
+        width: parent ? Math.min(parent.height, parent.width) / 1.3 : 0
+        height: width
+        parent: monthGrid.todayItem
+        anchors.centerIn: parent
+        z: -1
+        Rectangle {
+            anchors.fill: parent
+            anchors.margins: units.gu(0.5)
+            color: UbuntuColors.orange
+            radius: 5
         }
     }
 
-    onCurrentMonthChanged: {
-        intern.selectedIndex = -1;
+    UbuntuShape{
+        id: highlightedShape
+
+        visible: monthGrid.highlightedItem && (monthGrid.highlightedItem != monthGrid.todayItem)
+        color: UbuntuColors.darkGrey
+        width: parent ? Math.min(parent.height, parent.width) / 1.3 : 0
+        height: width
+        parent: monthGrid.highlightedItem
+        anchors.centerIn: parent
+        z: -1
+        Rectangle {
+            anchors.fill: parent
+            anchors.margins: units.gu(0.5)
+            color: UbuntuColors.lightGrey
+            radius: 5
+        }
     }
 
     Column{
@@ -166,9 +165,9 @@
                 ViewHeader{
                     id: monthHeader
                     anchors.fill: parent
-                    month: intern.curMonth
-                    year: intern.curMonthYear
-                    daysInMonth: intern.daysInCurMonth
+                    month: root.currentMonth
+                    year: root.currentYear
+                    daysInMonth: intern.daysInStartMonth
 
                     monthLabelFontSize: root.monthLabelFontSize
                     yearLabelFontSize: root.yearLabelFontSize
@@ -186,9 +185,11 @@
 
                 property int dayWidth: width / 7;
 
-                width: parent.width
-                anchors.horizontalCenter: parent.horizontalCenter
-                anchors.verticalCenter: parent.verticalCenter
+                anchors{
+                    left: parent.left
+                    right: parent.right
+                    verticalCenter: parent.verticalCenter
+                }
 
                 Repeater{
                     id: dayLabelRepeater
@@ -198,23 +199,75 @@
             }
         }
 
-        Grid{
+        Grid {
             id: monthGrid
             objectName: "monthGrid"
 
-            width: parent.width
-            height: parent.height - monthGrid.y
-
             property int dayWidth: width / 7 /*cols*/;
             property int dayHeight: height / 6/*rows*/;
+            readonly property var todayItem: (intern.todayIndex != -1) &&
+                                             (monthGrid.children.length > intern.todayIndex) ?
+                                               dateLabelRepeater.itemAt(intern.todayIndex) : null
+            readonly property var highlightedItem: (intern.highlightedIndex != -1) &&
+                                                   (monthGrid.children.length > intern.highlightedIndex) ?
+                                                       dateLabelRepeater.itemAt(intern.highlightedIndex) : null
 
-            rows: 6
+            anchors {
+                left: parent.left
+                right: parent.right
+            }
+            height: parent.height - monthGrid.y
             columns: 7
 
             Repeater{
                 id: dateLabelRepeater
-                model: 42 //monthGrid.rows * monthGrid.columns
-                delegate: defaultDateLabelComponent
+                model: 42
+                delegate: isYearView ? monthWithoutEventsDelegate : monthWithEventsDelegate
+            }
+        }
+    }
+
+    MouseArea {
+        id: mouseArea
+
+        function getItemAt(x, y)
+        {
+            var clickPosition = mouseArea.mapToItem(monthGrid, x, y)
+            return monthGrid.childAt(clickPosition.x, clickPosition.y)
+        }
+
+        anchors {
+            fill: column
+            topMargin: monthGrid.y
+        }
+
+        onPressAndHold: {
+            var dayItem = getItemAt(mouse.x, mouse.y)
+
+            if( dayItem.isSelected ) {
+                var selectedDate = new Date();
+                selectedDate.setFullYear(intern.monthStartYear)
+                selectedDate.setMonth(intern.monthStartMonth + 1)
+                selectedDate.setDate(dayItem.date)
+                selectedDate.setMinutes(60, 0, 0)
+                pageStack.push(Qt.resolvedUrl("NewEvent.qml"), {"date":selectedDate, "model":eventModel});
+            }
+        }
+        onClicked: {
+            var dayItem = getItemAt(mouse.x, mouse.y)
+            var selectedDate = new Date(intern.monthStartYear,
+                                        intern.monthStartMonth + 1,
+                                        dayItem.date, 0, 0, 0, 0)
+            if (root.isYearView) {
+                //If yearView is clicked then open selected MonthView
+                root.monthSelected(selectedDate);
+            } else {
+                if (dayItem.isSelected) {
+                    //If monthView is clicked then open selected DayView
+                    root.dateSelected(selectedDate);
+                } else {
+                    root.dateHighlighted(selectedDate)
+                }
             }
         }
     }
@@ -301,53 +354,9 @@
     }
 
     Component{
-        id: defaultDateLabelComponent
-        MonthComponentDateDelegate{
-            date: {
-                //try to find date from index and month's first week's first date
-                var temp = intern.daysInStartMonth - intern.offset + index
-                //date exceeds days in startMonth,
-                //this means previous month is over and we are now in current month
-                //to get actual date we need to remove number of days in startMonth
-                if( temp > intern.daysInStartMonth ) {
-                    temp = temp - intern.daysInStartMonth
-                    //date exceeds days in current month
-                    // this means date is from next month
-                    //to get actual date we need to remove number of days in current month
-                    if( temp > intern.daysInCurMonth ) {
-                        temp = temp - intern.daysInCurMonth
-                    }
-                }
-                return temp;
-            }
-
-            isCurrentMonth: {
-                //remove offset from index
-                //if index falls in 1 to no of days in current month
-                //then date is inside current month
-                var temp = index - intern.offset
-                return (temp >= 1 && temp <= intern.daysInCurMonth)
-            }
-
-            isToday: intern.todayDate == date && intern.isCurMonthTodayMonth
-
-            isSelected: showEvents && intern.selectedIndex == index
-
-            width: parent.dayWidth
-            height: parent.dayHeight
-            fontSize: intern.dateFontSize
-            showLunarCalendar:  displayLunarCalendar
-            showEvent: showEvents
-                        && intern.eventStatus !== undefined
-                        && intern.eventStatus[index] !== undefined
-                        && intern.eventStatus[index]
-        }
-    }
-
-    Component{
         id: dafaultDayLabelComponent
 
-        Label{
+        Text {
             id: weekDay
             objectName: "weekDay" + index
             width: parent.dayWidth
@@ -359,4 +368,48 @@
             color: "black"
         }
     }
+    Component {
+        id: monthWithEventsDelegate
+
+        MonthComponentWithEventsDateDelegate {
+            property var delegateDate: intern.monthStart.addDays(index)
+
+            date: delegateDate.getDate()
+            isCurrentMonth: delegateDate.getMonth() === root.currentMonth
+            showEvent: intern.eventStatus[index] === true
+            lunarData: {
+                if (!root.displayLunarCalendar)
+                    return null
+
+                var lunar = Lunar.calendar.solar2lunar(intern.monthStartYear,
+                                                       intern.monthStartMonth + 1,
+                                                       intern.monthStartDate + index)
+                if (lunar.isTerm) {
+                    return {"lunarText": lunar.Term, "isTerm" :lunar.isTerm};
+                } else {
+                    return {"lunarText": lunar.IDayCn, "isTerm" :lunar.isTerm};
+                }
+            }
+            isToday: intern.todayDate == date && intern.isCurMonthTodayMonth
+            isSelected: intern.highlightedIndex == index
+            width: monthGrid.dayWidth
+            height: monthGrid.dayHeight
+        }
+    }
+
+    Component {
+        id: monthWithoutEventsDelegate
+
+        MonthComponentDateDelegate {
+            property var delegateDate: intern.monthStart.addDays(index)
+
+            date: delegateDate.getDate()
+            isCurrentMonth: delegateDate.getMonth() === root.currentMonth
+
+            isToday: intern.todayDate == date && intern.isCurMonthTodayMonth
+            isSelected: intern.highlightedIndex == index
+            width: monthGrid.dayWidth
+            height: monthGrid.dayHeight
+        }
+    }
 }

=== modified file 'MonthComponentDateDelegate.qml'
--- MonthComponentDateDelegate.qml	2016-02-03 08:06:25 +0000
+++ MonthComponentDateDelegate.qml	2016-03-03 21:42:32 +0000
@@ -1,6 +1,5 @@
 import QtQuick 2.4
 import Ubuntu.Components 1.3
-import "./3rd-party/lunar.js" as Lunar
 
 Item{
     id: dateRootItem
@@ -8,30 +7,13 @@
     property int date;
     property bool isCurrentMonth;
     property bool isToday;
-    property bool showEvent;
-    property bool showLunarCalendar;
     property alias fontSize: dateLabel.font.pixelSize
-
     property bool isSelected: false
 
-    Loader {
-        sourceComponent: (isToday && isCurrentMonth) || isSelected ? highLightComp : undefined
-
-        onSourceComponentChanged: {
-            width = Qt.binding( function() {
-                var width = dateRootItem.height > dateRootItem.width ? dateRootItem.width :dateRootItem.height
-                return ( width / 1.3 );
-            });
-            height = Qt.binding ( function() { return width} );
-            anchors.centerIn = Qt.binding( function() { return dateLabel});
-        }
-    }
-
-    Label {
+    Text {
         id: dateLabel
         anchors.centerIn: parent
         text: date
-        fontSize: root.dateLabelFontSize
         color: {
             if( isCurrentMonth ) {
                 if( isToday || isSelected ) {
@@ -48,125 +30,4 @@
             }
         }
     }
-
-    Loader{
-        sourceComponent: showLunarCalendar ? reservedFiled : undefined
-        onSourceComponentChanged: {
-            if (item != undefined) {
-                item.reservedData = Qt.binding(function(){
-                    var lunarDate = Lunar.calendar.solar2lunar(intern.monthStartYear,
-                                                               intern.monthStartMonth + 1,
-                                                               intern.monthStartDate + index)
-                    if (lunarDate.isTerm) {
-                        return {"lunarText": lunarDate.Term, "isTerm" :lunarDate.isTerm};
-                    } else {
-                        return {"lunarText": lunarDate.IDayCn, "isTerm" :lunarDate.isTerm};
-                    }
-                })
-            }
-
-            width = Qt.binding( function() { return units.gu(0.8)})
-            height = Qt.binding( function() { return width })
-            anchors.horizontalCenter = Qt.binding( function() { return  parent.horizontalCenter })
-            anchors.top = Qt.binding( function() { return parent.verticalCenter })
-            anchors.topMargin = Qt.binding( function() {
-                return (dateRootItem.height > dateRootItem.width ? dateRootItem.width :dateRootItem.height)/ 4.0 + units.gu(0.25)
-            });
-        }
-    }
-
-    //this component is reserved for extra information display
-    Component {
-        id: reservedFiled
-        Label {
-            id: reservedLabel
-            property var reservedData
-            onReservedDataChanged: {
-                text = reservedData.lunarText
-                if (reservedData.isTerm)
-                    color = "red";
-            }
-
-            horizontalAlignment: Text.AlignHCenter
-            fontSize: root.subLabelFontSize
-            color: "#5D5D5D"
-        }
-    }
-
-    Loader{        
-        sourceComponent: showEvent ? eventIndicatorComp : undefined
-        onSourceComponentChanged: {
-            width = Qt.binding( function() { return units.gu(0.8)})
-            height = Qt.binding( function() { return width })
-            anchors.horizontalCenter = Qt.binding( function() { return  parent.horizontalCenter })
-            anchors.top = Qt.binding( function() { return parent.verticalCenter })
-            anchors.topMargin = Qt.binding( function() {
-                if (showLunarCalendar) {
-                    return (dateRootItem.height > dateRootItem.width ? dateRootItem.width :dateRootItem.height) / 2 + units.gu(1.5)
-                } else {
-                    var w = (dateRootItem.height > dateRootItem.width ? dateRootItem.width :dateRootItem.height)/1.3
-                    return (w/2) + units.gu(0.1)
-                }
-            });
-        }
-    }
-
-    Component{
-        id: eventIndicatorComp
-        Rectangle {
-            anchors.fill: parent
-            radius: height/2
-            color: "black"
-        }
-    }
-
-    Component{
-        id: highLightComp
-        UbuntuShape{
-            color: {
-                if( isToday && !isSelected ) {
-                    "#DD4814"
-                } else {
-                    "gray"
-                }
-            }
-
-            Rectangle{
-                anchors.fill: parent
-                anchors.margins: units.gu(0.5)
-                color: isToday ? "#DD4814" : "darkgray"
-            }
-        }
-    }
-
-    MouseArea {
-        anchors.fill: parent
-        onPressAndHold: {
-            if( isSelected ) {
-                var selectedDate = new Date();
-                selectedDate.setFullYear(intern.monthStartYear)
-                selectedDate.setMonth(intern.monthStartMonth + 1)
-                selectedDate.setDate(date)
-                selectedDate.setMinutes(60, 0, 0)
-                pageStack.push(Qt.resolvedUrl("NewEvent.qml"), {"date":selectedDate, "model":eventModel});
-            }
-        }
-        onClicked: {
-            var selectedDate = new Date(intern.monthStartYear,
-                                        intern.monthStartMonth,
-                                        intern.monthStartDate + index, 0, 0, 0, 0)
-            if( isYearView ) {
-                //If yearView is clicked then open selected MonthView
-                root.monthSelected(selectedDate);
-            } else {
-                if( isSelected ) {
-                    //If monthView is clicked then open selected DayView
-                    root.dateSelected(selectedDate);
-                } else {
-                    intern.selectedIndex = index
-                    root.dateHighlighted(selectedDate)
-                }
-            }
-        }
-    }
 }

=== added file 'MonthComponentWithEventsDateDelegate.qml'
--- MonthComponentWithEventsDateDelegate.qml	1970-01-01 00:00:00 +0000
+++ MonthComponentWithEventsDateDelegate.qml	2016-03-03 21:42:32 +0000
@@ -0,0 +1,80 @@
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+
+Item{
+    id: dateRootItem
+
+    property int date;
+    property bool isCurrentMonth;
+    property bool isToday;
+    property bool showEvent;
+    property alias fontSize: dateLabel.font.pixelSize
+    property bool isSelected: false
+    property alias lunarData: lunarLabel.lunarData
+
+    Text {
+        id: dateLabel
+        anchors.centerIn: parent
+        text: date
+        color: {
+            if( isCurrentMonth ) {
+                if( isToday || isSelected ) {
+                    "white"
+                } else {
+                    "#5D5D5D"
+                }
+            } else {
+                if(isSelected) {
+                    "white"
+                } else {
+                    "#AEA79F"
+                }
+            }
+        }
+    }
+
+    Label {
+        id: lunarLabel
+
+        property var lunarData: null
+
+        text: lunarData ? lunarData.lunarText : ""
+        color: {
+            if (lunarData && lunarData.isTerm) {
+                if (isCurrentMonth && isToday)
+                    return "black"
+                else
+                    return UbuntuColors.red
+            } else {
+                if (isSelected)
+                    return "white"
+                else
+                    return "#5D5D5D"
+            }
+        }
+        fontSize: "small"
+        visible: (lunarData != null)
+        horizontalAlignment: Text.AlignHCenter
+        width: parent.width
+        anchors {
+            top: dateLabel.bottom
+            topMargin: units.gu(0.5)
+        }
+    }
+
+    Rectangle {
+        id: eventIndicator
+
+        width: visible ? units.gu(0.8) : 0
+        height: width
+        anchors {
+            horizontalCenter: parent.horizontalCenter
+            //top: parent.verticalCenter
+            //topMargin: ((Math.min(parent.height, dateRootItem.width) / 1.3) / 2) + units.gu(0.1)
+            bottom: parent.bottom
+        }
+        radius: height/2
+        color:"black"
+        visible: showEvent
+    }
+}

=== modified file 'MonthView.qml'
--- MonthView.qml	2016-02-03 08:06:25 +0000
+++ MonthView.qml	2016-03-03 21:42:32 +0000
@@ -17,21 +17,31 @@
  */
 import QtQuick 2.4
 import Ubuntu.Components 1.3
+
 import "dateExt.js" as DateExt
 import "colorUtils.js" as Color
 import "./3rd-party/lunar.js" as Lunar
 
-Page {
+PageWithBottomEdge {
     id: monthViewPage
     objectName: "monthViewPage"
 
-    property var currentMonth: DateExt.today();
+    property var anchorDate: DateExt.today();
+    readonly property var firstDayOfAnchorDate: new Date(anchorDate.getFullYear(),
+                                                         anchorDate.getMonth(),
+                                                         1,
+                                                         0, 0, 0)
+    readonly property var currentDate: monthViewPath.currentItem.indexDate
+
     property var selectedDay;
+    property var highlightedDate;
+    property bool displayLunarCalendar: false
 
     signal dateSelected(var date);
-    signal dateHighlighted(var date);
 
     Keys.forwardTo: [monthViewPath]
+    createEventAt: highlightedDate ? highlightedDate : currentDate
+    onAnchorDateChanged: monthViewPath.scrollToBegginer()
 
     Action {
         id: calendarTodayAction
@@ -39,7 +49,7 @@
         iconName: "calendar-today"
         text: i18n.tr("Today")
         onTriggered: {
-            currentMonth = new Date().midnight()
+            anchorDate = new Date().midnight()
         }
     }
 
@@ -49,20 +59,26 @@
         leadingActionBar.actions: tabs.tabsAction
         trailingActionBar.actions: [
             calendarTodayAction,
-            commonHeaderActions.newEventAction,
             commonHeaderActions.showCalendarAction,
             commonHeaderActions.reloadAction,
             commonHeaderActions.syncCalendarAction,
             commonHeaderActions.settingsAction
         ]
         title: {
-            // TRANSLATORS: this is a time formatting string,
-            // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-            // It's used in the header of the month and week views
-            var monthName = currentMonth.toLocaleString(Qt.locale(),i18n.tr("MMMM yyyy"))
-            return monthName[0].toUpperCase() + monthName.substr(1, monthName.length - 1)
+            if (displayLunarCalendar) {
+                var year = currentDate.getFullYear()
+                var month = currentDate.getMonth()
+                var day = Math.floor(Date.daysInMonth(year, month) / 2.0)
+                var lunarDate = Lunar.calendar.solar2lunar(year, month + 1, day)
+                return i18n.tr("%1 %2").arg(lunarDate .IMonthCn).arg(lunarDate.gzYear)
+            } else {
+                // TRANSLATORS: this is a time formatting string,
+                // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
+                // It's used in the header of the month and week views
+                var monthName = currentDate.toLocaleString(Qt.locale(),i18n.tr("MMMM yyyy"))
+                return monthName[0].toUpperCase() + monthName.substr(1, monthName.length - 1)
+            }
         }
-
         flickable: null
     }
 
@@ -70,85 +86,33 @@
         id: monthViewPath
         objectName: "monthViewPath"
 
-        property var startMonth: currentMonth;
-
         anchors {
             fill: parent
             topMargin: header.height
         }
 
-        onNextItemHighlighted: {
-            nextMonth();
-        }
-
-        onPreviousItemHighlighted: {
-            previousMonth();
-        }
-
-        function nextMonth() {
-            currentMonth = addMonth(currentMonth, 1);
-        }
-
-        function previousMonth() {
-            currentMonth = addMonth(currentMonth, -1);
-        }
-
-        function addMonth(date,month) {
-            return  new Date(date.getFullYear(), date.getMonth() + month, 1, 0, 0, 0);
-        }
-
-        delegate: Loader {
+        delegate: MonthWithEventsComponent {
+            property var indexDate: firstDayOfAnchorDate.addMonths(monthViewPath.loopCurrentIndex + monthViewPath.indexType(index))
+
+            currentMonth: indexDate.getMonth()
+            currentYear: indexDate.getFullYear()
+            displayLunarCalendar: monthViewPage.displayLunarCalendar
+
+            modelFilter: eventModel.filter
             width: parent.width - units.gu(4)
             height: parent.height
-
-            sourceComponent: delegateComponent
-            asynchronous: index !== monthViewPath.currentIndex
-
-            Component {
-                id: delegateComponent
-
-                MonthComponent {
-                    isCurrentItem: index === monthViewPath.currentIndex
-
-                    showEvents: true
-
-                    displayWeekNumber: mainView.displayWeekNumber
-                    displayLunarCalendar: mainView.displayLunarCalendar
-                    anchors.fill: parent
-
-                    currentMonth: monthViewPath.addMonth(monthViewPath.startMonth,
-                                                         monthViewPath.indexType(index));
-
-                    selectedDay: monthViewPage.selectedDay
-                    isYearView: false
-
-                    onDateSelected: {
-                        monthViewPage.dateSelected(date);
-                    }
-
-                    onDateHighlighted: {
-                        monthViewPage.dateHighlighted(date);
-                    }
-                }
+            isCurrentItem: PathView.isCurrentItem
+            isActive: !monthViewPath.moving && !monthViewPath.flicking
+            displayWeekNumber: mainView.displayWeekNumber
+            highlightedDate: monthViewPage.highlightedDate
+            isYearView: false
+
+            onDateSelected: {
+                monthViewPage.dateSelected(date);
+            }
+            onDateHighlighted: {
+                monthViewPage.highlightedDate = date
             }
         }
     }
-
-    Component.onCompleted: {
-        pageHeader.title = Qt.binding(function(){
-            if(mainView.displayLunarCalendar){
-                var year = currentMonth.getFullYear()
-                var month = currentMonth.getMonth()
-                var day = Math.floor(Date.daysInMonth(year, month) / 2.0)
-                var lunarDate = Lunar.calendar.solar2lunar( year, month + 1, day)
-                return i18n.tr("%1 %2").arg(lunarDate .IMonthCn).arg(lunarDate.gzYear)
-            } else {
-                // TRANSLATORS: this is a time formatting string,
-                // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-                // It's used in the header of the month and week views
-                var monthName = currentMonth.toLocaleString(Qt.locale(),i18n.tr("MMMM yyyy"))
-                return monthName[0].toUpperCase() + monthName.substr(1, monthName.length - 1)
-            }
-        })
-    }
 }

=== added file 'MonthWithEventsComponent.qml'
--- MonthWithEventsComponent.qml	1970-01-01 00:00:00 +0000
+++ MonthWithEventsComponent.qml	2016-03-03 21:42:32 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * This file is part of Ubuntu Calendar App
+ *
+ * Ubuntu Calendar App is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Ubuntu Calendar App is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+import QtOrganizer 5.0
+import "dateExt.js" as DateExt
+import "colorUtils.js" as Color
+
+MonthComponent {
+    id: root
+    objectName: "MonthComponent"
+
+    property bool isActive: false
+    property var modelFilter: invalidFilter
+
+    onIsActiveChanged: {
+        if (isActive && (mainModel.filter === invalidFilter)) {
+            idleRefresh.reset()
+        }
+    }
+
+    Timer {
+        id: idleRefresh
+
+        function reset()
+        {
+            mainModel.filter = invalidFilter
+            restart()
+        }
+
+        interval: root.isCurrentItem ? 1000 : 2000
+        repeat: false
+        onTriggered: {
+            mainModel.filter = Qt.binding(function() { return root.modelFilter } )
+        }
+    }
+
+    InvalidFilter {
+        id: invalidFilter
+    }
+
+    EventListModel {
+        id: mainModel
+
+        startPeriod: root.monthStartDate.midnight();
+        endPeriod: root.monthStartDate.addDays((/*monthGrid.rows * cols */ 42 )-1).endOfDay()
+        filter: invalidFilter
+        fetchHint: FetchHint {
+            detailTypesHint: [ Detail.EventTime,
+                               Detail.JournalTime,
+                               Detail.TodoTime
+                             ]
+        }
+
+        onModelChanged: {
+            var eventStatus = mainModel.containsItems(startPeriod,
+                                                      endPeriod,
+                                                      86400/*24*60*60*/);
+            root.updateEvents(eventStatus)
+        }
+
+        onStartPeriodChanged: idleRefresh.reset()
+        onEndPeriodChanged: idleRefresh.reset()
+    }
+}

=== modified file 'NewEvent.qml'
--- NewEvent.qml	2016-02-02 22:54:03 +0000
+++ NewEvent.qml	2016-03-03 21:42:32 +0000
@@ -20,7 +20,7 @@
 import QtOrganizer 5.0
 import Ubuntu.Components 1.3
 import Ubuntu.Components.Popups 1.0
-import Ubuntu.Components.ListItems 1.0 as ListItem
+import Ubuntu.Components.ListItems 1.0 as ListItems
 import Ubuntu.Components.Themes.Ambiance 1.0
 import Ubuntu.Components.Pickers 1.0
 import QtOrganizer 5.0
@@ -31,10 +31,11 @@
     objectName: 'newEventPage'
 
     property var date;
+    property alias allDay: allDayEventCheckbox.checked
 
     property var event:null;
     property var rule :null;
-    property var model;
+    property var model:null;
 
     property var startDate;
     property var endDate;
@@ -42,56 +43,44 @@
     property alias scrollY: flickable.contentY
     property bool isEdit: false
 
-    flickable: null
-
     signal eventAdded(var event);
     signal eventDeleted(var event);
-
-    onStartDateChanged: {
-        startDateTimeInput.dateTime = startDate;
-
-        // set time forward to one hour
-        var time_forward = 3600000;
-
-        if (isEdit && event !== null) {
-            time_forward = event.endDateTime - event.startDateTime;
-        }
-        adjustEndDateToStartDate(time_forward);
-    }
-
-    onEndDateChanged: {
-        endDateTimeInput.dateTime = endDate;
-    }
-
-    head.actions: [
-        Action {
-            text: i18n.tr("Delete");
-            objectName: "delete"
-            iconName: "delete"
-            visible : isEdit
-            onTriggered: {
-                var dialog = PopupUtils.open(Qt.resolvedUrl("DeleteConfirmationDialog.qml"),root,{"event": event});
-                dialog.deleteEvent.connect( function(eventId){
-                    model.removeItem(eventId);
-                    pageStack.pop();
-                    root.eventDeleted(eventId);
-                });
-            }
-        },
-        Action {
-            iconName: "ok"
-            objectName: "save"
-            text: i18n.tr("Save")
-            enabled: !!titleEdit.text.trim()
-            onTriggered: saveToQtPim();
-        }]
+    signal canceled()
+
     Component.onCompleted: {
-        //If current date is setted by an argument we don't have to change it.
-        if(typeof(date) === 'undefined'){
+        setDate(root.date)
+
+        if (event === undefined) {
+            return
+        } else if(event === null){
+            isEdit = false;
+            addEvent();
+        } else{
+            isEdit = true;
+            editEvent(event);
+        }
+    }
+
+    function cancel()
+    {
+        if (pageStack)
+            pageStack.pop();
+        root.canceled()
+    }
+
+    function updateEventDate(date, allDay) {
+        root.startDate = undefined
+        root.endDate = undefined
+        setDate(date)
+        root.allDay = allDay
+    }
+
+    function setDate(date) {
+        if ((typeof(date) === 'undefined') || (date === null)) {
             date = new Date();
         }
 
-        if( typeof(date) == 'undefined' || (date.getHours() == 0 && date.getMinutes() == 0) ) {
+        if(date.getHours() === 0 && date.getMinutes() === 0)  {
             var newDate = new Date();
             date.setHours(newDate.getHours(), newDate.getMinutes());
         }
@@ -108,15 +97,6 @@
             endTimeInput.text = Qt.formatDateTime(endDate, Qt.locale().timeFormat(Locale.ShortFormat));
         }
 
-        if(event === null){
-            isEdit = false;
-            addEvent();
-        }
-
-        else{
-            isEdit = true;
-            editEvent(event);
-        }
     }
 
     function selectCalendar(collectionId) {
@@ -146,14 +126,14 @@
         }
 
         startDate =new Date(e.startDateTime);
-        endDate = new Date(e.endDateTime);
 
         if(e.displayLabel) {
             titleEdit.text = e.displayLabel;
         }
-        if(e.allDay){
-            allDayEventCheckbox.checked =true;
-            endDate = endDate.addDays(-1);
+
+        if (e.allDay) {
+            allDayEventCheckbox.checked = true
+            endDate = new Date(e.endDateTime).addDays(-1);
         }
 
         if(e.location) {
@@ -170,8 +150,7 @@
         if( e.itemType === Type.Event ) {
             if(e.attendees){
                 for( var j = 0 ; j < e.attendees.length ; ++j ) {
-                    contactList.array.push(e.attendees[j]);
-                    contactModel.append(e.attendees[j]);
+                    contactModel.append({"contact": e.attendees[j]});
                 }
             }
         }
@@ -202,11 +181,11 @@
             }
 
             event.allDay = allDayEventCheckbox.checked;
-            event.startDateTime = startDate;
-
             if (event.allDay){
-                event.endDateTime = endDate.addDays(1);
+                event.startDateTime = new Date(startDate).midnight()
+                event.endDateTime = new Date(endDate).addDays(1).midnight()
             } else {
+                event.startDateTime = startDate;
                 event.endDateTime = endDate;
             }
 
@@ -215,13 +194,14 @@
             event.location = locationEdit.text
 
             if( event.itemType === Type.Event ) {
-                event.attendees = []; // if Edit remove all attendes & add them again if any
-                var contacts = [];
-                for(var i=0; i < contactList.array.length ; ++i) {
-                    var contact = contactList.array[i]
-                    contacts.push(contact);
+                var newContacts = []
+                for(var i=0; i < contactModel.count ; ++i) {
+                    var contact = contactModel.get(i).contact
+                    if (contact) {
+                        newContacts.push(internal.attendeeFromData(contact.attendeeId, contact.name, contact.emailAddress));
+                    }
                 }
-                event.attendees = contacts;
+                event.attendees = newContacts;
             }
 
             //Set the Rule object to an event
@@ -253,9 +233,9 @@
                 event.removeDetail(comment);
             }
 
-            model.saveItem(event);
-            pageStack.pop();
-
+            model.saveItem(event)
+            if (pageStack)
+                pageStack.pop();
             root.eventAdded(event);
         }
     }
@@ -294,10 +274,15 @@
     function roundDate(date) {
         var tempDate = new Date(date)
         tempDate.setHours(date.getHours(), date.getMinutes(), 0, 0);
-        if(tempDate.getMinutes() < 30)
+        var tempMinutes = tempDate.getMinutes()
+        if (tempMinutes === 0) {
+            return tempDate
+        } else if(tempMinutes < 30) {
             return tempDate.setMinutes(30)
-        tempDate.setMinutes(0)
-        return tempDate.setHours(tempDate.getHours() + 1)
+        } else {
+            tempDate.setMinutes(0)
+            return tempDate.setHours(tempDate.getHours() + 1)
+        }
     }
 
     function adjustEndDateToStartDate(time_forward) {
@@ -322,10 +307,65 @@
         scrollAnimation.start()
     }
 
-    title: isEdit ? i18n.tr("Edit Event"):i18n.tr("New Event")
-
-    Keys.onEscapePressed: {
-        pageStack.pop();
+    Keys.onEscapePressed: root.cancel()
+    onStartDateChanged: {
+        if (!startDate)
+            return
+
+        startDateTimeInput.dateTime = startDate;
+
+        // set time forward to one hour
+        var time_forward = 3600000;
+
+        if (isEdit && event !== null) {
+            time_forward = event.endDateTime - event.startDateTime;
+        }
+        adjustEndDateToStartDate(time_forward);
+    }
+
+    onEndDateChanged: {
+        if (endDate)
+            endDateTimeInput.dateTime = endDate;
+    }
+
+    header: PageHeader {
+        id: pageHeader
+
+        flickable: null
+        title: isEdit ? i18n.tr("Edit Event"):i18n.tr("New Event")
+        leadingActionBar.actions: Action {
+            id: backAction
+
+            name: "cancel"
+            text: i18n.tr("Cancel")
+            iconName: isEdit ? "back" : "down"
+            onTriggered: root.cancel()
+        }
+
+        trailingActionBar.actions: [
+            Action {
+                text: i18n.tr("Delete");
+                objectName: "delete"
+                iconName: "delete"
+                visible : isEdit
+                onTriggered: {
+                    var dialog = PopupUtils.open(Qt.resolvedUrl("DeleteConfirmationDialog.qml"),root,{"event": event});
+                    dialog.deleteEvent.connect( function(eventId){
+                        model.removeItem(eventId);
+                        if (pageStack)
+                            pageStack.pop();
+                        root.eventDeleted(eventId);
+                    });
+                }
+            },
+            Action {
+                iconName: "ok"
+                objectName: "save"
+                text: i18n.tr("Save")
+                enabled: !!titleEdit.text.trim()
+                onTriggered: saveToQtPim();
+            }
+        ]
     }
 
     Component{
@@ -376,9 +416,16 @@
             flickable.returnToBounds()
         }
 
-        anchors.fill: parent
+        flickableDirection: Flickable.VerticalFlick
+        anchors{
+            left: parent.left
+            top: parent.top
+            topMargin: pageHeader.height
+            right: parent.right
+            bottom: keyboardRectangle.top
+        }
         contentWidth: width
-        contentHeight: column.height + units.gu(10)
+        contentHeight: column.height
 
         Column {
             id: column
@@ -411,7 +458,7 @@
                 }
             }
 
-            ListItem.Standard {
+            ListItems.Standard {
                 anchors {
                     left: parent.left
                     right: parent.right
@@ -426,13 +473,13 @@
                 }
             }
 
-            ListItem.ThinDivider {}
+            ListItems.ThinDivider {}
 
             Column {
                 width: parent.width
                 spacing: units.gu(1)
 
-                ListItem.Header{
+                ListItems.Header{
                     text: i18n.tr("Event Details")
                 }
 
@@ -446,6 +493,7 @@
                         margins: units.gu(2)
                     }
 
+                    inputMethodHints: Qt.ImhNoPredictiveText
                     placeholderText: i18n.tr("Event Name")
                     onFocusChanged: {
                         if(titleEdit.focus) {
@@ -482,6 +530,7 @@
                         margins: units.gu(2)
                     }
 
+                    inputMethodHints: Qt.ImhNoPredictiveText
                     placeholderText: i18n.tr("Location")
 
                     onFocusChanged: {
@@ -496,7 +545,7 @@
                 width: parent.width
                 spacing: units.gu(1)
 
-                ListItem.Header {
+                ListItems.Header {
                     text: i18n.tr("Calendar")
                 }
 
@@ -521,9 +570,11 @@
                             width: height
                             height: parent.height - units.gu(2)
                             color: modelData.color
-                            anchors.right: parent.right
-                            anchors.rightMargin: units.gu(2)
-                            anchors.verticalCenter: parent.verticalCenter
+                            anchors {
+                                right: parent.right
+                                rightMargin: units.gu(4)
+                                verticalCenter: parent.verticalCenter
+                            }
                         }
                     }
                     onExpandedChanged: Qt.inputMethod.hide();
@@ -534,14 +585,17 @@
                 width: parent.width
                 spacing: units.gu(1)
 
-                ListItem.Header {
+                ListItems.Header {
                     text: i18n.tr("Guests")
                 }
 
                 Button{
+                    id: addGuestButton
+                    objectName: "addGuestButton"
+
+                    property var contactsPopup: null
+
                     text: i18n.tr("Add Guest")
-                    objectName: "addGuestButton"
-
                     anchors {
                         left: parent.left
                         right: parent.right
@@ -549,14 +603,21 @@
                     }
 
                     onClicked: {
-                        var popup = PopupUtils.open(Qt.resolvedUrl("ContactChoicePopup.qml"), contactList);
-                        popup.contactSelected.connect( function(contact) {
-                            var t = internal.contactToAttendee(contact);
-                            if( !internal.isContactAlreadyAdded(contact) ) {
-                                contactModel.append(t);
-                                contactList.array.push(t);
+                        if (contactsPopup)
+                            return
+
+                        flickable.makeMeVisible(addGuestButton)
+                        contactsPopup = PopupUtils.open(Qt.resolvedUrl("ContactChoicePopup.qml"), addGuestButton);
+                        contactsPopup.contactSelected.connect( function(contact, emailAddress) {
+                            if(!internal.isContactAlreadyAdded(contact, emailAddress) ) {
+                                var t = internal.contactToAttendee(contact, emailAddress);
+                                contactModel.append({"contact": t});
                             }
+
                         });
+                        contactsPopup.Component.onDestruction.connect( function() {
+                            addGuestButton.contactsPopup = null
+                        })
                     }
                 }
 
@@ -577,35 +638,40 @@
                         width: parent.width
                         clip: true
 
-                        property var array: []
-
                         ListModel{
                             id: contactModel
                         }
 
                         Repeater{
                             model: contactModel
-                            delegate: ListItem.Standard {
+                            delegate: ListItem {
                                 objectName: "eventGuest%1".arg(index)
-                                height: units.gu(4)
-                                text: name
-                                removable: true
-                                onItemRemoved: {
-                                    contactList.array.splice(index, 1)
-                                    contactModel.remove(index)
+
+                                ListItemLayout {
+                                    title.text: contact.name
+                                    subtitle.text: contact.emailAddress
+                                }
+
+                                leadingActions: ListItemActions {
+                                    actions: Action {
+                                        iconName: "delete"
+                                        onTriggered: {
+                                            contactModel.remove(index)
+                                        }
+                                    }
                                 }
                             }
                         }
                     }
                 }
 
-                ListItem.ThinDivider {
-                    visible: event.itemType === Type.Event
+                ListItems.ThinDivider {
+                    visible: (event != undefined) && (event.itemType === Type.Event)
                 }
 
             }
 
-            ListItem.Subtitled{
+            ListItems.Subtitled{
                 id:thisHappens
                 objectName :"thisHappens"
 
@@ -615,17 +681,17 @@
 
                 showDivider: false
                 progression: true
-                visible: event.itemType === Type.Event
+                visible: (event != undefined) && (event.itemType === Type.Event)
                 text: i18n.tr("Repeats")
-                subText: event.itemType === Type.Event ? rule === null ? Defines.recurrenceLabel[0] : eventUtils.getRecurrenceString(rule) : ""
+                subText: (event != undefined) && (event.itemType === Type.Event) ? rule === null ? Defines.recurrenceLabel[0] : eventUtils.getRecurrenceString(rule) : ""
                 onClicked: pageStack.push(Qt.resolvedUrl("EventRepetition.qml"),{"eventRoot": root,"isEdit":isEdit});
             }
 
-            ListItem.ThinDivider {
-                visible: event.itemType === Type.Event
+            ListItems.ThinDivider {
+                visible: (event != undefined) && (event.itemType === Type.Event)
             }
 
-            ListItem.Subtitled{
+            ListItems.Subtitled{
                 id:eventReminder
                 objectName  : "eventReminder"
 
@@ -658,22 +724,42 @@
                                               "eventTitle": titleEdit.text})
             }
 
-            ListItem.ThinDivider {}
+            ListItems.ThinDivider {}
         }
     }
+
     // used to keep the field visible when the keyboard appear or dismiss
     KeyboardRectangle {
-        id: keyboard
-
-        onHeightChanged: {
-            if (flickable.activeItem) {
-                flickable.makeMeVisible(flickable.activeItem)
+        id: keyboardRectangle
+
+        anchors {
+            left: parent.left
+            right: parent.right
+            bottom: parent.bottom
+        }
+
+        Behavior on height {
+            SequentialAnimation {
+                PauseAnimation { duration: 200 }
+                ScriptAction {
+                    script: {
+                        if (addGuestButton.contactsPopup) {
+                            // WORKAROUND: causes the popover to follow the buttom position when keyboard appears
+                            flickable.makeMeVisible(addGuestButton)
+                            addGuestButton.contactsPopup.caller = null
+                            addGuestButton.contactsPopup.caller = addGuestButton
+                        } else {
+                            flickable.makeMeVisible(flickable.activeItem)
+                        }
+                    }
+                }
             }
         }
     }
 
     QtObject {
         id: internal
+
         property var collectionId;
 
         function clearFocus() {
@@ -685,22 +771,33 @@
             messageEdit.focus = false
         }
 
-        function isContactAlreadyAdded(contact) {
-            for(var i=0; i < contactList.array.length ; ++i) {
-                var attendee = contactList.array[i];
-                if( attendee.attendeeId === contact.contactId) {
-                    return true;
+        function isContactAlreadyAdded(contact, emailAddress) {
+            for(var i=0; i < contactModel.count; i++) {
+                var attendee = contactModel.get(i).contact;
+                if (attendee && (emailAddress.length > 0)) {
+                    if (attendee.emailAddress === emailAddress) {
+                        return true;
+                    }
+                } else {
+                    if (attendee.attendeeId === contact.contactId) {
+                        return true
+                    }
                 }
             }
             return false;
         }
 
-        function contactToAttendee(contact) {
-            var attendee = Qt.createQmlObject("import QtOrganizer 5.0; EventAttendee{}", event, "NewEvent.qml");
-            attendee.name = contact.displayLabel.label
-            attendee.emailAddress = contact.email.emailAddress;
-            attendee.attendeeId = contact.contactId;
+        function attendeeFromData(id, name, emailAddress)
+        {
+            var attendee = Qt.createQmlObject("import QtOrganizer 5.0; EventAttendee{}", internal, "NewEvent.qml");
+            attendee.name = name
+            attendee.emailAddress = emailAddress
+            attendee.attendeeId = id
             return attendee;
         }
+
+        function contactToAttendee(contact, emailAddress) {
+            return attendeeFromData(contact.contactId, contact.displayLabel.label, emailAddress)
+        }
     }
 }

=== added file 'NewEventBottomEdge.qml'
--- NewEventBottomEdge.qml	1970-01-01 00:00:00 +0000
+++ NewEventBottomEdge.qml	2016-03-03 21:42:32 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2013-2016 Canonical Ltd
+ *
+ * This file is part of Ubuntu Calendar App
+ *
+ * Ubuntu Calendar App is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Ubuntu Calendar App is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+
+BottomEdge {
+    id: bottomEdge
+    objectName: "bottomEdge"
+
+    property var pageStack: null
+    property var eventModel: null
+    property var date: new Date()
+
+    // WORKAROUND: BottomEdge component loads the page async while draging it
+    // this cause a very bad visual.
+    // To avoid that we create it as soon as the component is ready and keep
+    // it invisible until the user start to drag it.
+    property var _realPage: null
+
+    signal opened()
+    signal eventCreated(var event)
+
+    function updateNewEventDate(date, allDay)
+    {
+        _realPage.updateEventDate(date, allDay)
+    }
+
+    hint {
+        visible: bottomEdge.enabled
+        enabled: visible
+        action: Action {
+            objectName: "neweventbutton"
+            name: "neweventbutton"
+
+            iconName: "new-event"
+            text: i18n.tr("New Event")
+            shortcut: "ctrl+n"
+            enabled: bottomEdge.enabled
+            onTriggered: bottomEdge.commit()
+        }
+    }
+
+    contentComponent: Item {
+        id: pageContent
+
+        implicitWidth: bottomEdge.width
+        implicitHeight: bottomEdge.height
+        children: bottomEdge._realPage
+        Component.onDestruction: {
+            if (bottomEdge._realPage) {
+                bottomEdge._realPage.destroy()
+                bottomEdge._realPage = null
+                _realPage = editorPageBottomEdge.createObject(null)
+            }
+        }
+    }
+
+    onCommitStarted: {
+        bottomEdge.opened()
+        updateNewEventDate(bottomEdge.date ? bottomEdge.date : new Date(), false)
+    }
+
+    Component.onCompleted:  {
+        if (eventModel)
+            _realPage = editorPageBottomEdge.createObject(null)
+    }
+
+    onEventModelChanged: {
+        if (eventModel)
+            _realPage = editorPageBottomEdge.createObject(null)
+    }
+
+    Component {
+        id: editorPageBottomEdge
+        NewEvent {
+            id: newEventPage
+
+            implicitWidth: bottomEdge.width
+            implicitHeight: bottomEdge.height
+            model: bottomEdge.eventModel
+            date: bottomEdge.date
+            enabled: bottomEdge.status === BottomEdge.Committed
+            active: bottomEdge.status === BottomEdge.Committed
+            visible: (bottomEdge.status !== BottomEdge.Hidden)
+            onCanceled: bottomEdge.collapse()
+            onEventAdded: {
+                bottomEdge.collapse()
+                bottomEdge.eventCreated(event)
+            }
+        }
+    }
+
+    Component.onDestruction: {
+        if (bottomEdge._realPage) {
+            bottomEdge._realPage.destroy()
+            bottomEdge._realPage = null
+        }
+    }
+}

=== added file 'PageWithBottomEdge.qml'
--- PageWithBottomEdge.qml	1970-01-01 00:00:00 +0000
+++ PageWithBottomEdge.qml	2016-03-03 21:42:32 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013-2016 Canonical Ltd
+ *
+ * This file is part of Ubuntu Calendar App
+ *
+ * Ubuntu Calendar App is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Ubuntu Calendar App is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+
+Page {
+    id: root
+
+    property alias model: bottomEdge.eventModel
+    property alias createEventAt: bottomEdge.date
+    property bool bootomEdgeEnabled: bottomEdge.enabled
+
+    signal bottomEdgeCommitStarted()
+    signal eventCreated(var event)
+
+    function bottomEdgeCommit(date, allDay)
+    {
+        bottomEdge.commit()
+        bottomEdge.updateNewEventDate(date, allDay)
+    }
+
+    NewEventBottomEdge {
+        id: bottomEdge
+
+        pageStack: tabs
+        onOpened: root.bottomEdgeCommitStarted()
+        onEventCreated: root.eventCreated(event)
+    }
+}

=== modified file 'PathViewBase.qml'
--- PathViewBase.qml	2016-01-25 13:20:32 +0000
+++ PathViewBase.qml	2016-03-03 21:42:32 +0000
@@ -20,8 +20,7 @@
 PathView {
     id: root
 
-    model: 3
-    snapMode: PathView.SnapOneItem
+    readonly property alias loopCurrentIndex: intern.loopCurrentIndex
 
     signal nextItemHighlighted();
     signal previousItemHighlighted();
@@ -29,6 +28,8 @@
     signal scrollUp();
     signal scrollDown();
 
+    model: 3
+    snapMode: PathView.SnapOneItem
     preferredHighlightBegin: 0.5
     preferredHighlightEnd: 0.5
 
@@ -68,6 +69,11 @@
         }
     }
 
+    function scrollToBegginer()
+    {
+        intern.loopCurrentIndex = intern.previousIndex = currentIndex = 0
+    }
+
     Keys.onLeftPressed:{
         root.decrementCurrentIndex();
     }
@@ -98,15 +104,17 @@
         intern.previousIndex = currentIndex
 
         if ( diff > 0 ) {
-            root.nextItemHighlighted();
+            intern.loopCurrentIndex++
         }
         else {
-            root.previousItemHighlighted();
+            intern.loopCurrentIndex--
         }
     }
 
     QtObject{
         id: intern
+
+        property int loopCurrentIndex: 0
         property int previousIndex: root.currentIndex
     }
 }

=== modified file 'TimeLineBase.qml'
--- TimeLineBase.qml	2016-02-03 08:01:25 +0000
+++ TimeLineBase.qml	2016-03-03 21:42:32 +0000
@@ -1,4 +1,4 @@
-/*
+    /*
  * Copyright (C) 2013-2014 Canonical Ltd
  *
  * This file is part of Ubuntu Calendar App
@@ -20,36 +20,36 @@
 import QtOrganizer 5.0
 
 import "dateExt.js" as DateExt
+import "calendar_canvas.js" as CanlendarCanvas
 
 Item {
     id: bubbleOverLay
 
     property var delegate;
     property var day;
-    property int hourHeight: units.gu(8)
-    property var model;
-
-    Component.onCompleted: {
-        bubbleOverLay.createEvents();
+
+    property alias model: modelConnections.target
+    property var flickable: null
+    readonly property alias creatingEvent: overlayMouseArea.creatingEvent
+    readonly property real hourHeight: units.gu(8)
+    readonly property real minuteHeight: (hourHeight / 60)
+
+    signal pressAndHoldAt(var date)
+
+    function waitForModelChange()
+    {
+        intern.waitingForModelChange = true
     }
 
-    MouseArea {
-        anchors.fill: parent
-        objectName: "mouseArea"
-
-        onPressAndHold: {
-            var selectedDate = new Date(day);
-            var hour = parseInt(mouseY / hourHeight);
-            selectedDate.setHours(hour)
-            createOrganizerEvent(selectedDate);
-        }
-
-        onPressed: {
-            intern.now = new Date();
-            if( intern.now.isSameDay( bubbleOverLay.day ) ) {
-                bubbleOverLay.showSeparator();
-            }
-        }
+    function createOrganizerEvent( startDate ) {
+        var event = Qt.createQmlObject("import QtOrganizer 5.0; Event {}", Qt.application,"TimeLineBase.qml");
+        event.collectionId = (model.defaultCollection().collectionId);
+        var endDate = new Date( startDate.getTime() + 3600000 );
+        event.startDateTime = startDate;
+        event.endDateTime = endDate;
+        event.displayLabel = i18n.tr("New event");
+        event.setDetail(Qt.createQmlObject("import QtOrganizer 5.0; Comment{ comment: 'X-CAL-DEFAULT-EVENT'}", event,"TimeLineBase.qml"));
+        return event
     }
 
     function getTimeFromYPos(y, day) {
@@ -64,32 +64,6 @@
         return date;
     }
 
-    function createOrganizerEvent( startDate ) {
-        var event = Qt.createQmlObject("import QtOrganizer 5.0; Event {}", Qt.application,"TimeLineBase.qml");
-        event.collectionId = (model.defaultCollection().collectionId);
-        var endDate = new Date( startDate.getTime() + 3600000 );
-        event.startDateTime = startDate;
-        event.endDateTime = endDate;
-        event.displayLabel = i18n.tr("Untitled");
-        event.setDetail(Qt.createQmlObject("import QtOrganizer 5.0; Comment{ comment: 'X-CAL-DEFAULT-EVENT'}", event,"TimeLineBase.qml"));
-        model.saveItem(event);
-    }
-
-    TimeSeparator {
-        id: separator
-        objectName: "separator"
-        width:  bubbleOverLay.width
-        visible: false
-        z:10
-    }
-
-    QtObject {
-        id: intern
-        property var now : new Date();
-        property var eventMap;
-        property var unUsedEvents: new Object();
-    }
-
     function showEventDetails(event) {
         var comment = event.detail(Detail.Comment);
         if(comment && comment.comment === "X-CAL-DEFAULT-EVENT") {
@@ -101,167 +75,279 @@
 
     WorkerScript {
         id: eventLayoutHelper
-        source: "EventLayoutHelper.js"
 
+        source: "calendar_canvas_worker.js"
         onMessage: {
-            layoutEvents(messageObject.schedules,messageObject.maxDepth);
-        }
-    }
-
-    function layoutEvents(array, depth) {
-        for(var i=0; i < array.length ; ++i) {
-            var schedule = array[i];
-            var event = intern.eventMap[schedule.id];
-            bubbleOverLay.createEvent(event , schedule.depth, depth +1);
-        }
+            // check if anything changed during the process
+            if (intern.dirty) {
+                console.debug("Something has changed while work script was running, ignore message")
+            } else {
+                var events = messageObject.reply
+                var dirty = false
+                for (var i=0; i < events.length; i++) {
+                    var e = intern.eventsById[events[i].eventId]
+                    if (e.eventId != events[i].itemId) {
+                        console.warn("Event does not match id:", i)
+                        dirty = true
+                    }
+                    if (e.startDateTime.getTime() != events[i].eventStartTime) {
+                        console.warn("Event does not match start time")
+                        dirty = true
+                    }
+                    if (e.endDateTime.getTime() != events[i].eventEndTime) {
+                        console.warn("Event does not match end time")
+                        dirty = true
+                    }
+
+                    if (dirty) {
+                        console.warn("Mark as dirty")
+                        intern.dirty = true
+                        break
+                    }
+
+                    createVisual(events[i])
+                }
+            }
+            intern.busy = false
+            intern.eventsById = {}
+            if (intern.dirty) {
+                bubbleOverLay.idleCreateEvents()
+            }
+        }
+    }
+
+    function createVisual(eventInfo)
+    {
+        var eventBubble;
+        if (intern.unUsedEvents.length === 0) {
+            var incubator = delegate.incubateObject(bubbleOverLay)
+            incubator.forceCompletion()
+            eventBubble = incubator.object
+        } else {
+            eventBubble = getUnusedEventBubble();
+        }
+
+        var eventWidth =  (bubbleOverLay.width * eventInfo.width)
+
+        eventBubble.anchorDate = bubbleOverLay.day
+        eventBubble.minuteHeight = bubbleOverLay.minuteHeight
+        eventBubble.sizeOfRow = eventInfo.width
+        eventBubble.depthInRow = eventInfo.y
+        eventBubble.model = bubbleOverLay.model
+        eventBubble.event = intern.eventsById[eventInfo.eventId]
+        eventBubble.resize()
+        eventBubble.visible = true
+        eventBubble.clicked.connect( bubbleOverLay.showEventDetails );
+    }
+
+     function idleCreateEvents() {
+        createEventsTimer.restart()
     }
 
     function createEvents() {
         if(!bubbleOverLay || bubbleOverLay == undefined || model === undefined || model === null) {
-            return;
-        }
-
+            console.debug("\tabort.")
+            return;
+        }
+
+        // check if there is any update in progress
+        if (intern.busy) {
+            console.debug("Work script still busy, postpone update")
+            // mark as dirsty to triggere a new update after the message arrives
+            intern.dirty = true
+            return;
+        }
+
+        intern.busy = true
+        intern.dirty = false
         destroyAllChildren();
-
-        var eventMap = {};
-        var allSchs = [];
-
-        var startDate = new Date(day).midnight();
-        var endDate = new Date(day).endOfDay();
-        var items = model.getItems(startDate,endDate);
-        for(var i = 0; i < items.length; ++i) {
-            var event = items[i];
-
-            if(event.allDay) {
-                continue;
-            }
-
-            var schedule = {"startDateTime": event.startDateTime, "endDateTime": event.endDateTime,"id":event.itemId };
-            allSchs.push(schedule);
-            eventMap[event.itemId] = event;
-        }
-
-        intern.eventMap = eventMap;
-        eventLayoutHelper.sendMessage(allSchs);
-
-        if( intern.now.isSameDay( bubbleOverLay.day ) ) {
+        intern.eventsById = {}
+
+        var startDate = day.midnight()
+        var itemsOfTheDay = model.itemsByTimePeriod(startDate, startDate.endOfDay())
+        if (itemsOfTheDay.length === 0) {
             bubbleOverLay.showSeparator();
-        }
+            intern.busy = false
+            return
+        }
+
+        for(var i=0; i < itemsOfTheDay.length; i++) {
+            var e = itemsOfTheDay[i]
+            intern.eventsById[e.itemId] = e
+        }
+
+        var eventInfo = CanlendarCanvas.parseDayEvents(startDate, itemsOfTheDay)
+        eventLayoutHelper.sendMessage({'events': eventInfo})
+        bubbleOverLay.showSeparator();
     }
 
     function destroyAllChildren() {
-        for( var i = children.length - 1; i >= 0; --i ) {
-            if( children[i].objectName === "mouseArea" ||
-                    children[i].objectName === "weekdevider") {
+        separator.visible = false
+        for(var i=0; i < children.length; i++) {
+            var child = children[i]
+            if (!child.isEventBubble) {
                 continue;
             }
-            children[i].visible = false;
-            if( children[i].objectName !== "separator") {
-                children[i].clicked.disconnect( bubbleOverLay.showEventDetails );
-                var key = children[i].objectName;
-                if (intern.unUsedEvents[key] === "undefined") {
-                    intern.unUsedEvents[key] = children[i];
-                }
+            if (intern.unUsedEvents.indexOf(child) === -1) {
+                child.event = null
+                child.visible = false;
+                child.clicked.disconnect(bubbleOverLay.showEventDetails);
+                intern.unUsedEvents.push(child)
             }
         }
     }
 
-    function isHashEmpty(hash) {
-        for (var prop in hash) {
-            if (prop)
-                return false;
-        }
-        return true;
-    }
-
-    function getAKeyFromHash(hash) {
-        for (var prop in hash) {
-            return prop;
-        }
-        return "undefined";
-    }
-
     function getUnusedEventBubble() {
-        /* Recycle an item from unUsedEvents, and remove from hash */
-        var key = getAKeyFromHash(intern.unUsedEvents);
-        var unUsedBubble = intern.unUsedEvents[key];
-        delete intern.unUsedEvents[key];
-
-        return unUsedBubble;
-    }
-
-    function createEvent( event, depth, sizeOfRow ) {
-        var eventBubble;
-        if( isHashEmpty(intern.unUsedEvents) ) {
-            var incubator = delegate.incubateObject(bubbleOverLay);
-            if (incubator.status !== Component.Ready) {
-                incubator.onStatusChanged = function(status) {
-                    if (status === Component.Ready) {
-                        incubator.object.objectName = children.length;
-                        assignBubbleProperties(incubator.object, event, depth, sizeOfRow);
-                    }
-                }
-            } else {
-                incubator.object.objectName = children.length;
-                assignBubbleProperties(incubator.object, event, depth, sizeOfRow);
-            }
-        } else {
-            eventBubble = getUnusedEventBubble();
-            assignBubbleProperties(eventBubble, event, depth, sizeOfRow);
-        }
-    }
-
-    function assignBubbleProperties(eventBubble, event, depth, sizeOfRow) {
-        var yPos = 0;
-        var height = 0;
-        var hour = 0;
-        var durationMin = 0;
-
-        // skip it in case of endDateTime == dd-MM-yyyy 12:00 AM
-        if (event.endDateTime - day  == 0)
-            return;
-
-        if (event.endDateTime.isSameDay(day) &&
-                event.endDateTime.isSameDay(event.startDateTime)) {
-            hour = event.startDateTime.getHours();
-            yPos = (( event.startDateTime.getMinutes() * hourHeight) / 60) + hour * hourHeight
-            durationMin = (event.endDateTime - event.startDateTime)  / Date.msPerMin;
-        }
-        if (!event.startDateTime.isSameDay(day) &&
-                event.endDateTime.isSameDay(day)) {
-            hour = 0;
-            yPos = 0;
-            durationMin = event.endDateTime.getHours() * 60;
-            durationMin += event.endDateTime.getMinutes();
-        }
-        if (event.startDateTime.isSameDay(day) &&
-                !event.endDateTime.isSameDay(day)) {
-            hour = event.startDateTime.getHours();
-            yPos = (( event.startDateTime.getMinutes() * hourHeight) / 60) + hour * hourHeight
-            durationMin = (24 - event.startDateTime.getHours()) * 60;
-        }
-        if (!event.startDateTime.isSameDay(day) &&
-                !event.endDateTime.isSameDay(day)) {
-            hour = 0;
-            yPos = 0;
-            durationMin = 24 * 60;
-        }
-
-        eventBubble.y = yPos;
-        height = (durationMin * hourHeight )/ 60;
-        eventBubble.height = (height > eventBubble.minimumHeight) ? height:eventBubble.minimumHeight ;
-
-        eventBubble.model = bubbleOverLay.model
-        eventBubble.depthInRow = depth;
-        eventBubble.sizeOfRow = sizeOfRow;
-        eventBubble.event = event
-        eventBubble.visible = true;
-        eventBubble.clicked.connect( bubbleOverLay.showEventDetails );
+        var unusedEvent = null
+        if (intern.unUsedEvents.length > 0) {
+            unusedEvent = intern.unUsedEvents[0]
+            intern.unUsedEvents.splice(0, 1);
+        }
+        return unusedEvent
     }
 
     function showSeparator() {
-        var y = ((intern.now.getMinutes() * hourHeight) / 60) + intern.now.getHours() * hourHeight;
-        separator.y = y;
-        separator.visible = true;
+        intern.now = new Date();
+        if (intern.now.isSameDay(bubbleOverLay.day) ) {
+            var y = ((intern.now.getMinutes() * hourHeight) / 60) + intern.now.getHours() * hourHeight;
+            separator.y = y;
+            separator.visible = true;
+        } else {
+            separator.visible = false;
+        }
+    }
+
+    onDayChanged: bubbleOverLay.idleCreateEvents();
+    Component.onCompleted: bubbleOverLay.idleCreateEvents();
+    enabled: !intern.busy && !intern.waitingForModelChange
+
+    EventBubble {
+        id: temporaryEvent
+
+        isEventBubble: false
+        Drag.active: overlayMouseArea.drag.active
+        isLiveEditing: overlayMouseArea.creatingEvent
+        visible: overlayMouseArea.creatingEvent
+        sizeOfRow: 1.0
+        z: 100
+        onVisibleChanged: {
+            if (visible)
+                y = event ? CanlendarCanvas.minutesSince(bubbleOverLay.day, event.startDateTime) * bubbleOverLay.minuteHeight : 0
+        }
+    }
+
+    Item {
+        anchors {
+            topMargin: flickable ? flickable.contentY : 0
+            bottomMargin: flickable ? bubbleOverLay.height - flickable.contentY - flickable.height : bubbleOverLay.height
+            fill: parent
+        }
+
+        ActivityIndicator {
+            visible: intern.busy || intern.waitingForModelChange
+            running: visible
+            anchors.centerIn: parent
+        }
+
+        z: 100
+    }
+
+    MouseArea {
+        id: overlayMouseArea
+
+        property bool creatingEvent: false
+
+        anchors.fill: parent
+        objectName: "mouseArea"
+        drag {
+            target: creatingEvent ? temporaryEvent : null
+            axis: Drag.YAxis
+            minimumY: 0
+            maximumY: height - temporaryEvent.height
+        }
+
+
+        Binding {
+            target: temporaryEvent
+            property: "visible"
+            value: overlayMouseArea.creatingEvent
+        }
+
+        onPressAndHold: {
+            var selectedDate = new Date(day);
+            var pointY = mouse.y - (hourHeight / 2);
+            selectedDate.setHours(Math.floor(pointY / hourHeight))
+            selectedDate.setMinutes(Math.min(pointY % hourHeight, 60))
+            var event = createOrganizerEvent(selectedDate)
+
+            Haptics.play()
+
+            temporaryEvent.anchorDate = bubbleOverLay.day
+            temporaryEvent.minuteHeight = bubbleOverLay.minuteHeight
+            temporaryEvent.depthInRow = 0
+            temporaryEvent.model = bubbleOverLay.model
+            temporaryEvent.event = event
+            temporaryEvent.resize()
+            creatingEvent = true
+        }
+
+        onReleased: {
+            if (creatingEvent) {
+                bubbleOverLay.pressAndHoldAt(temporaryEvent.event.startDateTime)
+                creatingEvent = false
+            }
+        }
+
+        onCanceled: {
+            if (creatingEvent) {
+                creatingEvent = false
+            }
+        }
+    }
+
+    TimeSeparator {
+        id: separator
+        objectName: "separator"
+        width:  bubbleOverLay.width
+        visible: false
+        // make sure that the object is aways visible
+        z: 1000
+    }
+
+    Timer {
+        id: separtorUpdateTimer
+        interval: 300000 // every 5 minutes
+        running: true
+        repeat: true
+        onTriggered: showSeparator()
+    }
+
+    QtObject {
+        id: intern
+
+        property var now : new Date();
+        property var eventsById: ({})
+        property var unUsedEvents: []
+        property bool busy: false
+        property bool dirty: false
+        property bool waitingForModelChange: false
+    }
+
+    Timer {
+        id: createEventsTimer
+
+        interval: 300
+        running: false
+        repeat: false
+        onTriggered: createEvents()
+    }
+
+    Connections {
+        id: modelConnections
+        onModelChanged: {
+            intern.dirty = true
+            intern.waitingForModelChange = false
+            bubbleOverLay.idleCreateEvents()
+        }
     }
 }

=== modified file 'TimeLineBaseComponent.qml'
--- TimeLineBaseComponent.qml	2016-01-29 14:35:14 +0000
+++ TimeLineBaseComponent.qml	2016-03-03 21:42:32 +0000
@@ -29,58 +29,106 @@
 
     property var keyboardEventProvider;
 
+    property bool isCurrentItem: false
+    property bool isActive: false
+
     property date startDay: DateExt.today();
     property int weekNumber: startDay.weekNumber(Qt.locale().firstDayOfWeek);
-    property bool isActive: false
     property alias contentY: timeLineView.contentY
     property alias contentInteractive: timeLineView.interactive
+    property var modelFilter: invalidFilter
     property var selectedDay;
 
+    readonly property real hourItemHeight: units.gu(8)
+    readonly property int currentHour: timeLineView.contentY > hourItemHeight ?
+                                           Math.round(timeLineView.contentY / hourItemHeight) : 1
+    readonly property int currentDayOfWeek: timeLineView.contentX > timeLineView.delegateWidth ?
+                                                Math.floor(timeLineView.contentX / timeLineView.delegateWidth) : 0
     property int type: ViewType.ViewTypeWeek
 
     //visible hour
     property int scrollHour;
 
-    property EventListModel mainModel;
-
     signal dateSelected(var date);
     signal dateHighlighted(var date);
-
-    function scrollToCurrentTime() {
-        var currentTime = new Date();
-        scrollHour = currentTime.getHours();
-
-        timeLineView.contentY = scrollHour * units.gu(8);
-        if(timeLineView.contentY >= timeLineView.contentHeight - timeLineView.height) {
-            timeLineView.contentY = timeLineView.contentHeight - timeLineView.height
-        }
-    }
-
-    function scrollTocurrentDate() {
-        if ( type != ViewType.ViewTypeWeek ){
+    signal pressAndHoldAt(var date, bool allDay);
+
+    function timeIsVisible(date) {
+
+        var hour = date.getHours();
+        var currentTimeY = (hour * hourItemHeight)
+        return ((currentTimeY >= timeLineView.contentY) &&
+                (currentTimeY <= (timeLineView.contentY + timeLineView.height)));
+    }
+
+    function dateIsVisible(date) {
+        if (date.getFullYear() !== startDay.getFullYear()) {
+            return false;
+        }
+
+        if (type != ViewType.ViewTypeWeek) {
+            return ((date.getMonth() === startDay.getMonth) &&
+                    (date.getDate() === startDay.getDate()))
+        }
+
+        var dateDayOfWeekX = date.getDay() * timeLineView.delegateWidth
+        return ((dateDayOfWeekX >= timeLineView.contentX) &&
+                (dateDayOfWeekX <= (timeLineView.contentX + timeLineView.width)))
+    }
+
+    function dateTimeIsVisible(date) {
+        return dateIsVisible(date) && timeIsVisible(date);
+    }
+
+    function scrollToTime(date) {
+        scrollHour = date.getHours();
+
+        var currentTimeY = (scrollHour * hourItemHeight)
+        var margin = (timeLineView.height / 2.0) - units.gu(5)
+        currentTimeY =  currentTimeY - margin
+        timeLineView.contentY = Math.min(timeLineView.contentHeight - timeLineView.height, currentTimeY > 0 ? currentTimeY : 0)
+        timeLineView.returnToBounds()
+    }
+
+    function scrollToDate(date) {
+        if (type != ViewType.ViewTypeWeek) {
             return;
         }
 
-        var today = DateExt.today();
-        var startOfWeek = today.weekStart(Qt.locale().firstDayOfWeek);
-        var weekDay = today.getDay();
-        var diff = weekDay - Qt.locale().firstDayOfWeek
-        diff = diff < 0 ? 6 : diff
-
-        if( startOfWeek.isSameDay(startDay) && diff > 2) {
-            timeLineView.contentX = (diff * timeLineView.delegateWidth);
-            if( timeLineView.contentX  > (timeLineView.contentWidth - timeLineView.width) ) {
-                timeLineView.contentX = timeLineView.contentWidth - timeLineView.width
-            }
+        var todayWeekNumber = date.weekNumber(Qt.locale().firstDayOfWeek);
+
+        if (todayWeekNumber === root.weekNumber) {
+            var startOfWeek = date.weekStart(Qt.locale().firstDayOfWeek);
+            var weekDay = date.getDay();
+            var diff = weekDay - Qt.locale().firstDayOfWeek
+            diff = diff < 0 ? 0 : diff
+
+            var currentDayY = timeLineView.delegateWidth * diff
+            var margin = (timeLineView.width - timeLineView.delegateWidth) / 2
+            currentDayY = currentDayY - margin
+            timeLineView.contentX = Math.min(timeLineView.contentWidth - timeLineView.width, currentDayY > 0 ? currentDayY : 0)
         } else {
-            //need to check swipe direction
-            //and change startion position as per direction
-            if(weekViewPath.swipeDirection() === -1) {
-                timeLineView.contentX = timeLineView.contentWidth - timeLineView.width
-            } else {
-                timeLineView.contentX = 0;
-            }
+            timeLineView.contentX = 0
         }
+
+        timeLineView.returnToBounds()
+    }
+
+    function scrollToDateAndTime(date) {
+        scrollToTime(date)
+        scrollToDate(date)
+    }
+
+    function scrollToEnd()
+    {
+        timeLineView.contentX = timeLineView.contentWidth - timeLineView.width
+        timeLineView.returnToBounds()
+    }
+
+    function scrollToBegin()
+    {
+        timeLineView.contentX = 0
+        timeLineView.returnToBounds()
     }
 
     Connections{
@@ -110,29 +158,52 @@
         }
     }
 
-    Timer{
-       interval: 200; running: true; repeat: false
-       onTriggered: {
-           mainModel = modelComponent.createObject();
-           activityLoader.running = Qt.binding( function (){ return mainModel.isLoading;});
-       }
-    }
-
-    Component {
-        id: modelComponent
-        EventListModel {
-            id: mainModel
-            startPeriod: startDay.midnight();
-            endPeriod: type == ViewType.ViewTypeWeek ? startPeriod.addDays(7).endOfDay(): startPeriod.endOfDay()
-            filter: eventModel.filter
-        }
-    }
+    onIsActiveChanged: {
+        if (isActive && (mainModel.filter === invalidFilter)) {
+            idleRefresh.reset()
+        }
+    }
+
+    Timer {
+        id: idleRefresh
+
+        function reset()
+        {
+            mainModel.filter = invalidFilter
+            restart()
+        }
+
+        interval: root.isCurrentItem ? 500 : 1000
+        repeat: false
+        onTriggered: {
+            mainModel.filter = Qt.binding(function() { return root.modelFilter} )
+        }
+    }
+
+    InvalidFilter {
+        id: invalidFilter
+    }
+
+    EventListModel {
+        id: mainModel
+
+        manager:"eds"
+        startPeriod: startDay.midnight();
+        endPeriod: type == ViewType.ViewTypeWeek ? startPeriod.addDays(7).endOfDay(): startPeriod.endOfDay()
+        filter: invalidFilter
+        autoUpdate: true
+
+        onStartPeriodChanged: idleRefresh.reset()
+        onEndPeriodChanged: idleRefresh.reset()
+   }
 
     ActivityIndicator {
         id: activityLoader
+        objectName : "activityIndicator"
+
         visible: running
-        objectName : "activityIndicator"
         anchors.centerIn: parent
+        //running: mainModel.isLoading
         z:2
     }
 
@@ -149,11 +220,21 @@
             selectedDay: root.selectedDay
 
             onDateSelected: {
-                root.dateSelected(date);
+                root.dateSelected(date.getFullYear(),
+                                  date.getMonth(),
+                                  date.getDate(),
+                                  root.currentHour, 0, 0)
             }
 
             onDateHighlighted: {
-                root.dateHighlighted(date);
+                root.dateHighlighted(date.getFullYear(),
+                                     date.getMonth(),
+                                     date.getDate(),
+                                     root.currentHour, 0, 0)
+            }
+
+            onAllDayPressAndHold: {
+                root.pressAndHoldAt(date, true)
             }
         }
 
@@ -183,7 +264,7 @@
 
                 property int delegateWidth: {
                     if( type == ViewType.ViewTypeWeek ) {
-                        width/3 - units.gu(1) /*partial visible area*/
+                        width/3 - units.gu(1) // partial visible area
                     } else {
                         width
                     }
@@ -198,11 +279,6 @@
                     }
                 }
 
-                onContentWidthChanged: {
-                    scrollToCurrentTime();
-                    scrollTocurrentDate();
-                }
-
                 clip: true
 
                 TimeLineBackground{}
@@ -214,7 +290,12 @@
                         model: type == ViewType.ViewTypeWeek ? 7 : 1
 
                         delegate: TimeLineBase {
+                            id: delegate
+
+                            objectName: "TimeLineBase_" + root.objectName
+
                             property int idx: index
+                            flickable: timeLineView
                             anchors.top: parent.top
                             width: {
                                 if( type == ViewType.ViewTypeWeek ) {
@@ -228,12 +309,14 @@
                             day: startDay.addDays(index)
                             model: mainModel
 
-                            Connections{
-                                target: mainModel
+                            onPressAndHoldAt: {
+                                root.pressAndHoldAt(date, false)
+                            }
 
-                                onModelChanged: {
-                                    createEvents();
-                                }
+                            Binding {
+                                target: timeLineView
+                                property: "interactive"
+                                value: !delegate.creatingEvent
                             }
 
                             DropArea {
@@ -251,12 +334,13 @@
                                     event.startDateTime = startDate;
                                     event.endDateTime = endDate;
 
-                                     return event;
+                                    return event;
                                 }
 
                                 onDropped: {
                                     var event = dropArea.modifyEventForDrag(drop);
-                                    model.saveItem(event);
+                                    delegate.waitForModelChange()
+                                    delegate.model.saveItem(event);
                                 }
 
                                 onPositionChanged: {
@@ -299,13 +383,6 @@
                                     anchors.fill: parent
                                 }
                             }
-
-                            Connections{
-                                target: mainModel
-                                onStartPeriodChanged:{
-                                    destroyAllChildren();
-                                }
-                            }
                         }
                     }
                 }
@@ -317,8 +394,16 @@
         id: comp
         EventBubble {
             type: root.type == ViewType.ViewTypeWeek ? narrowType : wideType
-            flickable: root.isActive ? timeLineView : null
+            flickable: root.isCurrentItem ? timeLineView : null
             clip: true
+            opacity: parent.enabled ? 1.0 : 0.3
+
+            // send a signal to update application current date
+            onClicked: root.dateHighlighted(event.startDateTime)
+            onIsLiveEditingChanged: {
+                if (isLiveEditing)
+                    root.dateHighlighted(event.startDateTime)
+            }
         }
     }
 }

=== modified file 'TimeLineHeader.qml'
--- TimeLineHeader.qml	2016-01-29 14:35:14 +0000
+++ TimeLineHeader.qml	2016-03-03 21:42:32 +0000
@@ -33,6 +33,7 @@
 
     signal dateSelected(var date);
     signal dateHighlighted(var date);
+    signal allDayPressAndHold(var date);
 
     width: parent.width
     height: units.gu(10)
@@ -118,6 +119,9 @@
                 width: parent.width
                 height: units.gu(5)
 
+                onPressAndHold: headerRoot.allDayPressAndHold(date)
+
+
                 Connections{
                     target: mainModel
                     onModelChanged : {
@@ -184,6 +188,8 @@
                     height: units.gu(5)
                     model: mainModel
 
+                    onPressAndHold: headerRoot.allDayPressAndHold(date)
+
                     Connections{
                         target: mainModel
                         onModelChanged : {

=== modified file 'WeekView.qml'
--- WeekView.qml	2016-02-03 08:06:25 +0000
+++ WeekView.qml	2016-03-03 21:42:32 +0000
@@ -22,21 +22,30 @@
 import "ViewType.js" as ViewType
 import "./3rd-party/lunar.js" as Lunar
 
-Page{
+PageWithBottomEdge {
     id: weekViewPage
     objectName: "weekViewPage"
 
-    property var dayStart: new Date();
-    property var firstDay: dayStart.weekStart(Qt.locale().firstDayOfWeek);
+    property var anchorDate: new Date();
+    readonly property var anchorFirstDayOfWeek: anchorDate.weekStart(Qt.locale().firstDayOfWeek)
+    readonly property var currentDate: weekViewPath.currentItem.item.startDay
+    readonly property var currentFirstDayOfWeek: currentDate.weekStart(Qt.locale().firstDayOfWeek)
+
     property bool isCurrentPage: false
     property var selectedDay;
+    property var highlightedDay;
 
     signal dateSelected(var date);
-    signal dateHighlighted(var date);
+    signal pressAndHoldAt(var date, bool allDay)
+
+    function delayScrollToDate(scrollDate, scrollTime) {
+        idleScroll.scrollToTime = scrollTime != undefined ? scrollTime : true
+        idleScroll.scrollToDate = new Date(scrollDate)
+        idleScroll.restart()
+    }
 
     Keys.forwardTo: [weekViewPath]
-
-    flickable: null
+    createEventAt: null
 
     Action {
         id: calendarTodayAction
@@ -44,7 +53,60 @@
         iconName: "calendar-today"
         text: i18n.tr("Today")
         onTriggered: {
-            dayStart = new Date()
+            var today = new Date()
+            delayScrollToDate(today)
+            anchorDate = today
+        }
+    }
+
+    onAnchorDateChanged: {
+        weekViewPath.scrollToBegginer()
+    }
+
+    onEventCreated: {
+        var scrollDate = new Date(event.startDateTime)
+        var currentWeekNumber = currentDate.weekNumber(Qt.locale().firstDayOfWeek)
+        var eventWeekNumber = scrollDate.weekNumber(Qt.locale().firstDayOfWeek)
+        var needScroll = false
+
+        if ((scrollDate.getFullYear() !== currentDate.getFullYear()) ||
+            (currentWeekNumber !== eventWeekNumber)) {
+            anchorDate = new Date(scrollDate)
+            needScroll = true
+        } else {
+            if (event.allDay) {
+                needScroll = !weekViewPath.currentItem.item.dateIsVisible(scrollDate)
+            } else {
+                needScroll = !weekViewPath.currentItem.item.timeIsVisible(scrollDate)
+            }
+        }
+
+        highlightedDay = scrollDate
+        if (needScroll) {
+            delayScrollToDate(scrollDate, !event.allDay)
+        }
+    }
+
+    Timer {
+        id: idleScroll
+
+        property var scrollToDate: null
+        property bool scrollToTime: true
+
+        interval: 200
+        repeat:false
+        onTriggered: {
+            if (scrollToDate) {
+                if (scrollToTime)
+                    weekViewPath.currentItem.item.scrollToDateAndTime(scrollToDate);
+                else
+                    weekViewPath.currentItem.item.scrollToDate(scrollToDate);
+            } else {
+                weekViewPath.currentItem.item.scrollToBegin()
+            }
+
+            scrollToDate = null
+            scrollToTime = true
         }
     }
 
@@ -54,7 +116,6 @@
         leadingActionBar.actions: tabs.tabsAction
         trailingActionBar.actions: [
             calendarTodayAction,
-            commonHeaderActions.newEventAction,
             commonHeaderActions.showCalendarAction,
             commonHeaderActions.reloadAction,
             commonHeaderActions.syncCalendarAction,
@@ -65,8 +126,17 @@
             // TRANSLATORS: this is a time formatting string,
             // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
             // It's used in the header of the month and week views
-            var monthName = dayStart.toLocaleString(Qt.locale(),i18n.tr("MMMM yyyy"))
-            return monthName[0].toUpperCase() + monthName.substr(1, monthName.length - 1)
+            var currentLastDayOfWeek = currentFirstDayOfWeek.addDays(7)
+            if (currentLastDayOfWeek.getMonth() !== currentFirstDayOfWeek.getMonth()) {
+                var firstMonthName = currentFirstDayOfWeek.toLocaleString(Qt.locale(),i18n.tr("MMM"))
+                var lastMonthName = currentLastDayOfWeek.toLocaleString(Qt.locale(),i18n.tr("MMM"))
+                return (firstMonthName[0].toUpperCase() + firstMonthName.substr(1, 2) + "/" +
+                        lastMonthName[0].toUpperCase() + lastMonthName.substr(1, 2) + " " +
+                        currentLastDayOfWeek.getFullYear())
+            } else {
+                var monthName = currentDate.toLocaleString(Qt.locale(),i18n.tr("MMMM yyyy"))
+                return monthName[0].toUpperCase() + monthName.substr(1, monthName.length - 1)
+            }
         }
         flickable: null
     }
@@ -80,25 +150,13 @@
             topMargin: header.height
         }
 
+        onCurrentIndexChanged: {
+            weekViewPage.highlightedDay = null
+        }
+
         //This is used to scroll all view together when currentItem scrolls
         property var childContentY;
 
-        onNextItemHighlighted: {
-            nextWeek();
-        }
-
-        onPreviousItemHighlighted: {
-            previousWeek();
-        }
-
-        function nextWeek() {
-            dayStart = firstDay.addDays(7);
-        }
-
-        function previousWeek(){
-            dayStart = firstDay.addDays(-7);
-        }
-
         delegate: Loader {
             id: timelineLoader
             width: parent.width
@@ -112,39 +170,52 @@
                 TimeLineBaseComponent {
                     id: timeLineView
 
+                    startDay: anchorFirstDayOfWeek.addDays((weekViewPath.loopCurrentIndex + weekViewPath.indexType(index)) * 7)
+                    anchors.fill: parent
                     type: ViewType.ViewTypeWeek
-                    anchors.fill: parent
-                    isActive: parent.PathView.isCurrentItem
-                    startDay: firstDay.addDays( weekViewPath.indexType(index) * 7)
+                    isCurrentItem: parent.PathView.isCurrentItem
+                    isActive: !weekViewPath.moving && !weekViewPath.flicking
                     keyboardEventProvider: weekViewPath
                     selectedDay: weekViewPage.selectedDay
-
-                    onIsActiveChanged: {
-                        timeLineView.scrollTocurrentDate();
-                    }
+                    modelFilter: weekViewPage.model ? weekViewPage.model.filter : null
 
                     onDateSelected: {
                         weekViewPage.dateSelected(date);
                     }
 
                     onDateHighlighted:{
-                        weekViewPage.dateHighlighted(date);
+                        weekViewPage.highlightedDay = date
+                    }
+
+                    Component.onCompleted: {
+                        var iType = weekViewPath.indexType(index)
+                        if (iType === 0) {
+                            idleScroll.restart()
+                        } else if (iType < 0) {
+                            scrollToEnd()
+                        }
+                    }
+
+                    onPressAndHoldAt: {
+                        weekViewPage.pressAndHoldAt(date, allDay)
                     }
 
                     Connections{
                         target: calendarTodayAction
                         onTriggered:{
-                            if( isActive )
-                                timeLineView.scrollTocurrentDate();
-                        }
+                            if (isActive)
+                                timeLineView.scrollToDate(new Date());
+                            }
                     }
 
-                    Connections{
-                        target: weekViewPage
-                        onIsCurrentPageChanged:{
-                            if(weekViewPage.isCurrentPage){
-                                timeLineView.scrollToCurrentTime();
-                                timeLineView.scrollTocurrentDate();
+                    Connections {
+                        target: weekViewPath
+                        onLoopCurrentIndexChanged: {
+                            var iType = weekViewPath.indexType(index)
+                            if (iType < 0) {
+                                scrollToEnd()
+                            } else if (iType > 0) {
+                                scrollToBegin()
                             }
                         }
                     }
@@ -164,6 +235,11 @@
                         value: contentY
                         when: parent.PathView.isCurrentItem
                     }
+                    Binding {
+                        target: weekViewPath
+                        property: "interactive"
+                        value: timeLineView.contentInteractive
+                    }
                 }
             }
         }

=== modified file 'YearView.qml'
--- YearView.qml	2016-02-03 08:06:25 +0000
+++ YearView.qml	2016-03-03 21:42:32 +0000
@@ -18,22 +18,36 @@
 
 import QtQuick 2.4
 import Ubuntu.Components 1.3
+
 import "dateExt.js" as DateExt
 import "./3rd-party/lunar.js" as Lunar
 
-Page {
+PageWithBottomEdge {
     id: yearViewPage
     objectName: "yearViewPage"
 
-    property int currentYear: DateExt.today().getFullYear();
+    property int anchorYear: new Date().getFullYear()
+    property bool displayLunarCalendar: false
+    readonly property int currentYear: yearPathView.currentItem.item ? yearPathView.currentItem.item.year : anchorYear
+
     signal monthSelected(var date);
 
+    function refreshCurrentYear(year)
+    {
+        if (currentYear !== year) {
+            anchorYear = year;
+            yearPathView.scrollToBegginer()
+        }
+        var yearViewDelegate = yearPathView.currentItem;
+        if (yearViewDelegate && yearViewDelegate.item) {
+            yearViewDelegate.item.refresh();
+        }
+    }
+
+    createEventAt: null
     Keys.forwardTo: [yearPathView]
-
-    function refreshCurrentYear(year) {
-        currentYear = year;
-        var yearViewDelegate = yearPathView.currentItem.item;
-        yearViewDelegate.refresh();
+    onAnchorYearChanged: {
+        yearPathView.scrollToBegginer()
     }
 
     Action {
@@ -42,26 +56,50 @@
         iconName: "calendar-today"
         text: i18n.tr("Today")
         onTriggered: {
-            currentYear = new Date().getFullYear()
+            var todayYear = new Date().getFullYear()
+            yearViewPage.refreshCurrentYear(todayYear)
         }
     }
 
     header: PageHeader {
         id: pageHeader
-
         leadingActionBar.actions: tabs.tabsAction
         trailingActionBar.actions: [
             calendarTodayAction,
-            commonHeaderActions.newEventAction,
             commonHeaderActions.showCalendarAction,
             commonHeaderActions.reloadAction,
             commonHeaderActions.syncCalendarAction,
             commonHeaderActions.settingsAction
         ]
-        title: i18n.tr("Year %1").arg(currentYear)
+        title: {
+            if (displayLunarCalendar) {
+                var lunarDate = Lunar.calendar.solar2lunar(currentYear, 6, 0)
+                return lunarDate.gzYear +" "+ lunarDate.Animal
+            } else {
+                return i18n.tr("Year %1").arg(currentYear)
+            }
+        }
         flickable: null
     }
 
+    ActivityIndicator {
+        property var startDate: new Date()
+
+        visible: running
+        running: (yearPathView.currentItem.status !== Loader.Ready)
+        anchors.centerIn: parent
+        z:2
+
+        onRunningChanged: {
+            if (!running) {
+                var current  = new Date()
+                console.debug("Elapsed:" + (current.getTime() - startDate.getTime()))
+            }
+        }
+    }
+
+    flickable: null
+
     PathViewBase {
         id: yearPathView
         objectName: "yearPathView"
@@ -71,46 +109,24 @@
             topMargin: header.height
         }
 
-        onNextItemHighlighted: {
-            currentYear = currentYear + 1;
-        }
-
-        onPreviousItemHighlighted: {
-            currentYear = currentYear - 1;
-        }
-
         delegate: Loader {
-            width: parent.width
-            height: parent.height
-            anchors.top: parent.top
-
-            asynchronous: index !== yearPathView.currentIndex
-            sourceComponent: delegateComponent
-
-            Component{
-                id: delegateComponent
-
-                YearViewDelegate{
-                    focus: index == yearPathView.currentIndex
-
-                    scrollMonth: 0;
-                    isCurrentItem: index == yearPathView.currentIndex
-                    year: (currentYear + yearPathView.indexType(index))
-
-                    anchors.fill: parent
+            id: delegateLoader
+
+            asynchronous: true
+            width: PathView.view.width
+            height: PathView.view.height
+
+            sourceComponent: YearViewDelegate {
+                visible: delegateLoader.status === Loader.Ready
+                anchors.fill: parent
+                scrollMonth: 0;
+                isCurrentItem: (index === yearPathView.currentIndex)
+                focus: isCurrentItem
+                year: (yearViewPage.anchorYear + yearPathView.loopCurrentIndex + yearPathView.indexType(index))
+                onMonthSelected: {
+                    yearViewPage.monthSelected(date)
                 }
             }
         }
     }
-
-    Component.onCompleted: {
-        pageHeader.title = Qt.binding(function(){
-            if(mainView.displayLunarCalendar){
-                var lunarDate = Lunar.calendar.solar2lunar(currentYear, 6, 0)
-                return lunarDate.gzYear +" "+ lunarDate.Animal
-            } else {
-                return i18n.tr("Year %1").arg(currentYear)
-            }
-        })
-    }
 }

=== modified file 'YearViewDelegate.qml'
--- YearViewDelegate.qml	2016-02-03 08:06:25 +0000
+++ YearViewDelegate.qml	2016-03-03 21:42:32 +0000
@@ -1,26 +1,37 @@
 import QtQuick 2.4
 import Ubuntu.Components 1.3
 
-GridView{
+    GridView{
     id: yearView
-    clip: true
 
     property int scrollMonth;
     property bool isCurrentItem;
     property int year;
-
+    readonly property var currentDate: new Date()
+    readonly property int currentYear: currentDate.getFullYear()
+    readonly property int currentMonth: currentDate.getMonth()
     readonly property int minCellWidth: units.gu(30)
+
+    signal monthSelected(var date);
+
+    function refresh() {
+        scrollMonth = 0;
+        if(year == currentYear) {
+            scrollMonth = currentMonth
+        }
+        yearView.positionViewAtIndex(scrollMonth, GridView.Beginning);
+    }
+
+    // Does not increase cash buffer if user is scolling
+    cacheBuffer: parent.PathView.view.flicking || parent.PathView.view.dragging || !isCurrentItem ? 0 : 6 * cellHeight
+
     cellWidth: Math.floor(Math.min.apply(Math, [3, 4].map(function(n)
     { return ((width / n >= minCellWidth) ? width / n : width / 2) })))
-
     cellHeight: cellWidth * 1.4
 
+    clip: true
     model: 12 /* months in a year */
 
-    onYearChanged: {
-        refresh();
-    }
-
     //scroll in case content height changed
     onHeightChanged: {
         yearView.positionViewAtIndex(scrollMonth, GridView.Beginning);
@@ -30,71 +41,25 @@
         yearView.positionViewAtIndex(scrollMonth, GridView.Beginning);
     }
 
-    function refresh() {
-        scrollMonth = 0;
-        var today = new Date();
-        if(year == today.getFullYear()) {
-            scrollMonth = today.getMonth();
-        }
-        yearView.positionViewAtIndex(scrollMonth, GridView.Beginning);
-    }
-
-    Connections{
-        target: yearPathView
-        onScrollUp: {
-            scrollMonth -= 2;
-            if(scrollMonth < 0) {
-                scrollMonth = 0;
-            }
-            yearView.positionViewAtIndex(scrollMonth, GridView.Beginning);
-        }
-
-        onScrollDown: {
-            scrollMonth += 2;
-            var visibleMonths = yearView.height / cellHeight;
-            if( scrollMonth >= (11 - visibleMonths)) {
-                scrollMonth = (11 - visibleMonths);
-            }
-            yearView.positionViewAtIndex(scrollMonth, GridView.Beginning);
-        }
-    }
-
-    delegate: Loader {
-        width: yearView.cellWidth
-        height: yearView.cellHeight
-
-        sourceComponent: delegateComponent
-        asynchronous: !yearView.focus
-
-        Component {
-            id: delegateComponent
-
-            Item {
-                anchors.fill: parent
-                anchors.margins: units.gu(0.5)
-
-                MonthComponent {
-                    id: monthComponent
-                    objectName: "monthComponent" + index
-                    showEvents: false
-                    currentMonth: new Date(yearView.year, index, 1, 0, 0, 0, 0)
-                    displayWeekNumber: mainView.displayWeekNumber;
-                    displayLunarCalendar: false; //we disable lunar calendar display in yeaer view due to space
-                    isCurrentItem: yearView.focus
-
-                    isYearView: true
-                    anchors.fill: parent
-
-                    dayLabelFontSize:"x-small"
-                    dateLabelFontSize: "medium"
-                    monthLabelFontSize: "medium"
-                    yearLabelFontSize: "medium"
-
-                    onMonthSelected: {
-                        yearViewPage.monthSelected(date);
-                    }
-                }
-            }
-        }
+    delegate: MonthComponent {
+            id: monthComponent
+            objectName: "monthComponent" + index
+
+            width: yearView.cellWidth - units.gu(1)
+            height: yearView.cellHeight - units.gu(1)
+            y: units.gu(0.5)
+            x: units.gu(0.5)
+
+            currentYear: yearView.year
+            currentMonth: index
+            isCurrentItem: yearView.focus
+            isYearView: true
+            dayLabelFontSize:"x-small"
+            dateLabelFontSize: "medium"
+            monthLabelFontSize: "medium"
+            yearLabelFontSize: "medium"
+            onMonthSelected: {
+                yearView.monthSelected(date);
+            }
     }
 }

=== modified file 'calendar.qml'
--- calendar.qml	2016-02-26 12:57:00 +0000
+++ calendar.qml	2016-03-03 21:42:32 +0000
@@ -92,7 +92,7 @@
     focus: true
     Keys.forwardTo: [pageStack.currentPage]
     backgroundColor: "#ffffff"
-    anchorToKeyboard: true
+    anchorToKeyboard: false
 
     Connections {
         target: UriHandler
@@ -174,6 +174,8 @@
         EventListModel{
             id: eventModel
 
+            property bool isReady: false
+
             autoUpdate: true
             startPeriod: tabs.currentDay
             endPeriod: tabs.currentDay
@@ -193,8 +195,10 @@
                         collectionIds.push(collection.collectionId);
                     }
                 }
+                console.debug("Selected collections:" + collectionIds)
                 collectionFilter.ids = collectionIds;
-                filter = mainFilter
+                filter = Qt.binding(function() { return mainFilter; })
+                isReady = true
             }
 
             function showEventFromId(eventId) {
@@ -395,6 +399,11 @@
                     tabs.selectedTabIndex = settings.defaultViewIndex;
                 }
                 tabs.isReady = true
+                // WORKAROUND: Due the missing feature on SDK, they can not detect if
+                // there is a mouse attached to device or not. And this will cause the
+                // bootom edge component to not work correct on desktop.
+                // We will consider that  a mouse is always attached until it get implement on SDK.
+                QuickUtils.mouseAttached = true
             } // End of Component.onCompleted:
 
             Keys.onTabPressed: {
@@ -530,6 +539,15 @@
         id: yearViewComp
 
         YearView {
+            readonly property bool tabSelected: tabs.selectedTabIndex === yearTab.index
+
+            model: eventModel.isReady ? eventModel : null
+            bootomEdgeEnabled: tabSelected
+
+            onCurrentYearChanged: {
+                tabs.currentDay = new Date(currentYear, 1, 1)
+            }
+
             onMonthSelected: {
                 var now = DateExt.today();
                 if ((date.getMonth() === now.getMonth()) &&
@@ -540,9 +558,10 @@
                 }
                 tabs.selectedTabIndex = monthTab.index;
             }
-            onActiveChanged: {
-                if (active) {
-                    refreshCurrentYear(DateExt.today().getFullYear())
+
+            onTabSelectedChanged: {
+                if (tabSelected) {
+                    refreshCurrentYear(tabs.currentDay.getFullYear())
                 }
             }
         }
@@ -552,13 +571,35 @@
         id: monthViewComp
 
         MonthView {
+            readonly property bool tabSelected: tabs.selectedTabIndex === monthTab.index
+
+            model: eventModel.isReady ? eventModel : null
+            bootomEdgeEnabled: tabSelected
+            displayLunarCalendar: mainView.displayLunarCalendar
+
+            onCurrentDateChanged: {
+                tabs.currentDay = currentDate
+            }
+
+            onHighlightedDateChanged: {
+                if (highlightedDate)
+                    tabs.currentDay = highlightedDate
+                else
+                    tabs.currentDay = currentDate
+            }
+
             onDateSelected: {
-                tabs.currentDay = date;
+                tabs.currentDay = date
                 tabs.selectedTabIndex = dayTab.index
             }
-            onActiveChanged: {
-                if (active)
-                    currentMonth = tabs.currentDay.midnight()
+
+            onTabSelectedChanged: {
+                    if (tabSelected) {
+                        anchorDate = new Date(tabs.currentDay.getFullYear(),
+                                              tabs.currentDay.getMonth(),
+                                              1,
+                                              0, 0, 0)
+                    }
             }
         }
     }
@@ -567,16 +608,44 @@
         id: weekViewComp
 
         WeekView {
-            onDayStartChanged: {
-                tabs.currentDay = dayStart
-            }
+            readonly property bool tabSelected: tabs.selectedTab === weekTab
+
+            model: eventModel.isReady ? eventModel : null
+            bootomEdgeEnabled: tabSelected
+
+            onHighlightedDayChanged: {
+                if (highlightedDay)
+                    tabs.currentDay = highlightedDay
+                else
+                    tabs.currentDay = currentFirstDayOfWeek
+            }
+
+            onCurrentFirstDayOfWeekChanged: {
+                tabs.currentDay = currentFirstDayOfWeek
+            }
+
             onDateSelected: {
                 tabs.currentDay = date;
                 tabs.selectedTabIndex = dayTab.index
             }
-            onActiveChanged: {
-                if (active)
-                    dayStart = tabs.currentDay
+
+            onPressAndHoldAt: {
+                bottomEdgeCommit(date, allDay)
+            }
+
+            onTabSelectedChanged: {
+                if (tabSelected) {
+                    // 'tabs.currntDay' can change after set 'anchorDate' to avoid that
+                    // create a copy of the current value
+                    var tabDate = new Date(tabs.currentDay)
+                    if (!anchorDate ||
+                        (tabs.currentDay.getFullYear() != anchorDate.getFullYear()) ||
+                        (tabs.currentDay.getMonth() != anchorDate.getMonth()) ||
+                        (tabs.currentDay.getDate() != anchorDate.getDate())) {
+                        anchorDate = new Date(tabDate)
+                    }
+                    delayScrollToDate(tabDate)
+                }
             }
         }
     }
@@ -585,17 +654,36 @@
         id: dayViewComp
 
         DayView {
-            onCurrentDayChanged: {
-                tabs.currentDay = currentDay;
-            }
+            readonly property bool tabSelected: tabs.selectedTabIndex === dayTab.index
+
+            model: eventModel.isReady ? eventModel : null
+            bootomEdgeEnabled: tabSelected
 
             onDateSelected: {
                 tabs.currentDay = date
             }
 
-            onActiveChanged: {
-                if (active)
-                    currentDay = tabs.currentDay;
+            onPressAndHoldAt: {
+                bottomEdgeCommit(date, allDay)
+            }
+
+            onCurrentDateChanged: {
+                tabs.currentDay = currentDate
+            }
+
+            onTabSelectedChanged: {
+                if (tabSelected) {
+                    // 'tabs.currntDay' can change after set 'anchorDate' to avoid that
+                    // create a copy of the current value
+                    var tabDate = new Date(tabs.currentDay)
+                    if (!anchorDate ||
+                        (tabs.currentDay.getFullYear() != anchorDate.getFullYear()) ||
+                        (tabs.currentDay.getMonth() != anchorDate.getMonth()) ||
+                        (tabs.currentDay.getDate() != anchorDate.getDate())) {
+                        anchorDate = new Date(tabDate)
+                    }
+                    delayScrollToDate(tabDate)
+                }
             }
         }
     }
@@ -604,6 +692,9 @@
         id: agendaViewComp
 
         AgendaView {
+            model: eventModel.isReady ? eventModel : null
+            bootomEdgeEnabled: tabs.selectedTabIndex === agendaTab.index
+
             onDateSelected: {
                 tabs.currentDay = date;
                 tabs.selectedTabIndex = dayTab.index

=== added file 'calendar_canvas.js'
--- calendar_canvas.js	1970-01-01 00:00:00 +0000
+++ calendar_canvas.js	2016-03-03 21:42:32 +0000
@@ -0,0 +1,52 @@
+.pragma library
+.import "dateExt.js" as DateExt
+
+function minutesSince(since, until)
+{
+    var sinceTime = new Date(since)
+    sinceTime.setSeconds(0)
+    var untilTime =  new Date(until)
+    untilTime.setSeconds(0)
+
+    var sinceTimeInSecs = sinceTime.getTime()
+    var untilTimeInSecs = untilTime.getTime()
+
+    // limit to since day minutes
+    untilTimeInSecs = Math.min(sinceTime.endOfDay().getTime(), untilTimeInSecs)
+
+    // calculate the time in minutes of this event
+    var totalSecs =  untilTimeInSecs - sinceTimeInSecs
+    if (totalSecs > 0)
+        return (totalSecs / 60000)
+
+    return 0
+}
+
+function parseDayEvents(date, itemsOfTheDay)
+{
+    var eventsInfo = []
+    for(var c=0; c < itemsOfTheDay.length; c++) {
+        var event = itemsOfTheDay[c]
+        if (event.allDay)
+            continue
+
+        var eventStartTimeInMinutes = minutesSince(date, event.startDateTime)
+        var eventEndTimeInMinutes = minutesSince(date, event.endDateTime)
+
+        // avoid to draw events too small
+        if ((eventEndTimeInMinutes - eventStartTimeInMinutes) < 20)
+            eventEndTimeInMinutes = eventStartTimeInMinutes + 20
+
+        eventsInfo.push({'eventId': event.itemId,
+                         'eventStartTime': event.startDateTime.getTime(),
+                         'eventEndTime': event.endDateTime.getTime(),
+                         'startTime': eventStartTimeInMinutes,
+                         'endTime': eventEndTimeInMinutes,
+                         'endTimeInSecs': event.endDateTime.getTime(),
+                         'y': -1,
+                         'intersectionCount': 0,
+                         'width': 1.0})
+    }
+
+    return eventsInfo
+}

=== added file 'calendar_canvas_worker.js'
--- calendar_canvas_worker.js	1970-01-01 00:00:00 +0000
+++ calendar_canvas_worker.js	2016-03-03 21:42:32 +0000
@@ -0,0 +1,111 @@
+WorkerScript.onMessage = function(message) {
+    var processedEvents =  dayEventsMap(message.events)
+    WorkerScript.sendMessage({'reply': processedEvents})
+}
+
+function sortByStartAndSize(eventA, eventB)
+{
+    var sort = sortEventsByStart(eventA, eventB)
+    if (sort === 0)
+        sort = sortEventsBySize(eventA, eventB)
+    return sort
+}
+
+function sortEventsByStart(eventA, eventB)
+{
+        if (eventA.startTime < eventB.startTime)
+            return -1
+        else if (eventA.startTime > eventB.startTime)
+            return 1
+        else
+            return 0
+}
+
+function sortEventsBySize(eventA, eventB)
+{
+    var eventAEndTime = eventA.endTimeInSecs
+    var eventBEndTime = eventB.endTimeInSecs
+    if (eventAEndTime > eventBEndTime)
+        return -1
+    else if (eventAEndTime < eventBEndTime)
+        return 1
+    return 0
+}
+
+function yArrayCount(yArray, time)
+{
+    var maxY = yArray.length - 1
+    for(var i=yArray.length - 1; i >= 0; i--) {
+        if (!yArray[i] || (yArray[i].endTime <= time))
+           maxY = i
+    }
+}
+
+/*
+ * Find item 'y' position on the intersection list
+ */
+function findOptimalY(intersections)
+{
+    if (intersections.length === 0)
+        return
+
+    var eventWidth = 1.0 / intersections.length
+    var yArray = new Array(intersections.length)
+    var maxY = 0
+
+    for (var i = 0; i < intersections.length; i++) {
+        var intersection = intersections[i]
+        for (var y=0; y < yArray.length; y++) {
+            if (!yArray[y] || (yArray[y].endTime <= intersection.startTime)) {
+                if (y > maxY)
+                    maxY = y
+                intersection.y = y
+                intersection.intersectionCount = intersections.length
+                yArray[y] = intersection
+                break
+            }
+        }
+    }
+
+    for (var i = 0; i < intersections.length; i++) {
+        intersections[i].width = (1.0 / (maxY  + 1))
+    }
+
+}
+
+function dayEventsMap(eventsInfo)
+{
+    eventsInfo.sort(sortByStartAndSize)
+
+    var events = eventsInfo.slice()
+    var lines = []
+
+    while (events.length > 0) {
+        var aux = {"startTime": 0, "ednTime": 0}
+        var eventA = events[0]
+        events.splice(0, 1)
+        var line = [eventA]
+
+        aux.starTime = eventA.startTime
+        aux.endTime = eventA.endTime
+
+        var newList = []
+        for(var i = 0; i < events.length; i++) {
+            var eventB = events[i]
+            if ((aux.startTime < eventB.endTime) &&
+                (eventB.startTime < aux.endTime)) {
+                if (aux.endTime < eventB.endTime)
+                    aux.endTime = eventB.endTime
+                line.push(eventB)
+            } else {
+                newList.push(eventB)
+            }
+        }
+
+        findOptimalY(line)
+        lines.push(line)
+        events = newList
+    }
+
+    return eventsInfo
+}

=== modified file 'click/calendar.apparmor'
--- click/calendar.apparmor	2015-12-16 10:51:01 +0000
+++ click/calendar.apparmor	2016-03-03 21:42:32 +0000
@@ -6,5 +6,5 @@
         "accounts",
         "push-notification-client"
     ],
-    "policy_version": 1.2
+    "policy_version": 1.3
 }

=== modified file 'click/manifest.json.in'
--- click/manifest.json.in	2015-12-16 10:51:01 +0000
+++ click/manifest.json.in	2016-03-03 21:42:32 +0000
@@ -1,7 +1,7 @@
 {
     "architecture": "all",
     "description": "A calendar for Ubuntu which syncs with online accounts",
-    "framework": "ubuntu-sdk-14.10-qml",
+    "framework": "ubuntu-sdk-15.04.4",
     "hooks": {
         "calendar": {
             "account-application": "@PROJECT_NAME@_@APP_NAME@.application",

=== modified file 'dateExt.js'
--- dateExt.js	2015-11-27 01:34:46 +0000
+++ dateExt.js	2016-03-03 21:42:32 +0000
@@ -60,11 +60,23 @@
 }
 
 Date.prototype.addDays = function(days) {
+    if (days === 0)
+        return this
+
     var date = new Date(this)
     date.setDate(date.getDate() + days);
     return date
 }
 
+Date.prototype.addMinutes = function(minutes) {
+    if (minutes === 0)
+        return this
+
+    var date = new Date(this)
+    date.setMinutes(date.getMinutes() + minutes);
+    return date
+}
+
 Date.prototype.addMonths = function(months) {
     var date = new Date(this)
     date.setMonth(date.getMonth() + months)
@@ -87,8 +99,9 @@
 }
 
 Date.prototype.weekNumber = function(weekStartDay) {
-    var date = this.weekStart(weekStartDay).addDays(3) // Thursday midnight
-    var onejan = new Date(this.getFullYear(), 0, 3);
+    var date = new Date(this)
+    date = date.weekStart(weekStartDay).addDays(3) // Thursday midnight
+    var onejan = new Date(date.getFullYear(), 0, 3);
     return Math.ceil((((date - onejan) / 86400000) + onejan.getDay()+1)/7);
 }
 

=== modified file 'po/com.ubuntu.calendar.pot'
--- po/com.ubuntu.calendar.pot	2016-03-01 11:07:01 +0000
+++ po/com.ubuntu.calendar.pot	2016-03-03 21:42:32 +0000
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2016-03-01 16:35+0530\n"
+"POT-Creation-Date: 2016-03-02 13:04-0300\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -18,221 +18,277 @@
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
 
-#: ../AgendaView.qml:52 ../DayView.qml:41 ../MonthView.qml:40
-#: ../WeekView.qml:45 ../YearView.qml:43
+#: ../AgendaView.qml:53 ../DayView.qml:68 ../MonthView.qml:48
+#: ../WeekView.qml:52 ../YearView.qml:55 ../build/install/AgendaView.qml:53
+#: ../build/install/DayView.qml:43 ../build/install/MonthView.qml:47
+#: ../build/install/WeekView.qml:45 ../build/install/YearView.qml:49
+#: ../build/pkg/AgendaView.qml:53 ../build/pkg/DayView.qml:68
+#: ../build/pkg/MonthView.qml:48 ../build/pkg/WeekView.qml:52
+#: ../build/pkg/YearView.qml:55
 msgid "Today"
 msgstr ""
 
-#: ../AgendaView.qml:62 ../calendar.qml:288 ../calendar.qml:509
+#: ../AgendaView.qml:63 ../build/install/AgendaView.qml:63
+#: ../build/install/calendar.qml:287 ../build/install/calendar.qml:503
+#: ../build/pkg/AgendaView.qml:63 ../build/pkg/calendar.qml:288
+#: ../build/pkg/calendar.qml:504 ../calendar.qml:288 ../calendar.qml:504
 msgid "Agenda"
 msgstr ""
 
-#: ../AgendaView.qml:101
+#: ../AgendaView.qml:101 ../build/install/AgendaView.qml:101
+#: ../build/pkg/AgendaView.qml:101
 msgid "No upcoming events"
 msgstr ""
 
-#: ../AgendaView.qml:104
+#: ../AgendaView.qml:104 ../build/install/AgendaView.qml:104
+#: ../build/pkg/AgendaView.qml:104
 msgid "You have no calendars enabled"
 msgstr ""
 
-#: ../AgendaView.qml:114
+#: ../AgendaView.qml:114 ../build/install/AgendaView.qml:114
+#: ../build/pkg/AgendaView.qml:114
 msgid "Enable calendars"
 msgstr ""
 
 #. TRANSLATORS: the first argument (%1) refers to a start time for an event,
 #. while the second one (%2) refers to the end time
-#: ../AgendaView.qml:177 ../EventBubble.qml:133
+#: ../AgendaView.qml:177 ../EventBubble.qml:97
+#: ../build/install/AgendaView.qml:177 ../build/install/EventBubble.qml:134
+#: ../build/pkg/AgendaView.qml:177 ../build/pkg/EventBubble.qml:97
 #, qt-format
 msgid "%1 - %2"
 msgstr ""
 
-#: ../AgendaView.qml:183
-#, qt-format
-msgid "%1 %2 %3 %4 %5"
+#: ../AllDayEventComponent.qml:86 ../TimeLineBase.qml:50
+#: ../build/install/AllDayEventComponent.qml:108
+#: ../build/install/TimeLineBase.qml:131
+#: ../build/pkg/AllDayEventComponent.qml:86 ../build/pkg/TimeLineBase.qml:50
+msgid "New event"
 msgstr ""
 
 #. TRANSLATORS: the first parameter refers to the number of all-day events
 #. on a given day. "Ev." is short form for "Events".
 #. Please keep the translation of "Ev." to 3 characters only, as the week view
 #. where it's shown has limited space
-#: ../AllDayEventComponent.qml:123
+#: ../AllDayEventComponent.qml:158
+#: ../build/install/AllDayEventComponent.qml:156
+#: ../build/pkg/AllDayEventComponent.qml:158
 #, qt-format
 msgid "%1 ev."
 msgstr ""
 
 #. TRANSLATORS: the argument refers to the number of all day events
-#: ../AllDayEventComponent.qml:127
+#: ../AllDayEventComponent.qml:162
+#: ../build/install/AllDayEventComponent.qml:160
+#: ../build/pkg/AllDayEventComponent.qml:162
 #, qt-format
 msgid "%1 all day event"
 msgid_plural "%1 all day events"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../CalendarChoicePopup.qml:34 ../EventActions.qml:63
+#: ../CalendarChoicePopup.qml:33 ../EventActions.qml:51
+#: ../build/install/CalendarChoicePopup.qml:33
+#: ../build/install/EventActions.qml:51
+#: ../build/pkg/CalendarChoicePopup.qml:33 ../build/pkg/EventActions.qml:51
 msgid "Calendars"
 msgstr ""
 
-#: ../CalendarChoicePopup.qml:36 ../Settings.qml:31
+#: ../CalendarChoicePopup.qml:37 ../Settings.qml:32
+#: ../build/install/CalendarChoicePopup.qml:37
+#: ../build/install/Settings.qml:32 ../build/pkg/CalendarChoicePopup.qml:37
+#: ../build/pkg/Settings.qml:32
 msgid "Back"
 msgstr ""
 
 #. TRANSLATORS: Please translate this string  to 15 characters only.
 #. Currently ,there is no way we can increase width of action menu currently.
-#: ../CalendarChoicePopup.qml:48 ../EventActions.qml:37
+#: ../CalendarChoicePopup.qml:51 ../EventActions.qml:36
+#: ../build/install/CalendarChoicePopup.qml:51
+#: ../build/install/EventActions.qml:36
+#: ../build/pkg/CalendarChoicePopup.qml:51 ../build/pkg/EventActions.qml:36
 msgid "Sync"
 msgstr ""
 
-#: ../CalendarChoicePopup.qml:48 ../EventActions.qml:37
+#: ../CalendarChoicePopup.qml:51 ../EventActions.qml:36
+#: ../build/install/CalendarChoicePopup.qml:51
+#: ../build/install/EventActions.qml:36
+#: ../build/pkg/CalendarChoicePopup.qml:51 ../build/pkg/EventActions.qml:36
 msgid "Syncing"
 msgstr ""
 
-#: ../CalendarChoicePopup.qml:72
+#: ../CalendarChoicePopup.qml:70 ../build/install/CalendarChoicePopup.qml:70
+#: ../build/pkg/CalendarChoicePopup.qml:70
 msgid "Add online Calendar"
 msgstr ""
 
-#: ../ColorPickerDialog.qml:25
+#: ../ColorPickerDialog.qml:25 ../build/install/ColorPickerDialog.qml:25
+#: ../build/pkg/ColorPickerDialog.qml:25
 msgid "Select Color"
 msgstr ""
 
 #: ../ColorPickerDialog.qml:55 ../DeleteConfirmationDialog.qml:60
-#: ../EditEventConfirmationDialog.qml:53
+#: ../EditEventConfirmationDialog.qml:53 ../NewEvent.qml:340
+#: ../build/install/ColorPickerDialog.qml:55
+#: ../build/install/DeleteConfirmationDialog.qml:60
+#: ../build/install/EditEventConfirmationDialog.qml:53
+#: ../build/install/NewEvent.qml:344 ../build/pkg/ColorPickerDialog.qml:55
+#: ../build/pkg/DeleteConfirmationDialog.qml:60
+#: ../build/pkg/EditEventConfirmationDialog.qml:53
+#: ../build/pkg/NewEvent.qml:340
 msgid "Cancel"
 msgstr ""
 
-#: ../ContactChoicePopup.qml:37
+#: ../ContactChoicePopup.qml:37 ../build/install/ContactChoicePopup.qml:37
+#: ../build/pkg/ContactChoicePopup.qml:37
 msgid "No contact"
 msgstr ""
 
-#: ../ContactChoicePopup.qml:83
+#: ../ContactChoicePopup.qml:96 ../build/install/ContactChoicePopup.qml:96
+#: ../build/pkg/ContactChoicePage.qml:50
+#: ../build/pkg/ContactChoicePopup.qml:96
 msgid "Search contact"
 msgstr ""
 
 #. TRANSLATORS: this is a time formatting string,
 #. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
 #. It's used in the header of the month and week views
-#: ../DayView.qml:64 ../DayView.qml:157 ../MonthView.qml:62
-#: ../MonthView.qml:149 ../WeekView.qml:68 ../WeekView.qml:180
+#: ../DayView.qml:110 ../MonthView.qml:69 ../WeekView.qml:116
+#: ../build/install/DayView.qml:67 ../build/install/MonthView.qml:69
+#: ../build/install/WeekView.qml:68 ../build/pkg/DayView.qml:110
+#: ../build/pkg/MonthView.qml:69 ../build/pkg/WeekView.qml:116
 msgid "MMMM yyyy"
 msgstr ""
 
-#: ../DayView.qml:155 ../MonthView.qml:144 ../WeekView.qml:178
-#, qt-format
-msgid "%1 %2"
-msgstr ""
-
 #: ../DeleteConfirmationDialog.qml:31
+#: ../build/install/DeleteConfirmationDialog.qml:31
+#: ../build/pkg/DeleteConfirmationDialog.qml:31
 msgid "Delete Recurring Event"
 msgstr ""
 
 #: ../DeleteConfirmationDialog.qml:32
+#: ../build/install/DeleteConfirmationDialog.qml:32
+#: ../build/pkg/DeleteConfirmationDialog.qml:32
 msgid "Delete Event"
 msgstr ""
 
 #. TRANSLATORS: argument (%1) refers to an event name.
 #: ../DeleteConfirmationDialog.qml:36
+#: ../build/install/DeleteConfirmationDialog.qml:36
+#: ../build/pkg/DeleteConfirmationDialog.qml:36
 #, qt-format
 msgid "Delete only this event \"%1\", or all events in the series?"
 msgstr ""
 
 #: ../DeleteConfirmationDialog.qml:37
+#: ../build/install/DeleteConfirmationDialog.qml:37
+#: ../build/pkg/DeleteConfirmationDialog.qml:37
 #, qt-format
 msgid "Are you sure you want to delete the event \"%1\"?"
 msgstr ""
 
 #: ../DeleteConfirmationDialog.qml:40
+#: ../build/install/DeleteConfirmationDialog.qml:40
+#: ../build/pkg/DeleteConfirmationDialog.qml:40
 msgid "Delete series"
 msgstr ""
 
 #: ../DeleteConfirmationDialog.qml:51
+#: ../build/install/DeleteConfirmationDialog.qml:51
+#: ../build/pkg/DeleteConfirmationDialog.qml:51
 msgid "Delete this"
 msgstr ""
 
-#: ../DeleteConfirmationDialog.qml:51 ../NewEvent.qml:68
+#: ../DeleteConfirmationDialog.qml:51 ../NewEvent.qml:347
+#: ../build/install/DeleteConfirmationDialog.qml:51
+#: ../build/install/NewEvent.qml:352
+#: ../build/pkg/DeleteConfirmationDialog.qml:51 ../build/pkg/NewEvent.qml:347
 msgid "Delete"
 msgstr ""
 
-#: ../EditEventConfirmationDialog.qml:29 ../NewEvent.qml:325
+#: ../EditEventConfirmationDialog.qml:29 ../NewEvent.qml:335
+#: ../build/install/EditEventConfirmationDialog.qml:29
+#: ../build/install/NewEvent.qml:339
+#: ../build/pkg/EditEventConfirmationDialog.qml:29
+#: ../build/pkg/NewEvent.qml:335
 msgid "Edit Event"
 msgstr ""
 
 #. TRANSLATORS: argument (%1) refers to an event name.
 #: ../EditEventConfirmationDialog.qml:32
+#: ../build/install/EditEventConfirmationDialog.qml:32
+#: ../build/pkg/EditEventConfirmationDialog.qml:32
 #, qt-format
 msgid "Edit only this event \"%1\", or all events in the series?"
 msgstr ""
 
 #: ../EditEventConfirmationDialog.qml:35
+#: ../build/install/EditEventConfirmationDialog.qml:35
+#: ../build/pkg/EditEventConfirmationDialog.qml:35
 msgid "Edit series"
 msgstr ""
 
 #: ../EditEventConfirmationDialog.qml:44
+#: ../build/install/EditEventConfirmationDialog.qml:44
+#: ../build/pkg/EditEventConfirmationDialog.qml:44
 msgid "Edit this"
 msgstr ""
 
-#: ../EventActions.qml:52 ../NewEvent.qml:325
-msgid "New Event"
-msgstr ""
-
-#: ../EventActions.qml:75 ../Settings.qml:29
+#: ../EventActions.qml:63 ../Settings.qml:30
+#: ../build/install/EventActions.qml:63 ../build/install/Settings.qml:30
+#: ../build/pkg/EventActions.qml:63 ../build/pkg/Settings.qml:30
 msgid "Settings"
 msgstr ""
 
 #. TRANSLATORS: the first argument (%1) refers to a time for an event,
 #. while the second one (%2) refers to title of event
-#: ../EventBubble.qml:144 ../EventBubble.qml:149
+#: ../EventBubble.qml:108 ../EventBubble.qml:113
+#: ../build/install/EventBubble.qml:145 ../build/install/EventBubble.qml:150
+#: ../build/pkg/EventBubble.qml:108 ../build/pkg/EventBubble.qml:113
 #, qt-format
 msgid "%1 <b>%2</b>"
 msgstr ""
 
-#: ../EventDetails.qml:44 ../NewEvent.qml:436
+#: ../EventDetails.qml:43 ../NewEvent.qml:483
+#: ../build/install/EventDetails.qml:43 ../build/install/NewEvent.qml:489
+#: ../build/pkg/EventDetails.qml:43 ../build/pkg/NewEvent.qml:483
 msgid "Event Details"
 msgstr ""
 
 #. TRANSLATORS: the first parameter refers to the name of event calendar.
-#: ../EventDetails.qml:69
+#: ../EventDetails.qml:68 ../build/install/EventDetails.qml:68
+#: ../build/pkg/EventDetails.qml:68
 #, qt-format
 msgid "%1 Calendar"
 msgstr ""
 
-#: ../EventDetails.qml:143
-#, qt-format
-msgid "%1 %2 %3 - %4 %5 %6 (All Day)"
-msgstr ""
-
-#: ../EventDetails.qml:147
+#: ../EventDetails.qml:129 ../build/install/EventDetails.qml:129
+#: ../build/pkg/EventDetails.qml:129
 #, qt-format
 msgid "%1 - %2 (All Day)"
 msgstr ""
 
-#: ../EventDetails.qml:153
-#, qt-format
-msgid "%1 %2 %3 (All Day)"
-msgstr ""
-
-#: ../EventDetails.qml:156
+#: ../EventDetails.qml:133 ../build/install/EventDetails.qml:133
+#: ../build/pkg/EventDetails.qml:133
 #, qt-format
 msgid "%1 (All Day)"
 msgstr ""
 
-#: ../EventDetails.qml:162
-#, qt-format
-msgid "%1 %2 %3, %4 - %5 %6 %7, %8"
-msgstr ""
-
-#: ../EventDetails.qml:171
-#, qt-format
-msgid "%1 %2 %3, %4 - %5"
-msgstr ""
-
-#: ../EventDetails.qml:238
+#: ../EventDetails.qml:203 ../build/install/EventDetails.qml:203
+#: ../build/pkg/EventDetails.qml:203
 msgid "Edit"
 msgstr ""
 
-#: ../EventDetails.qml:389 ../NewEvent.qml:538
+#: ../EventDetails.qml:354 ../NewEvent.qml:589
+#: ../build/install/EventDetails.qml:354 ../build/install/NewEvent.qml:595
+#: ../build/pkg/EventDetails.qml:354 ../build/pkg/NewEvent.qml:589
 msgid "Guests"
 msgstr ""
 
-#: ../EventDetails.qml:432 ../EventReminder.qml:35 ../NewEvent.qml:635
+#: ../EventDetails.qml:397 ../EventReminder.qml:35 ../NewEvent.qml:701
+#: ../build/install/EventDetails.qml:397 ../build/install/EventReminder.qml:35
+#: ../build/install/NewEvent.qml:711 ../build/pkg/EventDetails.qml:397
+#: ../build/pkg/EventReminder.qml:35 ../build/pkg/NewEvent.qml:701
 msgid "Reminder"
 msgstr ""
 
@@ -241,31 +297,40 @@
 #. and as the header of the list item that shows the repetition
 #. summary in the page that displays the event details
 #: ../EventRepetition.qml:40 ../EventRepetition.qml:155
+#: ../build/install/EventRepetition.qml:40
+#: ../build/install/EventRepetition.qml:155
+#: ../build/pkg/EventRepetition.qml:40 ../build/pkg/EventRepetition.qml:155
 msgid "Repeat"
 msgstr ""
 
-#: ../EventRepetition.qml:174
+#: ../EventRepetition.qml:174 ../build/install/EventRepetition.qml:174
+#: ../build/pkg/EventRepetition.qml:174
 msgid "Repeats On:"
 msgstr ""
 
-#: ../EventRepetition.qml:219
+#: ../EventRepetition.qml:219 ../build/install/EventRepetition.qml:219
+#: ../build/pkg/EventRepetition.qml:219
 msgid "Recurring event ends"
 msgstr ""
 
 #. TRANSLATORS: this refers to how often a recurrent event repeats
 #. and it is shown as the header of the option selector to choose
 #. its repetition
-#: ../EventRepetition.qml:242 ../NewEvent.qml:619
+#: ../EventRepetition.qml:242 ../NewEvent.qml:685
+#: ../build/install/EventRepetition.qml:242 ../build/install/NewEvent.qml:695
+#: ../build/pkg/EventRepetition.qml:242 ../build/pkg/NewEvent.qml:685
 msgid "Repeats"
 msgstr ""
 
-#: ../EventRepetition.qml:267
+#: ../EventRepetition.qml:267 ../build/install/EventRepetition.qml:267
+#: ../build/pkg/EventRepetition.qml:267
 msgid "Date"
 msgstr ""
 
 #. TRANSLATORS: the argument refers to multiple recurrence of event with count .
 #. E.g. "Daily; 5 times."
-#: ../EventUtils.qml:75
+#: ../EventUtils.qml:75 ../build/install/EventUtils.qml:75
+#: ../build/pkg/EventUtils.qml:75
 #, qt-format
 msgid "%1; %2 time"
 msgid_plural "%1; %2 times"
@@ -274,217 +339,270 @@
 
 #. TRANSLATORS: the argument refers to recurrence until user selected date.
 #. E.g. "Daily; until 12/12/2014."
-#: ../EventUtils.qml:79
+#: ../EventUtils.qml:79 ../build/install/EventUtils.qml:79
+#: ../build/pkg/EventUtils.qml:79
 #, qt-format
 msgid "%1; until %2"
 msgstr ""
 
 #. TRANSLATORS: the argument refers to several different days of the week.
 #. E.g. "Weekly on Mondays, Tuesdays"
-#: ../EventUtils.qml:102
+#: ../EventUtils.qml:102 ../build/install/EventUtils.qml:102
+#: ../build/pkg/EventUtils.qml:102
 #, qt-format
 msgid "Weekly on %1"
 msgstr ""
 
-#: ../HeaderDateComponent.qml:90
-#, qt-format
-msgid "%1 %2 %3"
-msgstr ""
-
-#: ../LimitLabelModel.qml:25
+#: ../LimitLabelModel.qml:25 ../build/install/LimitLabelModel.qml:25
+#: ../build/pkg/LimitLabelModel.qml:25
 msgid "Never"
 msgstr ""
 
-#: ../LimitLabelModel.qml:26
+#: ../LimitLabelModel.qml:26 ../build/install/LimitLabelModel.qml:26
+#: ../build/pkg/LimitLabelModel.qml:26
 msgid "After X Occurrence"
 msgstr ""
 
-#: ../LimitLabelModel.qml:27
+#: ../LimitLabelModel.qml:27 ../build/install/LimitLabelModel.qml:27
+#: ../build/pkg/LimitLabelModel.qml:27
 msgid "After Date"
 msgstr ""
 
-#: ../MonthComponent.qml:262
+#: ../MonthComponent.qml:312 ../build/install/MonthComponent.qml:312
+#: ../build/pkg/MonthComponent.qml:312
 msgid "Wk"
 msgstr ""
 
-#: ../NewEvent.qml:84
+#: ../NewEvent.qml:171 ../build/install/NewEvent.qml:173
+#: ../build/pkg/NewEvent.qml:171
+msgid "End time can't be before start time"
+msgstr ""
+
+#: ../NewEvent.qml:335 ../NewEventBottomEdge.qml:52
+#: ../build/install/NewEvent.qml:339
+#: ../build/install/NewEventBottomEdge.qml:49 ../build/pkg/NewEvent.qml:335
+#: ../build/pkg/NewEventBottomEdge.qml:52
+msgid "New Event"
+msgstr ""
+
+#: ../NewEvent.qml:364 ../build/install/NewEvent.qml:370
+#: ../build/pkg/NewEvent.qml:364
 msgid "Save"
 msgstr ""
 
-#: ../NewEvent.qml:192
-msgid "End time can't be before start time"
-msgstr ""
-
-#: ../NewEvent.qml:335
+#: ../NewEvent.qml:375 ../build/install/NewEvent.qml:381
+#: ../build/pkg/NewEvent.qml:375
 msgid "Error"
 msgstr ""
 
-#: ../NewEvent.qml:337
+#: ../NewEvent.qml:377 ../build/install/NewEvent.qml:383
+#: ../build/pkg/NewEvent.qml:377
 msgid "OK"
 msgstr ""
 
-#: ../NewEvent.qml:390
+#: ../NewEvent.qml:437 ../build/install/NewEvent.qml:443
+#: ../build/pkg/NewEvent.qml:437
 msgid "From"
 msgstr ""
 
-#: ../NewEvent.qml:403
+#: ../NewEvent.qml:450 ../build/install/NewEvent.qml:456
+#: ../build/pkg/NewEvent.qml:450
 msgid "To"
 msgstr ""
 
-#: ../NewEvent.qml:420
+#: ../NewEvent.qml:467 ../build/install/NewEvent.qml:473
+#: ../build/pkg/NewEvent.qml:467
 msgid "All day event"
 msgstr ""
 
-#: ../NewEvent.qml:449
+#: ../NewEvent.qml:497 ../build/install/NewEvent.qml:503
+#: ../build/pkg/NewEvent.qml:497
 msgid "Event Name"
 msgstr ""
 
-#: ../NewEvent.qml:467
+#: ../NewEvent.qml:515 ../build/install/NewEvent.qml:521
+#: ../build/pkg/NewEvent.qml:515
 msgid "Description"
 msgstr ""
 
-#: ../NewEvent.qml:485
+#: ../NewEvent.qml:534 ../build/install/NewEvent.qml:540
+#: ../build/pkg/NewEvent.qml:534
 msgid "Location"
 msgstr ""
 
-#: ../NewEvent.qml:500 com.ubuntu.calendar_calendar.desktop.in.in.h:1
+#: ../NewEvent.qml:549 ../build/install/NewEvent.qml:555
+#: ../build/pkg/NewEvent.qml:549
+#: com.ubuntu.calendar_calendar.desktop.in.in.h:1
 msgid "Calendar"
 msgstr ""
 
-#: ../NewEvent.qml:542
+#: ../NewEvent.qml:598 ../build/install/NewEvent.qml:604
+#: ../build/pkg/NewEvent.qml:598
 msgid "Add Guest"
 msgstr ""
 
 #: ../RecurrenceLabelDefines.qml:23
+#: ../build/install/RecurrenceLabelDefines.qml:23
+#: ../build/pkg/RecurrenceLabelDefines.qml:23
 msgid "Once"
 msgstr ""
 
 #: ../RecurrenceLabelDefines.qml:24
+#: ../build/install/RecurrenceLabelDefines.qml:24
+#: ../build/pkg/RecurrenceLabelDefines.qml:24
 msgid "Daily"
 msgstr ""
 
 #: ../RecurrenceLabelDefines.qml:25
+#: ../build/install/RecurrenceLabelDefines.qml:25
+#: ../build/pkg/RecurrenceLabelDefines.qml:25
 msgid "On Weekdays"
 msgstr ""
 
 #. TRANSLATORS: The arguments refer to days of the week. E.g. "On Monday, Tuesday, Thursday"
 #: ../RecurrenceLabelDefines.qml:27
+#: ../build/install/RecurrenceLabelDefines.qml:27
+#: ../build/pkg/RecurrenceLabelDefines.qml:27
 #, qt-format
 msgid "On %1, %2 ,%3"
 msgstr ""
 
 #. TRANSLATORS: The arguments refer to days of the week. E.g. "On Monday and Thursday"
 #: ../RecurrenceLabelDefines.qml:29
+#: ../build/install/RecurrenceLabelDefines.qml:29
+#: ../build/pkg/RecurrenceLabelDefines.qml:29
 #, qt-format
 msgid "On %1 and %2"
 msgstr ""
 
 #: ../RecurrenceLabelDefines.qml:30
+#: ../build/install/RecurrenceLabelDefines.qml:30
+#: ../build/pkg/RecurrenceLabelDefines.qml:30
 msgid "Weekly"
 msgstr ""
 
 #: ../RecurrenceLabelDefines.qml:31
+#: ../build/install/RecurrenceLabelDefines.qml:31
+#: ../build/pkg/RecurrenceLabelDefines.qml:31
 msgid "Monthly"
 msgstr ""
 
 #: ../RecurrenceLabelDefines.qml:32
+#: ../build/install/RecurrenceLabelDefines.qml:32
+#: ../build/pkg/RecurrenceLabelDefines.qml:32
 msgid "Yearly"
 msgstr ""
 
-#: ../RemindersModel.qml:26
+#: ../RemindersModel.qml:26 ../build/install/RemindersModel.qml:26
+#: ../build/pkg/RemindersModel.qml:26
 msgid "No Reminder"
 msgstr ""
 
 #. TRANSLATORS: this refers to when a reminder should be shown as a notification
 #. in the indicators. "On Event" means that it will be shown right at the time
 #. the event starts, not any time before
-#: ../RemindersModel.qml:30
+#: ../RemindersModel.qml:30 ../build/install/RemindersModel.qml:30
+#: ../build/pkg/RemindersModel.qml:30
 msgid "On Event"
 msgstr ""
 
-#: ../RemindersModel.qml:31
+#: ../RemindersModel.qml:31 ../build/install/RemindersModel.qml:31
+#: ../build/pkg/RemindersModel.qml:31
 msgid "5 minutes"
 msgstr ""
 
-#: ../RemindersModel.qml:32
+#: ../RemindersModel.qml:32 ../build/install/RemindersModel.qml:32
+#: ../build/pkg/RemindersModel.qml:32
 msgid "15 minutes"
 msgstr ""
 
-#: ../RemindersModel.qml:33
+#: ../RemindersModel.qml:33 ../build/install/RemindersModel.qml:33
+#: ../build/pkg/RemindersModel.qml:33
 msgid "30 minutes"
 msgstr ""
 
-#: ../RemindersModel.qml:34
+#: ../RemindersModel.qml:34 ../build/install/RemindersModel.qml:34
+#: ../build/pkg/RemindersModel.qml:34
 msgid "1 hour"
 msgstr ""
 
-#: ../RemindersModel.qml:35
+#: ../RemindersModel.qml:35 ../build/install/RemindersModel.qml:35
+#: ../build/pkg/RemindersModel.qml:35
 msgid "2 hours"
 msgstr ""
 
-#: ../RemindersModel.qml:36
+#: ../RemindersModel.qml:36 ../build/install/RemindersModel.qml:36
+#: ../build/pkg/RemindersModel.qml:36
 msgid "1 day"
 msgstr ""
 
-#: ../RemindersModel.qml:37
+#: ../RemindersModel.qml:37 ../build/install/RemindersModel.qml:37
+#: ../build/pkg/RemindersModel.qml:37
 msgid "2 days"
 msgstr ""
 
-#: ../RemindersModel.qml:38
+#: ../RemindersModel.qml:38 ../build/install/RemindersModel.qml:38
+#: ../build/pkg/RemindersModel.qml:38
 msgid "1 week"
 msgstr ""
 
-#: ../RemindersModel.qml:39
+#: ../RemindersModel.qml:39 ../build/install/RemindersModel.qml:39
+#: ../build/pkg/RemindersModel.qml:39
 msgid "2 weeks"
 msgstr ""
 
-#: ../Settings.qml:55
+#: ../Settings.qml:60 ../build/install/Settings.qml:60
+#: ../build/pkg/Settings.qml:60
 msgid "Show week numbers"
 msgstr ""
 
-#: ../Settings.qml:71
-msgid "Show lunar calendar"
-msgstr ""
-
-#: ../TimeLineBase.qml:73
-msgid "Untitled"
-msgstr ""
-
 #. TRANSLATORS: W refers to Week, followed by the actual week number (%1)
-#: ../TimeLineHeader.qml:53
+#: ../TimeLineHeader.qml:54 ../build/install/TimeLineHeader.qml:54
+#: ../build/pkg/TimeLineHeader.qml:54
 #, qt-format
 msgid "W%1"
 msgstr ""
 
-#: ../TimeLineHeader.qml:65
+#: ../TimeLineHeader.qml:66 ../build/install/TimeLineHeader.qml:66
+#: ../build/pkg/TimeLineHeader.qml:66
 msgid "All Day"
 msgstr ""
 
-#: ../YearView.qml:61 ../YearView.qml:112
+#: ../YearView.qml:72 ../build/install/YearView.qml:66
+#: ../build/pkg/YearView.qml:72
 #, qt-format
 msgid "Year %1"
 msgstr ""
 
-#: ../calendar.qml:46
+#: ../build/install/calendar.qml:45 ../build/pkg/calendar.qml:45
+#: ../calendar.qml:45
 msgid ""
 "Calendar app accept four arguments: --starttime, --endtime, --newevent and --"
 "eventid. They will be managed by system. See the source for a full comment "
 "about them"
 msgstr ""
 
-#: ../calendar.qml:256 ../calendar.qml:425
+#: ../build/install/calendar.qml:255 ../build/install/calendar.qml:419
+#: ../build/pkg/calendar.qml:256 ../build/pkg/calendar.qml:420
+#: ../calendar.qml:256 ../calendar.qml:420
 msgid "Year"
 msgstr ""
 
-#: ../calendar.qml:264 ../calendar.qml:446
+#: ../build/install/calendar.qml:263 ../build/install/calendar.qml:440
+#: ../build/pkg/calendar.qml:264 ../build/pkg/calendar.qml:441
+#: ../calendar.qml:264 ../calendar.qml:441
 msgid "Month"
 msgstr ""
 
-#: ../calendar.qml:272 ../calendar.qml:467
+#: ../build/install/calendar.qml:271 ../build/install/calendar.qml:461
+#: ../build/pkg/calendar.qml:272 ../build/pkg/calendar.qml:462
+#: ../calendar.qml:272 ../calendar.qml:462
 msgid "Week"
 msgstr ""
 
-#: ../calendar.qml:280 ../calendar.qml:488
+#: ../build/install/calendar.qml:279 ../build/install/calendar.qml:482
+#: ../build/pkg/calendar.qml:280 ../build/pkg/calendar.qml:483
+#: ../calendar.qml:280 ../calendar.qml:483
 msgid "Day"
 msgstr ""
 

=== added file 'tests/unittests/tst_calendar_canvas.qml'
--- tests/unittests/tst_calendar_canvas.qml	1970-01-01 00:00:00 +0000
+++ tests/unittests/tst_calendar_canvas.qml	2016-03-03 21:42:32 +0000
@@ -0,0 +1,672 @@
+import QtQuick 2.0
+import QtTest 1.0
+import QtOrganizer 5.0
+
+import "../../calendar_canvas.js" as CanvasJs
+
+TestCase{
+    id: root
+    name: "Date tests"
+
+    Component {
+        id: modelComp
+
+        OrganizerModel {
+            id: eventModel
+
+            manager: "memory"
+            startPeriod: new Date(2016, 7, 2, 0, 0, 0, 0)
+            endPeriod: new Date(2016, 13, 2, 0, 0, 0, 0)
+            autoUpdate: true
+        }
+    }
+
+    Component {
+        id: eventComp
+
+        Event {
+        }
+    }
+
+    Component {
+        id: spyComp
+
+        SignalSpy {
+            id: spy
+            signalName: "onModelChanged"
+        }
+    }
+
+    WorkerScript {
+        id: worker
+
+        property var reply: null
+        property var eventsById: []
+        property bool done: false
+
+        function start(model, startDate)
+        {
+            worker.done = false
+            worker.reply = null
+            worker.eventsById = []
+
+            var itemsOfTheDay = model.itemsByTimePeriod(startDate.midnight(), startDate.endOfDay())
+            for(var i=0; i < itemsOfTheDay.length; i++) {
+                var e = itemsOfTheDay[i]
+                worker.eventsById[e.itemId] = e
+            }
+
+            console.debug("Items of Day:"+ itemsOfTheDay.length)
+
+            var events = CanvasJs.parseDayEvents(startDate.midnight(), itemsOfTheDay)
+            console.debug("Events:" + events.length)
+            worker.sendMessage({'events': events})
+        }
+
+        source: Qt.resolvedUrl("../../calendar_canvas_worker.js")
+        onMessage: {
+            var reply =  messageObject.reply
+            console.debug("Reply:" + reply.length)
+            for(var i=0; i < reply.length; i++) {
+                var info = reply[i]
+                console.debug("I:" + i + " id:" + info.eventId + " e:" + worker.eventsById[info.eventId])
+                info['event'] = worker.eventsById[info.eventId]
+            }
+            reply.sort(sortEventsByDateAndY)
+            worker.reply =reply
+            worker.done = true
+        }
+    }
+
+    function create_event_from_data(model, data)
+    {
+        return eventComp.createObject(model,
+                                      {'allDay': false,
+                                       'displayLabel': data.label,
+                                       'startDateTime': data.startDate,
+                                       'endDateTime': data.endDate})
+    }
+
+    function create_events(data)
+    {
+        var model = modelComp.createObject(root, {});
+        var spy = spyComp.createObject(root, {'target': model})
+
+        for(var i=0; i < data.length; i++) {
+            var ev = create_event_from_data(model, data[i])
+            model.saveItem(ev)
+            tryCompare(spy, 'count', i+1)
+        }
+        compare(model.itemCount, data.length)
+        return model
+    }
+
+    function debug_map(map)
+    {
+        for(var k in map) {
+            var info = map[k]
+            console.debug("\t" + (info.event ? info.event.displayLabel : "null") + " y:" + info.y)
+        }
+    }
+
+    function sortEventsByDateAndY(eventA, eventB)
+    {
+        if (eventA.startTime < eventB.startTime)
+            return -1
+        else if (eventA.startTime > eventB.startTime)
+            return 1
+        else {
+            if (eventA.y < eventB.y)
+                return -1
+            else if (eventA.y > eventB.y)
+                return 1
+        }
+        return 0
+    }
+
+    //    10:00 ----
+    //          |XX|
+    //    11:00 ----
+
+    //    12:00
+
+    //    13:00 ----
+    //          ----
+    //    14:00
+    function test_two_events_in_distinct_time()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 13, 30, 0, 0),
+                     label: "Event at 13:00 until 13:30"},
+                    {startDate: new Date(2016, 7, 2, 10, 10, 0, 0),
+                     endDate: new Date(2016, 7, 2, 11, 00, 0, 0),
+                     label: "Event at 10:10 until 11:00"}]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+
+        var eventMap = worker.reply
+        //"Event at 10:10 until 11:00"
+        var eventsAtTenTen = eventMap[0]
+        compare(eventsAtTenTen.event.displayLabel, "Event at 10:10 until 11:00")
+        compare(eventsAtTenTen.y, 0)
+
+        //"Event at 13:00 until 13:30"
+        var eventsAtOnePm = eventMap[1]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 13:30")
+        compare(eventsAtTenTen.y, 0)
+    }
+
+    //    13:00 ---- ----
+    //          |XX| |XX|
+    //    14:00 ---- ----
+    //
+    //    15:00
+    function test_two_events_at_the_same_time()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 13, 30, 0, 1),
+                     label: "Event at 13:00 until 13:30"},
+                    {startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 13, 30, 0, 0),
+                     label: "Event at 13:00 until 13:30 (1)"}]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        //"Event at 13:00 until 13:30"
+        var eventsAtOnePm = eventMap[0]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 13:30")
+        compare(eventsAtOnePm.y, 0)
+
+        eventsAtOnePm = eventMap[1]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 13:30 (1)")
+        compare(eventsAtOnePm.y, 1)
+    }
+
+    //    13:00 ----
+    //          |XX|
+    //    14:00 |XX| ----
+    //          |XX| |XX|
+    //    15:00 |XX| ----
+    //          ----
+    //    16:00
+    function test_intersec_two_events()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 30, 0, 0),
+                     label: "Event at 13:00 until 15:30"},
+                    {startDate: new Date(2016, 7, 2, 14, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 00, 0, 0),
+                     label: "Event at 14:00 until 15:00"}]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        //"Event at 13:00 until 15:30"
+        var eventsAtOnePm = eventMap[0]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 15:30")
+        compare(eventsAtOnePm.y, 0)
+
+        //Event at 14:00 until 15:00
+        var eventsAtTwoPm = eventMap[1]
+        compare(eventsAtTwoPm.event.displayLabel, "Event at 14:00 until 15:00")
+        compare(eventsAtTwoPm.y, 1)
+    }
+
+    //    13:00 ----
+    //          |XX| ----
+    //    14:00 |XX| |XX|
+    //          |XX| |XX|
+    //    15:00 |XX| |XX| ----
+    //          ---- ---- |XX|
+    //    16:00           |XX|
+    //                    |XX|
+    //    17:00           |XX|
+    //                    |XX|
+    //    18:00           |XX|
+    //                    |XX|
+    //    19:00           ----
+    function test_intersec_three_events()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 30, 0, 0),
+                     label: "Event at 13:00 until 15:30"},
+                    {startDate: new Date(2016, 7, 2, 13, 30, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 30, 0, 0),
+                     label: "Event at 13:30 until 15:30"},
+                    {startDate: new Date(2016, 7, 2, 15, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 19, 00, 0, 0),
+                     label: "Event at 15:00 until 19:00"}]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        //"Event at 13:00 until 15:30"
+        var eventsAtOnePm = eventMap[0]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 15:30")
+        compare(eventsAtOnePm.y, 0)
+
+        //"Event at 13:30 until 15:30"
+        var eventsAtHalfPastOnePm = eventMap[1]
+        compare(eventsAtHalfPastOnePm.event.displayLabel, "Event at 13:30 until 15:30")
+        compare(eventsAtHalfPastOnePm.y, 1)
+
+        //"Event at 15:00 until 19:00"
+        var eventsAtThreePm = eventMap[2]
+        compare(eventsAtThreePm.event.displayLabel, "Event at 15:00 until 19:00")
+        compare(eventsAtThreePm.y, 2)
+    }
+
+    //    13:00 ----
+    //          |XX|
+    //    14:00 |XX| ----
+    //          |XX| |XX|
+    //    15:00 |XX| |XX|
+    //          ---- |XX|
+    //    16:00      |XX|
+    //          ---- |XX|
+    //    17:00 |XX| |XX|
+    //          ---- |XX|
+    //    18:00      |XX|
+    //               |XX|
+    //    19:00      |XX|
+    //               ----
+    //    20:00
+    function test_intersec_three_events_2()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 30, 0, 0),
+                     label: "Event at 13:00 until 15:30"},
+                    {startDate: new Date(2016, 7, 2, 14, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 19, 30, 0, 0),
+                     label: "Event at 14:00 until 19:30"},
+                    {startDate: new Date(2016, 7, 2, 16, 30, 0, 0),
+                     endDate: new Date(2016, 7, 2, 17, 30, 0, 0),
+                     label: "Event at 16:30 until 17:30"}]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        //"Event at 13:00 until 15:30"
+        var eventsAtOnePm = eventMap[0]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 15:30")
+        compare(eventsAtOnePm.y, 0)
+
+        //"Event at 14:00 until 19:30"
+        var eventsAtTwoPm = eventMap[1]
+        compare(eventsAtTwoPm.event.displayLabel, "Event at 14:00 until 19:30")
+        compare(eventsAtTwoPm.y, 1)
+
+
+        //"Event at 16:30 until 17:30"
+        var eventsHalfPastFor = eventMap[2]
+        compare(eventsHalfPastFor.event.displayLabel, "Event at 16:30 until 17:30")
+        compare(eventsHalfPastFor.y, 0)
+
+    }
+
+    //    13:00 ---- ---- ----
+    //          |XX| |XX| |XX|
+    //    14:00 |XX| |XX| ----
+    //          |XX| |XX|
+    //    15:00 |XX| |XX| ---- ---- ----
+    //          |XX| |XX| |XX| |XX| |XX|
+    //    16:00 |XX| |XX| ---- ---- ----
+    //          |XX| |XX|
+    //    17:00 |XX| |XX|
+    //          |XX| ----
+    //    18:00 |XX|
+    function test_intersec_events_after()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 17, 30, 0, 0),
+                     label: "Event at 13:00 until 17:30"},
+                    {startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 18, 30, 0, 0),
+                     label: "Event at 13:00 until 18:30"},
+                    {startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 14, 0, 0, 0),
+                     label: "Event at 13:00 until 14:00"},
+                    {startDate: new Date(2016, 7, 2, 15, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 16, 0, 0, 3),
+                     label: "Event at 15:00 until 16:00"},
+                    {startDate: new Date(2016, 7, 2, 15, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 16, 0, 0, 2),
+                     label: "Event at 15:00 until 16:00 (1)"},
+                    {startDate: new Date(2016, 7, 2, 15, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 16, 0, 0, 1),
+                     label: "Event at 15:00 until 16:00 (2)"}
+                ]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        //Events @13:00
+        var eventsAtOnePm = eventMap[0]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 18:30")
+        compare(eventsAtOnePm.y, 0)
+
+        eventsAtOnePm = eventMap[1]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 17:30")
+        compare(eventsAtOnePm.y, 1)
+
+        eventsAtOnePm = eventMap[2]
+        compare(eventsAtOnePm.event.displayLabel, "Event at 13:00 until 14:00")
+        compare(eventsAtOnePm.y, 2)
+
+
+        //"Events @15:00
+        var eventsAtThreePm = eventMap[3]
+        compare(eventsAtThreePm.event.displayLabel, "Event at 15:00 until 16:00")
+        compare(eventsAtThreePm.y, 2)
+
+        eventsAtThreePm = eventMap[4]
+        compare(eventsAtThreePm.event.displayLabel, "Event at 15:00 until 16:00 (1)")
+        compare(eventsAtThreePm.y, 3)
+
+        eventsAtThreePm = eventMap[5]
+        compare(eventsAtThreePm.event.displayLabel, "Event at 15:00 until 16:00 (2)")
+        compare(eventsAtThreePm.y, 4)
+    }
+
+    //    12:00 ---- ----
+    //          |XX| |XX| ----
+    //    14:00 |XX| |XX| |XX|
+    //          |XX| |XX| ----
+    //    15:00 |XX| |XX|
+    //          ---- ----
+    function test_intersec_three_events_3()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 12, 30, 0, 0),
+                     endDate: new Date(2016, 7, 2, 14, 30, 0, 0),
+                     label: "Event at 12:30 until 14:30"},
+                    {startDate: new Date(2016, 7, 2, 12, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 30, 0, 1),
+                     label: "Event at 12:00 until 15:30"},
+                    {startDate: new Date(2016, 7, 2, 12, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 30, 0, 0),
+                     label: "Event at 12:00 until 15:30 (1)"}]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        //"Event at 12:00 until 15:30"
+        var eventsAtNoon = eventMap[0]
+        compare(eventsAtNoon.event.displayLabel, "Event at 12:00 until 15:30")
+        compare(eventsAtNoon.y, 0)
+
+        eventsAtNoon = eventMap[1]
+        compare(eventsAtNoon.event.displayLabel, "Event at 12:00 until 15:30 (1)")
+        compare(eventsAtNoon.y, 1)
+
+        //"Event at 12:30 until 14:30"
+        var eventsAtHalfPastNoon = eventMap[2]
+        compare(eventsAtHalfPastNoon.event.displayLabel, "Event at 12:30 until 14:30")
+        compare(eventsAtHalfPastNoon.y, 2)
+    }
+
+    function test_intersec_three_events_4()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 12, 15, 0, 0),
+                     endDate: new Date(2016, 7, 2, 12, 30, 0, 0),
+                     label: "Event at 12:15 until 12:30"},
+                    {startDate: new Date(2016, 7, 2, 12, 00, 0, 0),
+                     endDate: new Date(2016, 7, 2, 12, 30, 0, 1),
+                     label: "Event at 12:00 until 12:30"},
+                    {startDate: new Date(2016, 7, 2, 12, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 12, 30, 0, 0),
+                     label: "Event at 12:00 until 12:30 (1)"}]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        //"Event at 12:00 until 12:30"
+        var eventsAtNoon = eventMap[0]
+        compare(eventsAtNoon.event.displayLabel, "Event at 12:00 until 12:30")
+        compare(eventsAtNoon.y, 0)
+
+        eventsAtNoon = eventMap[1]
+        compare(eventsAtNoon.event.displayLabel, "Event at 12:00 until 12:30 (1)")
+        compare(eventsAtNoon.y, 1)
+
+        //"Event at 12:15 until 12:20"
+        var eventsAtHalfPastNoon = eventMap[2]
+        compare(eventsAtHalfPastNoon.event.displayLabel, "Event at 12:15 until 12:30")
+        compare(eventsAtHalfPastNoon.y, 2)
+    }
+
+    function test_intersec_next_day_events()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 23, 00, 0, 0),
+                     endDate: new Date(2016, 7, 2, 23, 30, 0, 0),
+                     label: "Event at 23:00 until 23:30"},
+                    {startDate: new Date(2016, 7, 2, 23, 10, 0, 0),
+                     endDate: new Date(2016, 7, 3, 00, 30, 0, 0),
+                     label: "Event at 23:10 until 00:30"}]
+        var model = create_events(data)
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        //"Event at 23:00 until 23:30"
+        var eventsAtElevenPm = eventMap[0]
+        compare(eventsAtElevenPm.event.displayLabel, "Event at 23:00 until 23:30")
+        compare(eventsAtElevenPm.y, 0)
+
+        //"Event at 23:30 until 00:30"
+        var eventsAtHalfPastElevenPm = eventMap[1]
+        compare(eventsAtHalfPastElevenPm.event.displayLabel, "Event at 23:10 until 00:30")
+        compare(eventsAtHalfPastElevenPm.y, 1)
+    }
+
+    //    10:00 ----
+    //          |XX|
+    //    11:00 |XX| ----
+    //          |XX| |XX|
+    //    12:00 |XX| |XX|
+    //          |XX| |XX|
+    //    13:00 ---- |XX|
+    //          |XX| |XX|
+    //    14:00 |XX| ----
+    //          |XX|
+    //    15:00 |XX| ----
+    //          |XX| |XX|
+    //    16:00 |XX| |XX|
+    //          ---- |XX|
+    //    17:00      ----
+    function test_intersec_five_events()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 10, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     label: "Event at 10:00 until 13:00"},
+                    {startDate: new Date(2016, 7, 2, 11, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 14, 00, 0, 0),
+                     label: "Event at 11:00 until 14:00"},
+                    {startDate: new Date(2016, 7, 2, 13, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 16, 30, 0, 0),
+                     label: "Event at 13:00 until 16:30"},
+                    {startDate: new Date(2016, 7, 2, 15, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 17, 00, 0, 0),
+                     label: "Event at 15:00 until 17:00"}
+                ]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        // "Event at 10:00 until 13:00"
+        var eventsAtTen = eventMap[0]
+        compare(eventsAtTen.event.displayLabel, "Event at 10:00 until 13:00")
+        compare(eventsAtTen.y, 0)
+
+        //"Event at 11:00 until 14:00"
+        var eventsAtEleven = eventMap[1]
+        compare(eventsAtEleven.event.displayLabel, "Event at 11:00 until 14:00")
+        compare(eventsAtEleven.y, 1)
+
+        //"Event at 13:00 until 16:30"
+        var eventAtOnePm = eventMap[2]
+        compare(eventAtOnePm.event.displayLabel, "Event at 13:00 until 16:30")
+        compare(eventAtOnePm.y, 0)
+
+        //"Event at 15:00 until 17:00"
+        var eventAtThreePm = eventMap[3]
+        compare(eventAtThreePm.event.displayLabel, "Event at 15:00 until 17:00")
+        compare(eventAtThreePm.y, 1)
+    }
+
+    //    10:00 ----
+    //          |XX|
+    //    11:00 |XX| ----
+    //          |XX| |XX|
+    //    12:00 |XX| |XX|
+    //          |XX| |XX|
+    //    13:00 |XX| |XX|
+    //          |XX| |XX|
+    //    14:00 |XX| |XX|
+    //          ---- |XX|
+    //    15:00 |XX| |XX|
+    //          |XX| |XX|
+    //    16:00 |XX| |XX| ----
+    //          ---- |XX| |XX|
+    //    17:00      ---- |XX|
+    //                    ----
+    //    18:00
+    function test_intersec_between_10_18()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 10, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 14, 30, 0, 0),
+                     label: "Event at 10:00 until 14:30"},
+                    {startDate: new Date(2016, 7, 2, 11, 0, 0, 0),
+                     endDate: new Date(2016, 7, 2, 17, 00, 0, 0),
+                     label: "Event at 11:00 until 17:00"},
+                    {startDate: new Date(2016, 7, 2, 14, 30, 0, 0),
+                     endDate: new Date(2016, 7, 2, 16, 30, 0, 0),
+                     label: "Event at 14:30 until 16:30"},
+                    {startDate: new Date(2016, 7, 2, 16, 00, 0, 0),
+                     endDate: new Date(2016, 7, 2, 17, 30, 0, 0),
+                     label: "Event at 16:00 until 17:30"}
+
+                ]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        // "Event at 10:00 until 14:30"
+        var eventsA = eventMap[0]
+        compare(eventsA.event.displayLabel, "Event at 10:00 until 14:30")
+        compare(eventsA.y, 0)
+
+        //"Event at 11:00 until 17:00"
+        var eventsB = eventMap[1]
+        compare(eventsB.event.displayLabel, "Event at 11:00 until 17:00")
+        compare(eventsB.y, 1)
+
+        //"Event at 14:30 until 16:30"
+        var eventsC = eventMap[2]
+        compare(eventsC.event.displayLabel, "Event at 14:30 until 16:30")
+        compare(eventsC.y, 0)
+
+        //"Event at 16:00 until 17:30"
+        var eventsD = eventMap[3]
+        compare(eventsD.event.displayLabel, "Event at 16:00 until 17:30")
+        compare(eventsD.y, 2)
+    }
+
+    //    14:00 ----
+    //          |XX| ---- ----
+    //    15:00 ---- ---- |XX|
+    //          ---- ---- ----
+    //    16:00 ---- ----
+    //
+    function test_intersec_between_14_15_until_16_30()
+    {
+        var data = [{startDate: new Date(2016, 7, 2, 14, 15, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 15, 0, 0),
+                     label: "Event at 14:15 until 15:15"},
+                    {startDate: new Date(2016, 7, 2, 14, 30, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 00, 0, 0),
+                     label: "Event at 14:30 until 15:00"},
+                    {startDate: new Date(2016, 7, 2, 14, 45, 0, 0),
+                     endDate: new Date(2016, 7, 2, 15, 45, 0, 0),
+                     label: "Event at 14:45 until 15:45"},
+                    {startDate: new Date(2016, 7, 2, 15, 30, 0, 0),
+                     endDate: new Date(2016, 7, 2, 16, 30, 0, 1),
+                     label: "Event at 15:30 until 16:30"},
+                    {startDate: new Date(2016, 7, 2, 15, 30, 0, 0),
+                     endDate: new Date(2016, 7, 2, 16, 30, 0, 0),
+                     label: "Event at 15:30 until 16:30 (1)"}
+                ]
+        var model = create_events(data)
+
+        var startDate = new Date(2016, 7, 2, 11, 11, 11, 11)
+        worker.start(model, startDate)
+        tryCompare(worker, 'done', true)
+        var eventMap = worker.reply
+
+        // "Event at 14:15 until 15:15"
+        var eventsA = eventMap[0]
+        compare(eventsA.event.displayLabel, "Event at 14:15 until 15:15")
+        compare(eventsA.y, 0)
+        compare(eventsA.intersectionCount, 5)
+        fuzzyCompare(eventsA.width, 0.2, 0.1)
+
+        //"Event at 14:30 until 15:00"
+        var eventsB = eventMap[1]
+        compare(eventsB.event.displayLabel, "Event at 14:30 until 15:00")
+        compare(eventsB.y, 1)
+        compare(eventsB.intersectionCount, 5)
+        fuzzyCompare(eventsB.width, 0.2, 0.1)
+
+        //"Event at 14:45 until 15:45"
+        var eventsC = eventMap[2]
+        compare(eventsC.event.displayLabel, "Event at 14:45 until 15:45")
+        compare(eventsC.y, 2)
+        compare(eventsC.intersectionCount, 5)
+        fuzzyCompare(eventsC.width, 0.2, 0.1)
+
+        //"Event at 15:30 until 16:30"
+        var eventsD = eventMap[3]
+        compare(eventsD.event.displayLabel, "Event at 15:30 until 16:30")
+        compare(eventsD.y, 0)
+        compare(eventsD.intersectionCount, 5)
+        fuzzyCompare(eventsD.width, 0.2, 0.1)
+
+        //"Event at 15:30 until 16:30 (1)"
+        var eventsE = eventMap[4]
+        compare(eventsE.event.displayLabel, "Event at 15:30 until 16:30 (1)")
+        compare(eventsE.y, 1)
+        compare(eventsE.intersectionCount, 5)
+        fuzzyCompare(eventsE.width, 0.2, 0.1)
+    }
+}


References