You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/korganizer/kotimelineview.cpp

356 lines
11 KiB

/*
This file is part of KOrganizer.
Copyright (c) 2007 Till Adam <adam@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, permission is given to link this program
with any edition of Qt, and distribute the resulting executable,
without including the source code for Qt in the source distribution.
*/
#include <libkcal/calendar.h>
#include <libkcal/calendarresources.h>
#include <qlayout.h>
#include <kdgantt/KDGanttViewTaskItem.h>
#include <kdgantt/KDGanttViewSubwidgets.h>
#include "koeventpopupmenu.h"
#include "koglobals.h"
#include "koprefs.h"
#include "timelineitem.h"
#include "kotimelineview.h"
using namespace KOrg;
using namespace KCal;
KOTimelineView::KOTimelineView(Calendar *calendar, QWidget *parent,
const char *name)
: KOEventView(calendar, parent, name),
mEventPopup( 0 )
{
QVBoxLayout* vbox = new QVBoxLayout(this);
mGantt = new KDGanttView(this);
mGantt->setCalendarMode( true );
mGantt->setShowLegendButton( false );
mGantt->setFixedHorizon( true );
mGantt->removeColumn( 0 );
mGantt->addColumn( i18n("Calendar") );
mGantt->setHeaderVisible( true );
if ( KGlobal::locale()->use12Clock() )
mGantt->setHourFormat( KDGanttView::Hour_12 );
else
mGantt->setHourFormat( KDGanttView::Hour_24_FourDigit );
vbox->addWidget( mGantt );
connect( mGantt, SIGNAL(gvCurrentChanged(KDGanttViewItem*)),
SLOT(itemSelected(KDGanttViewItem*)) );
connect( mGantt, SIGNAL(itemDoubleClicked(KDGanttViewItem*)),
SLOT(itemDoubleClicked(KDGanttViewItem*)) );
connect( mGantt, SIGNAL(itemRightClicked(KDGanttViewItem*)),
SLOT(itemRightClicked(KDGanttViewItem*)) );
connect( mGantt, SIGNAL(gvItemMoved(KDGanttViewItem*)),
SLOT(itemMoved(KDGanttViewItem*)) );
connect( mGantt, SIGNAL(rescaling(KDGanttView::Scale)),
SLOT(overscale(KDGanttView::Scale)) );
connect( mGantt, SIGNAL( dateTimeDoubleClicked( const QDateTime& ) ),
SLOT( newEventWithHint( const QDateTime& ) ) );
}
KOTimelineView::~KOTimelineView()
{
delete mEventPopup;
}
/*virtual*/
KCal::ListBase<KCal::Incidence> KOTimelineView::selectedIncidences()
{
return KCal::ListBase<KCal::Incidence>();
}
/*virtual*/
KCal::DateList KOTimelineView::selectedDates()
{
return KCal::DateList();
}
/*virtual*/
int KOTimelineView::currentDateCount()
{
return 0;
}
/*virtual*/
void KOTimelineView::showDates(const QDate& start, const QDate& end)
{
mStartDate = start;
mEndDate = end;
mHintDate = QDateTime();
mGantt->setHorizonStart( QDateTime(start) );
mGantt->setHorizonEnd( QDateTime(end.addDays(1)) );
mGantt->setMinorScaleCount( 1 );
mGantt->setScale( KDGanttView::Hour );
mGantt->setMinimumScale( KDGanttView::Hour );
mGantt->setMaximumScale( KDGanttView::Hour );
mGantt->zoomToFit();
mGantt->setUpdateEnabled( false );
mGantt->clear();
// item for every calendar
TimelineItem *item = 0;
CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
if ( !calres ) {
item = new TimelineItem( i18n("Calendar"), mGantt );
mCalendarItemMap[0][QString()] = item;
} else {
CalendarResourceManager *manager = calres->resourceManager();
for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) {
QColor resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
if ( (*it)->canHaveSubresources() ) {
QStringList subResources = (*it)->subresources();
for ( QStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) {
QString type = (*it)->subresourceType( *subit );
if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") )
continue;
item = new TimelineItem( (*it)->labelForSubresource( *subit ), mGantt );
resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
QColor subrescol = *KOPrefs::instance()->resourceColor( *subit );
if ( subrescol.isValid() )
resourceColor = subrescol;
if ( resourceColor.isValid() )
item->setColors( resourceColor, resourceColor, resourceColor );
mCalendarItemMap[*it][*subit] = item;
}
} else {
item = new TimelineItem( (*it)->resourceName(), mGantt );
if ( resourceColor.isValid() )
item->setColors( resourceColor, resourceColor, resourceColor );
mCalendarItemMap[*it][QString()] = item;
}
}
}
// add incidences
Event::List events;
for ( QDate day = start; day <= end; day = day.addDays( 1 ) ) {
events = calendar()->events( day, EventSortStartDate, SortDirectionAscending );
for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) {
insertIncidence( *it, day );
}
}
mGantt->setUpdateEnabled( true );
}
/*virtual*/
void KOTimelineView::showIncidences(const KCal::ListBase<KCal::Incidence>&)
{
}
/*virtual*/
void KOTimelineView::updateView()
{
if ( mStartDate.isValid() && mEndDate.isValid() )
showDates( mStartDate, mEndDate );
}
/*virtual*/
void KOTimelineView::changeIncidenceDisplay(KCal::Incidence* incidence, int mode)
{
kdDebug() << k_funcinfo << incidence << " " << mode << endl;
switch ( mode ) {
case KOGlobals::INCIDENCEADDED:
insertIncidence( incidence );
break;
case KOGlobals::INCIDENCEEDITED:
removeIncidence( incidence );
insertIncidence( incidence );
break;
case KOGlobals::INCIDENCEDELETED:
removeIncidence( incidence );
break;
default:
updateView();
}
}
void KOTimelineView::itemSelected( KDGanttViewItem *item )
{
TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
if ( tlitem )
emit incidenceSelected( tlitem->incidence() );
}
void KOTimelineView::itemDoubleClicked( KDGanttViewItem *item )
{
TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
if ( tlitem )
emit editIncidenceSignal( tlitem->incidence() );
}
void KOTimelineView::itemRightClicked( KDGanttViewItem *item )
{
mHintDate = mGantt->getDateTimeForCoordX( QCursor::pos().x(), true );
TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
if ( !tlitem ) {
showNewEventPopup();
return;
}
if ( !mEventPopup )
mEventPopup = eventPopup();
mEventPopup->showIncidencePopup( tlitem->incidence(), QDate() );
}
bool KOTimelineView::eventDurationHint(QDateTime & startDt, QDateTime & endDt, bool & allDay)
{
startDt = mHintDate;
endDt = mHintDate.addSecs( 2 * 60 * 60 );
allDay = false;
return mHintDate.isValid();
}
//slot
void KOTimelineView::newEventWithHint( const QDateTime& dt )
{
mHintDate = dt;
emit newEventSignal( dt );
}
TimelineItem * KOTimelineView::calendarItemForIncidence(KCal::Incidence * incidence)
{
CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
TimelineItem *item = 0;
if ( !calres ) {
item = mCalendarItemMap[0][QString()];
} else {
ResourceCalendar *res = calres->resource( incidence );
if ( !res )
return 0;
if ( res->canHaveSubresources() ) {
QString subRes = res->subresourceIdentifier( incidence );
item = mCalendarItemMap[res][subRes];
} else {
item = mCalendarItemMap[res][QString()];
}
}
return item;
}
void KOTimelineView::insertIncidence(KCal::Incidence * incidence, const QDate &day )
{
TimelineItem *item = calendarItemForIncidence( incidence );
if ( !item ) {
kdWarning() << k_funcinfo << "Help! Something is really wrong here!" << endl;
return;
}
if ( incidence->doesRecur() ) {
QValueList<QDateTime> l = incidence->startDateTimesForDate( day );
if ( l.isEmpty() ) {
// strange, but seems to happen for some recurring events...
item->insertIncidence( incidence, QDateTime( day, incidence->dtStart().time() ),
QDateTime( day, incidence->dtEnd().time() ) );
} else {
for ( QValueList<QDateTime>::ConstIterator it = l.constBegin();
it != l.constEnd(); ++it ) {
item->insertIncidence( incidence, *it, incidence->endDateForStart( *it ) );
}
}
} else {
if ( incidence->dtStart().date() == day || incidence->dtStart().date() < mStartDate )
item->insertIncidence( incidence );
}
}
void KOTimelineView::insertIncidence(KCal::Incidence * incidence)
{
KCal::Event *event = dynamic_cast<KCal::Event*>( incidence );
if ( !event )
return;
if ( incidence->doesRecur() )
insertIncidence( incidence, QDate() );
for ( QDate day = mStartDate; day <= mEndDate; day = day.addDays( 1 ) ) {
Event::List events = calendar()->events( day, EventSortStartDate, SortDirectionAscending );
for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) {
if ( events.contains( event ) )
insertIncidence( *it, day );
}
}
}
void KOTimelineView::removeIncidence(KCal::Incidence * incidence)
{
TimelineItem *item = calendarItemForIncidence( incidence );
if ( item ) {
item->removeIncidence( incidence );
} else {
// try harder, the incidence might already be removed from the resource
typedef QMap<QString, KOrg::TimelineItem*> M2_t;
typedef QMap<KCal::ResourceCalendar*, M2_t> M1_t;
for ( M1_t::ConstIterator it1 = mCalendarItemMap.constBegin(); it1 != mCalendarItemMap.constEnd(); ++it1 ) {
for ( M2_t::ConstIterator it2 = it1.data().constBegin(); it2 != it1.data().constEnd(); ++it2 ) {
if ( it2.data() ) {
it2.data()->removeIncidence( incidence );
}
}
}
}
}
void KOTimelineView::itemMoved(KDGanttViewItem * item)
{
TimelineSubItem *tlit = dynamic_cast<TimelineSubItem*>( item );
if ( !tlit )
return;
Incidence *i = tlit->incidence();
mChanger->beginChange( i );
QDateTime newStart = tlit->startTime();
if ( i->doesFloat() )
newStart = QDateTime( newStart.date() );
int delta = tlit->originalStart().secsTo( newStart );
i->setDtStart( i->dtStart().addSecs( delta ) );
int duration = tlit->startTime().secsTo( tlit->endTime() );
int allDayOffset = 0;
if ( i->doesFloat() ) {
duration /= (60*60*24);
duration *= (60*60*24);
allDayOffset = (60*60*24);
duration -= allDayOffset;
if ( duration < 0 ) duration = 0;
}
i->setDuration( duration );
TimelineItem *parent = static_cast<TimelineItem*>( tlit->parent() );
parent->moveItems( i, tlit->originalStart().secsTo( newStart ), duration + allDayOffset );
mChanger->endChange( i );
}
void KOTimelineView::overscale(KDGanttView::Scale scale)
{
Q_UNUSED( scale );
mGantt->setZoomFactor( 1, false );
mGantt->setScale( KDGanttView::Hour );
mGantt->setMinorScaleCount( 12 );
}
#include "kotimelineview.moc"