/*
* Copyright (c) 2009 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: Definition file for class CalenMonthGrid.
*
*/
// System includes
#include <hbgridview.h>
#include <hbabstractviewitem.h>
#include <hbstyleloader.h>
#include <hbcolorscheme.h>
#include <hbpangesture.h>
#include <hbswipegesture.h>
#include <hbtapgesture.h>
#include <hbdeviceprofile.h>
#include <hbinstance.h>
// User includes
#include "calenmonthgrid.h"
#include "calengriditemprototype.h"
#include "calenmonthdata.h"
#include "calenmonthview.h"
#include "calendateutils.h"
#include "calencommon.h"
#include "calenconstants.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "calenmonthgridTraces.h"
#endif
// Constants
#define SCROLL_SPEEED 3000
#define GRIDLINE_WIDTH 0.075 //units
#define MAX_PAN_DIRECTION_THRESHOLD 50
#define MIN_PAN_DIRECTION_THRESHOLD 20
/*!
\class CalenMonthGrid
Implements the month grid
*/
/*!
Default constructor.
*/
CalenMonthGrid::CalenMonthGrid(QGraphicsItem *parent):
HbGridView(parent),
mModel(0),
mDirection(invalid),
mIsPanGesture(false),
mIsAtomicScroll(true),
mView(NULL),
mCurrentRow(-100),
mIsNonActiveDayFocused(false),
mIgnoreItemActivated(false),
mGridLineColor(HbColorScheme::color("qtc_cal_grid_line")),
mActiveDatesSet(false)
{
OstTraceFunctionEntry0( CALENMONTHGRID_CALENMONTHGRID_ENTRY );
setScrollDirections(Qt::Vertical);
setRowCount(KNumOfVisibleRows);
setColumnCount(KCalenDaysInWeek);
setLongPressEnabled(false);
setItemRecycling(false);
setSelectionMode(HbGridView::NoSelection);
setUniformItemSizes(true);
setVerticalScrollBarPolicy(HbScrollArea::ScrollBarAlwaysOff);
setClampingStyle(HbScrollArea::StrictClamping);
setEnabledAnimations(HbAbstractItemView::None);
setFrictionEnabled(false);
setFlag(QGraphicsItem::ItemHasNoContents, false);
// Disable the rows and columns swapping on orientation change
setSwapDimensionsOnOrientationChange(false);
resetTransform();
// Get the content widget of the scroll area to draw the grid lines
mContentWidget = contentWidget();
// Get the localised dates well before
// TODO: Need to update the mLocalisedDates when user changes the
// phone language keeping calendar application in background
HbExtendedLocale locale = HbExtendedLocale::system();
for (int i = 1; i <= 31; i++) {
mLocalisedDates.append(locale.toString(i));
}
// Connect to scrolling finished signal
connect(this, SIGNAL(scrollingEnded()), this,
SLOT(scrollingFinished()));
connect(
HbTheme::instance(), SIGNAL(changed()),
this, SLOT(handleThemeChange()));
// Disable the haptic feedback for the month grid during scrolling
setAttribute(Hb::InteractionDisabled);
OstTraceFunctionExit0( CALENMONTHGRID_CALENMONTHGRID_EXIT );
}
/*!
Destructor
*/
CalenMonthGrid::~CalenMonthGrid()
{
OstTraceFunctionEntry0( DUP1_CALENMONTHGRID_CALENMONTHGRID_ENTRY );
// Nothing Yet
OstTraceFunctionExit0( DUP1_CALENMONTHGRID_CALENMONTHGRID_EXIT );
}
/*!
Stores the view pointer
*/
void CalenMonthGrid::setView(CalenMonthView *view)
{
OstTraceFunctionEntry0( CALENMONTHGRID_SETVIEW_ENTRY );
mView = view;
OstTraceFunctionExit0( CALENMONTHGRID_SETVIEW_EXIT );
}
/*!
Updates the model with the proper dates and sets the required user roles
*/
void CalenMonthGrid::updateMonthGridModel(QList<CalenMonthData> &monthDataArray,
int indexToBeScrolled, bool isFirstTime)
{
OstTraceFunctionEntry0( CALENMONTHGRID_UPDATEMONTHGRIDMODEL_ENTRY );
int loopStart = 0;
int loopEnd = monthDataArray.count();
if (isFirstTime) {
// Create the model with only 42 items as visible to the user
mModel = new QStandardItemModel(KCalenDaysInWeek * KNumOfVisibleRows,
1, this);
loopStart = (mView->rowsInPrevMonth()) * KCalenDaysInWeek;
loopEnd = loopStart + (KCalenDaysInWeek * KNumOfVisibleRows);
} else {
// Block the signals generated by model, this is being done as
// we want to avoid the overload of view listening to signals
mModel->blockSignals(true);
// Check the counts
int dataCount = monthDataArray.count();
int rowCount = mModel->rowCount();
int countDiff = dataCount - rowCount;
if (countDiff < 0) {
// Delete extra rows in the model
mModel->removeRows(dataCount,abs(countDiff));
} else if (countDiff > 0) {
// Add the necessary number of rows
mModel->insertRows(rowCount,countDiff);
}
loopEnd = dataCount;
}
QDateTime currDate = mView->getCurrentDay();
QDateTime currDateTime = CalenDateUtils::beginningOfDay(currDate);
QDateTime activeDay = mView->getActiveDay();
QDateTime activeDateTime = CalenDateUtils::beginningOfDay(activeDay);
QModelIndex currentIndex;
int modelIndex = 0;
for (int i = loopStart; i < loopEnd; i++) {
QDateTime dateTime = monthDataArray[i].Day();
currentIndex = mModel->index(modelIndex++, 0);
// Create the variant list to contain the date to depict a grid item
QVariantList itemData;
// !!!NOTE!!!: Add the data in the order mentioned in the
// CalendarNamespace::DataRole enum. Dont change the order.
itemData << mLocalisedDates.at(dateTime.date().day()-1);
// Check for active day
if (activeDateTime == CalenDateUtils::beginningOfDay(dateTime)) {
mCurrentRow = i;
// Set the focus attribute to true
itemData << true;
} else {
// reset the highlight
itemData << false;
}
// Check for current day
if (currDateTime == CalenDateUtils::beginningOfDay(dateTime)) {
// Set the underline attribute to true
itemData << true;
} else {
itemData << false;
}
// Check for events
if (monthDataArray[i].HasEvents()) {
// Set the event indicator attribute
itemData << true;
} else {
itemData << false;
}
// Add default text color
if (monthDataArray[i].isActive()) {
itemData << true;
} else {
itemData << false;
}
mModel->itemFromIndex(currentIndex)->setData(itemData);
}
if (isFirstTime) {
// Create the prototype
CalenGridItemPrototype* gridItemPrototype = new CalenGridItemPrototype(this);
connect(
HbTheme::instance(), SIGNAL(changed()),
gridItemPrototype, SLOT(handleThemeChange()));
// Set the mode and the prototype
setModel(mModel,gridItemPrototype);
// Register the widgetml and css files
HbStyleLoader::registerFilePath(":/");
// Set the layout name
setLayoutName("calendarCustomGridItem");
} else {
// Since, we have finished setData, Now unblock the signals
mModel->blockSignals(false);
// Since till now, we had blocked signals being generated frm the mode
// view will be unaware of the items that we added. Hence, inform the view
// explicitly in one shot
QModelIndex leftIndex = mModel->index(0, 0);
QModelIndex rightIndex = mModel->index(loopEnd-1, 0);
dataChanged(leftIndex, rightIndex);
// NOTE: To make sure that we always display proper month,
// two calls have been made to scrollTo(), one with top
// visible item and other with bottom visible item
// Calculate the first visible item in the grid
QModelIndex firstVisibleIndex = mModel->index(indexToBeScrolled -
(KNumOfVisibleRows * KCalenDaysInWeek - 1), 0);
scrollTo(firstVisibleIndex);
// Calculate the last visible item in the grid
QModelIndex lastVisibleIndex = mModel->index(indexToBeScrolled, 0);
scrollTo(lastVisibleIndex);
}
OstTraceFunctionExit0( CALENMONTHGRID_UPDATEMONTHGRIDMODEL_EXIT );
}
/*!
Updates the view with jprevious month dates when calendar is opened for the
first time to improve the opening time
*/
void CalenMonthGrid::updateMonthGridWithInActiveMonths(
QList<CalenMonthData> &monthDataArray)
{
OstTraceFunctionEntry0( CALENMONTHGRID_UPDATEMONTHGRIDWITHINACTIVEMONTHS_ENTRY );
// Prepend the required rows
handlePrependingRows(monthDataArray);
// Append the required rows
handleAppendingRows(monthDataArray);
int rowsInPrevMonth = mView->rowsInPrevMonth();
// Calculate the proper index to be scrolled to
int itemToBeScrolled = rowsInPrevMonth * KCalenDaysInWeek;
QModelIndex indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
mIsAtomicScroll = true;
scrollTo(indexToBeScrolled);
// Scroll to proper index
itemToBeScrolled = ((rowsInPrevMonth + KNumOfVisibleRows) *
KCalenDaysInWeek) - 1;
indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
mIsAtomicScroll = true;
scrollTo(indexToBeScrolled);
// Update the sart position of the content widget
mStartPos = mContentWidget->pos();
// Now connect to the signal which gets emitted when any item on the grid
// is tapped.
connect(this, SIGNAL(activated(const QModelIndex &)), this,
SLOT(itemActivated(const QModelIndex &)));
OstTraceFunctionExit0( CALENMONTHGRID_UPDATEMONTHGRIDWITHINACTIVEMONTHS_EXIT );
}
/*!
Updates the view with just event indicators
*/
void CalenMonthGrid::updateMonthGridWithEventIndicators(
QList<CalenMonthData> &monthDataArray)
{
OstTraceFunctionEntry0( CALENMONTHGRID_UPDATEMONTHGRIDWITHEVENTINDICATORS_ENTRY );
int count(monthDataArray.count());
for(int i = 0; i < count; i++) {
// Check if the day has events
if (monthDataArray[i].HasEvents()) {
QModelIndex itemIndex = mModel->index(i,0);
QVariant itemData = itemIndex.data(Qt::UserRole + 1);
QVariantList list = itemData.toList();
list.replace(CalendarNamespace::CalendarMonthEventRole, true);
mModel->itemFromIndex(itemIndex)->setData(list);
}
}
OstTraceFunctionExit0( CALENMONTHGRID_UPDATEMONTHGRIDWITHEVENTINDICATORS_EXIT );
}
/*!
Scrolls the content dowmwards
*/
void CalenMonthGrid::downGesture()
{
OstTraceFunctionEntry0( CALENMONTHGRID_DOWNGESTURE_ENTRY );
// Make sure that content widget is properly placed
// We are doing this as tapping on inactive date of previous month is leading to
// position the grid at wrong place after scrolling down. Hence, set the grid
// at proper position before we start actual scrolling
if (mIsNonActiveDayFocused) {
mIsAtomicScroll = true;
int itemToBeScrolled = mView->rowsInPrevMonth() * KCalenDaysInWeek;
QModelIndex indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
scrollTo(indexToBeScrolled);
}
// Set the required flags
mDirection = down;
mIsAtomicScroll = false;
// Set the active and inactive dates
QDateTime activeMonth = mView->getActiveDay();
// For previous month, substract one month to the current month
setActiveDates(activeMonth.addMonths(-1).date());
mActiveDatesSet = true;
// Set the focus to proper date before scrolling to avoid somekind of
// jerkiness
if (!mIsNonActiveDayFocused) {
setFocusToProperDay();
}
// Start the scrolling
QPointF targetPos(0.0, 0.0);
scrollContentsTo(targetPos,500);
OstTraceFunctionExit0( CALENMONTHGRID_DOWNGESTURE_EXIT );
}
/*!
Scrolls the content upwards
*/
void CalenMonthGrid::upGesture()
{
OstTraceFunctionEntry0( CALENMONTHGRID_UPGESTURE_ENTRY );
// Set the required flags
mDirection = up;
mIsAtomicScroll = false;
// Set the active and inactive dates
QDateTime activeMonth = mView->getActiveDay();
// For next month, add one month to the current month
setActiveDates(activeMonth.addMonths(1).date());
mActiveDatesSet = true;
// Set the focus to proper date before scrolling to avoid somekind of
// jerkiness
if (!mIsNonActiveDayFocused) {
setFocusToProperDay();
}
// Start the scrolling
QPointF targetPos(0.0, mStartPos.y() - size().height());
scrollContentsTo(-targetPos,500);
OstTraceFunctionExit0( CALENMONTHGRID_UPGESTURE_EXIT );
}
/*!
Function to listen mouse press events
*/
void CalenMonthGrid::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
OstTraceFunctionEntry0( CALENMONTHGRID_MOUSEPRESSEVENT_ENTRY );
// Pass it to parent
HbGridView::mousePressEvent(event);
OstTraceFunctionExit0( CALENMONTHGRID_MOUSEPRESSEVENT_EXIT );
}
/*!
Function to listen mouse release events
*/
void CalenMonthGrid::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
OstTraceFunctionEntry0( CALENMONTHGRID_MOUSERELEASEEVENT_ENTRY );
// Pass it grid view if pan gesture is not in progress else pass it to
// scrollarea. Problem here is, if we pass to gridview when panning, then
// its emitting item activated signal simply becasue of which focus item
// is getting changed when you finish the pan / shake
if (!mIsPanGesture) {
HbGridView::mouseReleaseEvent(event);
} else {
HbScrollArea::mouseReleaseEvent(event);
}
OstTraceFunctionExit0( CALENMONTHGRID_MOUSERELEASEEVENT_EXIT );
}
/*!
Function to list for all the gesture events
*/
void CalenMonthGrid::gestureEvent(QGestureEvent *event)
{
OstTraceFunctionEntry0( CALENMONTHGRID_GESTUREEVENT_ENTRY );
if(HbPanGesture *gesture = qobject_cast<HbPanGesture *>(event->gesture(Qt::PanGesture))) {
if (gesture->state() == Qt::GestureStarted) {
mIsAtomicScroll = false;
if (!mIsPanGesture) {
mDirection = invalid;
mStartPos = mContentWidget->pos();
// TODO: This work around till framework provides an api
// to know the direciton of the pan, until then we need
// calculate the direction explicitly
// Get to know the direction of the gesture
// Use our defined threshold temporarily till scrollarea
// frm orbit side is made clever enough not to scroll in other direction
// apart frm the registered scroll direction
QPointF delta = gesture->delta();
// Check the current orientation of the device and
// swap the vertical and horizontal distances in landscape
qreal horizontalDiff = 0.0;
qreal verticalDiff = 0.0;
if (hbInstance->allMainWindows().at(0)->orientation() == Qt::Vertical) {
horizontalDiff = delta.x();
verticalDiff = delta.y();
} else {
horizontalDiff = delta.y();
verticalDiff = delta.x();
}
if (abs(horizontalDiff) > MAX_PAN_DIRECTION_THRESHOLD) {
// Now see if y coord diff has crossed threshold
if (verticalDiff > MAX_PAN_DIRECTION_THRESHOLD) {
mIsPanGesture = true;
mIgnoreItemActivated = true;
mDirection = down;
} else if (verticalDiff < -MAX_PAN_DIRECTION_THRESHOLD){
mIsPanGesture = true;
mIgnoreItemActivated = true;
mDirection = up;
} else {
event->accept(Qt::PanGesture);
OstTraceFunctionExit0( CALENMONTHGRID_GESTUREEVENT_EXIT );
return;
}
} else if (abs(horizontalDiff) < MAX_PAN_DIRECTION_THRESHOLD) {
if (verticalDiff > MIN_PAN_DIRECTION_THRESHOLD) {
mIsPanGesture = true;
mIgnoreItemActivated = true;
mDirection = down;
} else if (verticalDiff < -MIN_PAN_DIRECTION_THRESHOLD){
mIsPanGesture = true;
mIgnoreItemActivated = true;
mDirection = up;
}else {
event->accept(Qt::PanGesture);
OstTraceFunctionExit0( DUP1_CALENMONTHGRID_GESTUREEVENT_EXIT );
return;
}
}
}
}
} else if(HbSwipeGesture *gesture = qobject_cast<HbSwipeGesture *>(event->gesture(Qt::SwipeGesture))) {
if (gesture->state() == Qt::GestureStarted) {
mIsAtomicScroll = false;
mDirection = invalid;
if (gesture->sceneVerticalDirection() == QSwipeGesture::Down) {
mDirection = down;
} else if (gesture->sceneVerticalDirection() == QSwipeGesture::Up) {
mDirection = up;
} else {
event->accept(Qt::SwipeGesture);
OstTraceFunctionExit0( DUP2_CALENMONTHGRID_GESTUREEVENT_EXIT );
return;
}
}
} else if (HbTapGesture *gesture = qobject_cast<HbTapGesture *>(event->gesture(Qt::TapGesture))) {
if(gesture->state() == Qt::GestureFinished) {
// Check if scrolling is in progress
if (mDirection != invalid) {
// Set the pan flag to true so that grid adjusts to nearest
// month after tapping
mIsPanGesture = true;
handlePanGestureFinished();
}
}
}
if (mDirection!= invalid) {
// Call the parent class to perform the pan gesture
// When scrolling finished, month grid will adjust to show the proper month
HbScrollArea::gestureEvent(event);
}
OstTraceFunctionExit0( DUP3_CALENMONTHGRID_GESTUREEVENT_EXIT );
}
/*!
Gets called when scrolling finishes to update the model
*/
void CalenMonthGrid::scrollingFinished()
{
OstTraceFunctionEntry0( CALENMONTHGRID_SCROLLINGFINISHED_ENTRY );
if (mIsPanGesture) {
handlePanGestureFinished();
} else if(!mIsAtomicScroll) {
QDateTime activeDate = mView->getActiveDay();
if(mDirection == down) { // down gesture
if (!mActiveDatesSet) {
setActiveDates(activeDate.addMonths(-1).date());
setFocusToProperDay();
}
prependRows();
} else if (mDirection == up) { //up gesture
if (!mActiveDatesSet) {
setActiveDates(activeDate.addMonths(1).date());
setFocusToProperDay();
}
appendRows();
}
mDirection = invalid;
mActiveDatesSet = false;
} else {
mIsAtomicScroll = false;
mDirection = invalid;
}
mIgnoreItemActivated = false;
OstTraceFunctionExit0( CALENMONTHGRID_SCROLLINGFINISHED_EXIT );
}
/*!
Function to handle completion of pan gesture
*/
void CalenMonthGrid::handlePanGestureFinished()
{
OstTraceFunctionEntry0( CALENMONTHGRID_HANDLEPANGESTUREFINISHED_ENTRY );
mIsPanGesture = false;
// Get the first item that is visible
QList<HbAbstractViewItem *> list = visibleItems();
HbAbstractViewItem* item = list[0];
QModelIndex modelIndex = item->modelIndex();
// Get the date which is visible at the above row
QList<CalenMonthData>& monthDataArray = mView->monthDataList();
QDateTime date = monthDataArray[modelIndex.row()].Day();
// Check if this date belong to current active month or
// previous month else future month
QDateTime activeMonth = mView->getActiveDay();
QDateTime prevMonth = activeMonth.addMonths(-1);
QDateTime nextMonth = activeMonth.addMonths(1);
int month = date.date().month();
if (month == activeMonth.date().month()) {
// Then pan is completed on current month
// Check if the date is more than half of the current month or it is
// more than or equal to half of the future month
if (date.date().day() > (activeMonth.date().daysInMonth()) / 2 ||
date.addDays(KNumOfVisibleRows*KCalenDaysInWeek).date().day() >=
(prevMonth.date().daysInMonth()) / 2) {
// up gesture to bring the next month
upGesture();
} else {
// we should again show the current month by scrolling downwards
mDirection = down;
mIsAtomicScroll = true;
scrollContentsTo(-mStartPos,500);
}
} else if (month == prevMonth.date().month()) {
// first visible item belongs to previous month
// Check if the date is more than half of the previous month
if (date.date().day() > (prevMonth.date().daysInMonth()) / 2) {
// we should again show the current month by scrolling upwards
mDirection = up;
mIsAtomicScroll = true;
scrollContentsTo(-mStartPos,500);
} else {
// down gesture to show the previous month
downGesture();
}
} else if (month == prevMonth.addMonths(-1).date().month()) {
// first visible date belong to previous to previous month
// hence, scroll down to bring the previous month
downGesture();
} else if (month == nextMonth.date().month()) {
// first visible item belongs to next month
// Check if the date is more than half of the next month
if (date.date().day() > (nextMonth.date().daysInMonth()) / 2) {
// up gesture to bring the next month
upGesture();
} else {
// we should again show the current month by scrolling upwards
mDirection = up;
scrollContentsTo(-mStartPos,500);
}
} else if (month == nextMonth.addMonths(1).date().month()) {
// first visible date belongs to next to next month
// hence, scroll up to show the next month
upGesture();
}
OstTraceFunctionExit0( CALENMONTHGRID_HANDLEPANGESTUREFINISHED_EXIT );
}
/*!
Called when down gesture is performed. Adds the new previous month details
to the model
*/
void CalenMonthGrid::prependRows()
{
OstTraceFunctionEntry0( CALENMONTHGRID_PREPENDROWS_ENTRY );
// Block the signals generated by model, this is being done as
// we want to avoid the overload of view listening to signals
mModel->blockSignals(true);
mIsNonActiveDayFocused = false;
int rowsInFutMonthEarlier = mView->rowsInFutMonth();
int rowsInPrevMonthEarlier = mView->rowsInPrevMonth();
// remove the cells in the future month
int deleteFromIndex = (rowsInPrevMonthEarlier + KNumOfVisibleRows) * KCalenDaysInWeek;
int numOfIndices = rowsInFutMonthEarlier * KCalenDaysInWeek;
// Get the updated dates from the view
mView->updateModelWithPrevMonth();
QList<CalenMonthData >& monthDataList = mView->monthDataList();
// Prepend the required rows
handlePrependingRows(monthDataList);
// Since, we have finished setData, Now unblock the signals
mModel->blockSignals(false);
int rowsInPrevMonth = mView->rowsInPrevMonth();
int countToBeAdded = rowsInPrevMonth * KCalenDaysInWeek;
// Since till now, we had blocked signals being generated frm the model
// view will be unaware of the items that we added. Hence, inform the view
// explicitly in one shot
QModelIndex leftIndex = mModel->index(0, 0);
QModelIndex rightIndex = mModel->index(countToBeAdded-1, 0);
dataChanged(leftIndex, rightIndex);
// Now remove the necessary items frm the model
mModel->removeRows(deleteFromIndex+countToBeAdded, numOfIndices);
mIsAtomicScroll = true;
int itemToBeScrolled = rowsInPrevMonth * KCalenDaysInWeek;
QModelIndex indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
scrollTo(indexToBeScrolled);
// Scroll to proper index
itemToBeScrolled = ((rowsInPrevMonth + KNumOfVisibleRows) *
KCalenDaysInWeek) - 1;
indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
mIsAtomicScroll = true;
scrollTo(indexToBeScrolled);
// Update the mCurrentRow
mCurrentRow += countToBeAdded;
// Update the sart position of the content widget
mStartPos = mContentWidget->pos();
OstTraceFunctionExit0( CALENMONTHGRID_PREPENDROWS_EXIT );
}
/*!
Helper function that prepends the required rows to the model
*/
void CalenMonthGrid::handlePrependingRows(QList<CalenMonthData > &monthDataList)
{
OstTraceFunctionEntry0( CALENMONTHGRID_HANDLEPREPENDINGROWS_ENTRY );
QDateTime currDate = mView->getCurrentDay();
QDateTime currDateTime = CalenDateUtils::beginningOfDay( currDate );
int rowsInPrevMonth = mView->rowsInPrevMonth();
// Add the new days
int countToBeAdded = rowsInPrevMonth * KCalenDaysInWeek;
mModel->insertRows(0, countToBeAdded);
for (int i = 0; i < countToBeAdded; i++) {
QDateTime dateTime = monthDataList[i].Day();
// Get the localised string for the day
QModelIndex currentIndex = mModel->index(i, 0);
// Create the variant list to contain the date to depict a grid item
QVariantList itemData;
// NOTE: Add the data in the order mentioned in the
// CalendarNamespace::DataRole enum. Dont change the order.
itemData << mLocalisedDates.at(dateTime.date().day()-1);;
// Disable the focus role
itemData << false;
// Check for current day
if (currDateTime == CalenDateUtils::beginningOfDay( dateTime )) {
// Set the underline icon attribute
itemData << true;
} else {
itemData << false;
}
// Update the event indicators
if (monthDataList[i].HasEvents()) {
// Set the event indicator attribute
itemData << true;
} else {
itemData << false;
}
// Add default text color
itemData << false;
// Set the data to model
mModel->itemFromIndex(currentIndex)->setData(itemData);
}
OstTraceFunctionExit0( CALENMONTHGRID_HANDLEPREPENDINGROWS_EXIT );
}
/*!
Called when Up gwsture is performed. Adds the new future month details
to the model
*/
void CalenMonthGrid::appendRows()
{
OstTraceFunctionEntry0( CALENMONTHGRID_APPENDROWS_ENTRY );
// Block the signals generated by model, this is being done as
// we want to avoid the overload of view listening to signals
mModel->blockSignals(true);
mIsNonActiveDayFocused = false;
int rowsInFutMonth = mView->rowsInFutMonth();
int rowsInPrevMonth = mView->rowsInPrevMonth();
// remove the cells in the previous month
int countToBeDeleted = rowsInPrevMonth * KCalenDaysInWeek;
// Get the updated dates from the view
mView->updateModelWithFutureMonth();
QList<CalenMonthData >& monthDataList = mView->monthDataList();
// Get the model count before we add any rows into the mode
int rowCount = mModel->rowCount();
// Append the required rows
handleAppendingRows(monthDataList);
// Since, we have finished setData, Now unblock the signals
mModel->blockSignals(false);
// Since till now, we had blocked signals being generated frm the mode
// view will be unaware of the items that we added. Hence, inform the view
// explicitly in one shot
QModelIndex leftIndex = mModel->index(rowCount-1, 0);
QModelIndex rightIndex = mModel->index(mModel->rowCount()-1, 0);
dataChanged(leftIndex, rightIndex);
// Update the mCurrentRow
mCurrentRow -= (countToBeDeleted);
for (int i = 0; i < countToBeDeleted; i++) {
mModel->removeRow(0);
}
mIsAtomicScroll = true;
rowsInFutMonth = mView->rowsInFutMonth();
rowsInPrevMonth = mView->rowsInPrevMonth();
// Calculate the proper index to be scrolled to
int itemToBeScrolled = rowsInPrevMonth * KCalenDaysInWeek;
QModelIndex indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
scrollTo(indexToBeScrolled);
itemToBeScrolled = ((rowsInPrevMonth + KNumOfVisibleRows) *
KCalenDaysInWeek) - 1;
indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
mIsAtomicScroll = true;
scrollTo(indexToBeScrolled);
// Update the sart position of the content widget
mStartPos = mContentWidget->pos();
OstTraceFunctionExit0( CALENMONTHGRID_APPENDROWS_EXIT );
}
/*!
Helper function that appends the required rows to the model
*/
void CalenMonthGrid::handleAppendingRows(QList<CalenMonthData > &monthDataList)
{
OstTraceFunctionEntry0( CALENMONTHGRID_HANDLEAPPENDINGROWS_ENTRY );
QDateTime currDate = mView->getCurrentDay();
QDateTime currDateTime = CalenDateUtils::beginningOfDay( currDate );
int rowsInFutMonth = mView->rowsInFutMonth();
int countToBeAdded = rowsInFutMonth * KCalenDaysInWeek;
int lastVisibleIndex = monthDataList.count() - countToBeAdded;
int rowCount = mModel->rowCount();
mModel->insertRows(rowCount, countToBeAdded);
for (int i = 0; i < countToBeAdded; i++) {
QModelIndex currentIndex = mModel->index(rowCount + i, 0);
QDateTime dateTime = monthDataList[lastVisibleIndex + i].Day();
// Create the variant list to contain the date to depict a grid item
QVariantList itemData;
// NOTE: Add the data in the order mentioned in the
// CalendarNamespace::DataRole enum. Dont change the order.
itemData << mLocalisedDates.at(dateTime.date().day()-1);;
// Disable the focus role
itemData << false;
// Check for current day
if (currDateTime == CalenDateUtils::beginningOfDay( dateTime )) {
// Set the underline icon attribute
itemData << true;
} else {
itemData << false;
}
// Update the event indicators
if (monthDataList[lastVisibleIndex + i].HasEvents()) {
// Set the event indicator attribute
itemData << true;
} else {
itemData << false;
}
// Add default text color
itemData << false;
// Set the data to model
mModel->itemFromIndex(currentIndex)->setData(itemData);
}
OstTraceFunctionExit0( CALENMONTHGRID_HANDLEAPPENDINGROWS_EXIT );
}
/*!
Slot to handle when a particular grid item is tapped
*/
void CalenMonthGrid::itemActivated(const QModelIndex &index)
{
OstTraceFunctionEntry0( CALENMONTHGRID_ITEMACTIVATED_ENTRY );
if (mIgnoreItemActivated) {
mIgnoreItemActivated = false;
OstTraceFunctionExit0( CALENMONTHGRID_ITEMACTIVATED_EXIT );
return;
}
mIsNonActiveDayFocused = false;
// Check if the same item has been tapped twice
if (mCurrentRow == index.row()) {
// Launch the Day view
mView->launchDayView();
} else {
// Reset the focus attribute to this item
QModelIndex itemIndex = mModel->index(mCurrentRow,0);
if(itemIndex.row() < 0 || itemIndex.row() >= mModel->rowCount() ||
itemIndex.column() < 0 || itemIndex.column() > mModel->columnCount()) {
OstTraceFunctionExit0( DUP1_CALENMONTHGRID_ITEMACTIVATED_EXIT );
return;
}
QVariant itemData = itemIndex.data(Qt::UserRole + 1);
QVariantList list = itemData.toList();
list.replace(CalendarNamespace::CalendarMonthFocusRole, false);
mModel->itemFromIndex(itemIndex)->setData(list);
// Inform view to update the context and preview panes
mCurrentRow = index.row();
itemIndex = mModel->index(mCurrentRow,0);
itemData = itemIndex.data(Qt::UserRole + 1);
list = itemData.toList();
list.replace(CalendarNamespace::CalendarMonthFocusRole,
true);
mModel->itemFromIndex(itemIndex)->setData(list);
// Check if inactive date is tapped
QDateTime activeMonth = mView->getActiveDay();
int month = activeMonth.date().month();
QList<CalenMonthData >& monthDataList = mView->monthDataList();
if(month != monthDataList[mCurrentRow].Day().date().month()){
// Set the flag
mIsNonActiveDayFocused = true;
QDateTime nonActiveFocusedDay = monthDataList[mCurrentRow].Day();
// Add one month to active month
activeMonth = activeMonth.addMonths(1);
if (activeMonth.date().month() ==
nonActiveFocusedDay.date().month()) {
mDirection = up;
// up gesture
upGesture();
} else {
mDirection = down;
// down gesture
downGesture();
}
}
mView->setContextForActiveDay(index.row());
}
OstTraceFunctionExit0( DUP2_CALENMONTHGRID_ITEMACTIVATED_EXIT );
}
/*!
Sets the focus to proper day after the flick scrollng
*/
void CalenMonthGrid::setFocusToProperDay()
{
OstTraceFunctionEntry0( CALENMONTHGRID_SETFOCUSTOPROPERDAY_ENTRY );
// Calculate the new item to be focussed
QDateTime oldFocussedDate = mView->getActiveDay();
QList<CalenMonthData> monthDataList = mView->monthDataList();
int listCount = monthDataList.count();
int rowsInPrevMonth = mView->rowsInPrevMonth();
QDateTime dateToBeFocussed;
int indexStart = 0;
int indexEnd = listCount - 1;
if (mDirection == up) {
dateToBeFocussed = oldFocussedDate.addMonths(1); // add the month
indexStart = (rowsInPrevMonth + 4) * KCalenDaysInWeek;
} else if (mDirection == down) {
dateToBeFocussed = oldFocussedDate.addMonths(-1); // substract the month
indexEnd = (rowsInPrevMonth + 1) * KCalenDaysInWeek;
}
// Reset the focus attribute to earlier current item
QModelIndex index = mModel->index(mCurrentRow,0);
QVariant itemData = index.data(Qt::UserRole + 1);
QVariantList list = itemData.toList();
list.replace(CalendarNamespace::CalendarMonthFocusRole, false);
mModel->itemFromIndex(index)->setData(list);
// Search for this date in the model
for (int i = indexStart; i <= indexEnd; i++) {
if (monthDataList[i].Day().date() == dateToBeFocussed.date()) {
index = mModel->index(i,0);
itemData = index.data(Qt::UserRole + 1);
list = itemData.toList();
list.replace(CalendarNamespace::CalendarMonthFocusRole,
true);
mModel->itemFromIndex(index)->setData(list);
mCurrentRow = i;
mView->setContextForActiveDay(i);
break;
}
}
OstTraceFunctionExit0( CALENMONTHGRID_SETFOCUSTOPROPERDAY_EXIT );
}
/*!
Sets the appropriate text color depending upon the active dates
*/
void CalenMonthGrid::setActiveDates(QDate activeDate)
{
OstTraceFunctionEntry0( CALENMONTHGRID_SETACTIVEDATES_ENTRY );
// By default, text color will be set as inactive date color
// set active date color only for the dates that fall in current month
// So, in the whole data array, start from where the current month starts
// and stop the loop where it the current month ends
int start = 0;
QList<CalenMonthData >& monthDataList = mView->monthDataList();
int end = monthDataList.count();
// Calculate the start and end values
QDate firstDateInGrid = mView->firstDayOfGrid().date();
// Get the date where active month starts
QDate startOfActiveMonth(activeDate.year(), activeDate.month(),1);
// Number of days frm start of the grid to start of the month
start = firstDateInGrid.daysTo(startOfActiveMonth);
// Get the date where active month ends
QDate endOfActiveMonth = startOfActiveMonth.addDays(
activeDate.daysInMonth());
// Number of days frm start of the grid to end of the month
end = firstDateInGrid.daysTo(endOfActiveMonth);
// Set the active text color
if (start >= 0 && end < monthDataList.count()) {
for (int i = start; i < end; i++) {
QModelIndex index = mModel->index(i,0);
QVariant itemData = index.data(Qt::UserRole + 1);
QVariantList list = itemData.toList();
list.replace(CalendarNamespace::CalendarMonthTextColorRole, true);
mModel->itemFromIndex(index)->setData(list);
}
}
// Now set the inactive text color to those which were active before the swipe
if (mDirection == invalid) {
// no need to do anything as other dates will be in inactive dates color
OstTraceFunctionExit0( CALENMONTHGRID_SETACTIVEDATES_EXIT );
return;
}
if (mDirection == up) {
// Came here as user did up gesture
// Get the activeDate that was set before the swipe
activeDate = activeDate.addMonths(-1);
// Get the date where active month starts
startOfActiveMonth = QDate(activeDate.year(), activeDate.month(),1);
// Number of days frm start of the grid to start of the month
start = firstDateInGrid.daysTo(startOfActiveMonth);
// Get the date where active month ends
QDate endOfActiveMonth = startOfActiveMonth.addDays(activeDate.daysInMonth());
// Number of days frm start of the grid to end of the month
end = firstDateInGrid.daysTo(endOfActiveMonth);
} else if (mDirection == down) {
// Came here as user did down gesture
// Get the activeDate that was set before the swipe
activeDate = activeDate.addMonths(1);
// Get the activeDate that was set before the swipe
startOfActiveMonth = QDate(activeDate.year(), activeDate.month(),1);
// Number of days frm start of the grid to start of the month
start = firstDateInGrid.daysTo(startOfActiveMonth);
// Get the date where active month ends
QDate endOfActiveMonth = startOfActiveMonth.addDays(activeDate.daysInMonth());
// Number of days frm start of the grid to end of the month
end = firstDateInGrid.daysTo(endOfActiveMonth);
}
// Set the inactive text color
if (start >= 0 && end < monthDataList.count()) {
for (int i = start; i < end; i++) {
QModelIndex index = mModel->index(i,0);
QVariant itemData = index.data(Qt::UserRole + 1);
QVariantList list = itemData.toList();
list.replace(CalendarNamespace::CalendarMonthTextColorRole, false);
mModel->itemFromIndex(index)->setData(list);
}
}
OstTraceFunctionExit0( DUP1_CALENMONTHGRID_SETACTIVEDATES_EXIT );
}
/*!
To get current foucsed index of monthGrid
*/
int CalenMonthGrid::getCurrentIndex()
{
OstTraceFunctionEntry0( CALENMONTHGRID_GETCURRENTINDEX_ENTRY );
OstTraceFunctionExit0( CALENMONTHGRID_GETCURRENTINDEX_EXIT );
return mCurrentRow;
}
/*!
To set the focus to Index
*/
void CalenMonthGrid::setCurrentIdex(int index)
{
OstTraceFunctionEntry0( CALENMONTHGRID_SETCURRENTIDEX_ENTRY );
itemActivated(mModel->index(index, 0));
OstTraceFunctionExit0( CALENMONTHGRID_SETCURRENTIDEX_EXIT );
}
/*!
Function to override the default behavior of hbgridview on orientation change
*/
void CalenMonthGrid::orientationChanged(Qt::Orientation newOrientation)
{
OstTraceFunctionEntry0( CALENMONTHGRID_ORIENTATIONCHANGED_ENTRY );
Q_UNUSED(newOrientation)
// We are overriding this function to avoid the default behavior of
// hbgridview on orientation change as it swaps the row and column counts
// Calculate the proper index to be scrolled to
int rowsInPrevMonth;
int itemToBeScrolled;
QModelIndex indexToBeScrolled;
if (newOrientation == Qt::Horizontal) {
rowsInPrevMonth = mView->rowsInPrevMonth();
itemToBeScrolled = rowsInPrevMonth * KCalenDaysInWeek;
indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
mIsAtomicScroll = true;
scrollTo(indexToBeScrolled);
} else {
rowsInPrevMonth = mView->rowsInPrevMonth();
itemToBeScrolled = rowsInPrevMonth * KCalenDaysInWeek;
indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
mIsAtomicScroll = true;
scrollTo(indexToBeScrolled);
itemToBeScrolled = ((rowsInPrevMonth + KNumOfVisibleRows) *
KCalenDaysInWeek) - 1;
indexToBeScrolled = mModel->index(itemToBeScrolled, 0);
mIsAtomicScroll = true;
scrollTo(indexToBeScrolled);
}
OstTraceFunctionExit0( CALENMONTHGRID_ORIENTATIONCHANGED_EXIT );
}
/*!
Paint function to draw grid lines
*/
void CalenMonthGrid::paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget)
{
OstTraceFunctionEntry0( CALENMONTHGRID_PAINT_ENTRY );
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setRenderHint(QPainter::NonCosmeticDefaultPen);
// Set the required attributes to the pen
QPen pen;
HbDeviceProfile deviceProf;
qreal unitValue = deviceProf.unitValue();
qreal widthInPixels = GRIDLINE_WIDTH * unitValue;
pen.setStyle(Qt::SolidLine);
pen.setWidth(widthInPixels);
pen.setBrush(mGridLineColor);
// Store the old pen
QPen oldPen = painter->pen();
// Set the new pen to the painter
painter->setPen(pen);
// Get the sizes of content widget
qreal contentHeight = mContentWidget->size().height();
qreal contentWidth = mContentWidget->size().width();
qreal rowWidth = 0.0;
int numOfRows = 0;
QPointF startPoint = mContentWidget->pos();
// NOTE!!!: There is a filcker when we blindly draw equally spaced lines
// on complete content widget when scrolling is finished. This happens only
// when content widget size is changed due to the change in total number
// of rows when we append or prepend rows. Hence, to avoid this, we draw
// lines on complete content widget only when it is scrolling.
// That means, as soon as scrolling is finished, we will end up drawing
// only 6 lines that are visible to the user.
if (mDirection == invalid) {
// Start point is left most point on the screen
startPoint = QPointF(0,0);
rowWidth = size().height() / KNumOfVisibleRows;
numOfRows = KNumOfVisibleRows;
} else {
// Get the num of rows
numOfRows = mModel->rowCount() / KCalenDaysInWeek;
// Draw horizontal lines
rowWidth = contentHeight / numOfRows;
}
QPointF endPoint(startPoint.x() + contentWidth,
startPoint.y());
// Create the list of points for which lines have to be drawn
// List should have even number of points so that it draws all the lines
// Painter draws the line for first two points in the list and then second
// line for next two points in the list like that. Hence, list should
// contain even number of points
// Dont draw the first horizontal line as we have thick line seperator
// coming between day names and the month grid
QVector<QPointF> pointList;
for (int i = 1; i < numOfRows; i++) {
pointList.append(QPointF(startPoint.x(),
startPoint.y() + (i * rowWidth)));
pointList.append(QPointF(endPoint.x(), endPoint.y() + (i * rowWidth)));
}
// Draw vertical lines
qreal colWidth = contentWidth / KCalenDaysInWeek;
endPoint = QPointF(startPoint.x(),
startPoint.y() + contentHeight);
for (int i = 1; i < KCalenDaysInWeek; i++) {
pointList.append(QPointF(startPoint.x() + (i * colWidth),
startPoint.y()));
pointList.append(QPointF(endPoint.x() + (i * colWidth), endPoint.y()));
}
// Draw the lines for the points in the vector list
painter->drawLines(pointList);
// Set the old pen back
painter->setPen(oldPen);
OstTraceFunctionExit0( CALENMONTHGRID_PAINT_EXIT );
}
/*!
Slot to handle the change in theme
*/
void CalenMonthGrid::handleThemeChange()
{
OstTraceFunctionEntry0(CALENMONTHGRID_HANDLETHEMECHANGE_ENTRY);
mGridLineColor = HbColorScheme::color("qtc_cal_grid_line");
OstTraceFunctionExit0(CALENMONTHGRID_HANDLETHEMECHANGE_EXIT);
}
// End of File