modelvector.h 8.53 KB
Newer Older
1
2
3
4
5
#ifndef MODELVECTOR_H
#define MODELVECTOR_H
#include <vector>
#include <QAbstractListModel>
#include <QDebug>
6
#include <memory>
7
#include "dmx/namedobject.h"
8

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace detail {

template<typename T> //by value
T getPointer(const std::vector<T> &v, int index){
    return v[index];
}

template<typename T> //by pointer
T*  getPointer(const std::vector<T*> &v, int index){
    return v[index];
}

template<typename T> //by std::shared_ptr<T>
T* getPointer(const std::vector<std::shared_ptr<T>> &v, int index){
    return v[index].get();
}

26
27
28
29
30
31
32
33
34
35
36
template<typename T> //by std::shared_ptr<T>
T* getPointer(const std::vector<std::unique_ptr<T>> &v, int index){
    return v[index].get();
}

template< class T > struct is_smart_pointer_helper     : std::false_type {};
template< class T > struct is_smart_pointer_helper<std::unique_ptr<T>> : std::true_type {};
template< class T > struct is_smart_pointer_helper<std::shared_ptr<T>> : std::true_type {};
template< class T > struct is_smart_pointer : is_smart_pointer_helper<typename std::remove_cv<T>::type> {};
template< class T > inline constexpr bool is_smart_pointer_v = is_smart_pointer<T>::value;

37
38
}

39
template<typename Type>
40
41
42
/**
 * @brief The ModelVector class is a wrapper around a std::vector thats support the QAbstractListModel Interface
 */
43
class ModelVector : public QAbstractListModel{
44
45
46
    /**
     * @brief model The Vector holding the data
     */
Leander Schulten's avatar
Leander Schulten committed
47
48
    std::vector<Type> model;

49
50
51
52
53
54
55
56
57
58
59
60
    /*
      Old code:
        namespace std {
            template<>
              struct __is_pointer_helper<std::shared_ptr<FOO>>
              : public true_type { };
        }


    decltype (&*model.at(std::declval<int>())) get(int index, std::true_type)const{
        // &* to handle smart pointer
        return &*model[index];
Leander Schulten's avatar
Leander Schulten committed
61
62
63
64
    }

    Type* get(int index, std::false_type)const{
        return const_cast<Type*>(&model[index]);
65
    }*/
Leander Schulten's avatar
Leander Schulten committed
66

67
public:
Leander Schulten's avatar
Leander Schulten committed
68
69
    using const_iterator = typename std::vector<Type>::const_iterator;

70
71
72
    enum{
        ModelDataRole = Qt::UserRole+1,
    };
Leander Schulten's avatar
Leander Schulten committed
73
74
75
    const std::vector<Type>& getVector()const{return model;}
    std::vector<Type>& getVector(){return model;}
    typename std::vector<Type>::size_type size()const{return model.size();}
Leander Schulten's avatar
Leander Schulten committed
76
    virtual int rowCount(const QModelIndex &) const override{return static_cast<int>(model.size());}
77
78
79
80
81
82
    /**
     * @brief data Return always, if the index is valid, a QVarient that contains the data at the vector
     * @param index the Index in the vector
     * @param role Not used here
     * @return A QVariant which hold a Pointer to the data
     */
83
84
85
    virtual QVariant data(const QModelIndex &index, int role) const override{
        Q_UNUSED(role);
        if(index.row()>=0&&index.row()<int(model.size())){
86
            //return QVariant::fromValue(get(index.row(),std::is_pointer<Type>()));
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
            if(role==Qt::DisplayRole){
                if constexpr(std::is_pointer_v<Type>){
                    if constexpr(std::is_base_of_v<DMX::NamedObject,std::remove_pointer<Type>>)
                        return detail::getPointer(model,index.row())->getName();
                    else
                        return "No Display Property available! See ModelVector";
                }else if constexpr(detail::is_smart_pointer_v<Type>){
                    if constexpr(std::is_base_of_v<DMX::NamedObject,typename Type::element_type>)
                        return detail::getPointer(model,index.row())->getName();
                    else
                        return "No Display Property available! See ModelVector";
                }else{
                    if constexpr(std::is_base_of_v<QObject, Type>)
                        return model[index.row()].property("name");
                    else
                        return "No Display Property available! See ModelVector";
                }
            }
105
            return QVariant::fromValue(detail::getPointer(model,index.row()));
106
107
108
        }
        return QVariant();
    }
109
110
111
112
113

    /**
     * @brief roleNames returns the standard role Names and added the Role "modelData"
     * @return
     */
114
    QHash<int,QByteArray> roleNames()const override{
115
        QHash<int,QByteArray> r = QAbstractListModel::roleNames();
116
117
118
        r[ModelDataRole] = "modelData";
        return r;
    }
119
    typename std::vector<Type>::iterator erase(typename std::vector<Type>::const_iterator i){
120
        const auto pos = std::distance(model.cbegin(),i);
121
        beginRemoveRows(QModelIndex(),pos,pos);
122
        const auto result = model.erase(i);
123
        endRemoveRows();
124
        return result;
125
    }
126
    typename std::vector<Type>::iterator  erase(const_iterator first, const_iterator last){
Leander Schulten's avatar
Leander Schulten committed
127
128
        const auto pos = std::distance(model.cbegin(),first);
        beginRemoveRows(QModelIndex(),pos,pos + std::distance(first,last) -1);
129
        const auto result = model.erase(first,last);
Leander Schulten's avatar
Leander Schulten committed
130
        endRemoveRows();
131
        return result;
Leander Schulten's avatar
Leander Schulten committed
132
    }
133
    Type erase(int i){
Leander Schulten's avatar
Leander Schulten committed
134
        Q_ASSERT(i>=0 && i < static_cast<int>(size()));
135
136
137
138
        beginRemoveRows(QModelIndex(),i,i);
        auto result = model[i];
        model.erase(model.cbegin() + i);
        endRemoveRows();
139
140
        return result;
    }
141
142
143

    template<typename Predicate>
    void remove_if(Predicate p){
144
        for (auto i = cbegin();i!=cend();) {
145
146
            if(p(*i)){
                i = erase(i);
147
148
            }else{
                ++i;
149
150
151
152
153
154
            }
        }
    }
    void removeAll(const Type & value){
        remove_if([&](const auto & v){return v == value;});
    }
155
156
157
158
    /**
     * @brief beginPushBack use this function only if you want to push_back at the underlieingvector by your own, if you are finished, you have to call endPushBack()
     * @param length How much objects you want to push_back
     */
159
    void beginPushBack(int length){beginInsertRows(QModelIndex(),model.size(),model.size()+length-1);}
160
161
162
    /**
     * @brief endPushBack Call this function if you have started push_backing with beginPushBack and are finisched
     */
163
    void endPushBack(){endInsertRows();}
Leander Schulten's avatar
Leander Schulten committed
164
    typename std::vector<Type>::const_iterator cbegin()const{
165
166
        return model.cbegin();
    }
Leander Schulten's avatar
Leander Schulten committed
167
    typename std::vector<Type>::const_iterator cend()const{
168
169
        return model.cend();
    }
Leander Schulten's avatar
Leander Schulten committed
170
171
172
173
174
175
176
    typename std::vector<Type>::const_iterator begin()const{
        return model.begin();
    }
    typename std::vector<Type>::const_iterator end()const{
        return model.end();
    }
    typename std::vector<Type>::iterator begin(){
177
178
        return model.begin();
    }
Leander Schulten's avatar
Leander Schulten committed
179
    typename std::vector<Type>::iterator end(){
180
181
        return model.end();
    }
182
183
184
185
    /**
     * @brief push_back Adds one Element at the back
     * @param t The Element to add
     */
186
    void push_back(const Type& t){
Leander Schulten's avatar
Leander Schulten committed
187
188
189
190
191
192
193
194
195
196
197
198
199
200
        if(std::is_pointer<Type>()){
            beginPushBack(1);
            model.push_back(t);
            endPushBack();
        }else{
            auto cap = model.capacity();
            beginPushBack(1);
            model.push_back(t);
            endPushBack();
            if(cap!=model.capacity()){
                emit dataChanged(index(0,0),index(model.size()-1,0));
            }
        }
    }
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    /**
     * @brief push_back Adds one Element at the back
     * @param t The Element to add
     */
    void push_back(Type&& t){
        if(std::is_pointer<Type>()){
            beginPushBack(1);
            model.push_back(std::forward<Type>(t));
            endPushBack();
        }else{
            auto cap = model.capacity();
            beginPushBack(1);
            model.push_back(std::forward<Type>(t));
            endPushBack();
            if(cap!=model.capacity()){
                emit dataChanged(index(0,0),index(model.size()-1,0));
            }
        }
    }
Leander Schulten's avatar
Leander Schulten committed
220
221
222
223
    template<typename... _Args>
    void
    emplace_back(_Args&&... __args){
        if(std::is_pointer<Type>()){
224
        beginPushBack(1);
Leander Schulten's avatar
Leander Schulten committed
225
        model.emplace_back(std::forward<_Args>(__args)...);
226
        endPushBack();
Leander Schulten's avatar
Leander Schulten committed
227
228
229
230
231
232
233
234
235
        }else{
            auto cap = model.capacity();
            beginPushBack(1);
            model.emplace_back(std::forward<_Args>(__args)...);
            endPushBack();
            if(cap!=model.capacity()){
                emit dataChanged(index(0,0),index(model.size()-1,0));
            }
        }
236
    }
Leander Schulten's avatar
Leander Schulten committed
237
    typename std::vector<Type>::reference back(){
238
239
        return model.back();
    }
240

241
242
243
244
245
    typename std::vector<Type>::reference operator[](int index){
        return model[index];
    }

    typename std::vector<Type>::const_reference operator[](int index)const{
246
247
248
        return model[index];
    }

249
250
251
252
253
254
255
256
    void clear(){
        if(size()==0){
            return;
        }
        beginRemoveRows(QModelIndex(),0,size()-1);
        model.clear();
        endRemoveRows();
    }
257
258
259
};

#endif // MODELVECTOR_H