|
|
|
/*
|
|
|
|
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 TQt, and distribute the resulting executable,
|
|
|
|
without including the source code for TQt in the source distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <libkcal/calendar.h>
|
|
|
|
#include <libkcal/calendarresources.h>
|
|
|
|
|
|
|
|
#include <tqlayout.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, TQWidget *parent,
|
|
|
|
const char *name)
|
|
|
|
: KOEventView(calendar, parent, name),
|
|
|
|
mEventPopup( 0 )
|
|
|
|
{
|
|
|
|
TQVBoxLayout* vbox = new TQVBoxLayout(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 ( TDEGlobal::locale()->use12Clock() )
|
|
|
|
mGantt->setHourFormat( KDGanttView::Hour_12 );
|
|
|
|
else
|
|
|
|
mGantt->setHourFormat( KDGanttView::Hour_24_FourDigit );
|
|
|
|
|
|
|
|
|
|
|
|
vbox->addWidget( mGantt );
|
|
|
|
|
|
|
|
connect( mGantt, TQT_SIGNAL(gvCurrentChanged(KDGanttViewItem*)),
|
|
|
|
TQT_SLOT(itemSelected(KDGanttViewItem*)) );
|
|
|
|
connect( mGantt, TQT_SIGNAL(itemDoubleClicked(KDGanttViewItem*)),
|
|
|
|
TQT_SLOT(itemDoubleClicked(KDGanttViewItem*)) );
|
|
|
|
connect( mGantt, TQT_SIGNAL(itemRightClicked(KDGanttViewItem*)),
|
|
|
|
TQT_SLOT(itemRightClicked(KDGanttViewItem*)) );
|
|
|
|
connect( mGantt, TQT_SIGNAL(gvItemMoved(KDGanttViewItem*)),
|
|
|
|
TQT_SLOT(itemMoved(KDGanttViewItem*)) );
|
|
|
|
connect( mGantt, TQT_SIGNAL(rescaling(KDGanttView::Scale)),
|
|
|
|
TQT_SLOT(overscale(KDGanttView::Scale)) );
|
|
|
|
connect( mGantt, TQT_SIGNAL( dateTimeDoubleClicked( const TQDateTime& ) ),
|
|
|
|
TQT_SLOT( newEventWithHint( const TQDateTime& ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
KOTimelineView::~KOTimelineView()
|
|
|
|
{
|
|
|
|
delete mEventPopup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/
|
|
|
|
KCal::ListBase<KCal::Incidence> KOTimelineView::selectedIncidences()
|
|
|
|
{
|
|
|
|
return KCal::ListBase<KCal::Incidence>();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/
|
|
|
|
KCal::DateList KOTimelineView::selectedIncidenceDates()
|
|
|
|
{
|
|
|
|
return KCal::DateList();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/
|
|
|
|
int KOTimelineView::currentDateCount()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/
|
|
|
|
void KOTimelineView::showDates(const TQDate& start, const TQDate& end)
|
|
|
|
{
|
|
|
|
mStartDate = start;
|
|
|
|
mEndDate = end;
|
|
|
|
mHintDate = TQDateTime();
|
|
|
|
mGantt->setHorizonStart( TQDateTime(start) );
|
|
|
|
mGantt->setHorizonEnd( TQDateTime(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"), calendar(), mGantt );
|
|
|
|
mCalendarItemMap[0][TQString()] = item;
|
|
|
|
} else {
|
|
|
|
CalendarResourceManager *manager = calres->resourceManager();
|
|
|
|
for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) {
|
|
|
|
TQColor resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
|
|
|
|
if ( (*it)->canHaveSubresources() ) {
|
|
|
|
TQStringList subResources = (*it)->subresources();
|
|
|
|
for ( TQStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) {
|
|
|
|
TQString type = (*it)->subresourceType( *subit );
|
|
|
|
if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") )
|
|
|
|
continue;
|
|
|
|
item = new TimelineItem( (*it)->labelForSubresource( *subit ), calendar(), mGantt );
|
|
|
|
resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
|
|
|
|
TQColor 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(), calendar(), mGantt );
|
|
|
|
if ( resourceColor.isValid() )
|
|
|
|
item->setColors( resourceColor, resourceColor, resourceColor );
|
|
|
|
mCalendarItemMap[*it][TQString()] = item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add incidences
|
|
|
|
Event::List events;
|
|
|
|
for ( TQDate 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>&, const TQDate &)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*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(), tlitem->originalStart().date() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KOTimelineView::itemDoubleClicked( KDGanttViewItem *item )
|
|
|
|
{
|
|
|
|
TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
|
|
|
|
if ( tlitem ) {
|
|
|
|
emit editIncidenceSignal( tlitem->incidence(), TQDate() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KOTimelineView::itemRightClicked( KDGanttViewItem *item )
|
|
|
|
{
|
|
|
|
mHintDate = mGantt->getDateTimeForCoordX( TQCursor::pos().x(), true );
|
|
|
|
TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
|
|
|
|
if ( !tlitem ) {
|
|
|
|
showNewEventPopup();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( !mEventPopup )
|
|
|
|
mEventPopup = eventPopup();
|
|
|
|
mEventPopup->showIncidencePopup( calendar(), tlitem->incidence(), TQDate() );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KOTimelineView::eventDurationHint(TQDateTime & startDt, TQDateTime & endDt, bool & allDay)
|
|
|
|
{
|
|
|
|
startDt = mHintDate;
|
|
|
|
endDt = mHintDate.addSecs( 2 * 60 * 60 );
|
|
|
|
allDay = false;
|
|
|
|
return mHintDate.isValid();
|
|
|
|
}
|
|
|
|
|
|
|
|
//slot
|
|
|
|
void KOTimelineView::newEventWithHint( const TQDateTime& dt )
|
|
|
|
{
|
|
|
|
mHintDate = dt;
|
|
|
|
emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, dt );
|
|
|
|
}
|
|
|
|
|
|
|
|
TimelineItem * KOTimelineView::calendarItemForIncidence(KCal::Incidence * incidence)
|
|
|
|
{
|
|
|
|
CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
|
|
|
|
TimelineItem *item = 0;
|
|
|
|
if ( !calres ) {
|
|
|
|
item = mCalendarItemMap[0][TQString()];
|
|
|
|
} else {
|
|
|
|
ResourceCalendar *res = calres->resource( incidence );
|
|
|
|
if ( !res )
|
|
|
|
return 0;
|
|
|
|
if ( res->canHaveSubresources() ) {
|
|
|
|
TQString subRes = res->subresourceIdentifier( incidence );
|
|
|
|
item = mCalendarItemMap[res][subRes];
|
|
|
|
} else {
|
|
|
|
item = mCalendarItemMap[res][TQString()];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KOTimelineView::insertIncidence(KCal::Incidence * incidence, const TQDate &day )
|
|
|
|
{
|
|
|
|
TimelineItem *item = calendarItemForIncidence( incidence );
|
|
|
|
if ( !item ) {
|
|
|
|
kdWarning() << k_funcinfo << "Help! Something is really wrong here!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( incidence->doesRecur() ) {
|
|
|
|
TQValueList<TQDateTime> l = incidence->startDateTimesForDate( day );
|
|
|
|
if ( l.isEmpty() ) {
|
|
|
|
// strange, but seems to happen for some recurring events...
|
|
|
|
item->insertIncidence( incidence, TQDateTime( day, incidence->dtStart().time() ),
|
|
|
|
TQDateTime( day, incidence->dtEnd().time() ) );
|
|
|
|
} else {
|
|
|
|
for ( TQValueList<TQDateTime>::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, TQDate() );
|
|
|
|
for ( TQDate 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 TQMap<TQString, KOrg::TimelineItem*> M2_t;
|
|
|
|
typedef TQMap<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, 0, TQString() );
|
|
|
|
TQDateTime newStart = tlit->startTime();
|
|
|
|
if ( i->doesFloat() )
|
|
|
|
newStart = TQDateTime( 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, 0, TQString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KOTimelineView::overscale(KDGanttView::Scale scale)
|
|
|
|
{
|
|
|
|
Q_UNUSED( scale );
|
|
|
|
mGantt->setZoomFactor( 1, false );
|
|
|
|
mGantt->setScale( KDGanttView::Hour );
|
|
|
|
mGantt->setMinorScaleCount( 12 );
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "kotimelineview.moc"
|