File: EditableDeclaration.h

package info (click to toggle)
darkradiant 3.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 41,080 kB
  • sloc: cpp: 264,743; ansic: 10,659; python: 1,852; xml: 1,650; sh: 92; makefile: 21
file content (94 lines) | stat: -rw-r--r-- 3,470 bytes parent folder | download | duplicates (2)
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
#pragma once

#include "DeclarationBase.h"

namespace decl
{

/**
 * Declaration class used by all types that can be changed after parsing
 * through their public API (e.g. Particles or Materials).
 *
 * Implementing classes need to invoke onParsedContentsChanged() on any
 * change of its contents.The attached syntax block will be marked as
 * outdated and calls to getSyntaxBlock() will trigger a refresh
 * of the syntax block through the generateSyntaxBlock() override.
 *
 * Note that calling setSyntaxBlock() will clear the invalid status,
 * the subsequent parseFromTokens() will very likely overwrite all changes.
 * It's up to the client code to avoid these situations.
 * On a related note, subclasses need to call ensureParsed() before altering
 * its members, to avoid parseFromTokens() from undoing the changes.
 *
 * Example implementation of a public setter method:
 *
 * void YourDeclaration::setFloatValue(float value)
 * {
 *     ensureParsed();
 *     _value = value;
 *     onParsedContentsChanged();
 * }
 */
template<typename DeclarationInterface>
class EditableDeclaration :
    public DeclarationBase<DeclarationInterface>
{
private:
    // Is set to true once the contents of the declaration
    // have been changed by the subclass (see onParsedContentsChanged).
    // The assigned syntax block's contents are no longer up to date
    // and will be regenerated before a call to getSyntaxBlock() returns.
    bool _syntaxBlockInvalidated;

protected:
    EditableDeclaration(decl::Type type, const std::string& name) :
        DeclarationBase<DeclarationInterface>(type, name),
        _syntaxBlockInvalidated(false)
    {}

    EditableDeclaration(const EditableDeclaration<DeclarationInterface>& other) = default;

public:
    const DeclarationBlockSyntax& getBlockSyntax() override
    {
        // In case the contents have been invalidated, acquire the new source text
        if (_syntaxBlockInvalidated)
        {
            _syntaxBlockInvalidated = false;
            DeclarationBase<DeclarationInterface>::assignSyntaxBlockContents(generateSyntax());
        }

        return DeclarationBase<DeclarationInterface>::getBlockSyntax();
    }

protected:
    void onSyntaxBlockAssigned(const DeclarationBlockSyntax& block) override
    {
        // Assigning a new syntax block overrides any previous edits to the decl
        // Otherwise the block contents would immediately get overwritten again
        // in getBlockSyntax() by invoking generateSyntax()
        _syntaxBlockInvalidated = false;

        DeclarationBase<DeclarationInterface>::onSyntaxBlockAssigned(block);
    }

    // Needs to be called by subclasses when members change and the
    // syntax block (that has been used to parse them) is no longer valid
    // The next time client code will acquire the syntax block, the subclass
    // will be asked to provide it through the virtual generateSyntaxBlock()
    void onParsedContentsChanged()
    {
        _syntaxBlockInvalidated = true;

        // Emit the changed signal of the base
        DeclarationBase<DeclarationInterface>::signal_DeclarationChanged().emit();
    }

    // Should generate a new syntax block based on the current state of the instance.
    // Will be invoked by the EditableDeclaration base class when clients request
    // the syntax using getSyntaxBlock() and the syntax has been invalidated by
    // onParsedContentsChanged().
    virtual std::string generateSyntax() = 0;
};

}