00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "multiagendaview.h"
00020
00021 #include "koagendaview.h"
00022 #include "koagenda.h"
00023 #include "koprefs.h"
00024 #include "timelabels.h"
00025
00026 #include <libkcal/calendarresources.h>
00027
00028 #include <kglobalsettings.h>
00029
00030 #include <qlayout.h>
00031 #include <qvbox.h>
00032 #include <qobjectlist.h>
00033 #include <qheader.h>
00034
00035 #define FOREACH_VIEW(av) \
00036 for(QValueList<KOAgendaView*>::ConstIterator it = mAgendaViews.constBegin(); \
00037 it != mAgendaViews.constEnd();) \
00038 for(KOAgendaView* av = (it != mAgendaViews.constEnd() ? (*it) : 0); \
00039 it != mAgendaViews.constEnd(); ++it, av = (*it) )
00040
00041 using namespace KOrg;
00042
00043 MultiAgendaView::MultiAgendaView( Calendar * cal, CalendarView *calendarView,
00044 QWidget * parent, const char *name ) :
00045 AgendaView( cal, parent, name ),
00046 mSelectedAgendaView( 0 ),
00047 mLastMovedSplitter( 0 ),
00048 mUpdateOnShow( false ),
00049 mPendingChanges( true ),
00050 mCalendarView( calendarView )
00051 {
00052 QBoxLayout *topLevelLayout = new QHBoxLayout( this );
00053
00054 QFontMetrics fm( font() );
00055 int topLabelHeight = 2 * fm.height() + fm.lineSpacing();
00056
00057 QVBox *topSideBox = new QVBox( this );
00058 mLeftTopSpacer = new QWidget( topSideBox );
00059 mLeftTopSpacer->setFixedHeight( topLabelHeight );
00060 mLeftSplitter = new QSplitter( Qt::Vertical, topSideBox );
00061 mLeftSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
00062 QLabel *label = new QLabel( i18n("All Day"), mLeftSplitter );
00063 label->setAlignment( Qt::AlignRight | Qt::AlignVCenter | Qt::WordBreak );
00064 QVBox *sideBox = new QVBox( mLeftSplitter );
00065 EventIndicator *eiSpacer = new EventIndicator( EventIndicator::Top, sideBox );
00066 eiSpacer->changeColumns( 0 );
00067 mTimeLabels = new TimeLabels( 24, sideBox );
00068 eiSpacer = new EventIndicator( EventIndicator::Bottom, sideBox );
00069 eiSpacer->changeColumns( 0 );
00070 mLeftBottomSpacer = new QWidget( topSideBox );
00071 topLevelLayout->addWidget( topSideBox );
00072
00073 mScrollView = new QScrollView( this );
00074 mScrollView->setResizePolicy( QScrollView::Manual );
00075 mScrollView->setVScrollBarMode( QScrollView::AlwaysOff );
00076 mScrollView->setFrameShape( QFrame::NoFrame );
00077 topLevelLayout->addWidget( mScrollView, 100 );
00078 mTopBox = new QHBox( mScrollView->viewport() );
00079 mScrollView->addChild( mTopBox );
00080
00081 topSideBox = new QVBox( this );
00082 mRightTopSpacer = new QWidget( topSideBox );
00083 mRightTopSpacer->setFixedHeight( topLabelHeight );
00084 mRightSplitter = new QSplitter( Qt::Vertical, topSideBox );
00085 mRightSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
00086 new QWidget( mRightSplitter );
00087 sideBox = new QVBox( mRightSplitter );
00088 eiSpacer = new EventIndicator( EventIndicator::Top, sideBox );
00089 eiSpacer->setFixedHeight( eiSpacer->minimumHeight() );
00090 eiSpacer->changeColumns( 0 );
00091 mScrollBar = new QScrollBar( Qt::Vertical, sideBox );
00092 eiSpacer = new EventIndicator( EventIndicator::Bottom, sideBox );
00093 eiSpacer->setFixedHeight( eiSpacer->minimumHeight() );
00094 eiSpacer->changeColumns( 0 );
00095 mRightBottomSpacer = new QWidget( topSideBox );
00096 topLevelLayout->addWidget( topSideBox );
00097
00098 recreateViews();
00099 }
00100
00101 void MultiAgendaView::recreateViews()
00102 {
00103 if ( !mPendingChanges )
00104 return;
00105 mPendingChanges = false;
00106
00107 deleteViews();
00108
00109 CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
00110 if ( !calres ) {
00111
00112 KOAgendaView* av = new KOAgendaView( calendar(), mCalendarView, mTopBox );
00113 mAgendaViews.append( av );
00114 mAgendaWidgets.append( av );
00115 mSelectedAgendaView = av;
00116 av->show();
00117 } else {
00118 CalendarResourceManager *manager = calres->resourceManager();
00119 for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) {
00120 if ( (*it)->canHaveSubresources() ) {
00121 QStringList subResources = (*it)->subresources();
00122 for ( QStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) {
00123 QString type = (*it)->subresourceType( *subit );
00124 if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") )
00125 continue;
00126 addView( (*it)->labelForSubresource( *subit ), *it, *subit );
00127 }
00128 } else {
00129 addView( (*it)->resourceName(), *it );
00130 }
00131 }
00132 }
00133
00134
00135 if ( mAgendaViews.isEmpty() )
00136 return;
00137
00138 setupViews();
00139 QTimer::singleShot( 0, this, SLOT(slotResizeScrollView()) );
00140 mTimeLabels->updateConfig();
00141
00142 QScrollBar *scrollBar = mAgendaViews.first()->agenda()->verticalScrollBar();
00143 mScrollBar->setMinValue( scrollBar->minValue() );
00144 mScrollBar->setMaxValue( scrollBar->maxValue() );
00145 mScrollBar->setLineStep( scrollBar->lineStep() );
00146 mScrollBar->setPageStep( scrollBar->pageStep() );
00147 mScrollBar->setValue( scrollBar->value() );
00148 connect( mTimeLabels->verticalScrollBar(), SIGNAL(valueChanged(int)),
00149 mScrollBar, SLOT(setValue(int)) );
00150 connect( mScrollBar, SIGNAL(valueChanged(int)),
00151 mTimeLabels, SLOT(positionChanged(int)) );
00152
00153 installSplitterEventFilter( mLeftSplitter );
00154 installSplitterEventFilter( mRightSplitter );
00155
00156 QValueList<int> sizes = KOGlobals::self()->config()->readIntListEntry("Separator AgendaView");
00157 if (sizes.count() != 2) {
00158 sizes = mLeftSplitter->sizes();
00159 }
00160 FOREACH_VIEW( agenda ) {
00161 agenda->splitter()->setSizes( sizes );
00162 }
00163 mLeftSplitter->setSizes( sizes );
00164 mRightSplitter->setSizes( sizes );
00165
00166 mTimeLabels->positionChanged();
00167 }
00168
00169 void MultiAgendaView::deleteViews()
00170 {
00171 for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin();
00172 it != mAgendaWidgets.constEnd(); ++it ) {
00173 delete *it;
00174 }
00175 mAgendaViews.clear();
00176 mAgendaWidgets.clear();
00177 mLastMovedSplitter = 0;
00178 }
00179
00180 void MultiAgendaView::setupViews()
00181 {
00182 FOREACH_VIEW( agenda ) {
00183 if ( !agenda->readOnly() ) {
00184 connect( agenda,
00185 SIGNAL(newEventSignal(ResourceCalendar *,const QString &)),
00186 SIGNAL(newEventSignal(ResourceCalendar *,const QString &)) );
00187 connect( agenda,
00188 SIGNAL(newEventSignal(ResourceCalendar *,const QString &,const QDate &)),
00189 SIGNAL(newEventSignal(ResourceCalendar *,const QString &,const QDate &)) );
00190 connect( agenda,
00191 SIGNAL(newEventSignal(ResourceCalendar *,const QString &,const QDateTime &)),
00192 SIGNAL(newEventSignal(ResourceCalendar *,const QString &,const QDateTime &)) );
00193 connect( agenda,
00194 SIGNAL(newEventSignal(ResourceCalendar *,const QString &,const QDateTime &,const QDateTime &)),
00195 SIGNAL(newEventSignal(ResourceCalendar *,const QString &,const QDateTime &,const QDateTime&)) );
00196
00197 connect( agenda,
00198 SIGNAL(newTodoSignal(ResourceCalendar *,const QString &,const QDate &)),
00199 SIGNAL(newTodoSignal(ResourceCalendar *,const QString &,const QDate &)) );
00200
00201 connect( agenda,
00202 SIGNAL(editIncidenceSignal(Incidence *)),
00203 SIGNAL(editIncidenceSignal(Incidence *)) );
00204 connect( agenda,
00205 SIGNAL(deleteIncidenceSignal(Incidence *)),
00206 SIGNAL(deleteIncidenceSignal(Incidence *)) );
00207 connect( agenda,
00208 SIGNAL(startMultiModify(const QString &)),
00209 SIGNAL(startMultiModify(const QString &)) );
00210 connect( agenda,
00211 SIGNAL(endMultiModify()),
00212 SIGNAL(endMultiModify()) );
00213
00214 connect( agenda,
00215 SIGNAL(cutIncidenceSignal(Incidence*)),
00216 SIGNAL(cutIncidenceSignal(Incidence*)) );
00217 connect( agenda,
00218 SIGNAL(pasteIncidenceSignal()),
00219 SIGNAL(pasteIncidenceSignal()) );
00220 connect( agenda,
00221 SIGNAL(toggleAlarmSignal(Incidence*)),
00222 SIGNAL(toggleAlarmSignal(Incidence*)) );
00223 connect( agenda,
00224 SIGNAL(dissociateOccurrenceSignal(Incidence*, const QDate&)),
00225 SIGNAL(dissociateOccurrenceSignal(Incidence*, const QDate&)) );
00226 connect( agenda,
00227 SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const QDate&)),
00228 SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const QDate&)) );
00229 }
00230
00231 connect( agenda,
00232 SIGNAL(copyIncidenceSignal(Incidence*)),
00233 SIGNAL(copyIncidenceSignal(Incidence*)) );
00234 connect( agenda,
00235 SIGNAL(showIncidenceSignal(Incidence *)),
00236 SIGNAL(showIncidenceSignal(Incidence *)) );
00237 connect( agenda,
00238 SIGNAL(incidenceSelected(Incidence *,const QDate &)),
00239 SIGNAL(incidenceSelected(Incidence *,const QDate &)) );
00240 connect( agenda,
00241 SIGNAL(incidenceSelected(Incidence*,const QDate &)),
00242 SLOT(slotSelectionChanged()) );
00243
00244 connect( agenda,
00245 SIGNAL(timeSpanSelectionChanged()),
00246 SLOT(slotClearTimeSpanSelection()) );
00247
00248 disconnect( agenda->agenda(),
00249 SIGNAL(zoomView(const int,const QPoint&,const Qt::Orientation)),
00250 agenda, 0 );
00251 connect( agenda->agenda(),
00252 SIGNAL(zoomView(const int,const QPoint&,const Qt::Orientation)),
00253 SLOT(zoomView(const int,const QPoint&,const Qt::Orientation)) );
00254 }
00255
00256 KOAgenda *anAgenda = mAgendaViews.first()->agenda();
00257 connect( anAgenda, SIGNAL(lowerYChanged(int) ), SLOT(resizeSpacers(int)) );
00258
00259 FOREACH_VIEW( agenda ) {
00260 agenda->readSettings();
00261 }
00262
00263 int minWidth = 0;
00264 for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin(); it != mAgendaWidgets.constEnd(); ++it )
00265 minWidth = QMAX( minWidth, (*it)->minimumSizeHint().width() );
00266 for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin(); it != mAgendaWidgets.constEnd(); ++it )
00267 (*it)->setMinimumWidth( minWidth );
00268 }
00269
00270 MultiAgendaView::~ MultiAgendaView()
00271 {
00272 }
00273
00274 Incidence::List MultiAgendaView::selectedIncidences()
00275 {
00276 Incidence::List list;
00277 FOREACH_VIEW(agendaView) {
00278 list += agendaView->selectedIncidences();
00279 }
00280 return list;
00281 }
00282
00283 DateList MultiAgendaView::selectedDates()
00284 {
00285 DateList list;
00286 FOREACH_VIEW(agendaView) {
00287 list += agendaView->selectedDates();
00288 }
00289 return list;
00290 }
00291
00292 int MultiAgendaView::currentDateCount()
00293 {
00294 FOREACH_VIEW( agendaView )
00295 return agendaView->currentDateCount();
00296 return 0;
00297 }
00298
00299 void MultiAgendaView::showDates(const QDate & start, const QDate & end)
00300 {
00301 mStartDate = start;
00302 mEndDate = end;
00303 recreateViews();
00304 FOREACH_VIEW( agendaView )
00305 agendaView->showDates( start, end );
00306 }
00307
00308 void MultiAgendaView::showIncidences(const Incidence::List & incidenceList, const QDate &date)
00309 {
00310 FOREACH_VIEW( agendaView )
00311 agendaView->showIncidences( incidenceList, date );
00312 }
00313
00314 void MultiAgendaView::updateView()
00315 {
00316 recreateViews();
00317 FOREACH_VIEW( agendaView )
00318 agendaView->updateView();
00319 }
00320
00321 void MultiAgendaView::changeIncidenceDisplay(Incidence * incidence, int mode)
00322 {
00323 FOREACH_VIEW( agendaView )
00324 agendaView->changeIncidenceDisplay( incidence, mode );
00325 }
00326
00327 int MultiAgendaView::maxDatesHint()
00328 {
00329 FOREACH_VIEW( agendaView )
00330 return agendaView->maxDatesHint();
00331 return 0;
00332 }
00333
00334 void MultiAgendaView::slotSelectionChanged()
00335 {
00336 FOREACH_VIEW( agenda ) {
00337 if ( agenda != sender() )
00338 agenda->clearSelection();
00339 }
00340 }
00341
00342 bool MultiAgendaView::eventDurationHint(QDateTime & startDt, QDateTime & endDt, bool & allDay)
00343 {
00344 FOREACH_VIEW( agenda ) {
00345 bool valid = agenda->eventDurationHint( startDt, endDt, allDay );
00346 if ( valid )
00347 return true;
00348 }
00349 return false;
00350 }
00351
00352 void MultiAgendaView::slotClearTimeSpanSelection()
00353 {
00354 FOREACH_VIEW( agenda ) {
00355 if ( agenda != sender() )
00356 agenda->clearTimeSpanSelection();
00357 }
00358 }
00359
00360 void MultiAgendaView::setTypeAheadReceiver(QObject * o)
00361 {
00362 FOREACH_VIEW( agenda )
00363 agenda->setTypeAheadReceiver( o );
00364 }
00365
00366 void MultiAgendaView::finishTypeAhead()
00367 {
00368 FOREACH_VIEW( agenda )
00369 agenda->finishTypeAhead();
00370 }
00371
00372 void MultiAgendaView::addView( const QString &label, KCal::ResourceCalendar * res, const QString & subRes )
00373 {
00374 bool readOnlyView = false;
00375
00376 QVBox *box = new QVBox( mTopBox );
00377
00378
00379 QHeader *title = new QHeader( 1, box );
00380 title->setClickEnabled( false );
00381 title->setStretchEnabled( true );
00382 if ( res->readOnly() || !res->subresourceWritable( subRes ) ) {
00383 readOnlyView = true;
00384 title->setLabel( 0, QIconSet( KOGlobals::self()->smallIcon( "readonlyevent" ) ), label );
00385 } else {
00386 QColor resColor;
00387 if ( subRes.isEmpty() ) {
00388 resColor = *KOPrefs::instance()->resourceColor( res->identifier() );
00389 } else {
00390 resColor = *KOPrefs::instance()->resourceColor( subRes );
00391 }
00392 QFontMetrics fm = fontMetrics();
00393 QPixmap px( fm.height(), fm.height() );
00394 px.fill( resColor );
00395 title->setLabel( 0, QIconSet( px, QIconSet::Small ), label );
00396 }
00397
00398
00399 KOAgendaView* av = new KOAgendaView( calendar(), mCalendarView, box, 0, true );
00400 mSelectedAgendaView = av;
00401 av->setReadOnly( readOnlyView );
00402 av->setResource( res, subRes );
00403 av->setIncidenceChanger( mChanger );
00404 av->agenda()->setVScrollBarMode( QScrollView::AlwaysOff );
00405 mAgendaViews.append( av );
00406 mAgendaWidgets.append( box );
00407 box->show();
00408 mTimeLabels->setAgenda( av->agenda() );
00409
00410 connect( av->agenda()->verticalScrollBar(), SIGNAL(valueChanged(int)),
00411 mTimeLabels, SLOT(positionChanged(int)) );
00412 connect( mTimeLabels->verticalScrollBar(), SIGNAL(valueChanged(int)),
00413 av, SLOT(setContentsPos(int)) );
00414
00415 av->installEventFilter( this );
00416 installSplitterEventFilter( av->splitter() );
00417 }
00418
00419 void MultiAgendaView::resizeEvent(QResizeEvent * ev)
00420 {
00421 resizeScrollView( ev->size() );
00422 AgendaView::resizeEvent( ev );
00423 }
00424
00425 void MultiAgendaView::resizeScrollView(const QSize & size)
00426 {
00427 const int widgetWidth = size.width() - mTimeLabels->width() - mScrollBar->width();
00428 int width = QMAX( mTopBox->sizeHint().width(), widgetWidth );
00429 int height = size.height();
00430 if ( width > widgetWidth ) {
00431 const int sbHeight = mScrollView->horizontalScrollBar()->height();
00432 height -= sbHeight;
00433 mLeftBottomSpacer->setFixedHeight( sbHeight );
00434 mRightBottomSpacer->setFixedHeight( sbHeight );
00435 } else {
00436 mLeftBottomSpacer->setFixedHeight( 0 );
00437 mRightBottomSpacer->setFixedHeight( 0 );
00438 }
00439 mScrollView->resizeContents( width, height );
00440 mTopBox->resize( width, height );
00441 }
00442
00443 void MultiAgendaView::setIncidenceChanger(IncidenceChangerBase * changer)
00444 {
00445 AgendaView::setIncidenceChanger( changer );
00446 FOREACH_VIEW( agenda )
00447 agenda->setIncidenceChanger( changer );
00448 }
00449
00450 void MultiAgendaView::updateConfig()
00451 {
00452 AgendaView::updateConfig();
00453 mTimeLabels->updateConfig();
00454 FOREACH_VIEW( agenda )
00455 agenda->updateConfig();
00456 }
00457
00458 bool MultiAgendaView::eventFilter(QObject * obj, QEvent * event)
00459 {
00460 if ( obj->className() == QCString("QSplitterHandle") ) {
00461
00462 if ( (event->type() == QEvent::MouseMove && KGlobalSettings::opaqueResize())
00463 || event->type() == QEvent::MouseButtonRelease ) {
00464 FOREACH_VIEW( agenda ) {
00465 if ( agenda->splitter() == obj->parent() )
00466 mLastMovedSplitter = agenda->splitter();
00467 }
00468 if ( mLeftSplitter == obj->parent() )
00469 mLastMovedSplitter = mLeftSplitter;
00470 else if ( mRightSplitter == obj->parent() )
00471 mLastMovedSplitter = mRightSplitter;
00472 QTimer::singleShot( 0, this, SLOT(resizeSplitters()) );
00473 }
00474 }
00475
00476 if ( obj->className() == QCString( "KOAgendaView" ) ) {
00477 if ( event->type() == QEvent::Enter ) {
00478 mSelectedAgendaView = (KOAgendaView *)obj;
00479 }
00480 }
00481
00482 return AgendaView::eventFilter( obj, event );
00483 }
00484
00485 void MultiAgendaView::resizeSplitters()
00486 {
00487 if ( !mLastMovedSplitter )
00488 mLastMovedSplitter = mAgendaViews.first()->splitter();
00489 FOREACH_VIEW( agenda ) {
00490 if ( agenda->splitter() == mLastMovedSplitter )
00491 continue;
00492 agenda->splitter()->setSizes( mLastMovedSplitter->sizes() );
00493 }
00494 if ( mLastMovedSplitter != mLeftSplitter )
00495 mLeftSplitter->setSizes( mLastMovedSplitter->sizes() );
00496 if ( mLastMovedSplitter != mRightSplitter )
00497 mRightSplitter->setSizes( mLastMovedSplitter->sizes() );
00498 }
00499
00500 void MultiAgendaView::resizeSpacers( int newY )
00501 {
00502
00503
00504
00505
00506
00507 Q_UNUSED( newY );
00508 QFontMetrics fm( font() );
00509 int topLabelHeight = mAgendaViews.first()->dayLabels()->height() +
00510 fm.height() + mLeftSplitter->handleWidth();
00511 mLeftTopSpacer->setFixedHeight( topLabelHeight );
00512 mRightTopSpacer->setFixedHeight( topLabelHeight );
00513 }
00514
00515 void MultiAgendaView::zoomView( const int delta, const QPoint & pos, const Qt::Orientation ori )
00516 {
00517 if ( ori == Qt::Vertical ) {
00518 if ( delta > 0 ) {
00519 if ( KOPrefs::instance()->mHourSize > 4 )
00520 KOPrefs::instance()->mHourSize--;
00521 } else {
00522 KOPrefs::instance()->mHourSize++;
00523 }
00524 }
00525
00526 FOREACH_VIEW( agenda )
00527 agenda->zoomView( delta, pos, ori );
00528
00529 mTimeLabels->updateConfig();
00530 mTimeLabels->positionChanged();
00531 mTimeLabels->repaint();
00532 }
00533
00534
00535 void MultiAgendaView::installSplitterEventFilter(QSplitter * splitter)
00536 {
00537 QObjectList *objlist = splitter->queryList( "QSplitterHandle" );
00538
00539
00540 if ( objlist->count() == 0 && !isVisible() )
00541 mUpdateOnShow = true;
00542 QObjectListIt it( *objlist );
00543 QObject *obj;
00544 while ( (obj = it.current()) != 0 ) {
00545 obj->removeEventFilter( this );
00546 obj->installEventFilter( this );
00547 ++it;
00548 }
00549 delete objlist;
00550 }
00551
00552 void MultiAgendaView::slotResizeScrollView()
00553 {
00554 resizeScrollView( size() );
00555 }
00556
00557 void MultiAgendaView::show()
00558 {
00559 AgendaView::show();
00560 if ( mUpdateOnShow ) {
00561 mUpdateOnShow = false;
00562 mPendingChanges = true;
00563 showDates( mStartDate, mEndDate );
00564 }
00565 }
00566
00567 void MultiAgendaView::resourcesChanged()
00568 {
00569 mPendingChanges = true;
00570 FOREACH_VIEW( agenda )
00571 agenda->resourcesChanged();
00572 }
00573
00574 #include "multiagendaview.moc"