sw: fix crash when dropdown field dialog outlives its field
In COOL, EditDropDownFieldDlg runs asynchronously while the user can keep editing the document. If anything destroys or replaces the underlying SwFormatField (undo, edits, spell-check replacement, ...) before the user accepts the dialog, the raw SwDropDownField* stored in the dialog dangles and Apply() crashes in GetPar1(). Listen on the owning SwFormatField and null out the field pointers on REMOVED/CHANGED/Dying so the existing guard in Apply() turns the click into a safe no-op. Change-Id: I7f52a926d3cbea259dc2b3f54618304e4c93db1d Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/2858 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins CPCI <releng@collaboraoffice.com> Signed-off-by: Andras Timar <andras.timar@collabora.com> Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2972 (cherry picked from commit 3d0366e6726a25ce1dbc65eda5211c8f079dcc22) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206203 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
committed by
Xisco Fauli
parent
0363353a99
commit
632f432d2f
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <wrtsh.hxx>
|
||||
#include <fldbas.hxx>
|
||||
#include <fmtfld.hxx>
|
||||
#include <DropDownFieldDialog.hxx>
|
||||
#include <flddropdown.hxx>
|
||||
|
||||
@@ -35,6 +36,7 @@ sw::DropDownFieldDialog::DropDownFieldDialog(weld::Widget *pParent, SwWrtShell &
|
||||
: GenericDialogController(pParent, u"modules/swriter/ui/dropdownfielddialog.ui"_ustr, u"DropdownFieldDialog"_ustr)
|
||||
, m_rSh( rS )
|
||||
, m_pDropField(nullptr)
|
||||
, m_pFormatField(nullptr)
|
||||
, m_pPressedButton(nullptr)
|
||||
, m_xListItemsLB(m_xBuilder->weld_tree_view(u"list"_ustr))
|
||||
, m_xOKPB(m_xBuilder->weld_button(u"ok"_ustr))
|
||||
@@ -64,6 +66,11 @@ sw::DropDownFieldDialog::DropDownFieldDialog(weld::Widget *pParent, SwWrtShell &
|
||||
{
|
||||
|
||||
m_pDropField = static_cast<SwDropDownField*>(pField);
|
||||
// Listen on the owning SwFormatField so we can detect if the field is
|
||||
// removed/replaced while this (async in COOL) dialog is open.
|
||||
m_pFormatField = pField->GetTyp()->FindFormatForField(pField);
|
||||
if (m_pFormatField)
|
||||
StartListening(*m_pFormatField);
|
||||
OUString sTitle = m_xDialog->get_title() +
|
||||
m_pDropField->GetPar2();
|
||||
m_xDialog->set_title(sTitle);
|
||||
@@ -81,6 +88,30 @@ sw::DropDownFieldDialog::DropDownFieldDialog(weld::Widget *pParent, SwWrtShell &
|
||||
|
||||
sw::DropDownFieldDialog::~DropDownFieldDialog()
|
||||
{
|
||||
EndListeningAll();
|
||||
}
|
||||
|
||||
void sw::DropDownFieldDialog::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
|
||||
{
|
||||
const SfxHintId nId = rHint.GetId();
|
||||
if (nId == SfxHintId::Dying)
|
||||
{
|
||||
EndListening(rBC);
|
||||
m_pDropField = nullptr;
|
||||
m_pFormatField = nullptr;
|
||||
return;
|
||||
}
|
||||
if (nId != SfxHintId::SwFormatField)
|
||||
return;
|
||||
const SwFormatFieldHint& rFormatHint = static_cast<const SwFormatFieldHint&>(rHint);
|
||||
const SwFormatFieldHintWhich eWhich = rFormatHint.Which();
|
||||
if (eWhich == SwFormatFieldHintWhich::REMOVED
|
||||
|| eWhich == SwFormatFieldHintWhich::CHANGED)
|
||||
{
|
||||
EndListening(rBC);
|
||||
m_pDropField = nullptr;
|
||||
m_pFormatField = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void sw::DropDownFieldDialog::Apply()
|
||||
|
||||
@@ -19,21 +19,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <svl/lstner.hxx>
|
||||
#include <vcl/weld/Button.hxx>
|
||||
#include <vcl/weld/DialogController.hxx>
|
||||
#include <vcl/weld/TreeView.hxx>
|
||||
|
||||
class SwDropDownField;
|
||||
class SwField;
|
||||
class SwFormatField;
|
||||
class SwWrtShell;
|
||||
|
||||
// Dialog to edit drop down field selection
|
||||
namespace sw
|
||||
{
|
||||
class DropDownFieldDialog final : public weld::GenericDialogController
|
||||
class DropDownFieldDialog final : public weld::GenericDialogController, public SfxListener
|
||||
{
|
||||
SwWrtShell &m_rSh;
|
||||
SwDropDownField* m_pDropField;
|
||||
SwFormatField* m_pFormatField;
|
||||
|
||||
weld::Button* m_pPressedButton;
|
||||
std::unique_ptr<weld::TreeView> m_xListItemsLB;
|
||||
@@ -53,6 +56,7 @@ public:
|
||||
bool PrevButtonPressed() const;
|
||||
bool NextButtonPressed() const;
|
||||
void Apply();
|
||||
virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
|
||||
virtual short run() override
|
||||
{
|
||||
short nRet = GenericDialogController::run();
|
||||
|
||||
Reference in New Issue
Block a user