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 <tqlayout.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, TQWidget *parent,
00045                                  const char *name)
00046   : KOEventView(calendar, parent, name),
00047   mEventPopup( 0 )
00048 {
00049     TQVBoxLayout* vbox = new TQVBoxLayout(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, TQT_SIGNAL(gvCurrentChanged(KDGanttViewItem*)),
00066              TQT_SLOT(itemSelected(KDGanttViewItem*)) );
00067     connect( mGantt, TQT_SIGNAL(itemDoubleClicked(KDGanttViewItem*)),
00068              TQT_SLOT(itemDoubleClicked(KDGanttViewItem*)) );
00069     connect( mGantt, TQT_SIGNAL(itemRightClicked(KDGanttViewItem*)),
00070              TQT_SLOT(itemRightClicked(KDGanttViewItem*)) );
00071     connect( mGantt, TQT_SIGNAL(gvItemMoved(KDGanttViewItem*)),
00072              TQT_SLOT(itemMoved(KDGanttViewItem*)) );
00073     connect( mGantt, TQT_SIGNAL(rescaling(KDGanttView::Scale)),
00074              TQT_SLOT(overscale(KDGanttView::Scale)) );
00075     connect( mGantt, TQT_SIGNAL( dateTimeDoubleClicked( const TQDateTime& ) ),
00076              TQT_SLOT( newEventWithHint( const TQDateTime& ) ) );
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::selectedIncidenceDates()
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 TQDate& start, const TQDate& end)
00104 {
00105   mStartDate = start;
00106   mEndDate = end;
00107   mHintDate = TQDateTime();
00108   mGantt->setHorizonStart( TQDateTime(start) );
00109   mGantt->setHorizonEnd( TQDateTime(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][TQString()] = item;
00125   } else {
00126     CalendarResourceManager *manager = calres->resourceManager();
00127     for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) {
00128       TQColor resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
00129       if ( (*it)->canHaveSubresources() ) {
00130         TQStringList subResources = (*it)->subresources();
00131         for ( TQStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) {
00132           TQString 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           TQColor 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][TQString()] = item;
00149       }
00150     }
00151   }
00152 
00153   // add incidences
00154   Event::List events;
00155   for ( TQDate 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 TQDate &)
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(), TQDate() );
00209   }
00210 }
00211 
00212 void KOTimelineView::itemRightClicked( KDGanttViewItem *item )
00213 {
00214   mHintDate = mGantt->getDateTimeForCoordX( TQCursor::pos().x(), true );
00215   TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
00216   if ( !tlitem ) {
00217     showNewEventPopup();
00218     return;
00219   }
00220   if ( !mEventPopup )
00221     mEventPopup = eventPopup();
00222   mEventPopup->showIncidencePopup( calendar(), tlitem->incidence(), TQDate() );
00223 }
00224 
00225 bool KOTimelineView::eventDurationHint(TQDateTime & startDt, TQDateTime & endDt, bool & allDay)
00226 {
00227   startDt = mHintDate;
00228   endDt = mHintDate.addSecs( 2 * 60 * 60 );
00229   allDay = false;
00230   return mHintDate.isValid();
00231 }
00232 
00233 //slot
00234 void KOTimelineView::newEventWithHint( const TQDateTime& dt )
00235 {
00236   mHintDate = dt;
00237   emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, dt );
00238 }
00239 
00240 TimelineItem * KOTimelineView::calendarItemForIncidence(KCal::Incidence * incidence)
00241 {
00242   CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
00243   TimelineItem *item = 0;
00244   if ( !calres ) {
00245     item = mCalendarItemMap[0][TQString()];
00246   } else {
00247     ResourceCalendar *res = calres->resource( incidence );
00248     if ( !res )
00249       return 0;
00250     if ( res->canHaveSubresources() ) {
00251       TQString subRes = res->subresourceIdentifier( incidence );
00252       item = mCalendarItemMap[res][subRes];
00253     } else {
00254       item = mCalendarItemMap[res][TQString()];
00255     }
00256   }
00257   return item;
00258 }
00259 
00260 void KOTimelineView::insertIncidence(KCal::Incidence * incidence, const TQDate &day )
00261 {
00262   TimelineItem *item = calendarItemForIncidence( incidence );
00263   if ( !item ) {
00264     kdWarning() << k_funcinfo << "Help! Something is really wrong here!" << endl;
00265     return;
00266   }
00267 
00268   if ( incidence->doesRecur() ) {
00269     TQValueList<TQDateTime> l = incidence->startDateTimesForDate( day );
00270     if ( l.isEmpty() ) {
00271       // strange, but seems to happen for some recurring events...
00272       item->insertIncidence( incidence, TQDateTime( day, incidence->dtStart().time() ),
00273                               TQDateTime( day, incidence->dtEnd().time() ) );
00274     } else {
00275       for ( TQValueList<TQDateTime>::ConstIterator it = l.constBegin();
00276             it != l.constEnd(); ++it ) {
00277         item->insertIncidence( incidence, *it, incidence->endDateForStart( *it ) );
00278       }
00279     }
00280   } else {
00281     if ( incidence->dtStart().date() == day || incidence->dtStart().date() < mStartDate )
00282       item->insertIncidence( incidence );
00283   }
00284 }
00285 
00286 void KOTimelineView::insertIncidence(KCal::Incidence * incidence)
00287 {
00288   KCal::Event *event = dynamic_cast<KCal::Event*>( incidence );
00289   if ( !event )
00290     return;
00291   if ( incidence->doesRecur() )
00292     insertIncidence( incidence, TQDate() );
00293   for ( TQDate day = mStartDate; day <= mEndDate; day = day.addDays( 1 ) ) {
00294     Event::List events = calendar()->events( day, EventSortStartDate, SortDirectionAscending );
00295     for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) {
00296       if ( events.contains( event ) )
00297         insertIncidence( *it, day );
00298     }
00299   }
00300 }
00301 
00302 void KOTimelineView::removeIncidence(KCal::Incidence * incidence)
00303 {
00304   TimelineItem *item = calendarItemForIncidence( incidence );
00305   if ( item ) {
00306     item->removeIncidence( incidence );
00307   } else {
00308     // try harder, the incidence might already be removed from the resource
00309     typedef TQMap<TQString, KOrg::TimelineItem*> M2_t;
00310     typedef TQMap<KCal::ResourceCalendar*, M2_t> M1_t;
00311     for ( M1_t::ConstIterator it1 = mCalendarItemMap.constBegin(); it1 != mCalendarItemMap.constEnd(); ++it1 ) {
00312       for ( M2_t::ConstIterator it2 = it1.data().constBegin(); it2 != it1.data().constEnd(); ++it2 ) {
00313         if ( it2.data() ) {
00314           it2.data()->removeIncidence( incidence );
00315         }
00316       }
00317     }
00318   }
00319 }
00320 
00321 void KOTimelineView::itemMoved(KDGanttViewItem * item)
00322 {
00323   TimelineSubItem *tlit = dynamic_cast<TimelineSubItem*>( item );
00324   if ( !tlit )
00325     return;
00326   Incidence *i = tlit->incidence();
00327   mChanger->beginChange( i, 0, TQString() );
00328   TQDateTime newStart = tlit->startTime();
00329   if ( i->doesFloat() )
00330     newStart = TQDateTime( newStart.date() );
00331   int delta = tlit->originalStart().secsTo( newStart );
00332   i->setDtStart( i->dtStart().addSecs( delta ) );
00333   int duration = tlit->startTime().secsTo( tlit->endTime() );
00334   int allDayOffset = 0;
00335   if ( i->doesFloat() ) {
00336     duration /= (60*60*24);
00337     duration *= (60*60*24);
00338     allDayOffset = (60*60*24);
00339     duration -= allDayOffset;
00340     if ( duration < 0 ) duration = 0;
00341   }
00342   i->setDuration( duration );
00343   TimelineItem *parent = static_cast<TimelineItem*>( tlit->parent() );
00344   parent->moveItems( i, tlit->originalStart().secsTo( newStart ), duration + allDayOffset );
00345   mChanger->endChange( i, 0, TQString() );
00346 }
00347 
00348 void KOTimelineView::overscale(KDGanttView::Scale scale)
00349 {
00350   Q_UNUSED( scale );
00351   mGantt->setZoomFactor( 1, false );
00352   mGantt->setScale( KDGanttView::Hour );
00353   mGantt->setMinorScaleCount( 12 );
00354 }
00355 
00356 #include "kotimelineview.moc"