source: trunk/src/HaliteListViewCtrl.hpp @ 657

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

Classic sorting and external sorting not playing nice together.

Line 
1
2//         Copyright Eóin O'Callaghan 2006 - 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#pragma once
8
9#include <boost/array.hpp>
10#include <boost/signals.hpp>
11#include <boost/algorithm/string/split.hpp>
12
13#include "stdAfx.hpp"
14#include "halTorrent.hpp"
15
16template <class TBase>
17class CHaliteListViewCtrl : public ATL::CWindowImpl<TBase, WTL::CListViewCtrl>
18{
19public:
20        typedef CHaliteListViewCtrl<TBase> thisClass;
21       
22protected:
23        template <typename L, typename S=std::string>
24        class selection_manager : 
25                private boost::noncopyable
26        {       
27        public:
28                selection_manager(L& m_list) :
29                        m_list_(m_list)
30                {}
31               
32                typedef const S& param_type;
33               
34                void sync_list(bool list_to_manager, bool signal_change=true)
35                {
36//                      hal::event_log.post(shared_ptr<hal::EventDetail>(new hal::EventDebug(hal::event_logger::info, (hal::wform(L"%1%, %2% %3%") % hal::from_utf8(selected_) % list_to_manager % signal_change).str().c_str())));
37                        if (list_to_manager)
38                        {       
39                                all_selected_.clear();
40                                int itemPos = m_list_.GetSelectionMark();       
41                       
42                                if (itemPos != -1)
43                                {
44                                        boost::array<wchar_t, MAX_PATH> pathBuffer;
45                                        m_list_.GetItemText(itemPos, 0, pathBuffer.c_array(), pathBuffer.size());       
46                                       
47                                        // Multi-Selected
48                                        int total = m_list_.GetItemCount();
49                                       
50                                        for (int i=0; i<total; ++i)
51                                        {
52                                                UINT flags = m_list_.GetItemState(i, LVIS_SELECTED);
53                                               
54                                                if (flags && LVIS_SELECTED)
55                                                {
56                                                        m_list_.GetItemText(i, 0, pathBuffer.c_array(), pathBuffer.size());     
57                                                        all_selected_.push_back(hal::to_utf8(pathBuffer.data()));
58                                                }
59                                        }
60                                       
61                                        // Single-Selected
62                                        string selected = hal::to_utf8(pathBuffer.data());
63                                       
64                                        if (selected_ != selected)
65                                        {
66                                                selected_ = selected;
67                                                if (signal_change) signal();
68                                        }
69                                }
70                                else
71                                {
72                                        selected_ = "";
73                                        if (signal_change) signal();
74                                }
75                        }
76                        else
77                        {
78                        /*      foreach (string name, all_selected_)
79                                {
80                                        selectMatch(name);
81                                }
82                        */
83                                int itemPos = selectMatch(selected_);                           
84                        //      if (itemPos != -1) m_list_.SetSelectionMark(itemPos);
85                               
86                                if (signal_change) signal();
87                        }
88                }
89               
90                int selectMatch(const string& name)
91                {
92                        LV_FINDINFO findInfo = { sizeof(LV_FINDINFO) }; 
93                        findInfo.flags = LVFI_STRING;
94                       
95                        wstring torrent_name = hal::from_utf8(name);           
96                        findInfo.psz = torrent_name.c_str();
97                       
98                        int itemPos = m_list_.FindItem(&findInfo, -1); 
99                       
100//                      hal::event_log.post(shared_ptr<hal::EventDetail>(new hal::EventDebug(hal::event_logger::info, (hal::wform(L"%1%, %2%") % torrent_name % itemPos).str().c_str())));
101                       
102                        if (itemPos == -1)
103                                return itemPos;
104                               
105                        UINT flags = m_list_.GetItemState(itemPos, LVIS_SELECTED);
106                       
107                        //if (!flags && LVIS_SELECTED)
108                        {
109                                LVITEM lvi = { LVIF_STATE };
110                                lvi.state = LVIS_SELECTED;
111                                lvi.stateMask = LVIS_SELECTED;
112                                m_list_.SetItemState(itemPos, &lvi);
113                        }
114               
115                        return itemPos;
116                }
117               
118                param_type selected() const { return selected_; }
119               
120                int selectedIndex()
121                {
122                        wstring torrent_name = hal::from_utf8(selected_);       
123                        LV_FINDINFO findInfo = { sizeof(LV_FINDINFO) };         
124                        findInfo.psz = torrent_name.c_str();
125                       
126                        return m_list_.FindItem(&findInfo, -1);         
127                }
128               
129                const std::vector<string>& allSelected() const { return all_selected_; }
130               
131                void setSelected(const string& sel) 
132                {
133                        selected_ = sel;
134                        sync_list(false);
135                }
136               
137                void setSelected(int itemPos)
138                {
139                        LVITEM lvi = { LVIF_STATE };
140                        lvi.state = LVIS_SELECTED;
141                        lvi.stateMask = LVIS_SELECTED;
142                        m_list_.SetItemState(itemPos, &lvi);
143                        m_list_.SetSelectionMark(itemPos);
144                        sync_list(true);
145                }
146               
147                void clear()
148                {
149                        m_list_.DeleteItem(m_list_.GetSelectionMark());
150                       
151                //      m_list_.SelectItem(0);
152                        sync_list(true);       
153                }
154               
155                void clearAllSelected()
156                {
157                        int total = m_list_.GetItemCount();
158                       
159                        for (int i=total-1; i>=0; --i)
160                        {
161                                UINT flags = m_list_.GetItemState(i, LVIS_SELECTED);
162                               
163                                if (flags && LVIS_SELECTED)
164                                        m_list_.DeleteItem(i);
165                        }
166                        all_selected_.clear();
167                       
168                //      m_list_.SelectItem(0);
169                        sync_list(true);       
170                }
171               
172                void clearAll()
173                {
174                        m_list_.DeleteAllItems();
175                        all_selected_.clear();
176                        sync_list(true);               
177                }
178               
179                void attach(boost::function<void (param_type)> fn) { selection_.connect(fn); }
180               
181                void signal() 
182                { 
183                        selection_(selected_); 
184                }
185               
186        private:
187                S selected_;
188                std::vector<S> all_selected_;
189               
190                boost::signal<void (param_type)> selection_;
191                L& m_list_;
192        };
193       
194        class CHaliteHeaderCtrl : public ATL::CWindowImpl<CHaliteHeaderCtrl, WTL::CHeaderCtrl>
195        {
196        public:
197                BEGIN_MSG_MAP(CHaliteHeaderCtrl)
198                        REFLECTED_NOTIFY_CODE_HANDLER(NM_RCLICK, OnRClick)
199                END_MSG_MAP()
200               
201                void Attach(HWND hWndNew)
202                {
203                        ATLASSERT(::IsWindow(hWndNew));
204                        CWindowImpl<CHaliteHeaderCtrl, CHeaderCtrl>::SubclassWindow(hWndNew);
205
206                        menu_.CreatePopupMenu();
207                       
208                        MENUITEMINFO minfo = {sizeof(MENUITEMINFO)};
209                        minfo.fMask = MIIM_STRING|MIIM_ID|MIIM_FTYPE|MIIM_STATE;
210                        minfo.fType = MFT_STRING;
211                        minfo.fState = MFS_CHECKED;
212                        minfo.dwTypeData = L"Hello";
213                       
214                        menu_.InsertMenuItem(0, false, &minfo);
215//                      TBase* pT = static_cast<TBase*>(this);
216//                      pT->OnAttach();
217                }
218               
219                LRESULT OnRClick(int i, LPNMHDR pnmh, BOOL&)
220                {
221                        POINT ptPoint;
222                        GetCursorPos(&ptPoint);
223                        menu_.TrackPopupMenu(0, ptPoint.x, ptPoint.y, m_hWnd);
224
225                        return 0;
226                }
227               
228        private:
229                WTL::CMenu menu_;
230        };
231       
232        template<typename T>
233        class column_type
234        {
235        public:
236                virtual ~column_type() = 0             
237                virtual bool less(cont T&, const T&) = 0
238                virtual std::string str() = 0;
239        };
240       
241        // EG T is a torrent_details, so have array column_types
242
243public:
244        typedef selection_manager<thisClass> selection_manage_class;
245       
246        enum sortDirection
247        {
248                none,
249                ascending,
250                descending
251        };
252       
253        CHaliteListViewCtrl<TBase>() :
254                sortingDirection_(CHaliteListViewCtrl<TBase>::none),
255                sortedColmun_(0),
256                manager_(*this)
257        {
258                if (TBase::LISTVIEW_ID_MENU)
259                {
260                        BOOL menu_created = menu_.LoadMenu(TBase::LISTVIEW_ID_MENU);
261                        assert(menu_created);   
262                }
263
264                wstring column_names = hal::app().res_wstr(TBase::LISTVIEW_ID_COLUMNNAMES);
265                boost::split(names_, column_names, boost::is_any_of(L";"));
266               
267                wstring column_widths = hal::app().res_wstr(TBase::LISTVIEW_ID_COLUMNWIDTHS);
268                std::vector<wstring> widths;
269                boost::split(widths, column_widths, boost::is_any_of(L";"));
270                               
271                listColumnWidth_.reserve(names_.size());       
272                listColumnOrder_.reserve(names_.size());
273               
274                for (size_t i=0; i<names_.size(); ++i)
275                {
276                        listColumnWidth_.push_back(lexical_cast<int>(widths[i]));
277                        listColumnOrder_.push_back(i);
278                }       
279        }
280
281        BEGIN_MSG_MAP_EX(CHaliteListViewCtrl<TBase>)
282                REFLECTED_NOTIFY_CODE_HANDLER(NM_CLICK, OnClick)
283                REFLECTED_NOTIFY_CODE_HANDLER(LVN_ITEMCHANGED, OnItemChanged)
284                REFLECTED_NOTIFY_CODE_HANDLER(NM_RCLICK, OnRClick)
285                REFLECTED_NOTIFY_CODE_HANDLER(LVN_COLUMNCLICK , OnColClick)
286
287                DEFAULT_REFLECTION_HANDLER()
288        END_MSG_MAP()
289
290        void Attach(HWND hWndNew)
291        {
292                ATLASSERT(::IsWindow(hWndNew));
293        CWindowImpl<TBase, CListViewCtrl>::SubclassWindow(hWndNew);
294
295                TBase* pT = static_cast<TBase*>(this);
296                pT->OnAttach();
297        }
298       
299        void SetListViewDetails()
300        {
301                vectorSizePreConditions();
302               
303                header_.Attach(this->GetHeader());
304                header_.ModifyStyle(0, HDS_DRAGDROP|HDS_FULLDRAG);
305                       
306                foreach (wstring name, names_)
307                {
308                        AddColumn(name.c_str(), header_.GetItemCount());
309                }               
310
311                for (unsigned i=0; i<names_.size(); ++i)
312                        SetColumnWidth(i, listColumnWidth_[i]);
313               
314                SetColumnOrderArray(names_.size(), &listColumnOrder_[0]);       
315        }
316       
317        template<std::size_t Size>
318        void SetDefaults(array<int, Size> a)
319        {
320                assert (Size == names_.size());
321                vectorSizePreConditions();
322               
323                for (size_t i=0; i<names_.size(); ++i)
324                {
325                        listColumnWidth_[i] = a[i];
326                        listColumnOrder_[i] = i;
327                }               
328        }
329       
330        // Should probably make this redundant!!
331        void GetListViewDetails()
332        {
333                vectorSizePreConditions();
334               
335                GetColumnOrderArray(names_.size(), &listColumnOrder_[0]);
336               
337                for (size_t i=0; i<names_.size(); ++i)
338                        listColumnWidth_[i] = GetColumnWidth(i);       
339        }
340
341        LRESULT OnClick(int, LPNMHDR pnmh, BOOL&)
342        {
343        //      manager().sync_list(true);
344
345                return 0;
346        }
347
348        LRESULT OnItemChanged(int, LPNMHDR pnmh, BOOL&)
349        {
350                manager().sync_list(true);
351
352                return 0;
353        }
354
355        LRESULT OnRClick(int i, LPNMHDR pnmh, BOOL&)
356        {
357                LPNMITEMACTIVATE pia = (LPNMITEMACTIVATE)pnmh;
358                manager().sync_list(true);
359               
360                if (TBase::LISTVIEW_ID_MENU)
361                {
362                        assert (menu_.IsMenu());
363                        CMenuHandle sMenu = menu_.GetSubMenu(0);
364                        assert (sMenu.IsMenu());
365       
366                        POINT ptPoint;
367                        GetCursorPos(&ptPoint);
368                        sMenu.TrackPopupMenu(0, ptPoint.x, ptPoint.y, m_hWnd);
369                }
370
371                return 0;
372        }
373
374        LRESULT OnColClick(int i, LPNMHDR pnmh, BOOL&)
375        {
376                LPNMLISTVIEW pnlv = (LPNMLISTVIEW)pnmh;
377               
378                MessageBox((lexical_cast<wstring>(pnlv->iSubItem)).c_str(), L"Hi", 0);
379                return 0;
380        }
381       
382        friend class boost::serialization::access;
383    template<class Archive>
384    void serialize(Archive & ar, const unsigned int version)
385    {
386        ar & boost::serialization::make_nvp("width", listColumnWidth_);
387        ar & boost::serialization::make_nvp("order", listColumnOrder_);
388    }
389
390        selection_manager<CHaliteListViewCtrl>& manager() { return manager_; }
391       
392        size_t sortedColmun() { return sortedColmun_; }
393        sortDirection sortingDirection() { return sortingDirection_; }
394       
395        std::vector<int>& ListColumnWidth() { return listColumnWidth_; }
396        std::vector<int>& ListColumnOrder() { return listColumnOrder_; }
397       
398        const std::vector<int>& ListColumnWidth() const { return listColumnWidth_; }
399        const std::vector<int>& ListColumnOrder() const { return listColumnOrder_; }
400       
401private:
402        selection_manager<CHaliteListViewCtrl> manager_;
403       
404        void vectorSizePreConditions()
405        {
406                if (listColumnWidth_.size() != names_.size())
407                {
408                        listColumnWidth_.clear();
409                        listColumnWidth_.insert(listColumnWidth_.end(), names_.size(), 50);     
410                }
411               
412                if (listColumnOrder_.size() != names_.size())
413                {               
414                        listColumnOrder_.clear();
415                        listColumnOrder_.insert(listColumnOrder_.end(), names_.size(), 0);
416                }               
417        }
418       
419        sortDirection sortingDirection_;
420        size_t sortedColmun_;
421       
422        WTL::CMenu menu_;
423        CHaliteHeaderCtrl header_;
424        std::vector<wstring> names_;
425        std::vector<int> listColumnWidth_;
426        std::vector<int> listColumnOrder_;
427};
Note: See TracBrowser for help on using the repository browser.