Commit 22b19b01 authored by David Jarvie's avatar David Jarvie
Browse files

Bug 448212: Fix crash after Defer is selected in alarm notification message

The crash occurred when the defer alarm dialog was closed after
clicking 'Defer' in an alarm notification message.
parent aa94131c
Pipeline #121756 passed with stage
in 1 minute and 22 seconds
KAlarm Change Log
=== Version 3.3.5 (KDE Applications 21.12.2) --- 10 January 2022 ===
=== Version 3.3.5 (KDE Applications 21.12.2) --- 11 January 2022 ===
* Fix crash after Defer is selected in alarm notification message [KDE Bug 448212]
* Fix regression introduced in version 3.1.0:
Make auto-close work for message windows.
......
/*
* mainwindow.cpp - main application window
* Program: kalarm
* SPDX-FileCopyrightText: 2001-2021 David Jarvie <djarvie@kde.org>
* SPDX-FileCopyrightText: 2001-2022 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -12,9 +12,11 @@
#include "alarmlistview.h"
#include "birthdaydlg.h"
#include "datepicker.h"
#include "deferdlg.h"
#include "functions.h"
#include "kalarmapp.h"
#include "kamail.h"
#include "messagedisplay.h"
#include "newalarmaction.h"
#include "prefdlg.h"
#include "preferences.h"
......@@ -1700,4 +1702,46 @@ void MainWindow::editAlarmDeleted(QObject* obj)
mEditAlarmMap.remove(static_cast<EditAlarmDlg*>(obj));
}
/******************************************************************************
* Called when the Defer button is clicked in an alarm window or notification.
* This controls the defer dialog created by the alarm display, and allows it to
* remain unaffected by the alarm display closing.
* See MessageWindow::slotEdit() for more information.
*/
void MainWindow::showDeferAlarmDlg(MessageDisplay::DeferDlgData* data)
{
DeferAlarmDlg* dlg = data->dlg;
mDeferAlarmMap[dlg] = data;
connect(dlg, &KEditToolBar::finished, this, &MainWindow::deferAlarmDlgDone);
connect(dlg, &KEditToolBar::destroyed, this, &MainWindow::deferAlarmDlgDeleted);
dlg->setAttribute(Qt::WA_DeleteOnClose, true); // ensure no memory leaks
dlg->show();
}
/******************************************************************************
* Called when OK is clicked in the defer alarm dialog shown by
* showDeferAlarmDlg().
*/
void MainWindow::deferAlarmDlgDone(int result)
{
processDeferAlarmDlg(sender(), result);
}
/******************************************************************************
* Called when the defer alarm dialog shown by showDeferAlarmDlg() is complete.
* Removes the dialog from the pending list, and processes the result.
*/
void MainWindow::processDeferAlarmDlg(QObject* obj, int result)
{
auto dlg = qobject_cast<DeferAlarmDlg*>(obj);
if (!dlg)
return;
QMap<DeferAlarmDlg*, MessageDisplay::DeferDlgData*>::Iterator it = mDeferAlarmMap.find(dlg);
if (it == mDeferAlarmMap.end())
return;
MessageDisplay::DeferDlgData* data = it.value();
mDeferAlarmMap.erase(it);
MessageDisplay::processDeferDlg(data, result);
}
// vim: et sw=4:
/*
* mainwindow.h - main application window
* Program: kalarm
* SPDX-FileCopyrightText: 2001-2021 David Jarvie <djarvie@kde.org>
* SPDX-FileCopyrightText: 2001-2022 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -12,6 +12,7 @@
#include "editdlg.h"
#include "mainwindowbase.h"
#include "messagedisplay.h"
#include "undo.h"
#include <KAlarmCal/KAEvent>
......@@ -37,6 +38,7 @@ class KHamburgerMenu;
class AlarmListModel;
class AlarmListView;
class DatePicker;
class DeferAlarmDlg;
class NewAlarmAction;
class TemplateDlg;
class ResourceSelector;
......@@ -55,6 +57,7 @@ public:
void selectEvent(const QString& eventId);
KAEvent selectedEvent() const;
void editAlarm(EditAlarmDlg*, const KAEvent&);
void showDeferAlarmDlg(MessageDisplay::DeferDlgData*);
void clearSelection();
QMenu* resourceContextMenu();
bool eventFilter(QObject*, QEvent*) override;
......@@ -131,6 +134,8 @@ private Q_SLOTS:
void showErrorMessage(const QString&);
void editAlarmOk();
void editAlarmDeleted(QObject*);
void deferAlarmDlgDone(int result);
void deferAlarmDlgDeleted(QObject* obj) { processDeferAlarmDlg(obj, QDialog::Rejected); }
private:
using WindowList = QVector<MainWindow*>;
......@@ -143,6 +148,7 @@ private:
void setSplitterSizes();
void initUndoMenu(QMenu*, Undo::Type);
void slotDelete(bool force);
void processDeferAlarmDlg(QObject*, int result);
static void enableTemplateMenuItem(bool);
static WindowList mWindowList; // active main windows
......@@ -154,7 +160,8 @@ private:
DatePicker* mDatePicker; // date navigator widget
QSplitter* mSplitter; // splits window into list and resource selector
QWidget* mPanel; // panel containing resource selector & date navigator
QMap<EditAlarmDlg*, KAEvent> mEditAlarmMap; // edit alarm dialogs to be handled by this window
QMap<EditAlarmDlg*, KAEvent> mEditAlarmMap; // edit alarm dialogs to be handled by this window
QMap<DeferAlarmDlg*, MessageDisplay::DeferDlgData*> mDeferAlarmMap; // defer alarm dialogs to be handled by this window
KToggleAction* mActionShowMenuBar;
KToggleAction* mActionToggleResourceSel;
KToggleAction* mActionToggleDateNavigator;
......
/*
* messagedisplay.cpp - base class to display an alarm or error message
* Program: kalarm
* SPDX-FileCopyrightText: 2001-2021 David Jarvie <djarvie@kde.org>
* SPDX-FileCopyrightText: 2001-2022 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -13,6 +13,7 @@
#include "displaycalendar.h"
#include "functions.h"
#include "kalarmapp.h"
#include "mainwindow.h"
#include "resourcescalendar.h"
#include "resources/resources.h"
#include "lib/messagebox.h"
......@@ -204,17 +205,18 @@ MessageDisplay::DeferDlgData::~DeferDlgData()
/******************************************************************************
* Create a defer message dialog.
*/
MessageDisplay::DeferDlgData* MessageDisplay::createDeferDlg(bool displayClosing)
MessageDisplay::DeferDlgData* MessageDisplay::createDeferDlg(QObject* thisObject, bool displayClosing)
{
DeferAlarmDlg* dlg = new DeferAlarmDlg(KADateTime::currentDateTime(Preferences::timeSpec()).addSecs(60), mDateTime().isDateOnly(), false, displayParent());
DeferAlarmDlg* dlg = new DeferAlarmDlg(KADateTime::currentDateTime(Preferences::timeSpec()).addSecs(60), mDateTime().isDateOnly(), false, MainWindow::mainMainWindow());
dlg->setObjectName(QStringLiteral("DeferDlg")); // used by LikeBack
dlg->setDeferMinutes(mDefaultDeferMinutes() > 0 ? mDefaultDeferMinutes() : Preferences::defaultDeferTime());
dlg->setLimit(mEvent());
auto data = new DeferDlgData(dlg);
auto data = new DeferDlgData(this, dlg);
if (!displayClosing)
data->displayObj = thisObject;
data->eventId = mEventId();
data->alarmType = mAlarmType();
data->commandError = mCommandError();
data->displayOpen = !displayClosing;
return data;
}
......@@ -223,7 +225,16 @@ MessageDisplay::DeferDlgData* MessageDisplay::createDeferDlg(bool displayClosing
*/
void MessageDisplay::executeDeferDlg(DeferDlgData* data)
{
if (data->dlg->exec() == QDialog::Accepted)
MainWindow::mainMainWindow()->showDeferAlarmDlg(data);
}
/******************************************************************************
* Process the result of a defer message dialog.
*/
void MessageDisplay::processDeferDlg(DeferDlgData* data, int result)
{
MessageDisplay* display = data->displayObj ? data->display : nullptr;
if (result == QDialog::Accepted)
{
const DateTime dateTime = data->dlg->getDateTime();
const int delayMins = data->dlg->deferMinutes();
......@@ -240,10 +251,10 @@ void MessageDisplay::executeDeferDlg(DeferDlgData* data)
newev.defer(dateTime, (data->alarmType & KAAlarm::REMINDER_ALARM), true);
newev.setDeferDefaultMinutes(delayMins);
KAlarm::updateEvent(newev, data->dlg, true);
if (data->displayOpen)
if (display)
{
if (newev.deferred())
mNoPostAction() = true;
display->mNoPostAction() = true;
}
}
else
......@@ -256,12 +267,13 @@ void MessageDisplay::executeDeferDlg(DeferDlgData* data)
{
// The event doesn't exist any more !?!, so recurrence data,
// flags, and more, have been lost.
KAMessageBox::error(displayParent(), xi18nc("@info", "<para>Cannot defer alarm:</para><para>Alarm not found.</para>"));
if (data->displayOpen)
QWidget* par = display ? display->displayParent() : MainWindow::mainMainWindow();
KAMessageBox::error(par, xi18nc("@info", "<para>Cannot defer alarm:</para><para>Alarm not found.</para>"));
if (display)
{
raiseDisplay();
enableDeferButton(false);
enableEditButton(false);
display->raiseDisplay();
display->enableDeferButton(false);
display->enableEditButton(false);
}
delete data;
return;
......@@ -273,10 +285,10 @@ void MessageDisplay::executeDeferDlg(DeferDlgData* data)
// Add the event back into the calendar file, retaining its ID
// and not updating KOrganizer.
KAlarm::addEvent(event2, resource, data->dlg, KAlarm::USE_EVENT_ID);
if (data->displayOpen)
if (display)
{
if (event2.deferred())
mNoPostAction() = true;
display->mNoPostAction() = true;
}
// Finally delete it from the archived calendar now that it has
// been reactivated.
......@@ -290,16 +302,16 @@ void MessageDisplay::executeDeferDlg(DeferDlgData* data)
// so start it if necessary so that the deferred alarm will be shown.
theApp()->displayTrayIcon(true);
}
if (data->displayOpen)
if (display)
{
mHelper->mNoCloseConfirm = true; // allow window to close without confirmation prompt
closeDisplay();
display->mHelper->mNoCloseConfirm = true; // allow window to close without confirmation prompt
display->closeDisplay();
}
}
else
{
if (data->displayOpen)
raiseDisplay();
if (display)
display->raiseDisplay();
}
delete data;
}
......
/*
* messagedisplay.h - base class to display an alarm or error message
* Program: kalarm
* SPDX-FileCopyrightText: 2001-2020 David Jarvie <djarvie@kde.org>
* SPDX-FileCopyrightText: 2001-2022 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -109,6 +109,25 @@ public:
static int instanceCount(bool excludeAlwaysHidden = false) { return MessageDisplayHelper::instanceCount(excludeAlwaysHidden); }
// Holds data required by defer dialog.
// This is needed because the display may have closed when the defer dialog
// is opened.
struct DeferDlgData
{
DeferAlarmDlg* dlg;
QPointer<QObject> displayObj {nullptr};
MessageDisplay* display;
EventId eventId;
KAAlarm::Type alarmType;
KAEvent::CmdErrType commandError;
DeferDlgData(MessageDisplay* m, DeferAlarmDlg* d) : dlg(d), display(m) {}
~DeferDlgData();
};
/** For use by MainWindow only. Called when a defer alarm dialog completes. */
static void processDeferDlg(DeferDlgData*, int result);
protected:
MessageDisplay();
MessageDisplay(const KAEvent& event, const KAAlarm& alarm, int flags);
......@@ -132,23 +151,8 @@ protected:
virtual void enableDeferButton(bool enable) = 0;
virtual void enableEditButton(bool enable) = 0;
// Holds data required by defer dialog.
// This is needed because the display may have closed when the defer dialog
// is opened.
struct DeferDlgData
{
DeferAlarmDlg* dlg;
EventId eventId;
KAAlarm::Type alarmType;
KAEvent::CmdErrType commandError;
bool displayOpen;
DeferDlgData(DeferAlarmDlg* d) : dlg(d) {}
~DeferDlgData();
};
DeferDlgData* createDeferDlg(bool displayClosing);
void executeDeferDlg(DeferDlgData* data);
DeferDlgData* createDeferDlg(QObject* thisObject, bool displayClosing);
static void executeDeferDlg(DeferDlgData*);
MessageDisplayHelper* mHelper;
......
/*
* messagenotification.cpp - displays an alarm message in a system notification
* Program: kalarm
* SPDX-FileCopyrightText: 2020 David Jarvie <djarvie@kde.org>
* SPDX-FileCopyrightText: 2020-2022 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -594,7 +594,7 @@ void MessageNotification::buttonActivated(unsigned int index)
}
else if (i == mDeferButtonIndex + 1)
{
DeferDlgData* data = createDeferDlg(true);
DeferDlgData* data = createDeferDlg(this, true);
executeDeferDlg(data);
}
}
......
/*
* messagewindow.cpp - displays an alarm message in a window
* Program: kalarm
* SPDX-FileCopyrightText: 2001-2021 David Jarvie <djarvie@kde.org>
* SPDX-FileCopyrightText: 2001-2022 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -1184,7 +1184,7 @@ void MessageWindow::activeWindowChanged(WId win)
*/
void MessageWindow::slotDefer()
{
mDeferData = createDeferDlg(false);
mDeferData = createDeferDlg(this, false);
if (windowFlags() & Qt::X11BypassWindowManagerHint)
mDeferData->dlg->setWindowFlags(mDeferData->dlg->windowFlags() | Qt::X11BypassWindowManagerHint);
if (!Preferences::modalMessages())
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment