summaryrefslogtreecommitdiff
path: root/FreeFileSync/Source/ui/tree_grid.h
blob: 0d69e820f911561a610eab8e1fc9c1c2e14a056f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// *****************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under    *
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0          *
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************

#ifndef TREE_VIEW_H_841703190201835280256673425
#define TREE_VIEW_H_841703190201835280256673425

#include <functional>
#include <zen/optional.h>
#include <wx+/grid.h>
#include "tree_grid_attr.h"
#include "../file_hierarchy.h"


namespace zen
{
//tree view of FolderComparison
class TreeView
{
public:
    TreeView() {}

    void setData(FolderComparison& newData); //set data, taking (partial) ownership

    //apply view filter: comparison results
    void updateCmpResult(bool showExcluded,
                         bool leftOnlyFilesActive,
                         bool rightOnlyFilesActive,
                         bool leftNewerFilesActive,
                         bool rightNewerFilesActive,
                         bool differentFilesActive,
                         bool equalFilesActive,
                         bool conflictFilesActive);

    //apply view filter: synchronization preview
    void updateSyncPreview(bool showExcluded,
                           bool syncCreateLeftActive,
                           bool syncCreateRightActive,
                           bool syncDeleteLeftActive,
                           bool syncDeleteRightActive,
                           bool syncDirOverwLeftActive,
                           bool syncDirOverwRightActive,
                           bool syncDirNoneActive,
                           bool syncEqualActive,
                           bool conflictFilesActive);

    enum NodeStatus
    {
        STATUS_EXPANDED,
        STATUS_REDUCED,
        STATUS_EMPTY
    };

    //---------------------------------------------------------------------
    struct Node
    {
        Node(int percent, uint64_t bytes, int itemCount, unsigned int level, NodeStatus status) :
            percent_(percent), bytes_(bytes), itemCount_(itemCount), level_(level), status_(status) {}
        virtual ~Node() {}

        const int percent_; //[0, 100]
        const uint64_t bytes_;
        const int itemCount_;
        const unsigned int level_;
        const NodeStatus status_;
    };

    struct FilesNode : public Node
    {
        FilesNode(int percent, uint64_t bytes, int itemCount, unsigned int level, const std::vector<FileSystemObject*>& filesAndLinks) :
            Node(percent, bytes, itemCount, level, STATUS_EMPTY), filesAndLinks_(filesAndLinks)  {}

        std::vector<FileSystemObject*> filesAndLinks_; //files and symlinks matching view filter; pointers are bound!
    };

    struct DirNode : public Node
    {
        DirNode(int percent, uint64_t bytes, int itemCount, unsigned int level, NodeStatus status, FolderPair& folder) : Node(percent, bytes, itemCount, level, status), folder_(folder) {}
        FolderPair& folder_;
    };

    struct RootNode : public Node
    {
        RootNode(int percent, uint64_t bytes, int itemCount, NodeStatus status, BaseFolderPair& baseFolder, const Zstring& displayName) :
            Node(percent, bytes, itemCount, 0, status), baseFolder_(baseFolder), displayName_(displayName) {}

        BaseFolderPair& baseFolder_;
        const Zstring displayName_;
    };

    std::unique_ptr<Node> getLine(size_t row) const; //return nullptr on error
    size_t linesTotal() const { return flatTree_.size(); }

    void expandNode(size_t row);
    void reduceNode(size_t row);
    NodeStatus getStatus(size_t row) const;
    ptrdiff_t getParent(size_t row) const; //return < 0 if none

    void setSortDirection(ColumnTypeTree colType, bool ascending); //apply permanently!
    std::pair<ColumnTypeTree, bool> getSortDirection() { return std::make_pair(sortColumn_, sortAscending_); }

private:
    struct DirNodeImpl;

    struct Container
    {
        uint64_t bytesGross = 0;
        uint64_t bytesNet   = 0; //bytes for files on view in this directory only
        int itemCountGross  = 0;
        int itemCountNet    = 0; //number of files on view for in this directory only

        std::vector<DirNodeImpl> subDirs;
        FileSystemObject::ObjectId firstFileId = nullptr; //weak pointer to first FilePair or SymlinkPair
        //- "compress" algorithm may hide file nodes for directories with a single included file, i.e. itemCountGross == itemCountNet == 1
        //- a ContainerObject* would be a better fit, but we need weak pointer semantics!
        //- a std::vector<FileSystemObject::ObjectId> would be a better design, but we don't want a second memory structure as large as custom grid!
    };

    struct DirNodeImpl : public Container
    {
        FileSystemObject::ObjectId objId = nullptr; //weak pointer to FolderPair
    };

    struct RootNodeImpl : public Container
    {
        std::shared_ptr<BaseFolderPair> baseFolder;
        Zstring displayName;
    };

    enum NodeType
    {
        TYPE_ROOT,      //-> RootNodeImpl
        TYPE_DIRECTORY, //-> DirNodeImpl
        TYPE_FILES      //-> Container
    };

    struct TreeLine
    {
        unsigned int level = 0;
        int percent = 0; //[0, 100]
        const Container* node = nullptr;     //
        NodeType type = NodeType::TYPE_ROOT; //we increase size of "flatTree" using C-style types rather than have a polymorphic "folderCmpView"
    };

    static void compressNode(Container& cont);
    template <class Function>
    static void extractVisibleSubtree(ContainerObject& hierObj, Container& cont, Function includeObject);
    void getChildren(const Container& cont, unsigned int level, std::vector<TreeLine>& output);
    template <class Predicate> void updateView(Predicate pred);
    void applySubView(std::vector<RootNodeImpl>&& newView);

    template <bool ascending> static void sortSingleLevel(std::vector<TreeLine>& items, ColumnTypeTree columnType);
    template <bool ascending> struct LessShortName;

    std::vector<TreeLine> flatTree_; //collapsable/expandable sub-tree of folderCmpView -> always sorted!
    /*             /|\
                    | (update...)
                    |                         */
    std::vector<RootNodeImpl> folderCmpView_; //partial view on folderCmp -> unsorted (cannot be, because files are not a separate entity)
    std::function<bool(const FileSystemObject& fsObj)> lastViewFilterPred_; //buffer view filter predicate for lazy evaluation of files/symlinks corresponding to a TYPE_FILES node
    /*             /|\
                    | (update...)
                    |                         */
    std::vector<std::shared_ptr<BaseFolderPair>> folderCmp_; //full raw data

    ColumnTypeTree sortColumn_ = treeGridLastSortColumnDefault;
    bool sortAscending_        = getDefaultSortDirection(treeGridLastSortColumnDefault);
};


Zstring getShortDisplayNameForFolderPair(const AbstractPath& itemPathL, const AbstractPath& itemPathR);

namespace treegrid
{
void init(Grid& grid);
TreeView& getDataView(Grid& grid);

void setShowPercentage(Grid& grid, bool value);
bool getShowPercentage(const Grid& grid);
}
}

#endif //TREE_VIEW_H_841703190201835280256673425
bgstack15