source: filezilla/trunk/fuentes/src/interface/filter.cpp @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 3 years ago

First release to xenial

File size: 25.0 KB
Line 
1#include <filezilla.h>
2#include "filter.h"
3#include "filteredit.h"
4#include "filezillaapp.h"
5#include "inputdialog.h"
6#include "ipcmutex.h"
7#include "local_filesys.h"
8#include "Mainfrm.h"
9#include "Options.h"
10#include "state.h"
11#include "xmlfunctions.h"
12
13#include <wx/regex.h>
14
15bool CFilterManager::m_loaded = false;
16std::vector<CFilter> CFilterManager::m_globalFilters;
17std::vector<CFilterSet> CFilterManager::m_globalFilterSets;
18unsigned int CFilterManager::m_globalCurrentFilterSet = 0;
19bool CFilterManager::m_filters_disabled = false;
20
21BEGIN_EVENT_TABLE(CFilterDialog, wxDialogEx)
22EVT_BUTTON(XRCID("wxID_OK"), CFilterDialog::OnOkOrApply)
23EVT_BUTTON(XRCID("wxID_CANCEL"), CFilterDialog::OnCancel)
24EVT_BUTTON(XRCID("wxID_APPLY"), CFilterDialog::OnOkOrApply)
25EVT_BUTTON(XRCID("ID_EDIT"), CFilterDialog::OnEdit)
26EVT_CHECKLISTBOX(wxID_ANY, CFilterDialog::OnFilterSelect)
27EVT_BUTTON(XRCID("ID_SAVESET"), CFilterDialog::OnSaveAs)
28EVT_BUTTON(XRCID("ID_RENAMESET"), CFilterDialog::OnRename)
29EVT_BUTTON(XRCID("ID_DELETESET"), CFilterDialog::OnDeleteSet)
30EVT_CHOICE(XRCID("ID_SETS"), CFilterDialog::OnSetSelect)
31
32EVT_BUTTON(XRCID("ID_LOCAL_ENABLEALL"), CFilterDialog::OnChangeAll)
33EVT_BUTTON(XRCID("ID_LOCAL_DISABLEALL"), CFilterDialog::OnChangeAll)
34EVT_BUTTON(XRCID("ID_REMOTE_ENABLEALL"), CFilterDialog::OnChangeAll)
35EVT_BUTTON(XRCID("ID_REMOTE_DISABLEALL"), CFilterDialog::OnChangeAll)
36END_EVENT_TABLE()
37
38CFilterCondition::CFilterCondition()
39{
40        type = filter_name;
41        condition = 0;
42        matchCase = true;
43        value = 0;
44}
45
46CFilter::CFilter()
47{
48        matchType = all;
49        filterDirs = true;
50        filterFiles = true;
51
52        // Filenames on Windows ignore case
53#ifdef __WXMSW__
54        matchCase = false;
55#else
56        matchCase = true;
57#endif
58}
59
60bool CFilter::HasConditionOfType(enum t_filterType type) const
61{
62        for (std::vector<CFilterCondition>::const_iterator iter = filters.begin(); iter != filters.end(); ++iter)
63        {
64                if (iter->type == type)
65                        return true;
66        }
67
68        return false;
69}
70
71bool CFilter::IsLocalFilter() const
72{
73         return HasConditionOfType(filter_attributes) || HasConditionOfType(filter_permissions);
74}
75
76CFilterDialog::CFilterDialog()
77        : m_shiftClick()
78        , m_pMainFrame()
79        , m_filters(m_globalFilters)
80        , m_filterSets(m_globalFilterSets)
81        , m_currentFilterSet(m_globalCurrentFilterSet)
82{
83}
84
85bool CFilterDialog::Create(CMainFrame* parent)
86{
87        m_pMainFrame = parent;
88
89        if (!Load(parent, _T("ID_FILTER")))
90                return false;
91
92        XRCCTRL(*this, "ID_LOCALFILTERS", wxCheckListBox)->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(CFilterDialog::OnMouseEvent), 0, this);
93        XRCCTRL(*this, "ID_LOCALFILTERS", wxCheckListBox)->Connect(wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(CFilterDialog::OnKeyEvent), 0, this);
94        XRCCTRL(*this, "ID_REMOTEFILTERS", wxCheckListBox)->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(CFilterDialog::OnMouseEvent), 0, this);
95        XRCCTRL(*this, "ID_REMOTEFILTERS", wxCheckListBox)->Connect(wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(CFilterDialog::OnKeyEvent), 0, this);
96
97        DisplayFilters();
98
99        wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
100        wxString name = _("Custom filter set");
101        pChoice->Append(_T("<") + name + _T(">"));
102        for (unsigned int i = 1; i < m_filterSets.size(); i++)
103                pChoice->Append(m_filterSets[i].name);
104        pChoice->SetSelection(m_currentFilterSet);
105        SetCtrlState();
106
107        GetSizer()->Fit(this);
108
109        return true;
110}
111
112void CFilterDialog::OnOkOrApply(wxCommandEvent& event)
113{
114        m_globalFilters = m_filters;
115        CompileRegexes();
116        m_globalFilterSets = m_filterSets;
117        m_globalCurrentFilterSet = m_currentFilterSet;
118
119        SaveFilters();
120
121        CContextManager::Get()->NotifyAllHandlers(STATECHANGE_APPLYFILTER);
122
123        if (event.GetId() == wxID_OK) {
124                EndModal(wxID_OK);
125        }
126}
127
128void CFilterDialog::OnCancel(wxCommandEvent& event)
129{
130        EndModal(wxID_CANCEL);
131}
132
133void CFilterDialog::OnEdit(wxCommandEvent& event)
134{
135        CFilterEditDialog dlg;
136        if (!dlg.Create(this, m_filters, m_filterSets))
137                return;
138
139        if (dlg.ShowModal() != wxID_OK)
140                return;
141
142        m_filters = dlg.GetFilters();
143        m_filterSets = dlg.GetFilterSets();
144        CompileRegexes();
145
146        DisplayFilters();
147}
148
149void CFilterDialog::SaveFilter(pugi::xml_node& element, const CFilter& filter)
150{
151        AddTextElement(element, "Name", filter.name);
152        AddTextElement(element, "ApplyToFiles", filter.filterFiles ? _T("1") : _T("0"));
153        AddTextElement(element, "ApplyToDirs", filter.filterDirs ? _T("1") : _T("0"));
154        AddTextElement(element, "MatchType", (filter.matchType == CFilter::any) ? _T("Any") : ((filter.matchType == CFilter::none) ? _T("None") : _T("All")));
155        AddTextElement(element, "MatchCase", filter.matchCase ? _T("1") : _T("0"));
156
157        auto xConditions = element.append_child("Conditions");
158        for (std::vector<CFilterCondition>::const_iterator conditionIter = filter.filters.begin(); conditionIter != filter.filters.end(); ++conditionIter) {
159                const CFilterCondition& condition = *conditionIter;
160
161                int type;
162                switch (condition.type)
163                {
164                case filter_name:
165                        type = 0;
166                        break;
167                case filter_size:
168                        type = 1;
169                        break;
170                case filter_attributes:
171                        type = 2;
172                        break;
173                case filter_permissions:
174                        type = 3;
175                        break;
176                case filter_path:
177                        type = 4;
178                        break;
179                case filter_date:
180                        type = 5;
181                        break;
182                default:
183                        wxFAIL_MSG(_T("Unhandled filter type"));
184                        continue;
185                }
186
187                auto xCondition = xConditions.append_child("Condition");
188                AddTextElement(xCondition, "Type", type);
189
190                if (condition.type == filter_size) {
191                        // Backwards compatibility sucks
192                        int v = condition.condition;
193                        if (v == 2)
194                                v = 3;
195                        else if (v > 2)
196                                --v;
197                        AddTextElement(xCondition, "Condition", v);
198                }
199                else
200                        AddTextElement(xCondition, "Condition", condition.condition);
201                AddTextElement(xCondition, "Value", condition.strValue);
202        }
203}
204
205void CFilterDialog::SaveFilters()
206{
207        CInterProcessMutex mutex(MUTEX_FILTERS);
208
209        CXmlFile xml(wxGetApp().GetSettingsFile(_T("filters")));
210        auto element = xml.Load();
211        if (!element) {
212                wxString msg = xml.GetError() + _T("\n\n") + _("Any changes made to the filters could not be saved.");
213                wxMessageBoxEx(msg, _("Error loading xml file"), wxICON_ERROR);
214
215                return;
216        }
217
218        auto xFilters = element.child("Filters");
219        while (xFilters) {
220                element.remove_child(xFilters);
221                xFilters = element.child("Filters");
222        }
223
224        xFilters = element.append_child("Filters");
225
226        for (auto const& filter : m_globalFilters) {
227                auto xFilter = xFilters.append_child("Filter");
228                SaveFilter(xFilter, filter);
229        }
230
231        auto xSets = element.child("Sets");
232        while (xSets) {
233                element.remove_child(xSets);
234                xSets = element.child("Sets");
235        }
236
237        xSets = element.append_child("Sets");
238        SetAttributeInt(xSets, "Current", m_currentFilterSet);
239
240        for (auto const& set : m_globalFilterSets) {
241                auto xSet = xSets.append_child("Set");
242
243                if (!set.name.empty()) {
244                        AddTextElement(xSet, "Name", set.name);
245                }
246
247                for (unsigned int i = 0; i < set.local.size(); ++i) {
248                        auto xItem = xSet.append_child("Item");
249                        AddTextElement(xItem, "Local", set.local[i] ? _T("1") : _T("0"));
250                        AddTextElement(xItem, "Remote", set.remote[i] ? _T("1") : _T("0"));
251                }
252        }
253
254        xml.Save(true);
255
256        m_filters_disabled = false;
257}
258
259void CFilterDialog::DisplayFilters()
260{
261        wxCheckListBox* pLocalFilters = XRCCTRL(*this, "ID_LOCALFILTERS", wxCheckListBox);
262        wxCheckListBox* pRemoteFilters = XRCCTRL(*this, "ID_REMOTEFILTERS", wxCheckListBox);
263
264        pLocalFilters->Clear();
265        pRemoteFilters->Clear();
266
267        for (unsigned int i = 0; i < m_filters.size(); ++i) {
268                const CFilter& filter = m_filters[i];
269
270                const bool localOnly = filter.IsLocalFilter();
271
272                pLocalFilters->Append(filter.name);
273                pRemoteFilters->Append(filter.name);
274
275                pLocalFilters->Check(i, m_filterSets[m_currentFilterSet].local[i]);
276                pRemoteFilters->Check(i, localOnly ? false : m_filterSets[m_currentFilterSet].remote[i]);
277        }
278}
279
280void CFilterDialog::OnMouseEvent(wxMouseEvent& event)
281{
282        m_shiftClick = event.ShiftDown();
283        event.Skip();
284}
285
286void CFilterDialog::OnKeyEvent(wxKeyEvent& event)
287{
288        m_shiftClick = event.ShiftDown();
289        event.Skip();
290}
291
292void CFilterDialog::OnFilterSelect(wxCommandEvent& event)
293{
294        wxCheckListBox* pLocal = XRCCTRL(*this, "ID_LOCALFILTERS", wxCheckListBox);
295        wxCheckListBox* pRemote = XRCCTRL(*this, "ID_REMOTEFILTERS", wxCheckListBox);
296
297        int item = event.GetSelection();
298
299        const CFilter& filter = m_filters[item];
300        const bool localOnly = filter.IsLocalFilter();
301        if (localOnly && event.GetEventObject() != pLocal) {
302                pRemote->Check(item, false);
303                wxMessageBoxEx(_("Selected filter only works for local files."), _("Cannot select filter"), wxICON_INFORMATION);
304                return;
305        }
306
307
308        if (m_shiftClick) {
309                if (event.GetEventObject() == pLocal) {
310                        if (!localOnly)
311                                pRemote->Check(item, pLocal->IsChecked(event.GetSelection()));
312                }
313                else
314                        pLocal->Check(item, pRemote->IsChecked(event.GetSelection()));
315        }
316
317        if (m_currentFilterSet) {
318                m_filterSets[0] = m_filterSets[m_currentFilterSet];
319                m_currentFilterSet = 0;
320                wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
321                pChoice->SetSelection(0);
322        }
323
324        bool localChecked = pLocal->IsChecked(event.GetSelection());
325        bool remoteChecked = pRemote->IsChecked(event.GetSelection());
326        m_filterSets[0].local[item] = localChecked;
327        m_filterSets[0].remote[item] = remoteChecked;
328}
329
330void CFilterDialog::OnSaveAs(wxCommandEvent& event)
331{
332        CInputDialog dlg;
333        dlg.Create(this, _("Enter name for filterset"), _("Please enter a unique name for this filter set"));
334        if (dlg.ShowModal() != wxID_OK)
335                return;
336
337        wxString name = dlg.GetValue();
338        if (name.empty()) {
339                wxMessageBoxEx(_("No name for the filterset given."), _("Cannot save filterset"), wxICON_INFORMATION);
340                return;
341        }
342        wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
343
344        CFilterSet set;
345        int old_pos = pChoice->GetSelection();
346        if (old_pos > 0)
347                set = m_filterSets[old_pos];
348        else
349                set = m_filterSets[0];
350
351        int pos = pChoice->FindString(name);
352        if (pos != wxNOT_FOUND) {
353                if (wxMessageBoxEx(_("Given filterset name already exists, overwrite filter set?"), _("Filter set already exists"), wxICON_QUESTION | wxYES_NO) != wxYES)
354                        return;
355        }
356
357        if (pos == wxNOT_FOUND) {
358                pos = m_filterSets.size();
359                m_filterSets.push_back(set);
360                pChoice->Append(name);
361        }
362        else
363                m_filterSets[pos] = set;
364
365        m_filterSets[pos].name = name;
366
367        pChoice->SetSelection(pos);
368        m_currentFilterSet = pos;
369
370        SetCtrlState();
371
372        GetSizer()->Fit(this);
373}
374
375void CFilterDialog::OnRename(wxCommandEvent& event)
376{
377        wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
378        int old_pos = pChoice->GetSelection();
379        if (old_pos == -1)
380                return;
381
382        if (!old_pos) {
383                wxMessageBoxEx(_("This filter set cannot be renamed."));
384                return;
385        }
386
387        CInputDialog dlg;
388
389        wxString msg = wxString::Format(_("Please enter a new name for the filter set \"%s\""), pChoice->GetStringSelection());
390
391        dlg.Create(this, _("Enter new name for filterset"), msg);
392        if (dlg.ShowModal() != wxID_OK)
393                return;
394
395        wxString name = dlg.GetValue();
396
397        if (name == pChoice->GetStringSelection()) {
398                // Nothing changed
399                return;
400        }
401
402        if (name.empty()) {
403                wxMessageBoxEx(_("No name for the filterset given."), _("Cannot save filterset"), wxICON_INFORMATION);
404                return;
405        }
406
407        int pos = pChoice->FindString(name);
408        if (pos != wxNOT_FOUND) {
409                if (wxMessageBoxEx(_("Given filterset name already exists, overwrite filter set?"), _("Filter set already exists"), wxICON_QUESTION | wxYES_NO) != wxYES)
410                        return;
411        }
412
413        // Remove old entry
414        pChoice->Delete(old_pos);
415        CFilterSet set = m_filterSets[old_pos];
416        m_filterSets.erase(m_filterSets.begin() + old_pos);
417
418        pos = pChoice->FindString(name);
419        if (pos == wxNOT_FOUND) {
420                pos = m_filterSets.size();
421                m_filterSets.push_back(set);
422                pChoice->Append(name);
423        }
424        else
425                m_filterSets[pos] = set;
426
427        m_filterSets[pos].name = name;
428
429        pChoice->SetSelection(pos);
430        m_currentFilterSet = pos;
431
432        GetSizer()->Fit(this);
433}
434
435void CFilterDialog::OnDeleteSet(wxCommandEvent& event)
436{
437        wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
438        int pos = pChoice->GetSelection();
439        if (pos == -1)
440                return;
441
442        if (!pos) {
443                wxMessageBoxEx(_("This filter set cannot be removed."));
444                return;
445        }
446
447        m_filterSets[0] = m_filterSets[pos];
448
449        pChoice->Delete(pos);
450        m_filterSets.erase(m_filterSets.begin() + pos);
451        wxASSERT(!m_filterSets.empty());
452
453        pChoice->SetSelection(0);
454        m_currentFilterSet = 0;
455
456        SetCtrlState();
457}
458
459void CFilterDialog::OnSetSelect(wxCommandEvent& event)
460{
461        m_currentFilterSet = event.GetSelection();
462        DisplayFilters();
463        SetCtrlState();
464}
465
466void CFilterDialog::OnChangeAll(wxCommandEvent& event)
467{
468        bool check = true;
469        if (event.GetId() == XRCID("ID_LOCAL_DISABLEALL") || event.GetId() == XRCID("ID_REMOTE_DISABLEALL"))
470                check = false;
471
472        bool local;
473        std::vector<bool>* pValues;
474        wxCheckListBox* pListBox;
475        if (event.GetId() == XRCID("ID_LOCAL_ENABLEALL") || event.GetId() == XRCID("ID_LOCAL_DISABLEALL")) {
476                pListBox = XRCCTRL(*this, "ID_LOCALFILTERS", wxCheckListBox);
477                pValues = &m_filterSets[0].local;
478                local = true;
479        }
480        else {
481                pListBox = XRCCTRL(*this, "ID_REMOTEFILTERS", wxCheckListBox);
482                pValues = &m_filterSets[0].remote;
483                local = false;
484        }
485
486        if (m_currentFilterSet) {
487                m_filterSets[0] = m_filterSets[m_currentFilterSet];
488                m_currentFilterSet = 0;
489                wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
490                pChoice->SetSelection(0);
491        }
492
493        for (size_t i = 0; i < pListBox->GetCount(); ++i) {
494                if (!local && (m_filters[i].IsLocalFilter())) {
495                        pListBox->Check(i, false);
496                        (*pValues)[i] = false;
497                }
498                else {
499                        pListBox->Check(i, check);
500                        (*pValues)[i] = check;
501                }
502        }
503}
504
505void CFilterDialog::SetCtrlState()
506{
507        wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
508
509        int sel = pChoice->GetSelection();
510        XRCCTRL(*this, "ID_RENAMESET", wxButton)->Enable(sel > 0);
511        XRCCTRL(*this, "ID_DELETESET", wxButton)->Enable(sel > 0);
512}
513
514CFilterManager::CFilterManager()
515{
516        LoadFilters();
517
518        if (m_globalFilterSets.empty()) {
519                CFilterSet set;
520                set.local.resize(m_globalFilters.size(), false);
521                set.remote.resize(m_globalFilters.size(), false);
522
523                m_globalFilterSets.push_back(set);
524        }
525}
526
527bool CFilterManager::HasActiveFilters(bool ignore_disabled /*=false*/)
528{
529        if (!m_loaded)
530                LoadFilters();
531
532        if (m_globalFilterSets.empty())
533                return false;
534
535        wxASSERT(m_globalCurrentFilterSet < m_globalFilterSets.size());
536
537        if (m_filters_disabled && !ignore_disabled)
538                return false;
539
540        const CFilterSet& set = m_globalFilterSets[m_globalCurrentFilterSet];
541        for (unsigned int i = 0; i < m_globalFilters.size(); ++i) {
542                if (set.local[i])
543                        return true;
544
545                if (set.remote[i])
546                        return true;
547        }
548
549        return false;
550}
551
552bool CFilterManager::HasSameLocalAndRemoteFilters() const
553{
554        const CFilterSet& set = m_globalFilterSets[m_globalCurrentFilterSet];
555        for (unsigned int i = 0; i < m_globalFilters.size(); i++)
556        {
557                if (set.local[i])
558                {
559                        if (!set.remote[i])
560                                return false;
561                }
562                else if (set.remote[i])
563                        return false;
564        }
565
566        return true;
567}
568
569bool CFilterManager::FilenameFiltered(const wxString& name, const wxString& path, bool dir, int64_t size, bool local, int attributes, CDateTime const& date) const
570{
571        if (m_filters_disabled)
572                return false;
573
574        wxASSERT(m_globalCurrentFilterSet < m_globalFilterSets.size());
575
576        const CFilterSet& set = m_globalFilterSets[m_globalCurrentFilterSet];
577
578        // Check active filters
579        for (unsigned int i = 0; i < m_globalFilters.size(); ++i) {
580                if (local) {
581                        if (set.local[i])
582                                if (FilenameFilteredByFilter(m_globalFilters[i], name, path, dir, size, attributes, date))
583                                        return true;
584                }
585                else {
586                        if (set.remote[i])
587                                if (FilenameFilteredByFilter(m_globalFilters[i], name, path, dir, size, attributes, date))
588                                        return true;
589                }
590        }
591
592        return false;
593}
594
595bool CFilterManager::FilenameFiltered(std::vector<CFilter> const& filters, const wxString& name, const wxString& path, bool dir, int64_t size, bool local, int attributes, CDateTime const& date) const
596{
597        for (auto const& filter : filters) {
598                if (FilenameFilteredByFilter(filter, name, path, dir, size, attributes, date))
599                        return true;
600        }
601
602        return false;
603}
604
605static bool StringMatch(const wxString& subject, const wxString& filter, int condition, bool matchCase, std::shared_ptr<const wxRegEx> const& pRegEx)
606{
607        bool match = false;
608
609        switch (condition)
610        {
611        case 0:
612                if (matchCase) {
613                        if (subject.Contains(filter))
614                                match = true;
615                }
616                else {
617                        if (subject.Lower().Contains(filter.Lower()))
618                                match = true;
619                }
620                break;
621        case 1:
622                if (matchCase) {
623                        if (subject == filter)
624                                match = true;
625                }
626                else {
627                        if (!subject.CmpNoCase(filter))
628                                match = true;
629                }
630                break;
631        case 2:
632                {
633                        const wxString& left = subject.Left(filter.Len());
634                        if (matchCase) {
635                                if (left == filter)
636                                        match = true;
637                        }
638                        else {
639                                if (!left.CmpNoCase(filter))
640                                        match = true;
641                        }
642                }
643                break;
644        case 3:
645                {
646                        const wxString& right = subject.Right(filter.Len());
647                        if (matchCase) {
648                                if (right == filter)
649                                        match = true;
650                        }
651                        else {
652                                if (!right.CmpNoCase(filter))
653                                        match = true;
654                        }
655                }
656                break;
657        case 4:
658                wxASSERT(pRegEx);
659                if (pRegEx && pRegEx->Matches(subject))
660                        match = true;
661                break;
662        case 5:
663                if (matchCase) {
664                        if (!subject.Contains(filter))
665                                match = true;
666                }
667                else {
668                        if (!subject.Lower().Contains(filter.Lower()))
669                                match = true;
670                }
671                break;
672        }
673
674        return match;
675}
676
677bool CFilterManager::FilenameFilteredByFilter(const CFilter& filter, const wxString& name, const wxString& path, bool dir, int64_t size, int attributes, CDateTime const& date)
678{
679        if (dir && !filter.filterDirs)
680                return false;
681        else if (!dir && !filter.filterFiles)
682                return false;
683
684        for (std::vector<CFilterCondition>::const_iterator iter = filter.filters.begin(); iter != filter.filters.end(); ++iter)
685        {
686                bool match = false;
687                const CFilterCondition& condition = *iter;
688
689                switch (condition.type)
690                {
691                case filter_name:
692                        match = StringMatch(name, condition.strValue, condition.condition, filter.matchCase, condition.pRegEx);
693                        break;
694                case filter_path:
695                        match = StringMatch(path, condition.strValue, condition.condition, filter.matchCase, condition.pRegEx);
696                        break;
697                case filter_size:
698                        if (size == -1)
699                                continue;
700                        switch (condition.condition)
701                        {
702                        case 0:
703                                if (size > condition.value)
704                                        match = true;
705                                break;
706                        case 1:
707                                if (size == condition.value)
708                                        match = true;
709                                break;
710                        case 2:
711                                if (size != condition.value)
712                                        match = true;
713                                break;
714                        case 3:
715                                if (size < condition.value)
716                                        match = true;
717                                break;
718                        }
719                        break;
720                case filter_attributes:
721#ifndef __WXMSW__
722                        continue;
723#else
724                        if (!attributes)
725                                continue;
726
727                        {
728                                int flag = 0;
729                                switch (condition.condition)
730                                {
731                                case 0:
732                                        flag = FILE_ATTRIBUTE_ARCHIVE;
733                                        break;
734                                case 1:
735                                        flag = FILE_ATTRIBUTE_COMPRESSED;
736                                        break;
737                                case 2:
738                                        flag = FILE_ATTRIBUTE_ENCRYPTED;
739                                        break;
740                                case 3:
741                                        flag = FILE_ATTRIBUTE_HIDDEN;
742                                        break;
743                                case 4:
744                                        flag = FILE_ATTRIBUTE_READONLY;
745                                        break;
746                                case 5:
747                                        flag = FILE_ATTRIBUTE_SYSTEM;
748                                        break;
749                                }
750
751                                int set = (flag & attributes) ? 1 : 0;
752                                if (set == condition.value)
753                                        match = true;
754                        }
755#endif //__WXMSW__
756                        break;
757                case filter_permissions:
758#ifdef __WXMSW__
759                        continue;
760#else
761                        if (attributes == -1)
762                                continue;
763
764                        {
765                                int flag = 0;
766                                switch (condition.condition)
767                                {
768                                case 0:
769                                        flag = S_IRUSR;
770                                        break;
771                                case 1:
772                                        flag = S_IWUSR;
773                                        break;
774                                case 2:
775                                        flag = S_IXUSR;
776                                        break;
777                                case 3:
778                                        flag = S_IRGRP;
779                                        break;
780                                case 4:
781                                        flag = S_IWGRP;
782                                        break;
783                                case 5:
784                                        flag = S_IXGRP;
785                                        break;
786                                case 6:
787                                        flag = S_IROTH;
788                                        break;
789                                case 7:
790                                        flag = S_IWOTH;
791                                        break;
792                                case 8:
793                                        flag = S_IXOTH;
794                                        break;
795                                }
796
797                                int set = (flag & attributes) ? 1 : 0;
798                                if (set == condition.value)
799                                        match = true;
800                        }
801#endif //__WXMSW__
802                        break;
803                case filter_date:
804                        if (date.IsValid()) {
805                                int cmp = date.Compare( condition.date );
806                                switch (condition.condition)
807                                {
808                                case 0: // Before
809                                        match = cmp < 0;
810                                        break;
811                                case 1: // Equals
812                                        match = cmp == 0;
813                                        break;
814                                case 2: // Not equals
815                                        match = cmp != 0;
816                                        break;
817                                case 3: // After
818                                        match = cmp > 0;
819                                        break;
820                                }
821                        }
822                        break;
823                default:
824                        wxFAIL_MSG(_T("Unhandled filter type"));
825                        break;
826                }
827                if (match) {
828                        if (filter.matchType == CFilter::any)
829                                return true;
830                        else if (filter.matchType == CFilter::none)
831                                return false;
832                }
833                else {
834                        if (filter.matchType == CFilter::all)
835                                return false;
836                }
837        }
838
839        if (filter.matchType != CFilter::any || filter.filters.empty())
840                return true;
841
842        return false;
843}
844
845bool CFilterManager::CompileRegexes(CFilter& filter)
846{
847        for (auto iter = filter.filters.begin(); iter != filter.filters.end(); ++iter)
848        {
849                CFilterCondition& condition = *iter;
850                if ((condition.type == filter_name || condition.type == filter_path) && condition.condition == 4) {
851                        condition.pRegEx = std::make_shared<wxRegEx>(condition.strValue);
852                        if (!condition.pRegEx->IsValid()) {
853                                condition.pRegEx.reset();
854                                return false;
855                        }
856                }
857                else
858                        condition.pRegEx.reset();
859        }
860
861        return true;
862}
863
864bool CFilterManager::CompileRegexes()
865{
866        for (auto & filter : m_globalFilters) {
867                CompileRegexes(filter);
868        }
869        return true;
870}
871
872bool CFilterManager::LoadFilter(pugi::xml_node& element, CFilter& filter)
873{
874        filter.name = GetTextElement(element, "Name");
875        filter.filterFiles = GetTextElement(element, "ApplyToFiles") == _T("1");
876        filter.filterDirs = GetTextElement(element, "ApplyToDirs") == _T("1");
877
878        wxString const matchType = GetTextElement(element, "MatchType");
879        if (matchType == _T("Any"))
880                filter.matchType = CFilter::any;
881        else if (matchType == _T("None"))
882                filter.matchType = CFilter::none;
883        else
884                filter.matchType = CFilter::all;
885        filter.matchCase = GetTextElement(element, "MatchCase") == _T("1");
886
887        auto xConditions = element.child("Conditions");
888        if (!xConditions)
889                return false;
890
891        for (auto xCondition = xConditions.child("Condition"); xCondition; xCondition = xCondition.next_sibling("Condition")) {
892                CFilterCondition condition;
893                int const type = GetTextElementInt(xCondition, "Type", 0);
894                switch (type) {
895                case 0:
896                        condition.type = filter_name;
897                        break;
898                case 1:
899                        condition.type = filter_size;
900                        break;
901                case 2:
902                        condition.type = filter_attributes;
903                        break;
904                case 3:
905                        condition.type = filter_permissions;
906                        break;
907                case 4:
908                        condition.type = filter_path;
909                        break;
910                case 5:
911                        condition.type = filter_date;
912                        break;
913                default:
914                        continue;
915                }
916                condition.condition = GetTextElementInt(xCondition, "Condition", 0);
917                if (condition.type == filter_size) {
918                        if (condition.value == 3)
919                                condition.value = 2;
920                        else if (condition.value >= 2)
921                                ++condition.value;
922                }
923                condition.strValue = GetTextElement(xCondition, "Value");
924                condition.matchCase = filter.matchCase;
925                if (condition.strValue.empty())
926                        continue;
927
928                if (condition.type == filter_size) {
929                        unsigned long long tmp;
930                        condition.strValue.ToULongLong(&tmp);
931                        condition.value = tmp;
932                }
933                else if (condition.type == filter_attributes || condition.type == filter_permissions) {
934                        if (condition.strValue == _T("0"))
935                                condition.value = 0;
936                        else
937                                condition.value = 1;
938                }
939                else if (condition.type == filter_date) {
940                        condition.date = CDateTime(condition.strValue, CDateTime::local);
941                        if (!condition.date.IsValid()) {
942                                continue;
943                        }
944                }
945
946                filter.filters.push_back(condition);
947        }
948
949        return true;
950}
951
952void CFilterManager::LoadFilters()
953{
954        if (m_loaded)
955                return;
956
957        m_loaded = true;
958
959        CInterProcessMutex mutex(MUTEX_FILTERS);
960
961        wxString file(wxGetApp().GetSettingsFile(_T("filters")));
962        if (CLocalFileSystem::GetSize(file) < 1) {
963                file = wxGetApp().GetResourceDir().GetPath() + _T("defaultfilters.xml");
964        }
965
966        CXmlFile xml(file);
967        auto element = xml.Load();
968        if (!element) {
969                wxString msg = xml.GetError() + _T("\n\n") + _("Any changes made to the filters will not be saved.");
970                wxMessageBoxEx(msg, _("Error loading xml file"), wxICON_ERROR);
971
972                return;
973        }
974
975        auto xFilters = element.child("Filters");
976        if (!xFilters)
977                return;
978
979        auto xFilter = xFilters.child("Filter");
980        while (xFilter) {
981                CFilter filter;
982
983                bool loaded = LoadFilter(xFilter, filter);
984
985                if (loaded && !filter.name.empty() && !filter.filters.empty())
986                        m_globalFilters.push_back(filter);
987
988                xFilter = xFilter.next_sibling("Filter");
989        }
990
991        CompileRegexes();
992
993        auto xSets = element.child("Sets");
994        if (!xSets)
995                return;
996
997        for (auto xSet = xSets.child("Set"); xSet; xSet = xSet.next_sibling("Set")) {
998                CFilterSet set;
999                auto xItem = xSet.child("Item");
1000                while (xItem) {
1001                        wxString local = GetTextElement(xItem, "Local");
1002                        wxString remote = GetTextElement(xItem, "Remote");
1003                        set.local.push_back(local == _T("1") ? true : false);
1004                        set.remote.push_back(remote == _T("1") ? true : false);
1005
1006                        xItem = xItem.next_sibling("Item");
1007                }
1008
1009                if (!m_globalFilterSets.empty()) {
1010                        set.name = GetTextElement(xSet, "Name");
1011                        if (set.name.empty())
1012                                continue;
1013                }
1014
1015                if (set.local.size() == m_globalFilters.size())
1016                        m_globalFilterSets.push_back(set);
1017        }
1018
1019        int value = GetAttributeInt(xSets, "Current");
1020        if (value >= 0 && static_cast<size_t>(value) < m_globalFilterSets.size()) {
1021                m_globalCurrentFilterSet = value;
1022        }
1023}
1024
1025void CFilterManager::ToggleFilters()
1026{
1027        if (m_filters_disabled) {
1028                m_filters_disabled = false;
1029                return;
1030        }
1031
1032        if (HasActiveFilters(true))
1033                m_filters_disabled = true;
1034}
1035
1036std::vector<CFilter> CFilterManager::GetActiveFilters(bool local)
1037{
1038        std::vector<CFilter> filters;
1039
1040        if (m_filters_disabled)
1041                return filters;
1042
1043        const CFilterSet& set = m_globalFilterSets[m_globalCurrentFilterSet];
1044
1045        // Check active filters
1046        for (unsigned int i = 0; i < m_globalFilters.size(); ++i) {
1047                if (local) {
1048                        if (set.local[i])
1049                                filters.push_back(m_globalFilters[i]);
1050                }
1051                else {
1052                        if (set.remote[i])
1053                                filters.push_back(m_globalFilters[i]);
1054                }
1055        }
1056
1057        return filters;
1058}
Note: See TracBrowser for help on using the repository browser.