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