diff --git a/Makefile.in b/Makefile.in index baa823c0b9..4c29d715d0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -3597,7 +3597,15 @@ COND_TOOLKIT_QT_GUI_HDR = \ wx/generic/activityindicator.h \ wx/qt/dataview.h \ wx/qt/dvrenderers.h \ - $(QT_PLATFORM_HDR) + $(QT_PLATFORM_HDR) \ + wx/qt/treectrl.h \ + wx/qt/private/winevent.h \ + wx/qt/private/converter.h \ + wx/qt/private/treeitemdelegate.h \ + wx/qt/private/treeitemfactory.h \ + wx/qt/private/pointer.h \ + wx/qt/private/timer.h \ + wx/qt/private/utils.h @COND_TOOLKIT_QT@GUI_HDR = $(COND_TOOLKIT_QT_GUI_HDR) @COND_TOOLKIT_COCOA@MEDIA_PLATFORM_HDR = @COND_TOOLKIT_GTK@MEDIA_PLATFORM_HDR = @@ -5566,7 +5574,7 @@ COND_TOOLKIT_MSW___GUI_SRC_OBJECTS = \ monodll_msw_textctrl.o \ monodll_msw_textentry.o \ monodll_msw_tglbtn.o \ - monodll_treectrl.o \ + monodll_msw_treectrl.o \ monodll_systhemectrl.o \ monodll_customdraw.o \ monodll_animateg.o \ @@ -5760,7 +5768,8 @@ COND_TOOLKIT_QT___GUI_SRC_OBJECTS = \ monodll_qt_uiaction.o \ monodll_qt_utils.o \ monodll_qt_window.o \ - $(__QT_PLATFORM_SRC_OBJECTS) + $(__QT_PLATFORM_SRC_OBJECTS) \ + monodll_qt_treectrl.o @COND_TOOLKIT_QT@__GUI_SRC_OBJECTS = $(COND_TOOLKIT_QT___GUI_SRC_OBJECTS) COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS = \ monodll_comimpl.o \ @@ -7551,7 +7560,7 @@ COND_TOOLKIT_MSW___GUI_SRC_OBJECTS_1 = \ monolib_msw_textctrl.o \ monolib_msw_textentry.o \ monolib_msw_tglbtn.o \ - monolib_treectrl.o \ + monolib_msw_treectrl.o \ monolib_systhemectrl.o \ monolib_customdraw.o \ monolib_animateg.o \ @@ -7745,7 +7754,8 @@ COND_TOOLKIT_QT___GUI_SRC_OBJECTS_1 = \ monolib_qt_uiaction.o \ monolib_qt_utils.o \ monolib_qt_window.o \ - $(__QT_PLATFORM_SRC_OBJECTS_1) + $(__QT_PLATFORM_SRC_OBJECTS_1) \ + monolib_qt_treectrl.o @COND_TOOLKIT_QT@__GUI_SRC_OBJECTS_1 = $(COND_TOOLKIT_QT___GUI_SRC_OBJECTS_1) COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_1 = \ monolib_comimpl.o \ @@ -9683,7 +9693,7 @@ COND_TOOLKIT_MSW___GUI_SRC_OBJECTS_2 = \ coredll_msw_textctrl.o \ coredll_msw_textentry.o \ coredll_msw_tglbtn.o \ - coredll_treectrl.o \ + coredll_msw_treectrl.o \ coredll_systhemectrl.o \ coredll_customdraw.o \ coredll_animateg.o \ @@ -9877,7 +9887,8 @@ COND_TOOLKIT_QT___GUI_SRC_OBJECTS_2 = \ coredll_qt_uiaction.o \ coredll_qt_utils.o \ coredll_qt_window.o \ - $(__QT_PLATFORM_SRC_OBJECTS_2) + $(__QT_PLATFORM_SRC_OBJECTS_2) \ + coredll_qt_treectrl.o @COND_TOOLKIT_QT@__GUI_SRC_OBJECTS_2 = $(COND_TOOLKIT_QT___GUI_SRC_OBJECTS_2) COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_2 = \ coredll_comimpl.o \ @@ -11404,7 +11415,7 @@ COND_TOOLKIT_MSW___GUI_SRC_OBJECTS_3 = \ corelib_msw_textctrl.o \ corelib_msw_textentry.o \ corelib_msw_tglbtn.o \ - corelib_treectrl.o \ + corelib_msw_treectrl.o \ corelib_systhemectrl.o \ corelib_customdraw.o \ corelib_animateg.o \ @@ -11598,7 +11609,8 @@ COND_TOOLKIT_QT___GUI_SRC_OBJECTS_3 = \ corelib_qt_uiaction.o \ corelib_qt_utils.o \ corelib_qt_window.o \ - $(__QT_PLATFORM_SRC_OBJECTS_3) + $(__QT_PLATFORM_SRC_OBJECTS_3) \ + corelib_qt_treectrl.o @COND_TOOLKIT_QT@__GUI_SRC_OBJECTS_3 = $(COND_TOOLKIT_QT___GUI_SRC_OBJECTS_3) COND_PLATFORM_WIN32_1___QT_PLATFORM_SRC_OBJECTS_3 = \ corelib_comimpl.o \ @@ -16376,7 +16388,7 @@ monodll_msw_textentry.o: $(srcdir)/src/msw/textentry.cpp $(MONODLL_ODEP) monodll_msw_tglbtn.o: $(srcdir)/src/msw/tglbtn.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/tglbtn.cpp -monodll_treectrl.o: $(srcdir)/src/msw/treectrl.cpp $(MONODLL_ODEP) +monodll_msw_treectrl.o: $(srcdir)/src/msw/treectrl.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/treectrl.cpp monodll_systhemectrl.o: $(srcdir)/src/msw/systhemectrl.cpp $(MONODLL_ODEP) @@ -16871,6 +16883,9 @@ monodll_qt_window.o: $(srcdir)/src/qt/window.cpp $(MONODLL_ODEP) monodll_qt_graphics.o: $(srcdir)/src/qt/graphics.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/qt/graphics.cpp +monodll_qt_treectrl.o: $(srcdir)/src/qt/treectrl.cpp $(MONODLL_ODEP) + $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/qt/treectrl.cpp + monodll_univ_anybutton.o: $(srcdir)/src/univ/anybutton.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/univ/anybutton.cpp @@ -21641,7 +21656,7 @@ monolib_msw_textentry.o: $(srcdir)/src/msw/textentry.cpp $(MONOLIB_ODEP) monolib_msw_tglbtn.o: $(srcdir)/src/msw/tglbtn.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/tglbtn.cpp -monolib_treectrl.o: $(srcdir)/src/msw/treectrl.cpp $(MONOLIB_ODEP) +monolib_msw_treectrl.o: $(srcdir)/src/msw/treectrl.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/treectrl.cpp monolib_systhemectrl.o: $(srcdir)/src/msw/systhemectrl.cpp $(MONOLIB_ODEP) @@ -22136,6 +22151,9 @@ monolib_qt_window.o: $(srcdir)/src/qt/window.cpp $(MONOLIB_ODEP) monolib_qt_graphics.o: $(srcdir)/src/qt/graphics.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/qt/graphics.cpp +monolib_qt_treectrl.o: $(srcdir)/src/qt/treectrl.cpp $(MONOLIB_ODEP) + $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/qt/treectrl.cpp + monolib_univ_anybutton.o: $(srcdir)/src/univ/anybutton.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/univ/anybutton.cpp @@ -27566,7 +27584,7 @@ coredll_msw_textentry.o: $(srcdir)/src/msw/textentry.cpp $(COREDLL_ODEP) coredll_msw_tglbtn.o: $(srcdir)/src/msw/tglbtn.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/msw/tglbtn.cpp -coredll_treectrl.o: $(srcdir)/src/msw/treectrl.cpp $(COREDLL_ODEP) +coredll_msw_treectrl.o: $(srcdir)/src/msw/treectrl.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/msw/treectrl.cpp coredll_systhemectrl.o: $(srcdir)/src/msw/systhemectrl.cpp $(COREDLL_ODEP) @@ -28061,6 +28079,9 @@ coredll_qt_window.o: $(srcdir)/src/qt/window.cpp $(COREDLL_ODEP) coredll_qt_graphics.o: $(srcdir)/src/qt/graphics.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/qt/graphics.cpp +coredll_qt_treectrl.o: $(srcdir)/src/qt/treectrl.cpp $(COREDLL_ODEP) + $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/qt/treectrl.cpp + coredll_univ_anybutton.o: $(srcdir)/src/univ/anybutton.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/univ/anybutton.cpp @@ -31820,7 +31841,7 @@ corelib_msw_textentry.o: $(srcdir)/src/msw/textentry.cpp $(CORELIB_ODEP) corelib_msw_tglbtn.o: $(srcdir)/src/msw/tglbtn.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/msw/tglbtn.cpp -corelib_treectrl.o: $(srcdir)/src/msw/treectrl.cpp $(CORELIB_ODEP) +corelib_msw_treectrl.o: $(srcdir)/src/msw/treectrl.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/msw/treectrl.cpp corelib_systhemectrl.o: $(srcdir)/src/msw/systhemectrl.cpp $(CORELIB_ODEP) @@ -32315,6 +32336,9 @@ corelib_qt_window.o: $(srcdir)/src/qt/window.cpp $(CORELIB_ODEP) corelib_qt_graphics.o: $(srcdir)/src/qt/graphics.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/qt/graphics.cpp +corelib_qt_treectrl.o: $(srcdir)/src/qt/treectrl.cpp $(CORELIB_ODEP) + $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/qt/treectrl.cpp + corelib_univ_anybutton.o: $(srcdir)/src/univ/anybutton.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/univ/anybutton.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index fef9dcca65..5a9e7ec7eb 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -347,7 +347,6 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/qt/toolbar.h wx/qt/tooltip.h wx/qt/toplevel.h - wx/qt/window.h wx/generic/fdrepdlg.h wx/generic/filepickerg.h @@ -362,6 +361,14 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/qt/dataview.h wx/qt/dvrenderers.h $(QT_PLATFORM_HDR) + wx/qt/treectrl.h + wx/qt/private/winevent.h + wx/qt/private/converter.h + wx/qt/private/treeitemdelegate.h + wx/qt/private/treeitemfactory.h + wx/qt/private/pointer.h + wx/qt/private/timer.h + wx/qt/private/utils.h @@ -460,6 +467,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/qt/utils.cpp src/qt/window.cpp $(QT_PLATFORM_SRC) + src/qt/treectrl.cpp diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index 9127a77413..49b3fa1e75 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -276,6 +276,14 @@ set(QT_HDR wx/qt/dataview.h wx/generic/activityindicator.h ${QT_PLATFORM_HDR} + wx/qt/treectrl.h + wx/qt/private/converter.h + wx/qt/private/winevent.h + wx/qt/private/timer.h + wx/qt/private/pointer.h + wx/qt/private/treeitemdelegate.h + wx/qt/private/treeitemfactory.h + wx/qt/private/utils.h ) set(QT_SRC @@ -374,6 +382,7 @@ set(QT_SRC src/qt/dataview.cpp src/qt/taskbar.cpp ${QT_PLATFORM_SRC} + src/qt/treectrl.cpp ) set(MEDIA_QT_SRC diff --git a/build/files b/build/files index 9e48fc3ff9..b35dadaa1d 100644 --- a/build/files +++ b/build/files @@ -297,7 +297,17 @@ QT_HDR = wx/qt/toolbar.h wx/qt/tooltip.h wx/qt/toplevel.h + wx/qt/treectrl.h wx/qt/window.h + wx/qt/private/converter.h + wx/qt/private/winevent.h + wx/qt/private/winevent.h + wx/qt/private/converter.h + wx/qt/private/pointer.h + wx/qt/private/timer.h + wx/qt/private/treeitemdelegate.h + wx/qt/private/treeitemfactory.h + wx/qt/private/utils.h QT_SRC= $(QT_PLATFORM_SRC) @@ -392,6 +402,7 @@ QT_SRC= src/qt/toolbar.cpp src/qt/tooltip.cpp src/qt/toplevel.cpp + src/qt/treectrl.cpp src/qt/uiaction.cpp src/qt/utils.cpp src/qt/window.cpp diff --git a/include/wx/generic/treectlg.h b/include/wx/generic/treectlg.h index 4fec700066..36843e3924 100644 --- a/include/wx/generic/treectlg.h +++ b/include/wx/generic/treectlg.h @@ -360,7 +360,7 @@ private: wxDECLARE_NO_COPY_CLASS(wxGenericTreeCtrl); }; -#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__) +#if !defined(__WXMSW__) && ! defined(__WXQT__) || defined(__WXUNIVERSAL__) /* * wxTreeCtrl has to be a real class or we have problems with * the run-time information. diff --git a/include/wx/qt/listctrl.h b/include/wx/qt/listctrl.h index e55b44ef98..f9818722cc 100644 --- a/include/wx/qt/listctrl.h +++ b/include/wx/qt/listctrl.h @@ -10,7 +10,7 @@ #include "wx/textctrl.h" -class wxQtTreeWidget; +class wxQtListTreeWidget; class QTreeWidgetItem; class WXDLLIMPEXP_FWD_CORE wxImageList; @@ -282,7 +282,7 @@ protected: m_ownsImageListSmall, m_ownsImageListState; private: - wxQtTreeWidget *m_qtTreeWidget; + wxQtListTreeWidget *m_qtTreeWidget; wxDECLARE_DYNAMIC_CLASS( wxListCtrl ); }; diff --git a/include/wx/qt/private/converter.h b/include/wx/qt/private/converter.h index 7cdce58fad..fbb4250bd6 100644 --- a/include/wx/qt/private/converter.h +++ b/include/wx/qt/private/converter.h @@ -15,10 +15,12 @@ #include "wx/kbdstate.h" #include "wx/gdicmn.h" +#include "wx/colour.h" #include #include #include +#include // Rely on overloading and let the compiler pick the correct version, which makes // them easier to use then to write wxQtConvertQtRectToWxRect() or wxQtConvertWxRectToQtRect() @@ -54,6 +56,16 @@ inline QString wxQtConvertString( const wxString &str ) return QString( str.utf8_str() ); } +inline wxColour wxQtConvertColour(const QColor &colour) +{ + return wxColour(colour.red(), colour.green(), colour.blue(), colour.alpha()); +} + +inline QColor wxQtConvertColour(const wxColour &colour) +{ + return QColor(colour.Red(), colour.Green(), colour.Blue(), colour.Alpha()); +} + #if wxUSE_DATETIME class WXDLLIMPEXP_FWD_BASE wxDateTime; diff --git a/include/wx/qt/private/treeitemdelegate.h b/include/wx/qt/private/treeitemdelegate.h new file mode 100644 index 0000000000..65025de442 --- /dev/null +++ b/include/wx/qt/private/treeitemdelegate.h @@ -0,0 +1,76 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/qt/private/treeitemdelegate.h +// Purpose: Delegate to create text edit controls for the tree items +// Author: Matthew Griffin +// Created: 2019-05-29 +// Copyright: Matthew Griffin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_QT_PRIVATE_TREEITEM_DELEGATE_H +#define _WX_QT_PRIVATE_TREEITEM_DELEGATE_H + +#include + +#include "wx/app.h" +#include "wx/textctrl.h" + +#include "treeitemfactory.h" + +class wxQTTreeItemDelegate : public QStyledItemDelegate +{ +public: + explicit wxQTTreeItemDelegate(wxWindow* parent) + : m_parent(parent), + m_textCtrl(NULL) + { + } + + QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &WXUNUSED(option), const QModelIndex &index) const wxOVERRIDE + { + if ( m_textCtrl != NULL ) + destroyEditor(m_textCtrl->GetHandle(), m_currentModelIndex); + + m_currentModelIndex = index; + m_textCtrl = new wxQtListTextCtrl(m_parent, parent); + m_textCtrl->SetFocus(); + return m_textCtrl->GetHandle(); + } + + void destroyEditor(QWidget *WXUNUSED(editor), const QModelIndex &WXUNUSED(index)) const wxOVERRIDE + { + if ( m_textCtrl != NULL ) + { + m_currentModelIndex = QModelIndex(); // invalidate the index + wxTheApp->ScheduleForDestruction(m_textCtrl); + m_textCtrl = NULL; + } + } + + void setModelData(QWidget *WXUNUSED(editor), QAbstractItemModel *WXUNUSED(model), const QModelIndex &WXUNUSED(index)) const wxOVERRIDE + { + // Don't set model data until wx has had a chance to send out events + } + + wxTextCtrl* GetEditControl() const + { + return m_textCtrl; + } + + QModelIndex GetCurrentModelIndex() const + { + return m_currentModelIndex; + } + + void AcceptModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const + { + QStyledItemDelegate::setModelData(editor, model, index); + } + +private: + wxWindow* m_parent; + mutable wxTextCtrl* m_textCtrl; + mutable QModelIndex m_currentModelIndex; +}; + +#endif // _WX_QT_PRIVATE_TREEITEM_DELEGATE_H diff --git a/include/wx/qt/private/treeitemfactory.h b/include/wx/qt/private/treeitemfactory.h new file mode 100644 index 0000000000..42ea7e1abf --- /dev/null +++ b/include/wx/qt/private/treeitemfactory.h @@ -0,0 +1,122 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/qt/private/treeitemfactory.h +// Purpose: Factory to create text edit controls for the tree items +// Author: Graham Dawes +// Created: 2019-02-07 +// Copyright: Graham Dawes +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_QT_PRIVATE_TREEITEM_FACTORY_H_ +#define _WX_QT_PRIVATE_TREEITEM_FACTORY_H_ + +#include +#include +#include + +#include "wx/recguard.h" +#include "wx/textctrl.h" + +// 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 eventPos = wxQtConvertPoint(event.GetPosition()); + const QPoint globalPos = m_actualParent->mapToGlobal(eventPos); + + // 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(globalPos); + + widget->move(eventPos + offset); + } + +private: + QWidget* m_actualParent; + wxRecursionGuardFlag m_moving; + + wxDECLARE_NO_COPY_CLASS(wxQtListTextCtrl); +}; + +// 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 wxQtTreeItemEditorFactory : public QItemEditorFactory +{ +public: + explicit wxQtTreeItemEditorFactory(wxWindow* parent) + : m_parent(parent), + m_textCtrl(NULL) + { + } + + void AttachTo(QTreeWidget *tree) + { + QAbstractItemDelegate* delegate = tree->itemDelegate(); + QItemDelegate *qItemDelegate = static_cast(delegate); + qItemDelegate->setItemEditorFactory(this); + } + + QWidget* createEditor(int WXUNUSED(userType), QWidget* parent) const wxOVERRIDE + { + if (m_textCtrl != NULL) + ClearEditor(); + + m_textCtrl = new wxQtListTextCtrl(m_parent, parent); + m_textCtrl->SetFocus(); + return m_textCtrl->GetHandle(); + } + + wxTextCtrl* GetEditControl() const + { + return m_textCtrl; + } + + void ClearEditor() const + { + delete m_textCtrl; + m_textCtrl = NULL; + } + +private: + wxWindow* m_parent; + mutable wxTextCtrl* m_textCtrl; + + wxDECLARE_NO_COPY_CLASS(wxQtTreeItemEditorFactory); +}; + +#endif //_WX_QT_PRIVATE_TREEITEM_FACTORY_H_ diff --git a/include/wx/qt/treectrl.h b/include/wx/qt/treectrl.h index 9eb385b71d..3db3838f7d 100644 --- a/include/wx/qt/treectrl.h +++ b/include/wx/qt/treectrl.h @@ -8,7 +8,7 @@ #ifndef _WX_QT_TREECTRL_H_ #define _WX_QT_TREECTRL_H_ -class QTreeWidget; +class wxQTreeWidget; class WXDLLIMPEXP_CORE wxTreeCtrl : public wxTreeCtrlBase { @@ -21,6 +21,8 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxTreeCtrlNameStr); + virtual ~wxTreeCtrl(); + bool Create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, @@ -28,113 +30,116 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxTreeCtrlNameStr); - virtual unsigned int GetCount() const; + virtual unsigned int GetCount() const wxOVERRIDE; - virtual unsigned int GetIndent() const; - virtual void SetIndent(unsigned int indent); + virtual unsigned int GetIndent() const wxOVERRIDE; + virtual void SetIndent(unsigned int indent) wxOVERRIDE; - virtual void SetImageList(wxImageList *imageList); - virtual void SetStateImageList(wxImageList *imageList); + virtual void SetImageList(wxImageList *imageList) wxOVERRIDE; + virtual void SetStateImageList(wxImageList *imageList) wxOVERRIDE; - virtual wxString GetItemText(const wxTreeItemId& item) const; + virtual wxString GetItemText(const wxTreeItemId& item) const wxOVERRIDE; virtual int GetItemImage(const wxTreeItemId& item, - wxTreeItemIcon which = wxTreeItemIcon_Normal) const; - virtual wxTreeItemData *GetItemData(const wxTreeItemId& item) const; - virtual wxColour GetItemTextColour(const wxTreeItemId& item) const; - virtual wxColour GetItemBackgroundColour(const wxTreeItemId& item) const; - virtual wxFont GetItemFont(const wxTreeItemId& item) const; + wxTreeItemIcon which = wxTreeItemIcon_Normal) const wxOVERRIDE; + virtual wxTreeItemData *GetItemData(const wxTreeItemId& item) const wxOVERRIDE; + virtual wxColour GetItemTextColour(const wxTreeItemId& item) const wxOVERRIDE; + virtual wxColour GetItemBackgroundColour(const wxTreeItemId& item) const wxOVERRIDE; + virtual wxFont GetItemFont(const wxTreeItemId& item) const wxOVERRIDE; - virtual void SetItemText(const wxTreeItemId& item, const wxString& text); + virtual void SetItemText(const wxTreeItemId& item, const wxString& text) wxOVERRIDE; virtual void SetItemImage(const wxTreeItemId& item, int image, - wxTreeItemIcon which = wxTreeItemIcon_Normal); - virtual void SetItemData(const wxTreeItemId& item, wxTreeItemData *data); - virtual void SetItemHasChildren(const wxTreeItemId& item, bool has = true); - virtual void SetItemBold(const wxTreeItemId& item, bool bold = true); - virtual void SetItemDropHighlight(const wxTreeItemId& item, bool highlight = true); - virtual void SetItemTextColour(const wxTreeItemId& item, const wxColour& col); - virtual void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& col); - virtual void SetItemFont(const wxTreeItemId& item, const wxFont& font); + wxTreeItemIcon which = wxTreeItemIcon_Normal) wxOVERRIDE; + virtual void SetItemData(const wxTreeItemId& item, wxTreeItemData *data) wxOVERRIDE; + virtual void SetItemHasChildren(const wxTreeItemId& item, bool has = true) wxOVERRIDE; + virtual void SetItemBold(const wxTreeItemId& item, bool bold = true) wxOVERRIDE; + virtual void SetItemDropHighlight(const wxTreeItemId& item, bool highlight = true) wxOVERRIDE; + virtual void SetItemTextColour(const wxTreeItemId& item, const wxColour& col) wxOVERRIDE; + virtual void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& col) wxOVERRIDE; + virtual void SetItemFont(const wxTreeItemId& item, const wxFont& font) wxOVERRIDE; - virtual bool IsVisible(const wxTreeItemId& item) const; - virtual bool ItemHasChildren(const wxTreeItemId& item) const; - virtual bool IsExpanded(const wxTreeItemId& item) const; - virtual bool IsSelected(const wxTreeItemId& item) const; - virtual bool IsBold(const wxTreeItemId& item) const; + virtual bool IsVisible(const wxTreeItemId& item) const wxOVERRIDE; + virtual bool ItemHasChildren(const wxTreeItemId& item) const wxOVERRIDE; + virtual bool IsExpanded(const wxTreeItemId& item) const wxOVERRIDE; + virtual bool IsSelected(const wxTreeItemId& item) const wxOVERRIDE; + virtual bool IsBold(const wxTreeItemId& item) const wxOVERRIDE; - virtual size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true) const; + virtual size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true) const wxOVERRIDE; - virtual wxTreeItemId GetRootItem() const; - virtual wxTreeItemId GetSelection() const; - virtual size_t GetSelections(wxArrayTreeItemIds& selections) const; + virtual wxTreeItemId GetRootItem() const wxOVERRIDE; + virtual wxTreeItemId GetSelection() const wxOVERRIDE; + virtual size_t GetSelections(wxArrayTreeItemIds& selections) const wxOVERRIDE; - virtual void SetFocusedItem(const wxTreeItemId& item); - virtual void ClearFocusedItem(); - virtual wxTreeItemId GetFocusedItem() const; + virtual void SetFocusedItem(const wxTreeItemId& item) wxOVERRIDE; + virtual void ClearFocusedItem() wxOVERRIDE; + virtual wxTreeItemId GetFocusedItem() const wxOVERRIDE; - virtual wxTreeItemId GetItemParent(const wxTreeItemId& item) const; - - virtual wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; - virtual wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; - virtual wxTreeItemId GetLastChild(const wxTreeItemId& item) const; - virtual wxTreeItemId GetNextSibling(const wxTreeItemId& item) const; - virtual wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const; - virtual wxTreeItemId GetFirstVisibleItem() const; - virtual wxTreeItemId GetNextVisible(const wxTreeItemId& item) const; - virtual wxTreeItemId GetPrevVisible(const wxTreeItemId& item) const; + virtual wxTreeItemId GetItemParent(const wxTreeItemId& item) const wxOVERRIDE; + virtual wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const wxOVERRIDE; + virtual wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const wxOVERRIDE; + virtual wxTreeItemId GetLastChild(const wxTreeItemId& item) const wxOVERRIDE; + virtual wxTreeItemId GetNextSibling(const wxTreeItemId& item) const wxOVERRIDE; + virtual wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const wxOVERRIDE; + virtual wxTreeItemId GetFirstVisibleItem() const wxOVERRIDE; + virtual wxTreeItemId GetNextVisible(const wxTreeItemId& item) const wxOVERRIDE; + virtual wxTreeItemId GetPrevVisible(const wxTreeItemId& item) const wxOVERRIDE; virtual wxTreeItemId AddRoot(const wxString& text, int image = -1, int selImage = -1, - wxTreeItemData *data = NULL); + wxTreeItemData *data = NULL) wxOVERRIDE; - virtual void Delete(const wxTreeItemId& item); - virtual void DeleteChildren(const wxTreeItemId& item); - virtual void DeleteAllItems(); + virtual void Delete(const wxTreeItemId& item) wxOVERRIDE; + virtual void DeleteChildren(const wxTreeItemId& item) wxOVERRIDE; + virtual void DeleteAllItems() wxOVERRIDE; - virtual void Expand(const wxTreeItemId& item); - virtual void Collapse(const wxTreeItemId& item); - virtual void CollapseAndReset(const wxTreeItemId& item); - virtual void Toggle(const wxTreeItemId& item); + virtual void Expand(const wxTreeItemId& item) wxOVERRIDE; + virtual void Collapse(const wxTreeItemId& item) wxOVERRIDE; + virtual void CollapseAndReset(const wxTreeItemId& item) wxOVERRIDE; + virtual void Toggle(const wxTreeItemId& item) wxOVERRIDE; - virtual void Unselect(); - virtual void UnselectAll(); - virtual void SelectItem(const wxTreeItemId& item, bool select = true); - virtual void SelectChildren(const wxTreeItemId& parent); + virtual void Unselect() wxOVERRIDE; + virtual void UnselectAll() wxOVERRIDE; + virtual void SelectItem(const wxTreeItemId& item, bool select = true) wxOVERRIDE; + virtual void SelectChildren(const wxTreeItemId& parent) wxOVERRIDE; - virtual void EnsureVisible(const wxTreeItemId& item); - virtual void ScrollTo(const wxTreeItemId& item); + virtual void EnsureVisible(const wxTreeItemId& item) wxOVERRIDE; + virtual void ScrollTo(const wxTreeItemId& item) wxOVERRIDE; - virtual wxTextCtrl *EditLabel(const wxTreeItemId& item, wxClassInfo* textCtrlClass = CLASSINFO(wxTextCtrl)); - virtual wxTextCtrl *GetEditControl() const; - virtual void EndEditLabel(const wxTreeItemId& item, bool discardChanges = false); + virtual wxTextCtrl *EditLabel(const wxTreeItemId& item, wxClassInfo* textCtrlClass = CLASSINFO(wxTextCtrl)) wxOVERRIDE; + virtual wxTextCtrl *GetEditControl() const wxOVERRIDE; + virtual void EndEditLabel(const wxTreeItemId& item, bool discardChanges = false) wxOVERRIDE; - virtual void SortChildren(const wxTreeItemId& item); + virtual void SortChildren(const wxTreeItemId& item) wxOVERRIDE; - virtual bool GetBoundingRect(const wxTreeItemId& item, wxRect& rect, bool textOnly = false) const; + virtual bool GetBoundingRect(const wxTreeItemId& item, wxRect& rect, bool textOnly = false) const wxOVERRIDE; + + virtual void SetWindowStyleFlag(long styles) wxOVERRIDE; virtual QWidget *GetHandle() const wxOVERRIDE; protected: - virtual int DoGetItemState(const wxTreeItemId& item) const; - virtual void DoSetItemState(const wxTreeItemId& item, int state); + virtual int DoGetItemState(const wxTreeItemId& item) const wxOVERRIDE; + virtual void DoSetItemState(const wxTreeItemId& item, int state) wxOVERRIDE; virtual wxTreeItemId DoInsertItem(const wxTreeItemId& parent, size_t pos, const wxString& text, int image, int selImage, - wxTreeItemData *data); + wxTreeItemData *data) wxOVERRIDE; virtual wxTreeItemId DoInsertAfter(const wxTreeItemId& parent, const wxTreeItemId& idPrevious, const wxString& text, int image = -1, int selImage = -1, - wxTreeItemData *data = NULL); + wxTreeItemData *data = NULL) wxOVERRIDE; - virtual wxTreeItemId DoTreeHitTest(const wxPoint& point, int& flags) const; + virtual wxTreeItemId DoTreeHitTest(const wxPoint& point, int& flags) const wxOVERRIDE; private: - QTreeWidget *m_qtTreeWidget; + void SendDeleteEvent(const wxTreeItemId &item); + wxTreeItemId GetNext(const wxTreeItemId &item) const; + wxQTreeWidget *m_qtTreeWidget; wxDECLARE_DYNAMIC_CLASS(wxTreeCtrl); }; diff --git a/include/wx/treectrl.h b/include/wx/treectrl.h index f73ade7b2a..055a5ad055 100644 --- a/include/wx/treectrl.h +++ b/include/wx/treectrl.h @@ -26,7 +26,7 @@ class WXDLLIMPEXP_FWD_CORE wxImageList; -#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__) +#if !defined(__WXMSW__) && !defined(__WXQT__) || defined(__WXUNIVERSAL__) #define wxHAS_GENERIC_TREECTRL #endif @@ -465,6 +465,8 @@ private: #include "wx/generic/treectlg.h" #elif defined(__WXMSW__) #include "wx/msw/treectrl.h" +#elif defined(__WXQT__) + #include "wx/qt/treectrl.h" #else #error "unknown native wxTreeCtrl implementation" #endif diff --git a/samples/treectrl/treetest.cpp b/samples/treectrl/treetest.cpp index 24a4186efd..b4840a6fa0 100644 --- a/samples/treectrl/treetest.cpp +++ b/samples/treectrl/treetest.cpp @@ -1055,7 +1055,7 @@ void MyTreeCtrl::CreateStateImageList(bool del) AssignStateImageList(states); } -#if USE_GENERIC_TREECTRL || !defined(__WXMSW__) +#if USE_GENERIC_TREECTRL || (!defined(__WXMSW__) && !defined(__WXQT__)) void MyTreeCtrl::CreateButtonsImageList(int size) { if ( size == -1 ) diff --git a/src/qt/listctrl.cpp b/src/qt/listctrl.cpp index 587961d3da..d8f71b6fd5 100644 --- a/src/qt/listctrl.cpp +++ b/src/qt/listctrl.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #ifndef WX_PRECOMP #include "wx/bitmap.h" @@ -23,110 +22,14 @@ #include "wx/listctrl.h" #include "wx/imaglist.h" -#include "wx/recguard.h" #include "wx/qt/private/winevent.h" +#include "wx/qt/private/treeitemfactory.h" -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 +class wxQtListTreeWidget : public wxQtEventSignalHandler< QTreeWidget, wxListCtrl > { 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 > -{ -public: - wxQtTreeWidget( wxWindow *parent, wxListCtrl *handler ); + wxQtListTreeWidget( wxWindow *parent, wxListCtrl *handler ); void EmitListEvent(wxEventType typ, QTreeWidgetItem *qitem, int column) const; @@ -153,21 +56,21 @@ private: qItemDelegate->setItemEditorFactory(&m_editorFactory); } - wxQtItemEditorFactory m_editorFactory; + wxQtTreeItemEditorFactory m_editorFactory; }; -wxQtTreeWidget::wxQtTreeWidget( wxWindow *parent, wxListCtrl *handler ) +wxQtListTreeWidget::wxQtListTreeWidget( wxWindow *parent, wxListCtrl *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); + connect(this, &QTreeWidget::itemClicked, this, &wxQtListTreeWidget::itemClicked); + connect(this, &QTreeWidget::itemPressed, this, &wxQtListTreeWidget::itemPressed); + connect(this, &QTreeWidget::itemActivated, this, &wxQtListTreeWidget::itemActivated); ChangeEditorFactory(); } -void wxQtTreeWidget::EmitListEvent(wxEventType typ, QTreeWidgetItem *qitem, int column) const +void wxQtListTreeWidget::EmitListEvent(wxEventType typ, QTreeWidgetItem *qitem, int column) const { wxListCtrl *handler = GetHandler(); if ( handler ) @@ -187,17 +90,17 @@ void wxQtTreeWidget::EmitListEvent(wxEventType typ, QTreeWidgetItem *qitem, int } } -void wxQtTreeWidget::itemClicked(QTreeWidgetItem *qitem, int column) +void wxQtListTreeWidget::itemClicked(QTreeWidgetItem *qitem, int column) { EmitListEvent(wxEVT_LIST_ITEM_SELECTED, qitem, column); } -void wxQtTreeWidget::itemPressed(QTreeWidgetItem *qitem, int column) +void wxQtListTreeWidget::itemPressed(QTreeWidgetItem *qitem, int column) { EmitListEvent(wxEVT_LIST_ITEM_SELECTED, qitem, column); } -void wxQtTreeWidget::itemActivated(QTreeWidgetItem *qitem, int column) +void wxQtListTreeWidget::itemActivated(QTreeWidgetItem *qitem, int column) { EmitListEvent(wxEVT_LIST_ITEM_ACTIVATED, qitem, column); } @@ -258,7 +161,7 @@ bool wxListCtrl::Create(wxWindow *parent, const wxValidator& validator, const wxString& name) { - m_qtTreeWidget = new wxQtTreeWidget( parent, this ); + m_qtTreeWidget = new wxQtListTreeWidget( parent, this ); if (style & wxLC_NO_HEADER) m_qtTreeWidget->setHeaderHidden(true); diff --git a/src/qt/treectrl.cpp b/src/qt/treectrl.cpp old mode 100644 new mode 100755 index f73a202612..2493744c4d --- a/src/qt/treectrl.cpp +++ b/src/qt/treectrl.cpp @@ -8,11 +8,513 @@ // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + #include "wx/treectrl.h" +#include "wx/imaglist.h" +#include "wx/settings.h" +#include "wx/sharedptr.h" +#include "wx/withimages.h" + +#include "wx/qt/private/winevent.h" +#include "wx/qt/private/treeitemdelegate.h" #include +#include +#include -wxTreeCtrl::wxTreeCtrl() +namespace +{ +struct TreeItemDataQt +{ + TreeItemDataQt() + { + } + + explicit TreeItemDataQt(wxTreeItemData* data) : data(data) + { + static bool s_registered = false; + if ( !s_registered ) + { + qRegisterMetaTypeStreamOperators("TreeItemDataQt"); + s_registered = true; + } + } + + wxTreeItemData *getData() const + { + return data.get(); + } + +private: + wxSharedPtr data; +}; + +QDataStream &operator<<(QDataStream &out, const TreeItemDataQt &WXUNUSED(obj)) +{ + return out; +} +QDataStream &operator>>(QDataStream &in, TreeItemDataQt &WXUNUSED(obj)) +{ + return in; +} + +QTreeWidgetItem *wxQtConvertTreeItem(const wxTreeItemId &item) +{ + return static_cast(item.GetID()); +} + +wxTreeItemId wxQtConvertTreeItem(QTreeWidgetItem *item) +{ + return wxTreeItemId(item); +} + +size_t CountChildren(QTreeWidgetItem *item) +{ + const int currentCount = item->childCount(); + size_t totalCount = currentCount; + + for ( int i = 0; i < currentCount; ++i ) + { + totalCount += CountChildren(item->child(i)); + } + + return totalCount; +} + +class ImageState +{ +public: + ImageState() : m_state(wxTREE_ITEMSTATE_NONE) + { + for ( int i = wxTreeItemIcon_Normal; i < wxTreeItemIcon_Max; ++i ) + { + m_imageStates[i] = wxWithImages::NO_IMAGE; + } + } + + int &operator[](size_t index) + { + wxASSERT(index < wxTreeItemIcon_Max); + return m_imageStates[index]; + } + + int operator[](size_t index) const + { + wxASSERT(index < wxTreeItemIcon_Max); + return m_imageStates[index]; + } + + void SetState(int state) + { + m_state = state; + } + + int GetState() const + { + return m_state; + } + +private: + int m_imageStates[wxTreeItemIcon_Max]; + int m_state; +}; + +} + +Q_DECLARE_METATYPE(TreeItemDataQt) + +class wxQTreeWidget : public wxQtEventSignalHandler +{ +public: + wxQTreeWidget(wxWindow *parent, wxTreeCtrl *handler) : + wxQtEventSignalHandler(parent, handler), + m_item_delegate(handler), + m_closing_editor(0) + { + connect(this, &QTreeWidget::currentItemChanged, + this, &wxQTreeWidget::OnCurrentItemChanged); + connect(this, &QTreeWidget::itemActivated, + this, &wxQTreeWidget::OnItemActivated); + connect(this, &QTreeWidget::itemClicked, + this, &wxQTreeWidget::OnItemClicked); + connect(this, &QTreeWidget::itemCollapsed, + this, &wxQTreeWidget::OnItemCollapsed); + connect(this, &QTreeWidget::itemExpanded, + this, &wxQTreeWidget::OnItemExpanded); + + setItemDelegate(&m_item_delegate); + setDragEnabled(true); + viewport()->setAcceptDrops(true); + setDropIndicatorShown(true); + setEditTriggers(QAbstractItemView::SelectedClicked); + } + + virtual void paintEvent (QPaintEvent * event) + { + //QT generates warnings if we try to paint to a QTreeWidget + //(perhaps because it's a compound widget) so we've disabled + //wx paint and erase background events + QTreeWidget::paintEvent(event); + } + + wxTextCtrl *GetEditControl() + { + return m_item_delegate.GetEditControl(); + } + + void SetItemImage(QTreeWidgetItem *item, int image, wxTreeItemIcon which) + { + m_imageStates[item][which] = image; + } + + int GetItemImage(QTreeWidgetItem *item, wxTreeItemIcon which) + { + if ( m_imageStates.find(item) == m_imageStates.end() ) + return 0; + + return m_imageStates[item][which]; + } + + void SetItemState(QTreeWidgetItem *item, int state) + { + m_imageStates[item].SetState(state); + } + + int GetItemState(QTreeWidgetItem *item) const + { + const ImageStateMap::const_iterator i = m_imageStates.find(item); + if ( i == m_imageStates.end() ) + return wxTREE_ITEMSTATE_NONE; + + return i->second.GetState(); + } + + void ResizeIcons(const QSize &size) + { + m_placeHolderImage = QPixmap(size); + m_placeHolderImage.fill(Qt::transparent); + ReplaceIcons(invisibleRootItem()); + } + + QPixmap GetPlaceHolderImage() const + { + return m_placeHolderImage; + } + +protected: + virtual void drawRow( + QPainter *painter, + const QStyleOptionViewItem &options, + const QModelIndex &index + + ) const wxOVERRIDE + { + QTreeWidget::drawRow(painter, options, index); + + QTreeWidgetItem *item = itemFromIndex(index); + const int imageIndex = ChooseBestImage(item); + + if ( imageIndex != -1 ) + { + const wxImageList *imageList = GetHandler()->GetImageList(); + const wxBitmap bitmap = imageList->GetBitmap(imageIndex); + const QRect rect = visualRect(index); + painter->drawPixmap(rect.topLeft(), *bitmap.GetHandle()); + } + } + + bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event) wxOVERRIDE + { + // AllEditTriggers means that editor is about to open, not waiting for double click + if (trigger == AllEditTriggers) + { + // Allow event handlers to veto opening the editor + wxTreeEvent wx_event( + wxEVT_TREE_BEGIN_LABEL_EDIT, + GetHandler(), + wxQtConvertTreeItem(itemFromIndex(index)) + ); + if (GetHandler()->HandleWindowEvent(wx_event) && !wx_event.IsAllowed()) + return false; + } + return QTreeWidget::edit(index, trigger, event); + } + + void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint) wxOVERRIDE + { + // Close process can re-signal closeEditor so we need to guard against + // reentrant calls. + wxRecursionGuard guard(m_closing_editor); + + if (guard.IsInside()) + return; + + // There can be multiple calls to close editor when the item loses focus + const QModelIndex current_index = m_item_delegate.GetCurrentModelIndex(); + if (!current_index.isValid()) + return; + + wxTreeEvent event( + wxEVT_TREE_END_LABEL_EDIT, + GetHandler(), + wxQtConvertTreeItem(itemFromIndex(current_index)) + ); + if (hint == QAbstractItemDelegate::RevertModelCache) + { + event.SetEditCanceled(true); + EmitEvent(event); + } + else + { + // Allow event handlers to decide whether to accept edited text + const wxString editor_text = m_item_delegate.GetEditControl()->GetLineText(0); + event.SetLabel(editor_text); + if (!GetHandler()->HandleWindowEvent(event) || event.IsAllowed()) + m_item_delegate.AcceptModelData(editor, model(), current_index); + } + // wx doesn't have hints to edit next/previous item + if (hint == QAbstractItemDelegate::EditNextItem || hint == QAbstractItemDelegate::EditPreviousItem) + hint = QAbstractItemDelegate::SubmitModelCache; + + QTreeWidget::closeEditor(editor, hint); + } + +private: + void ReplaceIcons(QTreeWidgetItem *item) + { + item->setIcon(0, m_placeHolderImage); + const int childCount = item->childCount(); + for ( int i = 0; i < childCount; ++i ) + { + ReplaceIcons(item->child(i)); + } + } + + void OnCurrentItemChanged( + QTreeWidgetItem *current, + QTreeWidgetItem *previous + ) + { + wxTreeCtrl* treeCtrl = GetHandler(); + + wxTreeEvent changingEvent( + wxEVT_TREE_SEL_CHANGING, + treeCtrl, + wxQtConvertTreeItem(current) + ); + + changingEvent.SetOldItem(wxQtConvertTreeItem(previous)); + EmitEvent(changingEvent); + + if ( !changingEvent.IsAllowed() ) + { + blockSignals(true); + setCurrentItem(previous); + blockSignals(false); + return; + } + + // QT doesn't update the selection until this signal has been + // processed. Deferring this event ensures that + // wxTreeCtrl::GetSelection returns the new selection in the + // wx event handler. + wxTreeEvent changedEvent( + wxEVT_TREE_SEL_CHANGED, + treeCtrl, + wxQtConvertTreeItem(current) + ); + changedEvent.SetOldItem(wxQtConvertTreeItem(previous)); + wxPostEvent(treeCtrl, changedEvent); + } + + void OnItemActivated(QTreeWidgetItem *item, int WXUNUSED(column)) + { + wxTreeEvent event( + wxEVT_TREE_ITEM_ACTIVATED, + GetHandler(), + wxQtConvertTreeItem(item) + ); + + EmitEvent(event); + } + + void OnItemClicked(QTreeWidgetItem *item) + { + wxMouseState mouseState = wxGetMouseState(); + + wxEventType eventType; + if ( mouseState.RightIsDown() ) + eventType = wxEVT_TREE_ITEM_RIGHT_CLICK; + else if ( mouseState.MiddleIsDown() ) + eventType = wxEVT_TREE_ITEM_MIDDLE_CLICK; + else + return; + + wxTreeEvent event(eventType, GetHandler(), wxQtConvertTreeItem(item)); + EmitEvent(event); + } + + void OnItemCollapsed(QTreeWidgetItem *item) + { + wxTreeEvent collapsingEvent( + wxEVT_TREE_ITEM_COLLAPSING, + GetHandler(), + wxQtConvertTreeItem(item) + ); + EmitEvent(collapsingEvent); + + if ( !collapsingEvent.IsAllowed() ) + { + blockSignals(true); + item->setExpanded(true); + blockSignals(false); + return; + } + + wxTreeEvent collapsedEvent( + wxEVT_TREE_ITEM_COLLAPSED, + GetHandler(), + wxQtConvertTreeItem(item) + ); + EmitEvent(collapsedEvent); + } + + void OnItemExpanded(QTreeWidgetItem *item) + { + wxTreeEvent expandingEvent( + wxEVT_TREE_ITEM_EXPANDING, + GetHandler(), + wxQtConvertTreeItem(item) + ); + EmitEvent(expandingEvent); + + if ( !expandingEvent.IsAllowed() ) + { + blockSignals(true); + item->setExpanded(false); + blockSignals(false); + return; + } + + wxTreeEvent expandedEvent( + wxEVT_TREE_ITEM_EXPANDED, + GetHandler(), + wxQtConvertTreeItem(item) + ); + EmitEvent(expandedEvent); + } + + void tryStartDrag(const QMouseEvent *event) + { + wxEventType command = event->buttons() & Qt::RightButton + ? wxEVT_TREE_BEGIN_RDRAG + : wxEVT_TREE_BEGIN_DRAG; + + QTreeWidgetItem *hitItem = itemAt(event->pos()); + + wxTreeEvent tree_event( + command, + GetHandler(), + wxQtConvertTreeItem(hitItem) + ); + + tree_event.SetPoint(wxQtConvertPoint(event->pos())); + + // Vetoed unless explicitly accepted. + tree_event.Veto(); + + EmitEvent(tree_event); + + if ( !tree_event.IsAllowed() ) + { + setState(DragSelectingState); + } + } + + void endDrag(QPoint position) + { + QTreeWidgetItem *hitItem = itemAt(position); + + wxTreeEvent tree_event( + wxEVT_TREE_END_DRAG, + GetHandler(), + wxQtConvertTreeItem(hitItem) + ); + + tree_event.SetPoint(wxQtConvertPoint(position)); + + EmitEvent(tree_event); + } + + virtual void dropEvent(QDropEvent* event) wxOVERRIDE + { + endDrag(event->pos()); + + // We don't want Qt to actually do the drop. + event->ignore(); + } + + virtual void mouseMoveEvent(QMouseEvent *event) wxOVERRIDE + { + const bool wasDragging = state() == DraggingState; + wxQtEventSignalHandler::mouseMoveEvent(event); + + const bool nowDragging = state() == DraggingState; + if ( !wasDragging && nowDragging ) + { + tryStartDrag(event); + } + } + + int ChooseBestImage(QTreeWidgetItem *item) const + { + int imageIndex = -1; + + const ImageStateMap::const_iterator i = m_imageStates.find(item); + + if ( i == m_imageStates.end() ) + { + return -1; + } + + const ImageState &states = i->second; + + if ( item->isExpanded() ) + { + if ( item->isSelected() ) + imageIndex = states[wxTreeItemIcon_SelectedExpanded]; + + if (imageIndex == -1) + imageIndex = states[wxTreeItemIcon_Expanded]; + } + else + { + if ( item->isSelected() ) + imageIndex = states[wxTreeItemIcon_Selected]; + } + + if ( imageIndex == -1 ) + imageIndex = states[wxTreeItemIcon_Normal]; + + return imageIndex; + } + + wxQTTreeItemDelegate m_item_delegate; + wxRecursionGuardFlag m_closing_editor; + + typedef std::map ImageStateMap; + ImageStateMap m_imageStates; + + // Place holder image to reserve enough space in a row + // for us to draw our icon + QPixmap m_placeHolderImage; +}; + +wxTreeCtrl::wxTreeCtrl() : + m_qtTreeWidget(NULL) { } @@ -23,7 +525,7 @@ wxTreeCtrl::wxTreeCtrl(wxWindow *parent, wxWindowID id, const wxValidator& validator, const wxString& name) { - Create( parent, id, pos, size, style, validator, name ); + Create(parent, id, pos, size, style, validator, name); } bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id, @@ -33,16 +535,28 @@ bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id, const wxValidator& validator, const wxString& name) { - m_qtTreeWidget = new QTreeWidget( parent->GetHandle() ); + m_qtTreeWidget = new wxQTreeWidget(parent, this); + m_qtTreeWidget->header()->hide(); - return QtCreateControl( parent, id, pos, size, style, validator, name ); + SetWindowStyleFlag(style); + + return QtCreateControl(parent, id, pos, size, style, validator, name); +} + +wxTreeCtrl::~wxTreeCtrl() +{ + if ( m_qtTreeWidget != NULL ) + m_qtTreeWidget->deleteLater(); } unsigned wxTreeCtrl::GetCount() const { - return 0; -} + QTreeWidgetItem *root = m_qtTreeWidget->invisibleRootItem(); + if ( root->childCount() == 0 ) + return 0; + return CountChildren(root->child(0)); +} unsigned wxTreeCtrl::GetIndent() const { @@ -56,275 +570,716 @@ void wxTreeCtrl::SetIndent(unsigned int indent) void wxTreeCtrl::SetImageList(wxImageList *imageList) { + m_imageListNormal = imageList; + + int width, height; + m_imageListNormal->GetSize(0, width, height); + m_qtTreeWidget->ResizeIcons(QSize(width, height)); + m_qtTreeWidget->update(); } void wxTreeCtrl::SetStateImageList(wxImageList *imageList) { + m_imageListState = imageList; + m_qtTreeWidget->update(); } wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const { - return wxString(); + if ( !item.IsOk() ) + return wxString(); + + const QTreeWidgetItem* qTreeItem = wxQtConvertTreeItem(item); + return wxQtConvertString(qTreeItem->text(0)); } -int wxTreeCtrl::GetItemImage(const wxTreeItemId& item, - wxTreeItemIcon which) const +int wxTreeCtrl::GetItemImage( + const wxTreeItemId& item, + wxTreeItemIcon which +) const { - return 0; + wxCHECK_MSG(item.IsOk(), -1, "invalid tree item"); + return m_qtTreeWidget->GetItemImage(wxQtConvertTreeItem(item), which); } wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const { - return NULL; + wxCHECK_MSG(item.IsOk(), NULL, "invalid tree item"); + + const QTreeWidgetItem* qTreeItem = wxQtConvertTreeItem(item); + const QVariant itemData = qTreeItem->data(0, Qt::UserRole); + const TreeItemDataQt value = itemData.value(); + return value.getData(); } wxColour wxTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const { - return wxColour(); + wxCHECK_MSG(item.IsOk(), wxNullColour, "invalid tree item"); + + const QTreeWidgetItem* qTreeItem = wxQtConvertTreeItem(item); + return wxQtConvertColour(qTreeItem->textColor(0)); } wxColour wxTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const { - return wxColour(); + wxCHECK_MSG(item.IsOk(), wxNullColour, "invalid tree item"); + + const QTreeWidgetItem* qTreeItem = wxQtConvertTreeItem(item); + return wxQtConvertColour(qTreeItem->backgroundColor(0)); } wxFont wxTreeCtrl::GetItemFont(const wxTreeItemId& item) const { - return wxFont(); + wxCHECK_MSG(item.IsOk(), wxNullFont, "invalid tree item"); + + const QTreeWidgetItem* qTreeItem = wxQtConvertTreeItem(item); + return wxFont(qTreeItem->font(0)); } void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem* qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setText(0, wxQtConvertString(text)); } -void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, - int image, - wxTreeItemIcon which) +void wxTreeCtrl::SetItemImage( + const wxTreeItemId& item, + int image, + wxTreeItemIcon which +) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + m_qtTreeWidget->SetItemImage(wxQtConvertTreeItem(item), image, which); } void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + if ( data != NULL ) + data->SetId(item); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + const TreeItemDataQt treeItemData(data); + qTreeItem->setData(0, Qt::UserRole, QVariant::fromValue(treeItemData)); } void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setChildIndicatorPolicy(has + ? QTreeWidgetItem::ShowIndicator + : QTreeWidgetItem::DontShowIndicatorWhenChildless); } void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + QFont font = qTreeItem->font(0); + font.setBold(bold); + qTreeItem->setFont(0, font); } void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + + wxColour fg, bg; + + if ( highlight ) + { + bg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + fg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + } + else + { + bg = GetBackgroundColour(); + fg = GetForegroundColour(); + } + + qTreeItem->setBackgroundColor(0, wxQtConvertColour(bg)); + qTreeItem->setTextColor(0, wxQtConvertColour(fg)); } -void wxTreeCtrl::SetItemTextColour(const wxTreeItemId& item, const wxColour& col) +void wxTreeCtrl::SetItemTextColour( + const wxTreeItemId& item, + const wxColour& col +) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setTextColor(0, wxQtConvertColour(col)); } -void wxTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& col) +void wxTreeCtrl::SetItemBackgroundColour( + const wxTreeItemId& item, + const wxColour& col +) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setBackgroundColor(0, wxQtConvertColour(col)); } void wxTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setFont(0, font.GetHandle()); } bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const { - return false; + wxCHECK_MSG(item.IsOk(), false, "invalid tree item"); + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + const QRect visualRect = m_qtTreeWidget->visualItemRect(qTreeItem); + return visualRect.isValid(); } bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const { - return false; + wxCHECK_MSG(item.IsOk(), false, "invalid tree item"); + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + return qTreeItem->childCount() > 0; } bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const { - return false; + wxCHECK_MSG(item.IsOk(), false, "invalid tree item"); + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + return qTreeItem->isExpanded(); } bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const { - return false; + wxCHECK_MSG(item.IsOk(), false, "invalid tree item"); + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + return qTreeItem->isSelected(); } bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const { - return false; + wxCHECK_MSG(item.IsOk(), false, "invalid tree item"); + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + const QFont font = qTreeItem->font(0); + return font.bold(); } -size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively) const +size_t wxTreeCtrl::GetChildrenCount( + const wxTreeItemId& item, + bool recursively +) const { - return 0; + wxCHECK_MSG(item.IsOk(), 0, "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + + if ( recursively ) + return CountChildren(qTreeItem); + + return qTreeItem->childCount(); } wxTreeItemId wxTreeCtrl::GetRootItem() const { - return wxTreeItemId(); + const QTreeWidgetItem *root = m_qtTreeWidget->invisibleRootItem(); + return wxQtConvertTreeItem(root->child(0)); } wxTreeItemId wxTreeCtrl::GetSelection() const { - return wxTreeItemId(); + QList selections = m_qtTreeWidget->selectedItems(); + return selections.isEmpty() + ? wxTreeItemId() + : wxQtConvertTreeItem(selections[0]); } size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds& selections) const { - return 0; + QList qtSelections = m_qtTreeWidget->selectedItems(); + + const size_t numberOfSelections = qtSelections.size(); + selections.reserve(numberOfSelections); + for ( size_t i = 0; i < numberOfSelections; ++i ) + { + QTreeWidgetItem *item = qtSelections[i]; + selections.push_back(wxQtConvertTreeItem(item)); + } + + return numberOfSelections; } void wxTreeCtrl::SetFocusedItem(const wxTreeItemId& item) { - + wxCHECK_RET(item.IsOk(), "invalid tree item"); + m_qtTreeWidget->setCurrentItem(wxQtConvertTreeItem(item), 0); } void wxTreeCtrl::ClearFocusedItem() { - + m_qtTreeWidget->setCurrentItem(NULL); } wxTreeItemId wxTreeCtrl::GetFocusedItem() const { - return wxTreeItemId(); + return wxQtConvertTreeItem(m_qtTreeWidget->currentItem()); } wxTreeItemId wxTreeCtrl::GetItemParent(const wxTreeItemId& item) const { - return wxTreeItemId(); + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + return wxQtConvertTreeItem(qTreeItem->parent()); } -wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const +wxTreeItemId wxTreeCtrl::GetFirstChild( + const wxTreeItemId& item, + wxTreeItemIdValue& cookie +) const { - return wxTreeItemId(); + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + + cookie = 0; + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + + return qTreeItem->childCount() > 0 + ? wxQtConvertTreeItem(qTreeItem->child(0)) + : wxTreeItemId(); } -wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const +wxTreeItemId wxTreeCtrl::GetNextChild( + const wxTreeItemId& item, + wxTreeItemIdValue& cookie +) const { + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + + wxIntPtr currentIndex = reinterpret_cast(cookie); + ++currentIndex; + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + + if ( currentIndex < qTreeItem->childCount() ) + { + cookie = reinterpret_cast(currentIndex); + return wxQtConvertTreeItem(qTreeItem->child(currentIndex)); + } + return wxTreeItemId(); } wxTreeItemId wxTreeCtrl::GetLastChild(const wxTreeItemId& item) const { - return wxTreeItemId(); + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + const int childCount = qTreeItem->childCount(); + return childCount == 0 + ? wxTreeItemId() + : wxQtConvertTreeItem(qTreeItem->child(childCount - 1)); } wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const { - return wxTreeItemId(); + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + QTreeWidgetItem *parent = qTreeItem->parent(); + + if ( parent != NULL ) + { + int index = parent->indexOfChild(qTreeItem); + wxASSERT(index != -1); + + ++index; + return index < parent->childCount() + ? wxQtConvertTreeItem(parent->child(index)) + : wxTreeItemId(); + } + + int index = m_qtTreeWidget->indexOfTopLevelItem(qTreeItem); + wxASSERT(index != -1); + + ++index; + return index < m_qtTreeWidget->topLevelItemCount() + ? wxQtConvertTreeItem(m_qtTreeWidget->topLevelItem(index)) + : wxTreeItemId(); } wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const { - return wxTreeItemId(); + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + QTreeWidgetItem *parent = qTreeItem->parent(); + + if ( parent != NULL ) + { + int index = parent->indexOfChild(qTreeItem); + wxASSERT(index != -1); + + --index; + return index >= 0 + ? wxQtConvertTreeItem(parent->child(index)) + : wxTreeItemId(); + } + + int index = m_qtTreeWidget->indexOfTopLevelItem(qTreeItem); + wxASSERT(index != -1); + + --index; + return index >= 0 + ? wxQtConvertTreeItem(m_qtTreeWidget->topLevelItem(index)) + : wxTreeItemId(); } wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const { + wxTreeItemId itemid = GetRootItem(); + if ( !itemid.IsOk() ) + return itemid; + + do + { + if ( IsVisible(itemid) ) + return itemid; + itemid = GetNext(itemid); + } while ( itemid.IsOk() ); + return wxTreeItemId(); } wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const { + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + wxASSERT_MSG(IsVisible(item), "this item itself should be visible"); + + wxTreeItemId id = item; + if ( id.IsOk() ) + { + while ( id = GetNext(id), id.IsOk() ) + { + if ( IsVisible(id) ) + return id; + } + } return wxTreeItemId(); } wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const { - return wxTreeItemId(); + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + wxASSERT_MSG(IsVisible(item), "this item itself should be visible"); + + // find out the starting point + wxTreeItemId prevItem = GetPrevSibling(item); + if ( !prevItem.IsOk() ) + { + prevItem = GetItemParent(item); + } + + // find the first visible item after it + while ( prevItem.IsOk() && !IsVisible(prevItem) ) + { + prevItem = GetNext(prevItem); + if ( !prevItem.IsOk() || prevItem == item ) + { + // there are no visible items before item + return wxTreeItemId(); + } + } + + // from there we must be able to navigate until this item + while ( prevItem.IsOk() ) + { + const wxTreeItemId nextItem = GetNextVisible(prevItem); + if ( !nextItem.IsOk() || nextItem == item ) + break; + + prevItem = nextItem; + } + + return prevItem; } wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text, int image, int selImage, wxTreeItemData *data) { - return wxTreeItemId(); + QTreeWidgetItem *root = m_qtTreeWidget->invisibleRootItem(); + wxTreeItemId newItem = DoInsertItem( + wxQtConvertTreeItem(root), + 0, + text, + image, + selImage, + data + ); + + m_qtTreeWidget->setCurrentItem(NULL); + + if ( (GetWindowStyleFlag() & wxTR_HIDE_ROOT) != 0 ) + m_qtTreeWidget->setRootIndex(m_qtTreeWidget->model()->index(0, 0)); + else + m_qtTreeWidget->setRootIndex(QModelIndex()); + + return newItem; } void wxTreeCtrl::Delete(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + QTreeWidgetItem *parent = qTreeItem->parent(); + + DeleteChildren(qTreeItem); + + if ( parent != NULL ) + { + parent->removeChild(qTreeItem); + } + else + { + m_qtTreeWidget->removeItemWidget(qTreeItem, 0); + } + + SendDeleteEvent(item); + + delete qTreeItem; } +class wxQtEnsureSignalsBlocked +{ +public: + wxQtEnsureSignalsBlocked(QWidget *widget) : + m_widget(widget) + { + m_restore = m_widget->blockSignals(true); + } + + ~wxQtEnsureSignalsBlocked() + { + m_widget->blockSignals(m_restore); + } + +private: + QWidget *m_widget; + bool m_restore; +}; + void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + wxQtEnsureSignalsBlocked ensureSignalsBlock(m_qtTreeWidget); + while ( qTreeItem->childCount() > 0 ) + { + QTreeWidgetItem *child = qTreeItem->child(0); + DeleteChildren(wxQtConvertTreeItem(child)); + qTreeItem->removeChild(child); + + SendDeleteEvent(wxQtConvertTreeItem(child)); + + delete child; + } } void wxTreeCtrl::DeleteAllItems() { + DeleteChildren(wxQtConvertTreeItem(m_qtTreeWidget->invisibleRootItem())); } void wxTreeCtrl::Expand(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setExpanded(true); } void wxTreeCtrl::Collapse(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setExpanded(false); } void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + Collapse(item); + DeleteChildren(item); } void wxTreeCtrl::Toggle(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setSelected(!qTreeItem->isSelected()); } void wxTreeCtrl::Unselect() { + QTreeWidgetItem *current = m_qtTreeWidget->currentItem(); + + if ( current != NULL ) + current->setSelected(false); } void wxTreeCtrl::UnselectAll() { + QList selections = m_qtTreeWidget->selectedItems(); + const size_t selectedCount = selections.size(); + for ( size_t i = 0; i < selectedCount; ++i) + { + selections[i]->setSelected(false); + } } void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + if ( !HasFlag(wxTR_MULTIPLE) ) + { + m_qtTreeWidget->clearSelection(); + } + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->setSelected(select); } void wxTreeCtrl::SelectChildren(const wxTreeItemId& parent) { + wxCHECK_RET(parent.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(parent); + const int childCount = qTreeItem->childCount(); + + for ( int i = 0; i < childCount; ++i ) + { + qTreeItem->child(i)->setSelected(true); + } } void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + QTreeWidgetItem *parent = qTreeItem->parent(); + + while ( parent != NULL ) + { + parent->setExpanded(true); + parent = parent->parent(); + } + + ScrollTo(item); } void wxTreeCtrl::ScrollTo(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + m_qtTreeWidget->scrollToItem(qTreeItem); } -wxTextCtrl *wxTreeCtrl::EditLabel(const wxTreeItemId& item, wxClassInfo* textCtrlClass) +wxTextCtrl *wxTreeCtrl::EditLabel( + const wxTreeItemId& item, + wxClassInfo* WXUNUSED(textCtrlClass) +) { - return NULL; + wxCHECK_MSG(item.IsOk(), NULL, "invalid tree item"); + m_qtTreeWidget->editItem(wxQtConvertTreeItem(item)); + return m_qtTreeWidget->GetEditControl(); } wxTextCtrl *wxTreeCtrl::GetEditControl() const { - return NULL; + return m_qtTreeWidget->GetEditControl(); } -void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges) +void wxTreeCtrl::EndEditLabel( + const wxTreeItemId& item, + bool WXUNUSED(discardChanges) +) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + m_qtTreeWidget->closePersistentEditor(qTreeItem); } void wxTreeCtrl::SortChildren(const wxTreeItemId& item) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + qTreeItem->sortChildren(0, Qt::AscendingOrder); } -bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect, bool textOnly) const +bool wxTreeCtrl::GetBoundingRect( + const wxTreeItemId& item, + wxRect& rect, + bool WXUNUSED(textOnly) +) const { - return false; + wxCHECK_MSG(item.IsOk(), false, "invalid tree item"); + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + const QRect visualRect = m_qtTreeWidget->visualItemRect(qTreeItem); + if ( !visualRect.isValid() ) + return false; + + rect = wxQtConvertRect(visualRect); + return true; +} + +void wxTreeCtrl::SetWindowStyleFlag(long styles) +{ + wxControl::SetWindowStyleFlag(styles); + + m_qtTreeWidget->setSelectionMode( + styles & wxTR_MULTIPLE + ? QTreeWidget::ExtendedSelection + : QTreeWidget::SingleSelection + ); } int wxTreeCtrl::DoGetItemState(const wxTreeItemId& item) const { - return 0; + wxCHECK_MSG(item.IsOk(), wxTREE_ITEMSTATE_NONE, "invalid tree item"); + return m_qtTreeWidget->GetItemState(wxQtConvertTreeItem(item)); } void wxTreeCtrl::DoSetItemState(const wxTreeItemId& item, int state) { + wxCHECK_RET(item.IsOk(), "invalid tree item"); + m_qtTreeWidget->SetItemState(wxQtConvertTreeItem(item), state); } wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent, @@ -333,7 +1288,37 @@ wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent, int image, int selImage, wxTreeItemData *data) { - return wxTreeItemId(); + wxCHECK_MSG(parent.IsOk(), wxTreeItemId(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(parent); + + QTreeWidgetItem *newItem = new QTreeWidgetItem; + newItem->setText(0, wxQtConvertString(text)); + newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); + + TreeItemDataQt treeItemData(data); + newItem->setData(0, Qt::UserRole, QVariant::fromValue(treeItemData)); + + m_qtTreeWidget->SetItemImage(newItem, image, wxTreeItemIcon_Normal); + m_qtTreeWidget->SetItemImage(newItem, selImage, wxTreeItemIcon_Selected); + + newItem->setIcon(0, m_qtTreeWidget->GetPlaceHolderImage()); + + wxTreeItemId wxItem = wxQtConvertTreeItem(newItem); + + if ( data != NULL ) + data->SetId(wxItem); + + if ( pos == static_cast(-1) ) + { + qTreeItem->addChild(newItem); + } + else + { + qTreeItem->insertChild(pos, newItem); + } + + return wxItem; } wxTreeItemId wxTreeCtrl::DoInsertAfter(const wxTreeItemId& parent, @@ -342,15 +1327,67 @@ wxTreeItemId wxTreeCtrl::DoInsertAfter(const wxTreeItemId& parent, int image, int selImage, wxTreeItemData *data) { - return wxTreeItemId(); + wxCHECK_MSG(parent.IsOk(), wxTreeItemId(), "invalid tree item"); + wxCHECK_MSG(idPrevious.IsOk(), wxTreeItemId(), "invalid tree item"); + + const QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(parent); + const int index = qTreeItem->indexOfChild(wxQtConvertTreeItem(idPrevious)); + return DoInsertItem(parent, index + 1, text, image, selImage, data); } wxTreeItemId wxTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) const { - return wxTreeItemId(); + int w, h; + GetSize(&w, &h); + flags = 0; + if ( point.x < 0 ) + flags |= wxTREE_HITTEST_TOLEFT; + else if ( point.x > w ) + flags |= wxTREE_HITTEST_TORIGHT; + + if ( point.y < 0 ) + flags |= wxTREE_HITTEST_ABOVE; + else if ( point.y > h ) + flags |= wxTREE_HITTEST_BELOW; + + if ( flags != 0 ) + return wxTreeItemId(); + + QTreeWidgetItem *hitItem = m_qtTreeWidget->itemAt(wxQtConvertPoint(point)); + flags = hitItem == NULL ? wxTREE_HITTEST_NOWHERE : wxTREE_HITTEST_ONITEM; + return wxQtConvertTreeItem(hitItem); } QWidget *wxTreeCtrl::GetHandle() const { return m_qtTreeWidget; } + +void wxTreeCtrl::SendDeleteEvent(const wxTreeItemId &item) +{ + wxTreeEvent event(wxEVT_TREE_DELETE_ITEM, GetId()); + event.SetItem(item); + HandleWindowEvent(event); +} + +wxTreeItemId wxTreeCtrl::GetNext(const wxTreeItemId &item) const +{ + wxCHECK_MSG(item.IsOk(), wxTreeItemId(), "invalid tree item"); + + QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); + + if ( qTreeItem->childCount() > 0 ) + { + return qTreeItem->child(0); + } + + // Try a sibling of this or ancestor instead + wxTreeItemId p = item; + wxTreeItemId toFind; + do + { + toFind = GetNextSibling(p); + p = GetItemParent(p); + } while ( p.IsOk() && !toFind.IsOk() ); + return toFind; +} diff --git a/tests/controls/treectrltest.cpp b/tests/controls/treectrltest.cpp index 433c32ce61..2b1cd2e2ed 100644 --- a/tests/controls/treectrltest.cpp +++ b/tests/controls/treectrltest.cpp @@ -70,6 +70,7 @@ private: CPPUNIT_TEST( SelectItemMulti ); CPPUNIT_TEST( PseudoTest_SetHiddenRoot ); CPPUNIT_TEST( HasChildren ); + CPPUNIT_TEST( GetCount ); CPPUNIT_TEST_SUITE_END(); void ItemClick(); @@ -94,6 +95,7 @@ private: void Sort(); void KeyNavigation(); void HasChildren(); + void GetCount(); void SelectItemSingle(); void SelectItemMulti(); void PseudoTest_MultiSelect() { ms_multiSelect = true; } @@ -175,6 +177,11 @@ void TreeCtrlTestCase::HasChildren() CPPUNIT_ASSERT( !m_tree->HasChildren(m_grandchild) ); } +void TreeCtrlTestCase::GetCount() +{ + CPPUNIT_ASSERT_EQUAL(3, m_tree->GetCount()); +} + void TreeCtrlTestCase::SelectItemSingle() { // this test should be only ran in single-selection control @@ -272,9 +279,10 @@ void TreeCtrlTestCase::DeleteItem() EventCounter deleteitem(m_tree, wxEVT_TREE_DELETE_ITEM); wxTreeItemId todelete = m_tree->AppendItem(m_root, "deleteme"); + m_tree->AppendItem(todelete, "deleteme2"); m_tree->Delete(todelete); - CPPUNIT_ASSERT_EQUAL(1, deleteitem.GetCount()); + CPPUNIT_ASSERT_EQUAL(2, deleteitem.GetCount()); } void TreeCtrlTestCase::DeleteChildren()