source: src/HaliteSortListViewCtrl.hpp @ 244

Revision 244, 12.2 KB checked in by Eoin, 13 years ago (diff)
RevLine 
[239]1
2#pragma once
3
4#include <boost/array.hpp>
5#include <boost/signals.hpp>
6#include <boost/algorithm/string/split.hpp>
7#include <boost/serialization/vector.hpp>
8#include <boost/serialization/split_free.hpp>
[243]9#include <boost/ptr_container/ptr_vector.hpp>
[239]10
11#include "stdAfx.hpp"
12#include "halTorrent.hpp"
13
14template<class T>
15class UpdateLock
16{
17public:
18        UpdateLock(T& window) :
19                window_(window)
20        {
21                ++window_.updateLock_;
22                window_.SetRedraw(false);
23        }
24       
25        ~UpdateLock()
26        {
27                if (!--window_.updateLock_)
28                        unlock();
29        }
30       
31        void unlock()
32        {
33                window_.SetRedraw(true);
34                window_.InvalidateRect(NULL, true);
35        }
36       
37private:
38        T& window_;
39};
40
[243]41template <class TBase, typename adapterType, size_t N=-1>
42class CHaliteListViewCtrl2 : 
43        public CSortListViewCtrlImpl<CHaliteListViewCtrl2<TBase, adapterType, N> >
[239]44{
45public:
[243]46        typedef CHaliteListViewCtrl2<TBase, adapterType, N> thisClass;
47        typedef CSortListViewCtrlImpl<thisClass> parentClass;
[239]48       
49        class selection_manager : 
50                private boost::noncopyable
51        {       
52        public:
[243]53                selection_manager(thisClass& m_list) :
[239]54                        m_list_(m_list)
55                {}
56               
[243]57                typedef std::wstring string_t; 
58                typedef const string_t& param_type;
[239]59               
60                void sync_list(bool list_to_manager, bool signal_change=true)
61                {
62                        if (list_to_manager)
63                        {       
[240]64                                if (listToManager() && signal_change) signal();
65                        }
66                        else
67                        {
68                                if (managerToList() && signal_change) signal();
69                        }
70                }
71               
72                bool listToManager()
73                {
74                        boost::array<wchar_t, MAX_PATH> pathBuffer;
[243]75                        std::set<string_t> all_selected;
76                        string_t selected = L"";
[240]77                       
78                        bool do_signal = false;
79                       
80                        int total = m_list_.GetItemCount();
81                       
82                        for (int i=0; i<total; ++i)
83                        {
84                                UINT flags = m_list_.GetItemState(i, LVIS_SELECTED);
[239]85                               
[240]86                                if (flags && LVIS_SELECTED)
[239]87                                {
[240]88                                        m_list_.GetItemText(i, 0, pathBuffer.c_array(), pathBuffer.size());     
[243]89                                        all_selected.insert(pathBuffer.data());
[240]90                                }
91                                if (flags && LVIS_FOCUSED)
92                                {
[243]93                                        selected = pathBuffer.data();
[240]94                                }
95                        }
96
97                        if (all_selected != all_selected_)
98                        {
99                                std::swap(all_selected_, all_selected);
100                                do_signal = true;
101                        }
[239]102                                       
[240]103                        if (selected_ != selected)
104                        {
105                                std::swap(selected_, selected);
106                                do_signal = true;
107                        }
108                       
109                        return do_signal;
110                }
111               
112                bool managerToList()
113                {
114                        // Prevent changing states from signaling another sync
[243]115                        UpdateLock<thisClass> lock(m_list_);
[240]116                       
117                        boost::array<wchar_t, MAX_PATH> pathBuffer;
118                        LV_FINDINFO findInfo = { sizeof(LV_FINDINFO) }; 
119                        findInfo.flags = LVFI_STRING;
120                       
121                        bool do_signal = true; // Always signal for now!
122                       
123                        int total = m_list_.GetItemCount();
124                       
125                        for (int i=0; i<total; ++i)
126                        {
127                                m_list_.GetItemText(i, 0, pathBuffer.c_array(), pathBuffer.size());
[243]128                                string_t temp_name = pathBuffer.data();
[239]129                               
[240]130                                LVITEM lvi = { LVIF_STATE };
131                                lvi.state = 0;
132                                lvi.stateMask = LVIS_SELECTED|LVIS_FOCUSED;
[239]133                               
[240]134                                if (temp_name == selected_)
[239]135                                {
[240]136                                        lvi.state |= LVIS_FOCUSED;
[239]137                                }
[240]138                                if (all_selected_.find(temp_name) != all_selected_.end())
[239]139                                {
[240]140                                        lvi.state |= LVIS_SELECTED;
[239]141                                }
142                               
[240]143                                m_list_.SetItemState(i, &lvi);
144                        }                       
[239]145                       
[240]146                        return do_signal;
[239]147                }
148               
[243]149                int selectMatch(const string_t& name)
[239]150                {
151                        LV_FINDINFO findInfo = { sizeof(LV_FINDINFO) }; 
152                        findInfo.flags = LVFI_STRING;
[243]153                                       
154                        findInfo.psz = name.c_str();
[239]155                       
156                        int itemPos = m_list_.FindItem(&findInfo, -1); 
[243]157                                               
[239]158                        if (itemPos == -1)
159                                return itemPos;
160                               
161                        UINT flags = m_list_.GetItemState(itemPos, LVIS_SELECTED);
162                       
163                        //if (!flags && LVIS_SELECTED)
164                        {
165                                LVITEM lvi = { LVIF_STATE };
166                                lvi.state = LVIS_SELECTED;
167                                lvi.stateMask = LVIS_SELECTED;
168                                m_list_.SetItemState(itemPos, &lvi);
169                        }
170               
171                        return itemPos;
172                }
173               
174                param_type selected() const { return selected_; }
175               
176                int selectedIndex()
177                {
178                        LV_FINDINFO findInfo = { sizeof(LV_FINDINFO) };         
[243]179                        findInfo.psz = selected_.c_str();
[239]180                       
181                        return m_list_.FindItem(&findInfo, -1);         
182                }
183               
[243]184                const std::set<string_t>& allSelected() const { return all_selected_; }
[239]185               
[243]186                void setSelected(const string_t& sel) 
[239]187                {
188                        selected_ = sel;
189                }
190               
191                void setSelected(int itemPos)
[240]192                {               
193                        hal::event().post(shared_ptr<hal::EventDetail>(new hal::EventDebug(hal::Event::info, (wformat(L"Set Selected %1%") % itemPos).str().c_str())));
194
[239]195                        LVITEM lvi = { LVIF_STATE };
[241]196                        lvi.state = LVIS_SELECTED|LVIS_FOCUSED;
197                        lvi.stateMask = LVIS_SELECTED|LVIS_FOCUSED;
[239]198                        m_list_.SetItemState(itemPos, &lvi);
[241]199                       
[239]200                        m_list_.SetSelectionMark(itemPos);
[241]201                       
[239]202                        sync_list(true);
203                }
204               
205                void clear()
206                {
[241]207                        // Prevent changing states from signaling another sync
[243]208                        UpdateLock<thisClass> lock(m_list_);
[241]209                       
[243]210//                      hal::event().post(shared_ptr<hal::EventDetail>(new hal::EventDebug(hal::Event::info, (wformat(L"Clear")).str().c_str())));
[241]211       
212                        m_list_.DeleteItem(selectedIndex());
[239]213                       
214                        sync_list(true);       
215                }
216               
[241]217                void clear_all_selected()
[239]218                {
[241]219                        // Prevent changing states from signaling another sync
[243]220                        UpdateLock<thisClass> lock(m_list_);
[241]221                       
[243]222//                      hal::event().post(shared_ptr<hal::EventDetail>(new hal::EventDebug(hal::Event::info, (wformat(L"ClearAllSelected")).str().c_str())));
[240]223
[239]224                        int total = m_list_.GetItemCount();
225                       
226                        for (int i=total-1; i>=0; --i)
227                        {
228                                UINT flags = m_list_.GetItemState(i, LVIS_SELECTED);
229                               
230                                if (flags && LVIS_SELECTED)
231                                        m_list_.DeleteItem(i);
232                        }
233                        all_selected_.clear();
234                       
235                        sync_list(true);       
236                }
237               
[241]238                void clear_all()
[239]239                {
[241]240                        // Prevent changing states from signaling another sync
[243]241                        UpdateLock<thisClass> lock(m_list_);
[241]242                       
[243]243//                      hal::event().post(shared_ptr<hal::EventDetail>(new hal::EventDebug(hal::Event::info, (wformat(L"ClearAll")).str().c_str())));
[241]244
[239]245                        m_list_.DeleteAllItems();
246                        all_selected_.clear();
[241]247                       
[239]248                        sync_list(true);               
249                }
250               
[240]251                void attach(boost::function<void (param_type)> fn) const { selection_.connect(fn); }
[239]252               
253                void signal() 
254                { 
255                        selection_(selected_); 
256                }
257               
258        private:
[243]259                string_t selected_;
260                std::set<string_t> all_selected_;
[239]261               
[240]262                mutable boost::signal<void (param_type)> selection_;
[243]263                thisClass& m_list_;
[239]264        };
265       
266        class CHaliteHeaderCtrl : public CWindowImpl<CHaliteHeaderCtrl, CHeaderCtrl>
267        {
268        public:
269                BEGIN_MSG_MAP(CHaliteHeaderCtrl)
270                        REFLECTED_NOTIFY_CODE_HANDLER(NM_RCLICK, OnRClick)
271                END_MSG_MAP()
272               
273                void Attach(HWND hWndNew)
274                {
275                        ATLASSERT(::IsWindow(hWndNew));
276                        CWindowImpl<CHaliteHeaderCtrl, CHeaderCtrl>::SubclassWindow(hWndNew);
277
278                        menu_.CreatePopupMenu();
279                       
280                        MENUITEMINFO minfo = {sizeof(MENUITEMINFO)};
281                        minfo.fMask = MIIM_STRING|MIIM_ID|MIIM_FTYPE|MIIM_STATE;
282                        minfo.fType = MFT_STRING;
283                        minfo.fState = MFS_CHECKED;
284                        minfo.dwTypeData = L"Hello";
285                       
286                        menu_.InsertMenuItem(0, false, &minfo);
287//                      TBase* pT = static_cast<TBase*>(this);
288//                      pT->OnAttach();
289                }
290               
291                LRESULT OnRClick(int i, LPNMHDR pnmh, BOOL&)
292                {
293                        POINT ptPoint;
294                        GetCursorPos(&ptPoint);
295                        menu_.TrackPopupMenu(0, ptPoint.x, ptPoint.y, m_hWnd);
296
297                        return 0;
298                }
299               
300        private:
301                WTL::CMenu menu_;
302        };
303       
[243]304        class Adapter
[239]305        {
[243]306        public:
307                virtual bool less(adapterType& l, adapterType& r) = 0;
308                virtual std::wstring print(adapterType& t) = 0;
[239]309        };
[243]310
311public:
312        typedef selection_manager SelectionManager;
313        typedef SelectionManager selection_manager_class;
[239]314       
[243]315        thisClass() :
[239]316                manager_(*this),
317                updateLock_(0)
318        {
319                if (TBase::LISTVIEW_ID_MENU)
320                {
321                        BOOL menu_created = menu_.LoadMenu(TBase::LISTVIEW_ID_MENU);
322                        assert(menu_created);   
323                }
324
325                wstring column_names = hal::app().res_wstr(TBase::LISTVIEW_ID_COLUMNNAMES);
326                boost::split(names_, column_names, boost::is_any_of(L";"));
327               
328                wstring column_widths = hal::app().res_wstr(TBase::LISTVIEW_ID_COLUMNWIDTHS);
329                std::vector<wstring> widths;
330                boost::split(widths, column_widths, boost::is_any_of(L";"));
331                               
332                listColumnWidth_.reserve(names_.size());       
333                listColumnOrder_.reserve(names_.size());
334               
335                for (size_t i=0; i<names_.size(); ++i)
336                {
337                        listColumnWidth_.push_back(lexical_cast<int>(widths[i]));
338                        listColumnOrder_.push_back(i);
339                }       
340        }
341
[243]342        BEGIN_MSG_MAP_EX(thisClass)
[239]343                REFLECTED_NOTIFY_CODE_HANDLER(NM_CLICK, OnClick)
[240]344                REFLECTED_NOTIFY_CODE_HANDLER(NM_RCLICK, OnRClick)
[239]345                REFLECTED_NOTIFY_CODE_HANDLER(LVN_ITEMCHANGED, OnItemChanged)
[243]346        //      REFLECTED_NOTIFY_CODE_HANDLER(LVN_COLUMNCLICK , OnColClick)
[239]347
348                DEFAULT_REFLECTION_HANDLER()
[243]349                CHAIN_MSG_MAP(parentClass)
[239]350        END_MSG_MAP()
351
352        void Attach(HWND hWndNew)
353        {
354                ATLASSERT(::IsWindow(hWndNew));
[243]355        parentClass::SubclassWindow(hWndNew);
[239]356
357                TBase* pT = static_cast<TBase*>(this);
358                pT->OnAttach();
359        }
360       
361        void SetListViewDetails()
362        {
363                vectorSizePreConditions();
364               
365                header_.Attach(this->GetHeader());
366                header_.ModifyStyle(0, HDS_DRAGDROP|HDS_FULLDRAG);
367                       
368                foreach (wstring name, names_)
369                {
[243]370                        int i = header_.GetItemCount();
371                       
372                        AddColumn(name.c_str(), i);
373                        SetColumnSortType(i, LVCOLSORT_CUSTOM);
[239]374                }               
375
376                for (unsigned i=0; i<names_.size(); ++i)
377                        SetColumnWidth(i, listColumnWidth_[i]);
378               
379                SetColumnOrderArray(names_.size(), &listColumnOrder_[0]);       
380        }
381       
382        template<std::size_t Size>
383        void SetDefaults(array<int, Size> a)
384        {
385                assert (Size == names_.size());
386                vectorSizePreConditions();
387               
388                for (size_t i=0; i<names_.size(); ++i)
389                {
390                        listColumnWidth_[i] = a[i];
391                        listColumnOrder_[i] = i;
392                }               
393        }
394       
395        // Should probably make this redundant!!
396        void GetListViewDetails()
397        {
398                vectorSizePreConditions();
399               
400                GetColumnOrderArray(names_.size(), &listColumnOrder_[0]);
401               
402                for (size_t i=0; i<names_.size(); ++i)
403                        listColumnWidth_[i] = GetColumnWidth(i);       
404        }
405
406        LRESULT OnClick(int, LPNMHDR pnmh, BOOL&)
407        {
408        //      manager().sync_list(true);
409
410                return 0;
411        }
412
413        LRESULT OnItemChanged(int, LPNMHDR pnmh, BOOL&)
414        {               
415                if (canUpdate()) 
[240]416                {
417                        manager_.sync_list(true, true);
[239]418                }
419               
420                return 0;
421        }
422
423        LRESULT OnRClick(int i, LPNMHDR pnmh, BOOL&)
424        {
[240]425                hal::event().post(shared_ptr<hal::EventDetail>(new hal::EventDebug(hal::Event::info, (wformat(L"RClick %1%") % pnmh->code).str().c_str())));
[239]426                LPNMITEMACTIVATE pia = (LPNMITEMACTIVATE)pnmh;
[240]427                manager_.sync_list(true);
[239]428               
429                if (TBase::LISTVIEW_ID_MENU)
430                {
431                        assert (menu_.IsMenu());
432                        CMenuHandle sMenu = menu_.GetSubMenu(0);
433                        assert (sMenu.IsMenu());
434       
435                        POINT ptPoint;
436                        GetCursorPos(&ptPoint);
437                        sMenu.TrackPopupMenu(0, ptPoint.x, ptPoint.y, m_hWnd);
438                }
439
440                return 0;
441        }
442
443        LRESULT OnColClick(int i, LPNMHDR pnmh, BOOL&)
444        {
445                LPNMLISTVIEW pnlv = (LPNMLISTVIEW)pnmh;
446               
447                MessageBox((lexical_cast<wstring>(pnlv->iSubItem)).c_str(), L"Hi", 0);
448                return 0;
449        }
[243]450               
451        int CompareItemsCustom(LVCompareParam* pItem1, LVCompareParam* pItem2, int iSortCol)
452        {
453                TBase* pT = static_cast<TBase*>(this);
454                return pT->CompareItemsCustom(pItem1, pItem2, iSortCol);
455        }
[239]456       
457        friend class boost::serialization::access;
458    template<class Archive>
459    void serialize(Archive & ar, const unsigned int version)
460    {
461        ar & boost::serialization::make_nvp("width", listColumnWidth_);
462        ar & boost::serialization::make_nvp("order", listColumnOrder_);
463    }
464
[243]465        const SelectionManager& manager() { return manager_; }
466               
[239]467        std::vector<int>& listColumnWidth() { return listColumnWidth_; }
468        std::vector<int>& listColumnOrder() { return listColumnOrder_; }
469       
470        const std::vector<int>& listColumnWidth() const { return listColumnWidth_; }
471        const std::vector<int>& listColumnOrder() const { return listColumnOrder_; }
472       
[240]473        bool canUpdate() const { return updateLock_ == 0; }
[241]474       
475        void clearFocused() { manager_.clear(); }
476        void clearSelected() { manager_.clear_all_selected(); }
477        void clearAll() { manager_.clear(); }
[240]478
479protected:
[243]480        SelectionManager manager_;
481        boost::ptr_vector<Adapter> adapters_;
[239]482       
483private:
484        void vectorSizePreConditions()
485        {
486                if (listColumnWidth_.size() != names_.size())
487                {
488                        listColumnWidth_.clear();
489                        listColumnWidth_.insert(listColumnWidth_.end(), names_.size(), 50);     
490                }
491               
492                if (listColumnOrder_.size() != names_.size())
493                {               
494                        listColumnOrder_.clear();
495                        listColumnOrder_.insert(listColumnOrder_.end(), names_.size(), 0);
496                }               
497        }
[243]498               
[239]499        WTL::CMenu menu_;
500        CHaliteHeaderCtrl header_;
501        std::vector<wstring> names_;
502        std::vector<int> listColumnWidth_;
503        std::vector<int> listColumnOrder_;
504       
505        int updateLock_;
506        friend class UpdateLock<thisClass>;
507};
Note: See TracBrowser for help on using the repository browser.