korganizer

koeditorrecurrence.cpp

00001 /*
00002     This file is part of KOrganizer.
00003     Copyright (c) 2000-2003 Cornelius Schumacher <schumacher@kde.org>
00004     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <qtooltip.h>
00026 #include <qfiledialog.h>
00027 #include <qlayout.h>
00028 #include <qvbox.h>
00029 #include <qbuttongroup.h>
00030 #include <qvgroupbox.h>
00031 #include <qwidgetstack.h>
00032 #include <qdatetime.h>
00033 #include <qlistbox.h>
00034 #include <qspinbox.h>
00035 #include <qcheckbox.h>
00036 #include <qgroupbox.h>
00037 #include <qwidgetstack.h>
00038 #include <qradiobutton.h>
00039 #include <qlabel.h>
00040 #include <qpushbutton.h>
00041 #include <qwhatsthis.h>
00042 
00043 #include <kdialog.h>
00044 #include <kglobal.h>
00045 #include <klocale.h>
00046 #include <kiconloader.h>
00047 #include <kdebug.h>
00048 #include <knumvalidator.h>
00049 #include <kcalendarsystem.h>
00050 #include <kmessagebox.h>
00051 
00052 #include <libkdepim/kdateedit.h>
00053 #include <libkcal/todo.h>
00054 
00055 #include "koprefs.h"
00056 #include "koglobals.h"
00057 
00058 #include "koeditorrecurrence.h"
00059 #include "koeditorrecurrence.moc"
00060 
00062 
00063 RecurBase::RecurBase( QWidget *parent, const char *name ) :
00064   QWidget( parent, name )
00065 {
00066   mFrequencyEdit = new QSpinBox( 1, 9999, 1, this );
00067   mFrequencyEdit->setValue( 1 );
00068 }
00069 
00070 QWidget *RecurBase::frequencyEdit()
00071 {
00072   return mFrequencyEdit;
00073 }
00074 
00075 void RecurBase::setFrequency( int f )
00076 {
00077   if ( f < 1 ) f = 1;
00078 
00079   mFrequencyEdit->setValue( f );
00080 }
00081 
00082 int RecurBase::frequency()
00083 {
00084   return mFrequencyEdit->value();
00085 }
00086 
00087 QComboBox *RecurBase::createWeekCountCombo( QWidget *parent, const char *name )
00088 {
00089   QComboBox *combo = new QComboBox( parent, name );
00090   QWhatsThis::add( combo,
00091                    i18n("The number of the week from the beginning "
00092                         "of the month on which this event or to-do "
00093                         "should recur.") );
00094   if ( !combo ) return 0;
00095   combo->insertItem( i18n("1st") );
00096   combo->insertItem( i18n("2nd") );
00097   combo->insertItem( i18n("3rd") );
00098   combo->insertItem( i18n("4th") );
00099   combo->insertItem( i18n("5th") );
00100   combo->insertItem( i18n("Last") );
00101   combo->insertItem( i18n("2nd Last") );
00102   combo->insertItem( i18n("3rd Last") );
00103   combo->insertItem( i18n("4th Last") );
00104   combo->insertItem( i18n("5th Last") );
00105   return combo;
00106 }
00107 
00108 QComboBox *RecurBase::createWeekdayCombo( QWidget *parent, const char *name )
00109 {
00110   QComboBox *combo = new QComboBox( parent, name );
00111   QWhatsThis::add( combo,
00112                    i18n("The weekday on which this event or to-do "
00113                         "should recur.") );
00114   if ( !combo ) return 0;
00115   const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
00116   for( int i = 1; i <= 7; ++i ) {
00117     combo->insertItem( calSys->weekDayName( i ) );
00118   }
00119   return combo;
00120 }
00121 
00122 QComboBox *RecurBase::createMonthNameCombo( QWidget *parent, const char *name )
00123 {
00124   QComboBox *combo = new QComboBox( parent, name );
00125   QWhatsThis::add( combo,
00126                    i18n("The month during which this event or to-do "
00127                         "should recur.") );
00128   if ( !combo ) return 0;
00129   const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
00130   for( int i = 1; i <= 12; ++i ) {
00131     // use an arbitrary year, we just need the month name...
00132     QDate dt( 2005, i, 1 );
00133     combo->insertItem( calSys->monthName( dt ) );
00134   }
00135   return combo;
00136 }
00137 
00138 QBoxLayout *RecurBase::createFrequencySpinBar( QWidget *parent, QLayout *layout,
00139     QString everyText, QString unitText )
00140 {
00141   QBoxLayout *freqLayout = new QHBoxLayout( layout );
00142 
00143   QString whatsThis = i18n("Sets how often this event or to-do should recur.");
00144   QLabel *preLabel = new QLabel( everyText, parent );
00145   QWhatsThis::add( preLabel, whatsThis );
00146   freqLayout->addWidget( preLabel );
00147 
00148   freqLayout->addWidget( frequencyEdit() );
00149   preLabel->setBuddy( frequencyEdit() );
00150   QWhatsThis::add( preLabel->buddy(), whatsThis );
00151 
00152   QLabel *postLabel = new QLabel( unitText, parent );
00153   QWhatsThis::add( postLabel, whatsThis );
00154   freqLayout->addWidget( postLabel );
00155   freqLayout->addStretch();
00156   return freqLayout;
00157 }
00158 
00160 
00161 RecurDaily::RecurDaily( QWidget *parent, const char *name ) :
00162   RecurBase( parent, name )
00163 {
00164   QBoxLayout *topLayout = new QVBoxLayout( this );
00165   topLayout->setSpacing( KDialog::spacingHint() );
00166 
00167   createFrequencySpinBar( this, topLayout, i18n("&Recur every"), i18n("day(s)") );
00168 }
00169 
00170 
00172 
00173 RecurWeekly::RecurWeekly( QWidget *parent, const char *name ) :
00174   RecurBase( parent, name )
00175 {
00176   QBoxLayout *topLayout = new QVBoxLayout( this );
00177   topLayout->setSpacing( KDialog::spacingHint() );
00178 
00179 //  topLayout->addStretch( 1 );
00180 
00181   createFrequencySpinBar( this, topLayout, i18n("&Recur every"), i18n("week(s) on:") );
00182 
00183   QHBox *dayBox = new QHBox( this );
00184   topLayout->addWidget( dayBox, 1, AlignVCenter );
00185   // Respect start of week setting
00186   int weekStart=KGlobal::locale()->weekStartDay();
00187   for ( int i = 0; i < 7; ++i ) {
00188     // i is the nr of the combobox, not the day of week!
00189     // label=(i+weekStart+6)%7 + 1;
00190     // index in CheckBox array(=day): label-1
00191     const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
00192     QString weekDayName = calSys->weekDayName(
00193       (i + weekStart + 6)%7 + 1, true );
00194     if ( KOPrefs::instance()->mCompactDialogs ) {
00195       weekDayName = weekDayName.left( 1 );
00196     }
00197     mDayBoxes[ (i + weekStart + 6)%7 ] = new QCheckBox( weekDayName, dayBox );
00198     QWhatsThis::add( mDayBoxes[ (i + weekStart + 6)%7 ],
00199                      i18n("Day of the week on which this event or to-do "
00200                           "should recur.") );
00201   }
00202 
00203   topLayout->addStretch( 1 );
00204 }
00205 
00206 void RecurWeekly::setDays( const QBitArray &days )
00207 {
00208   for ( int i = 0; i < 7; ++i ) {
00209     mDayBoxes[ i ]->setChecked( days.testBit( i ) );
00210   }
00211 }
00212 
00213 QBitArray RecurWeekly::days()
00214 {
00215   QBitArray days( 7 );
00216 
00217   for ( int i = 0; i < 7; ++i ) {
00218     days.setBit( i, mDayBoxes[ i ]->isChecked() );
00219   }
00220 
00221   return days;
00222 }
00223 
00225 
00226 RecurMonthly::RecurMonthly( QWidget *parent, const char *name ) :
00227   RecurBase( parent, name )
00228 {
00229   QBoxLayout *topLayout = new QVBoxLayout( this );
00230   topLayout->setSpacing( KDialog::spacingHint() );
00231 
00232   createFrequencySpinBar( this, topLayout, i18n("&Recur every"), i18n("month(s)") );
00233 
00234   QButtonGroup *buttonGroup = new QButtonGroup( this );
00235   buttonGroup->setFrameStyle( QFrame::NoFrame );
00236   topLayout->addWidget( buttonGroup, 1, AlignVCenter );
00237 
00238   QGridLayout *buttonLayout = new QGridLayout( buttonGroup, 3, 2 );
00239   buttonLayout->setSpacing( KDialog::spacingHint() );
00240 
00241 
00242   QString recurOnText;
00243   if ( !KOPrefs::instance()->mCompactDialogs ) {
00244     recurOnText = i18n("&Recur on the");
00245   }
00246 
00247   mByDayRadio = new QRadioButton( recurOnText, buttonGroup );
00248   QWhatsThis::add( mByDayRadio,
00249                    i18n("Sets a specific day of the month on which "
00250                         "this event or to-do should recur.") );
00251 
00252   buttonLayout->addWidget( mByDayRadio, 0, 0 );
00253 
00254   QString whatsThis = i18n("The day of the month on which this event or to-do "
00255                            "should recur.");
00256   mByDayCombo = new QComboBox( buttonGroup );
00257   QWhatsThis::add( mByDayCombo, whatsThis );
00258   mByDayCombo->setSizeLimit( 7 );
00259   mByDayCombo->insertItem( i18n("1st") );
00260   mByDayCombo->insertItem( i18n("2nd") );
00261   mByDayCombo->insertItem( i18n("3rd") );
00262   mByDayCombo->insertItem( i18n("4th") );
00263   mByDayCombo->insertItem( i18n("5th") );
00264   mByDayCombo->insertItem( i18n("6th") );
00265   mByDayCombo->insertItem( i18n("7th") );
00266   mByDayCombo->insertItem( i18n("8th") );
00267   mByDayCombo->insertItem( i18n("9th") );
00268   mByDayCombo->insertItem( i18n("10th") );
00269   mByDayCombo->insertItem( i18n("11th") );
00270   mByDayCombo->insertItem( i18n("12th") );
00271   mByDayCombo->insertItem( i18n("13th") );
00272   mByDayCombo->insertItem( i18n("14th") );
00273   mByDayCombo->insertItem( i18n("15th") );
00274   mByDayCombo->insertItem( i18n("16th") );
00275   mByDayCombo->insertItem( i18n("17th") );
00276   mByDayCombo->insertItem( i18n("18th") );
00277   mByDayCombo->insertItem( i18n("19th") );
00278   mByDayCombo->insertItem( i18n("20th") );
00279   mByDayCombo->insertItem( i18n("21st") );
00280   mByDayCombo->insertItem( i18n("22nd") );
00281   mByDayCombo->insertItem( i18n("23rd") );
00282   mByDayCombo->insertItem( i18n("24th") );
00283   mByDayCombo->insertItem( i18n("25th") );
00284   mByDayCombo->insertItem( i18n("26th") );
00285   mByDayCombo->insertItem( i18n("27th") );
00286   mByDayCombo->insertItem( i18n("28th") );
00287   mByDayCombo->insertItem( i18n("29th") );
00288   mByDayCombo->insertItem( i18n("30th") );
00289   mByDayCombo->insertItem( i18n("31st") );
00290   mByDayCombo->insertItem( i18n("Last") );
00291   mByDayCombo->insertItem( i18n("2nd Last") );
00292   mByDayCombo->insertItem( i18n("3rd Last") );
00293   mByDayCombo->insertItem( i18n("4th Last") );
00294   mByDayCombo->insertItem( i18n("5th Last") );
00295   // FIXME: After the string freeze is over, insert all possible values, not
00296   //        just the ones we already have translated:
00297 /*  mByDayCombo->insertItem( i18n("6th Last") );
00298   mByDayCombo->insertItem( i18n("7th Last") );
00299   mByDayCombo->insertItem( i18n("8th Last") );
00300   mByDayCombo->insertItem( i18n("9th Last") );
00301   mByDayCombo->insertItem( i18n("10th Last") );
00302   mByDayCombo->insertItem( i18n("11th Last") );
00303   mByDayCombo->insertItem( i18n("12th Last") );
00304   mByDayCombo->insertItem( i18n("13th Last") );
00305   mByDayCombo->insertItem( i18n("14th Last") );
00306   mByDayCombo->insertItem( i18n("15th Last") );
00307   mByDayCombo->insertItem( i18n("16th Last") );
00308   mByDayCombo->insertItem( i18n("17th Last") );
00309   mByDayCombo->insertItem( i18n("18th Last") );
00310   mByDayCombo->insertItem( i18n("19th Last") );
00311   mByDayCombo->insertItem( i18n("20th Last") );
00312   mByDayCombo->insertItem( i18n("21st Last") );
00313   mByDayCombo->insertItem( i18n("22nd Last") );
00314   mByDayCombo->insertItem( i18n("23rd Last") );
00315   mByDayCombo->insertItem( i18n("24th Last") );
00316   mByDayCombo->insertItem( i18n("25th Last") );
00317   mByDayCombo->insertItem( i18n("26th Last") );
00318   mByDayCombo->insertItem( i18n("27th Last") );
00319   mByDayCombo->insertItem( i18n("28th Last") );
00320   mByDayCombo->insertItem( i18n("29th Last") );
00321   mByDayCombo->insertItem( i18n("30th Last") );
00322   mByDayCombo->insertItem( i18n("31st Last") );*/
00323   buttonLayout->addWidget( mByDayCombo, 0, 1 );
00324 
00325   QLabel *byDayLabel = new QLabel( i18n("day"), buttonGroup );
00326   QWhatsThis::add( byDayLabel, whatsThis );
00327   buttonLayout->addWidget( byDayLabel, 0, 2 );
00328 
00329 
00330   mByPosRadio = new QRadioButton( recurOnText, buttonGroup);
00331   QWhatsThis::add( mByPosRadio,
00332                    i18n("Sets a weekday and specific week in the month "
00333                         "on which this event or to-do should recur") );
00334   buttonLayout->addWidget( mByPosRadio, 1, 0 );
00335 
00336   mByPosCountCombo = createWeekCountCombo( buttonGroup );
00337   buttonLayout->addWidget( mByPosCountCombo, 1, 1 );
00338 
00339   mByPosWeekdayCombo = createWeekdayCombo( buttonGroup );
00340   buttonLayout->addWidget( mByPosWeekdayCombo, 1, 2 );
00341 }
00342 
00343 void RecurMonthly::setByDay( int day )
00344 {
00345   mByDayRadio->setChecked( true );
00346   // Days from the end are after the ones from the begin, so correct for the
00347   // negative sign and add 30 (index starting at 0)
00348   if ( day > 0 && day <= 31 )
00349     mByDayCombo->setCurrentItem( day-1 );
00350   else if ( day < 0 )
00351     mByDayCombo->setCurrentItem( 31 - 1 - day );
00352 }
00353 
00354 void RecurMonthly::setByPos( int count, int weekday )
00355 {
00356   mByPosRadio->setChecked( true );
00357   if (count>0)
00358     mByPosCountCombo->setCurrentItem( count - 1 );
00359   else
00360     // negative weeks means counted from the end of month
00361     mByPosCountCombo->setCurrentItem( -count + 4 );
00362   mByPosWeekdayCombo->setCurrentItem( weekday - 1 );
00363 }
00364 
00365 bool RecurMonthly::byDay()
00366 {
00367   return mByDayRadio->isChecked();
00368 }
00369 
00370 bool RecurMonthly::byPos()
00371 {
00372   return mByPosRadio->isChecked();
00373 }
00374 
00375 int RecurMonthly::day()
00376 {
00377   int day = mByDayCombo->currentItem();
00378   if ( day >= 31 ) day = 31-day-1;
00379   else ++day;
00380   return day;
00381 }
00382 
00383 int RecurMonthly::count()
00384 {
00385   int pos=mByPosCountCombo->currentItem();
00386   if (pos<=4) // positive  count
00387     return pos+1;
00388   else
00389     return -pos+4;
00390 }
00391 
00392 int RecurMonthly::weekday()
00393 {
00394   return mByPosWeekdayCombo->currentItem() + 1;
00395 }
00396 
00398 
00399 RecurYearly::RecurYearly( QWidget *parent, const char *name ) :
00400   RecurBase( parent, name )
00401 {
00402   QBoxLayout *topLayout = new QVBoxLayout( this );
00403   topLayout->setSpacing( KDialog::spacingHint() );
00404 
00405   createFrequencySpinBar( this, topLayout, i18n("&Recur every"), i18n("year(s)") );
00406 
00407 
00408   QButtonGroup *buttonGroup = new QButtonGroup( this );
00409   buttonGroup->setFrameStyle( QFrame::NoFrame );
00410   topLayout->addWidget( buttonGroup, 1, AlignVCenter );
00411 
00412   QBoxLayout *buttonLayout = new QVBoxLayout( buttonGroup );
00413 
00414 
00415   /* YearlyMonth (day n of Month Y) */
00416   QBoxLayout *monthLayout = new QHBoxLayout( buttonLayout );
00417   QString recurInMonthText(
00418       i18n("part before XXX of 'Recur on day XXX of month YYY'",
00419       "&Recur on day "));
00420   if ( KOPrefs::instance()->mCompactDialogs ) {
00421     recurInMonthText = i18n("&Day ");
00422   }
00423   mByMonthRadio = new QRadioButton( recurInMonthText, buttonGroup );
00424   QWhatsThis::add( mByMonthRadio,
00425        i18n("Sets a specific day in a specific month on which "
00426       "this event or to-do should recur.") );
00427   monthLayout->addWidget( mByMonthRadio );
00428   mByMonthSpin = new QSpinBox( 1, 31, 1, buttonGroup );
00429   QWhatsThis::add( mByMonthSpin,
00430        i18n("The day of the month on which this event or to-do "
00431       "should recur.") );
00432   monthLayout->addWidget( mByMonthSpin );
00433   QLabel *ofLabel = new QLabel(
00434       i18n("part between XXX and YYY of 'Recur on day XXX of month YYY'", " &of "),
00435       buttonGroup );
00436   //What do I do here? I'm not sure if this label should have What's This in it... - Antonio
00437   monthLayout->addWidget( ofLabel );
00438 
00439   mByMonthCombo = createMonthNameCombo( buttonGroup );
00440   monthLayout->addWidget( mByMonthCombo );
00441   ofLabel->setBuddy( mByMonthCombo );
00442 
00443   monthLayout->addStretch( 1 );
00444 
00445 
00446   /* YearlyPos (weekday X of week N of month Y) */
00447   QBoxLayout *posLayout = new QHBoxLayout( buttonLayout );
00448   QString recurOnPosText( i18n("Part before XXX in 'Recur on NNN. WEEKDAY of MONTH', short version", "&On" ) );
00449   if ( !KOPrefs::instance()->mCompactDialogs ) {
00450     recurOnPosText = i18n("Part before XXX in 'Recur on NNN. WEEKDAY of MONTH'", "&On the" );
00451   }
00452   mByPosRadio = new QRadioButton( recurOnPosText, buttonGroup );
00453   QWhatsThis::add( mByPosRadio,
00454        i18n("Sets a specific day in a specific week of a specific "
00455       "month on which this event or to-do should recur.") );
00456   posLayout->addWidget( mByPosRadio );
00457 
00458   mByPosDayCombo = createWeekCountCombo( buttonGroup );
00459   posLayout->addWidget( mByPosDayCombo );
00460 
00461   mByPosWeekdayCombo = createWeekdayCombo( buttonGroup );
00462   posLayout->addWidget( mByPosWeekdayCombo );
00463 
00464   ofLabel = new QLabel(
00465       i18n("part between WEEKDAY and MONTH in 'Recur on NNN. WEEKDAY of MONTH'", " o&f "),
00466       buttonGroup );
00467   posLayout->addWidget( ofLabel );
00468 
00469   mByPosMonthCombo  = createMonthNameCombo( buttonGroup );
00470   posLayout->addWidget( mByPosMonthCombo );
00471   ofLabel->setBuddy( mByPosMonthCombo );
00472 
00473   posLayout->addStretch( 1 );
00474 
00475 
00476   /* YearlyDay (day N of the year) */
00477   QBoxLayout *dayLayout = new QHBoxLayout( buttonLayout );
00478   QString recurOnDayText;
00479   if ( KOPrefs::instance()->mCompactDialogs ) {
00480     recurOnDayText = i18n("Day #");
00481   } else {
00482     recurOnDayText = i18n("Recur on &day #");
00483   }
00484   QString whatsThis = i18n("Sets a specific day within the year on which this "
00485          "event or to-do should recur.");
00486   mByDayRadio = new QRadioButton( recurOnDayText, buttonGroup );
00487   QWhatsThis::add( mByDayRadio, whatsThis );
00488   dayLayout->addWidget( mByDayRadio );
00489 
00490   mByDaySpin = new QSpinBox( 1, 366, 1, buttonGroup );
00491   QWhatsThis::add( mByDaySpin, whatsThis );
00492 
00493   dayLayout->addWidget( mByDaySpin );
00494 
00495   QString ofTheYear( i18n("part after NNN of 'Recur on day #NNN of the year'", " of the &year"));
00496   if ( KOPrefs::instance()->mCompactDialogs ) {
00497     ofTheYear = i18n("part after NNN of 'Recur on day #NNN of the year', short version",
00498         " of the year");
00499   }
00500   ofLabel = new QLabel( ofTheYear, buttonGroup );
00501   QWhatsThis::add( ofLabel, whatsThis );
00502   dayLayout->addWidget( ofLabel );
00503   ofLabel->setBuddy( mByDaySpin );
00504 
00505   dayLayout->addStretch( 1 );
00506 }
00507 
00508 void RecurYearly::setByDay( int day )
00509 {
00510   mByDayRadio->setChecked( true );
00511   mByDaySpin->setValue( day );
00512 }
00513 
00514 void RecurYearly::setByPos( int count, int weekday, int month )
00515 {
00516   mByPosRadio->setChecked( true );
00517   if ( count > 0 )
00518     mByPosDayCombo->setCurrentItem( count - 1 );
00519   else
00520     mByPosDayCombo->setCurrentItem( -count + 4 );
00521   mByPosWeekdayCombo->setCurrentItem( weekday - 1 );
00522   mByPosMonthCombo->setCurrentItem( month-1 );
00523 }
00524 
00525 void RecurYearly::setByMonth( int day, int month )
00526 {
00527   mByMonthRadio->setChecked( true );
00528   mByMonthSpin->setValue( day );
00529   mByMonthCombo->setCurrentItem( month - 1 );
00530 }
00531 
00532 RecurYearly::YearlyType RecurYearly::getType()
00533 {
00534   if ( mByMonthRadio->isChecked() ) return byMonth;
00535   if ( mByPosRadio->isChecked() ) return byPos;
00536   if ( mByDayRadio->isChecked() ) return byDay;
00537   return byMonth;
00538 }
00539 
00540 int RecurYearly::monthDay()
00541 {
00542   return mByMonthSpin->value();
00543 }
00544 
00545 int RecurYearly::month()
00546 {
00547   return mByMonthCombo->currentItem() + 1;
00548 }
00549 
00550 int RecurYearly::posCount()
00551 {
00552   int pos = mByPosDayCombo->currentItem();
00553   if ( pos <= 4 ) // positive  count
00554     return pos + 1;
00555   else
00556     return -pos + 4;
00557 }
00558 
00559 int RecurYearly::posWeekday()
00560 {
00561   return mByPosWeekdayCombo->currentItem() + 1;
00562 }
00563 
00564 int RecurYearly::posMonth()
00565 {
00566   return mByPosMonthCombo->currentItem() + 1;
00567 }
00568 
00569 int RecurYearly::day()
00570 {
00571   return mByDaySpin->value();
00572 }
00573 
00575 
00576 ExceptionsWidget::ExceptionsWidget( QWidget *parent, const char *name ) :
00577   QWidget( parent, name )
00578 {
00579   QBoxLayout *topLayout = new QVBoxLayout( this );
00580 
00581   QGroupBox *groupBox = new QGroupBox( 1, Horizontal, i18n("E&xceptions"),
00582                                        this );
00583   topLayout->addWidget( groupBox );
00584 
00585   QWidget *box = new QWidget( groupBox );
00586 
00587   QGridLayout *boxLayout = new QGridLayout( box );
00588 
00589   mExceptionDateEdit = new KDateEdit( box );
00590   QWhatsThis::add( mExceptionDateEdit,
00591        i18n("A date that should be considered an exception "
00592       "to the recurrence rules for this event or to-do.") );
00593   mExceptionDateEdit->setDate( QDate::currentDate() );
00594   boxLayout->addWidget( mExceptionDateEdit, 0, 0 );
00595 
00596   QPushButton *addExceptionButton = new QPushButton(
00597       i18n( "Add a new recurrence to the recurrence list", "&Add" ), box );
00598   QWhatsThis::add( addExceptionButton,
00599        i18n("Add this date as an exception "
00600       "to the recurrence rules for this event or to-do.") );
00601   boxLayout->addWidget( addExceptionButton, 1, 0 );
00602   QPushButton *changeExceptionButton = new QPushButton( i18n("&Change"), box );
00603   QWhatsThis::add( changeExceptionButton,
00604        i18n("Replace the currently selected date with this date.") );
00605   boxLayout->addWidget( changeExceptionButton, 2, 0 );
00606   QPushButton *deleteExceptionButton = new QPushButton( i18n("&Delete"), box );
00607   QWhatsThis::add( deleteExceptionButton,
00608        i18n("Delete the currently selected date from the list of dates "
00609             "that should be considered exceptions to the recurrence rules "
00610             "for this event or to-do.") );
00611   boxLayout->addWidget( deleteExceptionButton, 3, 0 );
00612 
00613   mExceptionList = new QListBox( box );
00614   QWhatsThis::add( mExceptionList,
00615        i18n("Displays current dates that are being considered "
00616       "exceptions to the recurrence rules for this event "
00617       "or to-do.") );
00618   boxLayout->addMultiCellWidget( mExceptionList, 0, 3, 1, 1 );
00619 
00620   boxLayout->setRowStretch( 4, 1 );
00621   boxLayout->setColStretch( 1, 3 );
00622 
00623   connect( addExceptionButton, SIGNAL( clicked() ),
00624            SLOT( addException() ) );
00625   connect( changeExceptionButton, SIGNAL( clicked() ),
00626            SLOT( changeException() ) );
00627   connect( deleteExceptionButton, SIGNAL( clicked() ),
00628            SLOT( deleteException() ) );
00629 }
00630 
00631 void ExceptionsWidget::addException()
00632 {
00633   QDate date = mExceptionDateEdit->date();
00634   QString dateStr = KGlobal::locale()->formatDate( date );
00635   if( !mExceptionList->findItem( dateStr ) ) {
00636     mExceptionDates.append( date );
00637     mExceptionList->insertItem( dateStr );
00638   }
00639 }
00640 
00641 void ExceptionsWidget::changeException()
00642 {
00643   int pos = mExceptionList->currentItem();
00644   if ( pos < 0 ) return;
00645 
00646   QDate date = mExceptionDateEdit->date();
00647   mExceptionDates[ pos ] = date;
00648   mExceptionList->changeItem( KGlobal::locale()->formatDate( date ), pos );
00649 }
00650 
00651 void ExceptionsWidget::deleteException()
00652 {
00653   int pos = mExceptionList->currentItem();
00654   if ( pos < 0 ) return;
00655 
00656   mExceptionDates.remove( mExceptionDates.at( pos ) );
00657   mExceptionList->removeItem( pos );
00658 }
00659 
00660 void ExceptionsWidget::setDates( const DateList &dates )
00661 {
00662   mExceptionList->clear();
00663   mExceptionDates.clear();
00664   DateList::ConstIterator dit;
00665   for ( dit = dates.begin(); dit != dates.end(); ++dit ) {
00666     mExceptionList->insertItem( KGlobal::locale()->formatDate(* dit ) );
00667     mExceptionDates.append( *dit );
00668   }
00669 }
00670 
00671 DateList ExceptionsWidget::dates()
00672 {
00673   return mExceptionDates;
00674 }
00675 
00677 
00678 ExceptionsDialog::ExceptionsDialog( QWidget *parent, const char *name ) :
00679   KDialogBase( parent, name, true, i18n("Edit Exceptions"), Ok|Cancel )
00680 {
00681   mExceptions = new ExceptionsWidget( this );
00682   setMainWidget( mExceptions );
00683 }
00684 
00685 void ExceptionsDialog::setDates( const DateList &dates )
00686 {
00687   mExceptions->setDates( dates );
00688 }
00689 
00690 DateList ExceptionsDialog::dates()
00691 {
00692   return mExceptions->dates();
00693 }
00694 
00696 
00697 RecurrenceRangeWidget::RecurrenceRangeWidget( QWidget *parent,
00698                                               const char *name )
00699   : QWidget( parent, name )
00700 {
00701   QBoxLayout *topLayout = new QVBoxLayout( this );
00702 
00703   mRangeGroupBox = new QGroupBox( 1, Horizontal, i18n("Recurrence Range"),
00704                                   this );
00705   QWhatsThis::add( mRangeGroupBox,
00706        i18n("Sets a range for which these recurrence rules will "
00707       "apply to this event or to-do.") );
00708   topLayout->addWidget( mRangeGroupBox );
00709 
00710   QWidget *rangeBox = new QWidget( mRangeGroupBox );
00711   QVBoxLayout *rangeLayout = new QVBoxLayout( rangeBox );
00712   rangeLayout->setSpacing( KDialog::spacingHint() );
00713 
00714   mStartDateLabel = new QLabel( i18n("Begin on:"), rangeBox );
00715   QWhatsThis::add( mStartDateLabel,
00716        i18n("The date on which the recurrences for this event or to-do "
00717       "should begin.") );
00718   rangeLayout->addWidget( mStartDateLabel );
00719 
00720   QButtonGroup *rangeButtonGroup = new QButtonGroup( this );
00721   rangeButtonGroup->hide();
00722 
00723   mNoEndDateButton = new QRadioButton( i18n("&No ending date"), rangeBox );
00724   QWhatsThis::add( mNoEndDateButton,
00725        i18n("Sets the event or to-do to recur forever.") );
00726   rangeButtonGroup->insert( mNoEndDateButton );
00727   rangeLayout->addWidget( mNoEndDateButton );
00728 
00729   QBoxLayout *durationLayout = new QHBoxLayout( rangeLayout );
00730   durationLayout->setSpacing( KDialog::spacingHint() );
00731 
00732   mEndDurationButton = new QRadioButton( i18n("End &after"), rangeBox );
00733   QWhatsThis::add( mEndDurationButton,
00734        i18n("Sets the event or to-do to stop recurring after a "
00735       "certain number of occurrences.") );
00736   rangeButtonGroup->insert( mEndDurationButton );
00737   durationLayout->addWidget( mEndDurationButton );
00738 
00739   QString whatsThis = i18n("Number of times the event or to-do should recur "
00740            "before stopping.");
00741   mEndDurationEdit = new QSpinBox( 1, 9999, 1, rangeBox );
00742   QWhatsThis::add( mEndDurationEdit, whatsThis );
00743   durationLayout->addWidget( mEndDurationEdit );
00744 
00745   QLabel *endDurationLabel = new QLabel( i18n("&occurrence(s)"), rangeBox );
00746   QWhatsThis::add( endDurationLabel, whatsThis );
00747   durationLayout ->addWidget( endDurationLabel );
00748   endDurationLabel->setBuddy( mEndDurationEdit );
00749 
00750   QBoxLayout *endDateLayout = new QHBoxLayout( rangeLayout );
00751   endDateLayout->setSpacing( KDialog::spacingHint() );
00752 
00753   mEndDateButton = new QRadioButton( i18n("End &on:"), rangeBox );
00754   QWhatsThis::add( mEndDateButton,
00755                    i18n("Sets the event or to-do to stop recurring on "
00756                         "a certain date.") );
00757   rangeButtonGroup->insert( mEndDateButton );
00758   endDateLayout->addWidget( mEndDateButton );
00759 
00760   mEndDateEdit = new KDateEdit( rangeBox );
00761   QWhatsThis::add( mEndDateEdit,
00762                    i18n("Date after which the event or to-do should stop "
00763                         "recurring") );
00764   endDateLayout->addWidget( mEndDateEdit );
00765 
00766   endDateLayout->addStretch( 1 );
00767 
00768   connect( mNoEndDateButton, SIGNAL( toggled( bool ) ),
00769            SLOT( showCurrentRange() ) );
00770   connect( mEndDurationButton, SIGNAL( toggled( bool ) ),
00771            SLOT( showCurrentRange() ) );
00772   connect( mEndDateButton, SIGNAL( toggled( bool ) ),
00773            SLOT( showCurrentRange() ) );
00774 }
00775 
00776 void RecurrenceRangeWidget::setDefaults( const QDateTime &from  )
00777 {
00778   mNoEndDateButton->setChecked( true );
00779 
00780   setDateTimes( from );
00781   setEndDate( from.date() );
00782 }
00783 
00784 void RecurrenceRangeWidget::setDuration( int duration )
00785 {
00786   if ( duration == -1 ) {
00787     mNoEndDateButton->setChecked( true );
00788   } else if ( duration == 0 ) {
00789     mEndDateButton->setChecked( true );
00790   } else {
00791     mEndDurationButton->setChecked( true );
00792     mEndDurationEdit->setValue( duration );
00793   }
00794 }
00795 
00796 int RecurrenceRangeWidget::duration()
00797 {
00798   if ( mNoEndDateButton->isChecked() ) {
00799     return -1;
00800   } else if ( mEndDurationButton->isChecked() ) {
00801     return mEndDurationEdit->value();
00802   } else {
00803     return 0;
00804   }
00805 }
00806 
00807 void RecurrenceRangeWidget::setEndDate( const QDate &date )
00808 {
00809   mEndDateEdit->setDate( date );
00810 }
00811 
00812 QDate RecurrenceRangeWidget::endDate()
00813 {
00814   return mEndDateEdit->date();
00815 }
00816 
00817 void RecurrenceRangeWidget::showCurrentRange()
00818 {
00819   mEndDurationEdit->setEnabled( mEndDurationButton->isChecked() );
00820   mEndDateEdit->setEnabled( mEndDateButton->isChecked() );
00821 }
00822 
00823 void RecurrenceRangeWidget::setDateTimes( const QDateTime &start,
00824                                           const QDateTime & )
00825 {
00826   mStartDateLabel->setText( i18n("Begins on: %1")
00827       .arg( KGlobal::locale()->formatDate( start.date() ) ) );
00828 }
00829 
00831 
00832 RecurrenceRangeDialog::RecurrenceRangeDialog( QWidget *parent,
00833                                               const char *name ) :
00834   KDialogBase( parent, name, true, i18n("Edit Recurrence Range"), Ok|Cancel )
00835 {
00836   mRecurrenceRangeWidget = new RecurrenceRangeWidget( this );
00837   setMainWidget( mRecurrenceRangeWidget );
00838 }
00839 
00840 void RecurrenceRangeDialog::setDefaults( const QDateTime &from )
00841 {
00842   mRecurrenceRangeWidget->setDefaults( from );
00843 }
00844 
00845 void RecurrenceRangeDialog::setDuration( int duration )
00846 {
00847   mRecurrenceRangeWidget->setDuration( duration );
00848 }
00849 
00850 int RecurrenceRangeDialog::duration()
00851 {
00852   return mRecurrenceRangeWidget->duration();
00853 }
00854 
00855 void RecurrenceRangeDialog::setEndDate( const QDate &date )
00856 {
00857   mRecurrenceRangeWidget->setEndDate( date );
00858 }
00859 
00860 QDate RecurrenceRangeDialog::endDate()
00861 {
00862   return mRecurrenceRangeWidget->endDate();
00863 }
00864 
00865 void RecurrenceRangeDialog::setDateTimes( const QDateTime &start,
00866                                           const QDateTime &end )
00867 {
00868   mRecurrenceRangeWidget->setDateTimes( start, end );
00869 }
00870 
00872 
00873 RecurrenceChooser::RecurrenceChooser( QWidget *parent, const char *name ) :
00874   QWidget( parent, name )
00875 {
00876   QBoxLayout *topLayout = new QVBoxLayout( this );
00877 
00878   if ( KOPrefs::instance()->mCompactDialogs ) {
00879     mTypeCombo = new QComboBox( this );
00880     QWhatsThis::add( mTypeCombo,
00881                      i18n("Sets the type of recurrence this event or to-do "
00882                           "should have.") );
00883     mTypeCombo->insertItem( i18n("Daily") );
00884     mTypeCombo->insertItem( i18n("Weekly") );
00885     mTypeCombo->insertItem( i18n("Monthly") );
00886     mTypeCombo->insertItem( i18n("Yearly") );
00887 
00888     topLayout->addWidget( mTypeCombo );
00889 
00890     connect( mTypeCombo, SIGNAL( activated( int ) ), SLOT( emitChoice() ) );
00891   } else {
00892     mTypeCombo = 0;
00893 
00894     QButtonGroup *ruleButtonGroup = new QButtonGroup( 1, Horizontal, this );
00895     ruleButtonGroup->setFrameStyle( QFrame::NoFrame );
00896     topLayout->addWidget( ruleButtonGroup );
00897 
00898     mDailyButton = new QRadioButton( i18n("&Daily"), ruleButtonGroup );
00899     QWhatsThis::add( mDailyButton,
00900                      i18n("Sets the event or to-do to recur daily according "
00901                           "to the specified rules.") );
00902     mWeeklyButton = new QRadioButton( i18n("&Weekly"), ruleButtonGroup );
00903     QWhatsThis::add( mWeeklyButton,
00904                      i18n("Sets the event or to-do to recur weekly according "
00905                           "to the specified rules.") );
00906     mMonthlyButton = new QRadioButton( i18n("&Monthly"), ruleButtonGroup );
00907     QWhatsThis::add( mMonthlyButton,
00908                      i18n("Sets the event or to-do to recur monthly according "
00909                           "to the specified rules.") );
00910     mYearlyButton = new QRadioButton( i18n("&Yearly"), ruleButtonGroup );
00911     QWhatsThis::add( mYearlyButton,
00912                      i18n("Sets the event or to-do to recur yearly according "
00913                           "to the specified rules.") );
00914 
00915     connect( mDailyButton, SIGNAL( toggled( bool ) ),
00916              SLOT( emitChoice() ) );
00917     connect( mWeeklyButton, SIGNAL( toggled( bool ) ),
00918              SLOT( emitChoice() ) );
00919     connect( mMonthlyButton, SIGNAL( toggled( bool ) ),
00920              SLOT( emitChoice() ) );
00921     connect( mYearlyButton, SIGNAL( toggled( bool ) ),
00922              SLOT( emitChoice() ) );
00923   }
00924 }
00925 
00926 int RecurrenceChooser::type()
00927 {
00928   if ( mTypeCombo ) {
00929     return mTypeCombo->currentItem();
00930   } else {
00931     if ( mDailyButton->isChecked() ) return Daily;
00932     else if ( mWeeklyButton->isChecked() ) return Weekly;
00933     else if ( mMonthlyButton->isChecked() ) return Monthly;
00934     else return Yearly;
00935   }
00936 }
00937 
00938 void RecurrenceChooser::setType( int type )
00939 {
00940   if ( mTypeCombo ) {
00941     mTypeCombo->setCurrentItem( type );
00942   } else {
00943     switch ( type ) {
00944       case Daily:
00945         mDailyButton->setChecked( true );
00946         break;
00947       case Weekly:
00948         mWeeklyButton->setChecked( true );
00949         break;
00950       case Monthly:
00951         mMonthlyButton->setChecked( true );
00952         break;
00953       case Yearly:
00954       default:
00955         mYearlyButton->setChecked( true );
00956         break;
00957     }
00958   }
00959 }
00960 
00961 void RecurrenceChooser::emitChoice()
00962 {
00963   emit chosen ( type() );
00964 }
00965 
00967 
00968 KOEditorRecurrence::KOEditorRecurrence( QWidget* parent, const char *name ) :
00969   QWidget( parent, name )
00970 {
00971   QGridLayout *topLayout = new QGridLayout( this );
00972   topLayout->setSpacing( KDialog::spacingHint() );
00973 
00974   mEnabledCheck = new QCheckBox( i18n("&Enable recurrence"), this );
00975   QWhatsThis::add( mEnabledCheck,
00976                    i18n("Enables recurrence for this event or to-do according "
00977                         "to the specified rules.") );
00978   connect( mEnabledCheck, SIGNAL( toggled( bool ) ),
00979            SLOT( setRecurrenceEnabled( bool ) ) );
00980   topLayout->addMultiCellWidget( mEnabledCheck, 0, 0, 0, 1 );
00981 
00982 
00983   mTimeGroupBox = new QGroupBox( 1, Horizontal, i18n("Appointment Time "),
00984                                  this );
00985   QWhatsThis::add( mTimeGroupBox,
00986                    i18n("Displays appointment time information.") );
00987   topLayout->addMultiCellWidget( mTimeGroupBox, 1, 1 , 0 , 1 );
00988 
00989   if ( KOPrefs::instance()->mCompactDialogs ) {
00990     mTimeGroupBox->hide();
00991   }
00992 
00993 //  QFrame *timeFrame = new QFrame( mTimeGroupBox );
00994 //  QBoxLayout *layoutTimeFrame = new QHBoxLayout( timeFrame );
00995 //  layoutTimeFrame->setSpacing( KDialog::spacingHint() );
00996 
00997   mDateTimeLabel = new QLabel( mTimeGroupBox );
00998 //  mDateTimeLabel = new QLabel( timeFrame );
00999 //  layoutTimeFrame->addWidget( mDateTimeLabel );
01000 
01001   Qt::Orientation orientation;
01002   if ( KOPrefs::instance()->mCompactDialogs ) orientation = Horizontal;
01003   else orientation = Vertical;
01004 
01005   mRuleBox = new QGroupBox( 1, orientation, i18n("Recurrence Rule"), this );
01006   QWhatsThis::add( mRuleBox,
01007                    i18n("Options concerning the type of recurrence this event "
01008                         "or to-do should have.") );
01009   if ( KOPrefs::instance()->mCompactDialogs ) {
01010     topLayout->addWidget( mRuleBox, 2, 0 );
01011   } else {
01012     topLayout->addMultiCellWidget( mRuleBox, 2, 2, 0, 1 );
01013   }
01014 
01015   mRecurrenceChooser = new RecurrenceChooser( mRuleBox );
01016   connect( mRecurrenceChooser, SIGNAL( chosen( int ) ),
01017            SLOT( showCurrentRule( int ) ) );
01018 
01019   if ( !KOPrefs::instance()->mCompactDialogs ) {
01020     QFrame *ruleSepFrame = new QFrame( mRuleBox );
01021     ruleSepFrame->setFrameStyle( QFrame::VLine | QFrame::Sunken );
01022   }
01023 
01024   mRuleStack = new QWidgetStack( mRuleBox );
01025 
01026   mDaily = new RecurDaily( mRuleStack );
01027   mRuleStack->addWidget( mDaily, 0 );
01028 
01029   mWeekly = new RecurWeekly( mRuleStack );
01030   mRuleStack->addWidget( mWeekly, 0 );
01031 
01032   mMonthly = new RecurMonthly( mRuleStack );
01033   mRuleStack->addWidget( mMonthly, 0 );
01034 
01035   mYearly = new RecurYearly( mRuleStack );
01036   mRuleStack->addWidget( mYearly, 0 );
01037 
01038   showCurrentRule( mRecurrenceChooser->type() );
01039 
01040   if ( KOPrefs::instance()->mCompactDialogs ) {
01041     mRecurrenceRangeWidget = 0;
01042     mRecurrenceRangeDialog = new RecurrenceRangeDialog( this );
01043     mRecurrenceRange = mRecurrenceRangeDialog;
01044     mRecurrenceRangeButton = new QPushButton( i18n("Recurrence Range..."),
01045                                               this );
01046     QWhatsThis::add( mRecurrenceRangeButton,
01047                      i18n("Options concerning the time range during which "
01048                           "this event or to-do should recur.") );
01049     topLayout->addWidget( mRecurrenceRangeButton, 3, 0 );
01050     connect( mRecurrenceRangeButton, SIGNAL( clicked() ),
01051              SLOT( showRecurrenceRangeDialog() ) );
01052 
01053     mExceptionsWidget = 0;
01054     mExceptionsDialog = new ExceptionsDialog( this );
01055     mExceptions = mExceptionsDialog;
01056     mExceptionsButton = new QPushButton( i18n("Exceptions..."), this );
01057     topLayout->addWidget( mExceptionsButton, 4, 0 );
01058     connect( mExceptionsButton, SIGNAL( clicked() ),
01059              SLOT( showExceptionsDialog() ) );
01060 
01061   } else {
01062     mRecurrenceRangeWidget = new RecurrenceRangeWidget( this );
01063     QWhatsThis::add( mRecurrenceRangeWidget,
01064                      i18n("Options concerning the time range during which "
01065                           "this event or to-do should recur.") );
01066     mRecurrenceRangeDialog = 0;
01067     mRecurrenceRange = mRecurrenceRangeWidget;
01068     mRecurrenceRangeButton = 0;
01069     topLayout->addWidget( mRecurrenceRangeWidget, 3, 0 );
01070 
01071     mExceptionsWidget = new ExceptionsWidget( this );
01072     mExceptionsDialog = 0;
01073     mExceptions = mExceptionsWidget;
01074     mExceptionsButton = 0;
01075     topLayout->addWidget( mExceptionsWidget, 3, 1 );
01076   }
01077 }
01078 
01079 KOEditorRecurrence::~KOEditorRecurrence()
01080 {
01081 }
01082 
01083 void KOEditorRecurrence::setRecurrenceEnabled( bool enabled )
01084 {
01085 //  kdDebug(5850) << "KOEditorRecurrence::setRecurrenceEnabled(): " << (enabled ? "on" : "off") << endl;
01086 
01087   mEnabledCheck->setChecked( enabled );
01088   mTimeGroupBox->setEnabled( enabled );
01089   mRuleBox->setEnabled( enabled );
01090   if ( mRecurrenceRangeWidget ) mRecurrenceRangeWidget->setEnabled( enabled );
01091   if ( mRecurrenceRangeButton ) mRecurrenceRangeButton->setEnabled( enabled );
01092   if ( mExceptionsWidget ) mExceptionsWidget->setEnabled( enabled );
01093   if ( mExceptionsButton ) mExceptionsButton->setEnabled( enabled );
01094 }
01095 
01096 void KOEditorRecurrence::showCurrentRule( int current )
01097 {
01098   switch ( current ) {
01099     case Daily:
01100       mRuleStack->raiseWidget( mDaily );
01101       break;
01102     case Weekly:
01103       mRuleStack->raiseWidget( mWeekly );
01104       break;
01105     case Monthly:
01106       mRuleStack->raiseWidget( mMonthly );
01107       break;
01108     default:
01109     case Yearly:
01110       mRuleStack->raiseWidget( mYearly );
01111       break;
01112   }
01113 }
01114 
01115 void KOEditorRecurrence::setDateTimes( const QDateTime &start, const QDateTime &end )
01116 {
01117 //  kdDebug(5850) << "KOEditorRecurrence::setDateTimes" << endl;
01118 
01119   mEventStartDt = start;
01120   mRecurrenceRange->setDateTimes( start, end );
01121   mDaily->setDateTimes( start, end );
01122   mWeekly->setDateTimes( start, end );
01123   mMonthly->setDateTimes( start, end );
01124   mYearly->setDateTimes( start, end );
01125 
01126   // Now set the defaults for all unused types, use the start time for it
01127   bool enabled = mEnabledCheck->isChecked();
01128   int type = mRecurrenceChooser->type();
01129 
01130   if ( !enabled || type != RecurrenceChooser::Weekly ) {
01131     QBitArray days( 7 );
01132     days.fill( 0 );
01133     days.setBit( (start.date().dayOfWeek()+6) % 7 );
01134     mWeekly->setDays( days );
01135   }
01136   if ( !enabled || type != RecurrenceChooser::Monthly ) {
01137     mMonthly->setByPos( ( start.date().day() - 1 ) / 7 + 1, start.date().dayOfWeek() - 1 );
01138     mMonthly->setByDay( start.date().day() );
01139   }
01140   if ( !enabled || type != RecurrenceChooser::Yearly ) {
01141     mYearly->setByDay( start.date().dayOfYear() );
01142     mYearly->setByPos( ( start.date().day() - 1 ) / 7 + 1,
01143         start.date().dayOfWeek() - 1, start.date().month() );
01144     mYearly->setByMonth( start.date().day(), start.date().month() );
01145   }
01146 }
01147 
01148 void KOEditorRecurrence::setDefaults( const QDateTime &from, const QDateTime &to, bool )
01149 {
01150   setDateTimes( from, to );
01151 
01152   setRecurrenceEnabled( false );
01153 
01154   mRecurrenceRange->setDefaults( from );
01155 
01156   mRecurrenceChooser->setType( RecurrenceChooser::Weekly );
01157   showCurrentRule( mRecurrenceChooser->type() );
01158 
01159   mDaily->setFrequency( 1 );
01160 
01161   mWeekly->setFrequency( 1 );
01162   QBitArray days( 7 );
01163   days.fill( 0 );
01164   days.setBit( (from.date().dayOfWeek()+6) % 7 );
01165   mWeekly->setDays( days );
01166 
01167   mMonthly->setFrequency( 1 );
01168   mMonthly->setByPos( ( from.date().day() - 1 ) / 7 + 1, from.date().dayOfWeek() );
01169   mMonthly->setByDay( from.date().day() );
01170 
01171   mYearly->setFrequency( 1 );
01172   mYearly->setByDay( from.date().dayOfYear() );
01173   mYearly->setByPos( ( from.date().day() - 1 ) / 7 + 1,
01174       from.date().dayOfWeek(), from.date().month() );
01175   mYearly->setByMonth( from.date().day(), from.date().month() );
01176 }
01177 
01178 void KOEditorRecurrence::readIncidence(Incidence *incidence)
01179 {
01180   if (!incidence) return;
01181 
01182   QBitArray rDays( 7 );
01183   int day = 0;
01184   int count = 0;
01185   int month = 0;
01186 
01187   if ( incidence->type() == "Todo" ) {
01188     Todo *todo = static_cast<Todo *>(incidence);
01189     setDefaults( todo->dtStart(true), todo->dtDue(), todo->doesFloat() );
01190   } else {
01191     setDefaults( incidence->dtStart(), incidence->dtEnd(), incidence->doesFloat() );
01192   }
01193 
01194   uint recurs = incidence->recurrenceType();
01195   int f = 0;
01196   Recurrence *r = 0;
01197 
01198   if ( recurs ) {
01199     r = incidence->recurrence();
01200     f = r->frequency();
01201   }
01202 
01203   setRecurrenceEnabled( recurs );
01204 
01205   int recurrenceType = RecurrenceChooser::Weekly;
01206 
01207   switch ( recurs ) {
01208     case Recurrence::rNone:
01209       break;
01210     case Recurrence::rDaily:
01211       recurrenceType = RecurrenceChooser::Daily;
01212       mDaily->setFrequency( f );
01213       break;
01214     case Recurrence::rWeekly:
01215       recurrenceType = RecurrenceChooser::Weekly;
01216       mWeekly->setFrequency( f );
01217       mWeekly->setDays( r->days() );
01218       break;
01219     case Recurrence::rMonthlyPos: {
01220       // TODO: we only handle one possibility in the list right now,
01221       // so I have hardcoded calls with first().  If we make the GUI
01222       // more extended, this can be changed.
01223       recurrenceType = RecurrenceChooser::Monthly;
01224 
01225       QValueList<RecurrenceRule::WDayPos> rmp = r->monthPositions();
01226       if ( !rmp.isEmpty() ) {
01227         mMonthly->setByPos( rmp.first().pos(), rmp.first().day() );
01228       }
01229 
01230       mMonthly->setFrequency( f );
01231 
01232       break; }
01233     case Recurrence::rMonthlyDay: {
01234       recurrenceType = RecurrenceChooser::Monthly;
01235 
01236       QValueList<int> rmd = r->monthDays();
01237       // check if we have any setting for which day (vcs import is broken and
01238       // does not set any day, thus we need to check)
01239       if ( rmd.isEmpty() ) {
01240         day = incidence->dtStart().date().day();
01241       } else {
01242         day = rmd.first();
01243       }
01244       mMonthly->setByDay( day );
01245 
01246       mMonthly->setFrequency( f );
01247 
01248       break; }
01249     case Recurrence::rYearlyMonth: {
01250       recurrenceType = RecurrenceChooser::Yearly;
01251       QValueList<int> rmd = r->yearDates();
01252       if ( rmd.isEmpty() ) {
01253         day = incidence->dtStart().date().day();
01254       } else {
01255         day = rmd.first();
01256       }
01257       int month = incidence->dtStart().date().month();
01258       rmd = r->yearMonths();
01259       if ( !rmd.isEmpty() )
01260         month = rmd.first();
01261       mYearly->setByMonth( day, month );
01262       mYearly->setFrequency( f );
01263       break; }
01264     case Recurrence::rYearlyPos: {
01265       recurrenceType = RecurrenceChooser::Yearly;
01266 
01267       QValueList<int> months = r->yearMonths();
01268       if ( months.isEmpty() ) {
01269         month = incidence->dtStart().date().month();
01270       } else {
01271         month = months.first();
01272       }
01273 
01274       QValueList<RecurrenceRule::WDayPos> pos = r->yearPositions();
01275 
01276       if ( pos.isEmpty() ) {
01277         // Use dtStart if nothing is given (shouldn't happen!)
01278         count = ( incidence->dtStart().date().day() - 1 ) / 7;
01279         day = incidence->dtStart().date().dayOfWeek();
01280       } else {
01281         count = pos.first().pos();
01282         day = pos.first().day();
01283       }
01284       mYearly->setByPos( count, day, month );
01285       mYearly->setFrequency( f );
01286       break; }
01287     case Recurrence::rYearlyDay: {
01288       recurrenceType = RecurrenceChooser::Yearly;
01289       QValueList<int> days = r->yearDays();
01290       if ( days.isEmpty() ) {
01291         day = incidence->dtStart().date().dayOfYear();
01292       } else {
01293         day = days.first();
01294       }
01295       mYearly->setByDay( day );
01296 
01297       mYearly->setFrequency( f );
01298       break; }
01299     default:
01300       break;
01301   }
01302 
01303   mRecurrenceChooser->setType( recurrenceType );
01304   showCurrentRule( recurrenceType );
01305 
01306   mRecurrenceRange->setDateTimes( incidence->recurrence()->startDateTime() );
01307 
01308   if ( incidence->doesRecur() ) {
01309     mRecurrenceRange->setDuration( r->duration() );
01310     if ( r->duration() == 0 ) mRecurrenceRange->setEndDate( r->endDate() );
01311   }
01312 
01313   mExceptions->setDates( incidence->recurrence()->exDates() );
01314 }
01315 
01316 void KOEditorRecurrence::writeIncidence( Incidence *incidence )
01317 {
01318   if ( !mEnabledCheck->isChecked() || !isEnabled() )
01319   {
01320     if ( incidence->doesRecur() )
01321       incidence->recurrence()->unsetRecurs();
01322     return;
01323   }
01324 
01325   Recurrence *r = incidence->recurrence();
01326 
01327   // clear out any old settings;
01328   r->unsetRecurs();
01329 
01330   int duration = mRecurrenceRange->duration();
01331   QDate endDate;
01332   if ( duration == 0 ) endDate = mRecurrenceRange->endDate();
01333 
01334   int recurrenceType = mRecurrenceChooser->type();
01335   if ( recurrenceType == RecurrenceChooser::Daily ) {
01336     r->setDaily( mDaily->frequency() );
01337   } else if ( recurrenceType == RecurrenceChooser::Weekly ) {
01338     r->setWeekly( mWeekly->frequency(), mWeekly->days() );
01339   } else if ( recurrenceType == RecurrenceChooser::Monthly ) {
01340     r->setMonthly( mMonthly->frequency() );
01341 
01342     if ( mMonthly->byPos() ) {
01343       int pos = mMonthly->count();
01344 
01345       QBitArray days( 7 );
01346       days.fill( false );
01347       days.setBit( mMonthly->weekday() - 1 );
01348       r->addMonthlyPos( pos, days );
01349     } else {
01350       // it's by day
01351       r->addMonthlyDate( mMonthly->day() );
01352     }
01353   } else if ( recurrenceType == RecurrenceChooser::Yearly ) {
01354     r->setYearly( mYearly->frequency() );
01355 
01356     switch ( mYearly->getType() ) {
01357       case RecurYearly::byMonth:
01358         r->addYearlyDate( mYearly->monthDay() );
01359         r->addYearlyMonth( mYearly->month() );
01360         break;
01361       case RecurYearly::byPos:  {
01362         r->addYearlyMonth( mYearly->posMonth() );
01363         QBitArray days( 7 );
01364         days.fill( false );
01365         days.setBit( mYearly->posWeekday() - 1 );
01366         r->addYearlyPos( mYearly->posCount(), days );
01367         break; }
01368       case RecurYearly::byDay:
01369         r->addYearlyDay( mYearly->day() );
01370         break;
01371     }
01372   } // end "Yearly"
01373 
01374   if ( duration > 0 )
01375     r->setDuration( duration );
01376   else if ( duration == 0 )
01377     r->setEndDate( endDate );
01378   incidence->recurrence()->setExDates( mExceptions->dates() );
01379 }
01380 
01381 void KOEditorRecurrence::setDateTimeStr( const QString &str )
01382 {
01383   mDateTimeLabel->setText( str );
01384 }
01385 
01386 bool KOEditorRecurrence::validateInput()
01387 {
01388   // Check input here.
01389   // Check if the recurrence (if set to end at a date) is scheduled to end before the event starts.
01390   if ( mEnabledCheck->isChecked() && (mRecurrenceRange->duration()==0) &&
01391        mEventStartDt.isValid() && ((mRecurrenceRange->endDate())<mEventStartDt.date()) ) {
01392     KMessageBox::sorry( 0,
01393       i18n("The end date '%1' of the recurrence must be after the start date '%2' of the event.")
01394       .arg( KGlobal::locale()->formatDate( mRecurrenceRange->endDate() ) )
01395       .arg( KGlobal::locale()->formatDate( mEventStartDt.date() ) ) );
01396     return false;
01397   }
01398   int recurrenceType = mRecurrenceChooser->type();
01399   // Check if a weekly recurrence has at least one day selected
01400   // TODO: Get rid of this, it's not really needed (by default the day should be taken from dtStart)
01401   if( mEnabledCheck->isChecked() && recurrenceType == RecurrenceChooser::Weekly ) {
01402     const QBitArray &days = mWeekly->days();
01403     bool valid = false;
01404     for ( int i=0; i<7; ++i ) valid = valid || days.testBit( i );
01405     if ( !valid ) {
01406       KMessageBox::sorry( 0,
01407         i18n("A weekly recurring event or task has to have at least one weekday "
01408              "associated with it.") );
01409       return false;
01410     }
01411   }
01412   return true;
01413 }
01414 
01415 void KOEditorRecurrence::showExceptionsDialog()
01416 {
01417   DateList dates = mExceptions->dates();
01418   int result = mExceptionsDialog->exec();
01419   if ( result == QDialog::Rejected ) mExceptions->setDates( dates );
01420 }
01421 
01422 void KOEditorRecurrence::showRecurrenceRangeDialog()
01423 {
01424   int duration = mRecurrenceRange->duration();
01425   QDate endDate = mRecurrenceRange->endDate();
01426 
01427   int result = mRecurrenceRangeDialog->exec();
01428   if ( result == QDialog::Rejected ) {
01429     mRecurrenceRange->setDuration( duration );
01430     mRecurrenceRange->setEndDate( endDate );
01431   }
01432 }
01433 
01434 bool KOEditorRecurrence::doesRecur()
01435 {
01436   return mEnabledCheck->isChecked();
01437 }
01438 
01439 KOEditorRecurrenceDialog::KOEditorRecurrenceDialog(QWidget * parent)
01440   : KDialogBase( parent, 0, false, i18n("Recurrence"), Ok|Cancel ), mRecurEnabled( false )
01441 {
01442   mRecurrence = new KOEditorRecurrence( this );
01443   setMainWidget( mRecurrence );
01444 }
01445 
01446 void KOEditorRecurrenceDialog::slotOk()
01447 {
01448   mRecurEnabled = mRecurrence->doesRecur();
01449   emit okClicked();
01450   accept();
01451 }
01452 
01453 void KOEditorRecurrenceDialog::slotCancel()
01454 {
01455   mRecurrence->setRecurrenceEnabled( mRecurEnabled );
01456   reject();
01457 }
KDE Home | KDE Accessibility Home | Description of Access Keys