kalarm

editdlg.cpp

00001 /*
00002  *  editdlg.cpp  -  dialogue to create or modify an alarm or alarm template
00003  *  Program:  kalarm
00004  *  Copyright (c) 2001-2006 by David Jarvie <software@astrojar.org.uk>
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 along
00017  *  with this program; if not, write to the Free Software Foundation, Inc.,
00018  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "kalarm.h"
00022 
00023 #include <limits.h>
00024 
00025 #include <qlayout.h>
00026 #include <qpopupmenu.h>
00027 #include <qvbox.h>
00028 #include <qgroupbox.h>
00029 #include <qwidgetstack.h>
00030 #include <qdragobject.h>
00031 #include <qlabel.h>
00032 #include <qmessagebox.h>
00033 #include <qtabwidget.h>
00034 #include <qvalidator.h>
00035 #include <qwhatsthis.h>
00036 #include <qtooltip.h>
00037 #include <qdir.h>
00038 #include <qstyle.h>
00039 
00040 #include <kglobal.h>
00041 #include <klocale.h>
00042 #include <kconfig.h>
00043 #include <kfiledialog.h>
00044 #include <kiconloader.h>
00045 #include <kio/netaccess.h>
00046 #include <kfileitem.h>
00047 #include <kmessagebox.h>
00048 #include <kurldrag.h>
00049 #include <kurlcompletion.h>
00050 #include <kwin.h>
00051 #include <kwinmodule.h>
00052 #include <kstandarddirs.h>
00053 #include <kstdguiitem.h>
00054 #include <kabc/addresseedialog.h>
00055 #include <kdebug.h>
00056 
00057 #include <libkdepim/maillistdrag.h>
00058 #include <libkdepim/kvcarddrag.h>
00059 #include <libkcal/icaldrag.h>
00060 
00061 #include "alarmcalendar.h"
00062 #include "alarmtimewidget.h"
00063 #include "checkbox.h"
00064 #include "colourcombo.h"
00065 #include "deferdlg.h"
00066 #include "emailidcombo.h"
00067 #include "fontcolourbutton.h"
00068 #include "functions.h"
00069 #include "kalarmapp.h"
00070 #include "kamail.h"
00071 #include "latecancel.h"
00072 #include "lineedit.h"
00073 #include "mainwindow.h"
00074 #include "pickfileradio.h"
00075 #include "preferences.h"
00076 #include "radiobutton.h"
00077 #include "recurrenceedit.h"
00078 #include "reminder.h"
00079 #include "repetition.h"
00080 #include "shellprocess.h"
00081 #include "soundpicker.h"
00082 #include "specialactions.h"
00083 #include "spinbox.h"
00084 #include "templatepickdlg.h"
00085 #include "timeedit.h"
00086 #include "timespinbox.h"
00087 #include "editdlg.moc"
00088 #include "editdlgprivate.moc"
00089 
00090 using namespace KCal;
00091 
00092 static const char EDIT_DIALOG_NAME[] = "EditDialog";
00093 static const int  maxDelayTime = 99*60 + 59;    // < 100 hours
00094 
00095 /*=============================================================================
00096 = Class PickAlarmFileRadio
00097 =============================================================================*/
00098 class PickAlarmFileRadio : public PickFileRadio
00099 {
00100     public:
00101     PickAlarmFileRadio(const QString& text, QButtonGroup* parent, const char* name = 0)
00102         : PickFileRadio(text, parent, name) { }
00103     virtual QString pickFile()    // called when browse button is pressed to select a file to display
00104     {
00105         return KAlarm::browseFile(i18n("Choose Text or Image File to Display"), mDefaultDir, fileEdit()->text(),
00106                                   QString::null, KFile::ExistingOnly, parentWidget(), "pickAlarmFile");
00107     }
00108     private:
00109     QString mDefaultDir;   // default directory for file browse button
00110 };
00111 
00112 /*=============================================================================
00113 = Class PickLogFileRadio
00114 =============================================================================*/
00115 class PickLogFileRadio : public PickFileRadio
00116 {
00117     public:
00118     PickLogFileRadio(QPushButton* b, LineEdit* e, const QString& text, QButtonGroup* parent, const char* name = 0)
00119         : PickFileRadio(b, e, text, parent, name) { }
00120     virtual QString pickFile()    // called when browse button is pressed to select a log file
00121     {
00122         return KAlarm::browseFile(i18n("Choose Log File"), mDefaultDir, fileEdit()->text(), QString::null,
00123                                   KFile::LocalOnly, parentWidget(), "pickLogFile");
00124     }
00125     private:
00126     QString mDefaultDir;   // default directory for log file browse button
00127 };
00128 
00129 inline QString recurText(const KAEvent& event)
00130 {
00131     return QString::fromLatin1("%1 / %2").arg(event.recurrenceText()).arg(event.repetitionText());
00132 }
00133 
00134 // Collect these widget labels together to ensure consistent wording and
00135 // translations across different modules.
00136 QString EditAlarmDlg::i18n_ConfirmAck()         { return i18n("Confirm acknowledgment"); }
00137 QString EditAlarmDlg::i18n_k_ConfirmAck()       { return i18n("Confirm ac&knowledgment"); }
00138 QString EditAlarmDlg::i18n_SpecialActions()     { return i18n("Special Actions..."); }
00139 QString EditAlarmDlg::i18n_ShowInKOrganizer()   { return i18n("Show in KOrganizer"); }
00140 QString EditAlarmDlg::i18n_g_ShowInKOrganizer() { return i18n("Show in KOr&ganizer"); }
00141 QString EditAlarmDlg::i18n_EnterScript()        { return i18n("Enter a script"); }
00142 QString EditAlarmDlg::i18n_p_EnterScript()      { return i18n("Enter a scri&pt"); }
00143 QString EditAlarmDlg::i18n_ExecInTermWindow()   { return i18n("Execute in terminal window"); }
00144 QString EditAlarmDlg::i18n_w_ExecInTermWindow() { return i18n("Execute in terminal &window"); }
00145 QString EditAlarmDlg::i18n_u_ExecInTermWindow() { return i18n("Exec&ute in terminal window"); }
00146 QString EditAlarmDlg::i18n_g_LogToFile()        { return i18n("Lo&g to file"); }
00147 QString EditAlarmDlg::i18n_CopyEmailToSelf()    { return i18n("Copy email to self"); }
00148 QString EditAlarmDlg::i18n_e_CopyEmailToSelf()  { return i18n("Copy &email to self"); }
00149 QString EditAlarmDlg::i18n_s_CopyEmailToSelf()  { return i18n("Copy email to &self"); }
00150 QString EditAlarmDlg::i18n_EmailFrom()          { return i18n("'From' email address", "From:"); }
00151 QString EditAlarmDlg::i18n_f_EmailFrom()        { return i18n("'From' email address", "&From:"); }
00152 QString EditAlarmDlg::i18n_EmailTo()            { return i18n("Email addressee", "To:"); }
00153 QString EditAlarmDlg::i18n_EmailSubject()       { return i18n("Email subject", "Subject:"); }
00154 QString EditAlarmDlg::i18n_j_EmailSubject()     { return i18n("Email subject", "Sub&ject:"); }
00155 
00156 
00157 /******************************************************************************
00158  * Constructor.
00159  * Parameters:
00160  *   Template = true to edit/create an alarm template
00161  *            = false to edit/create an alarm.
00162  *   event   != to initialise the dialogue to show the specified event's data.
00163  */
00164 EditAlarmDlg::EditAlarmDlg(bool Template, const QString& caption, QWidget* parent, const char* name,
00165                            const KAEvent* event, bool readOnly)
00166     : KDialogBase(parent, name, true, caption,
00167                   (readOnly ? Cancel|Try : Template ? Ok|Cancel|Try : Ok|Cancel|Try|Default),
00168                   (readOnly ? Cancel : Ok)),
00169       mMainPageShown(false),
00170       mRecurPageShown(false),
00171       mRecurSetDefaultEndDate(true),
00172       mTemplateName(0),
00173       mSpecialActionsButton(0),
00174       mReminderDeferral(false),
00175       mReminderArchived(false),
00176       mEmailRemoveButton(0),
00177       mDeferGroup(0),
00178       mTimeWidget(0),
00179       mShowInKorganizer(0),
00180       mDeferGroupHeight(0),
00181       mTemplate(Template),
00182       mDesiredReadOnly(readOnly),
00183       mReadOnly(readOnly),
00184       mSavedEvent(0)
00185 {
00186     setButtonText(Default, i18n("Load Template..."));
00187     QVBox* mainWidget = new QVBox(this);
00188     mainWidget->setSpacing(spacingHint());
00189     setMainWidget(mainWidget);
00190     if (mTemplate)
00191     {
00192         QHBox* box = new QHBox(mainWidget);
00193         box->setSpacing(spacingHint());
00194         QLabel* label = new QLabel(i18n("Template name:"), box);
00195         label->setFixedSize(label->sizeHint());
00196         mTemplateName = new QLineEdit(box);
00197         mTemplateName->setReadOnly(mReadOnly);
00198         label->setBuddy(mTemplateName);
00199         QWhatsThis::add(box, i18n("Enter the name of the alarm template"));
00200         box->setFixedHeight(box->sizeHint().height());
00201     }
00202     mTabs = new QTabWidget(mainWidget);
00203     mTabs->setMargin(marginHint());
00204 
00205     QVBox* mainPageBox = new QVBox(mTabs);
00206     mainPageBox->setSpacing(spacingHint());
00207     mTabs->addTab(mainPageBox, i18n("&Alarm"));
00208     mMainPageIndex = 0;
00209     PageFrame* mainPage = new PageFrame(mainPageBox);
00210     connect(mainPage, SIGNAL(shown()), SLOT(slotShowMainPage()));
00211     QVBoxLayout* topLayout = new QVBoxLayout(mainPage, 0, spacingHint());
00212 
00213     // Recurrence tab
00214     QVBox* recurTab = new QVBox(mTabs);
00215     mainPageBox->setSpacing(spacingHint());
00216     mTabs->addTab(recurTab, i18n("&Recurrence"));
00217     mRecurPageIndex = 1;
00218     mRecurrenceEdit = new RecurrenceEdit(readOnly, recurTab, "recurPage");
00219     connect(mRecurrenceEdit, SIGNAL(shown()), SLOT(slotShowRecurrenceEdit()));
00220     connect(mRecurrenceEdit, SIGNAL(typeChanged(int)), SLOT(slotRecurTypeChange(int)));
00221     connect(mRecurrenceEdit, SIGNAL(frequencyChanged()), SLOT(slotRecurFrequencyChange()));
00222 
00223     // Alarm action
00224 
00225     mActionGroup = new ButtonGroup(i18n("Action"), mainPage, "actionGroup");
00226     connect(mActionGroup, SIGNAL(buttonSet(int)), SLOT(slotAlarmTypeChanged(int)));
00227     topLayout->addWidget(mActionGroup, 1);
00228     QGridLayout* grid = new QGridLayout(mActionGroup, 3, 5, marginHint(), spacingHint());
00229     grid->addRowSpacing(0, fontMetrics().lineSpacing()/2);
00230 
00231     // Message radio button
00232     mMessageRadio = new RadioButton(i18n("Te&xt"), mActionGroup, "messageButton");
00233     mMessageRadio->setFixedSize(mMessageRadio->sizeHint());
00234     QWhatsThis::add(mMessageRadio,
00235           i18n("If checked, the alarm will display a text message."));
00236     grid->addWidget(mMessageRadio, 1, 0);
00237     grid->setColStretch(1, 1);
00238 
00239     // File radio button
00240     mFileRadio = new PickAlarmFileRadio(i18n("&File"), mActionGroup, "fileButton");
00241     mFileRadio->setFixedSize(mFileRadio->sizeHint());
00242     QWhatsThis::add(mFileRadio,
00243           i18n("If checked, the alarm will display the contents of a text or image file."));
00244     grid->addWidget(mFileRadio, 1, 2);
00245     grid->setColStretch(3, 1);
00246 
00247     // Command radio button
00248     mCommandRadio = new RadioButton(i18n("Co&mmand"), mActionGroup, "cmdButton");
00249     mCommandRadio->setFixedSize(mCommandRadio->sizeHint());
00250     QWhatsThis::add(mCommandRadio,
00251           i18n("If checked, the alarm will execute a shell command."));
00252     grid->addWidget(mCommandRadio, 1, 4);
00253     grid->setColStretch(5, 1);
00254 
00255     // Email radio button
00256     mEmailRadio = new RadioButton(i18n("&Email"), mActionGroup, "emailButton");
00257     mEmailRadio->setFixedSize(mEmailRadio->sizeHint());
00258     QWhatsThis::add(mEmailRadio,
00259           i18n("If checked, the alarm will send an email."));
00260     grid->addWidget(mEmailRadio, 1, 6);
00261 
00262     initDisplayAlarms(mActionGroup);
00263     initCommand(mActionGroup);
00264     initEmail(mActionGroup);
00265     mAlarmTypeStack = new QWidgetStack(mActionGroup);
00266     grid->addMultiCellWidget(mAlarmTypeStack, 2, 2, 0, 6);
00267     grid->setRowStretch(2, 1);
00268     mAlarmTypeStack->addWidget(mDisplayAlarmsFrame, 0);
00269     mAlarmTypeStack->addWidget(mCommandFrame, 1);
00270     mAlarmTypeStack->addWidget(mEmailFrame, 1);
00271 
00272     // Deferred date/time: visible only for a deferred recurring event.
00273     mDeferGroup = new QGroupBox(1, Qt::Vertical, i18n("Deferred Alarm"), mainPage, "deferGroup");
00274     topLayout->addWidget(mDeferGroup);
00275     QLabel* label = new QLabel(i18n("Deferred to:"), mDeferGroup);
00276     label->setFixedSize(label->sizeHint());
00277     mDeferTimeLabel = new QLabel(mDeferGroup);
00278 
00279     mDeferChangeButton = new QPushButton(i18n("C&hange..."), mDeferGroup);
00280     mDeferChangeButton->setFixedSize(mDeferChangeButton->sizeHint());
00281     connect(mDeferChangeButton, SIGNAL(clicked()), SLOT(slotEditDeferral()));
00282     QWhatsThis::add(mDeferChangeButton, i18n("Change the alarm's deferred time, or cancel the deferral"));
00283     mDeferGroup->addSpace(0);
00284 
00285     QBoxLayout* layout = new QHBoxLayout(topLayout);
00286 
00287     // Date and time entry
00288     if (mTemplate)
00289     {
00290         mTemplateTimeGroup = new ButtonGroup(i18n("Time"), mainPage, "templateGroup");
00291         connect(mTemplateTimeGroup, SIGNAL(buttonSet(int)), SLOT(slotTemplateTimeType(int)));
00292         layout->addWidget(mTemplateTimeGroup);
00293         grid = new QGridLayout(mTemplateTimeGroup, 2, 2, marginHint(), spacingHint());
00294         grid->addRowSpacing(0, fontMetrics().lineSpacing()/2);
00295         // Get alignment to use in QGridLayout (AlignAuto doesn't work correctly there)
00296         int alignment = QApplication::reverseLayout() ? Qt::AlignRight : Qt::AlignLeft;
00297 
00298         mTemplateDefaultTime = new RadioButton(i18n("&Default time"), mTemplateTimeGroup, "templateDefTimeButton");
00299         mTemplateDefaultTime->setFixedSize(mTemplateDefaultTime->sizeHint());
00300         mTemplateDefaultTime->setReadOnly(mReadOnly);
00301         QWhatsThis::add(mTemplateDefaultTime,
00302               i18n("Do not specify a start time for alarms based on this template. "
00303                    "The normal default start time will be used."));
00304         grid->addWidget(mTemplateDefaultTime, 0, 0, alignment);
00305 
00306         QHBox* box = new QHBox(mTemplateTimeGroup);
00307         box->setSpacing(spacingHint());
00308         mTemplateUseTime = new RadioButton(i18n("Time:"), box, "templateTimeButton");
00309         mTemplateUseTime->setFixedSize(mTemplateUseTime->sizeHint());
00310         mTemplateUseTime->setReadOnly(mReadOnly);
00311         QWhatsThis::add(mTemplateUseTime,
00312               i18n("Specify a start time for alarms based on this template."));
00313         mTemplateTimeGroup->insert(mTemplateUseTime);
00314         mTemplateTime = new TimeEdit(box, "templateTimeEdit");
00315         mTemplateTime->setFixedSize(mTemplateTime->sizeHint());
00316         mTemplateTime->setReadOnly(mReadOnly);
00317         QWhatsThis::add(mTemplateTime,
00318               QString("%1\n\n%2").arg(i18n("Enter the start time for alarms based on this template."))
00319                                  .arg(TimeSpinBox::shiftWhatsThis()));
00320         box->setStretchFactor(new QWidget(box), 1);    // left adjust the controls
00321         box->setFixedHeight(box->sizeHint().height());
00322         grid->addWidget(box, 0, 1, alignment);
00323 
00324         mTemplateAnyTime = new RadioButton(i18n("An&y time"), mTemplateTimeGroup, "templateAnyTimeButton");
00325         mTemplateAnyTime->setFixedSize(mTemplateAnyTime->sizeHint());
00326         mTemplateAnyTime->setReadOnly(mReadOnly);
00327         QWhatsThis::add(mTemplateAnyTime,
00328               i18n("Set the '%1' option for alarms based on this template.").arg(i18n("Any time")));
00329         grid->addWidget(mTemplateAnyTime, 1, 0, alignment);
00330 
00331         box = new QHBox(mTemplateTimeGroup);
00332         box->setSpacing(spacingHint());
00333         mTemplateUseTimeAfter = new RadioButton(AlarmTimeWidget::i18n_w_TimeFromNow(), box, "templateFromNowButton");
00334         mTemplateUseTimeAfter->setFixedSize(mTemplateUseTimeAfter->sizeHint());
00335         mTemplateUseTimeAfter->setReadOnly(mReadOnly);
00336         QWhatsThis::add(mTemplateUseTimeAfter,
00337               i18n("Set alarms based on this template to start after the specified time "
00338                    "interval from when the alarm is created."));
00339         mTemplateTimeGroup->insert(mTemplateUseTimeAfter);
00340         mTemplateTimeAfter = new TimeSpinBox(1, maxDelayTime, box);
00341         mTemplateTimeAfter->setValue(1439);
00342         mTemplateTimeAfter->setFixedSize(mTemplateTimeAfter->sizeHint());
00343         mTemplateTimeAfter->setReadOnly(mReadOnly);
00344         QWhatsThis::add(mTemplateTimeAfter,
00345               QString("%1\n\n%2").arg(AlarmTimeWidget::i18n_TimeAfterPeriod())
00346                                  .arg(TimeSpinBox::shiftWhatsThis()));
00347         box->setFixedHeight(box->sizeHint().height());
00348         grid->addWidget(box, 1, 1, alignment);
00349 
00350         layout->addStretch();
00351     }
00352     else
00353     {
00354         mTimeWidget = new AlarmTimeWidget(i18n("Time"), AlarmTimeWidget::AT_TIME, mainPage, "timeGroup");
00355         connect(mTimeWidget, SIGNAL(anyTimeToggled(bool)), SLOT(slotAnyTimeToggled(bool)));
00356         topLayout->addWidget(mTimeWidget);
00357     }
00358 
00359     // Recurrence type display
00360     layout = new QHBoxLayout(topLayout, 2*spacingHint());
00361     QHBox* box = new QHBox(mainPage);   // this is to control the QWhatsThis text display area
00362     box->setSpacing(KDialog::spacingHint());
00363     label = new QLabel(i18n("Recurrence:"), box);
00364     label->setFixedSize(label->sizeHint());
00365     mRecurrenceText = new QLabel(box);
00366     QWhatsThis::add(box,
00367           i18n("How often the alarm recurs.\nThe times shown are those configured in the Recurrence tab and in the Simple Repetition dialog."));
00368     box->setFixedHeight(box->sizeHint().height());
00369     layout->addWidget(box);
00370 
00371     // Simple repetition button
00372     mSimpleRepetition = new RepetitionButton(i18n("Simple Repetition"), true, mainPage);
00373     mSimpleRepetition->setFixedSize(mSimpleRepetition->sizeHint());
00374     connect(mSimpleRepetition, SIGNAL(needsInitialisation()), SLOT(slotSetSimpleRepetition()));
00375     connect(mSimpleRepetition, SIGNAL(changed()), SLOT(slotRecurFrequencyChange()));
00376     QWhatsThis::add(mSimpleRepetition, i18n("Set up a simple, or additional, alarm repetition"));
00377     layout->addWidget(mSimpleRepetition);
00378 
00379     if (theApp()->korganizerEnabled())
00380     {
00381         // Show in KOrganizer checkbox
00382         mShowInKorganizer = new CheckBox(i18n_ShowInKOrganizer(), mainPage);
00383         mShowInKorganizer->setFixedSize(mShowInKorganizer->sizeHint());
00384         QWhatsThis::add(mShowInKorganizer, i18n("Check to copy the alarm into KOrganizer's calendar"));
00385         layout->addWidget(mShowInKorganizer);
00386     }
00387     layout->addStretch();
00388 
00389     // Late cancel selector - default = allow late display
00390     mLateCancel = new LateCancelSelector(true, mainPage);
00391     topLayout->addWidget(mLateCancel, 0, Qt::AlignAuto);
00392 
00393     setButtonWhatsThis(Ok, i18n("Schedule the alarm at the specified time."));
00394 
00395     // Initialise the state of all controls according to the specified event, if any
00396     initialise(event);
00397     if (mTemplateName)
00398         mTemplateName->setFocus();
00399 
00400     // Save the initial state of all controls so that we can later tell if they have changed
00401     saveState((event && (mTemplate || !event->isTemplate())) ? event : 0);
00402 
00403     // Note the current desktop so that the dialog can be shown on it.
00404     // If a main window is visible, the dialog will by KDE default always appear on its
00405     // desktop. If the user invokes the dialog via the system tray on a different desktop,
00406     // that can cause confusion.
00407     mDesktop = KWin::currentDesktop();
00408 }
00409 
00410 EditAlarmDlg::~EditAlarmDlg()
00411 {
00412     delete mSavedEvent;
00413 }
00414 
00415 /******************************************************************************
00416  * Set up the dialog controls common to display alarms.
00417  */
00418 void EditAlarmDlg::initDisplayAlarms(QWidget* parent)
00419 {
00420     mDisplayAlarmsFrame = new QFrame(parent);
00421     mDisplayAlarmsFrame->setFrameStyle(QFrame::NoFrame);
00422     QBoxLayout* frameLayout = new QVBoxLayout(mDisplayAlarmsFrame, 0, spacingHint());
00423 
00424     // Text message edit box
00425     mTextMessageEdit = new TextEdit(mDisplayAlarmsFrame);
00426     mTextMessageEdit->setWordWrap(QTextEdit::NoWrap);
00427     QWhatsThis::add(mTextMessageEdit, i18n("Enter the text of the alarm message. It may be multi-line."));
00428     frameLayout->addWidget(mTextMessageEdit);
00429 
00430     // File name edit box
00431     mFileBox = new QHBox(mDisplayAlarmsFrame);
00432     frameLayout->addWidget(mFileBox);
00433     mFileMessageEdit = new LineEdit(LineEdit::Url, mFileBox);
00434     mFileMessageEdit->setAcceptDrops(true);
00435     QWhatsThis::add(mFileMessageEdit, i18n("Enter the name or URL of a text or image file to display."));
00436 
00437     // File browse button
00438     mFileBrowseButton = new QPushButton(mFileBox);
00439     mFileBrowseButton->setPixmap(SmallIcon("fileopen"));
00440     mFileBrowseButton->setFixedSize(mFileBrowseButton->sizeHint());
00441     QToolTip::add(mFileBrowseButton, i18n("Choose a file"));
00442     QWhatsThis::add(mFileBrowseButton, i18n("Select a text or image file to display."));
00443     mFileRadio->init(mFileBrowseButton, mFileMessageEdit);
00444 
00445     // Colour choice drop-down list
00446     QBoxLayout* layout = new QHBoxLayout(frameLayout);
00447     QHBox* box;
00448     mBgColourChoose = createBgColourChooser(&box, mDisplayAlarmsFrame);
00449     mBgColourChoose->setFixedSize(mBgColourChoose->sizeHint());
00450     connect(mBgColourChoose, SIGNAL(highlighted(const QColor&)), SLOT(slotBgColourSelected(const QColor&)));
00451     layout->addWidget(box);
00452     layout->addSpacing(2*KDialog::spacingHint());
00453     layout->addStretch();
00454 
00455     // Font and colour choice drop-down list
00456     mFontColourButton = new FontColourButton(mDisplayAlarmsFrame);
00457     mFontColourButton->setFixedSize(mFontColourButton->sizeHint());
00458     connect(mFontColourButton, SIGNAL(selected()), SLOT(slotFontColourSelected()));
00459     layout->addWidget(mFontColourButton);
00460 
00461     // Sound checkbox and file selector
00462     mSoundPicker = new SoundPicker(mDisplayAlarmsFrame);
00463     mSoundPicker->setFixedSize(mSoundPicker->sizeHint());
00464     frameLayout->addWidget(mSoundPicker, 0, Qt::AlignAuto);
00465 
00466     // Reminder
00467     static const QString reminderText = i18n("Enter how long in advance of the main alarm to display a reminder alarm.");
00468     mReminder = new Reminder(i18n("Rem&inder:"),
00469                              i18n("Check to additionally display a reminder in advance of the main alarm time(s)."),
00470                              QString("%1\n\n%2").arg(reminderText).arg(TimeSpinBox::shiftWhatsThis()),
00471                              true, true, mDisplayAlarmsFrame);
00472     mReminder->setFixedSize(mReminder->sizeHint());
00473     frameLayout->addWidget(mReminder, 0, Qt::AlignAuto);
00474 
00475     // Acknowledgement confirmation required - default = no confirmation
00476     layout = new QHBoxLayout(frameLayout);
00477     mConfirmAck = createConfirmAckCheckbox(mDisplayAlarmsFrame);
00478     mConfirmAck->setFixedSize(mConfirmAck->sizeHint());
00479     layout->addWidget(mConfirmAck);
00480     layout->addSpacing(2*KDialog::spacingHint());
00481     layout->addStretch();
00482 
00483     if (ShellProcess::authorised())    // don't display if shell commands not allowed (e.g. kiosk mode)
00484     {
00485         // Special actions button
00486         mSpecialActionsButton = new SpecialActionsButton(i18n_SpecialActions(), mDisplayAlarmsFrame);
00487         mSpecialActionsButton->setFixedSize(mSpecialActionsButton->sizeHint());
00488         layout->addWidget(mSpecialActionsButton);
00489     }
00490 
00491     // Top-adjust the controls
00492     mFilePadding = new QHBox(mDisplayAlarmsFrame);
00493     frameLayout->addWidget(mFilePadding);
00494     frameLayout->setStretchFactor(mFilePadding, 1);
00495 }
00496 
00497 /******************************************************************************
00498  * Set up the command alarm dialog controls.
00499  */
00500 void EditAlarmDlg::initCommand(QWidget* parent)
00501 {
00502     mCommandFrame = new QFrame(parent);
00503     mCommandFrame->setFrameStyle(QFrame::NoFrame);
00504     QBoxLayout* frameLayout = new QVBoxLayout(mCommandFrame, 0, spacingHint());
00505 
00506     mCmdTypeScript = new CheckBox(i18n_p_EnterScript(), mCommandFrame);
00507     mCmdTypeScript->setFixedSize(mCmdTypeScript->sizeHint());
00508     connect(mCmdTypeScript, SIGNAL(toggled(bool)), SLOT(slotCmdScriptToggled(bool)));
00509     QWhatsThis::add(mCmdTypeScript, i18n("Check to enter the contents of a script instead of a shell command line"));
00510     frameLayout->addWidget(mCmdTypeScript, 0, Qt::AlignAuto);
00511 
00512     mCmdCommandEdit = new LineEdit(LineEdit::Url, mCommandFrame);
00513     QWhatsThis::add(mCmdCommandEdit, i18n("Enter a shell command to execute."));
00514     frameLayout->addWidget(mCmdCommandEdit);
00515 
00516     mCmdScriptEdit = new TextEdit(mCommandFrame);
00517     QWhatsThis::add(mCmdScriptEdit, i18n("Enter the contents of a script to execute"));
00518     frameLayout->addWidget(mCmdScriptEdit);
00519 
00520     // What to do with command output
00521 
00522     mCmdOutputGroup = new ButtonGroup(i18n("Command Output"), mCommandFrame);
00523     frameLayout->addWidget(mCmdOutputGroup);
00524     QBoxLayout* layout = new QVBoxLayout(mCmdOutputGroup, marginHint(), spacingHint());
00525     layout->addSpacing(fontMetrics().lineSpacing()/2);
00526 
00527     // Execute in terminal window
00528     RadioButton* button = new RadioButton(i18n_u_ExecInTermWindow(), mCmdOutputGroup, "execInTerm");
00529     button->setFixedSize(button->sizeHint());
00530     QWhatsThis::add(button, i18n("Check to execute the command in a terminal window"));
00531     mCmdOutputGroup->insert(button, EXEC_IN_TERMINAL);
00532     layout->addWidget(button, 0, Qt::AlignAuto);
00533 
00534     // Log file name edit box
00535     QHBox* box = new QHBox(mCmdOutputGroup);
00536     (new QWidget(box))->setFixedWidth(button->style().subRect(QStyle::SR_RadioButtonIndicator, button).width());   // indent the edit box
00537 //  (new QWidget(box))->setFixedWidth(button->style().pixelMetric(QStyle::PM_ExclusiveIndicatorWidth));   // indent the edit box
00538     mCmdLogFileEdit = new LineEdit(LineEdit::Url, box);
00539     mCmdLogFileEdit->setAcceptDrops(true);
00540     QWhatsThis::add(mCmdLogFileEdit, i18n("Enter the name or path of the log file."));
00541 
00542     // Log file browse button.
00543     // The file browser dialogue is activated by the PickLogFileRadio class.
00544     QPushButton* browseButton = new QPushButton(box);
00545     browseButton->setPixmap(SmallIcon("fileopen"));
00546     browseButton->setFixedSize(browseButton->sizeHint());
00547     QToolTip::add(browseButton, i18n("Choose a file"));
00548     QWhatsThis::add(browseButton, i18n("Select a log file."));
00549 
00550     // Log output to file
00551     button = new PickLogFileRadio(browseButton, mCmdLogFileEdit, i18n_g_LogToFile(), mCmdOutputGroup, "cmdLog");
00552     button->setFixedSize(button->sizeHint());
00553     QWhatsThis::add(button,
00554           i18n("Check to log the command output to a local file. The output will be appended to any existing contents of the file."));
00555     mCmdOutputGroup->insert(button, LOG_TO_FILE);
00556     layout->addWidget(button, 0, Qt::AlignAuto);
00557     layout->addWidget(box);
00558 
00559     // Discard output
00560     button = new RadioButton(i18n("Discard"), mCmdOutputGroup, "cmdDiscard");
00561     button->setFixedSize(button->sizeHint());
00562     QWhatsThis::add(button, i18n("Check to discard command output."));
00563     mCmdOutputGroup->insert(button, DISCARD_OUTPUT);
00564     layout->addWidget(button, 0, Qt::AlignAuto);
00565 
00566     // Top-adjust the controls
00567     mCmdPadding = new QHBox(mCommandFrame);
00568     frameLayout->addWidget(mCmdPadding);
00569     frameLayout->setStretchFactor(mCmdPadding, 1);
00570 }
00571 
00572 /******************************************************************************
00573  * Set up the email alarm dialog controls.
00574  */
00575 void EditAlarmDlg::initEmail(QWidget* parent)
00576 {
00577     mEmailFrame = new QFrame(parent);
00578     mEmailFrame->setFrameStyle(QFrame::NoFrame);
00579     QBoxLayout* layout = new QVBoxLayout(mEmailFrame, 0, spacingHint());
00580     QGridLayout* grid = new QGridLayout(layout, 3, 3, spacingHint());
00581     grid->setColStretch(1, 1);
00582 
00583     mEmailFromList = 0;
00584     if (Preferences::emailFrom() == Preferences::MAIL_FROM_KMAIL)
00585     {
00586         // Email sender identity
00587         QLabel* label = new QLabel(i18n_EmailFrom(), mEmailFrame);
00588         label->setFixedSize(label->sizeHint());
00589         grid->addWidget(label, 0, 0);
00590 
00591         mEmailFromList = new EmailIdCombo(KAMail::identityManager(), mEmailFrame);
00592         mEmailFromList->setMinimumSize(mEmailFromList->sizeHint());
00593         label->setBuddy(mEmailFromList);
00594         QWhatsThis::add(mEmailFromList,
00595               i18n("Your email identity, used to identify you as the sender when sending email alarms."));
00596         grid->addMultiCellWidget(mEmailFromList, 0, 0, 1, 2);
00597     }
00598 
00599     // Email recipients
00600     QLabel* label = new QLabel(i18n_EmailTo(), mEmailFrame);
00601     label->setFixedSize(label->sizeHint());
00602     grid->addWidget(label, 1, 0);
00603 
00604     mEmailToEdit = new LineEdit(LineEdit::Emails, mEmailFrame);
00605     mEmailToEdit->setMinimumSize(mEmailToEdit->sizeHint());
00606     QWhatsThis::add(mEmailToEdit,
00607           i18n("Enter the addresses of the email recipients. Separate multiple addresses by "
00608                "commas or semicolons."));
00609     grid->addWidget(mEmailToEdit, 1, 1);
00610 
00611     mEmailAddressButton = new QPushButton(mEmailFrame);
00612     mEmailAddressButton->setPixmap(SmallIcon("contents"));
00613     mEmailAddressButton->setFixedSize(mEmailAddressButton->sizeHint());
00614     connect(mEmailAddressButton, SIGNAL(clicked()), SLOT(openAddressBook()));
00615     QToolTip::add(mEmailAddressButton, i18n("Open address book"));
00616     QWhatsThis::add(mEmailAddressButton, i18n("Select email addresses from your address book."));
00617     grid->addWidget(mEmailAddressButton, 1, 2);
00618 
00619     // Email subject
00620     label = new QLabel(i18n_j_EmailSubject(), mEmailFrame);
00621     label->setFixedSize(label->sizeHint());
00622     grid->addWidget(label, 2, 0);
00623 
00624     mEmailSubjectEdit = new LineEdit(mEmailFrame);
00625     mEmailSubjectEdit->setMinimumSize(mEmailSubjectEdit->sizeHint());
00626     label->setBuddy(mEmailSubjectEdit);
00627     QWhatsThis::add(mEmailSubjectEdit, i18n("Enter the email subject."));
00628     grid->addMultiCellWidget(mEmailSubjectEdit, 2, 2, 1, 2);
00629 
00630     // Email body
00631     mEmailMessageEdit = new TextEdit(mEmailFrame);
00632     QWhatsThis::add(mEmailMessageEdit, i18n("Enter the email message."));
00633     layout->addWidget(mEmailMessageEdit);
00634 
00635     // Email attachments
00636     grid = new QGridLayout(layout, 2, 3, spacingHint());
00637     label = new QLabel(i18n("Attachment&s:"), mEmailFrame);
00638     label->setFixedSize(label->sizeHint());
00639     grid->addWidget(label, 0, 0);
00640 
00641     mEmailAttachList = new QComboBox(true, mEmailFrame);
00642     mEmailAttachList->setMinimumSize(mEmailAttachList->sizeHint());
00643     mEmailAttachList->lineEdit()->setReadOnly(true);
00644 QListBox* list = mEmailAttachList->listBox();
00645 QRect rect = list->geometry();
00646 list->setGeometry(rect.left() - 50, rect.top(), rect.width(), rect.height());
00647     label->setBuddy(mEmailAttachList);
00648     QWhatsThis::add(mEmailAttachList,
00649           i18n("Files to send as attachments to the email."));
00650     grid->addWidget(mEmailAttachList, 0, 1);
00651     grid->setColStretch(1, 1);
00652 
00653     mEmailAddAttachButton = new QPushButton(i18n("Add..."), mEmailFrame);
00654     connect(mEmailAddAttachButton, SIGNAL(clicked()), SLOT(slotAddAttachment()));
00655     QWhatsThis::add(mEmailAddAttachButton, i18n("Add an attachment to the email."));
00656     grid->addWidget(mEmailAddAttachButton, 0, 2);
00657 
00658     mEmailRemoveButton = new QPushButton(i18n("Remo&ve"), mEmailFrame);
00659     connect(mEmailRemoveButton, SIGNAL(clicked()), SLOT(slotRemoveAttachment()));
00660     QWhatsThis::add(mEmailRemoveButton, i18n("Remove the highlighted attachment from the email."));
00661     grid->addWidget(mEmailRemoveButton, 1, 2);
00662 
00663     // BCC email to sender
00664     mEmailBcc = new CheckBox(i18n_s_CopyEmailToSelf(), mEmailFrame);
00665     mEmailBcc->setFixedSize(mEmailBcc->sizeHint());
00666     QWhatsThis::add(mEmailBcc,
00667           i18n("If checked, the email will be blind copied to you."));
00668     grid->addMultiCellWidget(mEmailBcc, 1, 1, 0, 1, Qt::AlignAuto);
00669 }
00670 
00671 /******************************************************************************
00672  * Initialise the dialogue controls from the specified event.
00673  */
00674 void EditAlarmDlg::initialise(const KAEvent* event)
00675 {
00676     mReadOnly = mDesiredReadOnly;
00677     if (!mTemplate  &&  event  &&  event->action() == KAEvent::COMMAND  &&  !ShellProcess::authorised())
00678         mReadOnly = true;     // don't allow editing of existing command alarms in kiosk mode
00679     setReadOnly();
00680 
00681     mChanged           = false;
00682     mOnlyDeferred      = false;
00683     mExpiredRecurrence = false;
00684     mKMailSerialNumber = 0;
00685     bool deferGroupVisible = false;
00686     if (event)
00687     {
00688         // Set the values to those for the specified event
00689         if (mTemplate)
00690             mTemplateName->setText(event->templateName());
00691         bool recurs = event->recurs();
00692         if ((recurs || event->repeatCount())  &&  !mTemplate  &&  event->deferred())
00693         {
00694             deferGroupVisible = true;
00695             mDeferDateTime = event->deferDateTime();
00696             mDeferTimeLabel->setText(mDeferDateTime.formatLocale());
00697             mDeferGroup->show();
00698         }
00699         if (event->defaultFont())
00700             mFontColourButton->setDefaultFont();
00701         else
00702             mFontColourButton->setFont(event->font());
00703         mFontColourButton->setBgColour(event->bgColour());
00704         mFontColourButton->setFgColour(event->fgColour());
00705         mBgColourChoose->setColour(event->bgColour());     // set colour before setting alarm type buttons
00706         if (mTemplate)
00707         {
00708             // Editing a template
00709             int afterTime = event->isTemplate() ? event->templateAfterTime() : -1;
00710             bool noTime   = !afterTime;
00711             bool useTime  = !event->mainDateTime().isDateOnly();
00712             int button = mTemplateTimeGroup->id(noTime          ? mTemplateDefaultTime :
00713                                                 (afterTime > 0) ? mTemplateUseTimeAfter :
00714                                                 useTime         ? mTemplateUseTime : mTemplateAnyTime);
00715             mTemplateTimeGroup->setButton(button);
00716             mTemplateTimeAfter->setValue(afterTime > 0 ? afterTime : 1);
00717             if (!noTime && useTime)
00718                 mTemplateTime->setValue(event->mainDateTime().time());
00719             else
00720                 mTemplateTime->setValue(0);
00721         }
00722         else
00723         {
00724             if (event->isTemplate())
00725             {
00726                 // Initialising from an alarm template: use current date
00727                 QDateTime now = QDateTime::currentDateTime();
00728                 int afterTime = event->templateAfterTime();
00729                 if (afterTime >= 0)
00730                 {
00731                     mTimeWidget->setDateTime(now.addSecs(afterTime * 60));
00732                     mTimeWidget->selectTimeFromNow();
00733                 }
00734                 else
00735                 {
00736                     QDate d = now.date();
00737                     QTime t = event->startDateTime().time();
00738                     bool dateOnly = event->startDateTime().isDateOnly();
00739                     if (!dateOnly  &&  now.time() >= t)
00740                         d = d.addDays(1);     // alarm time has already passed, so use tomorrow
00741                     mTimeWidget->setDateTime(DateTime(QDateTime(d, t), dateOnly));
00742                 }
00743             }
00744             else
00745             {
00746                 mExpiredRecurrence = recurs && event->mainExpired();
00747                 mTimeWidget->setDateTime(!event->mainExpired() ? event->mainDateTime()
00748                                          : recurs ? DateTime() : event->deferDateTime());
00749             }
00750         }
00751 
00752         KAEvent::Action action = event->action();
00753         AlarmText altext;
00754         if (event->commandScript())
00755             altext.setScript(event->cleanText());
00756         else
00757             altext.setText(event->cleanText());
00758         setAction(action, altext);
00759         if (action == KAEvent::MESSAGE  &&  event->kmailSerialNumber()
00760         &&  AlarmText::checkIfEmail(event->cleanText()))
00761             mKMailSerialNumber = event->kmailSerialNumber();
00762         if (action == KAEvent::EMAIL)
00763             mEmailAttachList->insertStringList(event->emailAttachments());
00764 
00765         mLateCancel->setMinutes(event->lateCancel(), event->startDateTime().isDateOnly(),
00766                                 TimePeriod::HOURS_MINUTES);
00767         mLateCancel->showAutoClose(action == KAEvent::MESSAGE || action == KAEvent::FILE);
00768         mLateCancel->setAutoClose(event->autoClose());
00769         mLateCancel->setFixedSize(mLateCancel->sizeHint());
00770         if (mShowInKorganizer)
00771             mShowInKorganizer->setChecked(event->copyToKOrganizer());
00772         mConfirmAck->setChecked(event->confirmAck());
00773         int reminder = event->reminder();
00774         if (!reminder  &&  event->reminderDeferral()  &&  !recurs)
00775         {
00776             reminder = event->reminderDeferral();
00777             mReminderDeferral = true;
00778         }
00779         if (!reminder  &&  event->reminderArchived()  &&  recurs)
00780         {
00781             reminder = event->reminderArchived();
00782             mReminderArchived = true;
00783         }
00784         mReminder->setMinutes(reminder, (mTimeWidget ? mTimeWidget->anyTime() : mTemplateAnyTime->isOn()));
00785         mReminder->setOnceOnly(event->reminderOnceOnly());
00786         mReminder->enableOnceOnly(event->recurs());
00787         if (mSpecialActionsButton)
00788             mSpecialActionsButton->setActions(event->preAction(), event->postAction());
00789         mSimpleRepetition->set(event->repeatInterval(), event->repeatCount());
00790         mRecurrenceText->setText(recurText(*event));
00791         mRecurrenceEdit->set(*event);   // must be called after mTimeWidget is set up, to ensure correct date-only enabling
00792         SoundPicker::Type soundType = event->speak()                                ? SoundPicker::SPEAK
00793                                     : event->beep() || event->audioFile().isEmpty() ? SoundPicker::BEEP
00794                                     :                                                 SoundPicker::PLAY_FILE;
00795         mSoundPicker->set((soundType != SoundPicker::BEEP || event->beep()), soundType, event->audioFile(),
00796                           event->soundVolume(), event->fadeVolume(), event->fadeSeconds(), event->repeatSound());
00797         CmdLogType logType = event->commandXterm()       ? EXEC_IN_TERMINAL
00798                            : !event->logFile().isEmpty() ? LOG_TO_FILE
00799                            :                               DISCARD_OUTPUT;
00800         if (logType == LOG_TO_FILE)
00801             mCmdLogFileEdit->setText(event->logFile());    // set file name before setting radio button
00802         mCmdOutputGroup->setButton(logType);
00803         mEmailToEdit->setText(event->emailAddresses(", "));
00804         mEmailSubjectEdit->setText(event->emailSubject());
00805         mEmailBcc->setChecked(event->emailBcc());
00806         if (mEmailFromList)
00807             mEmailFromList->setCurrentIdentity(event->emailFromKMail());
00808     }
00809     else
00810     {
00811         // Set the values to their defaults
00812         if (!ShellProcess::authorised())
00813         {
00814             // Don't allow shell commands in kiosk mode
00815             mCommandRadio->setEnabled(false);
00816             if (mSpecialActionsButton)
00817                 mSpecialActionsButton->setEnabled(false);
00818         }
00819         mFontColourButton->setDefaultFont();
00820         mFontColourButton->setBgColour(Preferences::defaultBgColour());
00821         mFontColourButton->setFgColour(Preferences::defaultFgColour());
00822         mBgColourChoose->setColour(Preferences::defaultBgColour());     // set colour before setting alarm type buttons
00823         QDateTime defaultTime = QDateTime::currentDateTime().addSecs(60);
00824         if (mTemplate)
00825         {
00826             mTemplateTimeGroup->setButton(mTemplateTimeGroup->id(mTemplateDefaultTime));
00827             mTemplateTime->setValue(0);
00828             mTemplateTimeAfter->setValue(1);
00829         }
00830         else
00831             mTimeWidget->setDateTime(defaultTime);
00832         mActionGroup->setButton(mActionGroup->id(mMessageRadio));
00833         mLateCancel->setMinutes((Preferences::defaultLateCancel() ? 1 : 0), false, TimePeriod::HOURS_MINUTES);
00834         mLateCancel->showAutoClose(true);
00835         mLateCancel->setAutoClose(Preferences::defaultAutoClose());
00836         mLateCancel->setFixedSize(mLateCancel->sizeHint());
00837         if (mShowInKorganizer)
00838             mShowInKorganizer->setChecked(Preferences::defaultCopyToKOrganizer());
00839         mConfirmAck->setChecked(Preferences::defaultConfirmAck());
00840         if (mSpecialActionsButton)
00841             mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction());
00842         mRecurrenceEdit->setDefaults(defaultTime);   // must be called after mTimeWidget is set up, to ensure correct date-only enabling
00843         slotRecurFrequencyChange();      // update the Recurrence text
00844         mReminder->setMinutes(0, false);
00845         mReminder->enableOnceOnly(mRecurrenceEdit->isTimedRepeatType());   // must be called after mRecurrenceEdit is set up
00846         mSoundPicker->set(Preferences::defaultSound(), Preferences::defaultSoundType(), Preferences::defaultSoundFile(),
00847                           Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat());
00848         mCmdTypeScript->setChecked(Preferences::defaultCmdScript());
00849         mCmdLogFileEdit->setText(Preferences::defaultCmdLogFile());    // set file name before setting radio button
00850         mCmdOutputGroup->setButton(Preferences::defaultCmdLogType());
00851         mEmailBcc->setChecked(Preferences::defaultEmailBcc());
00852     }
00853     slotCmdScriptToggled(mCmdTypeScript->isChecked());
00854 
00855     if (!deferGroupVisible)
00856         mDeferGroup->hide();
00857 
00858     bool enable = !!mEmailAttachList->count();
00859     mEmailAttachList->setEnabled(enable);
00860     if (mEmailRemoveButton)
00861         mEmailRemoveButton->setEnabled(enable);
00862     AlarmCalendar* cal = AlarmCalendar::templateCalendar();
00863     bool empty = cal->isOpen()  &&  !cal->events().count();
00864     enableButton(Default, !empty);
00865 }
00866 
00867 /******************************************************************************
00868  * Set the read-only status of all non-template controls.
00869  */
00870 void EditAlarmDlg::setReadOnly()
00871 {
00872     // Common controls
00873     mMessageRadio->setReadOnly(mReadOnly);
00874     mFileRadio->setReadOnly(mReadOnly);
00875     mCommandRadio->setReadOnly(mReadOnly);
00876     mEmailRadio->setReadOnly(mReadOnly);
00877     if (mTimeWidget)
00878         mTimeWidget->setReadOnly(mReadOnly);
00879     mLateCancel->setReadOnly(mReadOnly);
00880     if (mReadOnly)
00881         mDeferChangeButton->hide();
00882     else
00883         mDeferChangeButton->show();
00884     mSimpleRepetition->setReadOnly(mReadOnly);
00885     if (mShowInKorganizer)
00886         mShowInKorganizer->setReadOnly(mReadOnly);
00887 
00888     // Message alarm controls
00889     mTextMessageEdit->setReadOnly(mReadOnly);
00890     mFileMessageEdit->setReadOnly(mReadOnly);
00891     mBgColourChoose->setReadOnly(mReadOnly);
00892     mFontColourButton->setReadOnly(mReadOnly);
00893     mSoundPicker->setReadOnly(mReadOnly);
00894     mConfirmAck->setReadOnly(mReadOnly);
00895     mReminder->setReadOnly(mReadOnly);
00896     if (mSpecialActionsButton)
00897         mSpecialActionsButton->setReadOnly(mReadOnly);
00898     if (mReadOnly)
00899     {
00900         mFileBrowseButton->hide();
00901         mFontColourButton->hide();
00902     }
00903     else
00904     {
00905         mFileBrowseButton->show();
00906         mFontColourButton->show();
00907     }
00908 
00909     // Command alarm controls
00910     mCmdTypeScript->setReadOnly(mReadOnly);
00911     mCmdCommandEdit->setReadOnly(mReadOnly);
00912     mCmdScriptEdit->setReadOnly(mReadOnly);
00913     for (int id = DISCARD_OUTPUT;  id < EXEC_IN_TERMINAL;  ++id)
00914         ((RadioButton*)mCmdOutputGroup->find(id))->setReadOnly(mReadOnly);
00915 
00916     // Email alarm controls
00917     mEmailToEdit->setReadOnly(mReadOnly);
00918     mEmailSubjectEdit->setReadOnly(mReadOnly);
00919     mEmailMessageEdit->setReadOnly(mReadOnly);
00920     mEmailBcc->setReadOnly(mReadOnly);
00921     if (mEmailFromList)
00922         mEmailFromList->setReadOnly(mReadOnly);
00923     if (mReadOnly)
00924     {
00925         mEmailAddressButton->hide();
00926         mEmailAddAttachButton->hide();
00927         mEmailRemoveButton->hide();
00928     }
00929     else
00930     {
00931         mEmailAddressButton->show();
00932         mEmailAddAttachButton->show();
00933         mEmailRemoveButton->show();
00934     }
00935 }
00936 
00937 /******************************************************************************
00938  * Set the dialog's action and the action's text.
00939  */
00940 void EditAlarmDlg::setAction(KAEvent::Action action, const AlarmText& alarmText)
00941 {
00942     QString text = alarmText.displayText();
00943     bool script;
00944     QRadioButton* radio;
00945     switch (action)
00946     {
00947         case KAEvent::FILE:
00948             radio = mFileRadio;
00949             mFileMessageEdit->setText(text);
00950             break;
00951         case KAEvent::COMMAND:
00952             radio = mCommandRadio;
00953             script = alarmText.isScript();
00954             mCmdTypeScript->setChecked(script);
00955             if (script)
00956                 mCmdScriptEdit->setText(text);
00957             else
00958                 mCmdCommandEdit->setText(text);
00959             break;
00960         case KAEvent::EMAIL:
00961             radio = mEmailRadio;
00962             mEmailMessageEdit->setText(text);
00963             break;
00964         case KAEvent::MESSAGE:
00965         default:
00966             radio = mMessageRadio;
00967             mTextMessageEdit->setText(text);
00968             mKMailSerialNumber = 0;
00969             if (alarmText.isEmail())
00970             {
00971                 mKMailSerialNumber = alarmText.kmailSerialNumber();
00972 
00973                 // Set up email fields also, in case the user wants an email alarm
00974                 mEmailToEdit->setText(alarmText.to());
00975                 mEmailSubjectEdit->setText(alarmText.subject());
00976                 mEmailMessageEdit->setText(alarmText.body());
00977             }
00978             else if (alarmText.isScript())
00979             {
00980                 // Set up command script field also, in case the user wants a command alarm
00981                 mCmdScriptEdit->setText(text);
00982                 mCmdTypeScript->setChecked(true);
00983             }
00984             break;
00985     }
00986     mActionGroup->setButton(mActionGroup->id(radio));
00987 }
00988 
00989 /******************************************************************************
00990  * Create a widget to choose the alarm message background colour.
00991  */
00992 ColourCombo* EditAlarmDlg::createBgColourChooser(QHBox** box, QWidget* parent, const char* name)
00993 {
00994     *box = new QHBox(parent);   // this is to control the QWhatsThis text display area
00995     QLabel* label = new QLabel(i18n("&Background color:"), *box);
00996     label->setFixedSize(label->sizeHint());
00997     ColourCombo* widget = new ColourCombo(*box, name);
00998     QSize size = widget->sizeHint();
00999     widget->setMinimumHeight(size.height() + 4);
01000     QToolTip::add(widget, i18n("Message color"));
01001     label->setBuddy(widget);
01002     (*box)->setFixedHeight((*box)->sizeHint().height());
01003     QWhatsThis::add(*box, i18n("Choose the background color for the alarm message."));
01004     return widget;
01005 }
01006 
01007 /******************************************************************************
01008  * Create an "acknowledgement confirmation required" checkbox.
01009  */
01010 CheckBox* EditAlarmDlg::createConfirmAckCheckbox(QWidget* parent, const char* name)
01011 {
01012     CheckBox* widget = new CheckBox(i18n_k_ConfirmAck(), parent, name);
01013     QWhatsThis::add(widget,
01014           i18n("Check to be prompted for confirmation when you acknowledge the alarm."));
01015     return widget;
01016 }
01017 
01018 /******************************************************************************
01019  * Save the state of all controls.
01020  */
01021 void EditAlarmDlg::saveState(const KAEvent* event)
01022 {
01023     mSavedEvent = 0;
01024     if (event)
01025         mSavedEvent = new KAEvent(*event);
01026     if (mTemplate)
01027     {
01028         mSavedTemplateName      = mTemplateName->text();
01029         mSavedTemplateTimeType  = mTemplateTimeGroup->selected();
01030         mSavedTemplateTime      = mTemplateTime->time();
01031         mSavedTemplateAfterTime = mTemplateTimeAfter->value();
01032     }
01033     mSavedTypeRadio        = mActionGroup->selected();
01034     mSavedSound            = mSoundPicker->sound();
01035     mSavedSoundType        = mSoundPicker->type();
01036     mSavedSoundFile        = mSoundPicker->file();
01037     mSavedSoundVolume      = mSoundPicker->volume(mSavedSoundFadeVolume, mSavedSoundFadeSeconds);
01038     mSavedRepeatSound      = mSoundPicker->repeat();
01039     mSavedConfirmAck       = mConfirmAck->isChecked();
01040     mSavedFont             = mFontColourButton->font();
01041     mSavedFgColour         = mFontColourButton->fgColour();
01042     mSavedBgColour         = mBgColourChoose->color();
01043     mSavedReminder         = mReminder->minutes();
01044     mSavedOnceOnly         = mReminder->isOnceOnly();
01045     if (mSpecialActionsButton)
01046     {
01047         mSavedPreAction  = mSpecialActionsButton->preAction();
01048         mSavedPostAction = mSpecialActionsButton->postAction();
01049     }
01050     checkText(mSavedTextFileCommandMessage, false);
01051     mSavedCmdScript        = mCmdTypeScript->isChecked();
01052     mSavedCmdOutputRadio   = mCmdOutputGroup->selected();
01053     mSavedCmdLogFile       = mCmdLogFileEdit->text();
01054     if (mEmailFromList)
01055         mSavedEmailFrom = mEmailFromList->currentIdentityName();
01056     mSavedEmailTo          = mEmailToEdit->text();
01057     mSavedEmailSubject     = mEmailSubjectEdit->text();
01058     mSavedEmailAttach.clear();
01059     for (int i = 0;  i < mEmailAttachList->count();  ++i)
01060         mSavedEmailAttach += mEmailAttachList->text(i);
01061     mSavedEmailBcc         = mEmailBcc->isChecked();
01062     if (mTimeWidget)
01063         mSavedDateTime = mTimeWidget->getDateTime(false, false);
01064     mSavedLateCancel       = mLateCancel->minutes();
01065     mSavedAutoClose        = mLateCancel->isAutoClose();
01066     if (mShowInKorganizer)
01067         mSavedShowInKorganizer = mShowInKorganizer->isChecked();
01068     mSavedRecurrenceType   = mRecurrenceEdit->repeatType();
01069     mSavedRepeatInterval   = mSimpleRepetition->interval();
01070     mSavedRepeatCount      = mSimpleRepetition->count();
01071 }
01072 
01073 /******************************************************************************
01074  * Check whether any of the controls has changed state since the dialog was
01075  * first displayed.
01076  * Reply = true if any non-deferral controls have changed, or if it's a new event.
01077  *       = false if no non-deferral controls have changed. In this case,
01078  *         mOnlyDeferred indicates whether deferral controls may have changed.
01079  */
01080 bool EditAlarmDlg::stateChanged() const
01081 {
01082     mChanged      = true;
01083     mOnlyDeferred = false;
01084     if (!mSavedEvent)
01085         return true;
01086     QString textFileCommandMessage;
01087     checkText(textFileCommandMessage, false);
01088     if (mTemplate)
01089     {
01090         if (mSavedTemplateName     != mTemplateName->text()
01091         ||  mSavedTemplateTimeType != mTemplateTimeGroup->selected()
01092         ||  mTemplateUseTime->isOn()  &&  mSavedTemplateTime != mTemplateTime->time()
01093         ||  mTemplateUseTimeAfter->isOn()  &&  mSavedTemplateAfterTime != mTemplateTimeAfter->value())
01094             return true;
01095     }
01096     else
01097         if (mSavedDateTime != mTimeWidget->getDateTime(false, false))
01098             return true;
01099     if (mSavedTypeRadio        != mActionGroup->selected()
01100     ||  mSavedLateCancel       != mLateCancel->minutes()
01101     ||  mShowInKorganizer && mSavedShowInKorganizer != mShowInKorganizer->isChecked()
01102     ||  textFileCommandMessage != mSavedTextFileCommandMessage
01103     ||  mSavedRecurrenceType   != mRecurrenceEdit->repeatType()
01104     ||  mSavedRepeatInterval   != mSimpleRepetition->interval()
01105     ||  mSavedRepeatCount      != mSimpleRepetition->count())
01106         return true;
01107     if (mMessageRadio->isOn()  ||  mFileRadio->isOn())
01108     {
01109         if (mSavedSound      != mSoundPicker->sound()
01110         ||  mSavedConfirmAck != mConfirmAck->isChecked()
01111         ||  mSavedFont       != mFontColourButton->font()
01112         ||  mSavedFgColour   != mFontColourButton->fgColour()
01113         ||  mSavedBgColour   != mBgColourChoose->color()
01114         ||  mSavedReminder   != mReminder->minutes()
01115         ||  mSavedOnceOnly   != mReminder->isOnceOnly()
01116         ||  mSavedAutoClose  != mLateCancel->isAutoClose())
01117             return true;
01118         if (mSpecialActionsButton)
01119         {
01120             if (mSavedPreAction  != mSpecialActionsButton->preAction()
01121             ||  mSavedPostAction != mSpecialActionsButton->postAction())
01122                 return true;
01123         }
01124         if (mSavedSound)
01125         {
01126             if (mSavedSoundType != mSoundPicker->type())
01127                 return true;
01128             if (mSavedSoundType == SoundPicker::PLAY_FILE)
01129             {
01130                 if (mSavedSoundFile != mSoundPicker->file())
01131                     return true;
01132                 if (!mSavedSoundFile.isEmpty())
01133                 {
01134                     float fadeVolume;
01135                     int   fadeSecs;
01136                     if (mSavedRepeatSound != mSoundPicker->repeat()
01137                     ||  mSavedSoundVolume != mSoundPicker->volume(fadeVolume, fadeSecs)
01138                     ||  mSavedSoundFadeVolume != fadeVolume
01139                     ||  mSavedSoundFadeSeconds != fadeSecs)
01140                         return true;
01141                 }
01142             }
01143         }
01144     }
01145     else if (mCommandRadio->isOn())
01146     {
01147         if (mSavedCmdScript      != mCmdTypeScript->isChecked()
01148         ||  mSavedCmdOutputRadio != mCmdOutputGroup->selected())
01149             return true;
01150         if (mCmdOutputGroup->selectedId() == LOG_TO_FILE)
01151         {
01152             if (mSavedCmdLogFile != mCmdLogFileEdit->text())
01153                 return true;
01154         }
01155     }
01156     else if (mEmailRadio->isOn())
01157     {
01158         QStringList emailAttach;
01159         for (int i = 0;  i < mEmailAttachList->count();  ++i)
01160             emailAttach += mEmailAttachList->text(i);
01161         if (mEmailFromList  &&  mSavedEmailFrom != mEmailFromList->currentIdentityName()
01162         ||  mSavedEmailTo      != mEmailToEdit->text()
01163         ||  mSavedEmailSubject != mEmailSubjectEdit->text()
01164         ||  mSavedEmailAttach  != emailAttach
01165         ||  mSavedEmailBcc     != mEmailBcc->isChecked())
01166             return true;
01167     }
01168     if (mRecurrenceEdit->stateChanged())
01169         return true;
01170     if (mSavedEvent  &&  mSavedEvent->deferred())
01171         mOnlyDeferred = true;
01172     mChanged = false;
01173     return false;
01174 }
01175 
01176 /******************************************************************************
01177  * Get the currently entered dialogue data.
01178  * The data is returned in the supplied KAEvent instance.
01179  * Reply = false if the only change has been to an existing deferral.
01180  */
01181 bool EditAlarmDlg::getEvent(KAEvent& event)
01182 {
01183     if (mChanged)
01184     {
01185         // It's a new event, or the edit controls have changed
01186         setEvent(event, mAlarmMessage, false);
01187         return true;
01188     }
01189 
01190     // Only the deferral time may have changed
01191     event = *mSavedEvent;
01192     if (mOnlyDeferred)
01193     {
01194         // Just modify the original event, to avoid expired recurring events
01195         // being returned as rubbish.
01196         if (mDeferDateTime.isValid())
01197             event.defer(mDeferDateTime, event.reminderDeferral(), false);
01198         else
01199             event.cancelDefer();
01200     }
01201     return false;
01202 }
01203 
01204 /******************************************************************************
01205 *  Extract the data in the dialogue and set up a KAEvent from it.
01206 *  If 'trial' is true, the event is set up for a simple one-off test, ignoring
01207 *  recurrence, reminder, template etc. data.
01208 */
01209 void EditAlarmDlg::setEvent(KAEvent& event, const QString& text, bool trial)
01210 {
01211     QDateTime dt;
01212     if (!trial)
01213     {
01214         if (!mTemplate)
01215             dt = mAlarmDateTime.dateTime();
01216         else if (mTemplateUseTime->isOn())
01217             dt.setTime(mTemplateTime->time());
01218     }
01219     KAEvent::Action type = getAlarmType();
01220     event.set(dt, text, mBgColourChoose->color(), mFontColourButton->fgColour(), mFontColourButton->font(),
01221               type, (trial ? 0 : mLateCancel->minutes()), getAlarmFlags());
01222     switch (type)
01223     {
01224         case KAEvent::MESSAGE:
01225             if (AlarmText::checkIfEmail(text))
01226                 event.setKMailSerialNumber(mKMailSerialNumber);
01227             // fall through to FILE
01228         case KAEvent::FILE:
01229         {
01230             float fadeVolume;
01231             int   fadeSecs;
01232             float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
01233             event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs);
01234             if (!trial)
01235                 event.setReminder(mReminder->minutes(), mReminder->isOnceOnly());
01236             if (mSpecialActionsButton)
01237                 event.setActions(mSpecialActionsButton->preAction(), mSpecialActionsButton->postAction());
01238             break;
01239         }
01240         case KAEvent::EMAIL:
01241         {
01242             QString from;
01243             if (mEmailFromList)
01244                 from = mEmailFromList->currentIdentityName();
01245             event.setEmail(from, mEmailAddresses, mEmailSubjectEdit->text(), mEmailAttachments);
01246             break;
01247         }
01248         case KAEvent::COMMAND:
01249             if (mCmdOutputGroup->selectedId() == LOG_TO_FILE)
01250                 event.setLogFile(mCmdLogFileEdit->text());
01251             break;
01252         default:
01253             break;
01254     }
01255     if (!trial)
01256     {
01257         if (mRecurrenceEdit->repeatType() != RecurrenceEdit::NO_RECUR)
01258         {
01259             mRecurrenceEdit->updateEvent(event, !mTemplate);
01260             mAlarmDateTime = event.startDateTime();
01261             if (mDeferDateTime.isValid()  &&  mDeferDateTime < mAlarmDateTime)
01262             {
01263                 bool deferral = true;
01264                 bool deferReminder = false;
01265                 int reminder = mReminder->minutes();
01266                 if (reminder)
01267                 {
01268                     DateTime remindTime = mAlarmDateTime.addMins(-reminder);
01269                     if (mDeferDateTime >= remindTime)
01270                     {
01271                         if (remindTime > QDateTime::currentDateTime())
01272                             deferral = false;    // ignore deferral if it's after next reminder
01273                         else if (mDeferDateTime > remindTime)
01274                             deferReminder = true;    // it's the reminder which is being deferred
01275                     }
01276                 }
01277                 if (deferral)
01278                     event.defer(mDeferDateTime, deferReminder, false);
01279             }
01280         }
01281         if (mSimpleRepetition->count())
01282             event.setRepetition(mSimpleRepetition->interval(), mSimpleRepetition->count());
01283         if (mTemplate)
01284         {
01285             int afterTime = mTemplateDefaultTime->isOn() ? 0
01286                           : mTemplateUseTimeAfter->isOn() ? mTemplateTimeAfter->value() : -1;
01287             event.setTemplate(mTemplateName->text(), afterTime);
01288         }
01289     }
01290 }
01291 
01292 /******************************************************************************
01293  * Get the currently specified alarm flag bits.
01294  */
01295 int EditAlarmDlg::getAlarmFlags() const
01296 {
01297     bool displayAlarm = mMessageRadio->isOn() || mFileRadio->isOn();
01298     bool cmdAlarm     = mCommandRadio->isOn();
01299     bool emailAlarm   = mEmailRadio->isOn();
01300     return (displayAlarm && mSoundPicker->beep()                                 ? KAEvent::BEEP : 0)
01301          | (displayAlarm && mSoundPicker->speak()                                ? KAEvent::SPEAK : 0)
01302          | (displayAlarm && mSoundPicker->repeat()                               ? KAEvent::REPEAT_SOUND : 0)
01303          | (displayAlarm && mConfirmAck->isChecked()                             ? KAEvent::CONFIRM_ACK : 0)
01304          | (displayAlarm && mLateCancel->isAutoClose()                           ? KAEvent::AUTO_CLOSE : 0)
01305          | (cmdAlarm     && mCmdTypeScript->isChecked()                          ? KAEvent::SCRIPT : 0)
01306          | (cmdAlarm     && mCmdOutputGroup->selectedId() == EXEC_IN_TERMINAL    ? KAEvent::EXEC_IN_XTERM : 0)
01307          | (emailAlarm   && mEmailBcc->isChecked()                               ? KAEvent::EMAIL_BCC : 0)
01308          | (mShowInKorganizer && mShowInKorganizer->isChecked()                  ? KAEvent::COPY_KORGANIZER : 0)
01309          | (mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN            ? KAEvent::REPEAT_AT_LOGIN : 0)
01310          | ((mTemplate ? mTemplateAnyTime->isOn() : mAlarmDateTime.isDateOnly()) ? KAEvent::ANY_TIME : 0)
01311          | (mFontColourButton->defaultFont()                                     ? KAEvent::DEFAULT_FONT : 0);
01312 }
01313 
01314 /******************************************************************************
01315  * Get the currently selected alarm type.
01316  */
01317 KAEvent::Action EditAlarmDlg::getAlarmType() const
01318 {
01319     return mFileRadio->isOn()    ? KAEvent::FILE
01320          : mCommandRadio->isOn() ? KAEvent::COMMAND
01321          : mEmailRadio->isOn()   ? KAEvent::EMAIL
01322          :                         KAEvent::MESSAGE;
01323 }
01324 
01325 /******************************************************************************
01326 *  Called when the dialog is displayed.
01327 *  The first time through, sets the size to the same as the last time it was
01328 *  displayed.
01329 */
01330 void EditAlarmDlg::showEvent(QShowEvent* se)
01331 {
01332     if (!mDeferGroupHeight)
01333     {
01334         mDeferGroupHeight = mDeferGroup->height() + spacingHint();
01335         QSize s;
01336         if (KAlarm::readConfigWindowSize(EDIT_DIALOG_NAME, s))
01337             s.setHeight(s.height() + (mDeferGroup->isHidden() ? 0 : mDeferGroupHeight));
01338         else
01339             s = minimumSize();
01340         resize(s);
01341     }
01342     KWin::setOnDesktop(winId(), mDesktop);    // ensure it displays on the desktop expected by the user
01343     KDialog::showEvent(se);
01344 }
01345 
01346 /******************************************************************************
01347 *  Called when the dialog's size has changed.
01348 *  Records the new size (adjusted to ignore the optional height of the deferred
01349 *  time edit widget) in the config file.
01350 */
01351 void EditAlarmDlg::resizeEvent(QResizeEvent* re)
01352 {
01353     if (isVisible())
01354     {
01355         QSize s = re->size();
01356         s.setHeight(s.height() - (mDeferGroup->isHidden() ? 0 : mDeferGroupHeight));
01357         KAlarm::writeConfigWindowSize(EDIT_DIALOG_NAME, s);
01358     }
01359     KDialog::resizeEvent(re);
01360 }
01361 
01362 /******************************************************************************
01363 *  Called when the OK button is clicked.
01364 *  Validate the input data.
01365 */
01366 void EditAlarmDlg::slotOk()
01367 {
01368     if (!stateChanged())
01369     {
01370         // No changes have been made except possibly to an existing deferral
01371         if (!mOnlyDeferred)
01372             reject();
01373         else
01374             accept();
01375         return;
01376     }
01377     RecurrenceEdit::RepeatType recurType = mRecurrenceEdit->repeatType();
01378     if (mTimeWidget
01379     &&  mTabs->currentPageIndex() == mRecurPageIndex  &&  recurType == RecurrenceEdit::AT_LOGIN)
01380         mTimeWidget->setDateTime(mRecurrenceEdit->endDateTime());
01381     bool timedRecurrence = mRecurrenceEdit->isTimedRepeatType();    // does it recur other than at login?
01382     bool repeated = mSimpleRepetition->count();
01383     if (mTemplate)
01384     {
01385         // Check that the template name is not blank and is unique
01386         QString errmsg;
01387         QString name = mTemplateName->text();
01388         if (name.isEmpty())
01389             errmsg = i18n("You must enter a name for the alarm template");
01390         else if (name != mSavedTemplateName)
01391         {
01392             AlarmCalendar* cal = AlarmCalendar::templateCalendarOpen();
01393             if (cal  &&  KAEvent::findTemplateName(*cal, name).valid())
01394                 errmsg = i18n("Template name is already in use");
01395         }
01396         if (!errmsg.isEmpty())
01397         {
01398             mTemplateName->setFocus();
01399             KMessageBox::sorry(this, errmsg);
01400             return;
01401         }
01402     }
01403     else
01404     {
01405         QWidget* errWidget;
01406         mAlarmDateTime = mTimeWidget->getDateTime(!(timedRecurrence || repeated), false, &errWidget);
01407         if (errWidget)
01408         {
01409             // It's more than just an existing deferral being changed, so the time matters
01410             mTabs->setCurrentPage(mMainPageIndex);
01411             errWidget->setFocus();
01412             mTimeWidget->getDateTime();   // display the error message now
01413             return;
01414         }
01415     }
01416     if (!checkCommandData()
01417     ||  !checkEmailData())
01418         return;
01419     if (!mTemplate)
01420     {
01421         if (timedRecurrence)
01422         {
01423             QDateTime now = QDateTime::currentDateTime();
01424             if (mAlarmDateTime.date() < now.date()
01425             ||  mAlarmDateTime.date() == now.date()
01426                 && !mAlarmDateTime.isDateOnly() && mAlarmDateTime.time() < now.time())
01427             {
01428                 // A timed recurrence has an entered start date which
01429                 // has already expired, so we must adjust it.
01430                 KAEvent event;
01431                 getEvent(event);     // this may adjust mAlarmDateTime
01432                 if ((  mAlarmDateTime.date() < now.date()
01433                     || mAlarmDateTime.date() == now.date()
01434                        && !mAlarmDateTime.isDateOnly() && mAlarmDateTime.time() < now.time())
01435                 &&  event.nextOccurrence(now, mAlarmDateTime, KAEvent::ALLOW_FOR_REPETITION) == KAEvent::NO_OCCURRENCE)
01436                 {
01437                     KMessageBox::sorry(this, i18n("Recurrence has already expired"));
01438                     return;
01439                 }
01440             }
01441         }
01442         QString errmsg;
01443         QWidget* errWidget = mRecurrenceEdit->checkData(mAlarmDateTime.dateTime(), errmsg);
01444         if (errWidget)
01445         {
01446             mTabs->setCurrentPage(mRecurPageIndex);
01447             errWidget->setFocus();
01448             KMessageBox::sorry(this, errmsg);
01449             return;
01450         }
01451     }
01452     int longestRecurInterval = -1;
01453     if (recurType != RecurrenceEdit::NO_RECUR)
01454     {
01455         int reminder = mReminder->minutes();
01456         if (reminder)
01457         {
01458             KAEvent event;
01459             mRecurrenceEdit->updateEvent(event, false);
01460             if (!mReminder->isOnceOnly())
01461             {
01462                 longestRecurInterval = event.longestRecurrenceInterval();
01463                 if (longestRecurInterval  &&  reminder >= longestRecurInterval)
01464                 {
01465                     mTabs->setCurrentPage(mMainPageIndex);
01466                     mReminder->setFocusOnCount();
01467                     KMessageBox::sorry(this, i18n("Reminder period must be less than the recurrence interval, unless '%1' is checked."
01468                                                  ).arg(Reminder::i18n_first_recurrence_only()));
01469                     return;
01470                 }
01471             }
01472         }
01473     }
01474     if (mSimpleRepetition->count())
01475     {
01476         switch (recurType)
01477         {
01478             case RecurrenceEdit::AT_LOGIN:    // alarm repeat not allowed
01479                 mSimpleRepetition->set(0, 0);
01480                 break;
01481             default:          // repeat duration must be less than recurrence interval
01482                 if (longestRecurInterval < 0)
01483                 {
01484                     KAEvent event;
01485                     mRecurrenceEdit->updateEvent(event, false);
01486                     longestRecurInterval = event.longestRecurrenceInterval();
01487                 }
01488                 if (mSimpleRepetition->count() * mSimpleRepetition->interval() >= longestRecurInterval - mReminder->minutes())
01489                 {
01490                     KMessageBox::sorry(this, i18n("Simple alarm repetition duration must be less than the recurrence interval minus any reminder period"));
01491                     mSimpleRepetition->activate();   // display the alarm repetition dialog again
01492                     return;
01493                 }
01494                 // fall through to NO_RECUR
01495             case RecurrenceEdit::NO_RECUR:    // no restriction on repeat duration
01496                 if (mSimpleRepetition->interval() % 1440
01497                 &&  (mTemplate && mTemplateAnyTime->isOn()  ||  !mTemplate && mAlarmDateTime.isDateOnly()))
01498                 {
01499                     KMessageBox::sorry(this, i18n("Simple alarm repetition period must be in units of days or weeks for a date-only alarm"));
01500                     mSimpleRepetition->activate();   // display the alarm repetition dialog again
01501                     return;
01502                 }
01503                 break;
01504         }
01505     }
01506     if (checkText(mAlarmMessage))
01507         accept();
01508 }
01509 
01510 /******************************************************************************
01511 *  Called when the Try button is clicked.
01512 *  Display/execute the alarm immediately for the user to check its configuration.
01513 */
01514 void EditAlarmDlg::slotTry()
01515 {
01516     QString text;
01517     if (checkText(text))
01518     {
01519         if (mEmailRadio->isOn())
01520         {
01521             if (!checkEmailData()
01522             ||  KMessageBox::warningContinueCancel(this, i18n("Do you really want to send the email now to the specified recipient(s)?"),
01523                                                    i18n("Confirm Email"), i18n("&Send")) != KMessageBox::Continue)
01524                 return;
01525         }
01526         KAEvent event;
01527         setEvent(event, text, true);
01528         void* proc = theApp()->execAlarm(event, event.firstAlarm(), false, false);
01529         if (proc)
01530         {
01531             if (mCommandRadio->isOn()  &&  mCmdOutputGroup->selectedId() != EXEC_IN_TERMINAL)
01532             {
01533                 theApp()->commandMessage((ShellProcess*)proc, this);
01534                 KMessageBox::information(this, i18n("Command executed:\n%1").arg(text));
01535                 theApp()->commandMessage((ShellProcess*)proc, 0);
01536             }
01537             else if (mEmailRadio->isOn())
01538             {
01539                 QString bcc;
01540                 if (mEmailBcc->isChecked())
01541                     bcc = i18n("\nBcc: %1").arg(Preferences::emailBccAddress());
01542                 KMessageBox::information(this, i18n("Email sent to:\n%1%2").arg(mEmailAddresses.join("\n")).arg(bcc));
01543             }
01544         }
01545     }
01546 }
01547 
01548 /******************************************************************************
01549 *  Called when the Cancel button is clicked.
01550 */
01551 void EditAlarmDlg::slotCancel()
01552 {
01553     reject();
01554 }
01555 
01556 /******************************************************************************
01557 *  Called when the Load Template button is clicked.
01558 *  Prompt to select a template and initialise the dialogue with its contents.
01559 */
01560 void EditAlarmDlg::slotDefault()
01561 {
01562     TemplatePickDlg dlg(this, "templPickDlg");
01563     if (dlg.exec() == QDialog::Accepted)
01564         initialise(dlg.selectedTemplate());
01565 }
01566 
01567 /******************************************************************************
01568  * Called when the Change deferral button is clicked.
01569  */
01570 void EditAlarmDlg::slotEditDeferral()
01571 {
01572     if (!mTimeWidget)
01573         return;
01574     bool limit = true;
01575     int repeatCount = mSimpleRepetition->count();
01576     DateTime start = mTimeWidget->getDateTime(!repeatCount, !mExpiredRecurrence);
01577     if (!start.isValid())
01578     {
01579         if (!mExpiredRecurrence)
01580             return;
01581         limit = false;
01582     }
01583     QDateTime now = QDateTime::currentDateTime();
01584     if (limit)
01585     {
01586         if (repeatCount  &&  start < now)
01587         {
01588             // Simple repetition - find the time of the next one
01589             int interval = mSimpleRepetition->interval() * 60;
01590             int repetition = (start.secsTo(now) + interval - 1) / interval;
01591             if (repetition > repeatCount)
01592             {
01593                 mTimeWidget->getDateTime();    // output the appropriate error message
01594                 return;
01595             }
01596             start = start.addSecs(repetition * interval);
01597         }
01598     }
01599 
01600     bool deferred = mDeferDateTime.isValid();
01601     DeferAlarmDlg deferDlg(i18n("Defer Alarm"), (deferred ? mDeferDateTime : DateTime(now.addSecs(60))),
01602                            deferred, this, "deferDlg");
01603     if (limit)
01604     {
01605         // Don't allow deferral past the next recurrence
01606         int reminder = mReminder->minutes();
01607         if (reminder)
01608         {
01609             DateTime remindTime = start.addMins(-reminder);
01610             if (QDateTime::currentDateTime() < remindTime)
01611                 start = remindTime;
01612         }
01613         deferDlg.setLimit(start.addSecs(-60));
01614     }
01615     if (deferDlg.exec() == QDialog::Accepted)
01616     {
01617         mDeferDateTime = deferDlg.getDateTime();
01618         mDeferTimeLabel->setText(mDeferDateTime.isValid() ? mDeferDateTime.formatLocale() : QString::null);
01619     }
01620 }
01621 
01622 /******************************************************************************
01623 *  Called when the main page is shown.
01624 *  Sets the focus widget to the first edit field.
01625 */
01626 void EditAlarmDlg::slotShowMainPage()
01627 {
01628     slotAlarmTypeChanged(-1);
01629     if (!mMainPageShown)
01630     {
01631         if (mTemplateName)
01632             mTemplateName->setFocus();
01633         mMainPageShown = true;
01634     }
01635     if (mTimeWidget)
01636     {
01637         if (!mReadOnly  &&  mRecurPageShown  &&  mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN)
01638             mTimeWidget->setDateTime(mRecurrenceEdit->endDateTime());
01639         if (mReadOnly  ||  mRecurrenceEdit->isTimedRepeatType())
01640             mTimeWidget->setMinDateTime();             // don't set a minimum date/time
01641         else
01642             mTimeWidget->setMinDateTimeIsCurrent();    // set the minimum date/time to track the clock
01643     }
01644 }
01645 
01646 /******************************************************************************
01647 *  Called when the recurrence edit page is shown.
01648 *  The recurrence defaults are set to correspond to the start date.
01649 *  The first time, for a new alarm, the recurrence end date is set according to
01650 *  the alarm start time.
01651 */
01652 void EditAlarmDlg::slotShowRecurrenceEdit()
01653 {
01654     mRecurPageIndex = mTabs->currentPageIndex();
01655     if (!mReadOnly  &&  !mTemplate)
01656     {
01657         QDateTime now = QDateTime::currentDateTime();
01658         mAlarmDateTime = mTimeWidget->getDateTime(false, false);
01659         bool expired = (mAlarmDateTime.dateTime() < now);
01660         if (mRecurSetDefaultEndDate)
01661         {
01662             mRecurrenceEdit->setDefaultEndDate(expired ? now.date() : mAlarmDateTime.date());
01663             mRecurSetDefaultEndDate = false;
01664         }
01665         mRecurrenceEdit->setStartDate(mAlarmDateTime.date(), now.date());
01666         if (mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN)
01667             mRecurrenceEdit->setEndDateTime(expired ? now : mAlarmDateTime);
01668     }
01669     mRecurPageShown = true;
01670 }
01671 
01672 /******************************************************************************
01673 *  Called when the recurrence type selection changes.
01674 *  Enables/disables date-only alarms as appropriate.
01675 */
01676 void EditAlarmDlg::slotRecurTypeChange(int repeatType)
01677 {
01678     if (!mTemplate)
01679     {
01680         bool recurs = (mRecurrenceEdit->repeatType() != RecurrenceEdit::NO_RECUR);
01681         if (mDeferGroup)
01682             mDeferGroup->setEnabled(recurs);
01683         mTimeWidget->enableAnyTime(!recurs || repeatType != RecurrenceEdit::SUBDAILY);
01684         bool atLogin = (mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN);
01685         if (atLogin)
01686         {
01687             mAlarmDateTime = mTimeWidget->getDateTime(false, false);
01688             mRecurrenceEdit->setEndDateTime(mAlarmDateTime.dateTime());
01689         }
01690         mReminder->enableOnceOnly(recurs && !atLogin);
01691     }
01692     slotRecurFrequencyChange();
01693 }
01694 
01695 /******************************************************************************
01696 *  Called when the recurrence frequency selection changes, or the simple
01697 *  repetition interval changes.
01698 *  Updates the recurrence frequency text.
01699 */
01700 void EditAlarmDlg::slotRecurFrequencyChange()
01701 {
01702     KAEvent event;
01703     mRecurrenceEdit->updateEvent(event, false);
01704     event.setRepetition(mSimpleRepetition->interval(), mSimpleRepetition->count());
01705     mRecurrenceText->setText(recurText(event));
01706 }
01707 
01708 /******************************************************************************
01709 *  Called when the Simple Repetition button has been pressed to display the
01710 *  alarm repetition dialog.
01711 *  Alarm repetition has the following restrictions:
01712 *  1) Not allowed for a repeat-at-login alarm
01713 *  2) For a date-only alarm, the repeat interval must be a whole number of days.
01714 *  3) The overall repeat duration must be less than the recurrence interval.
01715 */
01716 void EditAlarmDlg::slotSetSimpleRepetition()
01717 {
01718     bool dateOnly = mTemplate ? mTemplateAnyTime->isOn() : mTimeWidget->anyTime();
01719     int maxDuration;
01720     switch (mRecurrenceEdit->repeatType())
01721     {
01722         case RecurrenceEdit::NO_RECUR:  maxDuration = -1;  break;  // no restriction on repeat duration
01723         case RecurrenceEdit::AT_LOGIN:  maxDuration = 0;  break;   // alarm repeat not allowed
01724         default:          // repeat duration must be less than recurrence interval
01725         {
01726             KAEvent event;
01727             mRecurrenceEdit->updateEvent(event, false);
01728             maxDuration = event.longestRecurrenceInterval() - mReminder->minutes() - 1;
01729             break;
01730         }
01731     }
01732     mSimpleRepetition->initialise(mSimpleRepetition->interval(), mSimpleRepetition->count(), dateOnly, maxDuration);
01733 }
01734 
01735 /******************************************************************************
01736 *  Validate and convert command alarm data.
01737 */
01738 bool EditAlarmDlg::checkCommandData()
01739 {
01740     if (mCommandRadio->isOn()  &&  mCmdOutputGroup->selectedId() == LOG_TO_FILE)
01741     {
01742         // Validate the log file name
01743         QString file = mCmdLogFileEdit->text();
01744         QFileInfo info(file);
01745         QDir::setCurrent(QDir::homeDirPath());
01746         bool err = file.isEmpty()  ||  info.isDir();
01747         if (!err)
01748         {
01749             if (info.exists())
01750             {
01751                 err = !info.isWritable();
01752             }
01753             else
01754             {
01755                 QFileInfo dirinfo(info.dirPath(true));    // get absolute directory path
01756                 err = (!dirinfo.isDir()  ||  !dirinfo.isWritable());
01757             }
01758         }
01759         if (err)
01760         {
01761             mTabs->setCurrentPage(mMainPageIndex);
01762             mCmdLogFileEdit->setFocus();
01763             KMessageBox::sorry(this, i18n("Log file must be the name or path of a local file, with write permission."));
01764             return false;
01765         }
01766         // Convert the log file to an absolute path
01767         mCmdLogFileEdit->setText(info.absFilePath());
01768     }
01769     return true;
01770 }
01771 
01772 /******************************************************************************
01773 *  Convert the email addresses to a list, and validate them. Convert the email
01774 *  attachments to a list.
01775 */
01776 bool EditAlarmDlg::checkEmailData()
01777 {
01778     if (mEmailRadio->isOn())
01779     {
01780         QString addrs = mEmailToEdit->text();
01781         if (addrs.isEmpty())
01782             mEmailAddresses.clear();
01783         else
01784         {
01785             QString bad = KAMail::convertAddresses(addrs, mEmailAddresses);
01786             if (!bad.isEmpty())
01787             {
01788                 mEmailToEdit->setFocus();
01789                 KMessageBox::error(this, i18n("Invalid email address:\n%1").arg(bad));
01790                 return false;
01791             }
01792         }
01793         if (mEmailAddresses.isEmpty())
01794         {
01795             mEmailToEdit->setFocus();
01796             KMessageBox::error(this, i18n("No email address specified"));
01797             return false;
01798         }
01799 
01800         mEmailAttachments.clear();
01801         for (int i = 0;  i < mEmailAttachList->count();  ++i)
01802         {
01803             QString att = mEmailAttachList->text(i);
01804             switch (KAMail::checkAttachment(att))
01805             {
01806                 case 1:
01807                     mEmailAttachments.append(att);
01808                     break;
01809                 case 0:
01810                     break;      // empty
01811                 case -1:
01812                     mEmailAttachList->setFocus();
01813                     KMessageBox::error(this, i18n("Invalid email attachment:\n%1").arg(att));
01814                     return false;
01815             }
01816         }
01817     }
01818     return true;
01819 }
01820 
01821 /******************************************************************************
01822 *  Called when one of the alarm action type radio buttons is clicked,
01823 *  to display the appropriate set of controls for that action type.
01824 */
01825 void EditAlarmDlg::slotAlarmTypeChanged(int)
01826 {
01827     bool displayAlarm = false;
01828     QWidget* focus = 0;
01829     if (mMessageRadio->isOn())
01830     {
01831         mFileBox->hide();
01832         mFilePadding->hide();
01833         mTextMessageEdit->show();
01834         mFontColourButton->show();
01835         mSoundPicker->showSpeak(true);
01836         setButtonWhatsThis(Try, i18n("Display the alarm message now"));
01837         mAlarmTypeStack->raiseWidget(mDisplayAlarmsFrame);
01838         focus = mTextMessageEdit;
01839         displayAlarm = true;
01840     }
01841     else if (mFileRadio->isOn())
01842     {
01843         mTextMessageEdit->hide();
01844         mFileBox->show();
01845         mFilePadding->show();
01846         mFontColourButton->hide();
01847         mSoundPicker->showSpeak(false);
01848         setButtonWhatsThis(Try, i18n("Display the file now"));
01849         mAlarmTypeStack->raiseWidget(mDisplayAlarmsFrame);
01850         mFileMessageEdit->setNoSelect();
01851         focus = mFileMessageEdit;
01852         displayAlarm = true;
01853     }
01854     else if (mCommandRadio->isOn())
01855     {
01856         setButtonWhatsThis(Try, i18n("Execute the specified command now"));
01857         mAlarmTypeStack->raiseWidget(mCommandFrame);
01858         mCmdCommandEdit->setNoSelect();
01859         focus = mCmdCommandEdit;
01860     }
01861     else if (mEmailRadio->isOn())
01862     {
01863         setButtonWhatsThis(Try, i18n("Send the email to the specified addressees now"));
01864         mAlarmTypeStack->raiseWidget(mEmailFrame);
01865         mEmailToEdit->setNoSelect();
01866         focus = mEmailToEdit;
01867     }
01868     mLateCancel->showAutoClose(displayAlarm);
01869     mLateCancel->setFixedSize(mLateCancel->sizeHint());
01870     if (focus)
01871         focus->setFocus();
01872 }
01873 
01874 /******************************************************************************
01875 *  Called when one of the command type radio buttons is clicked,
01876 *  to display the appropriate edit field.
01877 */
01878 void EditAlarmDlg::slotCmdScriptToggled(bool on)
01879 {
01880     if (on)
01881     {
01882         mCmdCommandEdit->hide();
01883         mCmdPadding->hide();
01884         mCmdScriptEdit->show();
01885         mCmdScriptEdit->setFocus();
01886     }
01887     else
01888     {
01889         mCmdScriptEdit->hide();
01890         mCmdCommandEdit->show();
01891         mCmdPadding->show();
01892         mCmdCommandEdit->setFocus();
01893     }
01894 }
01895 
01896 /******************************************************************************
01897 *  Called when one of the template time radio buttons is clicked,
01898 *  to enable or disable the template time entry spin boxes.
01899 */
01900 void EditAlarmDlg::slotTemplateTimeType(int)
01901 {
01902     mTemplateTime->setEnabled(mTemplateUseTime->isOn());
01903     mTemplateTimeAfter->setEnabled(mTemplateUseTimeAfter->isOn());
01904 }
01905 
01906 /******************************************************************************
01907 *  Called when the a new background colour has been selected using the colour
01908 *  combo box.
01909 */
01910 void EditAlarmDlg::slotBgColourSelected(const QColor& colour)
01911 {
01912     mFontColourButton->setBgColour(colour);
01913 }
01914 
01915 /******************************************************************************
01916 *  Called when the a new font and colour have been selected using the font &
01917 *  colour pushbutton.
01918 */
01919 void EditAlarmDlg::slotFontColourSelected()
01920 {
01921     mBgColourChoose->setColour(mFontColourButton->bgColour());
01922 }
01923 
01924 /******************************************************************************
01925 *  Called when the "Any time" checkbox is toggled in the date/time widget.
01926 *  Sets the advance reminder and late cancel units to days if any time is checked.
01927 */
01928 void EditAlarmDlg::slotAnyTimeToggled(bool anyTime)
01929 {
01930     if (mReminder->isReminder())
01931         mReminder->setDateOnly(anyTime);
01932     mLateCancel->setDateOnly(anyTime);
01933 }
01934 
01935 /******************************************************************************
01936  * Get a selection from the Address Book.
01937  */
01938 void EditAlarmDlg::openAddressBook()
01939 {
01940     KABC::Addressee a = KABC::AddresseeDialog::getAddressee(this);
01941     if (a.isEmpty())
01942         return;
01943     Person person(a.realName(), a.preferredEmail());
01944     QString addrs = mEmailToEdit->text().stripWhiteSpace();
01945     if (!addrs.isEmpty())
01946         addrs += ", ";
01947     addrs += person.fullName();
01948     mEmailToEdit->setText(addrs);
01949 }
01950 
01951 /******************************************************************************
01952  * Select a file to attach to the email.
01953  */
01954 void EditAlarmDlg::slotAddAttachment()
01955 {
01956     QString url = KAlarm::browseFile(i18n("Choose File to Attach"), mAttachDefaultDir, QString::null,
01957                                      QString::null, KFile::ExistingOnly, this, "pickAttachFile");
01958     if (!url.isEmpty())
01959     {
01960         mEmailAttachList->insertItem(url);
01961         mEmailAttachList->setCurrentItem(mEmailAttachList->count() - 1);   // select the new item
01962         mEmailRemoveButton->setEnabled(true);
01963         mEmailAttachList->setEnabled(true);
01964     }
01965 }
01966 
01967 /******************************************************************************
01968  * Remove the currently selected attachment from the email.
01969  */
01970 void EditAlarmDlg::slotRemoveAttachment()
01971 {
01972     int item = mEmailAttachList->currentItem();
01973     mEmailAttachList->removeItem(item);
01974     int count = mEmailAttachList->count();
01975     if (item >= count)
01976         mEmailAttachList->setCurrentItem(count - 1);
01977     if (!count)
01978     {
01979         mEmailRemoveButton->setEnabled(false);
01980         mEmailAttachList->setEnabled(false);
01981     }
01982 }
01983 
01984 /******************************************************************************
01985 *  Clean up the alarm text, and if it's a file, check whether it's valid.
01986 */
01987 bool EditAlarmDlg::checkText(QString& result, bool showErrorMessage) const
01988 {
01989     if (mMessageRadio->isOn())
01990         result = mTextMessageEdit->text();
01991     else if (mEmailRadio->isOn())
01992         result = mEmailMessageEdit->text();
01993     else if (mCommandRadio->isOn())
01994     {
01995         if (mCmdTypeScript->isChecked())
01996             result = mCmdScriptEdit->text();
01997         else
01998             result = mCmdCommandEdit->text();
01999         result = result.stripWhiteSpace();
02000     }
02001     else if (mFileRadio->isOn())
02002     {
02003         QString alarmtext = mFileMessageEdit->text().stripWhiteSpace();
02004         // Convert any relative file path to absolute
02005         // (using home directory as the default)
02006         enum Err { NONE = 0, BLANK, NONEXISTENT, DIRECTORY, UNREADABLE, NOT_TEXT_IMAGE };
02007         Err err = NONE;
02008         KURL url;
02009         int i = alarmtext.find(QString::fromLatin1("/"));
02010         if (i > 0  &&  alarmtext[i - 1] == ':')
02011         {
02012             url = alarmtext;
02013             url.cleanPath();
02014             alarmtext = url.prettyURL();
02015             KIO::UDSEntry uds;
02016             if (!KIO::NetAccess::stat(url, uds, MainWindow::mainMainWindow()))
02017                 err = NONEXISTENT;
02018             else
02019             {
02020                 KFileItem fi(uds, url);
02021                 if (fi.isDir())             err = DIRECTORY;
02022                 else if (!fi.isReadable())  err = UNREADABLE;
02023             }
02024         }
02025         else if (alarmtext.isEmpty())
02026             err = BLANK;    // blank file name
02027         else
02028         {
02029             // It's a local file - convert to absolute path & check validity
02030             QFileInfo info(alarmtext);
02031             QDir::setCurrent(QDir::homeDirPath());
02032             alarmtext = info.absFilePath();
02033             url.setPath(alarmtext);
02034             alarmtext = QString::fromLatin1("file:") + alarmtext;
02035             if (!err)
02036             {
02037                 if      (info.isDir())        err = DIRECTORY;
02038                 else if (!info.exists())      err = NONEXISTENT;
02039                 else if (!info.isReadable())  err = UNREADABLE;
02040             }
02041         }
02042         if (!err)
02043         {
02044             switch (KAlarm::fileType(KFileItem(KFileItem::Unknown, KFileItem::Unknown, url).mimetype()))
02045             {
02046                 case KAlarm::TextFormatted:
02047                 case KAlarm::TextPlain:
02048                 case KAlarm::TextApplication:
02049                 case KAlarm::Image:
02050                     break;
02051                 default:
02052                     err = NOT_TEXT_IMAGE;
02053                     break;
02054             }
02055         }
02056         if (err  &&  showErrorMessage)
02057         {
02058             mFileMessageEdit->setFocus();
02059             QString errmsg;
02060             switch (err)
02061             {
02062                 case BLANK:
02063                     KMessageBox::sorry(const_cast<EditAlarmDlg*>(this), i18n("Please select a file to display"));
02064                     return false;
02065                 case NONEXISTENT:     errmsg = i18n("%1\nnot found");  break;
02066                 case DIRECTORY:       errmsg = i18n("%1\nis a folder");  break;
02067                 case UNREADABLE:      errmsg = i18n("%1\nis not readable");  break;
02068                 case NOT_TEXT_IMAGE:  errmsg = i18n("%1\nappears not to be a text or image file");  break;
02069                 case NONE:
02070                 default:
02071                     break;
02072             }
02073             if (KMessageBox::warningContinueCancel(const_cast<EditAlarmDlg*>(this), errmsg.arg(alarmtext))
02074                 == KMessageBox::Cancel)
02075                 return false;
02076         }
02077         result = alarmtext;
02078     }
02079     return true;
02080 }
02081 
02082 
02083 /*=============================================================================
02084 = Class TextEdit
02085 = A text edit field with a minimum height of 3 text lines.
02086 = Provides KDE 2 compatibility.
02087 =============================================================================*/
02088 TextEdit::TextEdit(QWidget* parent, const char* name)
02089     : QTextEdit(parent, name)
02090 {
02091     QSize tsize = sizeHint();
02092     tsize.setHeight(fontMetrics().lineSpacing()*13/4 + 2*frameWidth());
02093     setMinimumSize(tsize);
02094 }
02095 
02096 void TextEdit::dragEnterEvent(QDragEnterEvent* e)
02097 {
02098     if (KCal::ICalDrag::canDecode(e))
02099         e->accept(false);   // don't accept "text/calendar" objects
02100     QTextEdit::dragEnterEvent(e);
02101 }
KDE Home | KDE Accessibility Home | Description of Access Keys