source: filezilla/trunk/fuentes/src/interface/filelistctrl.h @ 3185

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 2 years ago

Update new version: 3.15.02

File size: 16.6 KB
Line 
1#ifndef __FILELISTCTRL_H__
2#define __FILELISTCTRL_H__
3
4#include "listctrlex.h"
5#include "systemimagelist.h"
6#include "listingcomparison.h"
7
8#include <cstring>
9#include <memory>
10
11class CQueueView;
12class CFileListCtrl_SortComparisonObject;
13class CState;
14class CFilelistStatusBar;
15#if defined(__WXGTK__) && !defined(__WXGTK3__)
16class CGtkEventCallbackProxyBase;
17#endif
18
19class CGenericFileData
20{
21public:
22        wxString fileType;
23        int icon{-2};
24
25        // t_fileEntryFlags is defined in listingcomparison.h as it will be used for
26        // both local and remote listings
27        CComparableListing::t_fileEntryFlags comparison_flags{CComparableListing::normal};
28};
29
30class CFileListCtrlSortBase
31{
32public:
33        enum DirSortMode
34        {
35                dirsort_ontop,
36                dirsort_onbottom,
37                dirsort_inline
38        };
39        enum NameSortMode
40        {
41                namesort_caseinsensitive,
42                namesort_casesensitive,
43                namesort_natural
44        };
45
46        virtual bool operator()(int a, int b) const = 0;
47        virtual ~CFileListCtrlSortBase() {} // Without this empty destructor GCC complains
48
49        #define CMP(f, data1, data2) \
50                {\
51                        int res = this->f(data1, data2);\
52                        if (res < 0)\
53                                return true;\
54                        else if (res > 0)\
55                                return false;\
56                }
57
58        #define CMP_LESS(f, data1, data2) \
59                {\
60                        int res = this->f(data1, data2);\
61                        if (res < 0)\
62                                return true;\
63                        else\
64                                return false;\
65                }
66
67        static int CmpCase(std::wstring const& str1, std::wstring const& str2)
68        {
69                return str1.compare(str2);
70        }
71
72        static int CmpCase(wxString const& str1, wxString const& str2)
73        {
74                return str1.Cmp(str2);
75        }
76
77        static int CmpNoCase(std::wstring const& str1, std::wstring const& str2)
78        {
79                int cmp = fz::stricmp(str1, str2);
80                if (cmp)
81                        return cmp;
82                return str1.compare(str2);
83        }
84
85        static int CmpNoCase(wxString const& str1, wxString const& str2)
86        {
87                int cmp = str1.CmpNoCase(str2);
88                if (cmp)
89                        return cmp;
90                return str1.Cmp(str2);
91        }
92
93        static int CmpNatural(wxString const& str1, wxString const& str2)
94        {
95                return CmpNatural(static_cast<wxChar const*>(str1.c_str()), static_cast<wxChar const*>(str2.c_str()));
96        }
97
98        static int CmpNatural(std::wstring const& str1, std::wstring const& str2)
99        {
100                return CmpNatural(str1.c_str(), str2.c_str());
101        }
102
103        static int CmpNatural(wxChar const* p1, wxChar const* p2)
104        {
105                int res = 0;
106                int zeroCount = 0;
107                bool isNumber = false;
108                for (; *p1 && *p2; ++p1, ++p2) {
109                        int diff = static_cast<int>(wxTolower(*p1)) - static_cast<int>(wxTolower(*p2));
110                        if (isNumber) {
111                                if (res == 0)
112                                        res = diff;
113                                int nbDigits = (wxIsdigit(*p1) ? 1 : 0) + (wxIsdigit(*p2) ? 1 : 0);
114                                if (nbDigits == 0 && res == 0) {
115                                        if (zeroCount)
116                                                break;
117                                        isNumber = false;
118                                } else if (nbDigits != 2)
119                                        break;
120                        } else if (wxIsdigit(*p1) && wxIsdigit(*p2)) {
121                                zeroCount = 0;
122                                for(; *p1 == '0' && *(p1+1) && wxIsdigit(*(p1+1)); ++p1)
123                                        zeroCount++;
124                                for(; *p2 == '0' && *(p2+1) && wxIsdigit(*(p2+1)); ++p2)
125                                        zeroCount--;
126                                res = *p1 - *p2;
127                                isNumber = true;
128                        } else if (diff)
129                                return diff;
130                }
131
132                if (res == 0 && isNumber)
133                        res = zeroCount;
134
135                if (!*p1 && !*p2)
136                        return res;
137                if (!isNumber || res == 0)
138                         return !*p1 ? -1 : 1;
139                if (*p1 && wxIsdigit(*p1))
140                        return 1;       //more digits
141                if (*p2 && wxIsdigit(*p2))
142                        return -1;      //fewer digits
143                return res;         //same length, compare first different digit in the sequence
144        }
145
146        typedef int (* CompareFunction)(const wxString&, const wxString&);
147        static CompareFunction GetCmpFunction(NameSortMode mode)
148        {
149                switch (mode)
150                {
151                default:
152                case CFileListCtrlSortBase::namesort_caseinsensitive:
153                        return &CFileListCtrlSortBase::CmpNoCase;
154                case CFileListCtrlSortBase::namesort_casesensitive:
155                        return &CFileListCtrlSortBase::CmpCase;
156                case CFileListCtrlSortBase::namesort_natural:
157                        return &CFileListCtrlSortBase::CmpNatural;
158                }
159        }
160};
161
162// Helper classes for fast sorting using std::sort
163// -----------------------------------------------
164
165template<typename value_type>
166inline int DoCmpName(value_type const& data1, value_type const& data2, CFileListCtrlSortBase::NameSortMode const nameSortMode)
167{
168        switch (nameSortMode)
169        {
170        case CFileListCtrlSortBase::namesort_casesensitive:
171                return CFileListCtrlSortBase::CmpCase(data1.name, data2.name);
172
173        default:
174        case CFileListCtrlSortBase::namesort_caseinsensitive:
175                return CFileListCtrlSortBase::CmpNoCase(data1.name, data2.name);
176
177        case CFileListCtrlSortBase::namesort_natural:
178                return CFileListCtrlSortBase::CmpNatural(data1.name, data2.name);
179        }
180}
181
182template<typename Listing>
183class CFileListCtrlSort : public CFileListCtrlSortBase
184{
185public:
186        typedef Listing List;
187        typedef typename Listing::value_type value_type;
188
189        CFileListCtrlSort(Listing const& listing, enum DirSortMode dirSortMode, enum NameSortMode nameSortMode)
190                : m_listing(listing), m_dirSortMode(dirSortMode), m_nameSortMode(nameSortMode)
191        {
192        }
193
194        inline int CmpDir(value_type const& data1, value_type const& data2) const
195        {
196                switch (m_dirSortMode)
197                {
198                default:
199                case dirsort_ontop:
200                        if (data1.is_dir()) {
201                                if (!data2.is_dir())
202                                        return -1;
203                                else
204                                        return 0;
205                        }
206                        else {
207                                if (data2.is_dir())
208                                        return 1;
209                                else
210                                        return 0;
211                        }
212                case dirsort_onbottom:
213                        if (data1.is_dir()) {
214                                if (!data2.is_dir())
215                                        return 1;
216                                else
217                                        return 0;
218                        }
219                        else {
220                                if (data2.is_dir())
221                                        return -1;
222                                else
223                                        return 0;
224                        }
225                case dirsort_inline:
226                        return 0;
227                }
228        }
229
230        template<typename value_type>
231        inline int CmpName(value_type const& data1, value_type const& data2) const
232        {
233                return DoCmpName(data1, data2, m_nameSortMode);
234        }
235
236        inline int CmpSize(const value_type &data1, const value_type &data2) const
237        {
238                int64_t const diff = data1.size - data2.size;
239                if (diff < 0)
240                        return -1;
241                else if (diff > 0)
242                        return 1;
243                else
244                        return 0;
245        }
246
247        inline int CmpStringNoCase(const wxString &data1, const wxString &data2) const
248        {
249                return data1.CmpNoCase(data2);
250        }
251
252        inline int CmpTime(const value_type &data1, const value_type &data2) const
253        {
254                if( data1.time < data2.time ) {
255                        return -1;
256                }
257                else if( data1.time > data2.time ) {
258                        return 1;
259                }
260                else {
261                        return 0;
262                }
263        }
264
265protected:
266        Listing const& m_listing;
267
268        DirSortMode const m_dirSortMode;
269        NameSortMode const m_nameSortMode;
270};
271
272template<class CFileData> class CFileListCtrl;
273
274template<class T, typename DataEntry> class CReverseSort : public T
275{
276public:
277        CReverseSort(typename T::List const& listing, std::vector<DataEntry>& fileData, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const pListView)
278                : T(listing, fileData, dirSortMode, nameSortMode, pListView)
279        {
280        }
281
282        inline bool operator()(int a, int b) const
283        {
284                return T::operator()(b, a);
285        }
286};
287
288template<typename Listing, typename DataEntry>
289class CFileListCtrlSortName : public CFileListCtrlSort<Listing>
290{
291public:
292        CFileListCtrlSortName(Listing const& listing, std::vector<DataEntry>&, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const)
293                : CFileListCtrlSort<Listing>(listing, dirSortMode, nameSortMode)
294        {
295        }
296
297        bool operator()(int a, int b) const
298        {
299                typename Listing::value_type const& data1 = this->m_listing[a];
300                typename Listing::value_type const& data2 = this->m_listing[b];
301
302                CMP(CmpDir, data1, data2);
303
304                CMP_LESS(CmpName, data1, data2);
305        }
306};
307
308template<typename Listing, typename DataEntry>
309class CFileListCtrlSortSize : public CFileListCtrlSort<Listing>
310{
311public:
312        CFileListCtrlSortSize(Listing const& listing, std::vector<DataEntry>&, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const)
313                : CFileListCtrlSort<Listing>(listing, dirSortMode, nameSortMode)
314        {
315        }
316
317        bool operator()(int a, int b) const
318        {
319                typename Listing::value_type const& data1 = this->m_listing[a];
320                typename Listing::value_type const& data2 = this->m_listing[b];
321
322                CMP(CmpDir, data1, data2);
323
324                CMP(CmpSize, data1, data2);
325
326                CMP_LESS(CmpName, data1, data2);
327        }
328};
329
330template<typename Listing, typename DataEntry>
331class CFileListCtrlSortType : public CFileListCtrlSort<Listing>
332{
333public:
334        CFileListCtrlSortType(Listing const& listing, std::vector<DataEntry>& fileData, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const pListView)
335                : CFileListCtrlSort<Listing>(listing, dirSortMode, nameSortMode), m_pListView(pListView), m_fileData(fileData)
336        {
337        }
338
339        bool operator()(int a, int b) const
340        {
341                typename Listing::value_type const& data1 = this->m_listing[a];
342                typename Listing::value_type const& data2 = this->m_listing[b];
343
344                CMP(CmpDir, data1, data2);
345
346                DataEntry &type1 = m_fileData[a];
347                DataEntry &type2 = m_fileData[b];
348                if (type1.fileType.empty())
349                        type1.fileType = m_pListView->GetType(data1.name, data1.is_dir());
350                if (type2.fileType.empty())
351                        type2.fileType = m_pListView->GetType(data2.name, data2.is_dir());
352
353                CMP(CmpStringNoCase, type1.fileType, type2.fileType);
354
355                CMP_LESS(CmpName, data1, data2);
356        }
357
358protected:
359        CFileListCtrl<DataEntry>* const m_pListView;
360        std::vector<DataEntry>& m_fileData;
361};
362
363template<typename Listing, typename DataEntry>
364class CFileListCtrlSortTime : public CFileListCtrlSort<Listing>
365{
366public:
367        CFileListCtrlSortTime(Listing const& listing, std::vector<DataEntry>&, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const)
368                : CFileListCtrlSort<Listing>(listing, dirSortMode, nameSortMode)
369        {
370        }
371
372        bool operator()(int a, int b) const
373        {
374                typename Listing::value_type const& data1 = this->m_listing[a];
375                typename Listing::value_type const& data2 = this->m_listing[b];
376
377                CMP(CmpDir, data1, data2);
378
379                CMP(CmpTime, data1, data2);
380
381                CMP_LESS(CmpName, data1, data2);
382        }
383};
384
385template<typename Listing, typename DataEntry>
386class CFileListCtrlSortPermissions : public CFileListCtrlSort<Listing>
387{
388public:
389        CFileListCtrlSortPermissions(Listing const& listing, std::vector<DataEntry>&, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const)
390                : CFileListCtrlSort<Listing>(listing, dirSortMode, nameSortMode)
391        {
392        }
393
394        bool operator()(int a, int b) const
395        {
396                typename Listing::value_type const& data1 = this->m_listing[a];
397                typename Listing::value_type const& data2 = this->m_listing[b];
398
399                CMP(CmpDir, data1, data2);
400
401                CMP(CmpStringNoCase, *data1.permissions, *data2.permissions);
402
403                CMP_LESS(CmpName, data1, data2);
404        }
405};
406
407template<typename Listing, typename DataEntry>
408class CFileListCtrlSortOwnerGroup : public CFileListCtrlSort<Listing>
409{
410public:
411        CFileListCtrlSortOwnerGroup(Listing const& listing, std::vector<DataEntry>&, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const)
412                : CFileListCtrlSort<Listing>(listing, dirSortMode, nameSortMode)
413        {
414        }
415
416        bool operator()(int a, int b) const
417        {
418                typename Listing::value_type const& data1 = this->m_listing[a];
419                typename Listing::value_type const& data2 = this->m_listing[b];
420
421                CMP(CmpDir, data1, data2);
422
423                CMP(CmpStringNoCase, *data1.ownerGroup, *data2.ownerGroup);
424
425                CMP_LESS(CmpName, data1, data2);
426        }
427};
428
429template<typename Listing, typename DataEntry>
430class CFileListCtrlSortPath : public CFileListCtrlSort<Listing>
431{
432public:
433        CFileListCtrlSortPath(Listing const& listing, std::vector<DataEntry>& fileData, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const)
434                : CFileListCtrlSort<Listing>(listing, dirSortMode, nameSortMode)
435                , m_fileData(fileData)
436        {
437        }
438
439        bool operator()(int a, int b) const
440        {
441                typename Listing::value_type const& data1 = this->m_listing[a];
442                typename Listing::value_type const& data2 = this->m_listing[b];
443
444                if (this->m_listing[a].path < m_fileData[b].path)
445                        return true;
446                if (this->m_listing[a].path != m_fileData[b].path)
447                        return false;
448
449                CMP_LESS(CmpName, static_cast<CDirentry const&>(data1), static_cast<CDirentry const&>(data2));
450        }
451        std::vector<DataEntry>& m_fileData;
452};
453
454template<typename Listing, typename DataEntry>
455class CFileListCtrlSortNamePath : public CFileListCtrlSort<Listing>
456{
457public:
458        CFileListCtrlSortNamePath(Listing const& listing, std::vector<DataEntry>& fileData, CFileListCtrlSortBase::DirSortMode dirSortMode, CFileListCtrlSortBase::NameSortMode nameSortMode, CFileListCtrl<DataEntry>* const)
459                : CFileListCtrlSort<Listing>(listing, dirSortMode, nameSortMode)
460                , m_fileData(fileData)
461        {
462        }
463
464        bool operator()(int a, int b) const
465        {
466                typename Listing::value_type const& data1 = this->m_listing[a];
467                typename Listing::value_type const& data2 = this->m_listing[b];
468
469                CMP(CmpDir, data1, data2);
470                CMP(CmpName, data1, data2);
471
472                if (this->m_listing[a].path < m_fileData[b].path)
473                        return true;
474                if (this->m_listing[a].path != m_fileData[b].path)
475                        return false;
476
477                CMP_LESS(CmpName, data1, data2);
478        }
479        std::vector<DataEntry>& m_fileData;
480};
481
482namespace genericTypes {
483        enum type {
484                file,
485                directory
486        };
487}
488
489template<class CFileData> class CFileListCtrl : public wxListCtrlEx, public CComparableListing
490{
491        template<typename Listing, typename DataEntry> friend class CFileListCtrlSortType;
492public:
493        CFileListCtrl(wxWindow* pParent, CState *pState, CQueueView *pQueue, bool border = false);
494        virtual ~CFileListCtrl();
495
496        class CSortComparisonObject : public std::binary_function<int,int,bool>
497        {
498        public:
499                CSortComparisonObject(CFileListCtrlSortBase* pObject)
500                        : m_pObject(pObject)
501                {
502                }
503
504                void Destroy()
505                {
506                        delete m_pObject;
507                }
508
509                inline bool operator()(int a, int b)
510                {
511                        return m_pObject->operator ()(a, b);
512                }
513        protected:
514                CFileListCtrlSortBase* m_pObject;
515        };
516
517        void SetFilelistStatusBar(CFilelistStatusBar* pFilelistStatusBar) { m_pFilelistStatusBar = pFilelistStatusBar; }
518        CFilelistStatusBar* GetFilelistStatusBar() { return m_pFilelistStatusBar; }
519
520        void ClearSelection();
521
522        virtual void OnNavigationEvent(bool) {}
523
524protected:
525        CQueueView *m_pQueue;
526
527        std::vector<CFileData> m_fileData;
528        std::vector<unsigned int> m_indexMapping;
529        std::vector<unsigned int> m_originalIndexMapping; // m_originalIndexMapping will only be set on comparisons
530
531        virtual bool ItemIsDir(int index) const = 0;
532        virtual int64_t ItemGetSize(int index) const = 0;
533
534        std::map<wxString, wxString> m_fileTypeMap;
535
536        // The .. item
537        bool m_hasParent;
538
539        int m_sortColumn;
540        int m_sortDirection;
541
542        void InitSort(int optionID); // Has to be called after initializing columns
543        void SortList(int column = -1, int direction = -1, bool updateSelections = true);
544        enum CFileListCtrlSortBase::DirSortMode GetDirSortMode();
545        enum CFileListCtrlSortBase::NameSortMode GetNameSortMode();
546        virtual CSortComparisonObject GetSortComparisonObject() = 0;
547
548        // An empty path denotes a virtual file
549        wxString GetType(wxString name, bool dir, const wxString& path = _T(""));
550
551        // Comparison related
552        virtual void ScrollTopItem(int item);
553        virtual void OnPostScroll();
554        virtual void OnExitComparisonMode();
555        virtual void CompareAddFile(t_fileEntryFlags flags);
556
557        int m_comparisonIndex;
558
559        // Remembers which non-fill items are selected if enabling/disabling comparison.
560        // Exploit fact that sort order doesn't change -> O(n)
561        void ComparisonRememberSelections();
562        void ComparisonRestoreSelections();
563        std::deque<int> m_comparisonSelections;
564
565        CFilelistStatusBar* m_pFilelistStatusBar;
566
567#ifndef __WXMSW__
568        // Generic wxListCtrl does not support wxLIST_STATE_DROPHILITED, emulate it
569        wxListItemAttr m_dropHighlightAttribute;
570#endif
571
572        void SetSelection(int item, bool select);
573#ifndef __WXMSW__
574        // Used by selection tracking
575        void SetItemCount(int count);
576#endif
577
578#ifdef __WXMSW__
579        virtual int GetOverlayIndex(int) { return 0; }
580#endif
581
582private:
583        void SortList_UpdateSelections(bool* selections, int focused_item, unsigned int focused_index);
584
585        // If this is set to true, don't process selection changed events
586        bool m_insideSetSelection;
587
588#ifdef __WXMSW__
589        virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam);
590        virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
591#else
592        int m_focusItem;
593        std::vector<bool> m_selections;
594        int m_pending_focus_processing;
595#endif
596
597#if defined(__WXGTK__) && !defined(__WXGTK3__)
598        std::unique_ptr<CGtkEventCallbackProxyBase> m_gtkEventCallbackProxy;
599#endif
600
601        wxString m_genericTypes[2];
602
603        DECLARE_EVENT_TABLE()
604        void OnColumnClicked(wxListEvent &event);
605        void OnColumnRightClicked(wxListEvent& event);
606        void OnItemSelected(wxListEvent& event);
607        void OnItemDeselected(wxListEvent& event);
608#ifndef __WXMSW__
609        void OnFocusChanged(wxListEvent& event);
610        void OnProcessFocusChange(wxCommandEvent& event);
611        void OnLeftDown(wxMouseEvent& event);
612        void OnProcessMouseEvent(wxCommandEvent& event);
613#endif
614        void OnKeyDown(wxKeyEvent& event);
615};
616
617#ifdef FILELISTCTRL_INCLUDE_TEMPLATE_DEFINITION
618#include "filelistctrl.cpp"
619#endif
620
621#endif //__FILELISTCTRL_H__
Note: See TracBrowser for help on using the repository browser.