korganizer

multiagendaview.cpp

00001 /*
00002     Copyright (c) 2007 Volker Krause <vkrause@kde.org>
00003 
00004     This program is free software; you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or
00007     (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software
00016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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 
00034 #define FOREACH_VIEW(av) \
00035 for(QValueList<KOAgendaView*>::ConstIterator it = mAgendaViews.constBegin(); \
00036   it != mAgendaViews.constEnd();) \
00037   for(KOAgendaView* av = (it != mAgendaViews.constEnd() ? (*it) : 0); \
00038       it != mAgendaViews.constEnd(); ++it, av = (*it)  )
00039 
00040 using namespace KOrg;
00041 
00042 MultiAgendaView::MultiAgendaView(Calendar * cal, QWidget * parent, const char *name ) :
00043     AgendaView( cal, parent, name ),
00044     mLastMovedSplitter( 0 ),
00045     mUpdateOnShow( false )
00046 {
00047   QBoxLayout *topLevelLayout = new QHBoxLayout( this );
00048 
00049   QFontMetrics fm( font() );
00050   int topLabelHeight = 2 * fm.height();
00051 
00052   QVBox *topSideBox = new QVBox( this );
00053   QWidget *topSideSpacer = new QWidget( topSideBox );
00054   topSideSpacer->setFixedHeight( topLabelHeight );
00055   mLeftSplitter = new QSplitter( Qt::Vertical, topSideBox );
00056   mLeftSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
00057   QLabel *label = new QLabel( i18n("All Day"), mLeftSplitter );
00058   label->setAlignment( Qt::AlignRight | Qt::AlignVCenter | Qt::WordBreak );
00059   QVBox *sideBox = new QVBox( mLeftSplitter );
00060   EventIndicator *eiSpacer = new EventIndicator( EventIndicator::Top, sideBox );
00061   eiSpacer->changeColumns( 0 );
00062   mTimeLabels = new TimeLabels( 24, sideBox );
00063   eiSpacer = new EventIndicator( EventIndicator::Bottom, sideBox );
00064   eiSpacer->changeColumns( 0 );
00065   mLeftBottomSpacer = new QWidget( topSideBox );
00066   topLevelLayout->addWidget( topSideBox );
00067 
00068   mScrollView = new QScrollView( this );
00069   mScrollView->setResizePolicy( QScrollView::Manual );
00070   mScrollView->setVScrollBarMode( QScrollView::AlwaysOff );
00071   mScrollView->setFrameShape( QFrame::NoFrame );
00072   topLevelLayout->addWidget( mScrollView, 100 );
00073   mTopBox = new QHBox( mScrollView->viewport() );
00074   mScrollView->addChild( mTopBox );
00075 
00076   topSideBox = new QVBox( this );
00077   topSideSpacer = new QWidget( topSideBox );
00078   topSideSpacer->setFixedHeight( topLabelHeight );
00079   mRightSplitter = new QSplitter( Qt::Vertical, topSideBox );
00080   mRightSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
00081   new QWidget( mRightSplitter );
00082   sideBox = new QVBox( mRightSplitter );
00083   eiSpacer = new EventIndicator( EventIndicator::Top, sideBox );
00084   eiSpacer->setFixedHeight( eiSpacer->minimumHeight() );
00085   eiSpacer->changeColumns( 0 );
00086   mScrollBar = new QScrollBar( Qt::Vertical, sideBox );
00087   eiSpacer = new EventIndicator( EventIndicator::Bottom, sideBox );
00088   eiSpacer->setFixedHeight( eiSpacer->minimumHeight() );
00089   eiSpacer->changeColumns( 0 );
00090   mRightBottomSpacer = new QWidget( topSideBox );
00091   topLevelLayout->addWidget( topSideBox );
00092 
00093   recreateViews();
00094 }
00095 
00096 void MultiAgendaView::recreateViews()
00097 {
00098   deleteViews();
00099 
00100   CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
00101   if ( !calres ) {
00102     // fallback to single-agenda
00103     KOAgendaView* av = new KOAgendaView( calendar(), mTopBox );
00104     mAgendaViews.append( av );
00105     mAgendaWidgets.append( av );
00106     av->show();
00107   } else {
00108     CalendarResourceManager *manager = calres->resourceManager();
00109     for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) {
00110       if ( (*it)->canHaveSubresources() ) {
00111         QStringList subResources = (*it)->subresources();
00112         for ( QStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) {
00113           QString type = (*it)->subresourceType( *subit );
00114           if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") )
00115             continue;
00116           addView( (*it)->labelForSubresource( *subit ), *it, *subit );
00117         }
00118       } else {
00119         addView( (*it)->resourceName(), *it );
00120       }
00121     }
00122   }
00123 
00124   // no resources activated, so stop here to avoid crashing somewhere down the line, TODO: show a nice message instead
00125   if ( mAgendaViews.isEmpty() )
00126     return;
00127 
00128   setupViews();
00129   QTimer::singleShot( 0, this, SLOT(slotResizeScrollView()) );
00130   mTimeLabels->updateConfig();
00131 
00132   QScrollBar *scrollBar = mAgendaViews.first()->agenda()->verticalScrollBar();
00133   mScrollBar->setMinValue( scrollBar->minValue() );
00134   mScrollBar->setMaxValue( scrollBar->maxValue() );
00135   mScrollBar->setLineStep( scrollBar->lineStep() );
00136   mScrollBar->setPageStep( scrollBar->pageStep() );
00137   mScrollBar->setValue( scrollBar->value() );
00138   connect( mTimeLabels->verticalScrollBar(), SIGNAL(valueChanged(int)),
00139            mScrollBar, SLOT(setValue(int)) );
00140   connect( mScrollBar, SIGNAL(valueChanged(int)),
00141            mTimeLabels, SLOT(positionChanged(int)) );
00142 
00143   installSplitterEventFilter( mLeftSplitter );
00144   installSplitterEventFilter( mRightSplitter );
00145   resizeSplitters();
00146 }
00147 
00148 void MultiAgendaView::deleteViews()
00149 {
00150   for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin();
00151         it != mAgendaWidgets.constEnd(); ++it ) {
00152     delete *it;
00153   }
00154   mAgendaViews.clear();
00155   mAgendaWidgets.clear();
00156   mLastMovedSplitter = 0;
00157 }
00158 
00159 void MultiAgendaView::setupViews()
00160 {
00161   FOREACH_VIEW( agenda ) {
00162     connect( agenda, SIGNAL( newEventSignal() ),
00163              SIGNAL( newEventSignal() ) );
00164     connect( agenda, SIGNAL( editIncidenceSignal( Incidence * ) ),
00165              SIGNAL( editIncidenceSignal( Incidence * ) ) );
00166     connect( agenda, SIGNAL( showIncidenceSignal( Incidence * ) ),
00167              SIGNAL( showIncidenceSignal( Incidence * ) ) );
00168     connect( agenda, SIGNAL( deleteIncidenceSignal( Incidence * ) ),
00169              SIGNAL( deleteIncidenceSignal( Incidence * ) ) );
00170     connect( agenda, SIGNAL( startMultiModify( const QString & ) ),
00171              SIGNAL( startMultiModify( const QString & ) ) );
00172     connect( agenda, SIGNAL( endMultiModify() ),
00173              SIGNAL( endMultiModify() ) );
00174 
00175     connect( agenda, SIGNAL( incidenceSelected( Incidence * ) ),
00176              SIGNAL( incidenceSelected( Incidence * ) ) );
00177 
00178     connect( agenda, SIGNAL(cutIncidenceSignal(Incidence*)),
00179              SIGNAL(cutIncidenceSignal(Incidence*)) );
00180     connect( agenda, SIGNAL(copyIncidenceSignal(Incidence*)),
00181              SIGNAL(copyIncidenceSignal(Incidence*)) );
00182     connect( agenda, SIGNAL(pasteIncidenceSignal()),
00183              SIGNAL(pasteIncidenceSignal()) );
00184     connect( agenda, SIGNAL(toggleAlarmSignal(Incidence*)),
00185              SIGNAL(toggleAlarmSignal(Incidence*)) );
00186     connect( agenda, SIGNAL(dissociateOccurrenceSignal(Incidence*, const QDate&)),
00187              SIGNAL(dissociateOccurrenceSignal(Incidence*, const QDate&)) );
00188     connect( agenda, SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const QDate&)),
00189              SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const QDate&)) );
00190 
00191     connect( agenda, SIGNAL(newEventSignal(const QDate&)),
00192              SIGNAL(newEventSignal(const QDate&)) );
00193     connect( agenda, SIGNAL(newEventSignal(const QDateTime&)),
00194              SIGNAL(newEventSignal(const QDateTime&)) );
00195     connect( agenda, SIGNAL(newEventSignal(const QDateTime&, const QDateTime&)),
00196              SIGNAL(newEventSignal(const QDateTime&, const QDateTime&)) );
00197     connect( agenda, SIGNAL(newTodoSignal(const QDate&)),
00198              SIGNAL(newTodoSignal(const QDate&)) );
00199 
00200     connect( agenda, SIGNAL(incidenceSelected(Incidence*)),
00201              SLOT(slotSelectionChanged()) );
00202 
00203     connect( agenda, SIGNAL(timeSpanSelectionChanged()),
00204              SLOT(slotClearTimeSpanSelection()) );
00205 
00206     disconnect( agenda->agenda(), SIGNAL(zoomView(const int,const QPoint&,const Qt::Orientation)), agenda, 0 );
00207     connect( agenda->agenda(), SIGNAL(zoomView(const int,const QPoint&,const Qt::Orientation)),
00208              SLOT(zoomView(const int,const QPoint&,const Qt::Orientation)) );
00209   }
00210 
00211   FOREACH_VIEW( agenda ) {
00212     agenda->readSettings();
00213   }
00214 
00215   int minWidth = 0;
00216   for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin(); it != mAgendaWidgets.constEnd(); ++it )
00217     minWidth = QMAX( minWidth, (*it)->minimumSizeHint().width() );
00218   for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin(); it != mAgendaWidgets.constEnd(); ++it )
00219     (*it)->setMinimumWidth( minWidth );
00220 }
00221 
00222 MultiAgendaView::~ MultiAgendaView()
00223 {
00224 }
00225 
00226 Incidence::List MultiAgendaView::selectedIncidences()
00227 {
00228   Incidence::List list;
00229   FOREACH_VIEW(agendaView) {
00230     list += agendaView->selectedIncidences();
00231   }
00232   return list;
00233 }
00234 
00235 DateList MultiAgendaView::selectedDates()
00236 {
00237   DateList list;
00238   FOREACH_VIEW(agendaView) {
00239     list += agendaView->selectedDates();
00240   }
00241   return list;
00242 }
00243 
00244 int MultiAgendaView::currentDateCount()
00245 {
00246   FOREACH_VIEW( agendaView )
00247     return agendaView->currentDateCount();
00248   return 0;
00249 }
00250 
00251 void MultiAgendaView::showDates(const QDate & start, const QDate & end)
00252 {
00253   mStartDate = start;
00254   mEndDate = end;
00255   recreateViews();
00256   FOREACH_VIEW( agendaView )
00257     agendaView->showDates( start, end );
00258 }
00259 
00260 void MultiAgendaView::showIncidences(const Incidence::List & incidenceList)
00261 {
00262   FOREACH_VIEW( agendaView )
00263     agendaView->showIncidences( incidenceList );
00264 }
00265 
00266 void MultiAgendaView::updateView()
00267 {
00268   recreateViews();
00269   FOREACH_VIEW( agendaView )
00270     agendaView->updateView();
00271 }
00272 
00273 void MultiAgendaView::changeIncidenceDisplay(Incidence * incidence, int mode)
00274 {
00275   FOREACH_VIEW( agendaView )
00276     agendaView->changeIncidenceDisplay( incidence, mode );
00277 }
00278 
00279 int MultiAgendaView::maxDatesHint()
00280 {
00281   FOREACH_VIEW( agendaView )
00282     return agendaView->maxDatesHint();
00283   return 0;
00284 }
00285 
00286 void MultiAgendaView::slotSelectionChanged()
00287 {
00288   FOREACH_VIEW( agenda ) {
00289     if ( agenda != sender() )
00290       agenda->clearSelection();
00291   }
00292 }
00293 
00294 bool MultiAgendaView::eventDurationHint(QDateTime & startDt, QDateTime & endDt, bool & allDay)
00295 {
00296   FOREACH_VIEW( agenda ) {
00297     bool valid = agenda->eventDurationHint( startDt, endDt, allDay );
00298     if ( valid )
00299       return true;
00300   }
00301   return false;
00302 }
00303 
00304 void MultiAgendaView::slotClearTimeSpanSelection()
00305 {
00306   FOREACH_VIEW( agenda ) {
00307     if ( agenda != sender() )
00308       agenda->clearTimeSpanSelection();
00309   }
00310 }
00311 
00312 void MultiAgendaView::setTypeAheadReceiver(QObject * o)
00313 {
00314   FOREACH_VIEW( agenda )
00315     agenda->setTypeAheadReceiver( o );
00316 }
00317 
00318 void MultiAgendaView::finishTypeAhead()
00319 {
00320   FOREACH_VIEW( agenda )
00321     agenda->finishTypeAhead();
00322 }
00323 
00324 void MultiAgendaView::addView( const QString &label, KCal::ResourceCalendar * res, const QString & subRes )
00325 {
00326   QVBox *box = new QVBox( mTopBox );
00327   QLabel *l = new QLabel( label, box );
00328   l->setAlignment( AlignVCenter | AlignHCenter );
00329   KOAgendaView* av = new KOAgendaView( calendar(), box, 0, true );
00330   av->setResource( res, subRes );
00331   av->setIncidenceChanger( mChanger );
00332   av->agenda()->setVScrollBarMode( QScrollView::AlwaysOff );
00333   mAgendaViews.append( av );
00334   mAgendaWidgets.append( box );
00335   box->show();
00336   mTimeLabels->setAgenda( av->agenda() );
00337 
00338   connect( av->agenda()->verticalScrollBar(), SIGNAL(valueChanged(int)),
00339            mTimeLabels, SLOT(positionChanged(int)) );
00340   connect( mTimeLabels->verticalScrollBar(), SIGNAL(valueChanged(int)),
00341            av, SLOT(setContentsPos(int)) );
00342 
00343   installSplitterEventFilter( av->splitter() );
00344 }
00345 
00346 void MultiAgendaView::resizeEvent(QResizeEvent * ev)
00347 {
00348   resizeScrollView( ev->size() );
00349   AgendaView::resizeEvent( ev );
00350 }
00351 
00352 void MultiAgendaView::resizeScrollView(const QSize & size)
00353 {
00354   const int widgetWidth = size.width() - mTimeLabels->width() - mScrollBar->width();
00355   int width = QMAX( mTopBox->sizeHint().width(), widgetWidth );
00356   int height = size.height();
00357   if ( width > widgetWidth ) {
00358     const int sbHeight = mScrollView->horizontalScrollBar()->height();
00359     height -= sbHeight;
00360     mLeftBottomSpacer->setFixedHeight( sbHeight );
00361     mRightBottomSpacer->setFixedHeight( sbHeight );
00362   } else {
00363     mLeftBottomSpacer->setFixedHeight( 0 );
00364     mRightBottomSpacer->setFixedHeight( 0 );
00365   }
00366   mScrollView->resizeContents( width, height );
00367   mTopBox->resize( width, height );
00368 }
00369 
00370 void MultiAgendaView::setIncidenceChanger(IncidenceChangerBase * changer)
00371 {
00372   AgendaView::setIncidenceChanger( changer );
00373   FOREACH_VIEW( agenda )
00374     agenda->setIncidenceChanger( changer );
00375 }
00376 
00377 void MultiAgendaView::updateConfig()
00378 {
00379   AgendaView::updateConfig();
00380   mTimeLabels->updateConfig();
00381   FOREACH_VIEW( agenda )
00382     agenda->updateConfig();
00383 }
00384 
00385 // KDE4: not needed anymore, QSplitter has a moved signal there
00386 bool MultiAgendaView::eventFilter(QObject * obj, QEvent * event)
00387 {
00388   if ( obj->className() == QCString("QSplitterHandle") ) {
00389     if ( (event->type() == QEvent::MouseMove && KGlobalSettings::opaqueResize())
00390            || event->type() == QEvent::MouseButtonRelease ) {
00391       FOREACH_VIEW( agenda ) {
00392         if ( agenda->splitter() == obj->parent() )
00393           mLastMovedSplitter = agenda->splitter();
00394       }
00395       if ( mLeftSplitter == obj->parent() )
00396         mLastMovedSplitter = mLeftSplitter;
00397       else if ( mRightSplitter == obj->parent() )
00398         mLastMovedSplitter = mRightSplitter;
00399       QTimer::singleShot( 0, this, SLOT(resizeSplitters()) );
00400     }
00401   }
00402   return AgendaView::eventFilter( obj, event );
00403 }
00404 
00405 void MultiAgendaView::resizeSplitters()
00406 {
00407   if ( !mLastMovedSplitter )
00408     mLastMovedSplitter = mAgendaViews.first()->splitter();
00409   FOREACH_VIEW( agenda ) {
00410     if ( agenda->splitter() == mLastMovedSplitter )
00411       continue;
00412     agenda->splitter()->setSizes( mLastMovedSplitter->sizes() );
00413   }
00414   if ( mLastMovedSplitter != mLeftSplitter )
00415     mLeftSplitter->setSizes( mLastMovedSplitter->sizes() );
00416   if ( mLastMovedSplitter != mRightSplitter )
00417     mRightSplitter->setSizes( mLastMovedSplitter->sizes() );
00418 }
00419 
00420 void MultiAgendaView::zoomView( const int delta, const QPoint & pos, const Qt::Orientation ori )
00421 {
00422   if ( ori == Qt::Vertical ) {
00423     if ( delta > 0 ) {
00424       if ( KOPrefs::instance()->mHourSize > 4 )
00425         KOPrefs::instance()->mHourSize--;
00426     } else {
00427       KOPrefs::instance()->mHourSize++;
00428     }
00429   }
00430 
00431   FOREACH_VIEW( agenda )
00432     agenda->zoomView( delta, pos, ori );
00433 
00434   mTimeLabels->updateConfig();
00435   mTimeLabels->positionChanged();
00436   mTimeLabels->repaint();
00437 }
00438 
00439 // KDE4: not needed, use existing QSplitter signals instead
00440 void MultiAgendaView::installSplitterEventFilter(QSplitter * splitter)
00441 {
00442   QObjectList *objlist = splitter->queryList( "QSplitterHandle" );
00443   // HACK: when not being visible, the splitter handle is sometimes not found
00444   // for unknown reasons, so trigger an update when we are shown again
00445   if ( objlist->count() == 0 && !isVisible() )
00446     mUpdateOnShow = true;
00447   QObjectListIt it( *objlist );
00448   QObject *obj;
00449   while ( (obj = it.current()) != 0 ) {
00450     obj->removeEventFilter( this );
00451     obj->installEventFilter( this );
00452     ++it;
00453   }
00454   delete objlist;
00455 }
00456 
00457 void MultiAgendaView::slotResizeScrollView()
00458 {
00459   resizeScrollView( size() );
00460 }
00461 
00462 void MultiAgendaView::show()
00463 {
00464   AgendaView::show();
00465   if ( mUpdateOnShow ) {
00466     mUpdateOnShow = false;
00467     showDates( mStartDate, mEndDate );
00468   }
00469 }
00470 
00471 #include "multiagendaview.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys