korganizer

kotimelineview.cpp
1 /*
2  This file is part of KOrganizer.
3 
4  Copyright (c) 2007 Till Adam <adam@kde.org>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20  As a special exception, permission is given to link this program
21  with any edition of TQt, and distribute the resulting executable,
22  without including the source code for TQt in the source distribution.
23 */
24 
25 
26 #include <libkcal/calendar.h>
28 
29 #include <tqlayout.h>
30 
31 #include <kdgantt/KDGanttViewTaskItem.h>
32 #include <kdgantt/KDGanttViewSubwidgets.h>
33 
34 #include "koeventpopupmenu.h"
35 #include "koglobals.h"
36 #include "koprefs.h"
37 #include "timelineitem.h"
38 
39 #include "kotimelineview.h"
40 
41 using namespace KOrg;
42 using namespace KCal;
43 
44 KOTimelineView::KOTimelineView(Calendar *calendar, TQWidget *parent,
45  const char *name)
46  : KOEventView(calendar, parent, name),
47  mEventPopup( 0 )
48 {
49  TQVBoxLayout* vbox = new TQVBoxLayout(this);
50  mGantt = new KDGanttView(this);
51  mGantt->setCalendarMode( true );
52  mGantt->setShowLegendButton( false );
53  mGantt->setFixedHorizon( true );
54  mGantt->removeColumn( 0 );
55  mGantt->addColumn( i18n("Calendar") );
56  mGantt->setHeaderVisible( true );
57  if ( TDEGlobal::locale()->use12Clock() )
58  mGantt->setHourFormat( KDGanttView::Hour_12 );
59  else
60  mGantt->setHourFormat( KDGanttView::Hour_24_FourDigit );
61 
62 
63  vbox->addWidget( mGantt );
64 
65  connect( mGantt, TQ_SIGNAL(gvCurrentChanged(KDGanttViewItem*)),
66  TQ_SLOT(itemSelected(KDGanttViewItem*)) );
67  connect( mGantt, TQ_SIGNAL(itemDoubleClicked(KDGanttViewItem*)),
68  TQ_SLOT(itemDoubleClicked(KDGanttViewItem*)) );
69  connect( mGantt, TQ_SIGNAL(itemRightClicked(KDGanttViewItem*)),
70  TQ_SLOT(itemRightClicked(KDGanttViewItem*)) );
71  connect( mGantt, TQ_SIGNAL(gvItemMoved(KDGanttViewItem*)),
72  TQ_SLOT(itemMoved(KDGanttViewItem*)) );
73  connect( mGantt, TQ_SIGNAL(rescaling(KDGanttView::Scale)),
74  TQ_SLOT(overscale(KDGanttView::Scale)) );
75  connect( mGantt, TQ_SIGNAL( dateTimeDoubleClicked( const TQDateTime& ) ),
76  TQ_SLOT( newEventWithHint( const TQDateTime& ) ) );
77 }
78 
79 KOTimelineView::~KOTimelineView()
80 {
81  delete mEventPopup;
82 }
83 
84 /*virtual*/
86 {
88 }
89 
90 /*virtual*/
92 {
93  return KCal::DateList();
94 }
95 
96 /*virtual*/
98 {
99  return 0;
100 }
101 
102 /*virtual*/
103 void KOTimelineView::showDates(const TQDate& start, const TQDate& end)
104 {
105  mStartDate = start;
106  mEndDate = end;
107  mHintDate = TQDateTime();
108  mGantt->setHorizonStart( TQDateTime(start) );
109  mGantt->setHorizonEnd( TQDateTime(end.addDays(1)) );
110  mGantt->setMinorScaleCount( 1 );
111  mGantt->setScale( KDGanttView::Hour );
112  mGantt->setMinimumScale( KDGanttView::Hour );
113  mGantt->setMaximumScale( KDGanttView::Hour );
114  mGantt->zoomToFit();
115 
116  mGantt->setUpdateEnabled( false );
117  mGantt->clear();
118 
119  // item for every calendar
120  TimelineItem *item = 0;
121  CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
122  if ( !calres ) {
123  item = new TimelineItem( i18n("Calendar"), calendar(), mGantt );
124  mCalendarItemMap[0][TQString()] = item;
125  } else {
126  CalendarResourceManager *manager = calres->resourceManager();
127  for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) {
128  TQColor resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
129  if ( (*it)->canHaveSubresources() ) {
130  TQStringList subResources = (*it)->subresources();
131  for ( TQStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) {
132  TQString type = (*it)->subresourceType( *subit );
133  if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") )
134  continue;
135  item = new TimelineItem( (*it)->labelForSubresource( *subit ), calendar(), mGantt );
136  resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
137  TQColor subrescol = *KOPrefs::instance()->resourceColor( *subit );
138  if ( subrescol.isValid() )
139  resourceColor = subrescol;
140  if ( resourceColor.isValid() )
141  item->setColors( resourceColor, resourceColor, resourceColor );
142  mCalendarItemMap[*it][*subit] = item;
143  }
144  } else {
145  item = new TimelineItem( (*it)->resourceName(), calendar(), mGantt );
146  if ( resourceColor.isValid() )
147  item->setColors( resourceColor, resourceColor, resourceColor );
148  mCalendarItemMap[*it][TQString()] = item;
149  }
150  }
151  }
152 
153  // add incidences
154  Event::List events;
155  for ( TQDate day = start; day <= end; day = day.addDays( 1 ) ) {
157  for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) {
158  insertIncidence( *it, day );
159  }
160  }
161 
162  mGantt->setUpdateEnabled( true );
163 }
164 
165 /*virtual*/
166 void KOTimelineView::showIncidences(const KCal::ListBase<KCal::Incidence>&, const TQDate &)
167 {
168 }
169 
170 /*virtual*/
172 {
173  if ( mStartDate.isValid() && mEndDate.isValid() )
174  showDates( mStartDate, mEndDate );
175 }
176 
177 /*virtual*/
179 {
180  kdDebug() << k_funcinfo << incidence << " " << mode << endl;
181  switch ( mode ) {
182  case KOGlobals::INCIDENCEADDED:
183  insertIncidence( incidence );
184  break;
185  case KOGlobals::INCIDENCEEDITED:
186  removeIncidence( incidence );
187  insertIncidence( incidence );
188  break;
189  case KOGlobals::INCIDENCEDELETED:
190  removeIncidence( incidence );
191  break;
192  default:
193  updateView();
194  }
195 }
196 
197 void KOTimelineView::itemSelected( KDGanttViewItem *item )
198 {
199  TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
200  if ( tlitem )
201  emit incidenceSelected( tlitem->incidence(), tlitem->originalStart().date() );
202 }
203 
204 void KOTimelineView::itemDoubleClicked( KDGanttViewItem *item )
205 {
206  TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
207  if ( tlitem ) {
208  emit editIncidenceSignal( tlitem->incidence(), TQDate() );
209  }
210 }
211 
212 void KOTimelineView::itemRightClicked( KDGanttViewItem *item )
213 {
214  mHintDate = mGantt->getDateTimeForCoordX( TQCursor::pos().x(), true );
215  TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
216  if ( !tlitem ) {
217  showNewEventPopup();
218  return;
219  }
220  if ( !mEventPopup )
221  mEventPopup = eventPopup();
222  mEventPopup->showIncidencePopup( calendar(), tlitem->incidence(), TQDate() );
223 }
224 
225 bool KOTimelineView::eventDurationHint(TQDateTime & startDt, TQDateTime & endDt, bool & allDay)
226 {
227  startDt = mHintDate;
228  endDt = mHintDate.addSecs( 2 * 60 * 60 );
229  allDay = false;
230  return mHintDate.isValid();
231 }
232 
233 //slot
234 void KOTimelineView::newEventWithHint( const TQDateTime& dt )
235 {
236  mHintDate = dt;
237  emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, dt );
238 }
239 
240 TimelineItem * KOTimelineView::calendarItemForIncidence(KCal::Incidence * incidence)
241 {
242  CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
243  TimelineItem *item = 0;
244  if ( !calres ) {
245  item = mCalendarItemMap[0][TQString()];
246  } else {
247  ResourceCalendar *res = calres->resource( incidence );
248  if ( !res )
249  return 0;
250  if ( res->canHaveSubresources() ) {
251  TQString subRes = res->subresourceIdentifier( incidence );
252  item = mCalendarItemMap[res][subRes];
253  } else {
254  item = mCalendarItemMap[res][TQString()];
255  }
256  }
257  return item;
258 }
259 
260 void KOTimelineView::insertIncidence(KCal::Incidence * incidence, const TQDate &day )
261 {
262  TimelineItem *item = calendarItemForIncidence( incidence );
263  if ( !item ) {
264  kdWarning() << k_funcinfo << "Help! Something is really wrong here!" << endl;
265  return;
266  }
267 
268  if ( incidence->doesRecur() ) {
269  TQValueList<TQDateTime> l = incidence->startDateTimesForDate( day );
270  if ( l.isEmpty() ) {
271  // strange, but seems to happen for some recurring events...
272  item->insertIncidence( incidence, TQDateTime( day, incidence->dtStart().time() ),
273  TQDateTime( day, incidence->dtEnd().time() ) );
274  } else {
275  for ( TQValueList<TQDateTime>::ConstIterator it = l.constBegin();
276  it != l.constEnd(); ++it ) {
277  item->insertIncidence( incidence, *it, incidence->endDateForStart( *it ) );
278  }
279  }
280  } else {
281  if ( incidence->dtStart().date() == day || incidence->dtStart().date() < mStartDate )
282  item->insertIncidence( incidence );
283  }
284 }
285 
286 void KOTimelineView::insertIncidence(KCal::Incidence * incidence)
287 {
288  KCal::Event *event = dynamic_cast<KCal::Event*>( incidence );
289  if ( !event )
290  return;
291  if ( incidence->doesRecur() )
292  insertIncidence( incidence, TQDate() );
293  for ( TQDate day = mStartDate; day <= mEndDate; day = day.addDays( 1 ) ) {
294  Event::List events = calendar()->events( day, EventSortStartDate, SortDirectionAscending );
295  for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) {
296  if ( events.contains( event ) )
297  insertIncidence( *it, day );
298  }
299  }
300 }
301 
302 void KOTimelineView::removeIncidence(KCal::Incidence * incidence)
303 {
304  TimelineItem *item = calendarItemForIncidence( incidence );
305  if ( item ) {
306  item->removeIncidence( incidence );
307  } else {
308  // try harder, the incidence might already be removed from the resource
309  typedef TQMap<TQString, KOrg::TimelineItem*> M2_t;
310  typedef TQMap<KCal::ResourceCalendar*, M2_t> M1_t;
311  for ( M1_t::ConstIterator it1 = mCalendarItemMap.constBegin(); it1 != mCalendarItemMap.constEnd(); ++it1 ) {
312  for ( M2_t::ConstIterator it2 = it1.data().constBegin(); it2 != it1.data().constEnd(); ++it2 ) {
313  if ( it2.data() ) {
314  it2.data()->removeIncidence( incidence );
315  }
316  }
317  }
318  }
319 }
320 
321 void KOTimelineView::itemMoved(KDGanttViewItem * item)
322 {
323  TimelineSubItem *tlit = dynamic_cast<TimelineSubItem*>( item );
324  if ( !tlit )
325  return;
326  Incidence *i = tlit->incidence();
327  mChanger->beginChange( i, 0, TQString() );
328  TQDateTime newStart = tlit->startTime();
329  if ( i->doesFloat() )
330  newStart = TQDateTime( newStart.date() );
331  int delta = tlit->originalStart().secsTo( newStart );
332  i->setDtStart( i->dtStart().addSecs( delta ) );
333  int duration = tlit->startTime().secsTo( tlit->endTime() );
334  int allDayOffset = 0;
335  if ( i->doesFloat() ) {
336  duration /= (60*60*24);
337  duration *= (60*60*24);
338  allDayOffset = (60*60*24);
339  duration -= allDayOffset;
340  if ( duration < 0 ) duration = 0;
341  }
342  i->setDuration( duration );
343  TimelineItem *parent = static_cast<TimelineItem*>( tlit->parent() );
344  parent->moveItems( i, tlit->originalStart().secsTo( newStart ), duration + allDayOffset );
345  mChanger->endChange( i, 0, TQString() );
346 }
347 
348 void KOTimelineView::overscale(KDGanttView::Scale scale)
349 {
350  Q_UNUSED( scale );
351  mGantt->setZoomFactor( 1, false );
352  mGantt->setScale( KDGanttView::Hour );
353  mGantt->setMinorScaleCount( 12 );
354 }
355 
356 #include "kotimelineview.moc"
ResourceCalendar * resource(Incidence *incidence)
CalendarResourceManager * resourceManager() const
virtual Event::List events(EventSortField sortField=EventSortUnsorted, SortDirection sortDirection=SortDirectionAscending)
Incidence * incidence(const TQString &uid)
bool doesFloat() const
virtual TQDateTime dtStart() const
virtual TQDateTime dtEnd() const
bool doesRecur() const
virtual void setDtStart(const TQDateTime &dtStart)
virtual TQValueList< TQDateTime > startDateTimesForDate(const TQDate &date) const
virtual TQDateTime endDateForStart(const TQDateTime &startDt) const
virtual TQString subresourceIdentifier(Incidence *incidence)
virtual bool canHaveSubresources() const
KOEventView is the abstract base class from which all other calendar views for event data are derived...
Definition: koeventview.h:56
KOEventPopupMenu * eventPopup()
Construct a standard context menu for an event.
Definition: koeventview.cpp:60
virtual void showDates(const TQDate &, const TQDate &)
Show incidences for the given date range.
virtual KCal::ListBase< KCal::Incidence > selectedIncidences()
virtual bool eventDurationHint(TQDateTime &startDt, TQDateTime &endDt, bool &allDay)
Set the default start/end date/time for new events.
virtual void updateView()
Updates the current display to reflect changes that may have happened in the calendar since the last ...
virtual KCal::DateList selectedIncidenceDates()
virtual int currentDateCount()
Return number of currently shown dates.
virtual void changeIncidenceDisplay(KCal::Incidence *incidence, int mode)
Updates the current display to reflect the changes to one particular incidence.
void editIncidenceSignal(Incidence *, const TQDate &)
instructs the receiver to begin editing the incidence specified in some manner.
void newEventSignal(ResourceCalendar *res, const TQString &subResource)
instructs the receiver to create a new event.
virtual Calendar * calendar()
Return calendar object of this view.
Definition: baseview.h:89
EventSortStartDate
SortDirectionAscending