File: PolyPtr.h

package info (click to toggle)
bornagain 23.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 103,936 kB
  • sloc: cpp: 423,131; python: 40,997; javascript: 11,167; awk: 630; sh: 318; ruby: 173; xml: 130; makefile: 51; ansic: 24
file content (132 lines) | stat: -rw-r--r-- 5,000 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
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
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Model/Descriptor/PolyPtr.h
//! @brief     Defines and implements template class PolyPtr.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2021
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#ifndef BORNAGAIN_GUI_MODEL_DESCRIPTOR_POLYPTR_H
#define BORNAGAIN_GUI_MODEL_DESCRIPTOR_POLYPTR_H

#include "GUI/Model/Util/UtilXML.h"

class PolyBase {
public:
    virtual ~PolyBase() = default;
    QString piLabel() const { return m_label; }
    QString piTooltip() const { return m_tooltip; }
    QStringList menuEntries() const { return m_menu_entries; }

    virtual void setCertainIndex(int index) = 0;
    virtual int certainIndex() const = 0;

protected:
    QString m_label;            //!< A label text (short, no trailing colon)
    QString m_tooltip;          //!< Tooltip text
    QStringList m_menu_entries; //!< List of options, usually presented as combo entries
};

//! Holds a polymorphous item. Possible types of the item are specified by a Catalog.
template <typename BaseItem, typename Catalog> class PolyPtrBase : public PolyBase {
public:
    void simpleInit(const QString& label, const QString& tooltip,
                    typename Catalog::Type currentType);

    BaseItem* certainItem() const { return m_item.get(); }

    void setCertainItem(BaseItem* t) { m_item.reset(t); }

    void writeTo(QXmlStreamWriter* w) const;
    template <typename... Args> void readFrom(QXmlStreamReader* r, Args... args);

    int certainIndex() const override { return m_types.indexOf(Catalog::type(m_item.get())); }

protected:
    std::unique_ptr<BaseItem> m_item; //!< Current selection

    QVector<typename Catalog::Type> m_types = Catalog::types();
};

//! Holds a polymorphous item that can be created without extra parameters.
template <typename BaseItem, typename Catalog>
class PolyPtr : public PolyPtrBase<BaseItem, Catalog> {
public:
    void setCertainIndex(int index) override
    {
        this->m_item.reset(Catalog::create(this->m_types[index]));
    }
};

//! Holds a polymorphous item that can only be created with an extra parameter.
template <typename BaseItem, typename Catalog, typename ContextData>
class PolyPtrWithContext : public PolyPtrBase<BaseItem, Catalog> {
public:
    PolyPtrWithContext(const ContextData* contextData)
        : m_contextData(contextData)
    {
    }
    void setCertainIndex(int index) override
    {
        this->m_item.reset(Catalog::create(this->m_types[index], m_contextData));
    }

private:
    const ContextData* m_contextData;
};

//! Initialize by means of a catalog class and optional creation arguments.
//!
//! The current selection will be initialized with the first type in the catalog types. The optional
//! arguments are the arguments which may be necessary for the creation method in the catalog.
template <typename BaseItem, typename Catalog>
void PolyPtrBase<BaseItem, Catalog>::simpleInit(const QString& label, const QString& tooltip,
                                                typename Catalog::Type currentType)
{
    m_label = label;
    m_tooltip = tooltip;

    m_menu_entries.clear();
    for (const auto type : m_types)
        m_menu_entries << Catalog::uiInfo(type).menuEntry;

    int index = Catalog::types().indexOf(currentType);
    setCertainIndex(index);
}

//! Serializes the catalog index of the currently selected type and calls
//! main serialization method of the selected class.
template <typename BaseItem, typename Catalog>
void PolyPtrBase<BaseItem, Catalog>::writeTo(QXmlStreamWriter* w) const
{
    const BaseItem* t = m_item.get();
    const uint typeIndex = static_cast<uint>(Catalog::type(t));
    XML::writeAttribute(w, XML::Attrib::type, typeIndex);
    // The next line allows to see the name of item type in XML. May be skipped while reading.
    XML::writeAttribute(w, XML::Attrib::kind, Catalog::uiInfo(Catalog::type(t)).menuEntry);
    if (t)
        t->writeTo(w);
}

//! Deserializes the catalog index of the currently selected type, creates a new
//! object of this type and calls main deserialization method of the selected class.
template <typename BaseItem, typename Catalog>
template <typename... Args>
void PolyPtrBase<BaseItem, Catalog>::readFrom(QXmlStreamReader* r, Args... args)
{
    const uint typeIndex = XML::readUInt(r, XML::Attrib::type);
    const QString kind = XML::readString(r, XML::Attrib::kind);
    const auto type = static_cast<typename Catalog::Type>(typeIndex);
    BaseItem* t = Catalog::create(type, args...);
    if (t)
        t->readFrom(r);
    m_item.reset(t);
}

#endif // BORNAGAIN_GUI_MODEL_DESCRIPTOR_POLYPTR_H