calendarui/views/dayview/src/calendaycontainer.cpp
changeset 50 579cc610882e
child 55 2c54b51f39c4
child 58 ef813d54df51
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calendarui/views/dayview/src/calendaycontainer.cpp	Tue Jul 06 14:14:56 2010 +0300
@@ -0,0 +1,531 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Day view control of calendar
+*
+*/
+
+//System includes
+#include <QTime>
+#include <QGraphicsLinearLayout>
+#include <QGesture>
+
+#ifdef _DEBUG
+	#include <QPainter>
+#endif
+
+#include <hbabstractitemview.h>
+#include <hbtextitem.h>
+#include <hbmodeliterator.h>
+#include <hbinstance.h>
+
+//User includes
+#include "calendaycontainer.h"
+#include "calendayutils.h"
+#include "calendayeventspane.h"
+#include "calendayitem.h"
+#include "calendaymodel.h"
+#include "calendayinfo.h"
+#include "calendayview.h"
+
+// -----------------------------------------------------------------------------
+// CalenDayContainer()
+// Constructor
+// -----------------------------------------------------------------------------
+//
+CalenDayContainer::CalenDayContainer(QGraphicsItem *parent) :
+    HbAbstractItemContainer(parent), mGeometryUpdated(false), mInfo(0)
+{
+    getTimedEventLayoutValues(mLayoutValues);
+    
+    // Get the height of element
+    qreal paneHeight = CalenDayUtils::instance()->hourElementHeight();
+    
+    QGraphicsLinearLayout* timeLinesLayout = new QGraphicsLinearLayout(
+        Qt::Vertical, this);
+    for (int i = 0; i < 24; i++) {
+        CalenDayEventsPane* element = new CalenDayEventsPane(this);
+        element->setPreferredHeight(paneHeight);
+        element->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+		// Draw top line at midnight
+        if (i == 0) {
+            element->drawTopLine(true);
+        }
+        timeLinesLayout->addItem(element);
+    }
+    timeLinesLayout->setContentsMargins(0.0, 0.0, 0.0, 0.0);
+    timeLinesLayout->setSpacing(0.0);
+
+    setLayout(timeLinesLayout);
+}
+
+// -----------------------------------------------------------------------------
+// ~CalenDayContainer()
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CalenDayContainer::~CalenDayContainer()
+{
+}
+
+// -----------------------------------------------------------------------------
+// itemAdded()
+// 
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::itemAdded( int index, HbAbstractViewItem *item, 
+                                     bool animate )
+{
+    Q_UNUSED( index )
+    Q_UNUSED( item )
+    Q_UNUSED( animate )
+}
+
+// -----------------------------------------------------------------------------
+// reset()
+// 
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::reset()
+{
+	// remove absorbers if exist
+	if (mAbsorbers.count())
+		{
+		qDeleteAll(mAbsorbers);
+		mAbsorbers.clear();
+		}
+	
+	// shrink event area when all-day events available after reset
+	getTimedEventLayoutValues(mLayoutValues);
+	
+    // position need to be maintained while changing model
+    QPointF position(pos());
+    HbAbstractItemContainer::reset();
+    setPos( position );
+}
+
+// -----------------------------------------------------------------------------
+// itemRemoved()
+// 
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::itemRemoved( HbAbstractViewItem *item, bool animate )
+{
+    Q_UNUSED( item )
+    Q_UNUSED( animate )
+}
+
+// -----------------------------------------------------------------------------
+// viewResized()
+// 
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::viewResized (const QSizeF &size)
+{
+    resize(size);
+    if (!mGeometryUpdated) {
+        mGeometryUpdated = true;
+        updateGeometry();
+    }
+}
+
+// -----------------------------------------------------------------------------
+// createDefaultPrototype()
+// 
+// -----------------------------------------------------------------------------
+//
+HbAbstractViewItem * CalenDayContainer::createDefaultPrototype() const
+{
+    CalenDayItem *calendarViewItem = new CalenDayItem;
+    return calendarViewItem;
+}
+
+// -----------------------------------------------------------------------------
+// setItemModelIndex()
+// 
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::setItemModelIndex(HbAbstractViewItem *item, 
+                                            const QModelIndex &index)
+{
+    QVariant variant = index.data( CalenDayEntry );
+    AgendaEntry entry = variant.value<AgendaEntry>();
+    
+    if (entry.isTimedEntry()) {
+        updateTimedEventGeometry( item, index );
+        item->setParentItem(this);
+    	}
+    else if( entry.type() == AgendaEntry::TypeEvent ){
+        updateAllDayEventGeometry( item, index );
+        item->setParentItem(this);
+    	} 
+    else {
+    	item->setVisible(false);
+    }
+    
+    // last item
+    if (index.row() == index.model()->rowCount() - 1) {
+    	createTouchEventAbsorbers();
+    }
+
+    HbAbstractItemContainer::setItemModelIndex(item, index);
+}
+
+// -----------------------------------------------------------------------------
+// updateTimedEventGeometry()
+// Updates geometry of a timed event.
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::updateTimedEventGeometry(HbAbstractViewItem *item, 
+                                                   const QModelIndex &index)
+{
+//safety check
+    if ( !mInfo ) {
+        return;
+    }
+    
+    QVariant variant = index.data( CalenDayEntry );
+    AgendaEntry entry = variant.value<AgendaEntry>();
+    
+//1. get 'virtual' event position from DayInfo
+//TODO: k.g.: Day Info should store model index instead of keeping redundant data
+    SCalenApptInfo apptInfo;
+    apptInfo.iIndex = index;
+    
+    QDateTime start;
+    QDateTime end;
+    QDateTime currentDate;
+    currentDate = static_cast<const CalenDayModel*>(index.model())->modelDate();
+    CalenDayUtils::instance()->getEventValidStartEndTime( start, end, entry,
+                                                          currentDate );
+    apptInfo.iStartTime = start;
+    apptInfo.iEndTime = end;
+    
+    TCalenInstanceId id = TCalenInstanceId::nullInstanceId();
+    id.mEntryLocalUid = index.row(); //index.row() - temporary ID
+    id.mInstanceTime = apptInfo.iStartTime; 
+    apptInfo.iId = id;
+    apptInfo.iAllDay = 0;
+    apptInfo.iColor = 0xffff;
+    
+    int startSlot, endSlot, columnIdx, columns;
+    mInfo->GetLocation( apptInfo, startSlot, endSlot, columnIdx, columns );
+    
+
+//2. set timed event's geometry
+    qreal eventStartX(mLayoutValues.eventAreaX );
+    qreal eventStartY(0.0);
+    qreal eventWidth(mLayoutValues.eventAreaWidth);
+    qreal eventHeight(0.0);
+       
+    //event's startY/height
+    eventStartY = startSlot * mLayoutValues.slotHeight;
+    eventHeight = (endSlot - startSlot) * mLayoutValues.slotHeight;
+
+    //event's startX/width
+    eventWidth /= columns;
+    
+    //In case when eventWidth will be smaller then 3.0un we need to 
+    //make spacings between events smaller.
+    //Check whether it's possible to shring them so the bubbles 
+    //width can stay at 3.0un (time stripe + frame margins).
+    qreal minWidth = 3.0 * mLayoutValues.unitInPixels; 
+    if(eventWidth - mLayoutValues.eventMargin < minWidth){
+        
+        //Calculate new margin value
+        //from totalMarginSpace we need to subtract 
+        //mLayoutValues.eventMargin because first margin is always 1.5un
+        qreal totalMarginSpace =  mLayoutValues.eventAreaWidth - minWidth * columns - mLayoutValues.eventMargin;
+        qreal newMarginValue = totalMarginSpace / (columns - 1);
+        
+        //check if we managed to pack all the events into space we have
+        if(newMarginValue > 0){
+            
+            eventWidth = minWidth;
+        }
+        else{
+            //there's not enough space
+            //new minWidth it's 1.5un (time stripe only)
+            minWidth = 1.5 * mLayoutValues.unitInPixels; 
+            totalMarginSpace =  mLayoutValues.eventAreaWidth - minWidth * columns - mLayoutValues.eventMargin;
+            newMarginValue = totalMarginSpace / (columns - 1);
+            eventWidth = minWidth;
+        }
+        
+        //First column margin should be always 1.5un (mLayoutValues.eventMargin)
+        eventStartX += columnIdx * (eventWidth + newMarginValue) + mLayoutValues.eventMargin;
+    }
+    else{
+        //add margins between the event
+        eventStartX += columnIdx * eventWidth + mLayoutValues.eventMargin;
+        eventWidth -= mLayoutValues.eventMargin;
+    }
+    
+    QRectF eventGeometry( eventStartX, eventStartY, eventWidth, eventHeight );
+    item->setGeometry(eventGeometry);}
+
+
+// -----------------------------------------------------------------------------
+// updateAllDayEventGeometry()
+// Updates geometry of a timed event.
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::updateAllDayEventGeometry(HbAbstractViewItem *item, 
+                                                   const QModelIndex &index)
+{
+	//safety check
+	if ( !mInfo ) {
+	      return;
+	}
+	    
+	QVariant variant = index.data( CalenDayEntry );
+	AgendaEntry entry = variant.value<AgendaEntry>();
+	    
+	//1. get 'virtual' event position from DayInfo
+	//TODO: k.g.: Day Info should store model index instead of keeping redundant data    
+	SCalenApptInfo apptInfo;
+	apptInfo.iIndex = index;
+	
+	
+	QDateTime start;
+    QDateTime end;
+    QDateTime currentDate;
+    currentDate = static_cast<const CalenDayModel*>(index.model())->modelDate();
+    CalenDayUtils::instance()->getEventValidStartEndTime( start, end, entry,
+                                                          currentDate );
+    apptInfo.iStartTime = start;
+    apptInfo.iEndTime = end;
+	
+	TCalenInstanceId id = TCalenInstanceId::nullInstanceId();
+	id.mEntryLocalUid = index.row(); //index.row() - temporary ID
+	id.mInstanceTime = apptInfo.iStartTime; 
+	apptInfo.iId = id;
+	apptInfo.iAllDay = true;
+	apptInfo.iColor = 0xffff;
+	
+	int startSlot, endSlot, columnIdx, columns;
+	mInfo->GetLocation( apptInfo, startSlot, endSlot, columnIdx, columns );
+	
+	//2. set timed event's geometry
+	qreal eventStartX(0.0);
+	qreal eventStartY(0.0);
+	qreal eventWidth(mLayoutValues.eventAreaX);
+	qreal eventHeight = (endSlot - startSlot) * mLayoutValues.slotHeight;
+
+	
+	//event's startX/width
+	if ( columns > 1 ) {
+		eventWidth /= columns;
+		eventStartX += columnIdx * eventWidth + mLayoutValues.eventMargin;
+		//add margins between the event
+		eventWidth -= mLayoutValues.eventMargin;
+	} else {
+		eventStartX += mLayoutValues.eventMargin;
+		eventWidth -= mLayoutValues.eventMargin;
+	}
+	
+	QRectF eventGeometry( eventStartX, eventStartY, eventWidth, eventHeight );
+	item->setGeometry(eventGeometry);
+	    
+}
+
+
+// -----------------------------------------------------------------------------
+// movingBackwards()
+// 
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::getTimedEventLayoutValues(LayoutValues& layoutValues)
+{
+    // get the width of content area
+    qreal contentWidth = CalenDayUtils::instance()->contentWidth();
+//1.time column width -> eventAreaX[out]
+    HbStyle style;
+    HbDeviceProfile deviceProfile;
+    layoutValues.unitInPixels = deviceProfile.unitValue();
+    
+    if ( mInfo && mInfo->AlldayCount())
+    	{ // 9.5 -> all-day area width 
+    	layoutValues.eventAreaX = 9.5 * layoutValues.unitInPixels;
+    	}
+    else
+    	{
+    	layoutValues.eventAreaX = 0;
+    	}
+    
+//2. event area width -> eventAreaWidth[out]
+    qreal emptyRightColumnWidth(0.0);
+    emptyRightColumnWidth = 6.0 * layoutValues.unitInPixels; //pix (according to UI spec)
+    layoutValues.eventAreaWidth = contentWidth - emptyRightColumnWidth - layoutValues.eventAreaX ;
+//3. margins between the overlapping events -> eventMargin[out]
+    layoutValues.eventMargin = 1.5 * layoutValues.unitInPixels;
+//4. half-hour slot'h height -> slotHeight[out]
+    //curent slot height corresponds to half an hour
+    layoutValues.slotHeight = 
+        CalenDayUtils::instance()->hourElementHeight() / 2;
+    
+    // 8.2 un (min. touchable event) from layout guide
+    layoutValues.maxColumns = layoutValues.eventAreaWidth / (8.2 * layoutValues.unitInPixels);  
+}
+
+// -----------------------------------------------------------------------------
+// setDayInfo()
+// Sets day's info structer to the container.
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::setDayInfo( CalenDayInfo* dayInfo )
+{
+    mInfo = dayInfo;
+}
+
+// -----------------------------------------------------------------------------
+// orientationChanged()
+// Slot handles layout switch.
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::orientationChanged(Qt::Orientation orientation)
+{
+	getTimedEventLayoutValues(mLayoutValues);
+	
+    Q_UNUSED( orientation )
+    QList<HbAbstractViewItem *> items = this->items();
+    int count(items.count());
+    for (int i = 0; i < count; i++) {
+        QModelIndex modelIndex = items[i]->modelIndex();
+        if (modelIndex.isValid()) {
+            QVariant variant = modelIndex.data(CalenDayEntry);
+            AgendaEntry entry = variant.value<AgendaEntry> ();
+            if (entry.isTimedEntry()) {
+                updateTimedEventGeometry(items[i], modelIndex);
+            }
+        }
+    }
+    
+    createTouchEventAbsorbers();
+}
+
+// -----------------------------------------------------------------------------
+// createTouchEventAbsorbers()
+// Creates absorbers which prevent touching to small items
+// -----------------------------------------------------------------------------
+//
+void CalenDayContainer::createTouchEventAbsorbers()
+{
+	// remove absorbers if exist
+	if (mAbsorbers.count())
+		{
+		qDeleteAll(mAbsorbers);
+		mAbsorbers.clear();
+		}
+	
+	const QList<CalenTimeRegion>& regionList = mInfo->RegionList();
+	
+	for(int i=0; i < regionList.count(); i++)
+		{
+		if(regionList[i].iColumns.count() > mLayoutValues.maxColumns )
+			{
+			TouchEventAbsorber* absorber = 
+				crateAbsorberBetweenSlots(regionList[i].iStartSlot, regionList[i].iEndSlot);
+			
+			mAbsorbers.append(absorber);
+			}
+		}
+	
+}
+
+// -----------------------------------------------------------------------------
+// crateAbsorberBetweenSlots()
+// Creates single absorber in given location
+// -----------------------------------------------------------------------------
+//
+TouchEventAbsorber *CalenDayContainer::crateAbsorberBetweenSlots
+												(int startSlot, int endSlot)
+{
+    TouchEventAbsorber *absorber = new TouchEventAbsorber(this);
+    absorber->setZValue(1000);
+    absorber->setVisible(true);
+    
+    absorber->setGeometry( mLayoutValues.eventAreaX,			// x
+			startSlot * mLayoutValues.slotHeight,				// y
+			mLayoutValues.eventAreaWidth,						// w
+			(endSlot-startSlot) * mLayoutValues.slotHeight ); 	// h
+    
+    return absorber;
+}
+
+
+// -----------------------------------------------------------------------------
+// TouchEventAbsorber::gestureEvent()
+// Handles tap event on overlapping area (currently it leads to Agenda View - 
+// as described in UI spec)
+// -----------------------------------------------------------------------------
+//
+void TouchEventAbsorber::gestureEvent(QGestureEvent *event)
+{
+    QTapGesture *tapGesture = qobject_cast<QTapGesture*> (event->gesture(
+        Qt::TapGesture));
+    
+    if (tapGesture && tapGesture->state() == Qt::GestureFinished)
+    	{
+    	CalenDayView* dayView = static_cast<CalenDayView*>
+                (CalenDayUtils::instance()->mainWindow()->currentView());
+    	
+    	dayView->changeView(ECalenAgendaView);
+    	}
+}
+
+// -----------------------------------------------------------------------------
+// TouchEventAbsorber()
+// default ctor
+// -----------------------------------------------------------------------------
+//
+TouchEventAbsorber::TouchEventAbsorber(QGraphicsItem *parent) : HbWidget(parent)
+{
+#ifdef _DEBUG
+    setFlag(QGraphicsItem::ItemHasNoContents, false);
+#endif	
+    grabGesture(Qt::TapGesture);    	    
+}
+
+// -----------------------------------------------------------------------------
+// TouchEventAbsorber()
+// default dtor
+// -----------------------------------------------------------------------------
+//
+TouchEventAbsorber::~TouchEventAbsorber()
+{
+	
+}
+
+// -----------------------------------------------------------------------------
+// TouchEventAbsorber::paint()
+// used for debugging purposes to see absorbers areas
+// -----------------------------------------------------------------------------
+//
+#ifdef _DEBUG
+void TouchEventAbsorber::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+								QWidget *widget)
+{
+	Q_UNUSED(option)
+	Q_UNUSED(widget)
+	
+	painter->save();
+	QPen pen;
+	pen.setWidth(2);
+	pen.setColor(Qt::red);
+	painter->setPen(pen);
+	painter->drawRect(boundingRect());
+	painter->restore();
+}
+#endif
+// End of File