summaryrefslogtreecommitdiffstats
path: root/kalarm/editdlg.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /kalarm/editdlg.cpp
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kalarm/editdlg.cpp')
-rw-r--r--kalarm/editdlg.cpp2043
1 files changed, 2043 insertions, 0 deletions
diff --git a/kalarm/editdlg.cpp b/kalarm/editdlg.cpp
new file mode 100644
index 000000000..232111000
--- /dev/null
+++ b/kalarm/editdlg.cpp
@@ -0,0 +1,2043 @@
+/*
+ * editdlg.cpp - dialogue to create or modify an alarm or alarm template
+ * Program: kalarm
+ * Copyright © 2001-2008 by David Jarvie <djarvie@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kalarm.h"
+
+#include <limits.h>
+
+#include <qlayout.h>
+#include <qpopupmenu.h>
+#include <qvbox.h>
+#include <qgroupbox.h>
+#include <qwidgetstack.h>
+#include <qdragobject.h>
+#include <qlabel.h>
+#include <qmessagebox.h>
+#include <qtabwidget.h>
+#include <qvalidator.h>
+#include <qwhatsthis.h>
+#include <qtooltip.h>
+#include <qdir.h>
+#include <qstyle.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <kio/netaccess.h>
+#include <kfileitem.h>
+#include <kmessagebox.h>
+#include <kurldrag.h>
+#include <kurlcompletion.h>
+#include <kwin.h>
+#include <kwinmodule.h>
+#include <kstandarddirs.h>
+#include <kstdguiitem.h>
+#include <kabc/addresseedialog.h>
+#include <kdebug.h>
+
+#include <libkdepim/maillistdrag.h>
+#include <libkdepim/kvcarddrag.h>
+#include <libkcal/icaldrag.h>
+
+#include "alarmcalendar.h"
+#include "alarmtimewidget.h"
+#include "checkbox.h"
+#include "colourcombo.h"
+#include "deferdlg.h"
+#include "emailidcombo.h"
+#include "fontcolourbutton.h"
+#include "functions.h"
+#include "kalarmapp.h"
+#include "kamail.h"
+#include "latecancel.h"
+#include "lineedit.h"
+#include "mainwindow.h"
+#include "pickfileradio.h"
+#include "preferences.h"
+#include "radiobutton.h"
+#include "recurrenceedit.h"
+#include "reminder.h"
+#include "shellprocess.h"
+#include "soundpicker.h"
+#include "specialactions.h"
+#include "spinbox.h"
+#include "templatepickdlg.h"
+#include "timeedit.h"
+#include "timespinbox.h"
+#include "editdlg.moc"
+#include "editdlgprivate.moc"
+
+using namespace KCal;
+
+static const char EDIT_DIALOG_NAME[] = "EditDialog";
+static const int maxDelayTime = 99*60 + 59; // < 100 hours
+
+/*=============================================================================
+= Class PickAlarmFileRadio
+=============================================================================*/
+class PickAlarmFileRadio : public PickFileRadio
+{
+ public:
+ PickAlarmFileRadio(const QString& text, QButtonGroup* parent, const char* name = 0)
+ : PickFileRadio(text, parent, name) { }
+ virtual QString pickFile() // called when browse button is pressed to select a file to display
+ {
+ return KAlarm::browseFile(i18n("Choose Text or Image File to Display"), mDefaultDir, fileEdit()->text(),
+ QString::null, KFile::ExistingOnly, parentWidget(), "pickAlarmFile");
+ }
+ private:
+ QString mDefaultDir; // default directory for file browse button
+};
+
+/*=============================================================================
+= Class PickLogFileRadio
+=============================================================================*/
+class PickLogFileRadio : public PickFileRadio
+{
+ public:
+ PickLogFileRadio(QPushButton* b, LineEdit* e, const QString& text, QButtonGroup* parent, const char* name = 0)
+ : PickFileRadio(b, e, text, parent, name) { }
+ virtual QString pickFile() // called when browse button is pressed to select a log file
+ {
+ return KAlarm::browseFile(i18n("Choose Log File"), mDefaultDir, fileEdit()->text(), QString::null,
+ KFile::LocalOnly, parentWidget(), "pickLogFile");
+ }
+ private:
+ QString mDefaultDir; // default directory for log file browse button
+};
+
+inline QString recurText(const KAEvent& event)
+{
+ QString r;
+ if (event.repeatCount())
+ r = QString::fromLatin1("%1 / %2").arg(event.recurrenceText()).arg(event.repetitionText());
+ else
+ r = event.recurrenceText();
+ return i18n("&Recurrence - [%1]").arg(r);
+}
+
+// Collect these widget labels together to ensure consistent wording and
+// translations across different modules.
+QString EditAlarmDlg::i18n_ConfirmAck() { return i18n("Confirm acknowledgment"); }
+QString EditAlarmDlg::i18n_k_ConfirmAck() { return i18n("Confirm ac&knowledgment"); }
+QString EditAlarmDlg::i18n_SpecialActions() { return i18n("Special Actions..."); }
+QString EditAlarmDlg::i18n_ShowInKOrganizer() { return i18n("Show in KOrganizer"); }
+QString EditAlarmDlg::i18n_g_ShowInKOrganizer() { return i18n("Show in KOr&ganizer"); }
+QString EditAlarmDlg::i18n_EnterScript() { return i18n("Enter a script"); }
+QString EditAlarmDlg::i18n_p_EnterScript() { return i18n("Enter a scri&pt"); }
+QString EditAlarmDlg::i18n_ExecInTermWindow() { return i18n("Execute in terminal window"); }
+QString EditAlarmDlg::i18n_w_ExecInTermWindow() { return i18n("Execute in terminal &window"); }
+QString EditAlarmDlg::i18n_u_ExecInTermWindow() { return i18n("Exec&ute in terminal window"); }
+QString EditAlarmDlg::i18n_g_LogToFile() { return i18n("Lo&g to file"); }
+QString EditAlarmDlg::i18n_CopyEmailToSelf() { return i18n("Copy email to self"); }
+QString EditAlarmDlg::i18n_e_CopyEmailToSelf() { return i18n("Copy &email to self"); }
+QString EditAlarmDlg::i18n_s_CopyEmailToSelf() { return i18n("Copy email to &self"); }
+QString EditAlarmDlg::i18n_EmailFrom() { return i18n("'From' email address", "From:"); }
+QString EditAlarmDlg::i18n_f_EmailFrom() { return i18n("'From' email address", "&From:"); }
+QString EditAlarmDlg::i18n_EmailTo() { return i18n("Email addressee", "To:"); }
+QString EditAlarmDlg::i18n_EmailSubject() { return i18n("Email subject", "Subject:"); }
+QString EditAlarmDlg::i18n_j_EmailSubject() { return i18n("Email subject", "Sub&ject:"); }
+
+
+/******************************************************************************
+ * Constructor.
+ * Parameters:
+ * Template = true to edit/create an alarm template
+ * = false to edit/create an alarm.
+ * event != to initialise the dialogue to show the specified event's data.
+ */
+EditAlarmDlg::EditAlarmDlg(bool Template, const QString& caption, QWidget* parent, const char* name,
+ const KAEvent* event, bool readOnly)
+ : KDialogBase(parent, (name ? name : Template ? "TemplEditDlg" : "EditDlg"), true, caption,
+ (readOnly ? Cancel|Try : Template ? Ok|Cancel|Try : Ok|Cancel|Try|Default),
+ (readOnly ? Cancel : Ok)),
+ mMainPageShown(false),
+ mRecurPageShown(false),
+ mRecurSetDefaultEndDate(true),
+ mTemplateName(0),
+ mSpecialActionsButton(0),
+ mReminderDeferral(false),
+ mReminderArchived(false),
+ mEmailRemoveButton(0),
+ mDeferGroup(0),
+ mTimeWidget(0),
+ mShowInKorganizer(0),
+ mDeferGroupHeight(0),
+ mTemplate(Template),
+ mDesiredReadOnly(readOnly),
+ mReadOnly(readOnly),
+ mSavedEvent(0)
+{
+ setButtonText(Default, i18n("Load Template..."));
+ QVBox* mainWidget = new QVBox(this);
+ mainWidget->setSpacing(spacingHint());
+ setMainWidget(mainWidget);
+ if (mTemplate)
+ {
+ QHBox* box = new QHBox(mainWidget);
+ box->setSpacing(spacingHint());
+ QLabel* label = new QLabel(i18n("Template name:"), box);
+ label->setFixedSize(label->sizeHint());
+ mTemplateName = new QLineEdit(box);
+ mTemplateName->setReadOnly(mReadOnly);
+ label->setBuddy(mTemplateName);
+ QWhatsThis::add(box, i18n("Enter the name of the alarm template"));
+ box->setFixedHeight(box->sizeHint().height());
+ }
+ mTabs = new QTabWidget(mainWidget);
+ mTabs->setMargin(marginHint());
+
+ QVBox* mainPageBox = new QVBox(mTabs);
+ mainPageBox->setSpacing(spacingHint());
+ mTabs->addTab(mainPageBox, i18n("&Alarm"));
+ mMainPageIndex = 0;
+ PageFrame* mainPage = new PageFrame(mainPageBox);
+ connect(mainPage, SIGNAL(shown()), SLOT(slotShowMainPage()));
+ QVBoxLayout* topLayout = new QVBoxLayout(mainPage, 0, spacingHint());
+
+ // Recurrence tab
+ QVBox* recurTab = new QVBox(mTabs);
+ mainPageBox->setSpacing(spacingHint());
+ mTabs->addTab(recurTab, QString::null);
+ mRecurPageIndex = 1;
+ mRecurrenceEdit = new RecurrenceEdit(readOnly, recurTab, "recurPage");
+ connect(mRecurrenceEdit, SIGNAL(shown()), SLOT(slotShowRecurrenceEdit()));
+ connect(mRecurrenceEdit, SIGNAL(typeChanged(int)), SLOT(slotRecurTypeChange(int)));
+ connect(mRecurrenceEdit, SIGNAL(frequencyChanged()), SLOT(slotRecurFrequencyChange()));
+ connect(mRecurrenceEdit, SIGNAL(repeatNeedsInitialisation()), SLOT(slotSetSubRepetition()));
+
+ // Alarm action
+
+ mActionGroup = new ButtonGroup(i18n("Action"), mainPage, "actionGroup");
+ connect(mActionGroup, SIGNAL(buttonSet(int)), SLOT(slotAlarmTypeChanged(int)));
+ topLayout->addWidget(mActionGroup, 1);
+ QBoxLayout* layout = new QVBoxLayout(mActionGroup, marginHint(), spacingHint());
+ layout->addSpacing(fontMetrics().lineSpacing()/2);
+ QGridLayout* grid = new QGridLayout(layout, 1, 5);
+
+ // Message radio button
+ mMessageRadio = new RadioButton(i18n("Te&xt"), mActionGroup, "messageButton");
+ mMessageRadio->setFixedSize(mMessageRadio->sizeHint());
+ QWhatsThis::add(mMessageRadio,
+ i18n("If checked, the alarm will display a text message."));
+ grid->addWidget(mMessageRadio, 1, 0);
+ grid->setColStretch(1, 1);
+
+ // File radio button
+ mFileRadio = new PickAlarmFileRadio(i18n("&File"), mActionGroup, "fileButton");
+ mFileRadio->setFixedSize(mFileRadio->sizeHint());
+ QWhatsThis::add(mFileRadio,
+ i18n("If checked, the alarm will display the contents of a text or image file."));
+ grid->addWidget(mFileRadio, 1, 2);
+ grid->setColStretch(3, 1);
+
+ // Command radio button
+ mCommandRadio = new RadioButton(i18n("Co&mmand"), mActionGroup, "cmdButton");
+ mCommandRadio->setFixedSize(mCommandRadio->sizeHint());
+ QWhatsThis::add(mCommandRadio,
+ i18n("If checked, the alarm will execute a shell command."));
+ grid->addWidget(mCommandRadio, 1, 4);
+ grid->setColStretch(5, 1);
+
+ // Email radio button
+ mEmailRadio = new RadioButton(i18n("&Email"), mActionGroup, "emailButton");
+ mEmailRadio->setFixedSize(mEmailRadio->sizeHint());
+ QWhatsThis::add(mEmailRadio,
+ i18n("If checked, the alarm will send an email."));
+ grid->addWidget(mEmailRadio, 1, 6);
+
+ initDisplayAlarms(mActionGroup);
+ layout->addWidget(mDisplayAlarmsFrame);
+ initCommand(mActionGroup);
+ layout->addWidget(mCommandFrame);
+ initEmail(mActionGroup);
+ layout->addWidget(mEmailFrame);
+
+ // Deferred date/time: visible only for a deferred recurring event.
+ mDeferGroup = new QGroupBox(1, Qt::Vertical, i18n("Deferred Alarm"), mainPage, "deferGroup");
+ topLayout->addWidget(mDeferGroup);
+ QLabel* label = new QLabel(i18n("Deferred to:"), mDeferGroup);
+ label->setFixedSize(label->sizeHint());
+ mDeferTimeLabel = new QLabel(mDeferGroup);
+
+ mDeferChangeButton = new QPushButton(i18n("C&hange..."), mDeferGroup);
+ mDeferChangeButton->setFixedSize(mDeferChangeButton->sizeHint());
+ connect(mDeferChangeButton, SIGNAL(clicked()), SLOT(slotEditDeferral()));
+ QWhatsThis::add(mDeferChangeButton, i18n("Change the alarm's deferred time, or cancel the deferral"));
+ mDeferGroup->addSpace(0);
+
+ layout = new QHBoxLayout(topLayout);
+
+ // Date and time entry
+ if (mTemplate)
+ {
+ mTemplateTimeGroup = new ButtonGroup(i18n("Time"), mainPage, "templateGroup");
+ connect(mTemplateTimeGroup, SIGNAL(buttonSet(int)), SLOT(slotTemplateTimeType(int)));
+ layout->addWidget(mTemplateTimeGroup);
+ grid = new QGridLayout(mTemplateTimeGroup, 2, 2, marginHint(), spacingHint());
+ grid->addRowSpacing(0, fontMetrics().lineSpacing()/2);
+ // Get alignment to use in QGridLayout (AlignAuto doesn't work correctly there)
+ int alignment = QApplication::reverseLayout() ? Qt::AlignRight : Qt::AlignLeft;
+
+ mTemplateDefaultTime = new RadioButton(i18n("&Default time"), mTemplateTimeGroup, "templateDefTimeButton");
+ mTemplateDefaultTime->setFixedSize(mTemplateDefaultTime->sizeHint());
+ mTemplateDefaultTime->setReadOnly(mReadOnly);
+ QWhatsThis::add(mTemplateDefaultTime,
+ i18n("Do not specify a start time for alarms based on this template. "
+ "The normal default start time will be used."));
+ grid->addWidget(mTemplateDefaultTime, 0, 0, alignment);
+
+ QHBox* box = new QHBox(mTemplateTimeGroup);
+ box->setSpacing(spacingHint());
+ mTemplateUseTime = new RadioButton(i18n("Time:"), box, "templateTimeButton");
+ mTemplateUseTime->setFixedSize(mTemplateUseTime->sizeHint());
+ mTemplateUseTime->setReadOnly(mReadOnly);
+ QWhatsThis::add(mTemplateUseTime,
+ i18n("Specify a start time for alarms based on this template."));
+ mTemplateTimeGroup->insert(mTemplateUseTime);
+ mTemplateTime = new TimeEdit(box, "templateTimeEdit");
+ mTemplateTime->setFixedSize(mTemplateTime->sizeHint());
+ mTemplateTime->setReadOnly(mReadOnly);
+ QWhatsThis::add(mTemplateTime,
+ QString("%1\n\n%2").arg(i18n("Enter the start time for alarms based on this template."))
+ .arg(TimeSpinBox::shiftWhatsThis()));
+ box->setStretchFactor(new QWidget(box), 1); // left adjust the controls
+ box->setFixedHeight(box->sizeHint().height());
+ grid->addWidget(box, 0, 1, alignment);
+
+ mTemplateAnyTime = new RadioButton(i18n("An&y time"), mTemplateTimeGroup, "templateAnyTimeButton");
+ mTemplateAnyTime->setFixedSize(mTemplateAnyTime->sizeHint());
+ mTemplateAnyTime->setReadOnly(mReadOnly);
+ QWhatsThis::add(mTemplateAnyTime,
+ i18n("Set the '%1' option for alarms based on this template.").arg(i18n("Any time")));
+ grid->addWidget(mTemplateAnyTime, 1, 0, alignment);
+
+ box = new QHBox(mTemplateTimeGroup);
+ box->setSpacing(spacingHint());
+ mTemplateUseTimeAfter = new RadioButton(AlarmTimeWidget::i18n_w_TimeFromNow(), box, "templateFromNowButton");
+ mTemplateUseTimeAfter->setFixedSize(mTemplateUseTimeAfter->sizeHint());
+ mTemplateUseTimeAfter->setReadOnly(mReadOnly);
+ QWhatsThis::add(mTemplateUseTimeAfter,
+ i18n("Set alarms based on this template to start after the specified time "
+ "interval from when the alarm is created."));
+ mTemplateTimeGroup->insert(mTemplateUseTimeAfter);
+ mTemplateTimeAfter = new TimeSpinBox(1, maxDelayTime, box);
+ mTemplateTimeAfter->setValue(1439);
+ mTemplateTimeAfter->setFixedSize(mTemplateTimeAfter->sizeHint());
+ mTemplateTimeAfter->setReadOnly(mReadOnly);
+ QWhatsThis::add(mTemplateTimeAfter,
+ QString("%1\n\n%2").arg(AlarmTimeWidget::i18n_TimeAfterPeriod())
+ .arg(TimeSpinBox::shiftWhatsThis()));
+ box->setFixedHeight(box->sizeHint().height());
+ grid->addWidget(box, 1, 1, alignment);
+
+ layout->addStretch();
+ }
+ else
+ {
+ mTimeWidget = new AlarmTimeWidget(i18n("Time"), AlarmTimeWidget::AT_TIME, mainPage, "timeGroup");
+ connect(mTimeWidget, SIGNAL(anyTimeToggled(bool)), SLOT(slotAnyTimeToggled(bool)));
+ topLayout->addWidget(mTimeWidget);
+ }
+
+ // Reminder
+ static const QString reminderText = i18n("Enter how long in advance of the main alarm to display a reminder alarm.");
+ mReminder = new Reminder(i18n("Rem&inder:"),
+ i18n("Check to additionally display a reminder in advance of the main alarm time(s)."),
+ QString("%1\n\n%2").arg(reminderText).arg(TimeSpinBox::shiftWhatsThis()),
+ true, true, mainPage);
+ mReminder->setFixedSize(mReminder->sizeHint());
+ topLayout->addWidget(mReminder, 0, Qt::AlignAuto);
+
+ // Late cancel selector - default = allow late display
+ mLateCancel = new LateCancelSelector(true, mainPage);
+ topLayout->addWidget(mLateCancel, 0, Qt::AlignAuto);
+
+ // Acknowledgement confirmation required - default = no confirmation
+ layout = new QHBoxLayout(topLayout, 0);
+ mConfirmAck = createConfirmAckCheckbox(mainPage);
+ mConfirmAck->setFixedSize(mConfirmAck->sizeHint());
+ layout->addWidget(mConfirmAck);
+ layout->addSpacing(2*spacingHint());
+ layout->addStretch();
+
+ if (theApp()->korganizerEnabled())
+ {
+ // Show in KOrganizer checkbox
+ mShowInKorganizer = new CheckBox(i18n_ShowInKOrganizer(), mainPage);
+ mShowInKorganizer->setFixedSize(mShowInKorganizer->sizeHint());
+ QWhatsThis::add(mShowInKorganizer, i18n("Check to copy the alarm into KOrganizer's calendar"));
+ layout->addWidget(mShowInKorganizer);
+ }
+
+ setButtonWhatsThis(Ok, i18n("Schedule the alarm at the specified time."));
+
+ // Initialise the state of all controls according to the specified event, if any
+ initialise(event);
+ if (mTemplateName)
+ mTemplateName->setFocus();
+
+ // Save the initial state of all controls so that we can later tell if they have changed
+ saveState((event && (mTemplate || !event->isTemplate())) ? event : 0);
+
+ // Note the current desktop so that the dialog can be shown on it.
+ // If a main window is visible, the dialog will by KDE default always appear on its
+ // desktop. If the user invokes the dialog via the system tray on a different desktop,
+ // that can cause confusion.
+ mDesktop = KWin::currentDesktop();
+}
+
+EditAlarmDlg::~EditAlarmDlg()
+{
+ delete mSavedEvent;
+}
+
+/******************************************************************************
+ * Set up the dialog controls common to display alarms.
+ */
+void EditAlarmDlg::initDisplayAlarms(QWidget* parent)
+{
+ mDisplayAlarmsFrame = new QFrame(parent);
+ mDisplayAlarmsFrame->setFrameStyle(QFrame::NoFrame);
+ QBoxLayout* frameLayout = new QVBoxLayout(mDisplayAlarmsFrame, 0, spacingHint());
+
+ // Text message edit box
+ mTextMessageEdit = new TextEdit(mDisplayAlarmsFrame);
+ mTextMessageEdit->setWordWrap(KTextEdit::NoWrap);
+ QWhatsThis::add(mTextMessageEdit, i18n("Enter the text of the alarm message. It may be multi-line."));
+ frameLayout->addWidget(mTextMessageEdit);
+
+ // File name edit box
+ mFileBox = new QHBox(mDisplayAlarmsFrame);
+ frameLayout->addWidget(mFileBox);
+ mFileMessageEdit = new LineEdit(LineEdit::Url, mFileBox);
+ mFileMessageEdit->setAcceptDrops(true);
+ QWhatsThis::add(mFileMessageEdit, i18n("Enter the name or URL of a text or image file to display."));
+
+ // File browse button
+ mFileBrowseButton = new QPushButton(mFileBox);
+ mFileBrowseButton->setPixmap(SmallIcon("fileopen"));
+ mFileBrowseButton->setFixedSize(mFileBrowseButton->sizeHint());
+ QToolTip::add(mFileBrowseButton, i18n("Choose a file"));
+ QWhatsThis::add(mFileBrowseButton, i18n("Select a text or image file to display."));
+ mFileRadio->init(mFileBrowseButton, mFileMessageEdit);
+
+ // Font and colour choice button and sample text
+ mFontColourButton = new FontColourButton(mDisplayAlarmsFrame);
+ mFontColourButton->setMaximumHeight(mFontColourButton->sizeHint().height());
+ frameLayout->addWidget(mFontColourButton);
+
+ QHBoxLayout* layout = new QHBoxLayout(frameLayout, 0, 0);
+ mBgColourBox = new QHBox(mDisplayAlarmsFrame);
+ mBgColourBox->setSpacing(spacingHint());
+ layout->addWidget(mBgColourBox);
+ layout->addStretch();
+ QLabel* label = new QLabel(i18n("&Background color:"), mBgColourBox);
+ mBgColourButton = new ColourCombo(mBgColourBox);
+ label->setBuddy(mBgColourButton);
+ QWhatsThis::add(mBgColourBox, i18n("Select the alarm message background color"));
+
+ // Sound checkbox and file selector
+ layout = new QHBoxLayout(frameLayout);
+ mSoundPicker = new SoundPicker(mDisplayAlarmsFrame);
+ mSoundPicker->setFixedSize(mSoundPicker->sizeHint());
+ layout->addWidget(mSoundPicker);
+ layout->addSpacing(2*spacingHint());
+ layout->addStretch();
+
+ if (ShellProcess::authorised()) // don't display if shell commands not allowed (e.g. kiosk mode)
+ {
+ // Special actions button
+ mSpecialActionsButton = new SpecialActionsButton(i18n_SpecialActions(), mDisplayAlarmsFrame);
+ mSpecialActionsButton->setFixedSize(mSpecialActionsButton->sizeHint());
+ layout->addWidget(mSpecialActionsButton);
+ }
+
+ // Top-adjust the controls
+ mFilePadding = new QHBox(mDisplayAlarmsFrame);
+ frameLayout->addWidget(mFilePadding);
+ frameLayout->setStretchFactor(mFilePadding, 1);
+}
+
+/******************************************************************************
+ * Set up the command alarm dialog controls.
+ */
+void EditAlarmDlg::initCommand(QWidget* parent)
+{
+ mCommandFrame = new QFrame(parent);
+ mCommandFrame->setFrameStyle(QFrame::NoFrame);
+ QBoxLayout* frameLayout = new QVBoxLayout(mCommandFrame, 0, spacingHint());
+
+ mCmdTypeScript = new CheckBox(i18n_p_EnterScript(), mCommandFrame);
+ mCmdTypeScript->setFixedSize(mCmdTypeScript->sizeHint());
+ connect(mCmdTypeScript, SIGNAL(toggled(bool)), SLOT(slotCmdScriptToggled(bool)));
+ QWhatsThis::add(mCmdTypeScript, i18n("Check to enter the contents of a script instead of a shell command line"));
+ frameLayout->addWidget(mCmdTypeScript, 0, Qt::AlignAuto);
+
+ mCmdCommandEdit = new LineEdit(LineEdit::Url, mCommandFrame);
+ QWhatsThis::add(mCmdCommandEdit, i18n("Enter a shell command to execute."));
+ frameLayout->addWidget(mCmdCommandEdit);
+
+ mCmdScriptEdit = new TextEdit(mCommandFrame);
+ QWhatsThis::add(mCmdScriptEdit, i18n("Enter the contents of a script to execute"));
+ frameLayout->addWidget(mCmdScriptEdit);
+
+ // What to do with command output
+
+ mCmdOutputGroup = new ButtonGroup(i18n("Command Output"), mCommandFrame);
+ frameLayout->addWidget(mCmdOutputGroup);
+ QBoxLayout* layout = new QVBoxLayout(mCmdOutputGroup, marginHint(), spacingHint());
+ layout->addSpacing(fontMetrics().lineSpacing()/2);
+
+ // Execute in terminal window
+ RadioButton* button = new RadioButton(i18n_u_ExecInTermWindow(), mCmdOutputGroup, "execInTerm");
+ button->setFixedSize(button->sizeHint());
+ QWhatsThis::add(button, i18n("Check to execute the command in a terminal window"));
+ mCmdOutputGroup->insert(button, EXEC_IN_TERMINAL);
+ layout->addWidget(button, 0, Qt::AlignAuto);
+
+ // Log file name edit box
+ QHBox* box = new QHBox(mCmdOutputGroup);
+ (new QWidget(box))->setFixedWidth(button->style().subRect(QStyle::SR_RadioButtonIndicator, button).width()); // indent the edit box
+// (new QWidget(box))->setFixedWidth(button->style().pixelMetric(QStyle::PM_ExclusiveIndicatorWidth)); // indent the edit box
+ mCmdLogFileEdit = new LineEdit(LineEdit::Url, box);
+ mCmdLogFileEdit->setAcceptDrops(true);
+ QWhatsThis::add(mCmdLogFileEdit, i18n("Enter the name or path of the log file."));
+
+ // Log file browse button.
+ // The file browser dialogue is activated by the PickLogFileRadio class.
+ QPushButton* browseButton = new QPushButton(box);
+ browseButton->setPixmap(SmallIcon("fileopen"));
+ browseButton->setFixedSize(browseButton->sizeHint());
+ QToolTip::add(browseButton, i18n("Choose a file"));
+ QWhatsThis::add(browseButton, i18n("Select a log file."));
+
+ // Log output to file
+ button = new PickLogFileRadio(browseButton, mCmdLogFileEdit, i18n_g_LogToFile(), mCmdOutputGroup, "cmdLog");
+ button->setFixedSize(button->sizeHint());
+ QWhatsThis::add(button,
+ i18n("Check to log the command output to a local file. The output will be appended to any existing contents of the file."));
+ mCmdOutputGroup->insert(button, LOG_TO_FILE);
+ layout->addWidget(button, 0, Qt::AlignAuto);
+ layout->addWidget(box);
+
+ // Discard output
+ button = new RadioButton(i18n("Discard"), mCmdOutputGroup, "cmdDiscard");
+ button->setFixedSize(button->sizeHint());
+ QWhatsThis::add(button, i18n("Check to discard command output."));
+ mCmdOutputGroup->insert(button, DISCARD_OUTPUT);
+ layout->addWidget(button, 0, Qt::AlignAuto);
+
+ // Top-adjust the controls
+ mCmdPadding = new QHBox(mCommandFrame);
+ frameLayout->addWidget(mCmdPadding);
+ frameLayout->setStretchFactor(mCmdPadding, 1);
+}
+
+/******************************************************************************
+ * Set up the email alarm dialog controls.
+ */
+void EditAlarmDlg::initEmail(QWidget* parent)
+{
+ mEmailFrame = new QFrame(parent);
+ mEmailFrame->setFrameStyle(QFrame::NoFrame);
+ QBoxLayout* layout = new QVBoxLayout(mEmailFrame, 0, spacingHint());
+ QGridLayout* grid = new QGridLayout(layout, 3, 3, spacingHint());
+ grid->setColStretch(1, 1);
+
+ mEmailFromList = 0;
+ if (Preferences::emailFrom() == Preferences::MAIL_FROM_KMAIL)
+ {
+ // Email sender identity
+ QLabel* label = new QLabel(i18n_EmailFrom(), mEmailFrame);
+ label->setFixedSize(label->sizeHint());
+ grid->addWidget(label, 0, 0);
+
+ mEmailFromList = new EmailIdCombo(KAMail::identityManager(), mEmailFrame);
+ mEmailFromList->setMinimumSize(mEmailFromList->sizeHint());
+ label->setBuddy(mEmailFromList);
+ QWhatsThis::add(mEmailFromList,
+ i18n("Your email identity, used to identify you as the sender when sending email alarms."));
+ grid->addMultiCellWidget(mEmailFromList, 0, 0, 1, 2);
+ }
+
+ // Email recipients
+ QLabel* label = new QLabel(i18n_EmailTo(), mEmailFrame);
+ label->setFixedSize(label->sizeHint());
+ grid->addWidget(label, 1, 0);
+
+ mEmailToEdit = new LineEdit(LineEdit::Emails, mEmailFrame);
+ mEmailToEdit->setMinimumSize(mEmailToEdit->sizeHint());
+ QWhatsThis::add(mEmailToEdit,
+ i18n("Enter the addresses of the email recipients. Separate multiple addresses by "
+ "commas or semicolons."));
+ grid->addWidget(mEmailToEdit, 1, 1);
+
+ mEmailAddressButton = new QPushButton(mEmailFrame);
+ mEmailAddressButton->setPixmap(SmallIcon("contents"));
+ mEmailAddressButton->setFixedSize(mEmailAddressButton->sizeHint());
+ connect(mEmailAddressButton, SIGNAL(clicked()), SLOT(openAddressBook()));
+ QToolTip::add(mEmailAddressButton, i18n("Open address book"));
+ QWhatsThis::add(mEmailAddressButton, i18n("Select email addresses from your address book."));
+ grid->addWidget(mEmailAddressButton, 1, 2);
+
+ // Email subject
+ label = new QLabel(i18n_j_EmailSubject(), mEmailFrame);
+ label->setFixedSize(label->sizeHint());
+ grid->addWidget(label, 2, 0);
+
+ mEmailSubjectEdit = new LineEdit(mEmailFrame);
+ mEmailSubjectEdit->setMinimumSize(mEmailSubjectEdit->sizeHint());
+ label->setBuddy(mEmailSubjectEdit);
+ QWhatsThis::add(mEmailSubjectEdit, i18n("Enter the email subject."));
+ grid->addMultiCellWidget(mEmailSubjectEdit, 2, 2, 1, 2);
+
+ // Email body
+ mEmailMessageEdit = new TextEdit(mEmailFrame);
+ QWhatsThis::add(mEmailMessageEdit, i18n("Enter the email message."));
+ layout->addWidget(mEmailMessageEdit);
+
+ // Email attachments
+ grid = new QGridLayout(layout, 2, 3, spacingHint());
+ label = new QLabel(i18n("Attachment&s:"), mEmailFrame);
+ label->setFixedSize(label->sizeHint());
+ grid->addWidget(label, 0, 0);
+
+ mEmailAttachList = new QComboBox(true, mEmailFrame);
+ mEmailAttachList->setMinimumSize(mEmailAttachList->sizeHint());
+ mEmailAttachList->lineEdit()->setReadOnly(true);
+QListBox* list = mEmailAttachList->listBox();
+QRect rect = list->geometry();
+list->setGeometry(rect.left() - 50, rect.top(), rect.width(), rect.height());
+ label->setBuddy(mEmailAttachList);
+ QWhatsThis::add(mEmailAttachList,
+ i18n("Files to send as attachments to the email."));
+ grid->addWidget(mEmailAttachList, 0, 1);
+ grid->setColStretch(1, 1);
+
+ mEmailAddAttachButton = new QPushButton(i18n("Add..."), mEmailFrame);
+ connect(mEmailAddAttachButton, SIGNAL(clicked()), SLOT(slotAddAttachment()));
+ QWhatsThis::add(mEmailAddAttachButton, i18n("Add an attachment to the email."));
+ grid->addWidget(mEmailAddAttachButton, 0, 2);
+
+ mEmailRemoveButton = new QPushButton(i18n("Remo&ve"), mEmailFrame);
+ connect(mEmailRemoveButton, SIGNAL(clicked()), SLOT(slotRemoveAttachment()));
+ QWhatsThis::add(mEmailRemoveButton, i18n("Remove the highlighted attachment from the email."));
+ grid->addWidget(mEmailRemoveButton, 1, 2);
+
+ // BCC email to sender
+ mEmailBcc = new CheckBox(i18n_s_CopyEmailToSelf(), mEmailFrame);
+ mEmailBcc->setFixedSize(mEmailBcc->sizeHint());
+ QWhatsThis::add(mEmailBcc,
+ i18n("If checked, the email will be blind copied to you."));
+ grid->addMultiCellWidget(mEmailBcc, 1, 1, 0, 1, Qt::AlignAuto);
+}
+
+/******************************************************************************
+ * Initialise the dialogue controls from the specified event.
+ */
+void EditAlarmDlg::initialise(const KAEvent* event)
+{
+ mReadOnly = mDesiredReadOnly;
+ if (!mTemplate && event && event->action() == KAEvent::COMMAND && !ShellProcess::authorised())
+ mReadOnly = true; // don't allow editing of existing command alarms in kiosk mode
+ setReadOnly();
+
+ mChanged = false;
+ mOnlyDeferred = false;
+ mExpiredRecurrence = false;
+ mKMailSerialNumber = 0;
+ bool deferGroupVisible = false;
+ if (event)
+ {
+ // Set the values to those for the specified event
+ if (mTemplate)
+ mTemplateName->setText(event->templateName());
+ bool recurs = event->recurs();
+ if ((recurs || event->repeatCount()) && !mTemplate && event->deferred())
+ {
+ deferGroupVisible = true;
+ mDeferDateTime = event->deferDateTime();
+ mDeferTimeLabel->setText(mDeferDateTime.formatLocale());
+ mDeferGroup->show();
+ }
+ if (event->defaultFont())
+ mFontColourButton->setDefaultFont();
+ else
+ mFontColourButton->setFont(event->font());
+ mFontColourButton->setBgColour(event->bgColour());
+ mFontColourButton->setFgColour(event->fgColour());
+ mBgColourButton->setColour(event->bgColour());
+ if (mTemplate)
+ {
+ // Editing a template
+ int afterTime = event->isTemplate() ? event->templateAfterTime() : -1;
+ bool noTime = !afterTime;
+ bool useTime = !event->mainDateTime().isDateOnly();
+ int button = mTemplateTimeGroup->id(noTime ? mTemplateDefaultTime :
+ (afterTime > 0) ? mTemplateUseTimeAfter :
+ useTime ? mTemplateUseTime : mTemplateAnyTime);
+ mTemplateTimeGroup->setButton(button);
+ mTemplateTimeAfter->setValue(afterTime > 0 ? afterTime : 1);
+ if (!noTime && useTime)
+ mTemplateTime->setValue(event->mainDateTime().time());
+ else
+ mTemplateTime->setValue(0);
+ }
+ else
+ {
+ if (event->isTemplate())
+ {
+ // Initialising from an alarm template: use current date
+ QDateTime now = QDateTime::currentDateTime();
+ int afterTime = event->templateAfterTime();
+ if (afterTime >= 0)
+ {
+ mTimeWidget->setDateTime(now.addSecs(afterTime * 60));
+ mTimeWidget->selectTimeFromNow();
+ }
+ else
+ {
+ QDate d = now.date();
+ QTime t = event->startDateTime().time();
+ bool dateOnly = event->startDateTime().isDateOnly();
+ if (!dateOnly && now.time() >= t)
+ d = d.addDays(1); // alarm time has already passed, so use tomorrow
+ mTimeWidget->setDateTime(DateTime(QDateTime(d, t), dateOnly));
+ }
+ }
+ else
+ {
+ mExpiredRecurrence = recurs && event->mainExpired();
+ mTimeWidget->setDateTime(recurs || event->uidStatus() == KAEvent::EXPIRED ? event->startDateTime()
+ : event->mainExpired() ? event->deferDateTime() : event->mainDateTime());
+ }
+ }
+
+ KAEvent::Action action = event->action();
+ AlarmText altext;
+ if (event->commandScript())
+ altext.setScript(event->cleanText());
+ else
+ altext.setText(event->cleanText());
+ setAction(action, altext);
+ if (action == KAEvent::MESSAGE && event->kmailSerialNumber()
+ && AlarmText::checkIfEmail(event->cleanText()))
+ mKMailSerialNumber = event->kmailSerialNumber();
+ if (action == KAEvent::EMAIL)
+ mEmailAttachList->insertStringList(event->emailAttachments());
+
+ mLateCancel->setMinutes(event->lateCancel(), event->startDateTime().isDateOnly(),
+ TimePeriod::HOURS_MINUTES);
+ mLateCancel->showAutoClose(action == KAEvent::MESSAGE || action == KAEvent::FILE);
+ mLateCancel->setAutoClose(event->autoClose());
+ mLateCancel->setFixedSize(mLateCancel->sizeHint());
+ if (mShowInKorganizer)
+ mShowInKorganizer->setChecked(event->copyToKOrganizer());
+ mConfirmAck->setChecked(event->confirmAck());
+ int reminder = event->reminder();
+ if (!reminder && event->reminderDeferral() && !recurs)
+ {
+ reminder = event->reminderDeferral();
+ mReminderDeferral = true;
+ }
+ if (!reminder && event->reminderArchived() && recurs)
+ {
+ reminder = event->reminderArchived();
+ mReminderArchived = true;
+ }
+ mReminder->setMinutes(reminder, (mTimeWidget ? mTimeWidget->anyTime() : mTemplateAnyTime->isOn()));
+ mReminder->setOnceOnly(event->reminderOnceOnly());
+ mReminder->enableOnceOnly(event->recurs());
+ if (mSpecialActionsButton)
+ mSpecialActionsButton->setActions(event->preAction(), event->postAction());
+ mRecurrenceEdit->set(*event, (mTemplate || event->isTemplate())); // must be called after mTimeWidget is set up, to ensure correct date-only enabling
+ mTabs->setTabLabel(mTabs->page(mRecurPageIndex), recurText(*event));
+ SoundPicker::Type soundType = event->speak() ? SoundPicker::SPEAK
+ : event->beep() ? SoundPicker::BEEP
+ : !event->audioFile().isEmpty() ? SoundPicker::PLAY_FILE
+ : SoundPicker::NONE;
+ mSoundPicker->set(soundType, event->audioFile(), event->soundVolume(),
+ event->fadeVolume(), event->fadeSeconds(), event->repeatSound());
+ CmdLogType logType = event->commandXterm() ? EXEC_IN_TERMINAL
+ : !event->logFile().isEmpty() ? LOG_TO_FILE
+ : DISCARD_OUTPUT;
+ if (logType == LOG_TO_FILE)
+ mCmdLogFileEdit->setText(event->logFile()); // set file name before setting radio button
+ mCmdOutputGroup->setButton(logType);
+ mEmailToEdit->setText(event->emailAddresses(", "));
+ mEmailSubjectEdit->setText(event->emailSubject());
+ mEmailBcc->setChecked(event->emailBcc());
+ if (mEmailFromList)
+ mEmailFromList->setCurrentIdentity(event->emailFromId());
+ }
+ else
+ {
+ // Set the values to their defaults
+ if (!ShellProcess::authorised())
+ {
+ // Don't allow shell commands in kiosk mode
+ mCommandRadio->setEnabled(false);
+ if (mSpecialActionsButton)
+ mSpecialActionsButton->setEnabled(false);
+ }
+ mFontColourButton->setDefaultFont();
+ mFontColourButton->setBgColour(Preferences::defaultBgColour());
+ mFontColourButton->setFgColour(Preferences::defaultFgColour());
+ mBgColourButton->setColour(Preferences::defaultBgColour());
+ QDateTime defaultTime = QDateTime::currentDateTime().addSecs(60);
+ if (mTemplate)
+ {
+ mTemplateTimeGroup->setButton(mTemplateTimeGroup->id(mTemplateDefaultTime));
+ mTemplateTime->setValue(0);
+ mTemplateTimeAfter->setValue(1);
+ }
+ else
+ mTimeWidget->setDateTime(defaultTime);
+ mActionGroup->setButton(mActionGroup->id(mMessageRadio));
+ mLateCancel->setMinutes((Preferences::defaultLateCancel() ? 1 : 0), false, TimePeriod::HOURS_MINUTES);
+ mLateCancel->showAutoClose(true);
+ mLateCancel->setAutoClose(Preferences::defaultAutoClose());
+ mLateCancel->setFixedSize(mLateCancel->sizeHint());
+ if (mShowInKorganizer)
+ mShowInKorganizer->setChecked(Preferences::defaultCopyToKOrganizer());
+ mConfirmAck->setChecked(Preferences::defaultConfirmAck());
+ if (mSpecialActionsButton)
+ mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction());
+ mRecurrenceEdit->setDefaults(defaultTime); // must be called after mTimeWidget is set up, to ensure correct date-only enabling
+ slotRecurFrequencyChange(); // update the Recurrence text
+ mReminder->setMinutes(0, false);
+ mReminder->enableOnceOnly(mRecurrenceEdit->isTimedRepeatType()); // must be called after mRecurrenceEdit is set up
+ mSoundPicker->set(Preferences::defaultSoundType(), Preferences::defaultSoundFile(),
+ Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat());
+ mCmdTypeScript->setChecked(Preferences::defaultCmdScript());
+ mCmdLogFileEdit->setText(Preferences::defaultCmdLogFile()); // set file name before setting radio button
+ mCmdOutputGroup->setButton(Preferences::defaultCmdLogType());
+ mEmailBcc->setChecked(Preferences::defaultEmailBcc());
+ }
+ slotCmdScriptToggled(mCmdTypeScript->isChecked());
+
+ if (!deferGroupVisible)
+ mDeferGroup->hide();
+
+ bool enable = !!mEmailAttachList->count();
+ mEmailAttachList->setEnabled(enable);
+ if (mEmailRemoveButton)
+ mEmailRemoveButton->setEnabled(enable);
+ AlarmCalendar* cal = AlarmCalendar::templateCalendar();
+ bool empty = cal->isOpen() && !cal->events().count();
+ enableButton(Default, !empty);
+}
+
+/******************************************************************************
+ * Set the read-only status of all non-template controls.
+ */
+void EditAlarmDlg::setReadOnly()
+{
+ // Common controls
+ mMessageRadio->setReadOnly(mReadOnly);
+ mFileRadio->setReadOnly(mReadOnly);
+ mCommandRadio->setReadOnly(mReadOnly);
+ mEmailRadio->setReadOnly(mReadOnly);
+ if (mTimeWidget)
+ mTimeWidget->setReadOnly(mReadOnly);
+ mLateCancel->setReadOnly(mReadOnly);
+ if (mReadOnly)
+ mDeferChangeButton->hide();
+ else
+ mDeferChangeButton->show();
+ if (mShowInKorganizer)
+ mShowInKorganizer->setReadOnly(mReadOnly);
+
+ // Message alarm controls
+ mTextMessageEdit->setReadOnly(mReadOnly);
+ mFileMessageEdit->setReadOnly(mReadOnly);
+ mFontColourButton->setReadOnly(mReadOnly);
+ mBgColourButton->setReadOnly(mReadOnly);
+ mSoundPicker->setReadOnly(mReadOnly);
+ mConfirmAck->setReadOnly(mReadOnly);
+ mReminder->setReadOnly(mReadOnly);
+ if (mSpecialActionsButton)
+ mSpecialActionsButton->setReadOnly(mReadOnly);
+ if (mReadOnly)
+ {
+ mFileBrowseButton->hide();
+ mFontColourButton->hide();
+ }
+ else
+ {
+ mFileBrowseButton->show();
+ mFontColourButton->show();
+ }
+
+ // Command alarm controls
+ mCmdTypeScript->setReadOnly(mReadOnly);
+ mCmdCommandEdit->setReadOnly(mReadOnly);
+ mCmdScriptEdit->setReadOnly(mReadOnly);
+ for (int id = DISCARD_OUTPUT; id < EXEC_IN_TERMINAL; ++id)
+ ((RadioButton*)mCmdOutputGroup->find(id))->setReadOnly(mReadOnly);
+
+ // Email alarm controls
+ mEmailToEdit->setReadOnly(mReadOnly);
+ mEmailSubjectEdit->setReadOnly(mReadOnly);
+ mEmailMessageEdit->setReadOnly(mReadOnly);
+ mEmailBcc->setReadOnly(mReadOnly);
+ if (mEmailFromList)
+ mEmailFromList->setReadOnly(mReadOnly);
+ if (mReadOnly)
+ {
+ mEmailAddressButton->hide();
+ mEmailAddAttachButton->hide();
+ mEmailRemoveButton->hide();
+ }
+ else
+ {
+ mEmailAddressButton->show();
+ mEmailAddAttachButton->show();
+ mEmailRemoveButton->show();
+ }
+}
+
+/******************************************************************************
+ * Set the dialog's action and the action's text.
+ */
+void EditAlarmDlg::setAction(KAEvent::Action action, const AlarmText& alarmText)
+{
+ QString text = alarmText.displayText();
+ bool script;
+ QRadioButton* radio;
+ switch (action)
+ {
+ case KAEvent::FILE:
+ radio = mFileRadio;
+ mFileMessageEdit->setText(text);
+ break;
+ case KAEvent::COMMAND:
+ radio = mCommandRadio;
+ script = alarmText.isScript();
+ mCmdTypeScript->setChecked(script);
+ if (script)
+ mCmdScriptEdit->setText(text);
+ else
+ mCmdCommandEdit->setText(text);
+ break;
+ case KAEvent::EMAIL:
+ radio = mEmailRadio;
+ mEmailMessageEdit->setText(text);
+ break;
+ case KAEvent::MESSAGE:
+ default:
+ radio = mMessageRadio;
+ mTextMessageEdit->setText(text);
+ mKMailSerialNumber = 0;
+ if (alarmText.isEmail())
+ {
+ mKMailSerialNumber = alarmText.kmailSerialNumber();
+
+ // Set up email fields also, in case the user wants an email alarm
+ mEmailToEdit->setText(alarmText.to());
+ mEmailSubjectEdit->setText(alarmText.subject());
+ mEmailMessageEdit->setText(alarmText.body());
+ }
+ else if (alarmText.isScript())
+ {
+ // Set up command script field also, in case the user wants a command alarm
+ mCmdScriptEdit->setText(text);
+ mCmdTypeScript->setChecked(true);
+ }
+ break;
+ }
+ mActionGroup->setButton(mActionGroup->id(radio));
+}
+
+/******************************************************************************
+ * Create an "acknowledgement confirmation required" checkbox.
+ */
+CheckBox* EditAlarmDlg::createConfirmAckCheckbox(QWidget* parent, const char* name)
+{
+ CheckBox* widget = new CheckBox(i18n_k_ConfirmAck(), parent, name);
+ QWhatsThis::add(widget,
+ i18n("Check to be prompted for confirmation when you acknowledge the alarm."));
+ return widget;
+}
+
+/******************************************************************************
+ * Save the state of all controls.
+ */
+void EditAlarmDlg::saveState(const KAEvent* event)
+{
+ delete mSavedEvent;
+ mSavedEvent = 0;
+ if (event)
+ mSavedEvent = new KAEvent(*event);
+ if (mTemplate)
+ {
+ mSavedTemplateName = mTemplateName->text();
+ mSavedTemplateTimeType = mTemplateTimeGroup->selected();
+ mSavedTemplateTime = mTemplateTime->time();
+ mSavedTemplateAfterTime = mTemplateTimeAfter->value();
+ }
+ mSavedTypeRadio = mActionGroup->selected();
+ mSavedSoundType = mSoundPicker->sound();
+ mSavedSoundFile = mSoundPicker->file();
+ mSavedSoundVolume = mSoundPicker->volume(mSavedSoundFadeVolume, mSavedSoundFadeSeconds);
+ mSavedRepeatSound = mSoundPicker->repeat();
+ mSavedConfirmAck = mConfirmAck->isChecked();
+ mSavedFont = mFontColourButton->font();
+ mSavedFgColour = mFontColourButton->fgColour();
+ mSavedBgColour = mFileRadio->isOn() ? mBgColourButton->colour() : mFontColourButton->bgColour();
+ mSavedReminder = mReminder->minutes();
+ mSavedOnceOnly = mReminder->isOnceOnly();
+ if (mSpecialActionsButton)
+ {
+ mSavedPreAction = mSpecialActionsButton->preAction();
+ mSavedPostAction = mSpecialActionsButton->postAction();
+ }
+ checkText(mSavedTextFileCommandMessage, false);
+ mSavedCmdScript = mCmdTypeScript->isChecked();
+ mSavedCmdOutputRadio = mCmdOutputGroup->selected();
+ mSavedCmdLogFile = mCmdLogFileEdit->text();
+ if (mEmailFromList)
+ mSavedEmailFrom = mEmailFromList->currentIdentityName();
+ mSavedEmailTo = mEmailToEdit->text();
+ mSavedEmailSubject = mEmailSubjectEdit->text();
+ mSavedEmailAttach.clear();
+ for (int i = 0; i < mEmailAttachList->count(); ++i)
+ mSavedEmailAttach += mEmailAttachList->text(i);
+ mSavedEmailBcc = mEmailBcc->isChecked();
+ if (mTimeWidget)
+ mSavedDateTime = mTimeWidget->getDateTime(0, false, false);
+ mSavedLateCancel = mLateCancel->minutes();
+ mSavedAutoClose = mLateCancel->isAutoClose();
+ if (mShowInKorganizer)
+ mSavedShowInKorganizer = mShowInKorganizer->isChecked();
+ mSavedRecurrenceType = mRecurrenceEdit->repeatType();
+}
+
+/******************************************************************************
+ * Check whether any of the controls has changed state since the dialog was
+ * first displayed.
+ * Reply = true if any non-deferral controls have changed, or if it's a new event.
+ * = false if no non-deferral controls have changed. In this case,
+ * mOnlyDeferred indicates whether deferral controls may have changed.
+ */
+bool EditAlarmDlg::stateChanged() const
+{
+ mChanged = true;
+ mOnlyDeferred = false;
+ if (!mSavedEvent)
+ return true;
+ QString textFileCommandMessage;
+ checkText(textFileCommandMessage, false);
+ if (mTemplate)
+ {
+ if (mSavedTemplateName != mTemplateName->text()
+ || mSavedTemplateTimeType != mTemplateTimeGroup->selected()
+ || mTemplateUseTime->isOn() && mSavedTemplateTime != mTemplateTime->time()
+ || mTemplateUseTimeAfter->isOn() && mSavedTemplateAfterTime != mTemplateTimeAfter->value())
+ return true;
+ }
+ else
+ if (mSavedDateTime != mTimeWidget->getDateTime(0, false, false))
+ return true;
+ if (mSavedTypeRadio != mActionGroup->selected()
+ || mSavedLateCancel != mLateCancel->minutes()
+ || mShowInKorganizer && mSavedShowInKorganizer != mShowInKorganizer->isChecked()
+ || textFileCommandMessage != mSavedTextFileCommandMessage
+ || mSavedRecurrenceType != mRecurrenceEdit->repeatType())
+ return true;
+ if (mMessageRadio->isOn() || mFileRadio->isOn())
+ {
+ if (mSavedSoundType != mSoundPicker->sound()
+ || mSavedConfirmAck != mConfirmAck->isChecked()
+ || mSavedFont != mFontColourButton->font()
+ || mSavedFgColour != mFontColourButton->fgColour()
+ || mSavedBgColour != (mFileRadio->isOn() ? mBgColourButton->colour() : mFontColourButton->bgColour())
+ || mSavedReminder != mReminder->minutes()
+ || mSavedOnceOnly != mReminder->isOnceOnly()
+ || mSavedAutoClose != mLateCancel->isAutoClose())
+ return true;
+ if (mSpecialActionsButton)
+ {
+ if (mSavedPreAction != mSpecialActionsButton->preAction()
+ || mSavedPostAction != mSpecialActionsButton->postAction())
+ return true;
+ }
+ if (mSavedSoundType == SoundPicker::PLAY_FILE)
+ {
+ if (mSavedSoundFile != mSoundPicker->file())
+ return true;
+ if (!mSavedSoundFile.isEmpty())
+ {
+ float fadeVolume;
+ int fadeSecs;
+ if (mSavedRepeatSound != mSoundPicker->repeat()
+ || mSavedSoundVolume != mSoundPicker->volume(fadeVolume, fadeSecs)
+ || mSavedSoundFadeVolume != fadeVolume
+ || mSavedSoundFadeSeconds != fadeSecs)
+ return true;
+ }
+ }
+ }
+ else if (mCommandRadio->isOn())
+ {
+ if (mSavedCmdScript != mCmdTypeScript->isChecked()
+ || mSavedCmdOutputRadio != mCmdOutputGroup->selected())
+ return true;
+ if (mCmdOutputGroup->selectedId() == LOG_TO_FILE)
+ {
+ if (mSavedCmdLogFile != mCmdLogFileEdit->text())
+ return true;
+ }
+ }
+ else if (mEmailRadio->isOn())
+ {
+ QStringList emailAttach;
+ for (int i = 0; i < mEmailAttachList->count(); ++i)
+ emailAttach += mEmailAttachList->text(i);
+ if (mEmailFromList && mSavedEmailFrom != mEmailFromList->currentIdentityName()
+ || mSavedEmailTo != mEmailToEdit->text()
+ || mSavedEmailSubject != mEmailSubjectEdit->text()
+ || mSavedEmailAttach != emailAttach
+ || mSavedEmailBcc != mEmailBcc->isChecked())
+ return true;
+ }
+ if (mRecurrenceEdit->stateChanged())
+ return true;
+ if (mSavedEvent && mSavedEvent->deferred())
+ mOnlyDeferred = true;
+ mChanged = false;
+ return false;
+}
+
+/******************************************************************************
+ * Get the currently entered dialogue data.
+ * The data is returned in the supplied KAEvent instance.
+ * Reply = false if the only change has been to an existing deferral.
+ */
+bool EditAlarmDlg::getEvent(KAEvent& event)
+{
+ if (mChanged)
+ {
+ // It's a new event, or the edit controls have changed
+ setEvent(event, mAlarmMessage, false);
+ return true;
+ }
+
+ // Only the deferral time may have changed
+ event = *mSavedEvent;
+ if (mOnlyDeferred)
+ {
+ // Just modify the original event, to avoid expired recurring events
+ // being returned as rubbish.
+ if (mDeferDateTime.isValid())
+ event.defer(mDeferDateTime, event.reminderDeferral(), false);
+ else
+ event.cancelDefer();
+ }
+ return false;
+}
+
+/******************************************************************************
+* Extract the data in the dialogue and set up a KAEvent from it.
+* If 'trial' is true, the event is set up for a simple one-off test, ignoring
+* recurrence, reminder, template etc. data.
+*/
+void EditAlarmDlg::setEvent(KAEvent& event, const QString& text, bool trial)
+{
+ QDateTime dt;
+ if (!trial)
+ {
+ if (!mTemplate)
+ dt = mAlarmDateTime.dateTime();
+ else if (mTemplateUseTime->isOn())
+ dt = QDateTime(QDate(2000,1,1), mTemplateTime->time());
+ }
+ KAEvent::Action type = getAlarmType();
+ event.set(dt, text, (mFileRadio->isOn() ? mBgColourButton->colour() : mFontColourButton->bgColour()),
+ mFontColourButton->fgColour(), mFontColourButton->font(),
+ type, (trial ? 0 : mLateCancel->minutes()), getAlarmFlags());
+ switch (type)
+ {
+ case KAEvent::MESSAGE:
+ if (AlarmText::checkIfEmail(text))
+ event.setKMailSerialNumber(mKMailSerialNumber);
+ // fall through to FILE
+ case KAEvent::FILE:
+ {
+ float fadeVolume;
+ int fadeSecs;
+ float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
+ event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs);
+ if (!trial)
+ event.setReminder(mReminder->minutes(), mReminder->isOnceOnly());
+ if (mSpecialActionsButton)
+ event.setActions(mSpecialActionsButton->preAction(), mSpecialActionsButton->postAction());
+ break;
+ }
+ case KAEvent::EMAIL:
+ {
+ uint from = mEmailFromList ? mEmailFromList->currentIdentity() : 0;
+ event.setEmail(from, mEmailAddresses, mEmailSubjectEdit->text(), mEmailAttachments);
+ break;
+ }
+ case KAEvent::COMMAND:
+ if (mCmdOutputGroup->selectedId() == LOG_TO_FILE)
+ event.setLogFile(mCmdLogFileEdit->text());
+ break;
+ default:
+ break;
+ }
+ if (!trial)
+ {
+ if (mRecurrenceEdit->repeatType() != RecurrenceEdit::NO_RECUR)
+ {
+ mRecurrenceEdit->updateEvent(event, !mTemplate);
+ QDateTime now = QDateTime::currentDateTime();
+ bool dateOnly = mAlarmDateTime.isDateOnly();
+ if (dateOnly && mAlarmDateTime.date() < now.date()
+ || !dateOnly && mAlarmDateTime.rawDateTime() < now)
+ {
+ // A timed recurrence has an entered start date which has
+ // already expired, so we must adjust the next repetition.
+ event.setNextOccurrence(now);
+ }
+ mAlarmDateTime = event.startDateTime();
+ if (mDeferDateTime.isValid() && mDeferDateTime < mAlarmDateTime)
+ {
+ bool deferral = true;
+ bool deferReminder = false;
+ int reminder = mReminder->minutes();
+ if (reminder)
+ {
+ DateTime remindTime = mAlarmDateTime.addMins(-reminder);
+ if (mDeferDateTime >= remindTime)
+ {
+ if (remindTime > QDateTime::currentDateTime())
+ deferral = false; // ignore deferral if it's after next reminder
+ else if (mDeferDateTime > remindTime)
+ deferReminder = true; // it's the reminder which is being deferred
+ }
+ }
+ if (deferral)
+ event.defer(mDeferDateTime, deferReminder, false);
+ }
+ }
+ if (mTemplate)
+ {
+ int afterTime = mTemplateDefaultTime->isOn() ? 0
+ : mTemplateUseTimeAfter->isOn() ? mTemplateTimeAfter->value() : -1;
+ event.setTemplate(mTemplateName->text(), afterTime);
+ }
+ }
+}
+
+/******************************************************************************
+ * Get the currently specified alarm flag bits.
+ */
+int EditAlarmDlg::getAlarmFlags() const
+{
+ bool displayAlarm = mMessageRadio->isOn() || mFileRadio->isOn();
+ bool cmdAlarm = mCommandRadio->isOn();
+ bool emailAlarm = mEmailRadio->isOn();
+ return (displayAlarm && mSoundPicker->sound() == SoundPicker::BEEP ? KAEvent::BEEP : 0)
+ | (displayAlarm && mSoundPicker->sound() == SoundPicker::SPEAK ? KAEvent::SPEAK : 0)
+ | (displayAlarm && mSoundPicker->repeat() ? KAEvent::REPEAT_SOUND : 0)
+ | (displayAlarm && mConfirmAck->isChecked() ? KAEvent::CONFIRM_ACK : 0)
+ | (displayAlarm && mLateCancel->isAutoClose() ? KAEvent::AUTO_CLOSE : 0)
+ | (cmdAlarm && mCmdTypeScript->isChecked() ? KAEvent::SCRIPT : 0)
+ | (cmdAlarm && mCmdOutputGroup->selectedId() == EXEC_IN_TERMINAL ? KAEvent::EXEC_IN_XTERM : 0)
+ | (emailAlarm && mEmailBcc->isChecked() ? KAEvent::EMAIL_BCC : 0)
+ | (mShowInKorganizer && mShowInKorganizer->isChecked() ? KAEvent::COPY_KORGANIZER : 0)
+ | (mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN ? KAEvent::REPEAT_AT_LOGIN : 0)
+ | ((mTemplate ? mTemplateAnyTime->isOn() : mAlarmDateTime.isDateOnly()) ? KAEvent::ANY_TIME : 0)
+ | (mFontColourButton->defaultFont() ? KAEvent::DEFAULT_FONT : 0);
+}
+
+/******************************************************************************
+ * Get the currently selected alarm type.
+ */
+KAEvent::Action EditAlarmDlg::getAlarmType() const
+{
+ return mFileRadio->isOn() ? KAEvent::FILE
+ : mCommandRadio->isOn() ? KAEvent::COMMAND
+ : mEmailRadio->isOn() ? KAEvent::EMAIL
+ : KAEvent::MESSAGE;
+}
+
+/******************************************************************************
+* Called when the dialog is displayed.
+* The first time through, sets the size to the same as the last time it was
+* displayed.
+*/
+void EditAlarmDlg::showEvent(QShowEvent* se)
+{
+ if (!mDeferGroupHeight)
+ {
+ mDeferGroupHeight = mDeferGroup->height() + spacingHint();
+ QSize s;
+ if (KAlarm::readConfigWindowSize(EDIT_DIALOG_NAME, s))
+ s.setHeight(s.height() + (mDeferGroup->isHidden() ? 0 : mDeferGroupHeight));
+ else
+ s = minimumSize();
+ resize(s);
+ }
+ KWin::setOnDesktop(winId(), mDesktop); // ensure it displays on the desktop expected by the user
+ KDialog::showEvent(se);
+}
+
+/******************************************************************************
+* Called when the dialog's size has changed.
+* Records the new size (adjusted to ignore the optional height of the deferred
+* time edit widget) in the config file.
+*/
+void EditAlarmDlg::resizeEvent(QResizeEvent* re)
+{
+ if (isVisible())
+ {
+ QSize s = re->size();
+ s.setHeight(s.height() - (mDeferGroup->isHidden() ? 0 : mDeferGroupHeight));
+ KAlarm::writeConfigWindowSize(EDIT_DIALOG_NAME, s);
+ }
+ KDialog::resizeEvent(re);
+}
+
+/******************************************************************************
+* Called when the OK button is clicked.
+* Validate the input data.
+*/
+void EditAlarmDlg::slotOk()
+{
+ if (!stateChanged())
+ {
+ // No changes have been made except possibly to an existing deferral
+ if (!mOnlyDeferred)
+ reject();
+ else
+ accept();
+ return;
+ }
+ RecurrenceEdit::RepeatType recurType = mRecurrenceEdit->repeatType();
+ if (mTimeWidget
+ && mTabs->currentPageIndex() == mRecurPageIndex && recurType == RecurrenceEdit::AT_LOGIN)
+ mTimeWidget->setDateTime(mRecurrenceEdit->endDateTime());
+ bool timedRecurrence = mRecurrenceEdit->isTimedRepeatType(); // does it recur other than at login?
+ if (mTemplate)
+ {
+ // Check that the template name is not blank and is unique
+ QString errmsg;
+ QString name = mTemplateName->text();
+ if (name.isEmpty())
+ errmsg = i18n("You must enter a name for the alarm template");
+ else if (name != mSavedTemplateName)
+ {
+ AlarmCalendar* cal = AlarmCalendar::templateCalendarOpen();
+ if (cal && KAEvent::findTemplateName(*cal, name).valid())
+ errmsg = i18n("Template name is already in use");
+ }
+ if (!errmsg.isEmpty())
+ {
+ mTemplateName->setFocus();
+ KMessageBox::sorry(this, errmsg);
+ return;
+ }
+ }
+ else
+ {
+ QWidget* errWidget;
+ mAlarmDateTime = mTimeWidget->getDateTime(0, !timedRecurrence, false, &errWidget);
+ if (errWidget)
+ {
+ // It's more than just an existing deferral being changed, so the time matters
+ mTabs->setCurrentPage(mMainPageIndex);
+ errWidget->setFocus();
+ mTimeWidget->getDateTime(); // display the error message now
+ return;
+ }
+ }
+ if (!checkCommandData()
+ || !checkEmailData())
+ return;
+ if (!mTemplate)
+ {
+ if (timedRecurrence)
+ {
+ QDateTime now = QDateTime::currentDateTime();
+ if (mAlarmDateTime.date() < now.date()
+ || mAlarmDateTime.date() == now.date()
+ && !mAlarmDateTime.isDateOnly() && mAlarmDateTime.time() < now.time())
+ {
+ // A timed recurrence has an entered start date which
+ // has already expired, so we must adjust it.
+ KAEvent event;
+ getEvent(event); // this may adjust mAlarmDateTime
+ if (( mAlarmDateTime.date() < now.date()
+ || mAlarmDateTime.date() == now.date()
+ && !mAlarmDateTime.isDateOnly() && mAlarmDateTime.time() < now.time())
+ && event.nextOccurrence(now, mAlarmDateTime, KAEvent::ALLOW_FOR_REPETITION) == KAEvent::NO_OCCURRENCE)
+ {
+ KMessageBox::sorry(this, i18n("Recurrence has already expired"));
+ return;
+ }
+ }
+ }
+ QString errmsg;
+ QWidget* errWidget = mRecurrenceEdit->checkData(mAlarmDateTime.dateTime(), errmsg);
+ if (errWidget)
+ {
+ mTabs->setCurrentPage(mRecurPageIndex);
+ errWidget->setFocus();
+ KMessageBox::sorry(this, errmsg);
+ return;
+ }
+ }
+ if (recurType != RecurrenceEdit::NO_RECUR)
+ {
+ KAEvent recurEvent;
+ int longestRecurInterval = -1;
+ int reminder = mReminder->minutes();
+ if (reminder && !mReminder->isOnceOnly())
+ {
+ mRecurrenceEdit->updateEvent(recurEvent, false);
+ longestRecurInterval = recurEvent.longestRecurrenceInterval();
+ if (longestRecurInterval && reminder >= longestRecurInterval)
+ {
+ mTabs->setCurrentPage(mMainPageIndex);
+ mReminder->setFocusOnCount();
+ KMessageBox::sorry(this, i18n("Reminder period must be less than the recurrence interval, unless '%1' is checked."
+ ).arg(Reminder::i18n_first_recurrence_only()));
+ return;
+ }
+ }
+ if (mRecurrenceEdit->subRepeatCount())
+ {
+ if (longestRecurInterval < 0)
+ {
+ mRecurrenceEdit->updateEvent(recurEvent, false);
+ longestRecurInterval = recurEvent.longestRecurrenceInterval();
+ }
+ if (longestRecurInterval > 0
+ && recurEvent.repeatInterval() * recurEvent.repeatCount() >= longestRecurInterval - reminder)
+ {
+ KMessageBox::sorry(this, i18n("The duration of a repetition within the recurrence must be less than the recurrence interval minus any reminder period"));
+ mRecurrenceEdit->activateSubRepetition(); // display the alarm repetition dialog again
+ return;
+ }
+ if (recurEvent.repeatInterval() % 1440
+ && (mTemplate && mTemplateAnyTime->isOn() || !mTemplate && mAlarmDateTime.isDateOnly()))
+ {
+ KMessageBox::sorry(this, i18n("For a repetition within the recurrence, its period must be in units of days or weeks for a date-only alarm"));
+ mRecurrenceEdit->activateSubRepetition(); // display the alarm repetition dialog again
+ return;
+ }
+ }
+ }
+ if (checkText(mAlarmMessage))
+ accept();
+}
+
+/******************************************************************************
+* Called when the Try button is clicked.
+* Display/execute the alarm immediately for the user to check its configuration.
+*/
+void EditAlarmDlg::slotTry()
+{
+ QString text;
+ if (checkText(text))
+ {
+ if (mEmailRadio->isOn())
+ {
+ if (!checkEmailData()
+ || KMessageBox::warningContinueCancel(this, i18n("Do you really want to send the email now to the specified recipient(s)?"),
+ i18n("Confirm Email"), i18n("&Send")) != KMessageBox::Continue)
+ return;
+ }
+ KAEvent event;
+ setEvent(event, text, true);
+ void* proc = theApp()->execAlarm(event, event.firstAlarm(), false, false);
+ if (proc)
+ {
+ if (mCommandRadio->isOn() && mCmdOutputGroup->selectedId() != EXEC_IN_TERMINAL)
+ {
+ theApp()->commandMessage((ShellProcess*)proc, this);
+ KMessageBox::information(this, i18n("Command executed:\n%1").arg(text));
+ theApp()->commandMessage((ShellProcess*)proc, 0);
+ }
+ else if (mEmailRadio->isOn())
+ {
+ QString bcc;
+ if (mEmailBcc->isChecked())
+ bcc = i18n("\nBcc: %1").arg(Preferences::emailBccAddress());
+ KMessageBox::information(this, i18n("Email sent to:\n%1%2").arg(mEmailAddresses.join("\n")).arg(bcc));
+ }
+ }
+ }
+}
+
+/******************************************************************************
+* Called when the Cancel button is clicked.
+*/
+void EditAlarmDlg::slotCancel()
+{
+ reject();
+}
+
+/******************************************************************************
+* Called when the Load Template button is clicked.
+* Prompt to select a template and initialise the dialogue with its contents.
+*/
+void EditAlarmDlg::slotDefault()
+{
+ TemplatePickDlg dlg(this, "templPickDlg");
+ if (dlg.exec() == QDialog::Accepted)
+ initialise(dlg.selectedTemplate());
+}
+
+/******************************************************************************
+ * Called when the Change deferral button is clicked.
+ */
+void EditAlarmDlg::slotEditDeferral()
+{
+ if (!mTimeWidget)
+ return;
+ bool limit = true;
+ int repeatInterval;
+ int repeatCount = mRecurrenceEdit->subRepeatCount(&repeatInterval);
+ DateTime start = mSavedEvent->recurs() ? (mExpiredRecurrence ? DateTime() : mSavedEvent->mainDateTime())
+ : mTimeWidget->getDateTime(0, !repeatCount, !mExpiredRecurrence);
+ if (!start.isValid())
+ {
+ if (!mExpiredRecurrence)
+ return;
+ limit = false;
+ }
+ QDateTime now = QDateTime::currentDateTime();
+ if (limit)
+ {
+ if (repeatCount && start < now)
+ {
+ // Sub-repetition - find the time of the next one
+ repeatInterval *= 60;
+ int repetition = (start.secsTo(now) + repeatInterval - 1) / repeatInterval;
+ if (repetition > repeatCount)
+ {
+ mTimeWidget->getDateTime(); // output the appropriate error message
+ return;
+ }
+ start = start.addSecs(repetition * repeatInterval);
+ }
+ }
+
+ bool deferred = mDeferDateTime.isValid();
+ DeferAlarmDlg deferDlg(i18n("Defer Alarm"), (deferred ? mDeferDateTime : DateTime(now.addSecs(60))),
+ deferred, this, "EditDeferDlg");
+ if (limit)
+ {
+ // Don't allow deferral past the next recurrence
+ int reminder = mReminder->minutes();
+ if (reminder)
+ {
+ DateTime remindTime = start.addMins(-reminder);
+ if (QDateTime::currentDateTime() < remindTime)
+ start = remindTime;
+ }
+ deferDlg.setLimit(start.addSecs(-60));
+ }
+ if (deferDlg.exec() == QDialog::Accepted)
+ {
+ mDeferDateTime = deferDlg.getDateTime();
+ mDeferTimeLabel->setText(mDeferDateTime.isValid() ? mDeferDateTime.formatLocale() : QString::null);
+ }
+}
+
+/******************************************************************************
+* Called when the main page is shown.
+* Sets the focus widget to the first edit field.
+*/
+void EditAlarmDlg::slotShowMainPage()
+{
+ slotAlarmTypeChanged(-1);
+ if (!mMainPageShown)
+ {
+ if (mTemplateName)
+ mTemplateName->setFocus();
+ mMainPageShown = true;
+ }
+ if (mTimeWidget)
+ {
+ if (!mReadOnly && mRecurPageShown && mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN)
+ mTimeWidget->setDateTime(mRecurrenceEdit->endDateTime());
+ if (mReadOnly || mRecurrenceEdit->isTimedRepeatType())
+ mTimeWidget->setMinDateTime(); // don't set a minimum date/time
+ else
+ mTimeWidget->setMinDateTimeIsCurrent(); // set the minimum date/time to track the clock
+ }
+}
+
+/******************************************************************************
+* Called when the recurrence edit page is shown.
+* The recurrence defaults are set to correspond to the start date.
+* The first time, for a new alarm, the recurrence end date is set according to
+* the alarm start time.
+*/
+void EditAlarmDlg::slotShowRecurrenceEdit()
+{
+ mRecurPageIndex = mTabs->currentPageIndex();
+ if (!mReadOnly && !mTemplate)
+ {
+ QDateTime now = QDateTime::currentDateTime();
+ mAlarmDateTime = mTimeWidget->getDateTime(0, false, false);
+ bool expired = (mAlarmDateTime.dateTime() < now);
+ if (mRecurSetDefaultEndDate)
+ {
+ mRecurrenceEdit->setDefaultEndDate(expired ? now.date() : mAlarmDateTime.date());
+ mRecurSetDefaultEndDate = false;
+ }
+ mRecurrenceEdit->setStartDate(mAlarmDateTime.date(), now.date());
+ if (mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN)
+ mRecurrenceEdit->setEndDateTime(expired ? now : mAlarmDateTime);
+ }
+ mRecurPageShown = true;
+}
+
+/******************************************************************************
+* Called when the recurrence type selection changes.
+* Enables/disables date-only alarms as appropriate.
+* Enables/disables controls depending on at-login setting.
+*/
+void EditAlarmDlg::slotRecurTypeChange(int repeatType)
+{
+ bool atLogin = (mRecurrenceEdit->repeatType() == RecurrenceEdit::AT_LOGIN);
+ if (!mTemplate)
+ {
+ bool recurs = (mRecurrenceEdit->repeatType() != RecurrenceEdit::NO_RECUR);
+ if (mDeferGroup)
+ mDeferGroup->setEnabled(recurs);
+ mTimeWidget->enableAnyTime(!recurs || repeatType != RecurrenceEdit::SUBDAILY);
+ if (atLogin)
+ {
+ mAlarmDateTime = mTimeWidget->getDateTime(0, false, false);
+ mRecurrenceEdit->setEndDateTime(mAlarmDateTime.dateTime());
+ }
+ mReminder->enableOnceOnly(recurs && !atLogin);
+ }
+ mReminder->setEnabled(!atLogin);
+ mLateCancel->setEnabled(!atLogin);
+ if (mShowInKorganizer)
+ mShowInKorganizer->setEnabled(!atLogin);
+ slotRecurFrequencyChange();
+}
+
+/******************************************************************************
+* Called when the recurrence frequency selection changes, or the sub-
+* repetition interval changes.
+* Updates the recurrence frequency text.
+*/
+void EditAlarmDlg::slotRecurFrequencyChange()
+{
+ slotSetSubRepetition();
+ KAEvent event;
+ mRecurrenceEdit->updateEvent(event, false);
+ mTabs->setTabLabel(mTabs->page(mRecurPageIndex), recurText(event));
+}
+
+/******************************************************************************
+* Called when the Repetition within Recurrence button has been pressed to
+* display the sub-repetition dialog.
+* Alarm repetition has the following restrictions:
+* 1) Not allowed for a repeat-at-login alarm
+* 2) For a date-only alarm, the repeat interval must be a whole number of days.
+* 3) The overall repeat duration must be less than the recurrence interval.
+*/
+void EditAlarmDlg::slotSetSubRepetition()
+{
+ bool dateOnly = mTemplate ? mTemplateAnyTime->isOn() : mTimeWidget->anyTime();
+ mRecurrenceEdit->setSubRepetition(mReminder->minutes(), dateOnly);
+}
+
+/******************************************************************************
+* Validate and convert command alarm data.
+*/
+bool EditAlarmDlg::checkCommandData()
+{
+ if (mCommandRadio->isOn() && mCmdOutputGroup->selectedId() == LOG_TO_FILE)
+ {
+ // Validate the log file name
+ QString file = mCmdLogFileEdit->text();
+ QFileInfo info(file);
+ QDir::setCurrent(QDir::homeDirPath());
+ bool err = file.isEmpty() || info.isDir();
+ if (!err)
+ {
+ if (info.exists())
+ {
+ err = !info.isWritable();
+ }
+ else
+ {
+ QFileInfo dirinfo(info.dirPath(true)); // get absolute directory path
+ err = (!dirinfo.isDir() || !dirinfo.isWritable());
+ }
+ }
+ if (err)
+ {
+ mTabs->setCurrentPage(mMainPageIndex);
+ mCmdLogFileEdit->setFocus();
+ KMessageBox::sorry(this, i18n("Log file must be the name or path of a local file, with write permission."));
+ return false;
+ }
+ // Convert the log file to an absolute path
+ mCmdLogFileEdit->setText(info.absFilePath());
+ }
+ return true;
+}
+
+/******************************************************************************
+* Convert the email addresses to a list, and validate them. Convert the email
+* attachments to a list.
+*/
+bool EditAlarmDlg::checkEmailData()
+{
+ if (mEmailRadio->isOn())
+ {
+ QString addrs = mEmailToEdit->text();
+ if (addrs.isEmpty())
+ mEmailAddresses.clear();
+ else
+ {
+ QString bad = KAMail::convertAddresses(addrs, mEmailAddresses);
+ if (!bad.isEmpty())
+ {
+ mEmailToEdit->setFocus();
+ KMessageBox::error(this, i18n("Invalid email address:\n%1").arg(bad));
+ return false;
+ }
+ }
+ if (mEmailAddresses.isEmpty())
+ {
+ mEmailToEdit->setFocus();
+ KMessageBox::error(this, i18n("No email address specified"));
+ return false;
+ }
+
+ mEmailAttachments.clear();
+ for (int i = 0; i < mEmailAttachList->count(); ++i)
+ {
+ QString att = mEmailAttachList->text(i);
+ switch (KAMail::checkAttachment(att))
+ {
+ case 1:
+ mEmailAttachments.append(att);
+ break;
+ case 0:
+ break; // empty
+ case -1:
+ mEmailAttachList->setFocus();
+ KMessageBox::error(this, i18n("Invalid email attachment:\n%1").arg(att));
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/******************************************************************************
+* Called when one of the alarm action type radio buttons is clicked,
+* to display the appropriate set of controls for that action type.
+*/
+void EditAlarmDlg::slotAlarmTypeChanged(int)
+{
+ bool displayAlarm = false;
+ QWidget* focus = 0;
+ if (mMessageRadio->isOn())
+ {
+ mFileBox->hide();
+ mFilePadding->hide();
+ mTextMessageEdit->show();
+ mFontColourButton->show();
+ mBgColourBox->hide();
+ mSoundPicker->showSpeak(true);
+ mDisplayAlarmsFrame->show();
+ mCommandFrame->hide();
+ mEmailFrame->hide();
+ mReminder->show();
+ mConfirmAck->show();
+ setButtonWhatsThis(Try, i18n("Display the alarm message now"));
+ focus = mTextMessageEdit;
+ displayAlarm = true;
+ }
+ else if (mFileRadio->isOn())
+ {
+ mTextMessageEdit->hide();
+ mFileBox->show();
+ mFilePadding->show();
+ mFontColourButton->hide();
+ mBgColourBox->show();
+ mSoundPicker->showSpeak(false);
+ mDisplayAlarmsFrame->show();
+ mCommandFrame->hide();
+ mEmailFrame->hide();
+ mReminder->show();
+ mConfirmAck->show();
+ setButtonWhatsThis(Try, i18n("Display the file now"));
+ mFileMessageEdit->setNoSelect();
+ focus = mFileMessageEdit;
+ displayAlarm = true;
+ }
+ else if (mCommandRadio->isOn())
+ {
+ mDisplayAlarmsFrame->hide();
+ mCommandFrame->show();
+ mEmailFrame->hide();
+ mReminder->hide();
+ mConfirmAck->hide();
+ setButtonWhatsThis(Try, i18n("Execute the specified command now"));
+ mCmdCommandEdit->setNoSelect();
+ focus = mCmdCommandEdit;
+ }
+ else if (mEmailRadio->isOn())
+ {
+ mDisplayAlarmsFrame->hide();
+ mCommandFrame->hide();
+ mEmailFrame->show();
+ mReminder->hide();
+ mConfirmAck->hide();
+ setButtonWhatsThis(Try, i18n("Send the email to the specified addressees now"));
+ mEmailToEdit->setNoSelect();
+ focus = mEmailToEdit;
+ }
+ mLateCancel->showAutoClose(displayAlarm);
+ mLateCancel->setFixedSize(mLateCancel->sizeHint());
+ if (focus)
+ focus->setFocus();
+}
+
+/******************************************************************************
+* Called when one of the command type radio buttons is clicked,
+* to display the appropriate edit field.
+*/
+void EditAlarmDlg::slotCmdScriptToggled(bool on)
+{
+ if (on)
+ {
+ mCmdCommandEdit->hide();
+ mCmdPadding->hide();
+ mCmdScriptEdit->show();
+ mCmdScriptEdit->setFocus();
+ }
+ else
+ {
+ mCmdScriptEdit->hide();
+ mCmdCommandEdit->show();
+ mCmdPadding->show();
+ mCmdCommandEdit->setFocus();
+ }
+}
+
+/******************************************************************************
+* Called when one of the template time radio buttons is clicked,
+* to enable or disable the template time entry spin boxes.
+*/
+void EditAlarmDlg::slotTemplateTimeType(int)
+{
+ mTemplateTime->setEnabled(mTemplateUseTime->isOn());
+ mTemplateTimeAfter->setEnabled(mTemplateUseTimeAfter->isOn());
+}
+
+/******************************************************************************
+* Called when the "Any time" checkbox is toggled in the date/time widget.
+* Sets the advance reminder and late cancel units to days if any time is checked.
+*/
+void EditAlarmDlg::slotAnyTimeToggled(bool anyTime)
+{
+ if (mReminder->isReminder())
+ mReminder->setDateOnly(anyTime);
+ mLateCancel->setDateOnly(anyTime);
+}
+
+/******************************************************************************
+ * Get a selection from the Address Book.
+ */
+void EditAlarmDlg::openAddressBook()
+{
+ KABC::Addressee a = KABC::AddresseeDialog::getAddressee(this);
+ if (a.isEmpty())
+ return;
+ Person person(a.realName(), a.preferredEmail());
+ QString addrs = mEmailToEdit->text().stripWhiteSpace();
+ if (!addrs.isEmpty())
+ addrs += ", ";
+ addrs += person.fullName();
+ mEmailToEdit->setText(addrs);
+}
+
+/******************************************************************************
+ * Select a file to attach to the email.
+ */
+void EditAlarmDlg::slotAddAttachment()
+{
+ QString url = KAlarm::browseFile(i18n("Choose File to Attach"), mAttachDefaultDir, QString::null,
+ QString::null, KFile::ExistingOnly, this, "pickAttachFile");
+ if (!url.isEmpty())
+ {
+ mEmailAttachList->insertItem(url);
+ mEmailAttachList->setCurrentItem(mEmailAttachList->count() - 1); // select the new item
+ mEmailRemoveButton->setEnabled(true);
+ mEmailAttachList->setEnabled(true);
+ }
+}
+
+/******************************************************************************
+ * Remove the currently selected attachment from the email.
+ */
+void EditAlarmDlg::slotRemoveAttachment()
+{
+ int item = mEmailAttachList->currentItem();
+ mEmailAttachList->removeItem(item);
+ int count = mEmailAttachList->count();
+ if (item >= count)
+ mEmailAttachList->setCurrentItem(count - 1);
+ if (!count)
+ {
+ mEmailRemoveButton->setEnabled(false);
+ mEmailAttachList->setEnabled(false);
+ }
+}
+
+/******************************************************************************
+* Clean up the alarm text, and if it's a file, check whether it's valid.
+*/
+bool EditAlarmDlg::checkText(QString& result, bool showErrorMessage) const
+{
+ if (mMessageRadio->isOn())
+ result = mTextMessageEdit->text();
+ else if (mEmailRadio->isOn())
+ result = mEmailMessageEdit->text();
+ else if (mCommandRadio->isOn())
+ {
+ if (mCmdTypeScript->isChecked())
+ result = mCmdScriptEdit->text();
+ else
+ result = mCmdCommandEdit->text();
+ result = result.stripWhiteSpace();
+ }
+ else if (mFileRadio->isOn())
+ {
+ QString alarmtext = mFileMessageEdit->text().stripWhiteSpace();
+ // Convert any relative file path to absolute
+ // (using home directory as the default)
+ enum Err { NONE = 0, BLANK, NONEXISTENT, DIRECTORY, UNREADABLE, NOT_TEXT_IMAGE };
+ Err err = NONE;
+ KURL url;
+ int i = alarmtext.find(QString::fromLatin1("/"));
+ if (i > 0 && alarmtext[i - 1] == ':')
+ {
+ url = alarmtext;
+ url.cleanPath();
+ alarmtext = url.prettyURL();
+ KIO::UDSEntry uds;
+ if (!KIO::NetAccess::stat(url, uds, MainWindow::mainMainWindow()))
+ err = NONEXISTENT;
+ else
+ {
+ KFileItem fi(uds, url);
+ if (fi.isDir()) err = DIRECTORY;
+ else if (!fi.isReadable()) err = UNREADABLE;
+ }
+ }
+ else if (alarmtext.isEmpty())
+ err = BLANK; // blank file name
+ else
+ {
+ // It's a local file - convert to absolute path & check validity
+ QFileInfo info(alarmtext);
+ QDir::setCurrent(QDir::homeDirPath());
+ alarmtext = info.absFilePath();
+ url.setPath(alarmtext);
+ alarmtext = QString::fromLatin1("file:") + alarmtext;
+ if (!err)
+ {
+ if (info.isDir()) err = DIRECTORY;
+ else if (!info.exists()) err = NONEXISTENT;
+ else if (!info.isReadable()) err = UNREADABLE;
+ }
+ }
+ if (!err)
+ {
+ switch (KAlarm::fileType(KFileItem(KFileItem::Unknown, KFileItem::Unknown, url).mimetype()))
+ {
+ case KAlarm::TextFormatted:
+ case KAlarm::TextPlain:
+ case KAlarm::TextApplication:
+ case KAlarm::Image:
+ break;
+ default:
+ err = NOT_TEXT_IMAGE;
+ break;
+ }
+ }
+ if (err && showErrorMessage)
+ {
+ mFileMessageEdit->setFocus();
+ QString errmsg;
+ switch (err)
+ {
+ case BLANK:
+ KMessageBox::sorry(const_cast<EditAlarmDlg*>(this), i18n("Please select a file to display"));
+ return false;
+ case NONEXISTENT: errmsg = i18n("%1\nnot found"); break;
+ case DIRECTORY: errmsg = i18n("%1\nis a folder"); break;
+ case UNREADABLE: errmsg = i18n("%1\nis not readable"); break;
+ case NOT_TEXT_IMAGE: errmsg = i18n("%1\nappears not to be a text or image file"); break;
+ case NONE:
+ default:
+ break;
+ }
+ if (KMessageBox::warningContinueCancel(const_cast<EditAlarmDlg*>(this), errmsg.arg(alarmtext))
+ == KMessageBox::Cancel)
+ return false;
+ }
+ result = alarmtext;
+ }
+ return true;
+}
+
+
+/*=============================================================================
+= Class TextEdit
+= A text edit field with a minimum height of 3 text lines.
+= Provides KDE 2 compatibility.
+=============================================================================*/
+TextEdit::TextEdit(QWidget* parent, const char* name)
+ : KTextEdit(parent, name)
+{
+ QSize tsize = sizeHint();
+ tsize.setHeight(fontMetrics().lineSpacing()*13/4 + 2*frameWidth());
+ setMinimumSize(tsize);
+}
+
+void TextEdit::dragEnterEvent(QDragEnterEvent* e)
+{
+ if (KCal::ICalDrag::canDecode(e))
+ e->accept(false); // don't accept "text/calendar" objects
+ KTextEdit::dragEnterEvent(e);
+}