diff -r fd30d51f876b -r b6db4fd4947b calendarui/views/dayview/src/calendaycontainer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/calendarui/views/dayview/src/calendaycontainer.cpp Mon Jun 28 15:22:02 2010 +0530 @@ -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 +#include +#include + +#ifdef _DEBUG + #include +#endif + +#include +#include +#include +#include + +//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(); + + 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(); + +//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(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(); + + //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(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 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 (); + 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& 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 (event->gesture( + Qt::TapGesture)); + + if (tapGesture && tapGesture->state() == Qt::GestureFinished) + { + CalenDayView* dayView = static_cast + (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