[pim/kalarm] /: Add option to give alarms a name

David Jarvie null at kde.org
Tue Oct 27 23:53:51 GMT 2020


Git commit ba9b2f7158c21df9ad2e4190a4f32a1393983f44 by David Jarvie.
Committed on 27/10/2020 at 23:52.
Pushed by djarvie into branch 'master'.

Add option to give alarms a name

M  +2    -1    Changelog
M  +-    --    doc/editwindow-simple.png
M  +-    --    doc/editwindow.png
M  +111  -27   doc/index.docbook
M  +-    --    doc/mainwindow-calendars.png
M  +-    --    doc/mainwindow.png
M  +62   -10   src/alarmlistview.cpp
M  +5    -0    src/alarmlistview.h
M  +16   -0    src/birthdaydlg.cpp
M  +41   -38   src/birthdaydlg.h
M  +14   -2    src/commandoptions.cpp
M  +3    -2    src/commandoptions.h
M  +9    -0    src/data/kalarmconfig.kcfg
M  +146  -40   src/dbushandler.cpp
M  +129  -75   src/dbushandler.h
M  +42   -32   src/editdlg.cpp
M  +165  -164  src/editdlg.h
M  +8    -8    src/editdlgtypes.cpp
M  +4    -4    src/editdlgtypes.h
M  +1    -0    src/eventlistview.cpp
M  +11   -8    src/kalarmapp.cpp
M  +4    -3    src/kalarmapp.h
M  +1    -1    src/mainwindow.cpp
M  +15   -1    src/prefdlg.cpp
M  +1    -0    src/prefdlg_p.h
M  +27   -0    src/resources/eventmodel.cpp
M  +7    -2    src/resources/eventmodel.h
M  +15   -9    src/resources/resourcedatamodelbase.cpp
M  +1    -1    src/resources/resourcedatamodelbase.h
M  +1    -1    src/resourcescalendar.cpp
M  +1    -1    src/templatemenuaction.cpp
M  +1    -1    src/undo.cpp

https://invent.kde.org/pim/kalarm/commit/ba9b2f7158c21df9ad2e4190a4f32a1393983f44

diff --git a/Changelog b/Changelog
index ae4aa4f6..9f9d5914 100644
--- a/Changelog
+++ b/Changelog
@@ -1,7 +1,8 @@
 KAlarm Change Log
 
-=== Version 3.1.0 (KDE Applications 20.12) --- 25 October 2020 ===
+=== Version 3.1.0 (KDE Applications 20.12) --- 28 October 2020 ===
 + Add option to show alarm message as a notification instead of in a window [KDE Bug 345922]
++ Add option to give alarms a name.
 + Don't execute display alarms while desktop notifications are inhibited.
 + Cancel any screen saver when an alarm is displayed.
 
diff --git a/doc/editwindow-simple.png b/doc/editwindow-simple.png
index b96b12a6..cd9217d2 100644
Binary files a/doc/editwindow-simple.png and b/doc/editwindow-simple.png differ
diff --git a/doc/editwindow.png b/doc/editwindow.png
index 256fc982..b3df19c3 100644
Binary files a/doc/editwindow.png and b/doc/editwindow.png differ
diff --git a/doc/index.docbook b/doc/index.docbook
index 663e673b..459e9405 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -39,7 +39,7 @@
 
 <!-- Don't change format of date and version of the documentation -->
 
-<date>2020-10-22</date>
+<date>2020-10-28</date>
 <releaseinfo>3.1.0 (Applications 20.12)</releaseinfo>
 
 <abstract>
@@ -66,10 +66,10 @@
 messages, the playing of sound files, the execution of commands and
 the sending of emails.</para>
 
-<para>In its default graphical mode, &kalarm; displays the list of
-pending alarms, showing their times and details.  You can create new
-alarms, or you can select existing alarms for modification or
-deletion. You can also optionally view expired alarms.</para>
+<para>&kalarm; displays the list of pending alarms, showing their
+times and details.  You can create new alarms, or you can select
+existing alarms for modification or deletion. You can also optionally
+view expired alarms.</para>
 
 <para>When configuring an alarm, you can choose whether it should
 repeat, and whether the alarm should be canceled if it cannot be
@@ -186,7 +186,7 @@ background.</para>
 <title>Alarm List</title>
 
 <para>The main &kalarm; window displays the current list of pending
-alarms, showing their times, repetition intervals, colors, and
+alarms, showing their times, repetition intervals, colors, names, and
 message texts, names of files to play or display, commands to execute
 or email subjects. (For a recurring alarm, the time shown is its next
 scheduled trigger time. For an alarm with a reminder, the time shown
@@ -194,6 +194,11 @@ is the time of the alarm proper, not the reminder time.) An icon at
 the left of each alarm text/file/command/email subject indicates the
 type of alarm.</para>
 
+<para>Note that the <guilabel>Name</guilabel> column only exists if
+the use of alarm names is enabled in the
+<link linkend="preferences-general">General</link> tab of the
+Configuration dialog.</para>
+
 <screenshot>
 <screeninfo>Screenshot of the &kalarm; main window</screeninfo>
 <mediaobject>
@@ -222,17 +227,19 @@ above.</para>
 <title>Changing the Alarm List Appearance</title>
 
 <para>The alarms may be ordered by date/time, repeat interval, color,
-type or text by clicking on the titlebar for the appropriate column.
-To reverse the sort order, click the column titlebar again.</para>
+type, name or text by clicking on the titlebar for the appropriate
+column. To reverse the sort order, click the column titlebar
+again.</para>
 
 <para>You can optionally show the remaining time until each alarm is
 due, together with, or instead of, the alarm's scheduled time.</para>
 
 <para>You can select which columns to display or hide by
 <mousebutton>Right</mousebutton> clicking on the column headings and
-using the context menu to set the columns to show. But note that the
-<guilabel>Message, File or Command</guilabel> column, and at least one
-of the <guilabel>Time</guilabel> or <guilabel>Time To</guilabel>
+using the context menu to set the columns to show. But note that at
+least one of the <guilabel>Name</guilabel> or
+<guilabel>Message, File or Command</guilabel> columns, and at least
+one of the <guilabel>Time</guilabel> or <guilabel>Time To</guilabel>
 columns, are always shown.</para>
 
 <para>If you use multiple alarm calendars, you can color code alarms
@@ -1173,6 +1180,21 @@ the Alarm Edit dialog using the
 </mediaobject>
 </screenshot>
 
+<sect2>
+<title>Alarm Name</title>
+
+<para>You can give a name to the alarm in the
+<guilabel>Alarm name</guilabel> field. This is a convenience to help
+you identify the alarm more easily. You do not have to enter a name,
+and it need not be unique.</para>
+
+<para>Note that this field is only displayed if the the use of alarm
+names is enabled in the
+<link linkend="preferences-general">General</link> tab of the
+Configuration dialog.</para>
+
+</sect2>
+
 <sect2>
 <title>Alarm Action</title>
 
@@ -2549,6 +2571,14 @@ option is automatically re-enabled by default whenever you change run
 mode.</para>
 </listitem>
 
+<listitem><para><guilabel>Use alarm names</guilabel>: Specify
+whether each alarm can be given a name to help you to identify it.
+This determines whether the <guilabel>Name</guilabel> column will be
+shown in the <link linkend="alarm-list">alarm list</link>, and
+whether the <guilabel>Alarm name</guilabel> field will appear in the
+<link linkend="alarm-edit-dlg">Alarm Edit dialog</link>.</para>
+</listitem>
+
 <listitem><para><guilabel>Confirm alarm deletions</guilabel>: Specify
 whether you should be prompted for confirmation each time you delete
 an alarm.</para>
@@ -3217,7 +3247,11 @@ time.</para>
   with this option.</entry>
 </row>
 <row>
-  <entry><option>-n</option>, <option>--notify</option></entry>
+  <entry><option>-n</option>, <option>--name</option></entry>
+  <entry>Specify a name to help you to identify the alarm.</entry>
+</row>
+<row>
+  <entry><option>-N</option>, <option>--notify</option></entry>
   <entry>Display the alarm as a notification, not in a window.
   <option>--color</option>, <option>--colorfg</option>,
   <option>--play</option>, <option>--ack-confirm</option> and
@@ -3559,7 +3593,8 @@ unchanged.</para>
 </refnamediv>
 <refsynopsisdiv>
 <synopsis>
-bool scheduleMessage(const QString& <replaceable>message</replaceable>,
+bool scheduleMessage(const QString& <replaceable>name</replaceable>,
+                     const QString& <replaceable>message</replaceable>,
                      const QString& <replaceable>startDateTime</replaceable>,
                      int <replaceable>lateCancel</replaceable>,
                      unsigned <replaceable>flags</replaceable>, 
@@ -3573,7 +3608,8 @@ bool scheduleMessage(const QString& <replaceable>message</replaceable>,
                      int <replaceable>subRepeatCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleMessage(const QString& <replaceable>message</replaceable>, 
+bool scheduleMessage(const QString& <replaceable>name</replaceable>,
+                     const QString& <replaceable>message</replaceable>,
                      const QString& <replaceable>startDateTime</replaceable>, 
                      int <replaceable>lateCancel</replaceable>,
                      unsigned <replaceable>flags</replaceable>, 
@@ -3587,7 +3623,8 @@ bool scheduleMessage(const QString& <replaceable>message</replaceable>,
                      int <replaceable>recurCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleMessage(const QString& <replaceable>message</replaceable>, 
+bool scheduleMessage(const QString& <replaceable>name</replaceable>,
+                     const QString& <replaceable>message</replaceable>,
                      const QString& <replaceable>startDateTime</replaceable>, 
                      int <replaceable>lateCancel</replaceable>, 
                      unsigned <replaceable>flags</replaceable>, 
@@ -3604,6 +3641,13 @@ bool scheduleMessage(const QString& <replaceable>message</replaceable>,
 <refsect2>
 <title>Parameters</title>
 <variablelist>
+<varlistentry>
+<term><parameter>name</parameter></term>
+<listitem>
+<para>Specifies an optional name for the alarm.</para>
+</listitem>
+</varlistentry>
+
 <varlistentry>
 <term><parameter>message</parameter></term>
 <listitem>
@@ -3819,7 +3863,8 @@ text or image file.</refpurpose>
 </refnamediv>
 <refsynopsisdiv>
 <synopsis>
-bool scheduleFile(const QString& <replaceable>URL</replaceable>,
+bool scheduleFile(const QString& <replaceable>name</replaceable>,
+                  const QString& <replaceable>URL</replaceable>,
                   const QString& <replaceable>startDateTime</replaceable>,
                   int <replaceable>lateCancel</replaceable>,
                   unsigned <replaceable>flags</replaceable>,
@@ -3831,7 +3876,8 @@ bool scheduleFile(const QString& <replaceable>URL</replaceable>,
                   int <replaceable>subRepeatCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleFile(const QString& <replaceable>URL</replaceable>,
+bool scheduleFile(const QString& <replaceable>name</replaceable>,
+                  const QString& <replaceable>URL</replaceable>,
                   const QString& <replaceable>startDateTime</replaceable>,
                   int <replaceable>lateCancel</replaceable>,
                   unsigned <replaceable>flags</replaceable>,
@@ -3843,7 +3889,8 @@ bool scheduleFile(const QString& <replaceable>URL</replaceable>,
                   int <replaceable>recurCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleFile(const QString& <replaceable>URL</replaceable>,
+bool scheduleFile(const QString& <replaceable>name</replaceable>,
+                  const QString& <replaceable>URL</replaceable>,
                   const QString& <replaceable>startDateTime</replaceable>,
                   int <replaceable>lateCancel</replaceable>,
                   unsigned <replaceable>flags</replaceable>,
@@ -3858,6 +3905,13 @@ bool scheduleFile(const QString& <replaceable>URL</replaceable>,
 <refsect2>
 <title>Parameters</title>
 <variablelist>
+<varlistentry>
+<term><parameter>name</parameter></term>
+<listitem>
+<para>Specifies an optional name for the alarm.</para>
+</listitem>
+</varlistentry>
+
 <varlistentry>
 <term><parameter>URL</parameter></term>
 <listitem>
@@ -4043,7 +4097,8 @@ command.</refpurpose>
 </refnamediv>
 <refsynopsisdiv>
 <synopsis>
-bool scheduleCommand(const QString& <replaceable>commandLine</replaceable>,
+bool scheduleCommand(const QString& <replaceable>name</replaceable>,
+                     const QString& <replaceable>commandLine</replaceable>,
                      const QString& <replaceable>startDateTime</replaceable>,
                      int <replaceable>lateCancel</replaceable>,
                      unsigned <replaceable>flags</replaceable>,
@@ -4052,7 +4107,8 @@ bool scheduleCommand(const QString& <replaceable>commandLine</replaceable>,
                      int <replaceable>subRepeatCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleCommand(const QString& <replaceable>commandLine</replaceable>,
+bool scheduleCommand(const QString& <replaceable>name</replaceable>,
+                     const QString& <replaceable>commandLine</replaceable>,
                      const QString& <replaceable>startDateTime</replaceable>,
                      int <replaceable>lateCancel</replaceable>,
                      unsigned <replaceable>flags</replaceable>,
@@ -4061,7 +4117,8 @@ bool scheduleCommand(const QString& <replaceable>commandLine</replaceable>,
                      int <replaceable>recurCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleCommand(const QString& <replaceable>commandLine</replaceable>,
+bool scheduleCommand(const QString& <replaceable>name</replaceable>,
+                     const QString& <replaceable>commandLine</replaceable>,
                      const QString& <replaceable>startDateTime</replaceable>,
                      int <replaceable>lateCancel</replaceable>,
                      unsigned <replaceable>flags</replaceable>,
@@ -4073,6 +4130,13 @@ bool scheduleCommand(const QString& <replaceable>commandLine</replaceable>,
 <refsect2>
 <title>Parameters</title>
 <variablelist>
+<varlistentry>
+<term><parameter>name</parameter></term>
+<listitem>
+<para>Specifies an optional name for the alarm.</para>
+</listitem>
+</varlistentry>
+
 <varlistentry>
 <term><parameter>commandLine</parameter></term>
 <listitem>
@@ -4225,7 +4289,8 @@ parameters, its usage is identical to
 </refnamediv>
 <refsynopsisdiv>
 <synopsis>
-bool scheduleEmail(const QString& <replaceable>fromID</replaceable>,
+bool scheduleEmail(const QString& <replaceable>name</replaceable>,
+                   const QString& <replaceable>fromID</replaceable>,
                    const QString& <replaceable>addresses</replaceable>,
                    const QString& <replaceable>subject</replaceable>,
                    const QString& <replaceable>message</replaceable>,
@@ -4238,7 +4303,8 @@ bool scheduleEmail(const QString& <replaceable>fromID</replaceable>,
                    int <replaceable>subRepeatCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleEmail(const QString& <replaceable>fromID</replaceable>,
+bool scheduleEmail(const QString& <replaceable>name</replaceable>,
+                   const QString& <replaceable>fromID</replaceable>,
                    const QString& <replaceable>addresses</replaceable>,
                    const QString& <replaceable>subject</replaceable>,
                    const QString& <replaceable>message</replaceable>,
@@ -4251,7 +4317,8 @@ bool scheduleEmail(const QString& <replaceable>fromID</replaceable>,
                    int <replaceable>recurCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleEmail(const QString& <replaceable>fromID</replaceable>,
+bool scheduleEmail(const QString& <replaceable>name</replaceable>,
+                   const QString& <replaceable>fromID</replaceable>,
                    const QString& <replaceable>addresses</replaceable>,
                    const QString& <replaceable>subject</replaceable>,
                    const QString& <replaceable>message</replaceable>,
@@ -4267,6 +4334,13 @@ bool scheduleEmail(const QString& <replaceable>fromID</replaceable>,
 <refsect2>
 <title>Parameters</title>
 <variablelist>
+<varlistentry>
+<term><parameter>name</parameter></term>
+<listitem>
+<para>Specifies an optional name for the alarm.</para>
+</listitem>
+</varlistentry>
+
 <varlistentry>
 <term><parameter>fromID</parameter></term>
 <listitem>
@@ -4450,7 +4524,8 @@ command.</refpurpose>
 </refnamediv>
 <refsynopsisdiv>
 <synopsis>
-bool scheduleAudio(const QString& <replaceable>audioURL</replaceable>,
+bool scheduleAudio(const QString& <replaceable>name</replaceable>,
+                   const QString& <replaceable>audioURL</replaceable>,
                    int <replaceable>volumePercent</replaceable>,
                    const QString& <replaceable>startDateTime</replaceable>,
                    int <replaceable>lateCancel</replaceable>,
@@ -4460,7 +4535,8 @@ bool scheduleAudio(const QString& <replaceable>audioURL</replaceable>,
                    int <replaceable>subRepeatCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleAudio(const QString& <replaceable>audioURL</replaceable>,
+bool scheduleAudio(const QString& <replaceable>name</replaceable>,
+                   const QString& <replaceable>audioURL</replaceable>,
                    int <replaceable>volumePercent</replaceable>,
                    const QString& <replaceable>startDateTime</replaceable>,
                    int <replaceable>lateCancel</replaceable>,
@@ -4470,7 +4546,8 @@ bool scheduleAudio(const QString& <replaceable>audioURL</replaceable>,
                    int <replaceable>recurCount</replaceable>)
 </synopsis>
 <synopsis>
-bool scheduleAudio(const QString& <replaceable>audioURL</replaceable>,
+bool scheduleAudio(const QString& <replaceable>name</replaceable>,
+                   const QString& <replaceable>audioURL</replaceable>,
                    int <replaceable>volumePercent</replaceable>,
                    const QString& <replaceable>startDateTime</replaceable>,
                    int <replaceable>lateCancel</replaceable>,
@@ -4483,6 +4560,13 @@ bool scheduleAudio(const QString& <replaceable>audioURL</replaceable>,
 <refsect2>
 <title>Parameters</title>
 <variablelist>
+<varlistentry>
+<term><parameter>name</parameter></term>
+<listitem>
+<para>Specifies an optional name for the alarm.</para>
+</listitem>
+</varlistentry>
+
 <varlistentry>
 <term><parameter>audioURL</parameter></term>
 <listitem>
diff --git a/doc/mainwindow-calendars.png b/doc/mainwindow-calendars.png
index 73970309..641c66c1 100644
Binary files a/doc/mainwindow-calendars.png and b/doc/mainwindow-calendars.png differ
diff --git a/doc/mainwindow.png b/doc/mainwindow.png
index 6e41fcd2..f89a37c7 100644
Binary files a/doc/mainwindow.png and b/doc/mainwindow.png differ
diff --git a/src/alarmlistview.cpp b/src/alarmlistview.cpp
index b0fa06b9..48fc4f4b 100644
--- a/src/alarmlistview.cpp
+++ b/src/alarmlistview.cpp
@@ -28,37 +28,52 @@ AlarmListView::AlarmListView(const QByteArray& configGroup, QWidget* parent)
     connect(header(), &QHeaderView::sectionMoved, this, &AlarmListView::saveColumnsState);
     header()->setContextMenuPolicy(Qt::CustomContextMenu);
     connect(header(), &QWidget::customContextMenuRequested, this, &AlarmListView::headerContextMenuRequested);
+    Preferences::connect(&Preferences::useAlarmNameChanged, this, &AlarmListView::useAlarmNameChanged);
 }
 
 /******************************************************************************
 * Return which of the optional columns are currently shown.
 * Note that the column order must be the same as in setColumnsVisible().
+* Reply = array of 5 columns if not using alarm names;
+*       = array of 6 columns if not using alarm names.
 */
 QList<bool> AlarmListView::columnsVisible() const
 {
     if (!model())
         return {};
-    return { !header()->isSectionHidden(AlarmListModel::TimeColumn),
-             !header()->isSectionHidden(AlarmListModel::TimeToColumn),
-             !header()->isSectionHidden(AlarmListModel::RepeatColumn),
-             !header()->isSectionHidden(AlarmListModel::ColourColumn),
-             !header()->isSectionHidden(AlarmListModel::TypeColumn) };
+    QList<bool> vis{ !header()->isSectionHidden(AlarmListModel::TimeColumn),
+                     !header()->isSectionHidden(AlarmListModel::TimeToColumn),
+                     !header()->isSectionHidden(AlarmListModel::RepeatColumn),
+                     !header()->isSectionHidden(AlarmListModel::ColourColumn),
+                     !header()->isSectionHidden(AlarmListModel::TypeColumn) };
+    if (Preferences::useAlarmName())
+        vis += !header()->isSectionHidden(AlarmListModel::TextColumn);
+    return vis;
 }
 
 /******************************************************************************
 * Set which of the optional columns are to be shown.
+* 'show' = array of 5 columns if not using alarm names;
+*        = array of 6 columns if not using alarm names.
 * Note that the column order must be the same as in columnsVisible().
 */
 void AlarmListView::setColumnsVisible(const QList<bool>& show)
 {
     if (!model())
         return;
-    const QList<bool> vis = (show.size() < 5) ? QList<bool>{true, false, true, true, true} : show;
+    const bool useName = Preferences::useAlarmName();
+    QList<bool> vis{ true, false, true, true, true, !useName };
+    const int colCount = useName ? 6 : 5;
+    for (int i = 0;  i < colCount;  ++i)
+        vis[i] = show[i];
     header()->setSectionHidden(AlarmListModel::TimeColumn,   !vis[0]);
     header()->setSectionHidden(AlarmListModel::TimeToColumn, !vis[1]);
     header()->setSectionHidden(AlarmListModel::RepeatColumn, !vis[2]);
     header()->setSectionHidden(AlarmListModel::ColourColumn, !vis[3]);
     header()->setSectionHidden(AlarmListModel::TypeColumn,   !vis[4]);
+    header()->setSectionHidden(AlarmListModel::NameColumn,   !useName);
+    header()->setSectionHidden(AlarmListModel::TextColumn,   !vis[5]);
+    setReplaceBlankName();
     setSortingEnabled(false);  // sortByColumn() won't work if sorting is already enabled!
     sortByColumn(vis[0] ? AlarmListModel::TimeColumn : AlarmListModel::TimeToColumn, Qt::AscendingOrder);
 }
@@ -71,13 +86,23 @@ void AlarmListView::initSections()
     KConfigGroup config(KSharedConfig::openConfig(), mConfigGroup.constData());
     const QByteArray settings = config.readEntry("ListHead", QByteArray());
     if (!settings.isEmpty())
+    {
         header()->restoreState(settings);
+        const bool useName = Preferences::useAlarmName();
+        header()->setSectionHidden(AlarmListModel::NameColumn, !useName);
+        if (!useName)
+        {
+            header()->setSectionHidden(AlarmListModel::TextColumn, false);
+            setReplaceBlankName();
+        }
+    }
     header()->setSectionsMovable(true);
     header()->setSectionResizeMode(AlarmListModel::TimeColumn, QHeaderView::ResizeToContents);
     header()->setSectionResizeMode(AlarmListModel::TimeToColumn, QHeaderView::ResizeToContents);
     header()->setSectionResizeMode(AlarmListModel::RepeatColumn, QHeaderView::ResizeToContents);
     header()->setSectionResizeMode(AlarmListModel::ColourColumn, QHeaderView::Fixed);
     header()->setSectionResizeMode(AlarmListModel::TypeColumn, QHeaderView::Fixed);
+    header()->setSectionResizeMode(AlarmListModel::NameColumn, QHeaderView::ResizeToContents);
     header()->setSectionResizeMode(AlarmListModel::TextColumn, QHeaderView::Stretch);
     header()->setStretchLastSection(true);   // necessary to ensure ResizeToContents columns do resize to contents!
     const int minWidth = viewOptions().fontMetrics.lineSpacing() * 3 / 4;
@@ -105,10 +130,12 @@ void AlarmListView::saveColumnsState()
 void AlarmListView::headerContextMenuRequested(const QPoint& pt)
 {
     QAbstractItemModel* almodel = model();
-    int count = header()->count();
     QMenu menu;
-    for (int col = 0;  col < count;  ++col)
+    const bool useName = Preferences::useAlarmName();
+    for (int col = 0, count = header()->count();  col < count;  ++col)
     {
+        if (col == AlarmListModel::NameColumn  &&  !useName)
+            continue;
         const QString title = almodel->headerData(col, Qt::Horizontal, ResourceDataModelBase::ColumnTitleRole).toString();
         if (!title.isEmpty())
         {
@@ -116,8 +143,10 @@ void AlarmListView::headerContextMenuRequested(const QPoint& pt)
             act->setData(col);
             act->setCheckable(true);
             act->setChecked(!header()->isSectionHidden(col));
-            if (col == AlarmListModel::TextColumn)
-                act->setEnabled(false);    // don't allow text column to be hidden
+            if (col == AlarmListModel::NameColumn)
+                act->setEnabled(false);    // don't allow name column to be hidden if name is used
+            else if (col == AlarmListModel::TextColumn  &&  !useName)
+                act->setEnabled(false);    // don't allow text column to be hidden if name not used
             else
                 QObject::connect(act, &QAction::triggered,
                                  this, [this, &menu, act] { showHideColumn(menu, act); });
@@ -127,6 +156,16 @@ void AlarmListView::headerContextMenuRequested(const QPoint& pt)
     menu.exec(header()->mapToGlobal(pt));
 }
 
+/******************************************************************************
+* Called when the 'use alarm name' setting has changed.
+*/
+void AlarmListView::useAlarmNameChanged(bool use)
+{
+    header()->setSectionHidden(AlarmListModel::NameColumn, !use);
+    header()->setSectionHidden(AlarmListModel::TextColumn, use);
+    setReplaceBlankName();
+}
+
 /******************************************************************************
 * Show or hide a column according to the header context menu.
 */
@@ -139,10 +178,23 @@ void AlarmListView::showHideColumn(QMenu& menu, QAction* act)
     header()->setSectionHidden(col, !show);
     if (col == AlarmListModel::TimeColumn  ||  col == AlarmListModel::TimeToColumn)
         enableTimeColumns(&menu);
+    if (col == AlarmListModel::TextColumn)
+        setReplaceBlankName();
     saveColumnsState();
     Q_EMIT columnsVisibleChanged();
 }
 
+/******************************************************************************
+* Set whether to replace a blank alarm name with the alarm text.
+*/
+void AlarmListView::setReplaceBlankName()
+{
+    bool textHidden = header()->isSectionHidden(AlarmListModel::TextColumn);
+    AlarmListModel* almodel = qobject_cast<AlarmListModel*>(model());
+    if (almodel)
+        almodel->setReplaceBlankName(textHidden);
+}
+
 /******************************************************************************
 * Disable Time or Time To in the context menu if the other one is not
 * selected to be displayed, to ensure that at least one is always shown.
diff --git a/src/alarmlistview.h b/src/alarmlistview.h
index da59f28a..382ad5f2 100644
--- a/src/alarmlistview.h
+++ b/src/alarmlistview.h
@@ -19,7 +19,10 @@ class AlarmListView : public EventListView
     Q_OBJECT
 public:
     explicit AlarmListView(const QByteArray& configGroup, QWidget* parent = nullptr);
+
+    /** Return which of the optional columns are currently shown. */
     QList<bool> columnsVisible() const;
+
     void        setColumnsVisible(const QList<bool>& show);
 
 Q_SIGNALS:
@@ -31,9 +34,11 @@ protected Q_SLOTS:
 private Q_SLOTS:
     void        saveColumnsState();
     void        headerContextMenuRequested(const QPoint&);
+    void        useAlarmNameChanged(bool);
 
 private:
     void        showHideColumn(QMenu&, QAction*);
+    void        setReplaceBlankName();
     void        enableTimeColumns(QMenu*);
 
     QByteArray  mConfigGroup;
diff --git a/src/birthdaydlg.cpp b/src/birthdaydlg.cpp
index 4a0f7a8c..6a8032a0 100644
--- a/src/birthdaydlg.cpp
+++ b/src/birthdaydlg.cpp
@@ -53,6 +53,21 @@ BirthdayDlg::BirthdayDlg(QWidget* parent)
 
     QVBoxLayout* topLayout = new QVBoxLayout(this);
 
+    if (Preferences::useAlarmName())
+    {
+        QHBoxLayout* hlayout = new QHBoxLayout();
+        hlayout->setContentsMargins(0, 0, 0, 0);
+        topLayout->addLayout(hlayout);
+        QLabel* label = new QLabel(i18nc("@label:textbox", "Alarm name:"), this);
+        label->setFixedSize(label->sizeHint());
+        hlayout->addWidget(label);
+        mName = new KLineEdit(this);
+        mName->setMinimumSize(mName->sizeHint());
+        label->setBuddy(mName);
+        mName->setWhatsThis(i18nc("@info:whatsthis", "Enter a name to help you identify this alarm. This is optional and need not be unique."));
+        hlayout->addWidget(mName);
+    }
+
     // Prefix and suffix to the name in the alarm text
     // Get default prefix and suffix texts from config file
     KConfigGroup config(KSharedConfig::openConfig(), "General");
@@ -264,6 +279,7 @@ QVector<KAEvent> BirthdayDlg::events() const
         if (date <= today)
             date.setDate(thisYear + 1, date.month(), date.day());
         KAEvent event(KADateTime(date, KADateTime::LocalZone),
+                      (mName ? mName->text() : QString()),
                       mPrefix->text() + name + mSuffix->text(),
                       mFontColourButton->bgColour(), mFontColourButton->fgColour(),
                       mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(),
diff --git a/src/birthdaydlg.h b/src/birthdaydlg.h
index 78eddc14..85adc1b3 100644
--- a/src/birthdaydlg.h
+++ b/src/birthdaydlg.h
@@ -1,7 +1,7 @@
 /*
  *  birthdaydlg.h  -  dialog to pick birthdays from address book
  *  Program:  kalarm
- *  SPDX-FileCopyrightText: 2002-2005, 2007-2011 David Jarvie <djarvie at kde.org>
+ *  SPDX-FileCopyrightText: 2002-2020 David Jarvie <djarvie at kde.org>
  *
  *  SPDX-License-Identifier: GPL-2.0-or-later
  */
@@ -10,9 +10,10 @@
 
 #include <KAlarmCal/KAEvent>
 
+#include <KLineEdit>
+
 #include <QDialog>
 #include <QVector>
-#include <QLineEdit>
 
 class QFocusEvent;
 class QTreeView;
@@ -31,51 +32,53 @@ using namespace KAlarmCal;
 
 class BirthdayDlg : public QDialog
 {
-        Q_OBJECT
-    public:
-        explicit BirthdayDlg(QWidget* parent = nullptr);
-        QVector<KAEvent> events() const;
+    Q_OBJECT
+public:
+    explicit BirthdayDlg(QWidget* parent = nullptr);
+    QVector<KAEvent> events() const;
 
-    protected Q_SLOTS:
-        virtual void   slotOk();
+protected Q_SLOTS:
+    virtual void   slotOk();
 
-    private Q_SLOTS:
-        void           slotSelectionChanged();
-        void           slotTextLostFocus();
-        void           resizeViewColumns();
-        void           setColours(const QColor& fg, const QColor& bg);
+private Q_SLOTS:
+    void           slotSelectionChanged();
+    void           slotTextLostFocus();
+    void           resizeViewColumns();
+    void           setColours(const QColor& fg, const QColor& bg);
 
-    private:
-        BirthdaySortModel*    mBirthdaySortModel;
-        QTreeView*            mListView;
-        BLineEdit*            mPrefix;
-        BLineEdit*            mSuffix;
-        Reminder*             mReminder;
-        SoundPicker*          mSoundPicker;
-        FontColourButton*     mFontColourButton;
-        CheckBox*             mConfirmAck;
-        LateCancelSelector*   mLateCancel;
-        SpecialActionsButton* mSpecialActionsButton {nullptr};
-        RepetitionButton*     mSubRepetition;
-        QDialogButtonBox*     mButtonBox;
-        QString               mPrefixText;   // last entered value of prefix text
-        QString               mSuffixText;   // last entered value of suffix text
-        KAEvent::Flags        mFlags;        // event flag bits
+private:
+    BirthdaySortModel*    mBirthdaySortModel;
+    QTreeView*            mListView;
+    KLineEdit*            mName {nullptr};
+    BLineEdit*            mPrefix;
+    BLineEdit*            mSuffix;
+    Reminder*             mReminder;
+    SoundPicker*          mSoundPicker;
+    FontColourButton*     mFontColourButton;
+    CheckBox*             mConfirmAck;
+    LateCancelSelector*   mLateCancel;
+    SpecialActionsButton* mSpecialActionsButton {nullptr};
+    RepetitionButton*     mSubRepetition;
+    QDialogButtonBox*     mButtonBox;
+    QString               mPrefixText;   // last entered value of prefix text
+    QString               mSuffixText;   // last entered value of suffix text
+    KAEvent::Flags        mFlags;        // event flag bits
 };
 
 
-class BLineEdit : public QLineEdit
+/** Line edit with a focusLost() signal. */
+class BLineEdit : public KLineEdit
 {
-        Q_OBJECT
-    public:
-        explicit BLineEdit(QWidget* parent = nullptr)                       : QLineEdit(parent) {}
-        explicit BLineEdit(const QString& text, QWidget* parent = nullptr)  : QLineEdit(text, parent) {}
+    Q_OBJECT
+public:
+    explicit BLineEdit(QWidget* parent = nullptr)                       : KLineEdit(parent) {}
+    explicit BLineEdit(const QString& text, QWidget* parent = nullptr)  : KLineEdit(text, parent) {}
 
-    Q_SIGNALS:
-        void         focusLost();
+Q_SIGNALS:
+    void focusLost();
 
-    protected:
-        void         focusOutEvent(QFocusEvent*) override { Q_EMIT focusLost(); }
+protected:
+    void focusOutEvent(QFocusEvent*) override { Q_EMIT focusLost(); }
 };
 
 #endif // BIRTHDAYDLG_H
diff --git a/src/commandoptions.cpp b/src/commandoptions.cpp
index 32e5dd94..499cbe7a 100644
--- a/src/commandoptions.cpp
+++ b/src/commandoptions.cpp
@@ -139,8 +139,11 @@ QStringList CommandOptions::setOptions(QCommandLineParser* parser, const QString
               = new QCommandLineOption(QStringList{QStringLiteral("m"), QStringLiteral("mail")},
                                        i18n("Send an email to the given address (repeat as needed)"),
                                        QStringLiteral("address"));
+    mOptions[NAME]
+              = new QCommandLineOption(QStringList{QStringLiteral("n"), QStringLiteral("name")},
+                                       i18n("Name of alarm"));
     mOptions[NOTIFY]
-              = new QCommandLineOption(QStringList{QStringLiteral("n"), QStringLiteral("notify")},
+              = new QCommandLineOption(QStringList{QStringLiteral("N"), QStringLiteral("notify")},
                                        i18n("Display alarm message as a notification"));
     mOptions[PLAY]
               = new QCommandLineOption(QStringList{QStringLiteral("p"), QStringLiteral("play")},
@@ -268,7 +271,7 @@ void CommandOptions::process()
     }
     if (checkCommand(OptEDIT_NEW_PRESET, EDIT_NEW_PRESET))
     {
-        mTemplateName = mParser->value(*mOptions.at(mCommandOpt));
+        mName = mParser->value(*mOptions.at(mCommandOpt));
     }
     if (checkCommand(FILE, NEW))
     {
@@ -408,6 +411,11 @@ void CommandOptions::process()
         case NEW:
         {
             // Display a message or file, execute a command, or send an email
+            if (mParser->isSet(*mOptions.at(NAME)))
+            {
+                // Alarm name is specified
+                mName = mParser->value(*mOptions.at(NAME));
+            }
             if (mParser->isSet(*mOptions.at(COLOUR)))
             {
                 // Background colour is specified
@@ -657,6 +665,10 @@ void CommandOptions::process()
                 errors << optionName(LATE_CANCEL);
             if (mParser->isSet(*mOptions.at(LOGIN)))
                 errors << optionName(LOGIN);
+            if (mParser->isSet(*mOptions.at(NAME)))
+                errors << optionName(NAME);
+            if (mParser->isSet(*mOptions.at(NOTIFY)))
+                errors << optionName(NOTIFY);
             if (mParser->isSet(*mOptions.at(PLAY)))
                 errors << optionName(PLAY);
             if (mParser->isSet(*mOptions.at(PLAY_REPEAT)))
diff --git a/src/commandoptions.h b/src/commandoptions.h
index aa57843a..186eb7ee 100644
--- a/src/commandoptions.h
+++ b/src/commandoptions.h
@@ -48,7 +48,7 @@ public:
     QString             commandName() const       { return optionName(mCommandOpt); }
     QString             eventId() const           { return mEventId; }
     QString             resourceId() const        { return mResourceId; }
-    QString             templateName() const      { return mTemplateName; }
+    QString             name() const              { return mName; }
     EditAlarmDlg::Type  editType() const          { return mEditType; }
     KAEvent::SubAction  editAction() const        { return mEditAction; }
     QString             text() const              { return mText; }
@@ -103,6 +103,7 @@ private:
         OptLIST,
         LOGIN,
         MAIL,
+        NAME,
         NOTIFY,
         PLAY,
         PLAY_REPEAT,
@@ -145,7 +146,7 @@ private:
     Option              mCommandOpt;             // option for the selected command
     QString             mEventId;                // TRIGGER_EVENT, CANCEL_EVENT, EDIT: event ID
     QString             mResourceId;             // TRIGGER_EVENT, CANCEL_EVENT, EDIT: optional resource ID
-    QString             mTemplateName;           // EDIT_NEW_PRESET: template name
+    QString             mName;                   // NEW, EDIT_NEW_PRESET: alarm/template name
     EditAlarmDlg::Type  mEditType;               // NEW, EDIT_NEW_*: alarm edit type
     KAEvent::SubAction  mEditAction;             // NEW: alarm edit sub-type
     bool                mEditActionSet {false};  // NEW: mEditAction is valid
diff --git a/src/data/kalarmconfig.kcfg b/src/data/kalarmconfig.kcfg
index ba604238..8978912c 100644
--- a/src/data/kalarmconfig.kcfg
+++ b/src/data/kalarmconfig.kcfg
@@ -37,6 +37,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
     <argument type="DateTime">Base_WorkDayEnd</argument>
     <argument type="Int">Base_WorkDays</argument>
   </signal>
+  <signal name="useAlarmNameChanged">
+    <argument type="Bool">UseAlarmName</argument>
+  </signal>
   <signal name="messageFontChanged">
     <argument type="Font">MessageFont</argument>
   </signal>
@@ -88,6 +91,12 @@ SPDX-License-Identifier: GPL-2.0-or-later
       <whatsthis context="@info:whatsthis">Default background color for alarm message windows.</whatsthis>
       <default code="true">KColorScheme(QPalette::Active).background(KColorScheme::NegativeBackground).color()</default>
     </entry>
+    <entry name="UseAlarmName" type="Bool">
+      <label context="@label">Use alarm names</label>
+      <whatsthis context="@info:whatsthis">Choose whether to be able to give each alarm a name. This is a convenience to help you to identify alarms.</whatsthis>
+      <default>false</default>
+      <emit signal="useAlarmNameChanged"/>
+    </entry>
     <entry name="MessageFont" type="Font">
       <label context="@label">Message font</label>
       <whatsthis context="@info:whatsthis">Default font for displaying alarm messages.</whatsthis>
diff --git a/src/dbushandler.cpp b/src/dbushandler.cpp
index 4f6a15fa..b0eb3ad5 100644
--- a/src/dbushandler.cpp
+++ b/src/dbushandler.cpp
@@ -64,7 +64,7 @@ QString DBusHandler::list()
     return theApp()->dbusList();
 }
 
-bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+bool DBusHandler::scheduleMessage(const QString& name, const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
                                   const QString& bgColor, const QString& fgColor, const QString& font,
                                   const QString& audioUrl, int reminderMins, const QString& recurrence,
                                   int subRepeatInterval, int subRepeatCount)
@@ -74,12 +74,12 @@ bool DBusHandler::scheduleMessage(const QString& message, const QString& startDa
     Duration subRepeatDuration;
     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
         return false;
-    return scheduleMessage(message, start, lateCancel, flags, bgColor, fgColor, font,
+    return scheduleMessage(name, message, start, lateCancel, flags, bgColor, fgColor, font,
                            QUrl::fromUserInput(audioUrl, QString(), QUrl::AssumeLocalFile),
                            reminderMins, recur, subRepeatDuration, subRepeatCount);
 }
 
-bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+bool DBusHandler::scheduleMessage(const QString& name, const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
                                   const QString& bgColor, const QString& fgColor, const QString& font,
                                   const QString& audioUrl, int reminderMins,
                                   int recurType, int recurInterval, int recurCount)
@@ -88,12 +88,12 @@ bool DBusHandler::scheduleMessage(const QString& message, const QString& startDa
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
         return false;
-    return scheduleMessage(message, start, lateCancel, flags, bgColor, fgColor, font,
+    return scheduleMessage(name, message, start, lateCancel, flags, bgColor, fgColor, font,
                            QUrl::fromUserInput(audioUrl, QString(), QUrl::AssumeLocalFile),
                            reminderMins, recur);
 }
 
-bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+bool DBusHandler::scheduleMessage(const QString& name, const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
                                   const QString& bgColor, const QString& fgColor, const QString& font,
                                   const QString& audioUrl, int reminderMins,
                                   int recurType, int recurInterval, const QString& endDateTime)
@@ -102,12 +102,39 @@ bool DBusHandler::scheduleMessage(const QString& message, const QString& startDa
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
         return false;
-    return scheduleMessage(message, start, lateCancel, flags, bgColor, fgColor, font,
+    return scheduleMessage(name, message, start, lateCancel, flags, bgColor, fgColor, font,
                            QUrl::fromUserInput(audioUrl, QString(), QUrl::AssumeLocalFile),
                            reminderMins, recur);
 }
 
-bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                  const QString& bgColor, const QString& fgColor, const QString& font,
+                                  const QString& audioUrl, int reminderMins, const QString& recurrence,
+                                  int subRepeatInterval, int subRepeatCount)
+{
+    return scheduleMessage(QString(), message, startDateTime, lateCancel, flags, bgColor, fgColor, font,
+                           audioUrl, reminderMins, recurrence, subRepeatInterval, subRepeatCount);
+}
+
+bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                  const QString& bgColor, const QString& fgColor, const QString& font,
+                                  const QString& audioUrl, int reminderMins,
+                                  int recurType, int recurInterval, int recurCount)
+{
+    return scheduleMessage(QString(), message, startDateTime, lateCancel, flags, bgColor, fgColor, font,
+                           audioUrl, reminderMins, recurType, recurInterval, recurCount);
+}
+
+bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                  const QString& bgColor, const QString& fgColor, const QString& font,
+                                  const QString& audioUrl, int reminderMins,
+                                  int recurType, int recurInterval, const QString& endDateTime)
+{
+    return scheduleMessage(QString(), message, startDateTime, lateCancel, flags, bgColor, fgColor, font,
+                           audioUrl, reminderMins, recurType, recurInterval, endDateTime);
+}
+
+bool DBusHandler::scheduleFile(const QString& name, const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
                                const QString& audioUrl, int reminderMins, const QString& recurrence,
                                int subRepeatInterval, int subRepeatCount)
 {
@@ -116,39 +143,61 @@ bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime,
     Duration subRepeatDuration;
     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
         return false;
-    return scheduleFile(QUrl::fromUserInput(url, QString(), QUrl::AssumeLocalFile),
+    return scheduleFile(name, QUrl::fromUserInput(url, QString(), QUrl::AssumeLocalFile),
                         start, lateCancel, flags, bgColor,
                         QUrl::fromUserInput(audioUrl, QString(), QUrl::AssumeLocalFile),
                         reminderMins, recur, subRepeatDuration, subRepeatCount);
 }
 
-bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+bool DBusHandler::scheduleFile(const QString& name, const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
                                const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount)
 {
     KADateTime start;
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
         return false;
-    return scheduleFile(QUrl::fromUserInput(url, QString(), QUrl::AssumeLocalFile),
+    return scheduleFile(name, QUrl::fromUserInput(url, QString(), QUrl::AssumeLocalFile),
                         start, lateCancel, flags, bgColor,
                         QUrl::fromUserInput(audioUrl, QString(), QUrl::AssumeLocalFile),
                         reminderMins, recur);
 }
 
-bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+bool DBusHandler::scheduleFile(const QString& name, const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
                                const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime)
 {
     KADateTime start;
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
         return false;
-    return scheduleFile(QUrl::fromUserInput(url, QString(), QUrl::AssumeLocalFile),
+    return scheduleFile(name, QUrl::fromUserInput(url, QString(), QUrl::AssumeLocalFile),
                         start, lateCancel, flags, bgColor,
                         QUrl::fromUserInput(audioUrl, QString(), QUrl::AssumeLocalFile),
                         reminderMins, recur);
 }
 
-bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                               const QString& audioUrl, int reminderMins, const QString& recurrence,
+                               int subRepeatInterval, int subRepeatCount)
+{
+    return scheduleFile(QString(), url, startDateTime, lateCancel, flags, bgColor,
+                        audioUrl, reminderMins, recurrence, subRepeatInterval, subRepeatCount);
+}
+
+bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                               const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount)
+{
+    return scheduleFile(QString(), url, startDateTime, lateCancel, flags, bgColor,
+                        audioUrl, reminderMins, recurType, recurInterval, recurCount);
+}
+
+bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                               const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime)
+{
+    return scheduleFile(QString(), url, startDateTime, lateCancel, flags, bgColor,
+                        audioUrl, reminderMins, recurType, recurInterval, endDateTime);
+}
+
+bool DBusHandler::scheduleCommand(const QString& name, const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
                                   const QString& recurrence, int subRepeatInterval, int subRepeatCount)
 {
     KADateTime start;
@@ -156,10 +205,10 @@ bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& sta
     Duration subRepeatDuration;
     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
         return false;
-    return scheduleCommand(commandLine, start, lateCancel, flags, recur, subRepeatDuration, subRepeatCount);
+    return scheduleCommand(name, commandLine, start, lateCancel, flags, recur, subRepeatDuration, subRepeatCount);
 }
 
-bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+bool DBusHandler::scheduleCommand(const QString& name, const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
                                   int recurType, int recurInterval, int recurCount)
 {
     KADateTime start = convertDateTime(startDateTime);
@@ -168,20 +217,38 @@ bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& sta
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
         return false;
-    return scheduleCommand(commandLine, start, lateCancel, flags, recur);
+    return scheduleCommand(name, commandLine, start, lateCancel, flags, recur);
 }
 
-bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+bool DBusHandler::scheduleCommand(const QString& name, const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
                                   int recurType, int recurInterval, const QString& endDateTime)
 {
     KADateTime start;
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
         return false;
-    return scheduleCommand(commandLine, start, lateCancel, flags, recur);
+    return scheduleCommand(name, commandLine, start, lateCancel, flags, recur);
 }
 
-bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                  const QString& recurrence, int subRepeatInterval, int subRepeatCount)
+{
+    return scheduleCommand(QString(), commandLine, startDateTime, lateCancel, flags, recurrence, subRepeatInterval, subRepeatCount);
+}
+
+bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                  int recurType, int recurInterval, int recurCount)
+{
+    return scheduleCommand(QString(), commandLine, startDateTime, lateCancel, flags, recurType, recurInterval, recurCount);
+}
+
+bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                  int recurType, int recurInterval, const QString& endDateTime)
+{
+    return scheduleCommand(QString(), commandLine, startDateTime, lateCancel, flags, recurType, recurInterval, endDateTime);
+}
+
+bool DBusHandler::scheduleEmail(const QString& name, const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
                                 const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
                                 const QString& recurrence, int subRepeatInterval, int subRepeatCount)
 {
@@ -190,10 +257,10 @@ bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses,
     Duration subRepeatDuration;
     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
         return false;
-    return scheduleEmail(fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur, subRepeatDuration, subRepeatCount);
+    return scheduleEmail(name, fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur, subRepeatDuration, subRepeatCount);
 }
 
-bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+bool DBusHandler::scheduleEmail(const QString& name, const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
                                 const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
                                 int recurType, int recurInterval, int recurCount)
 {
@@ -201,10 +268,10 @@ bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses,
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
         return false;
-    return scheduleEmail(fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur);
+    return scheduleEmail(name, fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur);
 }
 
-bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+bool DBusHandler::scheduleEmail(const QString& name, const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
                                 const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
                                 int recurType, int recurInterval, const QString& endDateTime)
 {
@@ -212,10 +279,31 @@ bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses,
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
         return false;
-    return scheduleEmail(fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur);
+    return scheduleEmail(name, fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur);
 }
 
-bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                const QString& recurrence, int subRepeatInterval, int subRepeatCount)
+{
+    return scheduleEmail(QString(), fromID, addresses, subject, message, attachments, startDateTime, lateCancel, flags, recurrence, subRepeatInterval, subRepeatCount);
+}
+
+bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                int recurType, int recurInterval, int recurCount)
+{
+    return scheduleEmail(QString(), fromID, addresses, subject, message, attachments, startDateTime, lateCancel, flags, recurType, recurInterval, recurCount);
+}
+
+bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                int recurType, int recurInterval, const QString& endDateTime)
+{
+    return scheduleEmail(QString(), fromID, addresses, subject, message, attachments, startDateTime, lateCancel, flags, recurType, recurInterval, endDateTime);
+}
+
+bool DBusHandler::scheduleAudio(const QString& name, const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
                                 unsigned flags, const QString& recurrence, int subRepeatInterval, int subRepeatCount)
 {
     KADateTime start;
@@ -223,10 +311,10 @@ bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, cons
     Duration subRepeatDuration;
     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
         return false;
-    return scheduleAudio(audioUrl, volumePercent, start, lateCancel, flags, recur, subRepeatDuration, subRepeatCount);
+    return scheduleAudio(name, audioUrl, volumePercent, start, lateCancel, flags, recur, subRepeatDuration, subRepeatCount);
 }
 
-bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+bool DBusHandler::scheduleAudio(const QString& name, const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
                                 unsigned flags, int recurType, int recurInterval, int recurCount)
 {
     KADateTime start = convertDateTime(startDateTime);
@@ -235,17 +323,35 @@ bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, cons
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
         return false;
-    return scheduleAudio(audioUrl, volumePercent, start, lateCancel, flags, recur);
+    return scheduleAudio(name, audioUrl, volumePercent, start, lateCancel, flags, recur);
 }
 
-bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+bool DBusHandler::scheduleAudio(const QString& name, const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
                                 unsigned flags, int recurType, int recurInterval, const QString& endDateTime)
 {
     KADateTime start;
     KARecurrence recur;
     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
         return false;
-    return scheduleAudio(audioUrl, volumePercent, start, lateCancel, flags, recur);
+    return scheduleAudio(name, audioUrl, volumePercent, start, lateCancel, flags, recur);
+}
+
+bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                unsigned flags, const QString& recurrence, int subRepeatInterval, int subRepeatCount)
+{
+    return scheduleAudio(QString(), audioUrl, volumePercent, startDateTime, lateCancel, flags, recurrence, subRepeatInterval, subRepeatCount);
+}
+
+bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                unsigned flags, int recurType, int recurInterval, int recurCount)
+{
+    return scheduleAudio(QString(), audioUrl, volumePercent, startDateTime, lateCancel, flags, recurType, recurInterval, recurCount);
+}
+
+bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                unsigned flags, int recurType, int recurInterval, const QString& endDateTime)
+{
+    return scheduleAudio(QString(), audioUrl, volumePercent, startDateTime, lateCancel, flags, recurType, recurInterval, endDateTime);
 }
 
 bool DBusHandler::edit(const QString& eventID)
@@ -281,7 +387,7 @@ bool DBusHandler::editNew(const QString& templateName)
 /******************************************************************************
 * Schedule a message alarm, after converting the parameters from strings.
 */
-bool DBusHandler::scheduleMessage(const QString& message, const KADateTime& start, int lateCancel, unsigned flags,
+bool DBusHandler::scheduleMessage(const QString& name, const QString& message, const KADateTime& start, int lateCancel, unsigned flags,
                                   const QString& bgColor, const QString& fgColor, const QString& fontStr,
                                   const QUrl& audioFile, int reminderMins, const KARecurrence& recurrence,
                                   const KCalendarCore::Duration& subRepeatDuration, int subRepeatCount)
@@ -314,14 +420,14 @@ bool DBusHandler::scheduleMessage(const QString& message, const KADateTime& star
             return false;
         }
     }
-    return theApp()->scheduleEvent(action, message, start, lateCancel, kaEventFlags, bg, fg, font,
+    return theApp()->scheduleEvent(action, name, message, start, lateCancel, kaEventFlags, bg, fg, font,
                                    audioFile.toString(), -1, reminderMins, recurrence, subRepeatDuration, subRepeatCount);
 }
 
 /******************************************************************************
 * Schedule a file alarm, after converting the parameters from strings.
 */
-bool DBusHandler::scheduleFile(const QUrl& file,
+bool DBusHandler::scheduleFile(const QString& name, const QUrl& file,
                                const KADateTime& start, int lateCancel, unsigned flags, const QString& bgColor,
                                const QUrl& audioFile, int reminderMins, const KARecurrence& recurrence,
                                const KCalendarCore::Duration& subRepeatDuration, int subRepeatCount)
@@ -330,26 +436,26 @@ bool DBusHandler::scheduleFile(const QUrl& file,
     const QColor bg = convertBgColour(bgColor);
     if (!bg.isValid())
         return false;
-    return theApp()->scheduleEvent(KAEvent::FILE, file.toString(), start, lateCancel, kaEventFlags, bg, Qt::black, QFont(),
+    return theApp()->scheduleEvent(KAEvent::FILE, name, file.toString(), start, lateCancel, kaEventFlags, bg, Qt::black, QFont(),
                                    audioFile.toString(), -1, reminderMins, recurrence, subRepeatDuration, subRepeatCount);
 }
 
 /******************************************************************************
 * Schedule a command alarm, after converting the parameters from strings.
 */
-bool DBusHandler::scheduleCommand(const QString& commandLine,
+bool DBusHandler::scheduleCommand(const QString& name, const QString& commandLine,
                                   const KADateTime& start, int lateCancel, unsigned flags,
                                   const KARecurrence& recurrence, const KCalendarCore::Duration& subRepeatDuration, int subRepeatCount)
 {
     const KAEvent::Flags kaEventFlags = convertStartFlags(start, flags);
-    return theApp()->scheduleEvent(KAEvent::COMMAND, commandLine, start, lateCancel, kaEventFlags, Qt::black, Qt::black, QFont(),
+    return theApp()->scheduleEvent(KAEvent::COMMAND, name, commandLine, start, lateCancel, kaEventFlags, Qt::black, Qt::black, QFont(),
                                    QString(), -1, 0, recurrence, subRepeatDuration, subRepeatCount);
 }
 
 /******************************************************************************
 * Schedule an email alarm, after validating the addresses and attachments.
 */
-bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject,
+bool DBusHandler::scheduleEmail(const QString& name, const QString& fromID, const QString& addresses, const QString& subject,
                                 const QString& message, const QString& attachments,
                                 const KADateTime& start, int lateCancel, unsigned flags,
                                 const KARecurrence& recurrence, const KCalendarCore::Duration& subRepeatDuration, int subRepeatCount)
@@ -384,20 +490,20 @@ bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses,
         qCCritical(KALARM_LOG) << "D-Bus call scheduleEmail(): invalid email attachment:" << bad;
         return false;
     }
-    return theApp()->scheduleEvent(KAEvent::EMAIL, message, start, lateCancel, kaEventFlags, Qt::black, Qt::black, QFont(),
+    return theApp()->scheduleEvent(KAEvent::EMAIL, name, message, start, lateCancel, kaEventFlags, Qt::black, Qt::black, QFont(),
                                    QString(), -1, 0, recurrence, subRepeatDuration, subRepeatCount, senderId, addrs, subject, atts);
 }
 
 /******************************************************************************
 * Schedule a audio alarm, after converting the parameters from strings.
 */
-bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent,
+bool DBusHandler::scheduleAudio(const QString& name, const QString& audioUrl, int volumePercent,
                                 const KADateTime& start, int lateCancel, unsigned flags,
                                 const KARecurrence& recurrence, const KCalendarCore::Duration& subRepeatDuration, int subRepeatCount)
 {
     const KAEvent::Flags kaEventFlags = convertStartFlags(start, flags);
     const float volume = (volumePercent >= 0) ? volumePercent / 100.0f : -1;
-    return theApp()->scheduleEvent(KAEvent::AUDIO, QString(), start, lateCancel, kaEventFlags, Qt::black, Qt::black, QFont(),
+    return theApp()->scheduleEvent(KAEvent::AUDIO, name, QString(), start, lateCancel, kaEventFlags, Qt::black, Qt::black, QFont(),
                                    audioUrl, volume, 0, recurrence, subRepeatDuration, subRepeatCount);
 }
 
diff --git a/src/dbushandler.h b/src/dbushandler.h
index deb17c65..4eec489b 100644
--- a/src/dbushandler.h
+++ b/src/dbushandler.h
@@ -1,7 +1,7 @@
 /*
  *  dbushandler.h  -  handler for D-Bus calls by other applications
  *  Program:  kalarm
- *  SPDX-FileCopyrightText: 2001-2012 David Jarvie <djarvie at kde.org>
+ *  SPDX-FileCopyrightText: 2001-2020 David Jarvie <djarvie at kde.org>
  *
  *  SPDX-License-Identifier: GPL-2.0-or-later
  */
@@ -22,80 +22,134 @@ using namespace KAlarmCal;
 
 class DBusHandler : public QObject, public KAlarmIface
 {
-        Q_OBJECT
-        Q_CLASSINFO("D-Bus Interface", "org.kde.kalarm.kalarm")
-    public:
-        DBusHandler();
-
-    public Q_SLOTS:
-        Q_SCRIPTABLE bool cancelEvent(const QString& eventId);
-        Q_SCRIPTABLE bool triggerEvent(const QString& eventId);
-        Q_SCRIPTABLE QString list();
-
-        Q_SCRIPTABLE bool scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
-                                          const QString& bgColor, const QString& fgColor, const QString& font,
-                                          const QString& audioUrl, int reminderMins, const QString& recurrence,
-                                          int subRepeatInterval, int subRepeatCount);
-        Q_SCRIPTABLE bool scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
-                                          const QString& bgColor, const QString& fgColor, const QString& font,
-                                          const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount);
-        Q_SCRIPTABLE bool scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
-                                          const QString& bgColor, const QString& fgColor, const QString& font,
-                                          const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime);
-        Q_SCRIPTABLE bool scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
-                                       const QString& audioUrl, int reminderMins, const QString& recurrence,
-                                       int subRepeatInterval, int subRepeatCount);
-        Q_SCRIPTABLE bool scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
-                                       const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount);
-        Q_SCRIPTABLE bool scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
-                                       const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime);
-        Q_SCRIPTABLE bool scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
-                                          const QString& recurrence, int subRepeatInterval, int subRepeatCount);
-        Q_SCRIPTABLE bool scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
-                                          int recurType, int recurInterval, int recurCount);
-        Q_SCRIPTABLE bool scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
-                                          int recurType, int recurInterval, const QString& endDateTime);
-        Q_SCRIPTABLE bool scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
-                                        const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
-                                        const QString& recurrence, int subRepeatInterval, int subRepeatCount);
-        Q_SCRIPTABLE bool scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
-                                        const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
-                                        int recurType, int recurInterval, int recurCount);
-        Q_SCRIPTABLE bool scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
-                                        const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
-                                        int recurType, int recurInterval, const QString& endDateTime);
-        Q_SCRIPTABLE bool scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
-                                        unsigned flags, const QString& recurrence, int subRepeatInterval, int subRepeatCount);
-        Q_SCRIPTABLE bool scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
-                                        unsigned flags, int recurType, int recurInterval, int recurCount);
-        Q_SCRIPTABLE bool scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
-                                        unsigned flags, int recurType, int recurInterval, const QString& endDateTime);
-        Q_SCRIPTABLE bool edit(const QString& eventID);
-        Q_SCRIPTABLE bool editNew(int type);
-        Q_SCRIPTABLE bool editNew(const QString& templateName);
-
-    private:
-        static bool scheduleMessage(const QString& message, const KADateTime& start, int lateCancel, unsigned flags,
-                                    const QString& bgColor, const QString& fgColor, const QString& fontStr,
-                                    const QUrl& audioFile, int reminderMins, const KARecurrence&,
-                                    const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
-        static bool scheduleFile(const QUrl& file, const KADateTime& start, int lateCancel, unsigned flags, const QString& bgColor,
-                                 const QUrl& audioFile, int reminderMins, const KARecurrence&,
-                                 const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
-        static bool scheduleCommand(const QString& commandLine, const KADateTime& start, int lateCancel, unsigned flags,
-                                    const KARecurrence&, const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
-        static bool scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
-                                  const QString& attachments, const KADateTime& start, int lateCancel, unsigned flags,
-                                  const KARecurrence&, const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
-        static bool scheduleAudio(const QString& audioUrl, int volumePercent, const KADateTime& start, int lateCancel, unsigned flags,
-                                  const KARecurrence&, const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
-        static KADateTime convertDateTime(const QString& dateTime, const KADateTime& = KADateTime());
-        static KAEvent::Flags convertStartFlags(const KADateTime& start, unsigned flags);
-        static QColor    convertBgColour(const QString& bgColor);
-        static bool      convertRecurrence(KADateTime& start, KARecurrence&, const QString& startDateTime, const QString& icalRecurrence, int subRepeatInterval, KCalendarCore::Duration& subRepeatDuration);
-        static bool      convertRecurrence(KADateTime& start, KARecurrence&, const QString& startDateTime, int recurType, int recurInterval, int recurCount);
-        static bool      convertRecurrence(KADateTime& start, KARecurrence&, const QString& startDateTime, int recurType, int recurInterval, const QString& endDateTime);
-        static bool      convertRecurrence(KARecurrence&, const KADateTime& start, int recurType, int recurInterval, int recurCount, const KADateTime& end);
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "org.kde.kalarm.kalarm")
+public:
+    DBusHandler();
+
+public Q_SLOTS:
+    Q_SCRIPTABLE bool cancelEvent(const QString& eventId);
+    Q_SCRIPTABLE bool triggerEvent(const QString& eventId);
+    Q_SCRIPTABLE QString list();
+
+    // Create a display alarm with a specified text message.
+    Q_SCRIPTABLE bool scheduleMessage(const QString& name, const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      const QString& bgColor, const QString& fgColor, const QString& font,
+                                      const QString& audioUrl, int reminderMins, const QString& recurrence,
+                                      int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleMessage(const QString& name, const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      const QString& bgColor, const QString& fgColor, const QString& font,
+                                      const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleMessage(const QString& name, const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      const QString& bgColor, const QString& fgColor, const QString& font,
+                                      const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime);
+    // Deprecated: Create a display alarm with a specified text message.
+    Q_SCRIPTABLE bool scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      const QString& bgColor, const QString& fgColor, const QString& font,
+                                      const QString& audioUrl, int reminderMins, const QString& recurrence,
+                                      int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      const QString& bgColor, const QString& fgColor, const QString& font,
+                                      const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      const QString& bgColor, const QString& fgColor, const QString& font,
+                                      const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime);
+
+    // Create a display alarm showing a file's contents.
+    Q_SCRIPTABLE bool scheduleFile(const QString& name, const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                                   const QString& audioUrl, int reminderMins, const QString& recurrence,
+                                   int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleFile(const QString& name, const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                                   const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleFile(const QString& name, const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                                   const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime);
+    // Deprecated: Create a display alarm showing a file's contents.
+    Q_SCRIPTABLE bool scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                                   const QString& audioUrl, int reminderMins, const QString& recurrence,
+                                   int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                                   const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
+                                   const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime);
+
+    // Create a command alarm.
+    Q_SCRIPTABLE bool scheduleCommand(const QString& name, const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      const QString& recurrence, int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleCommand(const QString& name, const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleCommand(const QString& name, const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      int recurType, int recurInterval, const QString& endDateTime);
+    // Deprecated: Create a command alarm.
+    Q_SCRIPTABLE bool scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      const QString& recurrence, int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
+                                      int recurType, int recurInterval, const QString& endDateTime);
+
+    // Create an email alarm.
+    Q_SCRIPTABLE bool scheduleEmail(const QString& name, const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                    const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                    const QString& recurrence, int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleEmail(const QString& name, const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                    const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                    int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleEmail(const QString& name, const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                    const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                    int recurType, int recurInterval, const QString& endDateTime);
+    // Deprecated: Create an email alarm.
+    Q_SCRIPTABLE bool scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                    const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                    const QString& recurrence, int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                    const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                    int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                                    const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
+                                    int recurType, int recurInterval, const QString& endDateTime);
+
+    // Create an audio alarm.
+    Q_SCRIPTABLE bool scheduleAudio(const QString& name, const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                    unsigned flags, const QString& recurrence, int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleAudio(const QString& name, const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                    unsigned flags, int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleAudio(const QString& name, const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                    unsigned flags, int recurType, int recurInterval, const QString& endDateTime);
+    // Deprecated: Create an audio alarm.
+    Q_SCRIPTABLE bool scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                    unsigned flags, const QString& recurrence, int subRepeatInterval, int subRepeatCount);
+    Q_SCRIPTABLE bool scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                    unsigned flags, int recurType, int recurInterval, int recurCount);
+    Q_SCRIPTABLE bool scheduleAudio(const QString& audioUrl, int volumePercent, const QString& startDateTime, int lateCancel,
+                                    unsigned flags, int recurType, int recurInterval, const QString& endDateTime);
+
+    // Edit an alarm.
+    Q_SCRIPTABLE bool edit(const QString& eventID);
+    Q_SCRIPTABLE bool editNew(int type);
+    Q_SCRIPTABLE bool editNew(const QString& templateName);
+
+private:
+    static bool scheduleMessage(const QString& name, const QString& message, const KADateTime& start, int lateCancel, unsigned flags,
+                                const QString& bgColor, const QString& fgColor, const QString& fontStr,
+                                const QUrl& audioFile, int reminderMins, const KARecurrence&,
+                                const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
+    static bool scheduleFile(const QString& name, const QUrl& file, const KADateTime& start, int lateCancel, unsigned flags, const QString& bgColor,
+                             const QUrl& audioFile, int reminderMins, const KARecurrence&,
+                             const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
+    static bool scheduleCommand(const QString& name, const QString& commandLine, const KADateTime& start, int lateCancel, unsigned flags,
+                                const KARecurrence&, const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
+    static bool scheduleEmail(const QString& name, const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
+                              const QString& attachments, const KADateTime& start, int lateCancel, unsigned flags,
+                              const KARecurrence&, const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
+    static bool scheduleAudio(const QString& name, const QString& audioUrl, int volumePercent, const KADateTime& start, int lateCancel, unsigned flags,
+                              const KARecurrence&, const KCalendarCore::Duration& subRepeatDuration = KCalendarCore::Duration(0), int subRepeatCount = 0);
+    static KADateTime convertDateTime(const QString& dateTime, const KADateTime& = KADateTime());
+    static KAEvent::Flags convertStartFlags(const KADateTime& start, unsigned flags);
+    static QColor    convertBgColour(const QString& bgColor);
+    static bool      convertRecurrence(KADateTime& start, KARecurrence&, const QString& startDateTime, const QString& icalRecurrence, int subRepeatInterval, KCalendarCore::Duration& subRepeatDuration);
+    static bool      convertRecurrence(KADateTime& start, KARecurrence&, const QString& startDateTime, int recurType, int recurInterval, int recurCount);
+    static bool      convertRecurrence(KADateTime& start, KARecurrence&, const QString& startDateTime, int recurType, int recurInterval, const QString& endDateTime);
+    static bool      convertRecurrence(KARecurrence&, const KADateTime& start, int recurType, int recurInterval, int recurCount, const KADateTime& end);
 };
 
 #endif // DBUSHANDLER_H
diff --git a/src/editdlg.cpp b/src/editdlg.cpp
index 48fdf076..0fd9cfbf 100644
--- a/src/editdlg.cpp
+++ b/src/editdlg.cpp
@@ -215,24 +215,6 @@ void EditAlarmDlg::init(const KAEvent* event)
         mButtonBox->button(QDialogButtonBox::Ok)->setWhatsThis(i18nc("@info:whatsthis", "Schedule the alarm at the specified time."));
 
     QVBoxLayout* mainLayout = new QVBoxLayout(this);
-    if (mTemplate)
-    {
-        QFrame* frame = new QFrame;
-        QHBoxLayout* box = new QHBoxLayout();
-        frame->setLayout(box);
-        box->setContentsMargins(0, 0, 0, 0);
-        QLabel* label = new QLabel(i18nc("@label:textbox", "Template name:"));
-        label->setFixedSize(label->sizeHint());
-        box->addWidget(label);
-        mTemplateName = new QLineEdit();
-        mTemplateName->setReadOnly(mReadOnly);
-        connect(mTemplateName, &QLineEdit::textEdited, this, &EditAlarmDlg::contentsChanged);
-        label->setBuddy(mTemplateName);
-        box->addWidget(mTemplateName);
-        frame->setWhatsThis(i18nc("@info:whatsthis", "Enter the name of the alarm template"));
-        frame->setFixedHeight(box->sizeHint().height());
-        mainLayout->addWidget(frame);
-    }
     mTabs = new QTabWidget(this);
     mainLayout->addWidget(mTabs);
     mTabScrollGroup = new StackedScrollGroup(this, mTabs);
@@ -261,6 +243,27 @@ void EditAlarmDlg::init(const KAEvent* event)
     connect(mRecurrenceEdit, &RecurrenceEdit::repeatNeedsInitialisation, this, &EditAlarmDlg::slotSetSubRepetition);
     connect(mRecurrenceEdit, &RecurrenceEdit::contentsChanged, this, &EditAlarmDlg::contentsChanged);
 
+    if (mTemplate  ||  Preferences::useAlarmName())
+    {
+        // Alarm/template name
+        QFrame* frame = new QFrame;
+        QHBoxLayout* box = new QHBoxLayout();
+        frame->setLayout(box);
+        box->setContentsMargins(0, 0, 0, 0);
+        QLabel* label = new QLabel(mTemplate ? i18nc("@label:textbox", "Template name:") : i18nc("@label:textbox", "Alarm name:"));
+        label->setFixedSize(label->sizeHint());
+        box->addWidget(label);
+        mName = new QLineEdit();
+        mName->setReadOnly(mReadOnly);
+        connect(mName, &QLineEdit::textEdited, this, &EditAlarmDlg::contentsChanged);
+        label->setBuddy(mName);
+        box->addWidget(mName);
+        frame->setWhatsThis(mTemplate ? i18nc("@info:whatsthis", "Enter the name of the alarm template")
+                                      : i18nc("@info:whatsthis", "Enter a name to help you identify this alarm. This is optional and need not be unique."));
+        frame->setFixedHeight(box->sizeHint().height());
+        topLayout->addWidget(frame);
+    }
+
     // Controls specific to the alarm type
     QGroupBox* actionBox = new QGroupBox(i18nc("@title:group", "Action"), mainPage);
     topLayout->addWidget(actionBox, 1);
@@ -424,8 +427,8 @@ void EditAlarmDlg::init(const KAEvent* event)
 
     // Initialise the state of all controls according to the specified event, if any
     initValues(event);
-    if (mTemplateName)
-        mTemplateName->setFocus();
+    if (mName)
+        mName->setFocus();
 
     if (!mNewAlarm)
     {
@@ -479,8 +482,8 @@ void EditAlarmDlg::initValues(const KAEvent* event)
     if (event)
     {
         // Set the values to those for the specified event
-        if (mTemplate)
-            mTemplateName->setText(event->templateName());
+        if (mName)
+            mName->setText(event->name());
         bool recurs = event->recurs();
         if ((recurs || event->repetition())  &&  !mTemplate  &&  event->deferred())
         {
@@ -585,6 +588,11 @@ void EditAlarmDlg::initValues(const KAEvent* event)
 /******************************************************************************
 * Initialise various values in the New Alarm dialogue.
 */
+void EditAlarmDlg::setName(const QString& name)
+{
+    if (mName)
+        mName->setText(name);
+}
 void EditAlarmDlg::setTime(const DateTime& start)
 {
     mTimeWidget->setDateTime(start);
@@ -641,9 +649,10 @@ void EditAlarmDlg::saveState(const KAEvent* event)
     mSavedEvent = nullptr;
     if (event)
         mSavedEvent = new KAEvent(*event);
+    if (mName)
+        mSavedName = mName->text();
     if (mTemplate)
     {
-        mSavedTemplateName      = mTemplateName->text();
         mSavedTemplateTimeType  = mTemplateTimeGroup->checkedButton();
         mSavedTemplateTime      = mTemplateTime->time();
         mSavedTemplateAfterTime = mTemplateTimeAfter->value();
@@ -671,12 +680,13 @@ bool EditAlarmDlg::stateChanged() const
     mOnlyDeferred = false;
     if (!mSavedEvent)
         return true;
+    if (mName  &&  mSavedName != mName->text())
+        return true;
     QString textFileCommandMessage;
     checkText(textFileCommandMessage, false);
     if (mTemplate)
     {
-        if (mSavedTemplateName     != mTemplateName->text()
-        ||  mSavedTemplateTimeType != mTemplateTimeGroup->checkedButton()
+        if (mSavedTemplateTimeType != mTemplateTimeGroup->checkedButton()
         ||  (mTemplateUseTime->isChecked()  &&  mSavedTemplateTime != mTemplateTime->time())
         ||  (mTemplateUseTimeAfter->isChecked()  &&  mSavedTemplateAfterTime != mTemplateTimeAfter->value()))
             return true;
@@ -761,7 +771,7 @@ void EditAlarmDlg::setEvent(KAEvent& event, const QString& text, bool trial)
     }
 
     int lateCancel = (trial || !mLateCancel->isEnabled()) ? 0 : mLateCancel->minutes();
-    type_setEvent(event, dt, text, lateCancel, trial);
+    type_setEvent(event, dt, (mName ? mName->text() : QString()), text, lateCancel, trial);
 
     if (!trial)
     {
@@ -802,7 +812,7 @@ void EditAlarmDlg::setEvent(KAEvent& event, const QString& text, bool trial)
         {
             int afterTime = mTemplateDefaultTime->isChecked() ? 0
                           : mTemplateUseTimeAfter->isChecked() ? mTemplateTimeAfter->value() : -1;
-            event.setTemplate(mTemplateName->text(), afterTime);
+            event.setTemplate(mName->text(), afterTime);
         }
     }
 }
@@ -974,17 +984,17 @@ bool EditAlarmDlg::validate()
     {
         // Check that the template name is not blank and is unique
         QString errmsg;
-        QString name = mTemplateName->text();
+        const QString name = mName->text();
         if (name.isEmpty())
             errmsg = i18nc("@info", "You must enter a name for the alarm template");
-        else if (name != mSavedTemplateName)
+        else if (name != mSavedName)
         {
             if (ResourcesCalendar::templateEvent(name).isValid())
                 errmsg = i18nc("@info", "Template name is already in use");
         }
         if (!errmsg.isEmpty())
         {
-            mTemplateName->setFocus();
+            mName->setFocus();
             KAMessageBox::sorry(this, errmsg);
             return false;
         }
@@ -1305,8 +1315,8 @@ void EditAlarmDlg::slotShowMainPage()
 {
     if (!mMainPageShown)
     {
-        if (mTemplateName)
-            mTemplateName->setFocus();
+        if (mName)
+            mName->setFocus();
         mMainPageShown = true;
     }
     else
diff --git a/src/editdlg.h b/src/editdlg.h
index 804b053f..ce4d121c 100644
--- a/src/editdlg.h
+++ b/src/editdlg.h
@@ -1,7 +1,7 @@
 /*
  *  editdlg.h  -  dialog to create or modify an alarm or alarm template
  *  Program:  kalarm
- *  SPDX-FileCopyrightText: 2001-2019 David Jarvie <djarvie at kde.org>
+ *  SPDX-FileCopyrightText: 2001-2020 David Jarvie <djarvie at kde.org>
  *
  *  SPDX-License-Identifier: GPL-2.0-or-later
  */
@@ -44,169 +44,170 @@ using namespace KAlarmCal;
 
 class EditAlarmDlg : public QDialog
 {
-        Q_OBJECT
-    public:
-        enum Type { NO_TYPE, DISPLAY, COMMAND, EMAIL, AUDIO };
-        enum GetResourceType {
-            RES_PROMPT,        // prompt for resource
-            RES_USE_EVENT_ID,  // use resource containing event, or prompt if not found
-            RES_IGNORE         // don't get resource
-        };
-
-        static EditAlarmDlg* create(bool Template, Type, QWidget* parent = nullptr,
-                                    GetResourceType = RES_PROMPT);
-        static EditAlarmDlg* create(bool Template, const KAEvent*, bool newAlarm, QWidget* parent = nullptr,
-                                    GetResourceType = RES_PROMPT, bool readOnly = false);
-        ~EditAlarmDlg() override;
-        bool            getEvent(KAEvent&, Resource&);
-
-        // Methods to initialise values in the New Alarm dialogue.
-        // N.B. setTime() must be called first to set the date-only characteristic,
-        //      followed by setRecurrence() if applicable.
-        void            setTime(const DateTime&);    // must be called first to set date-only value
-        void            setRecurrence(const KARecurrence&, const KCalendarCore::Duration& subRepeatInterval, int subRepeatCount);
-        void            setRepeatAtLogin();
-        virtual void    setAction(KAEvent::SubAction, const AlarmText& = AlarmText()) = 0;
-        void            setLateCancel(int minutes);
-        void            setShowInKOrganizer(bool);
-
-        QSize           sizeHint() const override    { return minimumSizeHint(); }
-
-        static int      instanceCount();
-        static QString  i18n_chk_ShowInKOrganizer();   // text of 'Show in KOrganizer' checkbox
-
-    protected:
-        EditAlarmDlg(bool Template, KAEvent::SubAction, QWidget* parent = nullptr,
-                     GetResourceType = RES_PROMPT);
-        EditAlarmDlg(bool Template, const KAEvent*, bool newAlarm, QWidget* parent = nullptr,
-                     GetResourceType = RES_PROMPT, bool readOnly = false);
-        void            init(const KAEvent* event);
-        void            resizeEvent(QResizeEvent*) override;
-        void            showEvent(QShowEvent*) override;
-        void            closeEvent(QCloseEvent*) override;
-        bool            eventFilter(QObject*, QEvent*) override;
-        virtual QString type_caption() const = 0;
-        virtual void    type_init(QWidget* parent, QVBoxLayout* frameLayout) = 0;
-        virtual void    type_initValues(const KAEvent*) = 0;
-        virtual void    type_showOptions(bool more) = 0;
-        virtual void    setReadOnly(bool readOnly) = 0;
-        virtual void    saveState(const KAEvent*) = 0;
-        virtual bool    type_stateChanged() const = 0;
-        virtual void    type_setEvent(KAEvent&, const KADateTime&, const QString& text, int lateCancel, bool trial) = 0;
-        virtual KAEvent::Flags getAlarmFlags() const;
-        virtual bool    type_validate(bool trial) = 0;
-        virtual void    type_aboutToTry() {}
-        virtual void    type_executedTry(const QString& text, void* obj) { Q_UNUSED(text); Q_UNUSED(obj); }
-        virtual Reminder* createReminder(QWidget* parent)  { Q_UNUSED(parent); return nullptr; }
-        virtual CheckBox* type_createConfirmAckCheckbox(QWidget* parent)  { Q_UNUSED(parent); return nullptr; }
-        virtual bool    checkText(QString& result, bool showErrorMessage = true) const = 0;
-
-        void            showMainPage();
-        bool            isTemplate() const         { return mTemplate; }
-        bool            isNewAlarm() const         { return mNewAlarm; }
-        bool            dateOnly() const;
-        bool            isTimedRecurrence() const;
-        bool            showingMore() const        { return mShowingMore; }
-        Reminder*       reminder() const           { return mReminder; }
-        LateCancelSelector* lateCancel() const     { return mLateCancel; }
-
-    protected Q_SLOTS:
-        virtual void    slotTry();
-        virtual void    slotHelp();      // Load Template
-        virtual void    slotDefault();   // More/Less Options
-        void            slotButtonClicked(QAbstractButton*);
-        void            contentsChanged();
-
-    private Q_SLOTS:
-        void            slotRecurTypeChange(int repeatType);
-        void            slotRecurFrequencyChange();
-        void            slotEditDeferral();
-        void            slotShowMainPage();
-        void            slotShowRecurrenceEdit();
-        void            slotAnyTimeToggled(bool anyTime);
-        void            slotTemplateTimeType(QAbstractButton*);
-        void            slotSetSubRepetition();
-        void            slotResize();
-        void            focusFixTimer();
-
-    private:
-        void            init(const KAEvent* event, GetResourceType getResource);
-        void            initValues(const KAEvent*);
-        void            setEvent(KAEvent&, const QString& text, bool trial);
-        bool            validate();
-        virtual bool    stateChanged() const;
-        void            showOptions(bool more);
-
-    protected:
-        KAEvent::SubAction  mAlarmType;           // actual alarm type
-
-        QDialogButtonBox*   mButtonBox;
-        QAbstractButton*    mTryButton;
-        QAbstractButton*    mLoadTemplateButton {nullptr};
-        QAbstractButton*    mMoreLessButton;
-
-    private:
-        static QList<EditAlarmDlg*> mWindowList;  // list of instances
-        QTabWidget*         mTabs;                // the tabs in the dialog
-        StackedScrollGroup* mTabScrollGroup;
-        int                 mMainPageIndex;
-        int                 mRecurPageIndex;
-        bool                mMainPageShown {false};          // true once the main tab has been displayed
-        bool                mRecurPageShown {false};         // true once the recurrence tab has been displayed
-        bool                mRecurSetDefaultEndDate {true};  // adjust default end date/time when recurrence tab is displayed
-
-        // Templates
-        QLineEdit*          mTemplateName {nullptr};
-        ButtonGroup*        mTemplateTimeGroup;
-        RadioButton*        mTemplateDefaultTime;  // no alarm time is specified
-        RadioButton*        mTemplateUseTimeAfter; // alarm time is specified as an offset from current
-        RadioButton*        mTemplateAnyTime;      // alarms have date only, no time
-        RadioButton*        mTemplateUseTime;      // an alarm time is specified
-        TimeSpinBox*        mTemplateTimeAfter;    // the specified offset from the current time
-        TimeEdit*           mTemplateTime;         // the alarm time which is specified
-        QGroupBox*          mDeferGroup {nullptr};
-        QLabel*             mDeferTimeLabel;
-        QPushButton*        mDeferChangeButton {nullptr};
-
-        AlarmTimeWidget*    mTimeWidget {nullptr};
-        LateCancelSelector* mLateCancel;
-        Reminder*           mReminder;             // null except for display alarms
-        CheckBox*           mShowInKorganizer {nullptr};
-
-        QFrame*             mMoreOptions;          // contains options hidden by default
-
-        RecurrenceEdit*     mRecurrenceEdit;
-
-        QString             mAlarmMessage;         // message text/file name/command/email message
-        DateTime            mAlarmDateTime;
-        DateTime            mDeferDateTime;
-        bool                mUseResourceEventId;   // whether to use mResourceEventId
-        QString             mResourceEventId;      // if non-null, save alarm in resource containing this event ID
-        Resource            mResource;             // resource to save event into, or invalid
-        int                 mDeferGroupHeight {0}; // height added by deferred time widget
-        int                 mDesktop;              // desktop to display the dialog in
-        QString             mEventId;              // UID of event being edited, or blank for new event
-        bool                mTemplate;             // editing an alarm template
-        bool                mNewAlarm;             // editing a new alarm
-        bool                mExpiredRecurrence;    // initially a recurrence which has expired
-        mutable bool        mChanged;              // controls other than deferral have changed since dialog was displayed
-        mutable bool        mOnlyDeferred;         // the only change made in the dialog was to the existing deferral
-        bool                mDesiredReadOnly;      // the specified read-only status of the dialog
-        bool                mReadOnly;             // the actual read-only status of the dialog
-        bool                mShowingMore {true};   // the More Options button has been clicked
-
-        // Initial state of all controls
-        KAEvent*            mSavedEvent {nullptr};
-        QString             mSavedTemplateName;     // mTemplateName value
-        QAbstractButton*    mSavedTemplateTimeType; // selected button in mTemplateTimeGroup
-        QTime               mSavedTemplateTime;     // mTemplateTime value
-        int                 mSavedTemplateAfterTime;// mTemplateAfterTime value
-        QString             mSavedTextFileCommandMessage;  // mTextMessageEdit/mFileMessageEdit/mCmdCommandEdit/mEmailMessageEdit value
-        KADateTime          mSavedDateTime;         // mTimeWidget value
-        KADateTime          mSavedDeferTime;        // mDeferDateTime value
-        int                 mSavedRecurrenceType;   // RecurrenceEdit::RepeatType value
-        int                 mSavedLateCancel;       // mLateCancel value
-        bool                mSavedShowInKorganizer; // mShowInKorganizer status
+    Q_OBJECT
+public:
+    enum Type { NO_TYPE, DISPLAY, COMMAND, EMAIL, AUDIO };
+    enum GetResourceType {
+        RES_PROMPT,        // prompt for resource
+        RES_USE_EVENT_ID,  // use resource containing event, or prompt if not found
+        RES_IGNORE         // don't get resource
+    };
+
+    static EditAlarmDlg* create(bool Template, Type, QWidget* parent = nullptr,
+                                GetResourceType = RES_PROMPT);
+    static EditAlarmDlg* create(bool Template, const KAEvent*, bool newAlarm, QWidget* parent = nullptr,
+                                GetResourceType = RES_PROMPT, bool readOnly = false);
+    ~EditAlarmDlg() override;
+    bool            getEvent(KAEvent&, Resource&);
+
+    // Methods to initialise values in the New Alarm dialogue.
+    void            setName(const QString&);
+    // N.B. setTime() must be called first to set the date-only characteristic,
+    //      followed by setRecurrence() if applicable.
+    void            setTime(const DateTime&);    // must be called first to set date-only value
+    void            setRecurrence(const KARecurrence&, const KCalendarCore::Duration& subRepeatInterval, int subRepeatCount);
+    void            setRepeatAtLogin();
+    virtual void    setAction(KAEvent::SubAction, const AlarmText& = AlarmText()) = 0;
+    void            setLateCancel(int minutes);
+    void            setShowInKOrganizer(bool);
+
+    QSize           sizeHint() const override    { return minimumSizeHint(); }
+
+    static int      instanceCount();
+    static QString  i18n_chk_ShowInKOrganizer();   // text of 'Show in KOrganizer' checkbox
+
+protected:
+    EditAlarmDlg(bool Template, KAEvent::SubAction, QWidget* parent = nullptr,
+                 GetResourceType = RES_PROMPT);
+    EditAlarmDlg(bool Template, const KAEvent*, bool newAlarm, QWidget* parent = nullptr,
+                 GetResourceType = RES_PROMPT, bool readOnly = false);
+    void            init(const KAEvent* event);
+    void            resizeEvent(QResizeEvent*) override;
+    void            showEvent(QShowEvent*) override;
+    void            closeEvent(QCloseEvent*) override;
+    bool            eventFilter(QObject*, QEvent*) override;
+    virtual QString type_caption() const = 0;
+    virtual void    type_init(QWidget* parent, QVBoxLayout* frameLayout) = 0;
+    virtual void    type_initValues(const KAEvent*) = 0;
+    virtual void    type_showOptions(bool more) = 0;
+    virtual void    setReadOnly(bool readOnly) = 0;
+    virtual void    saveState(const KAEvent*) = 0;
+    virtual bool    type_stateChanged() const = 0;
+    virtual void    type_setEvent(KAEvent&, const KADateTime&, const QString& name, const QString& text, int lateCancel, bool trial) = 0;
+    virtual KAEvent::Flags getAlarmFlags() const;
+    virtual bool    type_validate(bool trial) = 0;
+    virtual void    type_aboutToTry() {}
+    virtual void    type_executedTry(const QString& text, void* obj) { Q_UNUSED(text); Q_UNUSED(obj); }
+    virtual Reminder* createReminder(QWidget* parent)  { Q_UNUSED(parent); return nullptr; }
+    virtual CheckBox* type_createConfirmAckCheckbox(QWidget* parent)  { Q_UNUSED(parent); return nullptr; }
+    virtual bool    checkText(QString& result, bool showErrorMessage = true) const = 0;
+
+    void            showMainPage();
+    bool            isTemplate() const         { return mTemplate; }
+    bool            isNewAlarm() const         { return mNewAlarm; }
+    bool            dateOnly() const;
+    bool            isTimedRecurrence() const;
+    bool            showingMore() const        { return mShowingMore; }
+    Reminder*       reminder() const           { return mReminder; }
+    LateCancelSelector* lateCancel() const     { return mLateCancel; }
+
+protected Q_SLOTS:
+    virtual void    slotTry();
+    virtual void    slotHelp();      // Load Template
+    virtual void    slotDefault();   // More/Less Options
+    void            slotButtonClicked(QAbstractButton*);
+    void            contentsChanged();
+
+private Q_SLOTS:
+    void            slotRecurTypeChange(int repeatType);
+    void            slotRecurFrequencyChange();
+    void            slotEditDeferral();
+    void            slotShowMainPage();
+    void            slotShowRecurrenceEdit();
+    void            slotAnyTimeToggled(bool anyTime);
+    void            slotTemplateTimeType(QAbstractButton*);
+    void            slotSetSubRepetition();
+    void            slotResize();
+    void            focusFixTimer();
+
+private:
+    void            init(const KAEvent* event, GetResourceType getResource);
+    void            initValues(const KAEvent*);
+    void            setEvent(KAEvent&, const QString& text, bool trial);
+    bool            validate();
+    virtual bool    stateChanged() const;
+    void            showOptions(bool more);
+
+protected:
+    KAEvent::SubAction  mAlarmType;           // actual alarm type
+
+    QDialogButtonBox*   mButtonBox;
+    QAbstractButton*    mTryButton;
+    QAbstractButton*    mLoadTemplateButton {nullptr};
+    QAbstractButton*    mMoreLessButton;
+
+private:
+    static QList<EditAlarmDlg*> mWindowList;  // list of instances
+    QTabWidget*         mTabs;                // the tabs in the dialog
+    StackedScrollGroup* mTabScrollGroup;
+    int                 mMainPageIndex;
+    int                 mRecurPageIndex;
+    bool                mMainPageShown {false};          // true once the main tab has been displayed
+    bool                mRecurPageShown {false};         // true once the recurrence tab has been displayed
+    bool                mRecurSetDefaultEndDate {true};  // adjust default end date/time when recurrence tab is displayed
+
+    // Templates
+    ButtonGroup*        mTemplateTimeGroup;
+    RadioButton*        mTemplateDefaultTime;  // no alarm time is specified
+    RadioButton*        mTemplateUseTimeAfter; // alarm time is specified as an offset from current
+    RadioButton*        mTemplateAnyTime;      // alarms have date only, no time
+    RadioButton*        mTemplateUseTime;      // an alarm time is specified
+    TimeSpinBox*        mTemplateTimeAfter;    // the specified offset from the current time
+    TimeEdit*           mTemplateTime;         // the alarm time which is specified
+    QGroupBox*          mDeferGroup {nullptr};
+    QLabel*             mDeferTimeLabel;
+    QPushButton*        mDeferChangeButton {nullptr};
+
+    QLineEdit*          mName {nullptr};
+    AlarmTimeWidget*    mTimeWidget {nullptr};
+    LateCancelSelector* mLateCancel;
+    Reminder*           mReminder;             // null except for display alarms
+    CheckBox*           mShowInKorganizer {nullptr};
+
+    QFrame*             mMoreOptions;          // contains options hidden by default
+
+    RecurrenceEdit*     mRecurrenceEdit;
+
+    QString             mAlarmMessage;         // message text/file name/command/email message
+    DateTime            mAlarmDateTime;
+    DateTime            mDeferDateTime;
+    bool                mUseResourceEventId;   // whether to use mResourceEventId
+    QString             mResourceEventId;      // if non-null, save alarm in resource containing this event ID
+    Resource            mResource;             // resource to save event into, or invalid
+    int                 mDeferGroupHeight {0}; // height added by deferred time widget
+    int                 mDesktop;              // desktop to display the dialog in
+    QString             mEventId;              // UID of event being edited, or blank for new event
+    bool                mTemplate;             // editing an alarm template
+    bool                mNewAlarm;             // editing a new alarm
+    bool                mExpiredRecurrence;    // initially a recurrence which has expired
+    mutable bool        mChanged;              // controls other than deferral have changed since dialog was displayed
+    mutable bool        mOnlyDeferred;         // the only change made in the dialog was to the existing deferral
+    bool                mDesiredReadOnly;      // the specified read-only status of the dialog
+    bool                mReadOnly;             // the actual read-only status of the dialog
+    bool                mShowingMore {true};   // the More Options button has been clicked
+
+    // Initial state of all controls
+    KAEvent*            mSavedEvent {nullptr};
+    QString             mSavedName;             // mName value
+    QAbstractButton*    mSavedTemplateTimeType; // selected button in mTemplateTimeGroup
+    QTime               mSavedTemplateTime;     // mTemplateTime value
+    int                 mSavedTemplateAfterTime;// mTemplateAfterTime value
+    QString             mSavedTextFileCommandMessage;  // mTextMessageEdit/mFileMessageEdit/mCmdCommandEdit/mEmailMessageEdit value
+    KADateTime          mSavedDateTime;         // mTimeWidget value
+    KADateTime          mSavedDeferTime;        // mDeferDateTime value
+    int                 mSavedRecurrenceType;   // RecurrenceEdit::RepeatType value
+    int                 mSavedLateCancel;       // mLateCancel value
+    bool                mSavedShowInKorganizer; // mShowInKorganizer status
 };
 
 #endif // EDITDLG_H
diff --git a/src/editdlgtypes.cpp b/src/editdlgtypes.cpp
index 4923e84f..1659623c 100644
--- a/src/editdlgtypes.cpp
+++ b/src/editdlgtypes.cpp
@@ -596,7 +596,7 @@ bool EditDisplayAlarmDlg::type_stateChanged() const
 * Extract the data in the dialog specific to the alarm type and set up a
 * KAEvent from it.
 */
-void EditDisplayAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, const QString& text, int lateCancel, bool trial)
+void EditDisplayAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, const QString& name, const QString& text, int lateCancel, bool trial)
 {
     KAEvent::SubAction type;
     switch (mTypeCombo->currentIndex())
@@ -619,7 +619,7 @@ void EditDisplayAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, co
         fgColour = mFontColourButton->fgColour();
         font     = mFontColourButton->font();
     }
-    event = KAEvent(dt, text, bgColour, fgColour, font, type, lateCancel, getAlarmFlags());
+    event = KAEvent(dt, name, text, bgColour, fgColour, font, type, lateCancel, getAlarmFlags());
     if (type == KAEvent::MESSAGE)
     {
         if (AlarmText::checkIfEmail(text))
@@ -1022,10 +1022,10 @@ bool EditCommandAlarmDlg::type_stateChanged() const
 * Extract the data in the dialog specific to the alarm type and set up a
 * KAEvent from it.
 */
-void EditCommandAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, const QString& text, int lateCancel, bool trial)
+void EditCommandAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, const QString& name, const QString& text, int lateCancel, bool trial)
 {
     Q_UNUSED(trial);
-    event = KAEvent(dt, text, QColor(), QColor(), QFont(), KAEvent::COMMAND, lateCancel, getAlarmFlags());
+    event = KAEvent(dt, name, text, QColor(), QColor(), QFont(), KAEvent::COMMAND, lateCancel, getAlarmFlags());
     if (mCmdOutputGroup->checkedButton() == mCmdLogToFile)
         event.setLogFile(mCmdLogFileEdit->text());
 }
@@ -1412,10 +1412,10 @@ bool EditEmailAlarmDlg::type_stateChanged() const
 * Extract the data in the dialog specific to the alarm type and set up a
 * KAEvent from it.
 */
-void EditEmailAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, const QString& text, int lateCancel, bool trial)
+void EditEmailAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, const QString& name, const QString& text, int lateCancel, bool trial)
 {
     Q_UNUSED(trial);
-    event = KAEvent(dt, text, QColor(), QColor(), QFont(), KAEvent::EMAIL, lateCancel, getAlarmFlags());
+    event = KAEvent(dt, name, text, QColor(), QColor(), QFont(), KAEvent::EMAIL, lateCancel, getAlarmFlags());
     const uint from = mEmailFromList ? mEmailFromList->currentIdentity() : 0;
     event.setEmail(from, mEmailAddresses, mEmailSubjectEdit->text(), mEmailAttachments);
 }
@@ -1722,11 +1722,11 @@ bool EditAudioAlarmDlg::type_stateChanged() const
 * Extract the data in the dialog specific to the alarm type and set up a
 * KAEvent from it.
 */
-void EditAudioAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, const QString& text, int lateCancel, bool trial)
+void EditAudioAlarmDlg::type_setEvent(KAEvent& event, const KADateTime& dt, const QString& name, const QString& text, int lateCancel, bool trial)
 {
     Q_UNUSED(text);
     Q_UNUSED(trial);
-    event = KAEvent(dt, QString(), QColor(), QColor(), QFont(), KAEvent::AUDIO, lateCancel, getAlarmFlags());
+    event = KAEvent(dt, name, QString(), QColor(), QColor(), QFont(), KAEvent::AUDIO, lateCancel, getAlarmFlags());
     float volume, fadeVolume;
     int   fadeSecs;
     mSoundConfig->getVolume(volume, fadeVolume, fadeSecs);
diff --git a/src/editdlgtypes.h b/src/editdlgtypes.h
index 3f42b37f..52e6dc9a 100644
--- a/src/editdlgtypes.h
+++ b/src/editdlgtypes.h
@@ -72,7 +72,7 @@ protected:
     void            setReadOnly(bool readOnly) override;
     void            saveState(const KAEvent*) override;
     bool            type_stateChanged() const override;
-    void            type_setEvent(KAEvent&, const KADateTime&, const QString& text, int lateCancel, bool trial) override;
+    void            type_setEvent(KAEvent&, const KADateTime&, const QString& name, const QString& text, int lateCancel, bool trial) override;
     KAEvent::Flags  getAlarmFlags() const override;
     bool            type_validate(bool trial) override { Q_UNUSED(trial); return true; }
     CheckBox*       type_createConfirmAckCheckbox(QWidget* parent) override  { mConfirmAck = createConfirmAckCheckbox(parent); return mConfirmAck; }
@@ -159,7 +159,7 @@ protected:
     void            setReadOnly(bool readOnly) override;
     void            saveState(const KAEvent*) override;
     bool            type_stateChanged() const override;
-    void            type_setEvent(KAEvent&, const KADateTime&, const QString& text, int lateCancel, bool trial) override;
+    void            type_setEvent(KAEvent&, const KADateTime&, const QString& name, const QString& text, int lateCancel, bool trial) override;
     KAEvent::Flags  getAlarmFlags() const override;
     bool            type_validate(bool trial) override;
     void            type_executedTry(const QString& text, void* obj) override;
@@ -214,7 +214,7 @@ protected:
     void            setReadOnly(bool readOnly) override;
     void            saveState(const KAEvent*) override;
     bool            type_stateChanged() const override;
-    void            type_setEvent(KAEvent&, const KADateTime&, const QString& text, int lateCancel, bool trial) override;
+    void            type_setEvent(KAEvent&, const KADateTime&, const QString& name, const QString& text, int lateCancel, bool trial) override;
     KAEvent::Flags  getAlarmFlags() const override;
     bool            type_validate(bool trial) override;
     void            type_aboutToTry() override;
@@ -276,7 +276,7 @@ protected:
     void            setReadOnly(bool readOnly) override;
     void            saveState(const KAEvent*) override;
     bool            type_stateChanged() const override;
-    void            type_setEvent(KAEvent&, const KADateTime&, const QString& text, int lateCancel, bool trial) override;
+    void            type_setEvent(KAEvent&, const KADateTime&, const QString& name, const QString& text, int lateCancel, bool trial) override;
     KAEvent::Flags  getAlarmFlags() const override;
     bool            type_validate(bool trial) override { Q_UNUSED(trial); return true; }
     void            type_executedTry(const QString& text, void* obj) override;
diff --git a/src/eventlistview.cpp b/src/eventlistview.cpp
index 2eb0790f..05943ced 100644
--- a/src/eventlistview.cpp
+++ b/src/eventlistview.cpp
@@ -174,6 +174,7 @@ bool EventListView::viewportEvent(QEvent* e)
             {
                 EventListModel* m = qobject_cast<EventListModel*>(model());
                 if (index.column() == ResourceDataModelBase::TextColumn
+                ||  index.column() == ResourceDataModelBase::NameColumn
                 ||  !m  ||  m->event(index).commandError() == KAEvent::CMD_NO_ERROR)
                 {
                     // Single line tooltip. Only display it if the text column
diff --git a/src/kalarmapp.cpp b/src/kalarmapp.cpp
index c6b8baf2..b41b854b 100644
--- a/src/kalarmapp.cpp
+++ b/src/kalarmapp.cpp
@@ -513,6 +513,7 @@ int KAlarmApp::activateInstance(const QStringList& args, const QString& workingD
                         exitCode = 1;
                         break;
                     }
+                    editDlg->setName(options->name());
                     if (options->alarmTime().isValid())
                         editDlg->setTime(options->alarmTime());
                     if (options->recurrence())
@@ -600,7 +601,7 @@ int KAlarmApp::activateInstance(const QStringList& args, const QString& workingD
                     // running, this new instance will not exit after the dialogue is closed.
                     // This is deliberate, since exiting would mean that KAlarm wouldn't
                     // trigger the new alarm.
-                    KAlarm::editNewAlarm(options->templateName());
+                    KAlarm::editNewAlarm(options->name());
 
                     createOnlyMainWindow();   // prevent the application from quitting
                 }
@@ -613,9 +614,10 @@ int KAlarmApp::activateInstance(const QStringList& args, const QString& workingD
                     exitCode = 1;
                 else
                 {
-                    if (!scheduleEvent(options->editAction(), options->text(), options->alarmTime(),
-                                       options->lateCancel(), options->flags(), options->bgColour(),
-                                       options->fgColour(), QFont(), options->audioFile(), options->audioVolume(),
+                    if (!scheduleEvent(options->editAction(), options->name(), options->text(),
+                                       options->alarmTime(), options->lateCancel(), options->flags(),
+                                       options->bgColour(), options->fgColour(), QFont(),
+                                       options->audioFile(), options->audioVolume(),
                                        options->reminderMinutes(), (options->recurrence() ? *options->recurrence() : KARecurrence()),
                                        options->subRepeatInterval(), options->subRepeatCount(),
                                        options->fromID(), options->addressees(),
@@ -1661,9 +1663,10 @@ bool KAlarmApp::needWindowFocusFix() const
 * to command line options.
 * Reply = true unless there was a parameter error or an error opening calendar file.
 */
-bool KAlarmApp::scheduleEvent(KAEvent::SubAction action, const QString& text, const KADateTime& dateTime,
-                              int lateCancel, KAEvent::Flags flags, const QColor& bg, const QColor& fg,
-                              const QFont& font, const QString& audioFile, float audioVolume, int reminderMinutes,
+bool KAlarmApp::scheduleEvent(KAEvent::SubAction action, const QString& name, const QString& text,
+                              const KADateTime& dateTime, int lateCancel, KAEvent::Flags flags,
+                              const QColor& bg, const QColor& fg, const QFont& font,
+                              const QString& audioFile, float audioVolume, int reminderMinutes,
                               const KARecurrence& recurrence, const KCalendarCore::Duration& repeatInterval, int repeatCount,
                               uint mailFromID, const KCalendarCore::Person::List& mailAddresses,
                               const QString& mailSubject, const QStringList& mailAttachments)
@@ -1684,7 +1687,7 @@ bool KAlarmApp::scheduleEvent(KAEvent::SubAction action, const QString& text, co
     if (!dateTime.isDateOnly())
         alarmTime.setTime(QTime(alarmTime.time().hour(), alarmTime.time().minute(), 0));
 
-    KAEvent event(alarmTime, text, bg, fg, font, action, lateCancel, flags, true);
+    KAEvent event(alarmTime, name, text, bg, fg, font, action, lateCancel, flags, true);
     if (reminderMinutes)
     {
         const bool onceOnly = flags & KAEvent::REMINDER_ONCE;
diff --git a/src/kalarmapp.h b/src/kalarmapp.h
index 0ebf9eff..fce8bfe3 100644
--- a/src/kalarmapp.h
+++ b/src/kalarmapp.h
@@ -93,9 +93,10 @@ public:
     bool               windowFocusBroken() const;
     bool               needWindowFocusFix() const;
     // Methods called indirectly by the D-Bus interface
-    bool               scheduleEvent(KAEvent::SubAction, const QString& text, const KADateTime&,
-                                     int lateCancel, KAEvent::Flags flags, const QColor& bg, const QColor& fg,
-                                     const QFont&, const QString& audioFile, float audioVolume,
+    bool               scheduleEvent(KAEvent::SubAction, const QString& name, const QString& text,
+                                     const KADateTime&, int lateCancel, KAEvent::Flags flags,
+                                     const QColor& bg, const QColor& fg, const QFont&,
+                                     const QString& audioFile, float audioVolume,
                                      int reminderMinutes, const KARecurrence& recurrence,
                                      const KCalendarCore::Duration& repeatInterval, int repeatCount,
                                      uint mailFromID = 0, const KCalendarCore::Person::List& mailAddresses = KCalendarCore::Person::List(),
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index d3bf7db7..1b1e0cf5 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1276,7 +1276,7 @@ void MainWindow::executeDropEvent(MainWindow* win, QDropEvent* e)
             KAEvent::Flags flags = KAEvent::DEFAULT_FONT;
             if (start.isDateOnly())
                 flags |= KAEvent::ANY_TIME;
-            KAEvent ev(start, alarmText.displayText(), Preferences::defaultBgColour(), Preferences::defaultFgColour(),
+            KAEvent ev(start, todo->summary(), alarmText.displayText(), Preferences::defaultBgColour(), Preferences::defaultFgColour(),
                        QFont(), KAEvent::MESSAGE, 0, flags, true);
             ev.startChanges();
             if (todo->recurs())
diff --git a/src/prefdlg.cpp b/src/prefdlg.cpp
index 97534cd0..8c93bf15 100644
--- a/src/prefdlg.cpp
+++ b/src/prefdlg.cpp
@@ -445,10 +445,20 @@ MiscPrefTab::MiscPrefTab(StackedScrollGroup* scrollGroup)
     mQuitWarn->setWhatsThis(xi18nc("@info:whatsthis", "Check to display a warning prompt before quitting <application>KAlarm</application>."));
     vlayout->addWidget(mQuitWarn, 0, Qt::AlignLeft);
 
-    // Confirm alarm deletion?
+    // Use alarm names?
     QWidget* widget = new QWidget;  // this is for consistent left alignment
     topLayout()->addWidget(widget);
     QHBoxLayout* hbox = new QHBoxLayout(widget);
+    mUseAlarmNames = new QCheckBox(i18nc("@option:check", "Use alarm names"));
+    mUseAlarmNames->setMinimumSize(mUseAlarmNames->sizeHint());
+    mUseAlarmNames->setWhatsThis(i18nc("@info:whatsthis", "Check to have the option to give each alarm a name. This is a convenience to help you to identify alarms."));
+    hbox->addWidget(mUseAlarmNames);
+    hbox->addStretch();    // left adjust the controls
+
+    // Confirm alarm deletion?
+    widget = new QWidget;  // this is for consistent left alignment
+    topLayout()->addWidget(widget);
+    hbox = new QHBoxLayout(widget);
     mConfirmAlarmDeletion = new QCheckBox(i18nc("@option:check", "Confirm alarm deletions"));
     mConfirmAlarmDeletion->setMinimumSize(mConfirmAlarmDeletion->sizeHint());
     mConfirmAlarmDeletion->setWhatsThis(i18nc("@info:whatsthis", "Check to be prompted for confirmation each time you delete an alarm."));
@@ -527,6 +537,7 @@ void MiscPrefTab::restore(bool defaults, bool)
 {
     mAutoStart->setChecked(defaults ? true : Preferences::autoStart());
     mQuitWarn->setChecked(Preferences::quitWarn());
+    mUseAlarmNames->setChecked(Preferences::useAlarmName());
     mConfirmAlarmDeletion->setChecked(Preferences::confirmAlarmDeletion());
     mDefaultDeferTime->setValue(Preferences::defaultDeferTime());
     QString xtermCmd = Preferences::cmdXTermCommand();
@@ -587,6 +598,9 @@ void MiscPrefTab::apply(bool syncToDisc)
             Preferences::setNoAutoStart(false);
         Preferences::setAutoStartChangedByUser(true);  // prevent prompting the user on quit, about start-at-login
     }
+    b = mUseAlarmNames->isChecked();
+    if (b != Preferences::useAlarmName())
+        Preferences::setUseAlarmName(b);
     b = mConfirmAlarmDeletion->isChecked();
     if (b != Preferences::confirmAlarmDeletion())
         Preferences::setConfirmAlarmDeletion(b);
diff --git a/src/prefdlg_p.h b/src/prefdlg_p.h
index e46cbc0b..e4f9da43 100644
--- a/src/prefdlg_p.h
+++ b/src/prefdlg_p.h
@@ -83,6 +83,7 @@ private:
 
     QCheckBox*    mAutoStart;
     QCheckBox*    mQuitWarn;
+    QCheckBox*    mUseAlarmNames;
     QCheckBox*    mConfirmAlarmDeletion;
     TimeSpinBox*  mDefaultDeferTime;
     ButtonGroup*  mXtermType;
diff --git a/src/resources/eventmodel.cpp b/src/resources/eventmodel.cpp
index 74c76e74..41880022 100644
--- a/src/resources/eventmodel.cpp
+++ b/src/resources/eventmodel.cpp
@@ -264,6 +264,33 @@ bool AlarmListModel::filterAcceptsColumn(int sourceCol, const QModelIndex& ix) c
     return (sourceCol != ResourceDataModelBase::TemplateNameColumn);
 }
 
+/******************************************************************************
+* Return the data for a given index from the model.
+*/
+QVariant AlarmListModel::data(const QModelIndex& ix, int role) const
+{
+    if (mReplaceBlankName  &&  ix.column() == NameColumn)
+    {
+        // It's the Name column, and the name is being replaced by the alarm text
+        // when the name is blank. Return the alarm text instead for display and
+        // tooltip.
+        switch (role)
+        {
+            case Qt::DisplayRole:
+            case Qt::ToolTipRole:
+                if (EventListModel::data(ix, role).toString().isEmpty())
+                {
+                    const QModelIndex& ix2 = ix.siblingAtColumn(TextColumn);
+                    return EventListModel::data(ix2, role);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+    return EventListModel::data(ix, role);
+}
+
 QVariant AlarmListModel::headerData(int section, Qt::Orientation orientation, int role) const
 {
     if (orientation == Qt::Horizontal)
diff --git a/src/resources/eventmodel.h b/src/resources/eventmodel.h
index c00c012b..5df3e5a6 100644
--- a/src/resources/eventmodel.h
+++ b/src/resources/eventmodel.h
@@ -109,7 +109,7 @@ class AlarmListModel : public EventListModel
 public:
     enum   // data columns
     {
-        TimeColumn = 0, TimeToColumn, RepeatColumn, ColourColumn, TypeColumn, TextColumn,
+        TimeColumn = 0, TimeToColumn, RepeatColumn, ColourColumn, TypeColumn, NameColumn, TextColumn,
         ColumnCount
     };
 
@@ -133,6 +133,9 @@ public:
      */
     CalEvent::Types eventTypeFilter() const   { return mFilterTypes; }
 
+    /** Set whether to replace a blank alarm name with the alarm text. */
+    void setReplaceBlankName(bool replace)   { mReplaceBlankName = replace; }
+
     int  columnCount(const QModelIndex& = QModelIndex()) const  override { return ColumnCount; }
     QVariant headerData(int section, Qt::Orientation, int role = Qt::DisplayRole) const override;
 
@@ -141,10 +144,12 @@ protected:
 
     bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
     bool filterAcceptsColumn(int sourceCol, const QModelIndex& sourceParent) const override;
+    QVariant data(const QModelIndex&, int role) const override;
 
 private:
     static AlarmListModel* mAllInstance;
-    CalEvent::Types mFilterTypes;  // types of events contained in this model
+    CalEvent::Types mFilterTypes;    // types of events contained in this model
+    bool mReplaceBlankName {false};  // replace Name with Text for Qt::DisplayRole if Name is blank
 };
 
 
diff --git a/src/resources/resourcedatamodelbase.cpp b/src/resources/resourcedatamodelbase.cpp
index 9837fd30..14bea19d 100644
--- a/src/resources/resourcedatamodelbase.cpp
+++ b/src/resources/resourcedatamodelbase.cpp
@@ -125,6 +125,8 @@ QVariant ResourceDataModelBase::headerData(int section, Qt::Orientation orientat
                         return (role == Qt::DisplayRole) ? QString() : i18nc("@title:column", "Color");
                     case TypeColumn:
                         return (role == Qt::DisplayRole) ? QString() : i18nc("@title:column", "Type");
+                    case NameColumn:
+                        return i18nc("@title:column", "Name");
                     case TextColumn:
                         return i18nc("@title:column", "Message, File or Command");
                     case TemplateNameColumn:
@@ -396,31 +398,33 @@ QVariant ResourceDataModelBase::eventData(int role, int column, const KAEvent& e
                         return QStringLiteral("%1").arg(event.actionSubType(), 2, 10, QLatin1Char('0'));
                 }
                 break;
-            case TextColumn:
+            case NameColumn:
+            case TemplateNameColumn:
                 switch (role)
                 {
                     case Qt::BackgroundRole:
                         calendarColour = true;
                         break;
                     case Qt::DisplayRole:
-                    case SortRole:
-                        return AlarmText::summary(event, 1);
                     case Qt::ToolTipRole:
-                        return AlarmText::summary(event, 10);
-                    default:
-                        break;
+                        return event.name();
+                    case SortRole:
+                        return event.name().toUpper();
                 }
                 break;
-            case TemplateNameColumn:
+            case TextColumn:
                 switch (role)
                 {
                     case Qt::BackgroundRole:
                         calendarColour = true;
                         break;
                     case Qt::DisplayRole:
-                        return event.templateName();
                     case SortRole:
-                        return event.templateName().toUpper();
+                        return AlarmText::summary(event, 1);
+                    case Qt::ToolTipRole:
+                        return AlarmText::summary(event, 10);
+                    default:
+                        break;
                 }
                 break;
             default:
@@ -562,6 +566,8 @@ QString ResourceDataModelBase::whatsThisText(int column)
             return i18nc("@info:whatsthis", "Background color of alarm message");
         case TypeColumn:
             return i18nc("@info:whatsthis", "Alarm type (message, file, command or email)");
+        case NameColumn:
+            return i18nc("@info:whatsthis", "Alarm name, or alarm text if name is blank");
         case TextColumn:
             return i18nc("@info:whatsthis", "Alarm message text, URL of text file to display, command to execute, or email subject line");
         case TemplateNameColumn:
diff --git a/src/resources/resourcedatamodelbase.h b/src/resources/resourcedatamodelbase.h
index 243c4b20..f11b5b94 100644
--- a/src/resources/resourcedatamodelbase.h
+++ b/src/resources/resourcedatamodelbase.h
@@ -41,7 +41,7 @@ public:
     enum
     {
         // Item columns
-        TimeColumn = 0, TimeToColumn, RepeatColumn, ColourColumn, TypeColumn, TextColumn,
+        TimeColumn = 0, TimeToColumn, RepeatColumn, ColourColumn, TypeColumn, NameColumn, TextColumn,
         TemplateNameColumn,
         ColumnCount
     };
diff --git a/src/resourcescalendar.cpp b/src/resourcescalendar.cpp
index a0509818..d958a2ff 100644
--- a/src/resourcescalendar.cpp
+++ b/src/resourcescalendar.cpp
@@ -514,7 +514,7 @@ KAEvent ResourcesCalendar::templateEvent(const QString& templateName)
     const QVector<KAEvent> eventlist = events(CalEvent::TEMPLATE);
     for (const KAEvent& event : eventlist)
     {
-        if (event.templateName() == templateName)
+        if (event.name() == templateName)
             return event;
     }
     return KAEvent();
diff --git a/src/templatemenuaction.cpp b/src/templatemenuaction.cpp
index 3a843664..78275cc6 100644
--- a/src/templatemenuaction.cpp
+++ b/src/templatemenuaction.cpp
@@ -40,7 +40,7 @@ void TemplateMenuAction::slotInitMenu()
     const QVector<KAEvent> templates = KAlarm::templateList();
     for (const KAEvent& templ : templates)
     {
-        const QString name = templ.templateName();
+        const QString name = templ.name();
         int j = 0;
         for (int jend = sorted.count();
              j < jend  &&  QString::localeAwareCompare(name, sorted[j]) > 0;
diff --git a/src/undo.cpp b/src/undo.cpp
index 6879dd57..086caa04 100644
--- a/src/undo.cpp
+++ b/src/undo.cpp
@@ -643,7 +643,7 @@ UndoItem::~UndoItem()
 */
 QString UndoItem::description(const KAEvent& event) const
 {
-    return (mCalendar == CalEvent::TEMPLATE) ? event.templateName() : AlarmText::summary(event);
+    return (mCalendar == CalEvent::TEMPLATE) ? event.name() : AlarmText::summary(event);
 }
 
 /******************************************************************************


More information about the kde-doc-english mailing list