From 67d3fc4926c67818cfbee1cbb1e1b5cbb619afc0 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sat, 10 Nov 2007 00:55:14 +0000
Subject: [PATCH] added functions for setting the columns order in wxListCtrl
 (modified patch 1828074)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@49802 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt           |  1 +
 docs/latex/wx/listctrl.tex | 49 +++++++++++++++++++++
 include/wx/msw/listctrl.h  | 59 ++++++++++++++++----------
 src/msw/listctrl.cpp       | 87 ++++++++++++++++++++++++++++++++++++--
 4 files changed, 169 insertions(+), 27 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index df53c8c39e..f1a65323fe 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -191,6 +191,7 @@ All (GUI):
 - Added support for drop down toolbar buttons (Tim Kosse).
 - Added support for labels for toolbar controls (Vince Harron).
 - Added wxMessageDialog::SetMessage() and SetExtendedMessage().
+- Added wxListCtrl::Set/GetColumnsOrder() (Yury Voronov)
 - Added wxWindow::AlwaysShowScrollbars() (Julian Scheid)
 - Added wxMouseEvent::GetClickCount() (Julian Scheid)
 - Added wxBG_STYLE_TRANSPARENT background style (Julian Scheid)
diff --git a/docs/latex/wx/listctrl.tex b/docs/latex/wx/listctrl.tex
index e92d627f7d..ac0fdfb739 100644
--- a/docs/latex/wx/listctrl.tex
+++ b/docs/latex/wx/listctrl.tex
@@ -115,6 +115,22 @@ functions that take a \helpref{wxListEvent}{wxlistevent} argument.
 \twocolitem{{\bf EVT\_LIST\_CACHE\_HINT(id, func)}}{Prepare cache for a virtual list control}
 \end{twocollist}%
 
+\wxheading{Column ordering}
+
+In report view, the control has several columns which are identified by their
+internal indices. By default, these indices correspond to their order on
+screen, i.e. the column $0$ appears first (in the left-to-right or maybe
+right-to-left if the current language uses this writing direction), the column
+$1$ next and so on. However it is possible to reorder the columns visual order
+using \helpref{SetColumnsOrder}{wxlistctrlsetcolumnsorder} method and the
+user can also rearrange the columns interactively by dragging them. In this
+case, the index of the column is not the same as its order and the functions
+\helpref{GetColumnOrder}{wxlistctrlgetcolumnorder} and 
+\helpref{GetColumnIndexFromOrder}{wxlistctrlgetcolumnindexfromorder} should be
+used to translate between them.
+
+Please notice that current column reordering is implemented only in wxMSW.
+
 \wxheading{See also}
 
 \helpref{wxListCtrl overview}{wxlistctrloverview}, \helpref{wxListView}{wxlistview}, \helpref{wxListBox}{wxlistbox},\rtfsp
@@ -321,6 +337,28 @@ Returns the number of columns.
 Gets the column width (report view only).
 
 
+\membersection{wxListCtrl::GetColumnIndexFromOrder}\label{wxlistctrlgetcolumnindexfromorder}
+
+\constfunc{int}{GetColumnIndexFromOrder}{\param{int }{order}}
+
+Gets the column number by visual order index (report view only).
+
+
+\membersection{wxListCtrl::GetColumnOrder}\label{wxlistctrlgetcolumnorder}
+
+\constfunc{int}{GetColumnOrder}{\param{int }{col}}
+
+Gets the column visual order index (valid in report view only).
+
+
+\membersection{wxListCtrl::GetColumnsOrder}\label{wxlistctrlgetcolumnsorder}
+
+\constfunc{wxArrayInt}{GetColumnsOrder}{\void}
+
+Returns the array containing the orders of all columns. On error, an empty
+array is returned.
+
+
 \membersection{wxListCtrl::GetCountPerPage}\label{wxlistctrlgetcountperpage}
 
 \constfunc{int}{GetCountPerPage}{\void}
@@ -836,6 +874,17 @@ will resize the column to the length of the header (Win32) or 80 pixels (other p
 In small or normal icon view, {\it col} must be -1, and the column width is set for all columns.
 
 
+\membersection{wxListCtrl::SetColumnsOrder}\label{wxlistctrlsetcolumnsorder}
+
+\constfunc{bool}{SetColumnOrder}{\param{const wxArrayInt\& }{orders}}
+
+Sets the order of all columns at once. The \arg{orders} array must have the
+same number elements as the number of columns and contain each position exactly
+once.
+
+This function is valid in report view only.
+
+
 \membersection{wxListCtrl::SetImageList}\label{wxlistctrlsetimagelist}
 
 \func{void}{SetImageList}{\param{wxImageList*}{ imageList}, \param{int }{which}}
diff --git a/include/wx/msw/listctrl.h b/include/wx/msw/listctrl.h
index b732827376..00583ea8a3 100644
--- a/include/wx/msw/listctrl.h
+++ b/include/wx/msw/listctrl.h
@@ -13,6 +13,7 @@
 #define _WX_LISTCTRL_H_
 
 #include "wx/textctrl.h"
+#include "wx/dynarray.h"
 
 class WXDLLIMPEXP_FWD_CORE wxImageList;
 
@@ -114,13 +115,25 @@ public:
     bool GetColumn(int col, wxListItem& item) const;
 
     // Sets information about this column
-    bool SetColumn(int col, const wxListItem& item) ;
+    bool SetColumn(int col, const wxListItem& item);
 
     // Gets the column width
     int GetColumnWidth(int col) const;
 
     // Sets the column width
-    bool SetColumnWidth(int col, int width) ;
+    bool SetColumnWidth(int col, int width);
+
+
+    // Gets the column order from its index or index from its order
+    int GetColumnOrder(int col) const;
+    int GetColumnIndexFromOrder(int order) const;
+
+    // Gets the column order for all columns
+    wxArrayInt GetColumnsOrder() const;
+
+    // Sets the column order for all columns
+    bool SetColumnsOrder(const wxArrayInt& orders);
+
 
     // Gets the number of items that can fit vertically in the
     // visible area of the list control (list or report view)
@@ -135,48 +148,48 @@ public:
     wxTextCtrl* GetEditControl() const;
 
     // Gets information about the item
-    bool GetItem(wxListItem& info) const ;
+    bool GetItem(wxListItem& info) const;
 
     // Sets information about the item
-    bool SetItem(wxListItem& info) ;
+    bool SetItem(wxListItem& info);
 
     // Sets a string field at a particular column
     long SetItem(long index, int col, const wxString& label, int imageId = -1);
 
     // Gets the item state
-    int  GetItemState(long item, long stateMask) const ;
+    int  GetItemState(long item, long stateMask) const;
 
     // Sets the item state
-    bool SetItemState(long item, long state, long stateMask) ;
+    bool SetItemState(long item, long state, long stateMask);
 
     // Sets the item image
-    bool SetItemImage(long item, int image, int selImage = -1) ;
+    bool SetItemImage(long item, int image, int selImage = -1);
     bool SetItemColumnImage(long item, long column, int image);
 
     // Gets the item text
-    wxString GetItemText(long item) const ;
+    wxString GetItemText(long item) const;
 
     // Sets the item text
-    void SetItemText(long item, const wxString& str) ;
+    void SetItemText(long item, const wxString& str);
 
     // Gets the item data
-    wxUIntPtr GetItemData(long item) const ;
+    wxUIntPtr GetItemData(long item) const;
 
     // Sets the item data
     bool SetItemPtrData(long item, wxUIntPtr data);
     bool SetItemData(long item, long data) { return SetItemPtrData(item, data); }
 
     // Gets the item rectangle
-    bool GetItemRect(long item, wxRect& rect, int code = wxLIST_RECT_BOUNDS) const ;
+    bool GetItemRect(long item, wxRect& rect, int code = wxLIST_RECT_BOUNDS) const;
 
     // Gets the subitem rectangle in report mode
-    bool GetSubItemRect(long item, long subItem, wxRect& rect, int code = wxLIST_RECT_BOUNDS) const ;
+    bool GetSubItemRect(long item, long subItem, wxRect& rect, int code = wxLIST_RECT_BOUNDS) const;
 
     // Gets the item position
-    bool GetItemPosition(long item, wxPoint& pos) const ;
+    bool GetItemPosition(long item, wxPoint& pos) const;
 
     // Sets the item position
-    bool SetItemPosition(long item, const wxPoint& pos) ;
+    bool SetItemPosition(long item, const wxPoint& pos);
 
     // Gets the number of items in the list control
     int GetItemCount() const;
@@ -210,22 +223,22 @@ public:
 
     // Gets the index of the topmost visible item when in
     // list or report view
-    long GetTopItem() const ;
+    long GetTopItem() const;
 
     // Add or remove a single window style
-    void SetSingleStyle(long style, bool add = true) ;
+    void SetSingleStyle(long style, bool add = true);
 
     // Set the whole window style
-    void SetWindowStyleFlag(long style) ;
+    void SetWindowStyleFlag(long style);
 
     // Searches for an item, starting from 'item'.
     // item can be -1 to find the first item that matches the
     // specified flags.
     // Returns the item or -1 if unsuccessful.
-    long GetNextItem(long item, int geometry = wxLIST_NEXT_ALL, int state = wxLIST_STATE_DONTCARE) const ;
+    long GetNextItem(long item, int geometry = wxLIST_NEXT_ALL, int state = wxLIST_STATE_DONTCARE) const;
 
     // Gets one of the three image lists
-    wxImageList *GetImageList(int which) const ;
+    wxImageList *GetImageList(int which) const;
 
     // Sets the image list
     // N.B. There's a quirk in the Win95 list view implementation.
@@ -234,8 +247,8 @@ public:
     // haven't specified wxLIST_MASK_IMAGE when inserting.
     // So you have to set a NULL small-icon image list to be sure that
     // the wxLC_LIST mode works without icons. Of course, you may want icons...
-    void SetImageList(wxImageList *imageList, int which) ;
-    void AssignImageList(wxImageList *imageList, int which) ;
+    void SetImageList(wxImageList *imageList, int which);
+    void AssignImageList(wxImageList *imageList, int which);
 
     // are we in report mode?
     bool InReportView() const { return HasFlag(wxLC_REPORT); }
@@ -257,7 +270,7 @@ public:
     bool DeleteItem(long item);
 
     // Deletes all items
-    bool DeleteAllItems() ;
+    bool DeleteAllItems();
 
     // Deletes a column
     bool DeleteColumn(int col);
@@ -275,7 +288,7 @@ public:
     bool EndEditLabel(bool cancel);
 
     // Ensures this item is visible
-    bool EnsureVisible(long item) ;
+    bool EnsureVisible(long item);
 
     // Find an item whose label matches this string, starting from the item after 'start'
     // or the beginning if 'start' is -1.
diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp
index b248381832..1f67a95bbc 100644
--- a/src/msw/listctrl.cpp
+++ b/src/msw/listctrl.cpp
@@ -342,8 +342,17 @@ bool wxListCtrl::Create(wxWindow *parent,
     // styles because it's prettier (and also because wxGTK does it like this)
     if ( InReportView() && wxApp::GetComCtl32Version() >= 470 )
     {
-        ::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE,
-                      0, LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES);
+        ::SendMessage
+        (
+            GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
+            LVS_EX_LABELTIP |
+            LVS_EX_FULLROWSELECT |
+            LVS_EX_SUBITEMIMAGES |
+            // normally this should be governed by a style as it's probably not
+            // always appropriate, but we don't have any free styles left and
+            // it seems better to enable it by default than disable
+            LVS_EX_HEADERDRAGDROP
+        );
     }
 
     return true;
@@ -663,6 +672,68 @@ bool wxListCtrl::SetColumnWidth(int col, int width)
     return ListView_SetColumnWidth(GetHwnd(), col, width) != 0;
 }
 
+// ----------------------------------------------------------------------------
+// columns order
+// ----------------------------------------------------------------------------
+
+int wxListCtrl::GetColumnOrder(int col) const
+{
+    const int numCols = GetColumnCount();
+    wxCHECK_MSG( col >= 0 && col < numCols, -1, _T("Col index out of bounds") );
+
+    wxArrayInt indexArray(numCols);
+
+    if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols, &indexArray[0]) )
+        return -1;
+
+    return indexArray[col];
+}
+
+int wxListCtrl::GetColumnIndexFromOrder(int order) const
+{
+    const int numCols = GetColumnCount();
+    wxASSERT_MSG( order >= 0 && order < numCols, _T("Col order out of bounds") );
+
+    wxArrayInt indexArray(numCols);
+
+    if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols, &indexArray[0]) )
+        return -1;
+
+    for ( int col = 0; col < numCols; col++ )
+    {
+        if ( indexArray[col] == order )
+            return col;
+    }
+
+    wxFAIL_MSG( _T("no column with with given order?") );
+
+    return -1;
+}
+
+// Gets the column order for all columns
+wxArrayInt wxListCtrl::GetColumnsOrder() const
+{
+    const int numCols = GetColumnCount();
+
+    wxArrayInt orders(numCols);
+    if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols, &orders[0]) )
+        orders.clear();
+
+    return orders;
+}
+
+// Sets the column order for all columns
+bool wxListCtrl::SetColumnsOrder(const wxArrayInt& orders)
+{
+    const int numCols = GetColumnCount();
+
+    wxCHECK_MSG( orders.size() == (size_t)numCols, false,
+                    _T("wrong number of elements in column orders array") );
+
+    return ListView_SetColumnOrderArray(GetHwnd(), numCols, &orders[0]) != 0;
+}
+
+
 // Gets the number of items that can fit vertically in the
 // visible area of the list control (list or report view)
 // or the total number of items in the list control (icon
@@ -2750,14 +2821,22 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
 
             dc.SetPen(pen);
             dc.SetBrush(*wxTRANSPARENT_BRUSH);
+
+            int numCols = GetColumnCount();
+            int* indexArray = new int[numCols];
+            BOOL rv = ListView_GetColumnOrderArray( GetHwnd(), numCols, indexArray );
+            wxASSERT_MSG( rv == TRUE, _T("invalid column index array in OnPaint()") );
+
             int x = itemRect.GetX();
-            for (int col = 0; col < GetColumnCount(); col++)
+            for (int col = 0; col < numCols; col++)
             {
-                int colWidth = GetColumnWidth(col);
+                int colWidth = GetColumnWidth(indexArray[col]);
                 x += colWidth ;
                 dc.DrawLine(x-1, firstItemRect.GetY() - gap,
                             x-1, itemRect.GetBottom());
             }
+
+            delete indexArray;
         }
     }
 }
-- 
2.47.2

