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 TQt, and distribute the resulting executable, 00022 without including the source code for TQt 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"