calendarui/views/dayview/src/calendaycontainer.cpp
changeset 45 b6db4fd4947b
child 55 2c54b51f39c4
child 58 ef813d54df51
equal deleted inserted replaced
23:fd30d51f876b 45:b6db4fd4947b
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Day view control of calendar
       
    15 *
       
    16 */
       
    17 
       
    18 //System includes
       
    19 #include <QTime>
       
    20 #include <QGraphicsLinearLayout>
       
    21 #include <QGesture>
       
    22 
       
    23 #ifdef _DEBUG
       
    24 	#include <QPainter>
       
    25 #endif
       
    26 
       
    27 #include <hbabstractitemview.h>
       
    28 #include <hbtextitem.h>
       
    29 #include <hbmodeliterator.h>
       
    30 #include <hbinstance.h>
       
    31 
       
    32 //User includes
       
    33 #include "calendaycontainer.h"
       
    34 #include "calendayutils.h"
       
    35 #include "calendayeventspane.h"
       
    36 #include "calendayitem.h"
       
    37 #include "calendaymodel.h"
       
    38 #include "calendayinfo.h"
       
    39 #include "calendayview.h"
       
    40 
       
    41 // -----------------------------------------------------------------------------
       
    42 // CalenDayContainer()
       
    43 // Constructor
       
    44 // -----------------------------------------------------------------------------
       
    45 //
       
    46 CalenDayContainer::CalenDayContainer(QGraphicsItem *parent) :
       
    47     HbAbstractItemContainer(parent), mGeometryUpdated(false), mInfo(0)
       
    48 {
       
    49     getTimedEventLayoutValues(mLayoutValues);
       
    50     
       
    51     // Get the height of element
       
    52     qreal paneHeight = CalenDayUtils::instance()->hourElementHeight();
       
    53     
       
    54     QGraphicsLinearLayout* timeLinesLayout = new QGraphicsLinearLayout(
       
    55         Qt::Vertical, this);
       
    56     for (int i = 0; i < 24; i++) {
       
    57         CalenDayEventsPane* element = new CalenDayEventsPane(this);
       
    58         element->setPreferredHeight(paneHeight);
       
    59         element->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
       
    60 		// Draw top line at midnight
       
    61         if (i == 0) {
       
    62             element->drawTopLine(true);
       
    63         }
       
    64         timeLinesLayout->addItem(element);
       
    65     }
       
    66     timeLinesLayout->setContentsMargins(0.0, 0.0, 0.0, 0.0);
       
    67     timeLinesLayout->setSpacing(0.0);
       
    68 
       
    69     setLayout(timeLinesLayout);
       
    70 }
       
    71 
       
    72 // -----------------------------------------------------------------------------
       
    73 // ~CalenDayContainer()
       
    74 // Destructor
       
    75 // -----------------------------------------------------------------------------
       
    76 //
       
    77 CalenDayContainer::~CalenDayContainer()
       
    78 {
       
    79 }
       
    80 
       
    81 // -----------------------------------------------------------------------------
       
    82 // itemAdded()
       
    83 // 
       
    84 // -----------------------------------------------------------------------------
       
    85 //
       
    86 void CalenDayContainer::itemAdded( int index, HbAbstractViewItem *item, 
       
    87                                      bool animate )
       
    88 {
       
    89     Q_UNUSED( index )
       
    90     Q_UNUSED( item )
       
    91     Q_UNUSED( animate )
       
    92 }
       
    93 
       
    94 // -----------------------------------------------------------------------------
       
    95 // reset()
       
    96 // 
       
    97 // -----------------------------------------------------------------------------
       
    98 //
       
    99 void CalenDayContainer::reset()
       
   100 {
       
   101 	// remove absorbers if exist
       
   102 	if (mAbsorbers.count())
       
   103 		{
       
   104 		qDeleteAll(mAbsorbers);
       
   105 		mAbsorbers.clear();
       
   106 		}
       
   107 	
       
   108 	// shrink event area when all-day events available after reset
       
   109 	getTimedEventLayoutValues(mLayoutValues);
       
   110 	
       
   111     // position need to be maintained while changing model
       
   112     QPointF position(pos());
       
   113     HbAbstractItemContainer::reset();
       
   114     setPos( position );
       
   115 }
       
   116 
       
   117 // -----------------------------------------------------------------------------
       
   118 // itemRemoved()
       
   119 // 
       
   120 // -----------------------------------------------------------------------------
       
   121 //
       
   122 void CalenDayContainer::itemRemoved( HbAbstractViewItem *item, bool animate )
       
   123 {
       
   124     Q_UNUSED( item )
       
   125     Q_UNUSED( animate )
       
   126 }
       
   127 
       
   128 // -----------------------------------------------------------------------------
       
   129 // viewResized()
       
   130 // 
       
   131 // -----------------------------------------------------------------------------
       
   132 //
       
   133 void CalenDayContainer::viewResized (const QSizeF &size)
       
   134 {
       
   135     resize(size);
       
   136     if (!mGeometryUpdated) {
       
   137         mGeometryUpdated = true;
       
   138         updateGeometry();
       
   139     }
       
   140 }
       
   141 
       
   142 // -----------------------------------------------------------------------------
       
   143 // createDefaultPrototype()
       
   144 // 
       
   145 // -----------------------------------------------------------------------------
       
   146 //
       
   147 HbAbstractViewItem * CalenDayContainer::createDefaultPrototype() const
       
   148 {
       
   149     CalenDayItem *calendarViewItem = new CalenDayItem;
       
   150     return calendarViewItem;
       
   151 }
       
   152 
       
   153 // -----------------------------------------------------------------------------
       
   154 // setItemModelIndex()
       
   155 // 
       
   156 // -----------------------------------------------------------------------------
       
   157 //
       
   158 void CalenDayContainer::setItemModelIndex(HbAbstractViewItem *item, 
       
   159                                             const QModelIndex &index)
       
   160 {
       
   161     QVariant variant = index.data( CalenDayEntry );
       
   162     AgendaEntry entry = variant.value<AgendaEntry>();
       
   163     
       
   164     if (entry.isTimedEntry()) {
       
   165         updateTimedEventGeometry( item, index );
       
   166         item->setParentItem(this);
       
   167     	}
       
   168     else if( entry.type() == AgendaEntry::TypeEvent ){
       
   169         updateAllDayEventGeometry( item, index );
       
   170         item->setParentItem(this);
       
   171     	} 
       
   172     else {
       
   173     	item->setVisible(false);
       
   174     }
       
   175     
       
   176     // last item
       
   177     if (index.row() == index.model()->rowCount() - 1) {
       
   178     	createTouchEventAbsorbers();
       
   179     }
       
   180 
       
   181     HbAbstractItemContainer::setItemModelIndex(item, index);
       
   182 }
       
   183 
       
   184 // -----------------------------------------------------------------------------
       
   185 // updateTimedEventGeometry()
       
   186 // Updates geometry of a timed event.
       
   187 // -----------------------------------------------------------------------------
       
   188 //
       
   189 void CalenDayContainer::updateTimedEventGeometry(HbAbstractViewItem *item, 
       
   190                                                    const QModelIndex &index)
       
   191 {
       
   192 //safety check
       
   193     if ( !mInfo ) {
       
   194         return;
       
   195     }
       
   196     
       
   197     QVariant variant = index.data( CalenDayEntry );
       
   198     AgendaEntry entry = variant.value<AgendaEntry>();
       
   199     
       
   200 //1. get 'virtual' event position from DayInfo
       
   201 //TODO: k.g.: Day Info should store model index instead of keeping redundant data
       
   202     SCalenApptInfo apptInfo;
       
   203     apptInfo.iIndex = index;
       
   204     
       
   205     QDateTime start;
       
   206     QDateTime end;
       
   207     QDateTime currentDate;
       
   208     currentDate = static_cast<const CalenDayModel*>(index.model())->modelDate();
       
   209     CalenDayUtils::instance()->getEventValidStartEndTime( start, end, entry,
       
   210                                                           currentDate );
       
   211     apptInfo.iStartTime = start;
       
   212     apptInfo.iEndTime = end;
       
   213     
       
   214     TCalenInstanceId id = TCalenInstanceId::nullInstanceId();
       
   215     id.mEntryLocalUid = index.row(); //index.row() - temporary ID
       
   216     id.mInstanceTime = apptInfo.iStartTime; 
       
   217     apptInfo.iId = id;
       
   218     apptInfo.iAllDay = 0;
       
   219     apptInfo.iColor = 0xffff;
       
   220     
       
   221     int startSlot, endSlot, columnIdx, columns;
       
   222     mInfo->GetLocation( apptInfo, startSlot, endSlot, columnIdx, columns );
       
   223     
       
   224 
       
   225 //2. set timed event's geometry
       
   226     qreal eventStartX(mLayoutValues.eventAreaX );
       
   227     qreal eventStartY(0.0);
       
   228     qreal eventWidth(mLayoutValues.eventAreaWidth);
       
   229     qreal eventHeight(0.0);
       
   230        
       
   231     //event's startY/height
       
   232     eventStartY = startSlot * mLayoutValues.slotHeight;
       
   233     eventHeight = (endSlot - startSlot) * mLayoutValues.slotHeight;
       
   234 
       
   235     //event's startX/width
       
   236     eventWidth /= columns;
       
   237     
       
   238     //In case when eventWidth will be smaller then 3.0un we need to 
       
   239     //make spacings between events smaller.
       
   240     //Check whether it's possible to shring them so the bubbles 
       
   241     //width can stay at 3.0un (time stripe + frame margins).
       
   242     qreal minWidth = 3.0 * mLayoutValues.unitInPixels; 
       
   243     if(eventWidth - mLayoutValues.eventMargin < minWidth){
       
   244         
       
   245         //Calculate new margin value
       
   246         //from totalMarginSpace we need to subtract 
       
   247         //mLayoutValues.eventMargin because first margin is always 1.5un
       
   248         qreal totalMarginSpace =  mLayoutValues.eventAreaWidth - minWidth * columns - mLayoutValues.eventMargin;
       
   249         qreal newMarginValue = totalMarginSpace / (columns - 1);
       
   250         
       
   251         //check if we managed to pack all the events into space we have
       
   252         if(newMarginValue > 0){
       
   253             
       
   254             eventWidth = minWidth;
       
   255         }
       
   256         else{
       
   257             //there's not enough space
       
   258             //new minWidth it's 1.5un (time stripe only)
       
   259             minWidth = 1.5 * mLayoutValues.unitInPixels; 
       
   260             totalMarginSpace =  mLayoutValues.eventAreaWidth - minWidth * columns - mLayoutValues.eventMargin;
       
   261             newMarginValue = totalMarginSpace / (columns - 1);
       
   262             eventWidth = minWidth;
       
   263         }
       
   264         
       
   265         //First column margin should be always 1.5un (mLayoutValues.eventMargin)
       
   266         eventStartX += columnIdx * (eventWidth + newMarginValue) + mLayoutValues.eventMargin;
       
   267     }
       
   268     else{
       
   269         //add margins between the event
       
   270         eventStartX += columnIdx * eventWidth + mLayoutValues.eventMargin;
       
   271         eventWidth -= mLayoutValues.eventMargin;
       
   272     }
       
   273     
       
   274     QRectF eventGeometry( eventStartX, eventStartY, eventWidth, eventHeight );
       
   275     item->setGeometry(eventGeometry);}
       
   276 
       
   277 
       
   278 // -----------------------------------------------------------------------------
       
   279 // updateAllDayEventGeometry()
       
   280 // Updates geometry of a timed event.
       
   281 // -----------------------------------------------------------------------------
       
   282 //
       
   283 void CalenDayContainer::updateAllDayEventGeometry(HbAbstractViewItem *item, 
       
   284                                                    const QModelIndex &index)
       
   285 {
       
   286 	//safety check
       
   287 	if ( !mInfo ) {
       
   288 	      return;
       
   289 	}
       
   290 	    
       
   291 	QVariant variant = index.data( CalenDayEntry );
       
   292 	AgendaEntry entry = variant.value<AgendaEntry>();
       
   293 	    
       
   294 	//1. get 'virtual' event position from DayInfo
       
   295 	//TODO: k.g.: Day Info should store model index instead of keeping redundant data    
       
   296 	SCalenApptInfo apptInfo;
       
   297 	apptInfo.iIndex = index;
       
   298 	
       
   299 	
       
   300 	QDateTime start;
       
   301     QDateTime end;
       
   302     QDateTime currentDate;
       
   303     currentDate = static_cast<const CalenDayModel*>(index.model())->modelDate();
       
   304     CalenDayUtils::instance()->getEventValidStartEndTime( start, end, entry,
       
   305                                                           currentDate );
       
   306     apptInfo.iStartTime = start;
       
   307     apptInfo.iEndTime = end;
       
   308 	
       
   309 	TCalenInstanceId id = TCalenInstanceId::nullInstanceId();
       
   310 	id.mEntryLocalUid = index.row(); //index.row() - temporary ID
       
   311 	id.mInstanceTime = apptInfo.iStartTime; 
       
   312 	apptInfo.iId = id;
       
   313 	apptInfo.iAllDay = true;
       
   314 	apptInfo.iColor = 0xffff;
       
   315 	
       
   316 	int startSlot, endSlot, columnIdx, columns;
       
   317 	mInfo->GetLocation( apptInfo, startSlot, endSlot, columnIdx, columns );
       
   318 	
       
   319 	//2. set timed event's geometry
       
   320 	qreal eventStartX(0.0);
       
   321 	qreal eventStartY(0.0);
       
   322 	qreal eventWidth(mLayoutValues.eventAreaX);
       
   323 	qreal eventHeight = (endSlot - startSlot) * mLayoutValues.slotHeight;
       
   324 
       
   325 	
       
   326 	//event's startX/width
       
   327 	if ( columns > 1 ) {
       
   328 		eventWidth /= columns;
       
   329 		eventStartX += columnIdx * eventWidth + mLayoutValues.eventMargin;
       
   330 		//add margins between the event
       
   331 		eventWidth -= mLayoutValues.eventMargin;
       
   332 	} else {
       
   333 		eventStartX += mLayoutValues.eventMargin;
       
   334 		eventWidth -= mLayoutValues.eventMargin;
       
   335 	}
       
   336 	
       
   337 	QRectF eventGeometry( eventStartX, eventStartY, eventWidth, eventHeight );
       
   338 	item->setGeometry(eventGeometry);
       
   339 	    
       
   340 }
       
   341 
       
   342 
       
   343 // -----------------------------------------------------------------------------
       
   344 // movingBackwards()
       
   345 // 
       
   346 // -----------------------------------------------------------------------------
       
   347 //
       
   348 void CalenDayContainer::getTimedEventLayoutValues(LayoutValues& layoutValues)
       
   349 {
       
   350     // get the width of content area
       
   351     qreal contentWidth = CalenDayUtils::instance()->contentWidth();
       
   352 //1.time column width -> eventAreaX[out]
       
   353     HbStyle style;
       
   354     HbDeviceProfile deviceProfile;
       
   355     layoutValues.unitInPixels = deviceProfile.unitValue();
       
   356     
       
   357     if ( mInfo && mInfo->AlldayCount())
       
   358     	{ // 9.5 -> all-day area width 
       
   359     	layoutValues.eventAreaX = 9.5 * layoutValues.unitInPixels;
       
   360     	}
       
   361     else
       
   362     	{
       
   363     	layoutValues.eventAreaX = 0;
       
   364     	}
       
   365     
       
   366 //2. event area width -> eventAreaWidth[out]
       
   367     qreal emptyRightColumnWidth(0.0);
       
   368     emptyRightColumnWidth = 6.0 * layoutValues.unitInPixels; //pix (according to UI spec)
       
   369     layoutValues.eventAreaWidth = contentWidth - emptyRightColumnWidth - layoutValues.eventAreaX ;
       
   370 //3. margins between the overlapping events -> eventMargin[out]
       
   371     layoutValues.eventMargin = 1.5 * layoutValues.unitInPixels;
       
   372 //4. half-hour slot'h height -> slotHeight[out]
       
   373     //curent slot height corresponds to half an hour
       
   374     layoutValues.slotHeight = 
       
   375         CalenDayUtils::instance()->hourElementHeight() / 2;
       
   376     
       
   377     // 8.2 un (min. touchable event) from layout guide
       
   378     layoutValues.maxColumns = layoutValues.eventAreaWidth / (8.2 * layoutValues.unitInPixels);  
       
   379 }
       
   380 
       
   381 // -----------------------------------------------------------------------------
       
   382 // setDayInfo()
       
   383 // Sets day's info structer to the container.
       
   384 // -----------------------------------------------------------------------------
       
   385 //
       
   386 void CalenDayContainer::setDayInfo( CalenDayInfo* dayInfo )
       
   387 {
       
   388     mInfo = dayInfo;
       
   389 }
       
   390 
       
   391 // -----------------------------------------------------------------------------
       
   392 // orientationChanged()
       
   393 // Slot handles layout switch.
       
   394 // -----------------------------------------------------------------------------
       
   395 //
       
   396 void CalenDayContainer::orientationChanged(Qt::Orientation orientation)
       
   397 {
       
   398 	getTimedEventLayoutValues(mLayoutValues);
       
   399 	
       
   400     Q_UNUSED( orientation )
       
   401     QList<HbAbstractViewItem *> items = this->items();
       
   402     int count(items.count());
       
   403     for (int i = 0; i < count; i++) {
       
   404         QModelIndex modelIndex = items[i]->modelIndex();
       
   405         if (modelIndex.isValid()) {
       
   406             QVariant variant = modelIndex.data(CalenDayEntry);
       
   407             AgendaEntry entry = variant.value<AgendaEntry> ();
       
   408             if (entry.isTimedEntry()) {
       
   409                 updateTimedEventGeometry(items[i], modelIndex);
       
   410             }
       
   411         }
       
   412     }
       
   413     
       
   414     createTouchEventAbsorbers();
       
   415 }
       
   416 
       
   417 // -----------------------------------------------------------------------------
       
   418 // createTouchEventAbsorbers()
       
   419 // Creates absorbers which prevent touching to small items
       
   420 // -----------------------------------------------------------------------------
       
   421 //
       
   422 void CalenDayContainer::createTouchEventAbsorbers()
       
   423 {
       
   424 	// remove absorbers if exist
       
   425 	if (mAbsorbers.count())
       
   426 		{
       
   427 		qDeleteAll(mAbsorbers);
       
   428 		mAbsorbers.clear();
       
   429 		}
       
   430 	
       
   431 	const QList<CalenTimeRegion>& regionList = mInfo->RegionList();
       
   432 	
       
   433 	for(int i=0; i < regionList.count(); i++)
       
   434 		{
       
   435 		if(regionList[i].iColumns.count() > mLayoutValues.maxColumns )
       
   436 			{
       
   437 			TouchEventAbsorber* absorber = 
       
   438 				crateAbsorberBetweenSlots(regionList[i].iStartSlot, regionList[i].iEndSlot);
       
   439 			
       
   440 			mAbsorbers.append(absorber);
       
   441 			}
       
   442 		}
       
   443 	
       
   444 }
       
   445 
       
   446 // -----------------------------------------------------------------------------
       
   447 // crateAbsorberBetweenSlots()
       
   448 // Creates single absorber in given location
       
   449 // -----------------------------------------------------------------------------
       
   450 //
       
   451 TouchEventAbsorber *CalenDayContainer::crateAbsorberBetweenSlots
       
   452 												(int startSlot, int endSlot)
       
   453 {
       
   454     TouchEventAbsorber *absorber = new TouchEventAbsorber(this);
       
   455     absorber->setZValue(1000);
       
   456     absorber->setVisible(true);
       
   457     
       
   458     absorber->setGeometry( mLayoutValues.eventAreaX,			// x
       
   459 			startSlot * mLayoutValues.slotHeight,				// y
       
   460 			mLayoutValues.eventAreaWidth,						// w
       
   461 			(endSlot-startSlot) * mLayoutValues.slotHeight ); 	// h
       
   462     
       
   463     return absorber;
       
   464 }
       
   465 
       
   466 
       
   467 // -----------------------------------------------------------------------------
       
   468 // TouchEventAbsorber::gestureEvent()
       
   469 // Handles tap event on overlapping area (currently it leads to Agenda View - 
       
   470 // as described in UI spec)
       
   471 // -----------------------------------------------------------------------------
       
   472 //
       
   473 void TouchEventAbsorber::gestureEvent(QGestureEvent *event)
       
   474 {
       
   475     QTapGesture *tapGesture = qobject_cast<QTapGesture*> (event->gesture(
       
   476         Qt::TapGesture));
       
   477     
       
   478     if (tapGesture && tapGesture->state() == Qt::GestureFinished)
       
   479     	{
       
   480     	CalenDayView* dayView = static_cast<CalenDayView*>
       
   481                 (CalenDayUtils::instance()->mainWindow()->currentView());
       
   482     	
       
   483     	dayView->changeView(ECalenAgendaView);
       
   484     	}
       
   485 }
       
   486 
       
   487 // -----------------------------------------------------------------------------
       
   488 // TouchEventAbsorber()
       
   489 // default ctor
       
   490 // -----------------------------------------------------------------------------
       
   491 //
       
   492 TouchEventAbsorber::TouchEventAbsorber(QGraphicsItem *parent) : HbWidget(parent)
       
   493 {
       
   494 #ifdef _DEBUG
       
   495     setFlag(QGraphicsItem::ItemHasNoContents, false);
       
   496 #endif	
       
   497     grabGesture(Qt::TapGesture);    	    
       
   498 }
       
   499 
       
   500 // -----------------------------------------------------------------------------
       
   501 // TouchEventAbsorber()
       
   502 // default dtor
       
   503 // -----------------------------------------------------------------------------
       
   504 //
       
   505 TouchEventAbsorber::~TouchEventAbsorber()
       
   506 {
       
   507 	
       
   508 }
       
   509 
       
   510 // -----------------------------------------------------------------------------
       
   511 // TouchEventAbsorber::paint()
       
   512 // used for debugging purposes to see absorbers areas
       
   513 // -----------------------------------------------------------------------------
       
   514 //
       
   515 #ifdef _DEBUG
       
   516 void TouchEventAbsorber::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
       
   517 								QWidget *widget)
       
   518 {
       
   519 	Q_UNUSED(option)
       
   520 	Q_UNUSED(widget)
       
   521 	
       
   522 	painter->save();
       
   523 	QPen pen;
       
   524 	pen.setWidth(2);
       
   525 	pen.setColor(Qt::red);
       
   526 	painter->setPen(pen);
       
   527 	painter->drawRect(boundingRect());
       
   528 	painter->restore();
       
   529 }
       
   530 #endif
       
   531 // End of File