File size: 11,463 Bytes
985c397
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
// SPDX-License-Identifier: LGPL-2.1-or-later

/***************************************************************************
 *   Copyright (c) 2015 Eivind Kvedalen <eivind@kvedalen.name>             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#ifndef PROPERTYSHEET_H
#define PROPERTYSHEET_H

#ifdef _MSC_VER
# ifdef PropertySheet
#  undef PropertySheet  // Microsoft's #define conflicts with the use below
# endif
#endif

#include <map>

#include <App/DocumentObject.h>
#include <App/PropertyLinks.h>

#include <Mod/Spreadsheet/SpreadsheetGlobal.h>

#include "Cell.h"


namespace Spreadsheet
{

class Sheet;
class PropertySheet;
class SheetObserver;

class SpreadsheetExport PropertySheet: public App::PropertyExpressionContainer,
                                       private App::AtomicPropertyChangeInterface<PropertySheet>
{
    TYPESYSTEM_HEADER_WITH_OVERRIDE();

public:
    explicit PropertySheet(Sheet* _owner = nullptr);

    ~PropertySheet() override;

    std::map<App::ObjectIdentifier, const App::Expression*> getExpressions() const override;
    void setExpressions(std::map<App::ObjectIdentifier, App::ExpressionPtr>&& exprs) override;
    void onRelabeledDocument(const App::Document& doc) override;
    void onRenameDynamicProperty(const App::Property& prop, const char* oldName) override;

    void updateElementReference(
        App::DocumentObject* feature,
        bool reverse = false,
        bool notify = false
    ) override;
    bool referenceChanged() const override;
    bool adjustLink(const std::set<App::DocumentObject*>& inList) override;
    Property* CopyOnImportExternal(const std::map<std::string, std::string>& nameMap) const override;
    Property* CopyOnLabelChange(
        App::DocumentObject* obj,
        const std::string& ref,
        const char* newLabel
    ) const override;
    Property* CopyOnLinkReplace(
        const App::DocumentObject* parent,
        App::DocumentObject* oldObj,
        App::DocumentObject* newObj
    ) const override;
    void breakLink(App::DocumentObject* obj, bool clear) override;

    void afterRestore() override;
    void onContainerRestored() override;

    Property* Copy() const override;

    void Paste(const Property& from) override;

    void Save(Base::Writer& writer) const override;

    void Restore(Base::XMLReader& reader) override;

    void getLinksTo(
        std::vector<App::ObjectIdentifier>& identifiers,
        App::DocumentObject* obj,
        const char* subname = nullptr,
        bool all = false
    ) const override;

    void copyCells(Base::Writer& writer, const std::vector<App::Range>& ranges) const;

    void pasteCells(Base::XMLReader& reader, App::Range dstRange);

    Cell* createCell(App::CellAddress address);

    void setValue()
    {}

    void setContent(App::CellAddress address, const char* value);

    void setAlignment(App::CellAddress address, int _alignment);

    void setStyle(App::CellAddress address, const std::set<std::string>& _style);

    void setForeground(App::CellAddress address, const Base::Color& color);

    void setBackground(App::CellAddress address, const Base::Color& color);

    void setDisplayUnit(App::CellAddress address, const std::string& unit);

    void setAlias(App::CellAddress address, const std::string& alias);

    void setComputedUnit(App::CellAddress address, const Base::Unit& unit);

    void setSpans(App::CellAddress address, int rows, int columns);

    void clear(App::CellAddress address, bool toClearAlias = true);

    void clear();

    Cell* getValue(App::CellAddress key);

    const Cell* getValue(App::CellAddress key) const;

    Cell* getValueFromAlias(const std::string& alias);

    const Cell* getValueFromAlias(const std::string& alias) const;

    bool isValidAlias(const std::string& candidate);

    // checks whether candidate is of form A1, C4, etc.
    bool isValidCellAddressName(const std::string& candidate);

    std::vector<App::CellAddress> getUsedCells() const;

    std::tuple<App::CellAddress, App::CellAddress> getUsedRange() const;

    std::vector<App::CellAddress> getNonEmptyCells() const;

    std::tuple<App::CellAddress, App::CellAddress> getNonEmptyRange() const;

    Sheet* sheet() const
    {
        return owner;
    }

    const std::set<App::CellAddress>& getDirty()
    {
        return dirty;
    }

    void setDirty(App::CellAddress address);

    void setDirty();

    void clearDirty(App::CellAddress key)
    {
        dirty.erase(key);
    }

    void clearDirty()
    {
        dirty.clear();
        purgeTouched();
    }

    bool isDirty() const
    {
        return dirty.size() > 0;
    }

    void pasteCells(const std::map<App::CellAddress, std::string>& cells, int rowOffset, int colOffset);

    void insertRows(int row, int count);

    std::vector<App::CellAddress> getRows(int row, int count) const;

    void removeRows(int row, int count);

    void insertColumns(int col, int count);

    std::vector<App::CellAddress> getColumns(int column, int count) const;

    void removeColumns(int col, int count);

    unsigned int getMemSize() const override;

    bool mergeCells(App::CellAddress from, App::CellAddress to);

    void splitCell(App::CellAddress address);

    void getSpans(App::CellAddress address, int& rows, int& cols) const;

    bool hasSpan() const;

    App::CellAddress getAnchor(App::CellAddress address) const;

    bool isMergedCell(App::CellAddress address) const;

    bool isHidden(App::CellAddress address) const;

    const std::set<App::CellAddress>& getDeps(const std::string& name) const;

    const std::set<std::string>& getDeps(App::CellAddress pos) const;

    void recomputeDependencies(App::CellAddress key);

    PyObject* getPyObject() override;
    void setPyObject(PyObject*) override;

    PyObject* getPyValue(PyObject* key);

    void invalidateDependants(const App::DocumentObject* docObj);

    void renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier>& paths);

    void deletedDocumentObject(const App::DocumentObject* docObj);

    void documentSet();

    App::CellAddress getCellAddress(const char* addr, bool silent = false) const;
    App::Range getRange(const char* range, bool silent = false) const;

    std::string getRow(int offset = 0) const;

    std::string getColumn(int offset = 0) const;

    void setPathValue(const App::ObjectIdentifier& path, const boost::any& value) override;
    const boost::any getPathValue(const App::ObjectIdentifier& path) const override;

    unsigned getBindingBorder(App::CellAddress address) const;

    bool isBindingPath(
        const App::ObjectIdentifier& path,
        App::CellAddress* from = nullptr,
        App::CellAddress* to = nullptr,
        bool* href = nullptr
    ) const;

    enum BindingType
    {
        BindingNone,
        BindingNormal,
        BindingHiddenRef,
    };
    BindingType getBinding(
        const App::Range& range,
        App::ExpressionPtr* pStart = nullptr,
        App::ExpressionPtr* pEnd = nullptr,
        App::ObjectIdentifier* pTarget = nullptr
    ) const;

protected:
    void hasSetValue() override;
    void hasSetChildValue(App::Property& prop) override;
    void onBreakLink(App::DocumentObject* obj) override;
    void onAddDep(App::DocumentObject* obj) override;
    void onRemoveDep(App::DocumentObject* obj) override;

private:
    PropertySheet(const PropertySheet& other);
    PropertySheet& operator=(const PropertySheet&);

    /* friends */

    friend class AtomicPropertyChange;

    friend class SheetObserver;

    friend class Cell;

    friend class Sheet;

    Cell* cellAt(App::CellAddress address);

    Cell* nonNullCellAt(App::CellAddress address);

    const Cell* cellAt(App::CellAddress address) const;

    bool colSortFunc(const App::CellAddress& a, const App::CellAddress& b);

    bool rowSortFunc(const App::CellAddress& a, const App::CellAddress& b);

    /*! Set of cells that have been marked dirty */
    std::set<App::CellAddress> dirty;

    /*! Cell data in this property */
    std::map<App::CellAddress, Cell*> data;

    /*! Merged cells; cell -> anchor cell */
    std::map<App::CellAddress, App::CellAddress> mergedCells;

    /*! Owner of this property */
    Sheet* owner;

    void clearAlias(App::CellAddress address);

    void moveAlias(App::CellAddress currPos, App::CellAddress newPos);

    void moveCell(
        App::CellAddress currPos,
        App::CellAddress newPos,
        std::map<App::ObjectIdentifier, App::ObjectIdentifier>& renames
    );

    /*
     * Cell dependency tracking
     */

    void addDependencies(App::CellAddress key);

    void removeDependencies(App::CellAddress key);

    void slotChangedObject(const App::DocumentObject& obj, const App::Property& prop);
    void recomputeDependants(const App::DocumentObject* obj, const char* propName);

    /*! Cell dependencies, i.e when a change occurs to property given in key,
      the set of addresses needs to be recomputed.
      */
    std::map<std::string, std::set<App::CellAddress>> propertyNameToCellMap;

    /*! Properties this cell depends on */
    std::map<App::CellAddress, std::set<std::string>> cellToPropertyNameMap;

    /*! Cell dependencies, i.e when a change occurs to documentObject given in key,
      the set of addresses needs to be recomputed.
      */
    std::map<std::string, std::set<App::CellAddress>> documentObjectToCellMap;

    /*! DocumentObject this cell depends on */
    std::map<App::CellAddress, std::set<std::string>> cellToDocumentObjectMap;

    /*! Mapping of cell position to alias property */
    std::map<App::CellAddress, std::string> aliasProp;

    /*! Mapping of alias property to cell position */
    std::map<std::string, App::CellAddress> revAliasProp;

    /*! The associated python object */
    Py::SmartPtr PythonObject;

    std::map<const App::DocumentObject*, fastsignals::scoped_connection> depConnections;

    int updateCount = 0;
    bool restoring = false;
};

}  // namespace Spreadsheet
#endif  // PROPERTYSHEET_H