korganizer

kotimelineview.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2007 Till Adam <adam@kde.org>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 
00026 #include <libkcal/calendar.h>
00027 #include <libkcal/calendarresources.h>
00028 
00029 #include <qlayout.h>
00030 
00031 #include <kdgantt/KDGanttViewTaskItem.h>
00032 #include <kdgantt/KDGanttViewSubwidgets.h>
00033 
00034 #include "koeventpopupmenu.h"
00035 #include "koglobals.h"
00036 #include "koprefs.h"
00037 #include "timelineitem.h"
00038 
00039 #include "kotimelineview.h"
00040 
00041 using namespace KOrg;
00042 using namespace KCal;
00043 
00044 KOTimelineView::KOTimelineView(Calendar *calendar, QWidget *parent,
00045                                  const char *name)
00046   : KOEventView(calendar, parent, name),
00047   mEventPopup( 0 )
00048 {
00049     QVBoxLayout* vbox = new QVBoxLayout(this);
00050     mGantt = new KDGanttView(this);
00051     mGantt->setCalendarMode( true );
00052     mGantt->setShowLegendButton( false );
00053     mGantt->setFixedHorizon( true );
00054     mGantt->removeColumn( 0 );
00055     mGantt->addColumn( i18n("Calendar") );
00056     mGantt->setHeaderVisible( true );
00057     if ( KGlobal::locale()->use12Clock() )
00058       mGantt->setHourFormat( KDGanttView::Hour_12 );
00059     else
00060       mGantt->setHourFormat( KDGanttView::Hour_24_FourDigit );
00061 
00062 
00063     vbox->addWidget( mGantt );
00064 
00065     connect( mGantt, SIGNAL(gvCurrentChanged(KDGanttViewItem*)),
00066              SLOT(itemSelected(KDGanttViewItem*)) );
00067     connect( mGantt, SIGNAL(itemDoubleClicked(KDGanttViewItem*)),
00068              SLOT(itemDoubleClicked(KDGanttViewItem*)) );
00069     connect( mGantt, SIGNAL(itemRightClicked(KDGanttViewItem*)),
00070              SLOT(itemRightClicked(KDGanttViewItem*)) );
00071     connect( mGantt, SIGNAL(gvItemMoved(KDGanttViewItem*)),
00072              SLOT(itemMoved(KDGanttViewItem*)) );
00073     connect( mGantt, SIGNAL(rescaling(KDGanttView::Scale)),
00074              SLOT(overscale(KDGanttView::Scale)) );
00075     connect( mGantt, SIGNAL( dateTimeDoubleClicked( const QDateTime& ) ),
00076              SLOT( newEventWithHint( const QDateTime& ) ) );
00077 }
00078 
00079 KOTimelineView::~KOTimelineView()
00080 {
00081   delete mEventPopup;
00082 }
00083 
00084 /*virtual*/
00085 KCal::ListBase<KCal::Incidence> KOTimelineView::selectedIncidences()
00086 {
00087     return KCal::ListBase<KCal::Incidence>();
00088 }
00089 
00090 /*virtual*/
00091 KCal::DateList KOTimelineView::selectedDates()
00092 {
00093     return KCal::DateList();
00094 }
00095 
00096 /*virtual*/
00097 int KOTimelineView::currentDateCount()
00098 {
00099     return 0;
00100 }
00101 
00102 /*virtual*/
00103 void KOTimelineView::showDates(const QDate& start, const QDate& end)
00104 {
00105   mStartDate = start;
00106   mEndDate = end;
00107   mHintDate = QDateTime();
00108   mGantt->setHorizonStart( QDateTime(start) );
00109   mGantt->setHorizonEnd( QDateTime(end.addDays(1)) );
00110   mGantt->setMinorScaleCount( 1 );
00111   mGantt->setScale( KDGanttView::Hour );
00112   mGantt->setMinimumScale( KDGanttView::Hour );
00113   mGantt->setMaximumScale( KDGanttView::Hour );
00114   mGantt->zoomToFit();
00115 
00116   mGantt->setUpdateEnabled( false );
00117   mGantt->clear();
00118 
00119   // item for every calendar
00120   TimelineItem *item = 0;
00121   CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
00122   if ( !calres ) {
00123     item = new TimelineItem( i18n("Calendar"), calendar(), mGantt );
00124     mCalendarItemMap[0][QString()] = item;
00125   } else {
00126     CalendarResourceManager *manager = calres->resourceManager();
00127     for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) {
00128       QColor resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
00129       if ( (*it)->canHaveSubresources() ) {
00130         QStringList subResources = (*it)->subresources();
00131         for ( QStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) {
00132           QString type = (*it)->subresourceType( *subit );
00133           if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") )
00134             continue;
00135           item = new TimelineItem( (*it)->labelForSubresource( *subit ), calendar(), mGantt );
00136           resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
00137           QColor subrescol = *KOPrefs::instance()->resourceColor( *subit );
00138           if ( subrescol.isValid() )
00139             resourceColor = subrescol;
00140           if ( resourceColor.isValid() )
00141             item->setColors( resourceColor, resourceColor, resourceColor );
00142           mCalendarItemMap[*it][*subit] = item;
00143         }
00144       } else {
00145         item = new TimelineItem( (*it)->resourceName(), calendar(), mGantt );
00146         if ( resourceColor.isValid() )
00147           item->setColors( resourceColor, resourceColor, resourceColor );
00148         mCalendarItemMap[*it][QString()] = item;
00149       }
00150     }
00151   }
00152 
00153   // add incidences
00154   Event::List events;
00155   for ( QDate day = start; day <= end; day = day.addDays( 1 ) ) {
00156     events = calendar()->events( day, EventSortStartDate, SortDirectionAscending );
00157     for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) {
00158       insertIncidence( *it, day );
00159     }
00160   }
00161 
00162   mGantt->setUpdateEnabled( true );
00163 }
00164 
00165 /*virtual*/
00166 void KOTimelineView::showIncidences(const KCal::ListBase<KCal::Incidence>&, const QDate &)
00167 {
00168 }
00169 
00170 /*virtual*/
00171 void KOTimelineView::updateView()
00172 {
00173   if ( mStartDate.isValid() && mEndDate.isValid() )
00174     showDates( mStartDate, mEndDate );
00175 }
00176 
00177 /*virtual*/
00178 void KOTimelineView::changeIncidenceDisplay(KCal::Incidence* incidence, int mode)
00179 {
00180   kdDebug() << k_funcinfo << incidence << " " << mode << endl;
00181   switch ( mode ) {
00182     case KOGlobals::INCIDENCEADDED:
00183       insertIncidence( incidence );
00184       break;
00185     case KOGlobals::INCIDENCEEDITED:
00186       removeIncidence( incidence );
00187       insertIncidence( incidence );
00188       break;
00189     case KOGlobals::INCIDENCEDELETED:
00190       removeIncidence( incidence );
00191       break;
00192     default:
00193       updateView();
00194   }
00195 }
00196 
00197 void KOTimelineView::itemSelected( KDGanttViewItem *item )
00198 {
00199   TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
00200   if ( tlitem )
00201     emit incidenceSelected( tlitem->incidence(), tlitem->originalStart().date() );
00202 }
00203 
00204 void KOTimelineView::itemDoubleClicked( KDGanttViewItem *item )
00205 {
00206   TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
00207   if ( tlitem )
00208     emit editIncidenceSignal( tlitem->incidence() );
00209 }
00210 
00211 void KOTimelineView::itemRightClicked( KDGanttViewItem *item )
00212 {
00213   mHintDate = mGantt->getDateTimeForCoordX( QCursor::pos().x(), true );
00214   TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
00215   if ( !tlitem ) {
00216     showNewEventPopup();
00217     return;
00218   }
00219   if ( !mEventPopup )
00220     mEventPopup = eventPopup();
00221   mEventPopup->showIncidencePopup( calendar(), tlitem->incidence(), QDate() );
00222 }
00223 
00224 bool KOTimelineView::eventDurationHint(QDateTime & startDt, QDateTime & endDt, bool & allDay)
00225 {
00226   startDt = mHintDate;
00227   endDt = mHintDate.addSecs( 2 * 60 * 60 );
00228   allDay = false;
00229   return mHintDate.isValid();
00230 }
00231 
00232 //slot
00233 void KOTimelineView::newEventWithHint( const QDateTime& dt )
00234 {
00235   mHintDate = dt;
00236   emit newEventSignal( 0/*ResourceCalendar*/, QString()/*subResource*/, dt );
00237 }
00238 
00239 TimelineItem * KOTimelineView::calendarItemForIncidence(KCal::Incidence * incidence)
00240 {
00241   CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
00242   TimelineItem *item = 0;
00243   if ( !calres ) {
00244     item = mCalendarItemMap[0][QString()];
00245   } else {
00246     ResourceCalendar *res = calres->resource( incidence );
00247     if ( !res )
00248       return 0;
00249     if ( res->canHaveSubresources() ) {
00250       QString subRes = res->subresourceIdentifier( incidence );
00251       item = mCalendarItemMap[res][subRes];
00252     } else {
00253       item = mCalendarItemMap[res][QString()];
00254     }
00255   }
00256   return item;
00257 }
00258 
00259 void KOTimelineView::insertIncidence(KCal::Incidence * incidence, const QDate &day )
00260 {
00261   TimelineItem *item = calendarItemForIncidence( incidence );
00262   if ( !item ) {
00263     kdWarning() << k_funcinfo << "Help! Something is really wrong here!" << endl;
00264     return;
00265   }
00266 
00267   if ( incidence->doesRecur() ) {
00268     QValueList<QDateTime> l = incidence->startDateTimesForDate( day );
00269     if ( l.isEmpty() ) {
00270       // strange, but seems to happen for some recurring events...
00271       item->insertIncidence( incidence, QDateTime( day, incidence->dtStart().time() ),
00272                               QDateTime( day, incidence->dtEnd().time() ) );
00273     } else {
00274       for ( QValueList<QDateTime>::ConstIterator it = l.constBegin();
00275             it != l.constEnd(); ++it ) {
00276         item->insertIncidence( incidence, *it, incidence->endDateForStart( *it ) );
00277       }
00278     }
00279   } else {
00280     if ( incidence->dtStart().date() == day || incidence->dtStart().date() < mStartDate )
00281       item->insertIncidence( incidence );
00282   }
00283 }
00284 
00285 void KOTimelineView::insertIncidence(KCal::Incidence * incidence)
00286 {
00287   KCal::Event *event = dynamic_cast<KCal::Event*>( incidence );
00288   if ( !event )
00289     return;
00290   if ( incidence->doesRecur() )
00291     insertIncidence( incidence, QDate() );
00292   for ( QDate day = mStartDate; day <= mEndDate; day = day.addDays( 1 ) ) {
00293     Event::List events = calendar()->events( day, EventSortStartDate, SortDirectionAscending );
00294     for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) {
00295       if ( events.contains( event ) )
00296         insertIncidence( *it, day );
00297     }
00298   }
00299 }
00300 
00301 void KOTimelineView::removeIncidence(KCal::Incidence * incidence)
00302 {
00303   TimelineItem *item = calendarItemForIncidence( incidence );
00304   if ( item ) {
00305     item->removeIncidence( incidence );
00306   } else {
00307     // try harder, the incidence might already be removed from the resource
00308     typedef QMap<QString, KOrg::TimelineItem*> M2_t;
00309     typedef QMap<KCal::ResourceCalendar*, M2_t> M1_t;
00310     for ( M1_t::ConstIterator it1 = mCalendarItemMap.constBegin(); it1 != mCalendarItemMap.constEnd(); ++it1 ) {
00311       for ( M2_t::ConstIterator it2 = it1.data().constBegin(); it2 != it1.data().constEnd(); ++it2 ) {
00312         if ( it2.data() ) {
00313           it2.data()->removeIncidence( incidence );
00314         }
00315       }
00316     }
00317   }
00318 }
00319 
00320 void KOTimelineView::itemMoved(KDGanttViewItem * item)
00321 {
00322   TimelineSubItem *tlit = dynamic_cast<TimelineSubItem*>( item );
00323   if ( !tlit )
00324     return;
00325   Incidence *i = tlit->incidence();
00326   mChanger->beginChange( i );
00327   QDateTime newStart = tlit->startTime();
00328   if ( i->doesFloat() )
00329     newStart = QDateTime( newStart.date() );
00330   int delta = tlit->originalStart().secsTo( newStart );
00331   i->setDtStart( i->dtStart().addSecs( delta ) );
00332   int duration = tlit->startTime().secsTo( tlit->endTime() );
00333   int allDayOffset = 0;
00334   if ( i->doesFloat() ) {
00335     duration /= (60*60*24);
00336     duration *= (60*60*24);
00337     allDayOffset = (60*60*24);
00338     duration -= allDayOffset;
00339     if ( duration < 0 ) duration = 0;
00340   }
00341   i->setDuration( duration );
00342   TimelineItem *parent = static_cast<TimelineItem*>( tlit->parent() );
00343   parent->moveItems( i, tlit->originalStart().secsTo( newStart ), duration + allDayOffset );
00344   mChanger->endChange( i );
00345 }
00346 
00347 void KOTimelineView::overscale(KDGanttView::Scale scale)
00348 {
00349   Q_UNUSED( scale );
00350   mGantt->setZoomFactor( 1, false );
00351   mGantt->setScale( KDGanttView::Hour );
00352   mGantt->setMinorScaleCount( 12 );
00353 }
00354 
00355 #include "kotimelineview.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys