From f2d20384a0351a7a25bdc56fc31c00b40ab49340 Mon Sep 17 00:00:00 2001 From: Graham Dawes Date: Fri, 1 Feb 2019 09:26:59 +0000 Subject: [PATCH] Implement wxListCtrl::GetEditControl() for wxQt To get access to the control used for editing items, we need to create it ourselves, which involves defining our own factory for doing this, but seems to be the only way of achieving our goal. Closes https://github.com/wxWidgets/wxWidgets/pull/1204 --- include/wx/qt/listctrl.h | 4 +- src/qt/listctrl.cpp | 128 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/include/wx/qt/listctrl.h b/include/wx/qt/listctrl.h index 4cee40bb52..5d3a135fa7 100644 --- a/include/wx/qt/listctrl.h +++ b/include/wx/qt/listctrl.h @@ -10,7 +10,7 @@ #include "wx/textctrl.h" -class QTreeWidget; +class wxQtTreeWidget; class QTreeWidgetItem; class WXDLLIMPEXP_FWD_CORE wxImageList; @@ -303,7 +303,7 @@ protected: m_ownsImageListSmall, m_ownsImageListState; private: - QTreeWidget *m_qtTreeWidget; + wxQtTreeWidget *m_qtTreeWidget; wxDECLARE_DYNAMIC_CLASS( wxListCtrl ); }; diff --git a/src/qt/listctrl.cpp b/src/qt/listctrl.cpp index 5233a31eb6..2c13dd1f40 100644 --- a/src/qt/listctrl.cpp +++ b/src/qt/listctrl.cpp @@ -13,6 +13,9 @@ #endif #include +#include +#include +#include #ifndef WX_PRECOMP #include "wx/bitmap.h" @@ -20,9 +23,105 @@ #include "wx/listctrl.h" #include "wx/imaglist.h" +#include "wx/recguard.h" + #include "wx/qt/private/winevent.h" -#include +namespace +{ + +// wxQT Doesn't have a mechanism for "adopting" external widgets so we have to +// create an instance of wxTextCtrl rather than adopting the control QT would +// create. +// +// Unfortunately the factory is given an internal widget as the parent for +// editor. +// +// To work around these issues we create a wxTextCtl parented by the wxListCtrl +// then recalculate its position relative to the internal widget. +class wxQtListTextCtrl : public wxTextCtrl +{ +public: + wxQtListTextCtrl(wxWindow* parent, QWidget* actualParent) + : wxTextCtrl(parent, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxNO_BORDER), + m_actualParent(actualParent), + m_moving(0) + { + + Bind(wxEVT_MOVE, &wxQtListTextCtrl::onMove, this); + } + + void onMove(wxMoveEvent &event) + { + // QWidget::move generates a QMoveEvent so we need to guard against + // reentrant calls. + wxRecursionGuard guard(m_moving); + if ( guard.IsInside() ) + { + event.Skip(); + return; + } + + const QPoint eventPosition = wxQtConvertPoint(event.GetPosition()); + const QPoint globalPosition = m_actualParent->mapToGlobal(eventPosition); + + // For some reason this always gives us the offset from the header info + // the internal control. So we need to treat this as an offset rather + // than a position. + QWidget* widget = GetHandle(); + const QPoint offset = widget->mapFromGlobal(globalPosition); + + widget->move(eventPosition + offset); + } + +private: + QWidget* m_actualParent; + wxRecursionGuardFlag m_moving; + + wxDECLARE_NO_COPY_CLASS(wxQtListTextCtrl); +}; + +} // anonymous namespace + + +// QT doesn't give us direct access to the editor within the QTreeWidget. +// Instead, we'll supply a factory to create the widget for QT and keep track +// of it ourselves. +class wxQtItemEditorFactory : public QItemEditorFactory +{ +public: + explicit wxQtItemEditorFactory(wxWindow* parent) + : m_parent(parent), + m_textCtrl(NULL) + { + } + + QWidget* createEditor(int WXUNUSED(userType), QWidget* parent) const wxOVERRIDE + { + m_textCtrl = new wxQtListTextCtrl(m_parent, parent); + m_textCtrl->SetFocus(); + return m_textCtrl->GetHandle(); + } + + wxTextCtrl* GetEditControl() + { + return m_textCtrl; + } + + void ClearEditor() + { + delete m_textCtrl; + m_textCtrl = NULL; + } + +private: + wxWindow* m_parent; + mutable wxTextCtrl* m_textCtrl; + + wxDECLARE_NO_COPY_CLASS(wxQtItemEditorFactory); +}; class wxQtTreeWidget : public wxQtEventSignalHandler< QTreeWidget, wxListCtrl > { @@ -31,18 +130,41 @@ public: void EmitListEvent(wxEventType typ, QTreeWidgetItem *qitem, int column) const; + void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint) wxOVERRIDE + { + QTreeWidget::closeEditor(editor, hint); + m_editorFactory.ClearEditor(); + } + + wxTextCtrl *GetEditControl() + { + return m_editorFactory.GetEditControl(); + } + private: void itemClicked(QTreeWidgetItem * item, int column); void itemActivated(QTreeWidgetItem * item, int column); void itemPressed(QTreeWidgetItem * item, int column); + + void ChangeEditorFactory() + { + QItemDelegate *qItemDelegate = static_cast(itemDelegate()); + qItemDelegate->itemEditorFactory(); + qItemDelegate->setItemEditorFactory(&m_editorFactory); + } + + wxQtItemEditorFactory m_editorFactory; }; wxQtTreeWidget::wxQtTreeWidget( wxWindow *parent, wxListCtrl *handler ) - : wxQtEventSignalHandler< QTreeWidget, wxListCtrl >( parent, handler ) + : wxQtEventSignalHandler< QTreeWidget, wxListCtrl >( parent, handler ), + m_editorFactory(handler) { connect(this, &QTreeWidget::itemClicked, this, &wxQtTreeWidget::itemClicked); connect(this, &QTreeWidget::itemPressed, this, &wxQtTreeWidget::itemPressed); connect(this, &QTreeWidget::itemActivated, this, &wxQtTreeWidget::itemActivated); + + ChangeEditorFactory(); } void wxQtTreeWidget::EmitListEvent(wxEventType typ, QTreeWidgetItem *qitem, int column) const @@ -251,7 +373,7 @@ wxRect wxListCtrl::GetViewRect() const wxTextCtrl* wxListCtrl::GetEditControl() const { - return NULL; + return m_qtTreeWidget->GetEditControl(); } QTreeWidgetItem *wxListCtrl::QtGetItem(int id) const