source: trunk/src/WTLx/ListViewSortMixin.hpp @ 656

Revision 656, 10.4 KB checked in by Eoin, 11 years ago (diff)

Halite ListView? sorting fully working. Clean up to follow.

Line 
1
2//         Copyright Eóin O'Callaghan 2008 - 2008.
3// Distributed under the Boost Software License, Version 1.0.
4//    (See accompanying file LICENSE_1_0.txt or copy at
5//          http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef LISTVIEW_SORT_MIXIN_HPP_INCLUDED
8#define LISTVIEW_SORT_MIXIN_HPP_INCLUDED
9
10#include <boost/iterator/filter_iterator.hpp>
11#include <winstl/controls/listview_sequence.hpp>
12
13#define SORTLV_USESHELLBITMAPS  0x00000001
14
15namespace WTLx
16{
17
18template<typename T>
19class ListViewSortMixin : public WTL::CSortListViewImpl<T>
20{
21protected:
22       
23        // Column sort types. Can be set on a per-column basis with the SetColumnSortType method.
24/*      enum
25        {
26                LVCOLSORT_NONE,
27                LVCOLSORT_TEXT,   // default
28                LVCOLSORT_TEXTNOCASE,
29                LVCOLSORT_LONG,
30                LVCOLSORT_DOUBLE,
31                LVCOLSORT_DECIMAL,
32                LVCOLSORT_DATETIME,
33                LVCOLSORT_DATE,
34                LVCOLSORT_TIME,
35                LVCOLSORT_CUSTOM,
36                LVCOLSORT_LAST = LVCOLSORT_CUSTOM
37        };
38
39        enum
40        {
41                m_cchCmpTextMax = 32, // overrideable
42                m_cxSortImage = 16,
43                m_cySortImage = 15,
44                m_cxSortArrow = 11,
45                m_cySortArrow = 6,
46                m_iSortUp = 0,        // index of sort bitmaps
47                m_iSortDown = 1,
48                m_nShellSortUpID = 133
49        };     
50*/
51        BEGIN_MSG_MAP(ListViewSortMixin)
52                MESSAGE_HANDLER(LVM_INSERTCOLUMN, WTL::CSortListViewImpl<T>::OnInsertColumn)
53                MESSAGE_HANDLER(LVM_DELETECOLUMN, WTL::CSortListViewImpl<T>::OnDeleteColumn)
54                NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick)
55                NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick)
56                MESSAGE_HANDLER(WM_SETTINGCHANGE, WTL::CSortListViewImpl<T>::OnSettingChange)
57        END_MSG_MAP()
58
59/*      LRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& )
60        {
61                T* pT = static_cast<T*>(this);
62                LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
63                if(lRet == -1)
64                        return -1;
65
66                WORD wType = 0;
67                m_arrColSortType.Add(wType);
68                int nCount = m_arrColSortType.GetSize();
69                ATLASSERT(nCount == GetColumnCount());
70
71                for(int i = nCount - 1; i > lRet; i--)
72                        m_arrColSortType[i] = m_arrColSortType[i - 1];
73                m_arrColSortType[(int)lRet] = LVCOLSORT_TEXT;
74
75                if(lRet <= m_iSortColumn)
76                        m_iSortColumn++;
77
78                return lRet;
79        }
80
81        LRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&) 
82        {
83                T* pT = static_cast<T*>(this);
84                LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
85                if(lRet == 0)
86                        return 0;
87
88                int iCol = (int)wParam;
89                if(m_iSortColumn == iCol)
90                        m_iSortColumn = -1;
91                else if(m_iSortColumn > iCol)
92                        m_iSortColumn--;
93                m_arrColSortType.RemoveAt(iCol);
94
95                return lRet;
96        }
97
98        LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
99        {
100#ifndef _WIN32_WCE
101                if(wParam == SPI_SETNONCLIENTMETRICS)
102                        GetSystemSettings();
103#else  // CE specific
104                wParam; // avoid level 4 warning
105                GetSystemSettings();
106#endif // _WIN32_WCE
107                bHandled = FALSE;
108                return 0;
109        }
110
111        void GetSystemSettings()
112        {
113                if(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull())
114                {
115                        T* pT = static_cast<T*>(this);
116                        pT->CreateSortBitmaps();
117                        if(m_iSortColumn != -1)
118                                SetSortColumn(m_iSortColumn);
119                }
120        }
121*/
122        DWORD SetListViewSortMixinExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
123        {
124                DWORD dwPrevStyle = m_dwSortLVExtendedStyle;
125                if(dwMask == 0)
126                        m_dwSortLVExtendedStyle = dwExtendedStyle;
127                else
128                        m_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
129                return dwPrevStyle;
130        }
131
132        DWORD GetListViewSortMixibExtendedStyle() const
133        {
134                return m_dwSortLVExtendedStyle;
135        }
136       
137
138        void SetColumnSortType(int iCol, WORD wType)
139        {
140                HAL_DEV_MSG(hal::wform(L"SetColumnSortType(int iCol = %1%, WORD wType = %2%)") % iCol % wType);
141
142                ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());
143                ATLASSERT(wType >= WTL::LVCOLSORT_NONE);
144                m_arrColSortType[iCol] = wType;         
145        }
146
147/*      int GetColumnCount() const
148        {
149                const T* pT = static_cast<const T*>(this);
150                ATLASSERT(::IsWindow(pT->m_hWnd));
151                WTL::CHeaderCtrl header = pT->GetHeader();
152                return header.m_hWnd != NULL ? header.GetItemCount() : 0;
153        }
154        */
155        LRESULT OnHeaderItemClick(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
156        {               
157                HAL_DEV_MSG(hal::wform(L"OnHeaderItemClick(int idCtrl = %1%, LPNMHDR pnmh, BOOL& bHandled)") % idCtrl);
158
159                LPNMHEADER p = (LPNMHEADER)pnmh;
160                if(p->iButton == 0)
161                {
162                        int iOld = m_iSortColumn;
163                        bool bDescending = (m_iSortColumn == p->iItem) ? !m_bSortDescending : false;
164
165                        if (DoSortItems(p->iItem, bDescending))
166                                NotifyParentSortChanged(p->iItem, iOld);
167                }
168                bHandled = FALSE;
169                return 0;
170        }
171
172//  Operations
173        bool DoSortItems(int iCol, bool bDescending = false)
174        {
175                HAL_DEV_MSG(hal::wform(L"DoSortItems(int iCol = %1%, bool bDescending = %2%)") % iCol % bDescending);
176
177                T* pT = static_cast<T*>(this);
178                ATLASSERT(::IsWindow(pT->m_hWnd));
179                ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());
180
181                WORD wType = m_arrColSortType[iCol];
182                if(wType == WTL::LVCOLSORT_NONE)
183                        return false;
184                else if (wType <= WTL::LVCOLSORT_LAST)
185                {
186                        HAL_DEV_MSG(hal::wform(L"wType = %1%, passing DoSort() to base class") % wType);
187                        return WTL::CSortListViewImpl<T>::DoSortItems(iCol, bDescending);
188                }
189
190                int nCount = pT->GetItemCount();
191                if(nCount < 2)
192                {
193                        m_bSortDescending = bDescending;
194                        SetSortColumn(iCol);
195                        return true;
196                }
197
198                WTL::CWaitCursor waitCursor(false);
199                if(m_bUseWaitCursor)
200                        waitCursor.Set();
201
202                bool bRet = pT->DoSortItems(iCol, bDescending);
203
204                if(bRet)
205                {
206                        m_bSortDescending = bDescending;
207                        SetSortColumn(iCol);
208                }
209
210                if(m_bUseWaitCursor)
211                        waitCursor.Restore();
212
213                return bRet;
214        }
215/*
216        void SetSortColumn(int iCol)
217        {
218                T* pT = static_cast<T*>(this);
219                ATLASSERT(::IsWindow(pT->m_hWnd));
220                WTL::CHeaderCtrl header = pT->GetHeader();
221                ATLASSERT(header.m_hWnd != NULL);
222                ATLASSERT(iCol >= -1 && iCol < m_arrColSortType.GetSize());
223
224                int iOldSortCol = m_iSortColumn;
225                m_iSortColumn = iCol;
226
227                if(m_bCommCtrl6)
228                {
229#ifndef HDF_SORTUP
230                        const int HDF_SORTUP = 0x0400; 
231#endif // HDF_SORTUP
232#ifndef HDF_SORTDOWN
233                        const int HDF_SORTDOWN = 0x0200;       
234#endif // HDF_SORTDOWN
235                        const int nMask = HDF_SORTUP | HDF_SORTDOWN;
236                        HDITEM hditem = { HDI_FORMAT };
237                        if(iOldSortCol != iCol && iOldSortCol >= 0 && header.GetItem(iOldSortCol, &hditem))
238                        {
239                                hditem.fmt &= ~nMask;
240                                header.SetItem(iOldSortCol, &hditem);
241                        }
242                        if(iCol >= 0 && header.GetItem(iCol, &hditem))
243                        {
244                                hditem.fmt &= ~nMask;
245                                hditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP;
246                                header.SetItem(iCol, &hditem);
247                        }
248                        return;
249                }
250
251                if(m_bmSort[m_iSortUp].IsNull())
252                        pT->CreateSortBitmaps();
253
254                // restore previous sort column's bitmap, if any, and format
255                HDITEM hditem = { HDI_BITMAP | HDI_FORMAT };
256                if(iOldSortCol != iCol && iOldSortCol >= 0)
257                {
258                        hditem.hbm = m_hbmOldSortCol;
259                        hditem.fmt = m_fmtOldSortCol;
260                        header.SetItem(iOldSortCol, &hditem);
261                }
262
263                // save new sort column's bitmap and format, and add our sort bitmap
264                if(iCol >= 0 && header.GetItem(iCol, &hditem))
265                {
266                        if(iOldSortCol != iCol)
267                        {
268                                m_fmtOldSortCol = hditem.fmt;
269                                m_hbmOldSortCol = hditem.hbm;
270                        }
271                        hditem.fmt &= ~HDF_IMAGE;
272                        hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT;
273                        int i = m_bSortDescending ? m_iSortDown : m_iSortUp;
274                        hditem.hbm = m_bmSort[i];
275                        header.SetItem(iCol, &hditem);
276                }
277        }
278
279        void CreateSortBitmaps()
280        {
281                if((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0)
282                {
283                        bool bFree = false;
284                        LPCTSTR pszModule = _T("shell32.dll");
285                        HINSTANCE hShell = ::GetModuleHandle(pszModule);
286
287                        if (hShell == NULL)             
288                        {
289                                hShell = ::LoadLibrary(pszModule);
290                                bFree = true;
291                        }
292 
293                        if (hShell != NULL)
294                        {
295                                bool bSuccess = true;
296                                for(int i = m_iSortUp; i <= m_iSortDown; i++)
297                                {
298                                        if(!m_bmSort[i].IsNull())
299                                                m_bmSort[i].DeleteObject();
300                                        m_bmSort[i] = (HBITMAP)::LoadImage(hShell, MAKEINTRESOURCE(m_nShellSortUpID + i),
301#ifndef _WIN32_WCE
302                                                IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
303#else // CE specific
304                                                IMAGE_BITMAP, 0, 0, 0);
305#endif // _WIN32_WCE
306                                        if(m_bmSort[i].IsNull())
307                                        {
308                                                bSuccess = false;
309                                                break;
310                                        }
311                                }
312                                if(bFree)
313                                        ::FreeLibrary(hShell);
314                                if(bSuccess)
315                                        return;
316                        }
317                }
318
319                T* pT = static_cast<T*>(this);
320                for(int i = m_iSortUp; i <= m_iSortDown; i++)
321                {
322                        if(!m_bmSort[i].IsNull())
323                                m_bmSort[i].DeleteObject();
324
325                        WTL::CDC dcMem;
326                        WTL::CClientDC dc(::GetDesktopWindow());
327                        dcMem.CreateCompatibleDC(dc.m_hDC);
328                        m_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortImage, m_cySortImage);
329                        HBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]);
330                        RECT rc = {0,0,m_cxSortImage, m_cySortImage};
331                        pT->DrawSortBitmap(dcMem.m_hDC, i, &rc);
332                        dcMem.SelectBitmap(hbmOld);
333                        dcMem.DeleteDC();
334                }
335        }
336
337        void DrawSortBitmap(WTL::CDCHandle dc, int iBitmap, LPRECT prc)
338        {
339                dc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE));   
340                HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));
341                WTL::CPen pen;
342                pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW));
343                HPEN hpenOld = dc.SelectPen(pen);
344                POINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortImage - m_cySortArrow) / 2 };
345                if(iBitmap == m_iSortUp)
346                {
347                        POINT pts[3] =
348                        {
349                                { ptOrg.x + m_cxSortArrow / 2, ptOrg.y },
350                                { ptOrg.x, ptOrg.y + m_cySortArrow - 1 },
351                                { ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySortArrow - 1 }
352                        };
353                        dc.Polygon(pts, 3);
354                }
355                else
356                {
357                        POINT pts[3] =
358                        {
359                                { ptOrg.x, ptOrg.y },
360                                { ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySortArrow - 1 },
361                                { ptOrg.x + m_cxSortArrow - 1, ptOrg.y }
362                        };
363                        dc.Polygon(pts, 3);
364                }
365                dc.SelectBrush(hbrOld);
366                dc.SelectPen(hpenOld);
367        }
368
369        int GetSortColumn() const
370        {
371                return m_iSortColumn;
372        }
373
374        void SetColumnSortType(int iCol, WORD wType)
375        {
376                ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());
377                ATLASSERT(wType >= LVCOLSORT_NONE && wType <= LVCOLSORT_LAST);
378                m_arrColSortType[iCol] = wType;
379        }
380
381        WORD GetColumnSortType(int iCol) const
382        {
383                ATLASSERT((iCol >= 0) && iCol < m_arrColSortType.GetSize());
384                return m_arrColSortType[iCol];
385        }
386
387        bool IsSortDescending() const
388        {
389                return m_bSortDescending;
390        }
391
392private:
393        bool m_bSortDescending;
394        bool m_bCommCtrl6;
395        int m_iSortColumn;
396        WTL::CBitmap m_bmSort[2];
397        int m_fmtOldSortCol;
398        HBITMAP m_hbmOldSortCol;
399        DWORD m_dwSortLVExtendedStyle;
400        ATL::CSimpleArray<WORD> m_arrColSortType;
401        bool m_bUseWaitCursor;
402        */
403};
404
405}
406
407#endif // LISTVIEW_SORT_MIXIN_HPP_INCLUDED
Note: See TracBrowser for help on using the repository browser.