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   // set some initial defaults for the saved recurrence
01079   mSaveRec.setDuration( -1 ); // never ending
01080 }
01081 
01082 KOEditorRecurrence::~KOEditorRecurrence()
01083 {
01084 }
01085 
01086 void KOEditorRecurrence::setRecurrenceEnabled( bool enabled )
01087 {
01088 //  kdDebug(5850) << "KOEditorRecurrence::setRecurrenceEnabled(): " << (enabled ? "on" : "off") << endl;
01089 
01090   mEnabledCheck->setChecked( enabled );
01091   mTimeGroupBox->setEnabled( enabled );
01092   mRuleBox->setEnabled( enabled );
01093   if ( mRecurrenceRangeWidget ) mRecurrenceRangeWidget->setEnabled( enabled );
01094   if ( mRecurrenceRangeButton ) mRecurrenceRangeButton->setEnabled( enabled );
01095   if ( mExceptionsWidget ) mExceptionsWidget->setEnabled( enabled );
01096   if ( mExceptionsButton ) mExceptionsButton->setEnabled( enabled );
01097 }
01098 
01099 void KOEditorRecurrence::showCurrentRule( int current )
01100 {
01101   switch ( current ) {
01102     case Daily:
01103       mRuleStack->raiseWidget( mDaily );
01104       break;
01105     case Weekly:
01106       mRuleStack->raiseWidget( mWeekly );
01107       break;
01108     case Monthly:
01109       mRuleStack->raiseWidget( mMonthly );
01110       break;
01111     default:
01112     case Yearly:
01113       mRuleStack->raiseWidget( mYearly );
01114       break;
01115   }
01116 }
01117 
01118 void KOEditorRecurrence::setDateTimes( const QDateTime &start, const QDateTime &end )
01119 {
01120 //  kdDebug(5850) << "KOEditorRecurrence::setDateTimes" << endl;
01121 
01122   mEventStartDt = start;
01123   mRecurrenceRange->setDateTimes( start, end );
01124   mDaily->setDateTimes( start, end );
01125   mWeekly->setDateTimes( start, end );
01126   mMonthly->setDateTimes( start, end );
01127   mYearly->setDateTimes( start, end );
01128 
01129   // Now set the defaults for all unused types, use the start time for it
01130   bool enabled = mEnabledCheck->isChecked();
01131   int type = mRecurrenceChooser->type();
01132 
01133   if ( !enabled || type != RecurrenceChooser::Weekly ) {
01134     QBitArray days( 7 );
01135     days.fill( 0 );
01136     days.setBit( (start.date().dayOfWeek()+6) % 7 );
01137     mWeekly->setDays( days );
01138   }
01139   if ( !enabled || type != RecurrenceChooser::Monthly ) {
01140     mMonthly->setByPos( ( start.date().day() - 1 ) / 7 + 1, start.date().dayOfWeek() - 1 );
01141     mMonthly->setByDay( start.date().day() );
01142   }
01143   if ( !enabled || type != RecurrenceChooser::Yearly ) {
01144     mYearly->setByDay( start.date().dayOfYear() );
01145     mYearly->setByPos( ( start.date().day() - 1 ) / 7 + 1,
01146         start.date().dayOfWeek() - 1, start.date().month() );
01147     mYearly->setByMonth( start.date().day(), start.date().month() );
01148   }
01149 }
01150 
01151 void KOEditorRecurrence::setDefaults( const QDateTime &from, const QDateTime &to, bool )
01152 {
01153   setDateTimes( from, to );
01154 
01155   setRecurrenceEnabled( false );
01156 
01157   mRecurrenceRange->setDefaults( from );
01158 
01159   mRecurrenceChooser->setType( RecurrenceChooser::Weekly );
01160   showCurrentRule( mRecurrenceChooser->type() );
01161 
01162   mDaily->setFrequency( 1 );
01163 
01164   mWeekly->setFrequency( 1 );
01165   QBitArray days( 7 );
01166   days.fill( 0 );
01167   days.setBit( (from.date().dayOfWeek()+6) % 7 );
01168   mWeekly->setDays( days );
01169 
01170   mMonthly->setFrequency( 1 );
01171   mMonthly->setByPos( ( from.date().day() - 1 ) / 7 + 1, from.date().dayOfWeek() );
01172   mMonthly->setByDay( from.date().day() );
01173 
01174   mYearly->setFrequency( 1 );
01175   mYearly->setByDay( from.date().dayOfYear() );
01176   mYearly->setByPos( ( from.date().day() - 1 ) / 7 + 1,
01177       from.date().dayOfWeek(), from.date().month() );
01178   mYearly->setByMonth( from.date().day(), from.date().month() );
01179 }
01180 
01181 void KOEditorRecurrence::readIncidence(Incidence *incidence)
01182 {
01183   if (!incidence) return;
01184 
01185   QBitArray rDays( 7 );
01186   int day = 0;
01187   int count = 0;
01188   int month = 0;
01189 
01190   if ( incidence->type() == "Todo" ) {
01191     Todo *todo = static_cast<Todo *>(incidence);
01192     setDefaults( todo->dtStart(true), todo->dtDue(), todo->doesFloat() );
01193   } else {
01194     setDefaults( incidence->dtStart(), incidence->dtEnd(), incidence->doesFloat() );
01195   }
01196 
01197   uint recurs = incidence->recurrenceType();
01198   int f = 0;
01199   Recurrence *r = 0;
01200 
01201   if ( recurs ) {
01202     r = incidence->recurrence();
01203     f = r->frequency();
01204   }
01205 
01206   setRecurrenceEnabled( recurs );
01207 
01208   int recurrenceType = RecurrenceChooser::Weekly;
01209 
01210   switch ( recurs ) {
01211     case Recurrence::rNone:
01212       break;
01213     case Recurrence::rDaily:
01214       recurrenceType = RecurrenceChooser::Daily;
01215       mDaily->setFrequency( f );
01216       break;
01217     case Recurrence::rWeekly:
01218       recurrenceType = RecurrenceChooser::Weekly;
01219       mWeekly->setFrequency( f );
01220       mWeekly->setDays( r->days() );
01221       break;
01222     case Recurrence::rMonthlyPos: {
01223       // TODO: we only handle one possibility in the list right now,
01224       // so I have hardcoded calls with first().  If we make the GUI
01225       // more extended, this can be changed.
01226       recurrenceType = RecurrenceChooser::Monthly;
01227 
01228       QValueList<RecurrenceRule::WDayPos> rmp = r->monthPositions();
01229       if ( !rmp.isEmpty() ) {
01230         mMonthly->setByPos( rmp.first().pos(), rmp.first().day() );
01231       }
01232 
01233       mMonthly->setFrequency( f );
01234 
01235       break; }
01236     case Recurrence::rMonthlyDay: {
01237       recurrenceType = RecurrenceChooser::Monthly;
01238 
01239       QValueList<int> rmd = r->monthDays();
01240       // check if we have any setting for which day (vcs import is broken and
01241       // does not set any day, thus we need to check)
01242       if ( rmd.isEmpty() ) {
01243         day = incidence->dtStart().date().day();
01244       } else {
01245         day = rmd.first();
01246       }
01247       mMonthly->setByDay( day );
01248 
01249       mMonthly->setFrequency( f );
01250 
01251       break; }
01252     case Recurrence::rYearlyMonth: {
01253       recurrenceType = RecurrenceChooser::Yearly;
01254       QValueList<int> rmd = r->yearDates();
01255       if ( rmd.isEmpty() ) {
01256         day = incidence->dtStart().date().day();
01257       } else {
01258         day = rmd.first();
01259       }
01260       int month = incidence->dtStart().date().month();
01261       rmd = r->yearMonths();
01262       if ( !rmd.isEmpty() )
01263         month = rmd.first();
01264       mYearly->setByMonth( day, month );
01265       mYearly->setFrequency( f );
01266       break; }
01267     case Recurrence::rYearlyPos: {
01268       recurrenceType = RecurrenceChooser::Yearly;
01269 
01270       QValueList<int> months = r->yearMonths();
01271       if ( months.isEmpty() ) {
01272         month = incidence->dtStart().date().month();
01273       } else {
01274         month = months.first();
01275       }
01276 
01277       QValueList<RecurrenceRule::WDayPos> pos = r->yearPositions();
01278 
01279       if ( pos.isEmpty() ) {
01280         // Use dtStart if nothing is given (shouldn't happen!)
01281         count = ( incidence->dtStart().date().day() - 1 ) / 7;
01282         day = incidence->dtStart().date().dayOfWeek();
01283       } else {
01284         count = pos.first().pos();
01285         day = pos.first().day();
01286       }
01287       mYearly->setByPos( count, day, month );
01288       mYearly->setFrequency( f );
01289       break; }
01290     case Recurrence::rYearlyDay: {
01291       recurrenceType = RecurrenceChooser::Yearly;
01292       QValueList<int> days = r->yearDays();
01293       if ( days.isEmpty() ) {
01294         day = incidence->dtStart().date().dayOfYear();
01295       } else {
01296         day = days.first();
01297       }
01298       mYearly->setByDay( day );
01299 
01300       mYearly->setFrequency( f );
01301       break; }
01302     default:
01303       break;
01304   }
01305 
01306   mRecurrenceChooser->setType( recurrenceType );
01307   showCurrentRule( recurrenceType );
01308 
01309   mRecurrenceRange->setDateTimes( incidence->recurrence()->startDateTime() );
01310 
01311   if ( incidence->doesRecur() ) {
01312     mRecurrenceRange->setDuration( r->duration() );
01313     if ( r->duration() == 0 ) mRecurrenceRange->setEndDate( r->endDate() );
01314   }
01315 
01316   mExceptions->setDates( incidence->recurrence()->exDates() );
01317 }
01318 
01319 void KOEditorRecurrence::writeIncidence( Incidence *incidence )
01320 {
01321   if ( !mEnabledCheck->isChecked() || !isEnabled() )
01322   {
01323     if ( incidence->doesRecur() )
01324       incidence->recurrence()->unsetRecurs();
01325     return;
01326   }
01327 
01328   Recurrence *r = incidence->recurrence();
01329 
01330   // clear out any old settings;
01331   r->unsetRecurs();
01332 
01333   int duration = mRecurrenceRange->duration();
01334   QDate endDate;
01335   if ( duration == 0 ) endDate = mRecurrenceRange->endDate();
01336 
01337   int recurrenceType = mRecurrenceChooser->type();
01338   if ( recurrenceType == RecurrenceChooser::Daily ) {
01339     r->setDaily( mDaily->frequency() );
01340   } else if ( recurrenceType == RecurrenceChooser::Weekly ) {
01341     r->setWeekly( mWeekly->frequency(), mWeekly->days() );
01342   } else if ( recurrenceType == RecurrenceChooser::Monthly ) {
01343     r->setMonthly( mMonthly->frequency() );
01344 
01345     if ( mMonthly->byPos() ) {
01346       int pos = mMonthly->count();
01347 
01348       QBitArray days( 7 );
01349       days.fill( false );
01350       days.setBit( mMonthly->weekday() - 1 );
01351       r->addMonthlyPos( pos, days );
01352     } else {
01353       // it's by day
01354       r->addMonthlyDate( mMonthly->day() );
01355     }
01356   } else if ( recurrenceType == RecurrenceChooser::Yearly ) {
01357     r->setYearly( mYearly->frequency() );
01358 
01359     switch ( mYearly->getType() ) {
01360       case RecurYearly::byMonth:
01361         r->addYearlyDate( mYearly->monthDay() );
01362         r->addYearlyMonth( mYearly->month() );
01363         break;
01364       case RecurYearly::byPos:  {
01365         r->addYearlyMonth( mYearly->posMonth() );
01366         QBitArray days( 7 );
01367         days.fill( false );
01368         days.setBit( mYearly->posWeekday() - 1 );
01369         r->addYearlyPos( mYearly->posCount(), days );
01370         break; }
01371       case RecurYearly::byDay:
01372         r->addYearlyDay( mYearly->day() );
01373         break;
01374     }
01375   } // end "Yearly"
01376 
01377   if ( duration > 0 )
01378     r->setDuration( duration );
01379   else if ( duration == 0 )
01380     r->setEndDate( endDate );
01381   incidence->recurrence()->setExDates( mExceptions->dates() );
01382 }
01383 
01384 void KOEditorRecurrence::setDateTimeStr( const QString &str )
01385 {
01386   mDateTimeLabel->setText( str );
01387 }
01388 
01389 bool KOEditorRecurrence::validateInput()
01390 {
01391   // Check input here.
01392   // Check if the recurrence (if set to end at a date) is scheduled to end before the event starts.
01393   if ( mEnabledCheck->isChecked() && (mRecurrenceRange->duration()==0) &&
01394        mEventStartDt.isValid() && ((mRecurrenceRange->endDate())<mEventStartDt.date()) ) {
01395     KMessageBox::sorry( 0,
01396       i18n("The end date '%1' of the recurrence must be after the start date '%2' of the event.")
01397       .arg( KGlobal::locale()->formatDate( mRecurrenceRange->endDate() ) )
01398       .arg( KGlobal::locale()->formatDate( mEventStartDt.date() ) ) );
01399     return false;
01400   }
01401   int recurrenceType = mRecurrenceChooser->type();
01402   // Check if a weekly recurrence has at least one day selected
01403   // TODO: Get rid of this, it's not really needed (by default the day should be taken from dtStart)
01404   if( mEnabledCheck->isChecked() && recurrenceType == RecurrenceChooser::Weekly ) {
01405     const QBitArray &days = mWeekly->days();
01406     bool valid = false;
01407     for ( int i=0; i<7; ++i ) valid = valid || days.testBit( i );
01408     if ( !valid ) {
01409       KMessageBox::sorry( 0,
01410         i18n("A weekly recurring event or task has to have at least one weekday "
01411              "associated with it.") );
01412       return false;
01413     }
01414   }
01415   return true;
01416 }
01417 
01418 void KOEditorRecurrence::showExceptionsDialog()
01419 {
01420   DateList dates = mExceptions->dates();
01421   int result = mExceptionsDialog->exec();
01422   if ( result == QDialog::Rejected ) mExceptions->setDates( dates );
01423 }
01424 
01425 void KOEditorRecurrence::showRecurrenceRangeDialog()
01426 {
01427   int duration = mRecurrenceRange->duration();
01428   QDate endDate = mRecurrenceRange->endDate();
01429 
01430   int result = mRecurrenceRangeDialog->exec();
01431   if ( result == QDialog::Rejected ) {
01432     mRecurrenceRange->setDuration( duration );
01433     mRecurrenceRange->setEndDate( endDate );
01434   }
01435 }
01436 
01437 bool KOEditorRecurrence::doesRecur()
01438 {
01439   return mEnabledCheck->isChecked();
01440 }
01441 
01442 void KOEditorRecurrence::saveValues()
01443 {
01444   int duration = mRecurrenceRange->duration();
01445   QDate endDate;
01446   if ( duration == 0 ) {
01447     endDate = mRecurrenceRange->endDate();
01448   }
01449 
01450   int recurrenceType = mRecurrenceChooser->type();
01451   if ( recurrenceType == RecurrenceChooser::Daily ) {
01452     mSaveRec.setDaily( mDaily->frequency() );
01453   } else if ( recurrenceType == RecurrenceChooser::Weekly ) {
01454     mSaveRec.setWeekly( mWeekly->frequency(), mWeekly->days() );
01455   } else if ( recurrenceType == RecurrenceChooser::Monthly ) {
01456     mSaveRec.setMonthly( mMonthly->frequency() );
01457 
01458     if ( mMonthly->byPos() ) {
01459       int pos = mMonthly->count();
01460 
01461       QBitArray days( 7 );
01462       days.fill( false );
01463       days.setBit( mMonthly->weekday() - 1 );
01464       mSaveRec.addMonthlyPos( pos, days );
01465     } else {
01466       // it's by day
01467       mSaveRec.addMonthlyDate( mMonthly->day() );
01468     }
01469   } else if ( recurrenceType == RecurrenceChooser::Yearly ) {
01470     mSaveRec.setYearly( mYearly->frequency() );
01471 
01472     switch ( mYearly->getType() ) {
01473     case RecurYearly::byMonth:
01474       mSaveRec.addYearlyDate( mYearly->monthDay() );
01475       mSaveRec.addYearlyMonth( mYearly->month() );
01476       break;
01477 
01478     case RecurYearly::byPos:
01479     {
01480       mSaveRec.addYearlyMonth( mYearly->posMonth() );
01481       QBitArray days( 7 );
01482       days.fill( false );
01483       days.setBit( mYearly->posWeekday() - 1 );
01484       mSaveRec.addYearlyPos( mYearly->posCount(), days );
01485       break;
01486     }
01487 
01488     case RecurYearly::byDay:
01489       mSaveRec.addYearlyDay( mYearly->day() );
01490       break;
01491     }
01492   }
01493 
01494  if ( duration > 0 ) {
01495     mSaveRec.setDuration( duration );
01496   } else if ( duration == 0 ) {
01497     mSaveRec.setEndDate( endDate );
01498   }
01499 
01500   mSaveRec.setExDates( mExceptions->dates() );
01501 }
01502 
01503 void KOEditorRecurrence::restoreValues()
01504 {
01505   QBitArray rDays( 7 );
01506   int day = 0;
01507   int count = 0;
01508   int month = 0;
01509 
01510   if ( mSaveRec.startDateTime().isValid() && mSaveRec.endDateTime().isValid() ) {
01511     setDefaults( mSaveRec.startDateTime(), mSaveRec.endDateTime(), mSaveRec.doesFloat() );
01512   }
01513 
01514   int recurrenceType;
01515   switch ( mSaveRec.recurrenceType() ) {
01516   case Recurrence::rNone:
01517     recurrenceType = RecurrenceChooser::Weekly;
01518     break;
01519 
01520   case Recurrence::rDaily:
01521     recurrenceType = RecurrenceChooser::Daily;
01522     mDaily->setFrequency( mSaveRec.frequency() );
01523     break;
01524 
01525   case Recurrence::rWeekly:
01526     recurrenceType = RecurrenceChooser::Weekly;
01527 
01528     mWeekly->setFrequency( mSaveRec.frequency() );
01529     mWeekly->setDays( mSaveRec.days() );
01530     break;
01531 
01532   case Recurrence::rMonthlyPos:
01533   {
01534     // TODO: we only handle one possibility in the list right now,
01535     // so I have hardcoded calls with first().  If we make the GUI
01536     // more extended, this can be changed.
01537     recurrenceType = RecurrenceChooser::Monthly;
01538 
01539     QValueList<RecurrenceRule::WDayPos> rmp = mSaveRec.monthPositions();
01540     if ( !rmp.isEmpty() ) {
01541       mMonthly->setByPos( rmp.first().pos(), rmp.first().day() );
01542     }
01543     mMonthly->setFrequency( mSaveRec.frequency() );
01544     break;
01545   }
01546 
01547   case Recurrence::rMonthlyDay:
01548   {
01549     recurrenceType = RecurrenceChooser::Monthly;
01550 
01551     QValueList<int> rmd = mSaveRec.monthDays();
01552     // check if we have any setting for which day (vcs import is broken and
01553     // does not set any day, thus we need to check)
01554     if ( !rmd.isEmpty() ) {
01555       day = rmd.first();
01556     }
01557     if ( day > 0 ) {
01558       mMonthly->setByDay( day );
01559       mMonthly->setFrequency( mSaveRec.frequency() );
01560     }
01561     break;
01562   }
01563 
01564   case Recurrence::rYearlyMonth:
01565   {
01566     recurrenceType = RecurrenceChooser::Yearly;
01567 
01568     QValueList<int> rmd = mSaveRec.yearDates();
01569     if ( !rmd.isEmpty() ) {
01570       day = rmd.first();
01571     }
01572     rmd = mSaveRec.yearMonths();
01573     if ( !rmd.isEmpty() ) {
01574       month = rmd.first();
01575     }
01576     if ( day > 0 && month > 0 ) {
01577       mYearly->setByMonth( day, month );
01578       mYearly->setFrequency( mSaveRec.frequency() );
01579     }
01580     break;
01581   }
01582 
01583   case Recurrence::rYearlyPos:
01584   {
01585     recurrenceType = RecurrenceChooser::Yearly;
01586 
01587     QValueList<int> months = mSaveRec.yearMonths();
01588     if ( !months.isEmpty() ) {
01589       month = months.first();
01590     }
01591     QValueList<RecurrenceRule::WDayPos> pos = mSaveRec.yearPositions();
01592     if ( !pos.isEmpty() ) {
01593       count = pos.first().pos();
01594       day = pos.first().day();
01595     }
01596     if ( count > 0 && day > 0 && month > 0 ) {
01597       mYearly->setByPos( count, day, month );
01598       mYearly->setFrequency( mSaveRec.frequency() );
01599     }
01600     break;
01601   }
01602 
01603   case Recurrence::rYearlyDay:
01604   {
01605     recurrenceType = RecurrenceChooser::Yearly;
01606 
01607     QValueList<int> days = mSaveRec.yearDays();
01608     if ( !days.isEmpty() ) {
01609       day = days.first();
01610     }
01611     if ( day > 0 ) {
01612       mYearly->setByDay( day );
01613       mYearly->setFrequency( mSaveRec.frequency() );
01614     }
01615     break;
01616   }
01617   default:
01618     break;
01619   }
01620 
01621   mRecurrenceChooser->setType( recurrenceType );
01622   showCurrentRule( recurrenceType );
01623 
01624   if ( mSaveRec.startDateTime().isValid() ) {
01625     mRecurrenceRange->setDateTimes( mSaveRec.startDateTime() );
01626   }
01627 
01628   mRecurrenceRange->setDuration( mSaveRec.duration() );
01629   if ( mSaveRec.duration() == 0 && mSaveRec.endDate().isValid() ) {
01630     mRecurrenceRange->setEndDate( mSaveRec.endDate() );
01631   }
01632 
01633   mExceptions->setDates( mSaveRec.exDates() );
01634 }
01635 
01636 KOEditorRecurrenceDialog::KOEditorRecurrenceDialog(QWidget * parent)
01637   : KDialogBase( parent, 0, false, i18n("Recurrence"), Ok|Cancel ), mRecurEnabled( false )
01638 {
01639   mRecurrence = new KOEditorRecurrence( this );
01640   setMainWidget( mRecurrence );
01641 }
01642 
01643 void KOEditorRecurrenceDialog::slotOk()
01644 {
01645   mRecurEnabled = mRecurrence->doesRecur();
01646   mRecurrence->saveValues();
01647   emit okClicked(); // tell the incidence editor to update the recurrenceString
01648   accept();
01649 }
01650 
01651 void KOEditorRecurrenceDialog::slotCancel()
01652 {
01653   mRecurrence->setRecurrenceEnabled( mRecurEnabled );
01654   mRecurrence->restoreValues();
01655   reject();
01656 }
KDE Home | KDE Accessibility Home | Description of Access Keys