kalarm

editdlg.cpp

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