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

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

Update new version: 3.15.02

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