diff -r 5de72ea7a065 -r 579cc610882e calendarui/views/dayview/inc/calendayinfo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/calendarui/views/dayview/inc/calendayinfo.h Tue Jul 06 14:14:56 2010 +0300 @@ -0,0 +1,759 @@ +/* +* Copyright (c) 2007-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: Storage class for day and week views. +* +*/ + +#ifndef CALENDAYINFO_H +#define CALENDAYINFO_H + +// INCLUDES +#include +#include +#include +#include + +#include +#include "caleninstanceid.h" + + +// +/** Scrolling directions **/ +enum TScrollDirection + { + EScrollUp, + EScrollDown, + EScrollLeft, + EScrollRight + }; + +//Constants +const int KFSCalMaxDescriptionLength = 100; +const int KFSCalStartingHour = 8; +const int KFSCalSlotsInHour = 2; + +/** + * An interval containing a start and end slot. + * The start slot belongs to the interval, the end slot + * is the first slot outside of the interval. If the end slot + * is before or at the same slot as the start slot, the interval + * is considered empty. + */ +class CalenSlotInterval + { +public: + /** + * Check if this interval overlaps the second interval. + */ + bool Overlaps( const CalenSlotInterval& aInterval ) const; + + /** + * Add aOffset to all slot coordinates later than aPos + */ + void AddOffset( int aOffset, int aPos ); + + /** + * Set this interval to be the minimum interval + * containing both this original interval and aInterval. + */ + void Union( const CalenSlotInterval& aInterval ); + + /** + * Check if aInterval lies directly next to this interval. + */ + bool Adjacent( const CalenSlotInterval& aInterval ) const; + + /** + * Check if this interval is empty. + */ + bool IsEmpty() const; + + /** + * Set this interval to be the area contained in both + * this interval and to aInterval. + */ + void Intersect( const CalenSlotInterval& aInterval ); + + /** + * Remove aInterval from this interval. If aInterval lies + * within this interval, the result is two separate intervals. + * This object contains one of them, aSecondPart contains the other one. + * If the result is just one single interval, this interval contains that + * and aSecondPart is set to an empty interval. + */ + void Subtract( const CalenSlotInterval& aInterval, CalenSlotInterval& aSecondPart ); + + /** + * Check if this interval starts later than aInterval. + */ + bool operator>( const CalenSlotInterval& aInterval ) const; + + /** + * The starting slot of the interval. This is the first slot + * that belongs to the interval. + */ + int iStartSlot; + + /** + * The ending slot of the interval. This is the first slot + * that doesn't belong to the interval. + */ + int iEndSlot; + }; + + +/** + * Class for storing a calendar instance and the range it occupies. + */ +struct CalenTimedEventInfo : public CalenSlotInterval + { +public: + /** + * The id of the calendar instance + */ + TCalenInstanceId iId; + + /** + * Status of the entry, needed for setting the displayed color later + */ + AgendaEntry::Status iStatus; + + /** + * Replication status of the entry, needed for setting the displayed color + * later. + */ +// AgendaEntry::TReplicationStatus iReplicationStatus; + }; + +/** + * Class for storing general time intervals and their associated + * status (needed for displaying the interval). + */ +struct CalenEventInterval : public CalenSlotInterval + { +public: + /** + * The status of this interval, if it represents only one calendar + * instance. + */ + AgendaEntry::Status iStatus; + + /** + * The replication status of this interval, if it represents only one + * calendar instance. + */ +// AgendaEntry::TReplicationStatus iReplicationStatus; + + /** + * A flag saying that this interval represents a conflict between two or + * more calendar instances. + */ + bool iOverlap; + }; + + + +/** + * A class containing a sequence of non-overlapping events, + * visualised as a column. + */ +class CalenTimeColumn : public CalenSlotInterval + { +public: + + /** + * Explicitly frees the memory used by the event array. + */ + void Close(); + + /** + * Add a new event to this column. Events must be added sequentially, + * and must not overlap earlier events in this column. + */ + void AddEvent( const CalenTimedEventInfo& aEvent ); + + /** + * Check if a new event can be added to this column. + */ + bool CanFitEvent( const CalenTimedEventInfo& aEvent ); + + /** + * Check if this column contains an event with the id aId. + */ + bool ContainsEvent( const TCalenInstanceId& aId ); + + /** + * Add aOffset to all slot coordinates later than aPos + */ + void AddOffset( int aOffset, int aPos ); + + /** + * Event array. + */ + QList iEventArray; + }; + + +/** + * A class containing one or more columns with events, + * where every event overlaps at least one event in some other + * column. (Otherwise that event should be added to a separate region.) + */ +class CalenTimeRegion : public CalenSlotInterval + { +public: + + /** + * Explicitly frees the memory used by data structures. + */ + void Close(); + + /** + * Check if the given interval overlaps with this region. + */ + bool Overlaps( const CalenSlotInterval& aInterval ) const; + + /** + * Add an event to this region. Events must be added sequentially, + * and must overlap this region (unless it's the first event of the region). + */ + void AddEvent( const CalenTimedEventInfo& aEvent ); + + /** + * Add aOffset to all slot coordinates later than aPos + */ + void AddOffset( int aOffset, int aPos ); + +private: + + /** + * Add the event to the bookkeeping of overlapping/nonoverlapping + * intervals. + */ + void AddInterval( const CalenTimedEventInfo& aEvent ); + +public: + + QList iColumns; + QList iIntervals; + }; + + +/** + * A container struct, used by the clients of the slot info storage, + * to provide data in. + */ +struct SCalenApptInfo + { + QModelIndex iIndex; + QDateTime iStartTime; + QDateTime iEndTime; + bool iAllDay; + TCalenInstanceId iId; + AgendaEntry::Status iStatus; +// AgendaEntry::TReplicationStatus iReplicationStatus; + TBufC iSummary; + TUint32 iColor; + }; + + +/** + * Storage class for storing all calendar instances within one day. This + * class organises the data according to the way it will be needed in the + * day and week view. + */ +class CalenDayInfo + { +public: + + enum TSlotsInHour + { + EOne = 1, + ETwo, + EThree, + EFour + }; + +public: // Constructors and destructor + + /** + * C++ default constructor. + */ + CalenDayInfo( TSlotsInHour aSlotsInHour ); + + /** + * Destructor + */ + virtual ~CalenDayInfo(); + + +public: // New functions + + /** + * Reset the storage, remove all data and set the state back to normal. + */ + void Reset(); + + /** + * Add a timed event. All timed events must be added in increasing + * order (sorted by starting time). + */ + void InsertTimedEvent( const SCalenApptInfo& aItemInfo ); + + /** + * Add an untimed event. + */ +// void InsertUntimedEventL( const CCalInstance& aInstance ); + + /** + * Add an untimed event. (Nonleaving version, useful for testing.) + */ + void InsertUntimedEvent( AgendaEntry::Type aType, + const TCalenInstanceId& aId ); + /** + * Add an allday event. + */ + void InsertAlldayEvent( const SCalenApptInfo& aItemInfo ); + + /** + * Is the given event allday event + * @param aStart time to be checked + * @param aEnd time to be checked + * @return true if this is allday event, false otherwise + */ + static bool IsAlldayEvent( QDateTime aStart, QDateTime aEnd ); + + /** + * Is the given event allday event + * @param aInstance Instance to be checked + * @return true if this is allday event, false otherwise + */ +// static bool IsAlldayEvent( const CCalInstance& aInstance ); + + /** + * Return the slot number where this class would insert the + * untimed events if nothing else is specified. + */ + int SuggestedUntimedSlotPos(); + + /** + * Return how many untimed slots is needed for this day. + */ + int NeededUntimedSlotCount(); + + /** + * Update the indexing to take the current amount of untimed slots + * into account. This must be called after all untimed events + * have been added. + * + * @param aSlot the slot where the untimed events are to be added. + * If negative, uses the default, otherwise aSlot must + * be less than or equal to the default position as + * returned by SuggestedUntimedSlotPos(). + * @param aUntimedCount the number of slots to insert for untimed events. If + * aSlot is specified, this must be larger or equal + * to NeededUntimedSlotCount(). + */ + int UpdateUntimedPos( int aSlot = -1, int aUntimedCount = 0 ); + + /** + * Return the first slot containing a non-allday event. + * If this class doesn't contain any data, returns KErrNotFound. + */ + int FirstOccupiedSlot(); + + /** + * Return the last slot containing a non-allday event. + * If this class doesn't contain any data, returns KErrNotFound. + */ + int LastOccupiedSlot(); + + int EarliestEndSlot(); + int LastStartSlot(); + + + /** + * Convert a starting time into a slot index. + */ + int SlotIndexForStartTime( QDateTime aStartTime ); + + /** + * Convert an ending time into a slot index. + */ + int SlotIndexForEndTime( QDateTime aStartTime ); + + /** + * Get information about where the item aItemInfo + * should be displayed. The parameters are filled + * on return. + * + * @param aStartSlot the first slot of the event + * @param aEndSlot the first slot after the event + * @param aColumnIndex the column in which this event is located + * @param aColumns the total number of columns in the region + * this event belongs to + */ + void GetLocation( const SCalenApptInfo& aItemInfo, + int& aStartSlot, + int& aEndSlot, + int& aColumnIndex, + int& aColumns ); + + /** + * Get the number of allday events + */ + int AlldayCount(); + + /** + * Get the number of todo events + */ + int TodoCount(); + + /** + * Check if a slot is the first slot of an hour. + */ + bool IsHourStartSlot( const int& aSlotIndex ) const; + + /** + * Check if a slot is an extra slot (for untimed events). + */ + bool IsExtraSlot( const int& aSlotIndex ) const; + + /** + * Convert a slot index into a hour + */ + int HourFromSlotIndex( const int& aSlotIndex ) const; + + /** + * Convert a hour into a slot index. + */ + int SlotIndexFromHour( int aHour ); + + /** + * Rounds the slot number up (towards earlier hours) to an even hour + */ + int RoundHourUp( int aSlot ); + + /** + * Rounds the slot number down (towards later hours) to an even hour + */ + int RoundHourDown( int aSlot ); + + /** + * Get the starting slot of the current selection + */ + void GetSelectedSlot( int& aSlot, int& aRegion, int& aColumnIndex, int& aColumns ); + + /** + * Try to move the selection in the given direction + * + * @return true if able to move the selection, false if + * unable to move (indicating that the selection should move + * to the next/previous day). + */ + bool MoveSelection( TScrollDirection aDirection ); + + /** + * Move the selected slot within the currently selected event. + */ + void MoveSelectionInEvent( TScrollDirection aDirection ); + + /** + * Make sure the selected slot within the currently selected event is valid. + */ + void UpdateSelectionInEvent(); + + /** + * Check if any event currently is selected. + */ + bool IsEventSelected() const; + + /** + * Check if the current selection actually denotes + * more than one event (the todo event slot is selected, + * containing more than one todo). + */ + bool IsMultipleEventsSelected() const; + + /** + * Check if an allday event currently is selected. + */ + bool IsAlldayEventSelected() const; + + /** + * Get the instance id of the currently selected event. + */ + TCalenInstanceId SelectedEvent(); + + /** + * Update the state to make the given calendar instance selected + * + * @return KErrNotFound if the instance isn't found, KErrNone otherwise. + */ + int SelectEvent( const TCalenInstanceId& aId ); + + /** + * Get the instance id of an untimed event. Maximally one + * todo event is counted into this, i.e. aIndex = 1 never returns + * a todo event even though there are more than one. + */ + TCalenInstanceId UntimedEvent( int aIndex ); + + /** + * Get info about an allday event. + */ + const CalenTimedEventInfo& AlldayEvent( int aIndex ); + + /** + * Move the selection to the given slot, possibly selecting + * an event. + */ + void SelectSlot( int aSlot ); + + /** + * Return the list of regions. + */ + const QList& RegionList() const; + + /** + * Get the list of event intervals (for use in week view and ribbon). + */ + void GetEventIntervals( QList& aArray ) const; + + /** + * Return the interval which is selected currently. + */ + CalenSlotInterval SelectedInterval(); + + /** + * Sets selection within a region + * + * @param aRegion Region index. + * @param aColumn Column index. + * @param aSlot Slot number (has to be aligned to full hour). + */ + bool SetSelectionInRegion( int aRegion, int aColumn, int aSlot ); + +private: + + enum TMoveDirection + { + EMoveDirectionUp = -1, + EMoveDirectionDown = 1 + }; + + /** + * See if any region overlaps the given interval. Regions are searched + * in the direction specified by aDirection, e.g. if aDirection < 0, + * this returns the last overlapping region, if aDirection > 0, returns + * the first overlapping instead. + * + * @return the index of the found overlapping region, or -1 if no + * matching region was found. + */ + int FindRegion( const CalenSlotInterval& aInterval, int aDirection ); + + /** + * See if any event overlaps the given interval within the current column. + * Events are searched in the direction specified by aDirection, + * e.g. if aDirection < 0, this returns the last overlapping event, + * if aDirection > 0, returns the first overlapping instead. + * + * @return the index within the column of the overlapping event, or -1 if no + * matching event was found. + */ + int FindEvent( const CalenSlotInterval& aInterval, int aDirection ); + + /** + * Update the selection state by selecting the first event which ends at + * the end of the current region. + */ + void EnterRegionFromBelow(); + + /** + * Update the selection state by selecting the first event which starts + * at the start of the current region. + */ + void EnterRegionFromAbove(); + + /** + * Try to move the selection in the given direction, when an + * empty area is selected. + * + * @return true if able to move the selection, false if + * unable to move (indicating that the selection should move + * to the next/previous day). + */ + bool MoveInEmptyArea( TScrollDirection aDirection ); + + /** + * Try to move the selection in the given direction, when the + * selection is in a region. + * + * @return true if able to move the selection, false if + * unable to move (indicating that the selection should move + * to the next/previous day). + */ + bool MoveInRegion( TScrollDirection aDirection ); + + /** + * Try to move the selection in the given direction, when an + * allday event is selected + * + * @return true if able to move the selection, false if + * unable to move (indicating that the selection should move + * to the next/previous day). + */ + bool MoveInAlldayEvent( TScrollDirection aDirection ); + + /** + * Update the selection state by moving from one ordinary event column + * to another, in the given direction + */ + void MoveBetweenColumns( TScrollDirection aDirection ); + + /** + * Update the selection state by moving in the given direction + */ + void MoveInColumn( int aDirection ); + + /** + * The selection should be moved out of the current region (in the given + * direction), update the selection state according to what there is + * outside of the region. + */ + void MoveOutFromRegion( int aDirection ); + + /** + * Set the selected slot within the current event according to the selection + * direction. + */ + void SetSelectionInEvent( int aDirection ); + + /** + * Determines how large area to scan for new events/regions when moving in the + * given direction. + * + * I.e., if moving upwards, returns the whole interval from the start of aInterval + * up to the next slot which can be focused as an empty slot. If aInterval doesn't + * start on an even hour, the returned interval is from the start of the first whole + * hour before the interval, to the start of aInterval. + * + * If moving downwards, returns the whole interval from the end of aInterval to the + * end of the next whole hour after the interval. + * + */ + CalenSlotInterval NextFocusArea( const CalenSlotInterval& aInterval, int aDirection ); + + /** + * Return the next slot to focus if moving in the given direction from the interval + * and focusing an empty slot. + */ + int NextEmptyFocusSlot( const CalenSlotInterval& aInterval, int aDirection ); + + /** + * Return the interval which the current selection state represents, if + * an empty area is selected. + */ + CalenSlotInterval EmptySelectionInterval(); + + /** + * Backup the whole selection state. + */ + void StoreOrigSelection(); + + /** + * Check if the current selection state is valid, if not, reset it + * to the backed up copy + * @return true if selection state is valid, false if not. + */ + bool ValidateSelection(); + +private: // New data + + QList iRegionList; + QList iUntimedEvents; + QList iTodoEvents; + QList iAlldayEvents; + + int iLastStartSlot; + int iEarliestEndSlot; + /** + * The total number of untimed slots. + */ + int iUntimedSlotCount; + /** + * The slot index of the first untimed slot. + */ + int iFirstUntimedSlot; + /** + * The number of empty untimed slots. + */ + int iEmptyUntimedSlots; + /** + * The number of slots per hour. + */ + TSlotsInHour iSlotsInHour; + + /** + * Chooses which allday event is selected. If none currently is selected, + * this is negative. This variable overrides the rest selection variables. + * If this points to an allday event, the other variables are ignored, + * except iSelectedSlot which is used for returning to the original place + * if moving back to the ordinary events. + */ + int iSelectedAlldayEvent; + + /** + * Chooses which region currently is selected. If none currently is selected, + * this is negative. If this points to a region, iSelectedColumn and + * iSelectedColumnEventIndex are taken into account. + */ + int iSelectedRegion; + + /** + * Chooses which column is selected within the currently selected region. + * If this is equal to the number of columns, the last, implicit, empty column + * is selected. + */ + int iSelectedColumn; + /** + * Chooses which event is selected within the currently selected column. If + * none is selected, this is negative. + */ + int iSelectedColumnEventIndex; + /** + * Chooses which slot in the day currently is in focus. This must always point + * to a valid slot. If an event is selected within a column, it points to an + * slot within that event. If no event is selected, it points to the start + * of the currently selected empty time region (which is iSlotsInHour slots long). + * If an allday event is selected, this points to the last selected slot in the + * ordinary day area. + */ + int iSelectedSlot; + + // copies of the current selection state, to be used for reverting to the original + // state if the selection is moved to an invalid position + int iOrigSelectedAlldayEvent; + int iOrigSelectedRegion; + int iOrigSelectedColumn; + int iOrigSelectedSlot; + int iOrigSelectedColumnEventIndex; + + }; + +#endif // CALENDAYINFO_H + + +// End of File