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