From 31fb32e137a12d99dbf989b095782c3c6a6322c2 Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Fri, 6 Oct 2006 09:50:45 +0000 Subject: [PATCH] Implemended column header mouse clicks. Ascending/descending sorting. Setting the little arrow indicator for ascending and desceding sorting. Generic stubs. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41659 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/dataview.h | 27 ++++++++-- include/wx/generic/dataview.h | 4 ++ include/wx/gtk/dataview.h | 15 +++++- samples/dataview/dataview.cpp | 41 +++++++++++++-- src/common/datavcmn.cpp | 28 +++++++++-- src/generic/datavgen.cpp | 18 +++++++ src/gtk/dataview.cpp | 95 +++++++++++++++++++++++++++++++++-- 7 files changed, 211 insertions(+), 17 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index af2905c47b..2eb0882ae5 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -24,7 +24,7 @@ #if defined(__WXGTK20__) // for testing - #define wxUSE_GENERICDATAVIEWCTRL 1 + // #define wxUSE_GENERICDATAVIEWCTRL 1 #elif defined(__WXMAC__) #define wxUSE_GENERICDATAVIEWCTRL 1 #else @@ -159,6 +159,9 @@ public: wxDataViewSortedListModel( wxDataViewListModel *child ); virtual ~wxDataViewSortedListModel(); + void SetAscending( bool ascending ) { m_ascending = ascending; } + bool GetAscending() { return m_ascending; } + virtual unsigned int GetNumberOfRows(); virtual unsigned int GetNumberOfCols(); // return type as reported by wxVariant @@ -191,9 +194,12 @@ public: virtual void Resort(); private: + bool m_ascending; wxDataViewListModel *m_child; wxDataViewSortedIndexArray m_array; wxDataViewListModelNotifier *m_notifierOnChild; + + void InitStatics(); // BAD protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewSortedListModel) @@ -269,7 +275,11 @@ public: virtual const wxBitmap &GetBitmap(); virtual void SetAlignment( wxAlignment align ) = 0; + + virtual void SetSortable( bool sortable ) = 0; + virtual bool GetSortable() = 0; virtual void SetSortOrder( bool ascending ) = 0; + virtual bool IsSortOrderAscending() = 0; wxDataViewRenderer* GetRenderer() { return m_renderer; } @@ -359,7 +369,8 @@ public: m_row(-1), m_model(NULL), m_value(wxNullVariant), - m_editCancelled(false) + m_editCancelled(false), + m_column(NULL) { } wxDataViewEvent(const wxDataViewEvent& event) @@ -368,7 +379,8 @@ public: m_row(event.m_col), m_model(event.m_model), m_value(event.m_value), - m_editCancelled(event.m_editCancelled) + m_editCancelled(event.m_editCancelled), + m_column(event.m_column) { } int GetColumn() const { return m_col; } @@ -380,6 +392,10 @@ public: const wxVariant &GetValue() const { return m_value; } void SetValue( const wxVariant &value ) { m_value = value; } + // for wxEVT_DATAVIEW_COLUMN_HEADER_CLICKED only + void SetDataViewColumn( wxDataViewColumn *col ) { m_column = col; } + wxDataViewColumn *GetDataViewColumn() { return m_column; } + // was label editing canceled? (for wxEVT_COMMAND_DATVIEW_END_LABEL_EDIT only) bool IsEditCancelled() const { return m_editCancelled; } void SetEditCanceled(bool editCancelled) { m_editCancelled = editCancelled; } @@ -392,6 +408,7 @@ protected: wxDataViewModel *m_model; wxVariant m_value; bool m_editCancelled; + wxDataViewColumn *m_column; private: DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxDataViewEvent) @@ -400,6 +417,8 @@ private: BEGIN_DECLARE_EVENT_TYPES() DECLARE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ROW_SELECTED, -1) DECLARE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ROW_ACTIVATED, -1) + DECLARE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, -1) + DECLARE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, -1) END_DECLARE_EVENT_TYPES() typedef void (wxEvtHandler::*wxDataViewEventFunction)(wxDataViewEvent&); @@ -412,6 +431,8 @@ typedef void (wxEvtHandler::*wxDataViewEventFunction)(wxDataViewEvent&); #define EVT_DATAVIEW_ROW_SELECTED(id, fn) wx__DECLARE_DATAVIEWEVT(ROW_SELECTED, id, fn) #define EVT_DATAVIEW_ROW_ACTIVATED(id, fn) wx__DECLARE_DATAVIEWEVT(ROW_ACTIVATED, id, fn) +#define EVT_DATAVIEW_COLUMN_HEADER_CLICK(id, fn) wx__DECLARE_DATAVIEWEVT(COLUMN_HEADER_CLICK, id, fn) +#define EVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICKED(id, fn) wx__DECLARE_DATAVIEWEVT(COLUMN_HEADER_RIGHT_CLICK, id, fn) #if defined(wxUSE_GENERICDATAVIEWCTRL) diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index 5d6097d707..a8800e37aa 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -224,7 +224,11 @@ public: virtual void SetBitmap( const wxBitmap &bitmap ); virtual void SetAlignment( wxAlignment align ); + + virtual void SetSortable( bool sortable ); + virtual bool GetSortable(); virtual void SetSortOrder( bool ascending ); + virtual bool IsSortOrderAscending(); virtual int GetWidth(); diff --git a/include/wx/gtk/dataview.h b/include/wx/gtk/dataview.h index dbb3d78e11..6965502b28 100644 --- a/include/wx/gtk/dataview.h +++ b/include/wx/gtk/dataview.h @@ -198,7 +198,11 @@ public: virtual void SetBitmap( const wxBitmap &bitmap ); virtual void SetAlignment( wxAlignment align ); + + virtual void SetSortable( bool sortable ); + virtual bool GetSortable(); virtual void SetSortOrder( bool ascending ); + virtual bool IsSortOrderAscending(); virtual int GetWidth(); @@ -211,7 +215,12 @@ public: private: // holds the GTK handle void* m_column; - + + // delayed connection to mouse events + friend class wxDataViewCtrl; + void OnInternalIdle(); + bool m_isConnected; + protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewColumn) }; @@ -257,13 +266,15 @@ public: virtual int GetSelection() const; virtual int GetSelections(wxArrayInt& aSelections) const; - private: friend class wxDataViewCtrlDC; + friend class wxDataViewColumn; friend class wxGtkDataViewListModelNotifier; GtkWidget *m_treeview; wxDataViewListModelNotifier *m_notifier; + virtual void OnInternalIdle(); + private: DECLARE_DYNAMIC_CLASS(wxDataViewCtrl) DECLARE_NO_COPY_CLASS(wxDataViewCtrl) diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index cea6827c42..be70dd56be 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -338,6 +338,9 @@ public: void OnSelectedSorted(wxDataViewEvent &event); void OnActivatedUnsorted(wxDataViewEvent &event); + void OnHeaderClickSorted(wxDataViewEvent &event); + void OnHeaderClickUnsorted(wxDataViewEvent &event); + private: wxDataViewCtrl* dataview_left; wxDataViewCtrl* dataview_right; @@ -345,7 +348,8 @@ private: wxLog *m_logOld; wxTextCtrl *m_logWindow; - MyUnsortedTextModel *m_unsorted_model; + MyUnsortedTextModel *m_unsorted_model; + wxDataViewSortedListModel *m_sorted_model; DECLARE_EVENT_TABLE() }; @@ -474,6 +478,8 @@ BEGIN_EVENT_TABLE(MySortingFrame,wxFrame) EVT_DATAVIEW_ROW_SELECTED( ID_SORTED, MySortingFrame::OnSelectedSorted ) EVT_DATAVIEW_ROW_SELECTED( ID_UNSORTED, MySortingFrame::OnSelectedUnsorted ) EVT_DATAVIEW_ROW_ACTIVATED( ID_UNSORTED, MySortingFrame::OnActivatedUnsorted ) + EVT_DATAVIEW_COLUMN_HEADER_CLICK( ID_SORTED, MySortingFrame::OnHeaderClickSorted ) + EVT_DATAVIEW_COLUMN_HEADER_CLICK( ID_UNSORTED, MySortingFrame::OnHeaderClickUnsorted ) END_EVENT_TABLE() MySortingFrame::MySortingFrame(wxFrame *frame, wxChar *title, int x, int y, int w, int h): @@ -515,9 +521,8 @@ MySortingFrame::MySortingFrame(wxFrame *frame, wxChar *title, int x, int y, int // Right wxDataViewCtrl using the sorting model dataview_right = new wxDataViewCtrl( this, ID_SORTED ); - wxDataViewSortedListModel *sorted_model = - new wxDataViewSortedListModel( m_unsorted_model ); - dataview_right->AssociateModel( sorted_model ); + m_sorted_model = new wxDataViewSortedListModel( m_unsorted_model ); + dataview_right->AssociateModel( m_sorted_model ); text_renderer = new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_EDITABLE ); column = new wxDataViewColumn( wxT("editable"), text_renderer, 0, -1, wxDATAVIEW_COL_SORTABLE|wxDATAVIEW_COL_RESIZABLE ); dataview_right->AppendColumn( column ); @@ -592,6 +597,34 @@ void MySortingFrame::OnActivatedUnsorted(wxDataViewEvent &event) wxLogMessage( wxT("OnActivated from unsorted list, activated %d"), (int) event.GetRow() ); } +void MySortingFrame::OnHeaderClickSorted(wxDataViewEvent &event) +{ + wxDataViewColumn *col = event.GetDataViewColumn(); + wxLogMessage( wxT("OnHeaderClick from sorted list, column %s"), col->GetTitle().c_str() ); + + if (col->GetTitle() == wxT("editable")) + { + // this is the sorting column + if (col->IsSortOrderAscending()) + { + col->SetSortOrder( false ); + m_sorted_model->SetAscending( false ); + m_sorted_model->Resort(); + } + else + { + col->SetSortOrder( true ); + m_sorted_model->SetAscending( true ); + m_sorted_model->Resort(); + } + } +} + +void MySortingFrame::OnHeaderClickUnsorted(wxDataViewEvent &event) +{ + wxLogMessage( wxT("OnHeaderClick from unsorted list, column %s"), event.GetDataViewColumn()->GetTitle().c_str() ); +} + void MySortingFrame::OnQuit(wxCommandEvent& WXUNUSED(event) ) { Close(true); diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index 976723b2f4..26d78c6b4d 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -287,9 +287,15 @@ int wxCALLBACK wxDataViewListModelSortedDefaultCompare return 0; } +int wxCALLBACK wxDataViewListModelSortedDefaultCompareDescending + (unsigned int row1, unsigned int row2, unsigned int col, wxDataViewListModel* model ) +{ + return wxDataViewListModelSortedDefaultCompare( row2, row1, col, model ); +} + static wxDataViewListModelCompare s_CmpFunc; static wxDataViewListModel *s_CmpModel; -static unsigned int s_CmpCol; +static unsigned int s_CmpCol; int LINKAGEMODE wxDataViewIntermediateCmp( unsigned int row1, unsigned int row2 ) { @@ -306,9 +312,8 @@ wxDataViewSortedListModel::wxDataViewSortedListModel( wxDataViewListModel *child m_array( wxDataViewIntermediateCmp ) { m_child = child; - s_CmpCol = 0; - s_CmpModel = child; - s_CmpFunc = wxDataViewListModelSortedDefaultCompare; + + m_ascending = true; m_notifierOnChild = new wxDataViewSortedListModelNotifier( this ); m_child->AddNotifier( m_notifierOnChild ); @@ -321,8 +326,21 @@ wxDataViewSortedListModel::~wxDataViewSortedListModel() m_child->RemoveNotifier( m_notifierOnChild ); } +// FIXME +void wxDataViewSortedListModel::InitStatics() +{ + s_CmpCol = 0; + s_CmpModel = m_child; + if (m_ascending) + s_CmpFunc = wxDataViewListModelSortedDefaultCompare; + else + s_CmpFunc = wxDataViewListModelSortedDefaultCompareDescending; +} + void wxDataViewSortedListModel::Resort() { + InitStatics(); + m_array.Clear(); unsigned int n = m_child->GetNumberOfRows(); unsigned int i; @@ -866,6 +884,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxDataViewEvent,wxNotifyEvent) DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ROW_SELECTED) DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ROW_ACTIVATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK) #endif diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index d3564748c1..e3886ffcf4 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -617,11 +617,29 @@ void wxDataViewColumn::SetAlignment( wxAlignment WXUNUSED(align) ) // TODO } +void wxDataViewColumn::SetSortable( bool WXUNUSED(sortable) ) +{ + // TODO +} + +bool wxDataViewColumn::GetSortable() +{ + // TODO + return false; +} + void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending) ) { // TODO } +bool wxDataViewColumn::IsSortOrderAscending() +{ + // TODO + return true; +} + + wxDataViewColumn::~wxDataViewColumn() { } diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 752e3e69a8..7d4d4eafb0 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -1384,6 +1384,27 @@ bool wxDataViewDateRenderer::Activate( wxRect cell, wxDataViewListModel *model, // wxDataViewColumn // --------------------------------------------------------- + +static gboolean +gtk_dataview_header_button_press_callback( GtkWidget *widget, + GdkEventButton *gdk_event, + wxDataViewColumn *column ) +{ + if (gdk_event->type != GDK_BUTTON_PRESS) + return TRUE; + + if (gdk_event->button == 1) + { + wxDataViewCtrl *dv = column->GetOwner(); + wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, dv->GetId() ); + event.SetDataViewColumn( column ); + event.SetModel( dv->GetModel() ); + dv->GetEventHandler()->ProcessEvent( event ); + } + + return TRUE; +} + extern "C" { static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column, GtkCellRenderer *cell, @@ -1423,11 +1444,16 @@ wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *c int width, int flags ) : wxDataViewColumnBase( title, cell, model_column, width, flags ) { + m_isConnected = false; + GtkCellRenderer *renderer = (GtkCellRenderer *) cell->GetGtkHandle(); GtkTreeViewColumn *column = gtk_tree_view_column_new(); - - gtk_tree_view_column_set_title( column, wxGTK_CONV(title) ); + m_column = (void*) column; + + gtk_tree_view_column_set_clickable( column, true ); + + SetTitle( title ); if (flags & wxDATAVIEW_COL_RESIZABLE) gtk_tree_view_column_set_resizable( column, true ); @@ -1447,13 +1473,14 @@ wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *c gtk_tree_view_column_set_cell_data_func( column, renderer, wxGtkTreeCellDataFunc, (gpointer) cell, NULL ); - m_column = (void*) column; } wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell, unsigned int model_column, int width, int flags ) : wxDataViewColumnBase( bitmap, cell, model_column, width, flags ) { + m_isConnected = false; + GtkCellRenderer *renderer = (GtkCellRenderer *) cell->GetGtkHandle(); GtkTreeViewColumn *column = gtk_tree_view_column_new(); @@ -1484,13 +1511,41 @@ wxDataViewColumn::~wxDataViewColumn() { } +void wxDataViewColumn::OnInternalIdle() +{ + if (m_isConnected) + return; + + if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview)) + { + GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + if (column->button) + { + g_signal_connect(column->button, "button_press_event", + G_CALLBACK (gtk_dataview_header_button_press_callback), this); + + m_isConnected = true; + } + } +} + void wxDataViewColumn::SetTitle( const wxString &title ) { wxDataViewColumnBase::SetTitle( title ); GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; - gtk_tree_view_column_set_title( column, wxGTK_CONV(title) ); + if (m_isConnected) + { + // disconnect before column->button gets recreated + g_signal_handlers_disconnect_by_func( column->button, + (void*) gtk_dataview_header_button_press_callback, this); + + m_isConnected = false; + } + + gtk_tree_view_column_set_title( column, wxGTK_CONV(title) ); + gtk_tree_view_column_set_widget( column, NULL ); } @@ -1540,6 +1595,18 @@ void wxDataViewColumn::SetAlignment( wxAlignment align ) gtk_tree_view_column_set_alignment( column, xalign ); } +void wxDataViewColumn::SetSortable( bool sortable ) +{ + GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + gtk_tree_view_column_set_sort_indicator( column, sortable ); +} + +bool wxDataViewColumn::GetSortable() +{ + GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + return gtk_tree_view_column_get_sort_indicator( column ); +} + void wxDataViewColumn::SetSortOrder( bool ascending ) { GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; @@ -1550,6 +1617,13 @@ void wxDataViewColumn::SetSortOrder( bool ascending ) gtk_tree_view_column_set_sort_order( column, GTK_SORT_DESCENDING ); } +bool wxDataViewColumn::IsSortOrderAscending() +{ + GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + + return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING); +} + int wxDataViewColumn::GetWidth() { return gtk_tree_view_column_get_width( (GtkTreeViewColumn *)m_column ); @@ -1652,6 +1726,19 @@ bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id, return true; } +void wxDataViewCtrl::OnInternalIdle() +{ + wxWindow::OnInternalIdle(); + + unsigned int cols = GetNumberOfColumns(); + unsigned int i; + for (i = 0; i < cols; i++) + { + wxDataViewColumn *col = GetColumn( i ); + col->OnInternalIdle(); + } +} + bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model ) { if (!wxDataViewCtrlBase::AssociateModel( model )) -- 2.45.2