kalarm

editdlg.cpp

00001 /*
00002  *  editdlg.cpp  -  dialogue to create or modify an alarm or alarm template
00003  *  Program:  kalarm
00004  *  Copyright (C) 2001 - 2005 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_ShowInKOrganizer()   { return i18n("Show in KOrganizer"); }
00139 QString EditAlarmDlg::i18n_g_ShowInKOrganizer() { return i18n("Show in KOr&ganizer"); }
00140 QString EditAlarmDlg::i18n_EnterScript()        { return i18n("Enter a script"); }
00141 QString EditAlarmDlg::i18n_p_EnterScript()      { return i18n("Enter a scri&pt"); }
00142 QString EditAlarmDlg::i18n_ExecInTermWindow()   { return i18n("Execute in terminal window"); }
00143 QString EditAlarmDlg::i18n_w_ExecInTermWindow() { return i18n("Execute in terminal &window"); }
00144 QString EditAlarmDlg::i18n_u_ExecInTermWindow() { return i18n("Exec&ute in terminal window"); }
00145 QString EditAlarmDlg::i18n_g_LogToFile()        { return i18n("Lo&g to file"); }
00146 QString EditAlarmDlg::i18n_CopyEmailToSelf()    { return i18n("Copy email to self"); }
00147 QString EditAlarmDlg::i18n_e_CopyEmailToSelf()  { return i18n("Copy &email to self"); }
00148 QString EditAlarmDlg::i18n_s_CopyEmailToSelf()  { return i18n("Copy email to &self"); }
00149 QString EditAlarmDlg::i18n_EmailFrom()          { return i18n("'From' email address", "From:"); }
00150 QString EditAlarmDlg::i18n_f_EmailFrom()        { return i18n("'From' email address", "&From:"); }
00151 QString EditAlarmDlg::i18n_EmailTo()            { return i18n("Email addressee", "To:"); }
00152 QString EditAlarmDlg::i18n_EmailSubject()       { return i18n("Email subject", "Subject:"); }
00153 QString EditAlarmDlg::i18n_j_EmailSubject()     { return i18n("Email subject", "Sub&ject:"); }
00154 
00155 
00156 /******************************************************************************
00157  * Constructor.
00158  * Parameters:
00159  *   Template = true to edit/create an alarm template
00160  *            = false to edit/create an alarm.
00161  *   event   != to initialise the dialogue to show the specified event's data.
00162  */
00163 EditAlarmDlg::EditAlarmDlg(bool Template, const QString& caption, QWidget* parent, const char* name,
00164                            const KAEvent* event, bool readOnly)
00165     : KDialogBase(parent, name, true, caption,
00166                   (readOnly ? Cancel|Try : Template ? Ok|Cancel|Try : Ok|Cancel|Try|Default),
00167                   (readOnly ? Cancel : Ok)),
00168       mMainPageShown(false),
00169       mRecurPageShown(false),
00170       mRecurSetDefaultEndDate(true),
00171       mTemplateName(0),
00172       mSpecialActionsButton(0),
00173       mReminderDeferral(false),
00174       mReminderArchived(false),
00175       mEmailRemoveButton(0),
00176       mDeferGroup(0),
00177       mTimeWidget(0),
00178       mShowInKorganizer(0),
00179       mDeferGroupHeight(0),
00180       mTemplate(Template),
00181       mDesiredReadOnly(readOnly),
00182       mReadOnly(readOnly),
00183       mSavedEvent(0)
00184 {
00185     setButtonText(Default, i18n("Load Template..."));
00186     QVBox* mainWidget = new QVBox(this);
00187     mainWidget->setSpacing(spacingHint());
00188     setMainWidget(mainWidget);
00189     if (mTemplate)
00190     {
00191         QHBox* box = new QHBox(mainWidget);
00192         box->setSpacing(spacingHint());
00193         QLabel* label = new QLabel(i18n("Template name:"), box);
00194         label->setFixedSize(label->sizeHint());
00195         mTemplateName = new QLineEdit(box);
00196         mTemplateName->setReadOnly(mReadOnly);
00197         label->setBuddy(mTemplateName);
00198         QWhatsThis::add(box, i18n("Enter the name of the alarm template"));
00199         box->setFixedHeight(box->sizeHint().height());
00200     }
00201     mTabs = new QTabWidget(mainWidget);
00202     mTabs->setMargin(marginHint());
00203 
00204     QVBox* mainPageBox = new QVBox(mTabs);
00205     mainPageBox->setSpacing(spacingHint());
00206     mTabs->addTab(mainPageBox, i18n("&Alarm"));
00207     mMainPageIndex = 0;
00208     PageFrame* mainPage = new PageFrame(mainPageBox);
00209     connect(mainPage, SIGNAL(shown()), SLOT(slotShowMainPage()));
00210     QVBoxLayout* topLayout = new QVBoxLayout(mainPage, 0, spacingHint());
00211 
00212     // Recurrence tab
00213     QVBox* recurTab = new QVBox(mTabs);
00214     mainPageBox->setSpacing(spacingHint());
00215     mTabs->addTab(recurTab, i18n("&Recurrence"));
00216     mRecurPageIndex = 1;
00217     mRecurrenceEdit = new RecurrenceEdit(readOnly, recurTab, "recurPage");
00218     connect(mRecurrenceEdit, SIGNAL(shown()), SLOT(slotShowRecurrenceEdit()));
00219     connect(mRecurrenceEdit, SIGNAL(typeChanged(int)), SLOT(slotRecurTypeChange(int)));
00220     connect(mRecurrenceEdit, SIGNAL(frequencyChanged()), SLOT(slotRecurFrequencyChange()));
00221 
00222     // Alarm action
00223 
00224     mActionGroup = new ButtonGroup(i18n("Action"), mainPage, "actionGroup");
00225     connect(mActionGroup, SIGNAL(buttonSet(int)), SLOT(slotAlarmTypeChanged(int)));
00226     topLayout->addWidget(mActionGroup, 1);
00227     QGridLayout* grid = new QGridLayout(mActionGroup, 3, 5, marginHint(), spacingHint());
00228     grid->addRowSpacing(0, fontMetrics().lineSpacing()/2);
00229 
00230     // Message radio button
00231     mMessageRadio = new RadioButton(i18n("Te&xt"), mActionGroup, "messageButton");
00232     mMessageRadio->setFixedSize(mMessageRadio->sizeHint());
00233     QWhatsThis::add(mMessageRadio,
00234           i18n("If checked, the alarm will display a text message."));
00235     grid->addWidget(mMessageRadio, 1, 0);
00236     grid->setColStretch(1, 1);
00237 
00238     // File radio button
00239     mFileRadio = new PickAlarmFileRadio(i18n("&File"), mActionGroup, "fileButton");
00240     mFileRadio->setFixedSize(mFileRadio->sizeHint());
00241     QWhatsThis::add(mFileRadio,
00242           i18n("If checked, the alarm will display the contents of a text or image file."));
00243     grid->addWidget(mFileRadio, 1, 2);
00244     grid->setColStretch(3, 1);
00245 
00246     // Command radio button
00247     mCommandRadio = new RadioButton(i18n("Co&mmand"), mActionGroup, "cmdButton");
00248     mCommandRadio->setFixedSize(mCommandRadio->sizeHint());
00249     QWhatsThis::add(mCommandRadio,
00250           i18n("If checked, the alarm will execute a shell command."));
00251     grid->addWidget(mCommandRadio, 1, 4);
00252     grid->setColStretch(5, 1);
00253 
00254     // Email radio button
00255     mEmailRadio = new RadioButton(i18n("&Email"), mActionGroup, "emailButton");
00256     mEmailRadio->setFixedSize(mEmailRadio->sizeHint());
00257     QWhatsThis::add(mEmailRadio,
00258           i18n("If checked, the alarm will send an email."));
00259     grid->addWidget(mEmailRadio, 1, 6);
00260 
00261     initDisplayAlarms(mActionGroup);
00262     initCommand(mActionGroup);
00263     initEmail(mActionGroup);
00264     mAlarmTypeStack = new QWidgetStack(mActionGroup);
00265     grid->addMultiCellWidget(mAlarmTypeStack, 2, 2, 0, 6);
00266     grid->setRowStretch(2, 1);
00267     mAlarmTypeStack->addWidget(mDisplayAlarmsFrame, 0);
00268     mAlarmTypeStack->addWidget(mCommandFrame, 1);
00269     mAlarmTypeStack->addWidget(mEmailFrame, 1);
00270 
00271     // Deferred date/time: visible only for a deferred recurring event.
00272     mDeferGroup = new QGroupBox(1, Qt::Vertical, i18n("Deferred Alarm"), mainPage, "deferGroup");
00273     topLayout->addWidget(mDeferGroup);
00274     QLabel* label = new QLabel(i18n("Deferred to:"), mDeferGroup);
00275     label->setFixedSize(label->sizeHint());
00276     mDeferTimeLabel = new QLabel(mDeferGroup);
00277 
00278     mDeferChangeButton = new QPushButton(i18n("C&hange..."), mDeferGroup);
00279     mDeferChangeButton->setFixedSize(mDeferChangeButton->sizeHint());
00280     connect(mDeferChangeButton, SIGNAL(clicked()), SLOT(slotEditDeferral()));
00281     QWhatsThis::add(mDeferChangeButton, i18n("Change the alarm's deferred time, or cancel the deferral"));
00282     mDeferGroup->addSpace(0);
00283 
00284     QBoxLayout* layout = new QHBoxLayout(topLayout);
00285 
00286     // Date and time entry
00287     if (mTemplate)
00288     {
00289         mTemplateTimeGroup = new ButtonGroup(i18n("Time"), mainPage, "templateGroup");
00290         connect(mTemplateTimeGroup, SIGNAL(buttonSet(int)), SLOT(slotTemplateTimeType(int)));
00291         layout->addWidget(mTemplateTimeGroup);
00292         grid = new QGridLayout(mTemplateTimeGroup, 2, 2, marginHint(), spacingHint());
00293         grid->addRowSpacing(0, fontMetrics().lineSpacing()/2);
00294         // Get alignment to use in QGridLayout (AlignAuto doesn't work correctly there)
00295         int alignment = QApplication::reverseLayout() ? Qt::AlignRight : Qt::AlignLeft;
00296 
00297         mTemplateDefaultTime = new RadioButton(i18n("&Default time"), mTemplateTimeGroup, "templateDefTimeButton");
00298         mTemplateDefaultTime->setFixedSize(mTemplateDefaultTime->sizeHint());
00299         mTemplateDefaultTime->setReadOnly(mReadOnly);
00300         QWhatsThis::add(mTemplateDefaultTime,
00301               i18n("Do not specify a start time for alarms based on this template. "
00302                    "The normal default start time will be used."));
00303         grid->addWidget(mTemplateDefaultTime, 0, 0, alignment);
00304 
00305         QHBox* box = new QHBox(mTemplateTimeGroup);
00306         box->setSpacing(spacingHint());
00307         mTemplateUseTime = new RadioButton(i18n("Time:"), box, "templateTimeButton");
00308         mTemplateUseTime->setFixedSize(mTemplateUseTime->sizeHint());
00309         mTemplateUseTime->setReadOnly(mReadOnly);
00310         QWhatsThis::add(mTemplateUseTime,
00311               i18n("Specify a start time for alarms based on this template."));
00312         mTemplateTimeGroup->insert(mTemplateUseTime);
00313         mTemplateTime = new TimeEdit(box, "templateTimeEdit");
00314         mTemplateTime->setFixedSize(mTemplateTime->sizeHint());
00315         mTemplateTime->setReadOnly(mReadOnly);
00316         QWhatsThis::add(mTemplateTime,
00317               QString("%1\n\n%2").arg(i18n("Enter the start time for alarms based on this template."))
00318                                  .arg(TimeSpinBox::shiftWhatsThis()));
00319         box->setStretchFactor(new QWidget(box), 1);    // left adjust the controls
00320         box->setFixedHeight(box->sizeHint().height());
00321         grid->addWidget(box, 0, 1, alignment);
00322 
00323         mTemplateAnyTime = new RadioButton(i18n("An&y time"), mTemplateTimeGroup, "templateAnyTimeButton");
00324         mTemplateAnyTime->setFixedSize(mTemplateAnyTime->sizeHint());
00325         mTemplateAnyTime->setReadOnly(mReadOnly);
00326         QWhatsThis::add(mTemplateAnyTime,
00327               i18n("Set the '%1' option for alarms based on this template.").arg(i18n("Any time")));
00328         grid->addWidget(mTemplateAnyTime, 1, 0, alignment);
00329 
00330         box = new QHBox(mTemplateTimeGroup);
00331         box->setSpacing(spacingHint());
00332         mTemplateUseTimeAfter = new RadioButton(AlarmTimeWidget::i18n_w_TimeFromNow(), box, "templateFromNowButton");
00333         mTemplateUseTimeAfter->setFixedSize(mTemplateUseTimeAfter->sizeHint());
00334         mTemplateUseTimeAfter->setReadOnly(mReadOnly);
00335         QWhatsThis::add(mTemplateUseTimeAfter,
00336               i18n("Set alarms based on this template to start after the specified time "
00337                    "interval from when the alarm is created."));
00338         mTemplateTimeGroup->insert(mTemplateUseTimeAfter);
00339         mTemplateTimeAfter = new TimeSpinBox(1, maxDelayTime, box);
00340         mTemplateTimeAfter->setValue(1439);
00341         mTemplateTimeAfter->setFixedSize(mTemplateTimeAfter->sizeHint());
00342         mTemplateTimeAfter->setReadOnly(mReadOnly);
00343         QWhatsThis::add(mTemplateTimeAfter,
00344               QString("%1\n\n%2").arg(AlarmTimeWidget::i18n_TimeAfterPeriod())
00345                                  .arg(TimeSpinBox::shiftWhatsThis()));
00346         box->setFixedHeight(box->sizeHint().height());
00347         grid->addWidget(box, 1, 1, alignment);
00348 
00349         layout->addStretch();
00350     }
00351     else
00352     {
00353         mTimeWidget = new AlarmTimeWidget(i18n("Time"), AlarmTimeWidget::AT_TIME, mainPage, "timeGroup");
00354         connect(mTimeWidget, SIGNAL(anyTimeToggled(bool)), SLOT(slotAnyTimeToggled(bool)));
00355         topLayout->addWidget(mTimeWidget);
00356     }
00357 
00358     // Recurrence type display
00359     layout = new QHBoxLayout(topLayout, 2*spacingHint());
00360     QHBox* box = new QHBox(mainPage);   // this is to control the QWhatsThis text display area
00361     box->setSpacing(KDialog::spacingHint());
00362     label = new QLabel(i18n("Recurrence:"), box);
00363     label->setFixedSize(label->sizeHint());
00364     mRecurrenceText = new QLabel(box);
00365     QWhatsThis::add(box,
00366           i18n("How often the alarm recurs.\nThe times shown are those configured in the Recurrence tab and in the Simple Repetition dialog."));
00367     box->setFixedHeight(box->sizeHint().height());
00368     layout->addWidget(box);
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     if (theApp()->korganizerEnabled())
00379     {
00380         // Show in KOrganizer checkbox
00381         mShowInKorganizer = new CheckBox(i18n_ShowInKOrganizer(), mainPage);
00382         mShowInKorganizer->setFixedSize(mShowInKorganizer->sizeHint());
00383         QWhatsThis::add(mShowInKorganizer, i18n("Check to copy the alarm into KOrganizer's calendar"));
00384         layout->addWidget(mShowInKorganizer);
00385     }
00386     layout->addStretch();
00387 
00388     // Late cancel selector - default = allow late display
00389     mLateCancel = new LateCancelSelector(true, mainPage);
00390     topLayout->addWidget(mLateCancel, 0, Qt::AlignAuto);
00391 
00392     setButtonWhatsThis(Ok, i18n("Schedule the alarm at the specified time."));
00393 
00394     // Initialise the state of all controls according to the specified event, if any
00395     initialise(event);
00396     if (mTemplateName)
00397         mTemplateName->setFocus();
00398 
00399     // Save the initial state of all controls so that we can later tell if they have changed
00400     saveState(event);
00401 
00402     // Note the current desktop so that the dialog can be shown on it.
00403     // If a main window is visible, the dialog will by KDE default always appear on its
00404     // desktop. If the user invokes the dialog via the system tray on a different desktop,
00405     // that can cause confusion.
00406     mDesktop = KWin::currentDesktop();
00407 }
00408 
00409 EditAlarmDlg::~EditAlarmDlg()
00410 {
00411     delete mSavedEvent;
00412 }
00413 
00414 /******************************************************************************
00415  * Set up the dialog controls common to display alarms.
00416  */
00417 void EditAlarmDlg::initDisplayAlarms(QWidget* parent)
00418 {
00419     mDisplayAlarmsFrame = new QFrame(parent);
00420     mDisplayAlarmsFrame->setFrameStyle(QFrame::NoFrame);
00421     QBoxLayout* frameLayout = new QVBoxLayout(mDisplayAlarmsFrame, 0, spacingHint());
00422 
00423     // Text message edit box
00424     mTextMessageEdit = new TextEdit(mDisplayAlarmsFrame);
00425     mTextMessageEdit->setWordWrap(QTextEdit::NoWrap);
00426     QWhatsThis::add(mTextMessageEdit, i18n("Enter the text of the alarm message. It may be multi-line."));
00427     frameLayout->addWidget(mTextMessageEdit);
00428 
00429     // File name edit box
00430     mFileBox = new QHBox(mDisplayAlarmsFrame);
00431     frameLayout->addWidget(mFileBox);
00432     mFileMessageEdit = new LineEdit(LineEdit::Url, mFileBox);
00433     mFileMessageEdit->setAcceptDrops(true);
00434     QWhatsThis::add(mFileMessageEdit, i18n("Enter the name or URL of a text or image file to display."));
00435 
00436     // File browse button
00437     mFileBrowseButton = new QPushButton(mFileBox);
00438     mFileBrowseButton->setPixmap(SmallIcon("fileopen"));
00439     mFileBrowseButton->setFixedSize(mFileBrowseButton->sizeHint());
00440     QToolTip::add(mFileBrowseButton, i18n("Choose a file"));
00441     QWhatsThis::add(mFileBrowseButton, i18n("Select a text or image file to display."));
00442     mFileRadio->init(mFileBrowseButton, mFileMessageEdit);
00443 
00444     // Colour choice drop-down list
00445     QBoxLayout* layout = new QHBoxLayout(frameLayout);
00446     QHBox* box;
00447     mBgColourChoose = createBgColourChooser(&box, mDisplayAlarmsFrame);
00448     mBgColourChoose->setFixedSize(mBgColourChoose->sizeHint());
00449     connect(mBgColourChoose, SIGNAL(highlighted(const QColor&)), SLOT(slotBgColourSelected(const QColor&)));
00450     layout->addWidget(box);
00451     layout->addSpacing(2*KDialog::spacingHint());
00452     layout->addStretch();
00453 
00454     // Font and colour choice drop-down list
00455     mFontColourButton = new FontColourButton(mDisplayAlarmsFrame);
00456     mFontColourButton->setFixedSize(mFontColourButton->sizeHint());
00457     connect(mFontColourButton, SIGNAL(selected()), SLOT(slotFontColourSelected()));
00458     layout->addWidget(mFontColourButton);
00459 
00460     // Sound checkbox and file selector
00461     mSoundPicker = new SoundPicker(mDisplayAlarmsFrame);
00462     mSoundPicker->setFixedSize(mSoundPicker->sizeHint());
00463     frameLayout->addWidget(mSoundPicker, 0, Qt::AlignAuto);
00464 
00465     // Reminder
00466     static const QString reminderText = i18n("Enter how long in advance of the main alarm to display a reminder alarm.");
00467     mReminder = new Reminder(i18n("Rem&inder:"),
00468                              i18n("Check to additionally display a reminder in advance of the main alarm time(s)."),
00469                              QString("%1\n\n%2").arg(reminderText).arg(TimeSpinBox::shiftWhatsThis()),
00470                              true, true, mDisplayAlarmsFrame);
00471     mReminder->setFixedSize(mReminder->sizeHint());
00472     frameLayout->addWidget(mReminder, 0, Qt::AlignAuto);
00473 
00474     // Acknowledgement confirmation required - default = no confirmation
00475     layout = new QHBoxLayout(frameLayout);
00476     mConfirmAck = createConfirmAckCheckbox(mDisplayAlarmsFrame);
00477     mConfirmAck->setFixedSize(mConfirmAck->sizeHint());
00478     layout->addWidget(mConfirmAck);
00479     layout->addSpacing(2*KDialog::spacingHint());
00480     layout->addStretch();
00481 
00482     if (ShellProcess::authorised())    // don't display if shell commands not allowed (e.g. kiosk mode)
00483     {
00484         // Special actions button
00485         mSpecialActionsButton = new SpecialActionsButton(i18n("Special Actions..."), mDisplayAlarmsFrame);
00486         mSpecialActionsButton->setFixedSize(mSpecialActionsButton->sizeHint());
00487         layout->addWidget(mSpecialActionsButton);
00488     }
00489 
00490     // Top-adjust the controls
00491     mFilePadding = new QHBox(mDisplayAlarmsFrame);
00492     frameLayout->addWidget(mFilePadding);
00493     frameLayout->setStretchFactor(mFilePadding, 1);
00494 }
00495 
00496 /******************************************************************************
00497  * Set up the command alarm dialog controls.
00498  */
00499 void EditAlarmDlg::initCommand(QWidget* parent)
00500 {
00501     mCommandFrame = new QFrame(parent);
00502     mCommandFrame->setFrameStyle(QFrame::NoFrame);
00503     QBoxLayout* frameLayout = new QVBoxLayout(mCommandFrame, 0, spacingHint());
00504 
00505     mCmdTypeScript = new CheckBox(i18n_p_EnterScript(), mCommandFrame);
00506     mCmdTypeScript->setFixedSize(mCmdTypeScript->sizeHint());
00507     connect(mCmdTypeScript, SIGNAL(toggled(bool)), SLOT(slotCmdScriptToggled(bool)));
00508     QWhatsThis::add(mCmdTypeScript, i18n("Check to enter the contents of a script instead of a shell command line"));
00509     frameLayout->addWidget(mCmdTypeScript, 0, Qt::AlignAuto);
00510 
00511     mCmdCommandEdit = new LineEdit(LineEdit::Url, mCommandFrame);
00512     QWhatsThis::add(mCmdCommandEdit, i18n("Enter a shell command to execute."));
00513     frameLayout->addWidget(mCmdCommandEdit);
00514 
00515     mCmdScriptEdit = new TextEdit(mCommandFrame);
00516     QWhatsThis::add(mCmdScriptEdit, i18n("Enter the contents of a script to execute"));
00517     frameLayout->addWidget(mCmdScriptEdit);
00518 
00519     // What to do with command output
00520 
00521     mCmdOutputGroup = new ButtonGroup(i18n("Command Output"), mCommandFrame);
00522     frameLayout->addWidget(mCmdOutputGroup);
00523     QBoxLayout* layout = new QVBoxLayout(mCmdOutputGroup, marginHint(), spacingHint());
00524     layout->addSpacing(fontMetrics().lineSpacing()/2);
00525 
00526     // Execute in terminal window
00527     RadioButton* button = new RadioButton(i18n_u_ExecInTermWindow(), mCmdOutputGroup, "execInTerm");
00528     button->setFixedSize(button->sizeHint());
00529     QWhatsThis::add(button, i18n("Check to execute the command in a terminal window"));
00530     mCmdOutputGroup->insert(button, EXEC_IN_TERMINAL);
00531     layout->addWidget(button, 0, Qt::AlignAuto);
00532 
00533     // Log file name edit box
00534     QHBox* box = new QHBox(mCmdOutputGroup);
00535     (new QWidget(box))->setFixedWidth(button->style().subRect(QStyle::SR_RadioButtonIndicator, button).width());   // indent the edit box
00536 //  (new QWidget(box))->setFixedWidth(button->style().pixelMetric(QStyle::PM_ExclusiveIndicatorWidth));   // indent the edit box
00537     mCmdLogFileEdit = new LineEdit(LineEdit::Url, box);
00538     mCmdLogFileEdit->setAcceptDrops(true);
00539     QWhatsThis::add(mCmdLogFileEdit, i18n("Enter the name or path of the log file."));
00540 
00541     // Log file browse button.
00542     // The file browser dialogue is activated by the PickLogFileRadio class.
00543     QPushButton* browseButton = new QPushButton(box);
00544     browseButton->setPixmap(SmallIcon("fileopen"));
00545     browseButton->setFixedSize(browseButton->sizeHint());
00546     QToolTip::add(browseButton, i18n("Choose a file"));
00547     QWhatsThis::add(browseButton, i18n("Select a log file."));
00548 
00549     // Log output to file
00550     button = new PickLogFileRadio(browseButton, mCmdLogFileEdit, i18n_g_LogToFile(), mCmdOutputGroup, "cmdLog");
00551     button->setFixedSize(button->sizeHint());
00552     QWhatsThis::add(button,
00553           i18n("Check to log the command output to a local file. The output will be appended to any existing contents of the file."));
00554     mCmdOutputGroup->insert(button, LOG_TO_FILE);
00555     layout->addWidget(button, 0, Qt::AlignAuto);
00556     layout->addWidget(box);
00557 
00558     // Discard output
00559     button = new RadioButton(i18n("Discard"), mCmdOutputGroup, "cmdDiscard");
00560     button->setFixedSize(button->sizeHint());
00561     QWhatsThis::add(button, i18n("Check to discard command output."));
00562     mCmdOutputGroup->insert(button, DISCARD_OUTPUT);
00563     layout->addWidget(button, 0, Qt::AlignAuto);
00564 
00565     // Top-adjust the controls
00566     mCmdPadding = new QHBox(mCommandFrame);
00567     frameLayout->addWidget(mCmdPadding);
00568     frameLayout->setStretchFactor(mCmdPadding, 1);
00569 }
00570 
00571 /******************************************************************************
00572  * Set up the email alarm dialog controls.
00573  */
00574 void EditAlarmDlg::initEmail(QWidget* parent)
00575 {
00576     mEmailFrame = new QFrame(parent);
00577     mEmailFrame->setFrameStyle(QFrame::NoFrame);
00578     QBoxLayout* layout = new QVBoxLayout(mEmailFrame, 0, spacingHint());
00579     QGridLayout* grid = new QGridLayout(layout, 3, 3, spacingHint());
00580     grid->setColStretch(1, 1);
00581 
00582     mEmailFromList = 0;
00583     if (Preferences::emailFrom() == Preferences::MAIL_FROM_KMAIL)
00584     {
00585         // Email sender identity
00586         QLabel* label = new QLabel(i18n_EmailFrom(), mEmailFrame);
00587         label->setFixedSize(label->sizeHint());
00588         grid->addWidget(label, 0, 0);
00589 
00590         mEmailFromList = new EmailIdCombo(KAMail::identityManager(), mEmailFrame);
00591         mEmailFromList->setMinimumSize(mEmailFromList->sizeHint());
00592         label->setBuddy(mEmailFromList);
00593         QWhatsThis::add(mEmailFromList,
00594               i18n("Your email identity, used to identify you as the sender when sending email alarms."));
00595         grid->addMultiCellWidget(mEmailFromList, 0, 0, 1, 2);
00596     }
00597 
00598     // Email recipients
00599     QLabel* label = new QLabel(i18n_EmailTo(), mEmailFrame);
00600     label->setFixedSize(label->sizeHint());
00601     grid->addWidget(label, 1, 0);
00602 
00603     mEmailToEdit = new LineEdit(LineEdit::Emails, mEmailFrame);
00604     mEmailToEdit->setMinimumSize(mEmailToEdit->sizeHint());
00605     QWhatsThis::add(mEmailToEdit,
00606           i18n("Enter the addresses of the email recipients. Separate multiple addresses by "
00607                "commas or semicolons."));
00608     grid->addWidget(mEmailToEdit, 1, 1);
00609 
00610     mEmailAddressButton = new QPushButton(mEmailFrame);
00611     mEmailAddressButton->setPixmap(SmallIcon("contents"));
00612     mEmailAddressButton->setFixedSize(mEmailAddressButton->sizeHint());
00613     connect(mEmailAddressButton, SIGNAL(clicked()), SLOT(openAddressBook()));
00614     QToolTip::add(mEmailAddressButton, i18n("Open address book"));
00615     QWhatsThis::add(mEmailAddressButton, i18n("Select email addresses from your address book."));
00616     grid->addWidget(mEmailAddressButton, 1, 2);
00617 
00618     // Email subject
00619     label = new QLabel(i18n_j_EmailSubject(), mEmailFrame);
00620     label->setFixedSize(label->sizeHint());
00621     grid->addWidget(label, 2, 0);
00622 
00623     mEmailSubjectEdit = new LineEdit(mEmailFrame);
00624     mEmailSubjectEdit->setMinimumSize(mEmailSubjectEdit->sizeHint());
00625     label->setBuddy(mEmailSubjectEdit);
00626     QWhatsThis::add(mEmailSubjectEdit, i18n("Enter the email subject."));
00627     grid->addMultiCellWidget(mEmailSubjectEdit, 2, 2, 1, 2);
00628 
00629     // Email body
00630     mEmailMessageEdit = new TextEdit(mEmailFrame);
00631     QWhatsThis::add(mEmailMessageEdit, i18n("Enter the email message."));
00632     layout->addWidget(mEmailMessageEdit);
00633 
00634     // Email attachments
00635     grid = new QGridLayout(layout, 2, 3, spacingHint());
00636     label = new QLabel(i18n("Attachment&s:"), mEmailFrame);
00637     label->setFixedSize(label->sizeHint());
00638     grid->addWidget(label, 0, 0);
00639 
00640     mEmailAttachList = new QComboBox(true, mEmailFrame);
00641     mEmailAttachList->setMinimumSize(mEmailAttachList->sizeHint());
00642     mEmailAttachList->lineEdit()->setReadOnly(true);
00643 QListBox* list = mEmailAttachList->listBox();
00644 QRect rect = list->geometry();
00645 list->setGeometry(rect.left() - 50, rect.top(), rect.width(), rect.height());
00646     label->setBuddy(mEmailAttachList);
00647     QWhatsThis::add(mEmailAttachList,
00648           i18n("Files to send as attachments to the email."));
00649     grid->addWidget(mEmailAttachList, 0, 1);
00650     grid->setColStretch(1, 1);
00651 
00652     mEmailAddAttachButton = new QPushButton(i18n("Add..."), mEmailFrame);
00653     connect(mEmailAddAttachButton, SIGNAL(clicked()), SLOT(slotAddAttachment()));
00654     QWhatsThis::add(mEmailAddAttachButton, i18n("Add an attachment to the email."));
00655     grid->addWidget(mEmailAddAttachButton, 0, 2);
00656 
00657     mEmailRemoveButton = new QPushButton(i18n("Remo&ve"), mEmailFrame);
00658     connect(mEmailRemoveButton, SIGNAL(clicked()), SLOT(slotRemoveAttachment()));
00659     QWhatsThis::add(mEmailRemoveButton, i18n("Remove the highlighted attachment from the email."));
00660     grid->addWidget(mEmailRemoveButton, 1, 2);
00661 
00662     // BCC email to sender
00663     mEmailBcc = new CheckBox(i18n_s_CopyEmailToSelf(), mEmailFrame);
00664     mEmailBcc->setFixedSize(mEmailBcc->sizeHint());
00665     QWhatsThis::add(mEmailBcc,
00666           i18n("If checked, the email will be blind copied to you."));
00667     grid->addMultiCellWidget(mEmailBcc, 1, 1, 0, 1, Qt::AlignAuto);
00668 }
00669 
00670 /******************************************************************************
00671  * Initialise the dialogue controls from the specified event.
00672  */
00673 void EditAlarmDlg::initialise(const KAEvent* event)
00674 {
00675     mReadOnly = mDesiredReadOnly;
00676     if (!mTemplate  &&  event  &&  event->action() == KAEvent::COMMAND  &&  !ShellProcess::authorised())
00677         mReadOnly = true;     // don't allow editing of existing command alarms in kiosk mode
00678     setReadOnly();
00679 
00680     mChanged           = false;
00681     mOnlyDeferred      = false;
00682     mExpiredRecurrence = false;
00683     mKMailSerialNumber = 0;
00684     bool deferGroupVisible = false;
00685     if (event)
00686     {
00687         // Set the values to those for the specified event
00688         if (mTemplate)
00689             mTemplateName->setText(event->templateName());
00690         bool recurs = event->recurs();
00691         if ((recurs || event->repeatCount())  &&  !mTemplate  &&  event->deferred())
00692         {
00693             deferGroupVisible = true;
00694             mDeferDateTime = event->deferDateTime();
00695             mDeferTimeLabel->setText(mDeferDateTime.formatLocale());
00696             mDeferGroup->show();
00697         }
00698         if (event->defaultFont())
00699             mFontColourButton->setDefaultFont();
00700         else
00701             mFontColourButton->setFont(event->font());
00702         mFontColourButton->setBgColour(event->bgColour());
00703         mFontColourButton->setFgColour(event->fgColour());
00704         mBgColourChoose->setColour(event->bgColour());     // set colour before setting alarm type buttons
00705         if (mTemplate)
00706         {
00707             // Editing a template
00708             int afterTime = event->isTemplate() ? event->templateAfterTime() : -1;
00709             bool noTime   = !afterTime;
00710             bool useTime  = !event->mainDateTime().isDateOnly();
00711             int button = mTemplateTimeGroup->id(noTime          ? mTemplateDefaultTime :
00712                                                 (afterTime > 0) ? mTemplateUseTimeAfter :
00713                                                 useTime         ? mTemplateUseTime : mTemplateAnyTime);
00714             mTemplateTimeGroup->setButton(button);
00715             mTemplateTimeAfter->setValue(afterTime > 0 ? afterTime : 1);
00716             if (!noTime && useTime)
00717                 mTemplateTime->setValue(event->mainDateTime().time());
00718             else
00719                 mTemplateTime->setValue(0);
00720         }
00721         else
00722         {
00723             if (event->isTemplate())
00724             {
00725                 // Initialising from an alarm template: use current date
00726                 QDateTime now = QDateTime::currentDateTime();
00727                 int afterTime = event->templateAfterTime();
00728                 if (afterTime >= 0)
00729                 {
00730                     mTimeWidget->setDateTime(now.addSecs(afterTime * 60));
00731                     mTimeWidget->selectTimeFromNow();
00732                 }
00733                 else
00734                 {
00735                     QDate d = now.date();
00736                     QTime t = event->startDateTime().time();
00737                     bool dateOnly = event->startDateTime().isDateOnly();
00738                     if (!dateOnly  &&  now.time() >= t)
00739                         d = d.addDays(1);     // alarm time has already passed, so use tomorrow
00740                     mTimeWidget->setDateTime(DateTime(QDateTime(d, t), dateOnly));
00741                 }
00742             }
00743             else
00744             {
00745                 mExpiredRecurrence = recurs && event->mainExpired();
00746                 mTimeWidget->setDateTime(!event->mainExpired() ? event->mainDateTime()
00747                                          : recurs ? DateTime() : event->deferDateTime());
00748             }
00749         }
00750 
00751         KAEvent::Action action = event->action();
00752         AlarmText altext;
00753         if (event->commandScript())
00754             altext.setScript(event->cleanText());
00755         else
00756             altext.setText(event->cleanText());
00757         setAction(action, altext);
00758         if (action == KAEvent::MESSAGE  &&  event->kmailSerialNumber()
00759         &&  AlarmText::checkIfEmail(event->cleanText()))
00760             mKMailSerialNumber = event->kmailSerialNumber();
00761         if (action == KAEvent::EMAIL)
00762             mEmailAttachList->insertStringList(event->emailAttachments());
00763 
00764         mLateCancel->setMinutes(event->lateCancel(), event->startDateTime().isDateOnly(),
00765                                 TimePeriod::HOURS_MINUTES);
00766         mLateCancel->showAutoClose(action == KAEvent::MESSAGE || action == KAEvent::FILE);
00767         mLateCancel->setAutoClose(event->autoClose());
00768         mLateCancel->setFixedSize(mLateCancel->sizeHint());
00769         if (mShowInKorganizer)
00770             mShowInKorganizer->setChecked(event->copyToKOrganizer());
00771         mConfirmAck->setChecked(event->confirmAck());
00772         int reminder = event->reminder();
00773         if (!reminder  &&  event->reminderDeferral()  &&  !recurs)
00774         {
00775             reminder = event->reminderDeferral();
00776             mReminderDeferral = true;
00777         }
00778         if (!reminder  &&  event->reminderArchived()  &&  recurs)
00779         {
00780             reminder = event->reminderArchived();
00781             mReminderArchived = true;
00782         }
00783         mReminder->setMinutes(reminder, (mTimeWidget ? mTimeWidget->anyTime() : mTemplateAnyTime->isOn()));
00784         mReminder->setOnceOnly(event->reminderOnceOnly());
00785         mReminder->enableOnceOnly(event->recurs());
00786         if (mSpecialActionsButton)
00787             mSpecialActionsButton->setActions(event->preAction(), event->postAction());
00788         mSimpleRepetition->set(event->repeatInterval(), event->repeatCount());
00789         mRecurrenceText->setText(recurText(*event));
00790         mRecurrenceEdit->set(*event);   // must be called after mTimeWidget is set up, to ensure correct date-only enabling
00791         SoundPicker::Type soundType = event->speak()                                ? SoundPicker::SPEAK
00792                                     : event->beep() || event->audioFile().isEmpty() ? SoundPicker::BEEP
00793                                     :                                                 SoundPicker::PLAY_FILE;
00794         mSoundPicker->set((soundType != SoundPicker::BEEP || event->beep()), soundType, event->audioFile(),
00795                           event->soundVolume(), event->fadeVolume(), event->fadeSeconds(), event->repeatSound());
00796         CmdLogType logType = event->commandXterm()       ? EXEC_IN_TERMINAL
00797                            : !event->logFile().isEmpty() ? LOG_TO_FILE
00798                            :                               DISCARD_OUTPUT;
00799         if (logType == LOG_TO_FILE)
00800             mCmdLogFileEdit->setText(event->logFile());    // set file name before setting radio button
00801         mCmdOutputGroup->setButton(logType);
00802         mEmailToEdit->setText(event->emailAddresses(", "));
00803         mEmailSubjectEdit->setText(event->emailSubject());
00804         mEmailBcc->setChecked(event->emailBcc());
00805         if (mEmailFromList)
00806             mEmailFromList->setCurrentIdentity(event->emailFromKMail());
00807     }
00808     else
00809     {
00810         // Set the values to their defaults
00811         if (!ShellProcess::authorised())
00812         {
00813             // Don't allow shell commands in kiosk mode
00814             mCommandRadio->setEnabled(false);
00815             if (mSpecialActionsButton)
00816                 mSpecialActionsButton->setEnabled(false);
00817         }
00818         mFontColourButton->setDefaultFont();
00819         mFontColourButton->setBgColour(Preferences::defaultBgColour());
00820         mFontColourButton->setFgColour(Preferences::defaultFgColour());
00821         mBgColourChoose->setColour(Preferences::defaultBgColour());     // set colour before setting alarm type buttons
00822         QDateTime defaultTime = QDateTime::currentDateTime().addSecs(60);
00823         if (mTemplate)
00824         {
00825             mTemplateTimeGroup->setButton(mTemplateTimeGroup->id(mTemplateDefaultTime));
00826             mTemplateTime->setValue(0);
00827             mTemplateTimeAfter->setValue(1);
00828         }
00829         else
00830             mTimeWidget->setDateTime(defaultTime);
00831         mActionGroup->setButton(mActionGroup->id(mMessageRadio));
00832         mLateCancel->setMinutes((Preferences::defaultLateCancel() ? 1 : 0), false, TimePeriod::HOURS_MINUTES);
00833         mLateCancel->showAutoClose(true);
00834         mLateCancel->setAutoClose(Preferences::defaultAutoClose());
00835         mLateCancel->setFixedSize(mLateCancel->sizeHint());
00836         if (mShowInKorganizer)
00837             mShowInKorganizer->setChecked(Preferences::defaultCopyToKOrganizer());
00838         mConfirmAck->setChecked(Preferences::defaultConfirmAck());
00839         if (mSpecialActionsButton)
00840             mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction());
00841         mRecurrenceEdit->setDefaults(defaultTime);   // must be called after mTimeWidget is set up, to ensure correct date-only enabling
00842         slotRecurFrequencyChange();      // update the Recurrence text
00843         mReminder->setMinutes(0, false);
00844         mReminder->enableOnceOnly(mRecurrenceEdit->isTimedRepeatType());   // must be called after mRecurrenceEdit is set up
00845         mSoundPicker->set(Preferences::defaultSound(), Preferences::defaultSoundType(), Preferences::defaultSoundFile(),
00846                           Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat());
00847         mCmdTypeScript->setChecked(Preferences::defaultCmdScript());
00848         mCmdLogFileEdit->setText(Preferences::defaultCmdLogFile());    // set file name before setting radio button
00849         mCmdOutputGroup->setButton(Preferences::defaultCmdLogType());
00850         mEmailBcc->setChecked(Preferences::defaultEmailBcc());
00851     }
00852     slotCmdScriptToggled(mCmdTypeScript->isChecked());
00853 
00854     if (!deferGroupVisible)
00855         mDeferGroup->hide();
00856 
00857     bool enable = !!mEmailAttachList->count();
00858     mEmailAttachList->setEnabled(enable);
00859     if (mEmailRemoveButton)
00860         mEmailRemoveButton->setEnabled(enable);
00861     AlarmCalendar* cal = AlarmCalendar::templateCalendar();
00862     bool empty = cal->isOpen()  &&  !cal->events().count();
00863     enableButton(Default, !empty);
00864 }
00865 
00866 /******************************************************************************
00867  * Set the read-only status of all non-template controls.
00868  */
00869 void EditAlarmDlg::setReadOnly()
00870 {
00871     // Common controls
00872     mMessageRadio->setReadOnly(mReadOnly);
00873     mFileRadio->setReadOnly(mReadOnly);
00874     mCommandRadio->setReadOnly(mReadOnly);
00875     mEmailRadio->setReadOnly(mReadOnly);
00876     if (mTimeWidget)
00877         mTimeWidget->setReadOnly(mReadOnly);
00878     mLateCancel->setReadOnly(mReadOnly);
00879     if (mReadOnly)
00880         mDeferChangeButton->hide();
00881     else
00882         mDeferChangeButton->show();
00883     mSimpleRepetition->setReadOnly(mReadOnly);
00884     if (mShowInKorganizer)
00885         mShowInKorganizer->setReadOnly(mReadOnly);
00886 
00887     // Message alarm controls
00888     mTextMessageEdit->setReadOnly(mReadOnly);
00889     mFileMessageEdit->setReadOnly(mReadOnly);
00890     mBgColourChoose->setReadOnly(mReadOnly);
00891     mFontColourButton->setReadOnly(mReadOnly);
00892     mSoundPicker->setReadOnly(mReadOnly);
00893     mConfirmAck->setReadOnly(mReadOnly);
00894     mReminder->setReadOnly(mReadOnly);
00895     if (mSpecialActionsButton)
00896         mSpecialActionsButton->setReadOnly(mReadOnly);
00897     if (mReadOnly)
00898     {
00899         mFileBrowseButton->hide();
00900         mFontColourButton->hide();
00901     }
00902     else
00903     {
00904         mFileBrowseButton->show();
00905         mFontColourButton->show();
00906     }
00907 
00908     // Command alarm controls
00909     mCmdTypeScript->setReadOnly(mReadOnly);
00910     mCmdCommandEdit->setReadOnly(mReadOnly);
00911     mCmdScriptEdit->setReadOnly(mReadOnly);
00912     for (int id = DISCARD_OUTPUT;  id < EXEC_IN_TERMINAL;  ++id)
00913         ((RadioButton*)mCmdOutputGroup->find(id))->setReadOnly(mReadOnly);
00914 
00915     // Email alarm controls
00916     mEmailToEdit->setReadOnly(mReadOnly);
00917     mEmailSubjectEdit->setReadOnly(mReadOnly);
00918     mEmailMessageEdit->setReadOnly(mReadOnly);
00919     mEmailBcc->setReadOnly(mReadOnly);
00920     if (mEmailFromList)
00921         mEmailFromList->setReadOnly(mReadOnly);
00922     if (mReadOnly)
00923     {
00924         mEmailAddressButton->hide();
00925         mEmailAddAttachButton->hide();
00926         mEmailRemoveButton->hide();
00927     }
00928     else
00929     {
00930         mEmailAddressButton->show();
00931         mEmailAddAttachButton->show();
00932         mEmailRemoveButton->show();
00933     }
00934 }
00935 
00936 /******************************************************************************
00937  * Set the dialog's action and the action's text.
00938  */
00939 void EditAlarmDlg::setAction(KAEvent::Action action, const AlarmText& alarmText)
00940 {
00941     QString text = alarmText.displayText();
00942     bool script;
00943     QRadioButton* radio;
00944     switch (action)
00945     {
00946         case KAEvent::FILE:
00947             radio = mFileRadio;
00948             mFileMessageEdit->setText(text);
00949             break;
00950         case KAEvent::COMMAND:
00951             radio = mCommandRadio;
00952             script = alarmText.isScript();
00953             mCmdTypeScript->setChecked(script);
00954             if (script)
00955                 mCmdScriptEdit->setText(text);
00956             else
00957                 mCmdCommandEdit->setText(text);
00958             break;
00959         case KAEvent::EMAIL:
00960             radio = mEmailRadio;
00961             mEmailMessageEdit->setText(text);
00962             break;
00963         case KAEvent::MESSAGE:
00964         default:
00965             radio = mMessageRadio;
00966             mTextMessageEdit->setText(text);
00967             mKMailSerialNumber = 0;
00968             if (alarmText.isEmail())
00969             {
00970                 mKMailSerialNumber = alarmText.kmailSerialNumber();
00971 
00972                 // Set up email fields also, in case the user wants an email alarm
00973                 mEmailToEdit->setText(alarmText.to());
00974                 mEmailSubjectEdit->setText(alarmText.subject());
00975                 mEmailMessageEdit->setText(alarmText.body());
00976             }
00977             else if (alarmText.isScript())
00978             {
00979                 // Set up command script field also, in case the user wants a command alarm
00980                 mCmdScriptEdit->setText(text);
00981                 mCmdTypeScript->setChecked(true);
00982             }
00983             break;
00984     }
00985     mActionGroup->setButton(mActionGroup->id(radio));
00986 }
00987 
00988 /******************************************************************************
00989  * Create a widget to choose the alarm message background colour.
00990  */
00991 ColourCombo* EditAlarmDlg::createBgColourChooser(QHBox** box, QWidget* parent, const char* name)
00992 {
00993     *box = new QHBox(parent);   // this is to control the QWhatsThis text display area
00994     QLabel* label = new QLabel(i18n("&Background color:"), *box);
00995     label->setFixedSize(label->sizeHint());
00996     ColourCombo* widget = new ColourCombo(*box, name);
00997     QSize size = widget->sizeHint();
00998     widget->setMinimumHeight(size.height() + 4);
00999     QToolTip::add(widget, i18n("Message color"));
01000     label->setBuddy(widget);
01001     (*box)->setFixedHeight((*box)->sizeHint().height());
01002     QWhatsThis::add(*box, i18n("Choose the background color for the alarm message."));
01003     return widget;
01004 }
01005 
01006 /******************************************************************************
01007  * Create an "acknowledgement confirmation required" checkbox.
01008  */
01009 CheckBox* EditAlarmDlg::createConfirmAckCheckbox(QWidget* parent, const char* name)
01010 {
01011     CheckBox* widget = new CheckBox(i18n_k_ConfirmAck(), parent, name);
01012     QWhatsThis::add(widget,
01013           i18n("Check to be prompted for confirmation when you acknowledge the alarm."));
01014     return widget;
01015 }
01016 
01017 /******************************************************************************
01018  * Save the state of all controls.
01019  */
01020 void EditAlarmDlg::saveState(const KAEvent* event)
01021 {
01022     mSavedEvent = 0;
01023     if (event)
01024         mSavedEvent = new KAEvent(*event);
01025     if (mTemplate)
01026     {
01027         mSavedTemplateName      = mTemplateName->text();
01028         mSavedTemplateTimeType  = mTemplateTimeGroup->selected();
01029         mSavedTemplateTime      = mTemplateTime->time();
01030         mSavedTemplateAfterTime = mTemplateTimeAfter->value();
01031     }
01032     mSavedTypeRadio        = mActionGroup->selected();
01033     mSavedSound            = mSoundPicker->sound();
01034     mSavedSoundType        = mSoundPicker->type();
01035     mSavedSoundFile        = mSoundPicker->file();
01036     mSavedSoundVolume      = mSoundPicker->volume(mSavedSoundFadeVolume, mSavedSoundFadeSeconds);
01037     mSavedRepeatSound      = mSoundPicker->repeat();
01038     mSavedConfirmAck       = mConfirmAck->isChecked();
01039     mSavedFont             = mFontColourButton->font();
01040     mSavedFgColour         = mFontColourButton->fgColour();
01041     mSavedBgColour         = mBgColourChoose->color();
01042     mSavedReminder         = mReminder->minutes();
01043     mSavedOnceOnly         = mReminder->isOnceOnly();
01044     if (mSpecialActionsButton)
01045     {
01046         mSavedPreAction  = mSpecialActionsButton->preAction();
01047         mSavedPostAction = mSpecialActionsButton->postAction();
01048     }
01049     checkText(mSavedTextFileCommandMessage, false);
01050     mSavedCmdScript        = mCmdTypeScript->isChecked();
01051     mSavedCmdOutputRadio   = mCmdOutputGroup->selected();
01052     mSavedCmdLogFile       = mCmdLogFileEdit->text();
01053     if (mEmailFromList)
01054         mSavedEmailFrom = mEmailFromList->currentIdentityName();
01055     mSavedEmailTo          = mEmailToEdit->text();
01056     mSavedEmailSubject     = mEmailSubjectEdit->text();
01057     mSavedEmailAttach.clear();
01058     for (int i = 0;  i < mEmailAttachList->count();  ++i)
01059         mSavedEmailAttach += mEmailAttachList->text(i);
01060     mSavedEmailBcc         = mEmailBcc->isChecked();
01061     if (mTimeWidget)
01062         mSavedDateTime = mTimeWidget->getDateTime(false, false);
01063     mSavedLateCancel       = mLateCancel->minutes();
01064     mSavedAutoClose        = mLateCancel->isAutoClose();
01065     if (mShowInKorganizer)
01066         mSavedShowInKorganizer = mShowInKorganizer->isChecked();
01067     mSavedRecurrenceType   = mRecurrenceEdit->repeatType();
01068     mSavedRepeatInterval   = mSimpleRepetition->interval();
01069     mSavedRepeatCount      = mSimpleRepetition->count();
01070 }
01071 
01072 /******************************************************************************
01073  * Check whether any of the controls has changed state since the dialog was
01074  * first displayed.
01075  * Reply = true if any non-deferral controls have changed, or if it's a new event.
01076  *       = false if no non-deferral controls have changed. In this case,
01077  *         mOnlyDeferred indicates whether deferral controls may have changed.
01078  */
01079 bool EditAlarmDlg::stateChanged() const
01080 {
01081     mChanged      = true;
01082     mOnlyDeferred = false;
01083     if (!mSavedEvent)
01084         return true;
01085     QString textFileCommandMessage;
01086     checkText(textFileCommandMessage, false);
01087     if (mTemplate)
01088     {
01089         if (mSavedTemplateName     != mTemplateName->text()
01090         ||  mSavedTemplateTimeType != mTemplateTimeGroup->selected()
01091         ||  mTemplateUseTime->isOn()  &&  mSavedTemplateTime != mTemplateTime->time()
01092         ||  mTemplateUseTimeAfter->isOn()  &&  mSavedTemplateAfterTime != mTemplateTimeAfter->value())
01093             return true;
01094     }
01095     else
01096         if (mSavedDateTime != mTimeWidget->getDateTime(false, false))
01097             return true;
01098     if (mSavedTypeRadio        != mActionGroup->selected()
01099     ||  mSavedLateCancel       != mLateCancel->minutes()
01100     ||  mShowInKorganizer && mSavedShowInKorganizer != mShowInKorganizer->isChecked()
01101     ||  textFileCommandMessage != mSavedTextFileCommandMessage
01102     ||  mSavedRecurrenceType   != mRecurrenceEdit->repeatType()
01103     ||  mSavedRepeatInterval   != mSimpleRepetition->interval()
01104     ||  mSavedRepeatCount      != mSimpleRepetition->count())
01105         return true;
01106     if (mMessageRadio->isOn()  ||  mFileRadio->isOn())
01107     {
01108         if (mSavedSound      != mSoundPicker->sound()
01109         ||  mSavedConfirmAck != mConfirmAck->isChecked()
01110         ||  mSavedFont       != mFontColourButton->font()
01111         ||  mSavedFgColour   != mFontColourButton->fgColour()
01112         ||  mSavedBgColour   != mBgColourChoose->color()
01113         ||  mSavedReminder   != mReminder->minutes()
01114         ||  mSavedOnceOnly   != mReminder->isOnceOnly()
01115         ||  mSavedAutoClose  != mLateCancel->isAutoClose())
01116             return true;
01117         if (mSpecialActionsButton)
01118         {
01119             if (mSavedPreAction  != mSpecialActionsButton->preAction()
01120             ||  mSavedPostAction != mSpecialActionsButton->postAction())
01121                 return true;
01122         }
01123         if (mSavedSound)
01124         {
01125             if (mSavedSoundType != mSoundPicker->type())
01126                 return true;
01127             if (mSavedSoundType == SoundPicker::PLAY_FILE)
01128             {
01129                 if (mSavedSoundFile != mSoundPicker->file())
01130                     return true;
01131                 if (!mSavedSoundFile.isEmpty())
01132                 {
01133                     float fadeVolume;
01134                     int   fadeSecs;
01135                     if (mSavedRepeatSound != mSoundPicker->repeat()
01136                     ||  mSavedSoundVolume != mSoundPicker->volume(fadeVolume, fadeSecs)
01137                     ||  mSavedSoundFadeVolume != fadeVolume
01138                     ||  mSavedSoundFadeSeconds != fadeSecs)
01139                         return true;
01140                 }
01141             }
01142         }
01143     }
01144     else if (mCommandRadio->isOn())
01145     {
01146         if (mSavedCmdScript      != mCmdTypeScript->isChecked()
01147         ||  mSavedCmdOutputRadio != mCmdOutputGroup->selected())
01148             return true;
01149         if (mCmdOutputGroup->selectedId() == LOG_TO_FILE)
01150         {
01151             if (mSavedCmdLogFile != mCmdLogFileEdit->text())
01152                 return true;
01153         }
01154     }
01155     else if (mEmailRadio->isOn())
01156     {
01157         QStringList emailAttach;
01158         for (int i = 0;  i < mEmailAttachList->count();  ++i)
01159             emailAttach += mEmailAttachList->text(i);
01160         if (mEmailFromList  &&  mSavedEmailFrom != mEmailFromList->currentIdentityName()
01161         ||  mSavedEmailTo      != mEmailToEdit->text()
01162         ||  mSavedEmailSubject != mEmailSubjectEdit->text()
01163         ||  mSavedEmailAttach  != emailAttach
01164         ||  mSavedEmailBcc     != mEmailBcc->isChecked())
01165             return true;
01166     }
01167     if (mRecurrenceEdit->stateChanged())
01168         return true;
01169     if (mSavedEvent  &&  mSavedEvent->deferred())
01170         mOnlyDeferred = true;
01171     mChanged = false;
01172     return false;
01173 }
01174 
01175 /******************************************************************************
01176  * Get the currently entered dialogue data.
01177  * The data is returned in the supplied KAEvent instance.
01178  * Reply = false if the only change has been to an existing deferral.
01179  */
01180 bool EditAlarmDlg::getEvent(KAEvent& event)
01181 {
01182     if (mChanged)
01183     {
01184         // It's a new event, or the edit controls have changed
01185         setEvent(event, mAlarmMessage, false);
01186         return true;
01187     }
01188 
01189     // Only the deferral time may have changed
01190     event = *mSavedEvent;
01191     if (mOnlyDeferred)
01192     {
01193         // Just modify the original event, to avoid expired recurring events
01194         // being returned as rubbish.
01195         if (mDeferDateTime.isValid())
01196             event.defer(mDeferDateTime, event.reminderDeferral(), false);
01197         else
01198             event.cancelDefer();
01199     }
01200     return false;
01201 }
01202 
01203 /******************************************************************************
01204 *  Extract the data in the dialogue and set up a KAEvent from it.
01205 *  If 'trial' is true, the event is set up for a simple one-off test, ignoring
01206 *  recurrence, reminder, template etc. data.
01207 */
01208 void EditAlarmDlg::setEvent(KAEvent& event, const QString& text, bool trial)
01209 {
01210     QDateTime dt;
01211     if (!trial)
01212     {
01213         if (!mTemplate)
01214             dt = mAlarmDateTime.dateTime();
01215         else if (mTemplateUseTime->isOn())
01216             dt.setTime(mTemplateTime->time());
01217     }
01218     KAEvent::Action type = getAlarmType();
01219     event.set(dt, text, mBgColourChoose->color(), mFontColourButton->fgColour(), mFontColourButton->font(),
01220               type, (trial ? 0 : mLateCancel->minutes()), getAlarmFlags());
01221     switch (type)
01222     {
01223         case KAEvent::MESSAGE:
01224             if (AlarmText::checkIfEmail(text))
01225                 event.setKMailSerialNumber(mKMailSerialNumber);
01226             // fall through to FILE
01227         case KAEvent::FILE:
01228         {
01229             float fadeVolume;
01230             int   fadeSecs;
01231             float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
01232             event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs);
01233             if (!trial)
01234                 event.setReminder(mReminder->minutes(), mReminder->isOnceOnly());
01235             if (mSpecialActionsButton)
01236                 event.setActions(mSpecialActionsButton->preAction(), mSpecialActionsButton->postAction());
01237             break;
01238         }
01239         case KAEvent::EMAIL:
01240         {
01241             QString from;
01242             if (mEmailFromList)
01243                 from = mEmailFromList->currentIdentityName();
01244             event.setEmail(from, mEmailAddresses, mEmailSubjectEdit->text(), mEmailAttachments);
01245             break;
01246         }
01247         case KAEvent::COMMAND:
01248             if (mCmdOutputGroup->selectedId() == LOG_TO_FILE)
01249                 event.setLogFile(mCmdLogFileEdit->text());
01250             break;
01251         default:
01252             break;
01253     }
01254     if (!trial)
01255     {
01256         if (mRecurrenceEdit->repeatType() != RecurrenceEdit::NO_RECUR)
01257         {
01258             mRecurrenceEdit->updateEvent(event, !mTemplate);
01259             mAlarmDateTime = event.startDateTime();
01260             if (mDeferDateTime.isValid()  &&  mDeferDateTime < mAlarmDateTime)
01261             {
01262                 bool deferral = true;
01263                 bool deferReminder = false;
01264                 int reminder = mReminder->minutes();
01265                 if (reminder)
01266                 {
01267                     DateTime remindTime = mAlarmDateTime.addMins(-reminder);
01268                     if (mDeferDateTime >= remindTime)
01269                     {
01270                         if (remindTime > QDateTime::currentDateTime())
01271                             deferral = false;    // ignore deferral if it's after next reminder
01272                         else if (mDeferDateTime > remindTime)
01273                             deferReminder = true;    // it's the reminder which is being deferred
01274                     }
01275                 }
01276                 if (deferral)
01277                     event.defer(mDeferDateTime, deferReminder, false);
01278             }
01279         }
01280         if (mSimpleRepetition->count())
01281             event.setRepetition(mSimpleRepetition->interval(), mSimpleRepetition->count());
01282         if (mTemplate)
01283         {
01284             int afterTime = mTemplateDefaultTime->isOn() ? 0
01285                           : mTemplateUseTimeAfter->isOn() ? mTemplateTimeAfter->value() : -1;
01286             event.setTemplate(mTemplateName->text(), afterTime);
01287         }
01288     }
01289 }
01290 
01291 /******************************************************************************
01292  * Get the currently specified alarm flag bits.
01293  */
01294 int EditAlarmDlg::getAlarmFlags() const
01295 {
01296     bool displayAlarm = mMessageRadio->isOn() || mFileRadio->isOn();
01297     bool cmdAlarm     = mCommandRadio->isOn();
01298     bool emailAlarm   = mEmailRadio->isOn();
01299     return (displayAlarm && mSoundPicker->beep()                                 ? KAEvent::BEEP : 0)
01300          | (displayAlarm && mSoundPicker->speak()                                ? KAEvent::SPEAK : 0)
01301          | (displayAlarm && mSoundPicker->repeat()                               ? KAEvent::REPEAT_SOUND : 0)
01302          | (displayAlarm && mConfirmAck->isChecked()                             ? KAEvent::CONFIRM_ACK : 0)
01303          | (displayAlarm && mLateCancel->isAutoClose()                           ? KAEvent::AUTO_CLOSE : 0)
01304          | (cmdAlarm     && mCmdTypeScript->isChecked()                          ? KAEvent::SCRIPT : 0)
01305          | (cmdAlarm     && mCmdOutputGroup->selectedId() == EXEC_IN_TERMINAL    ? KAEvent::EXEC_IN_XTERM : 0)
01306          | (emailAlarm   && mEmailBcc->isChecked()                               ? KAEvent::EMAIL_BCC : 0)
01307          | (mShowInKorganizer && mShowInKorganizer->isChecked()                  ? KAEvent::COPY_KORGANIZER : 0)
01308          | (mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN            ? KAEvent::REPEAT_AT_LOGIN : 0)
01309          | ((mTemplate ? mTemplateAnyTime->isOn() : mAlarmDateTime.isDateOnly()) ? KAEvent::ANY_TIME : 0)
01310          | (mFontColourButton->defaultFont()                                     ? KAEvent::DEFAULT_FONT : 0);
01311 }
01312 
01313 /******************************************************************************
01314  * Get the currently selected alarm type.
01315  */
01316 KAEvent::Action EditAlarmDlg::getAlarmType() const
01317 {
01318     return mFileRadio->isOn()    ? KAEvent::FILE
01319          : mCommandRadio->isOn() ? KAEvent::COMMAND
01320          : mEmailRadio->isOn()   ? KAEvent::EMAIL
01321          :                         KAEvent::MESSAGE;
01322 }
01323 
01324 /******************************************************************************
01325 *  Called when the dialog is displayed.
01326 *  The first time through, sets the size to the same as the last time it was
01327 *  displayed.
01328 */
01329 void EditAlarmDlg::showEvent(QShowEvent* se)
01330 {
01331     if (!mDeferGroupHeight)
01332     {
01333         mDeferGroupHeight = mDeferGroup->height() + spacingHint();
01334         QSize s;
01335         if (KAlarm::readConfigWindowSize(EDIT_DIALOG_NAME, s))
01336             s.setHeight(s.height() + (mDeferGroup->isHidden() ? 0 : mDeferGroupHeight));
01337         else
01338             s = minimumSize();
01339         resize(s);
01340     }
01341     KWin::setOnDesktop(winId(), mDesktop);    // ensure it displays on the desktop expected by the user
01342     KDialog::showEvent(se);
01343 }
01344 
01345 /******************************************************************************
01346 *  Called when the dialog's size has changed.
01347 *  Records the new size (adjusted to ignore the optional height of the deferred
01348 *  time edit widget) in the config file.
01349 */
01350 void EditAlarmDlg::resizeEvent(QResizeEvent* re)
01351 {
01352     if (isVisible())
01353     {
01354         QSize s = re->size();
01355         s.setHeight(s.height() - (mDeferGroup->isHidden() ? 0 : mDeferGroupHeight));
01356         KAlarm::writeConfigWindowSize(EDIT_DIALOG_NAME, s);
01357     }
01358     KDialog::resizeEvent(re);
01359 }
01360 
01361 /******************************************************************************
01362 *  Called when the OK button is clicked.
01363 *  Validate the input data.
01364 */
01365 void EditAlarmDlg::slotOk()
01366 {
01367     if (!stateChanged())
01368     {
01369         // No changes have been made except possibly to an existing deferral
01370         if (!mOnlyDeferred)
01371             reject();
01372         else
01373             accept();
01374         return;
01375     }
01376     RecurrenceEdit::RepeatType recurType = mRecurrenceEdit->repeatType();
01377     if (mTimeWidget
01378     &&  mTabs->currentPageIndex() == mRecurPageIndex  &&  recurType == RecurrenceEdit::AT_LOGIN)
01379         mTimeWidget->setDateTime(mRecurrenceEdit->endDateTime());
01380     bool timedRecurrence = mRecurrenceEdit->isTimedRepeatType();    // does it recur other than at login?
01381     bool repeated = mSimpleRepetition->count();
01382     if (mTemplate)
01383     {
01384         // Check that the template name is not blank and is unique
01385         QString errmsg;
01386         QString name = mTemplateName->text();
01387         if (name.isEmpty())
01388             errmsg = i18n("You must enter a name for the alarm template");
01389         else if (name != mSavedTemplateName)
01390         {
01391             AlarmCalendar* cal = AlarmCalendar::templateCalendarOpen();
01392             if (cal  &&  KAEvent::findTemplateName(*cal, name).valid())
01393                 errmsg = i18n("Template name is already in use");
01394         }
01395         if (!errmsg.isEmpty())
01396         {
01397             mTemplateName->setFocus();
01398             KMessageBox::sorry(this, errmsg);
01399             return;
01400         }
01401     }
01402     else
01403     {
01404         QWidget* errWidget;
01405         mAlarmDateTime = mTimeWidget->getDateTime(!(timedRecurrence || repeated), false, &errWidget);
01406         if (errWidget)
01407         {
01408             // It's more than just an existing deferral being changed, so the time matters
01409             mTabs->setCurrentPage(mMainPageIndex);
01410             errWidget->setFocus();
01411             mTimeWidget->getDateTime();   // display the error message now
01412             return;
01413         }
01414     }
01415     if (!checkCommandData()
01416     ||  !checkEmailData())
01417         return;
01418     if (!mTemplate)
01419     {
01420         if (timedRecurrence)
01421         {
01422             QDateTime now = QDateTime::currentDateTime();
01423             if (mAlarmDateTime.date() < now.date()
01424             ||  !mAlarmDateTime.isDateOnly() && mAlarmDateTime.time() < now.time())
01425             {
01426                 // A timed recurrence has an entered start date which
01427                 // has already expired, so we must adjust it.
01428                 KAEvent event;
01429                 getEvent(event);     // this may adjust mAlarmDateTime
01430                 if ((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(!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, "deferDlg");
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(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(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         setButtonWhatsThis(Try, i18n("Display the alarm message now"));
01834         mAlarmTypeStack->raiseWidget(mDisplayAlarmsFrame);
01835         focus = mTextMessageEdit;
01836         displayAlarm = true;
01837     }
01838     else if (mFileRadio->isOn())
01839     {
01840         mTextMessageEdit->hide();
01841         mFileBox->show();
01842         mFilePadding->show();
01843         mFontColourButton->hide();
01844         mSoundPicker->showSpeak(false);
01845         setButtonWhatsThis(Try, i18n("Display the file now"));
01846         mAlarmTypeStack->raiseWidget(mDisplayAlarmsFrame);
01847         mFileMessageEdit->setNoSelect();
01848         focus = mFileMessageEdit;
01849         displayAlarm = true;
01850     }
01851     else if (mCommandRadio->isOn())
01852     {
01853         setButtonWhatsThis(Try, i18n("Execute the specified command now"));
01854         mAlarmTypeStack->raiseWidget(mCommandFrame);
01855         mCmdCommandEdit->setNoSelect();
01856         focus = mCmdCommandEdit;
01857     }
01858     else if (mEmailRadio->isOn())
01859     {
01860         setButtonWhatsThis(Try, i18n("Send the email to the specified addressees now"));
01861         mAlarmTypeStack->raiseWidget(mEmailFrame);
01862         mEmailToEdit->setNoSelect();
01863         focus = mEmailToEdit;
01864     }
01865     mLateCancel->showAutoClose(displayAlarm);
01866     mLateCancel->setFixedSize(mLateCancel->sizeHint());
01867     if (focus)
01868         focus->setFocus();
01869 }
01870 
01871 /******************************************************************************
01872 *  Called when one of the command type radio buttons is clicked,
01873 *  to display the appropriate edit field.
01874 */
01875 void EditAlarmDlg::slotCmdScriptToggled(bool on)
01876 {
01877     if (on)
01878     {
01879         mCmdCommandEdit->hide();
01880         mCmdPadding->hide();
01881         mCmdScriptEdit->show();
01882         mCmdScriptEdit->setFocus();
01883     }
01884     else
01885     {
01886         mCmdScriptEdit->hide();
01887         mCmdCommandEdit->show();
01888         mCmdPadding->show();
01889         mCmdCommandEdit->setFocus();
01890     }
01891 }
01892 
01893 /******************************************************************************
01894 *  Called when one of the template time radio buttons is clicked,
01895 *  to enable or disable the template time entry spin boxes.
01896 */
01897 void EditAlarmDlg::slotTemplateTimeType(int)
01898 {
01899     mTemplateTime->setEnabled(mTemplateUseTime->isOn());
01900     mTemplateTimeAfter->setEnabled(mTemplateUseTimeAfter->isOn());
01901 }
01902 
01903 /******************************************************************************
01904 *  Called when the a new background colour has been selected using the colour
01905 *  combo box.
01906 */
01907 void EditAlarmDlg::slotBgColourSelected(const QColor& colour)
01908 {
01909     mFontColourButton->setBgColour(colour);
01910 }
01911 
01912 /******************************************************************************
01913 *  Called when the a new font and colour have been selected using the font &
01914 *  colour pushbutton.
01915 */
01916 void EditAlarmDlg::slotFontColourSelected()
01917 {
01918     mBgColourChoose->setColour(mFontColourButton->bgColour());
01919 }
01920 
01921 /******************************************************************************
01922 *  Called when the "Any time" checkbox is toggled in the date/time widget.
01923 *  Sets the advance reminder and late cancel units to days if any time is checked.
01924 */
01925 void EditAlarmDlg::slotAnyTimeToggled(bool anyTime)
01926 {
01927     if (mReminder->isReminder())
01928         mReminder->setDateOnly(anyTime);
01929     mLateCancel->setDateOnly(anyTime);
01930 }
01931 
01932 /******************************************************************************
01933  * Get a selection from the Address Book.
01934  */
01935 void EditAlarmDlg::openAddressBook()
01936 {
01937     KABC::Addressee a = KABC::AddresseeDialog::getAddressee(this);
01938     if (a.isEmpty())
01939         return;
01940     Person person(a.realName(), a.preferredEmail());
01941     QString addrs = mEmailToEdit->text().stripWhiteSpace();
01942     if (!addrs.isEmpty())
01943         addrs += ", ";
01944     addrs += person.fullName();
01945     mEmailToEdit->setText(addrs);
01946 }
01947 
01948 /******************************************************************************
01949  * Select a file to attach to the email.
01950  */
01951 void EditAlarmDlg::slotAddAttachment()
01952 {
01953     QString url = KAlarm::browseFile(i18n("Choose File to Attach"), mAttachDefaultDir, QString::null,
01954                                      QString::null, KFile::ExistingOnly, this, "pickAttachFile");
01955     if (!url.isEmpty())
01956     {
01957         mEmailAttachList->insertItem(url);
01958         mEmailAttachList->setCurrentItem(mEmailAttachList->count() - 1);   // select the new item
01959         mEmailRemoveButton->setEnabled(true);
01960         mEmailAttachList->setEnabled(true);
01961     }
01962 }
01963 
01964 /******************************************************************************
01965  * Remove the currently selected attachment from the email.
01966  */
01967 void EditAlarmDlg::slotRemoveAttachment()
01968 {
01969     int item = mEmailAttachList->currentItem();
01970     mEmailAttachList->removeItem(item);
01971     int count = mEmailAttachList->count();
01972     if (item >= count)
01973         mEmailAttachList->setCurrentItem(count - 1);
01974     if (!count)
01975     {
01976         mEmailRemoveButton->setEnabled(false);
01977         mEmailAttachList->setEnabled(false);
01978     }
01979 }
01980 
01981 /******************************************************************************
01982 *  Clean up the alarm text, and if it's a file, check whether it's valid.
01983 */
01984 bool EditAlarmDlg::checkText(QString& result, bool showErrorMessage) const
01985 {
01986     if (mMessageRadio->isOn())
01987         result = mTextMessageEdit->text();
01988     else if (mEmailRadio->isOn())
01989         result = mEmailMessageEdit->text();
01990     else if (mCommandRadio->isOn())
01991     {
01992         if (mCmdTypeScript->isChecked())
01993             result = mCmdScriptEdit->text();
01994         else
01995             result = mCmdCommandEdit->text();
01996         result = result.stripWhiteSpace();
01997     }
01998     else if (mFileRadio->isOn())
01999     {
02000         QString alarmtext = mFileMessageEdit->text().stripWhiteSpace();
02001         // Convert any relative file path to absolute
02002         // (using home directory as the default)
02003         enum Err { NONE = 0, BLANK, NONEXISTENT, DIRECTORY, UNREADABLE, NOT_TEXT_IMAGE };
02004         Err err = NONE;
02005         KURL url;
02006         int i = alarmtext.find(QString::fromLatin1("/"));
02007         if (i > 0  &&  alarmtext[i - 1] == ':')
02008         {
02009             url = alarmtext;
02010             url.cleanPath();
02011             alarmtext = url.prettyURL();
02012             KIO::UDSEntry uds;
02013             if (!KIO::NetAccess::stat(url, uds, MainWindow::mainMainWindow()))
02014                 err = NONEXISTENT;
02015             else
02016             {
02017                 KFileItem fi(uds, url);
02018                 if (fi.isDir())             err = DIRECTORY;
02019                 else if (!fi.isReadable())  err = UNREADABLE;
02020             }
02021         }
02022         else if (alarmtext.isEmpty())
02023             err = BLANK;    // blank file name
02024         else
02025         {
02026             // It's a local file - convert to absolute path & check validity
02027             QFileInfo info(alarmtext);
02028             QDir::setCurrent(QDir::homeDirPath());
02029             alarmtext = info.absFilePath();
02030             url.setPath(alarmtext);
02031             alarmtext = QString::fromLatin1("file:") + alarmtext;
02032             if (!err)
02033             {
02034                 if      (info.isDir())        err = DIRECTORY;
02035                 else if (!info.exists())      err = NONEXISTENT;
02036                 else if (!info.isReadable())  err = UNREADABLE;
02037             }
02038         }
02039         if (!err)
02040         {
02041             switch (KAlarm::fileType(KFileItem(KFileItem::Unknown, KFileItem::Unknown, url).mimetype()))
02042             {
02043                 case KAlarm::TextFormatted:
02044                 case KAlarm::TextPlain:
02045                 case KAlarm::TextApplication:
02046                 case KAlarm::Image:
02047                     break;
02048                 default:
02049                     err = NOT_TEXT_IMAGE;
02050                     break;
02051             }
02052         }
02053         if (err  &&  showErrorMessage)
02054         {
02055             mFileMessageEdit->setFocus();
02056             QString errmsg;
02057             switch (err)
02058             {
02059                 case BLANK:
02060                     KMessageBox::sorry(const_cast<EditAlarmDlg*>(this), i18n("Please select a file to display"));
02061                     return false;
02062                 case NONEXISTENT:     errmsg = i18n("%1\nnot found");  break;
02063                 case DIRECTORY:       errmsg = i18n("%1\nis a folder");  break;
02064                 case UNREADABLE:      errmsg = i18n("%1\nis not readable");  break;
02065                 case NOT_TEXT_IMAGE:  errmsg = i18n("%1\nappears not to be a text or image file");  break;
02066                 case NONE:
02067                 default:
02068                     break;
02069             }
02070             if (KMessageBox::warningContinueCancel(const_cast<EditAlarmDlg*>(this), errmsg.arg(alarmtext))
02071                 == KMessageBox::Cancel)
02072                 return false;
02073         }
02074         result = alarmtext;
02075     }
02076     return true;
02077 }
02078 
02079 
02080 /*=============================================================================
02081 = Class TextEdit
02082 = A text edit field with a minimum height of 3 text lines.
02083 = Provides KDE 2 compatibility.
02084 =============================================================================*/
02085 TextEdit::TextEdit(QWidget* parent, const char* name)
02086     : QTextEdit(parent, name)
02087 {
02088     QSize tsize = sizeHint();
02089     tsize.setHeight(fontMetrics().lineSpacing()*13/4 + 2*frameWidth());
02090     setMinimumSize(tsize);
02091 }
02092 
02093 void TextEdit::dragEnterEvent(QDragEnterEvent* e)
02094 {
02095     if (KCal::ICalDrag::canDecode(e))
02096         e->accept(false);   // don't accept "text/calendar" objects
02097     QTextEdit::dragEnterEvent(e);
02098 }
KDE Home | KDE Accessibility Home | Description of Access Keys