1 /**************************************************************************
2 ** This file is part of LiteIDE
3 **
4 ** Copyright (c) 2011-2017 LiteIDE. All rights reserved.
5 **
6 ** This library is free software; you can redistribute it and/or
7 ** modify it under the terms of the GNU Lesser General Public
8 ** License as published by the Free Software Foundation; either
9 ** version 2.1 of the License, or (at your option) any later version.
10 **
11 ** This library is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ** Lesser General Public License for more details.
15 **
16 ** In addition, as a special exception,  that plugins developed for LiteIDE,
17 ** are allowed to remain closed sourced and can be distributed under any license .
18 ** These rights are included in the file LGPL_EXCEPTION.txt in this package.
19 **
20 **************************************************************************/
21 // Module: abstractmultiproxymodel.cpp
22 // Creator: visualfc <visualfc@gmail.com>
23 
24 #include "abstractmultiproxymodel.h"
25 #include "abstractmultiproxymodel_p.h"
26 
27 #include <QSize>
28 #include <QStringList>
29 #include <QDebug>
30 
31 //detects the deletion of the source model
_q_sourceModelDestroyed()32 void AbstractMultiProxyModelPrivate::_q_sourceModelDestroyed()
33 {
34     //model = QAbstractItemModelPrivate::staticEmptyModel();
35     Q_Q(AbstractMultiProxyModel);
36     QAbstractItemModel *sourceModel = (QAbstractItemModel*)sender();
37     q->removeSourceModel(sourceModel);
38 }
39 
40 /*!
41     Constructs a proxy model with the given \a parent.
42 */
43 
AbstractMultiProxyModel(QObject * parent)44 AbstractMultiProxyModel::AbstractMultiProxyModel(QObject *parent)
45     :QAbstractItemModel(parent)
46 {
47     d_ptr = new AbstractMultiProxyModelPrivate;
48     d_ptr->q_ptr = this;
49     //setSourceModel(QAbstractItemModelPrivate::staticEmptyModel());
50 }
51 
52 /*!
53     \internal
54 */
55 
AbstractMultiProxyModel(AbstractMultiProxyModelPrivate & dd,QObject * parent)56 AbstractMultiProxyModel::AbstractMultiProxyModel(AbstractMultiProxyModelPrivate &dd, QObject *parent)
57     : QAbstractItemModel(parent), d_ptr(&dd)
58 {
59     d_ptr->q_ptr = this;
60 
61 }
62 
63 /*!
64     Destroys the proxy model.
65 */
~AbstractMultiProxyModel()66 AbstractMultiProxyModel::~AbstractMultiProxyModel()
67 {
68 
69 }
70 
71 /*!
72     Sets the given \a sourceModel to be processed by the proxy model.
73 */
74 
addSourceModel(QAbstractItemModel * sourceModel,const QModelIndex & sourceIndex)75 bool AbstractMultiProxyModel::addSourceModel(QAbstractItemModel *sourceModel,  const QModelIndex &sourceIndex)
76 {
77     Q_D(AbstractMultiProxyModel);
78     if (d->containsModel(sourceModel)) {
79         return false;
80     }
81 //    if (sourceModel) {
82 //        connect(sourceModel,SIGNAL(destroyed(QObject*)),d,SLOT(_q_sourceModelDestroyed()));
83 //    }
84     d->indexList.push_back(SourceModelIndex(sourceModel,sourceIndex));
85     return true;
86 }
87 
removeSourceModel(QAbstractItemModel * sourceModel)88 bool AbstractMultiProxyModel::removeSourceModel(QAbstractItemModel *sourceModel)
89 {
90     Q_D(AbstractMultiProxyModel);
91     QMutableListIterator<SourceModelIndex> i(d->indexList);
92     int n = 0;
93     while (i.hasNext()) {
94         SourceModelIndex index = i.next();
95         if (index.model == sourceModel) {
96             this->beginRemoveRows(QModelIndex(),n,n);
97             disconnect(sourceModel,0,this,0);
98             i.remove();
99             this->endRemoveRows();
100             return true;
101         }
102         n++;
103     }
104     return false;
105 }
106 
removeAllSourceModel()107 void AbstractMultiProxyModel::removeAllSourceModel()
108 {
109     this->beginResetModel();
110     Q_D(AbstractMultiProxyModel);
111     foreach (SourceModelIndex si, d->indexList) {
112         disconnect(si.model,0,this,0);
113     }
114     d->indexList.clear();
115     this->endResetModel();
116 }
117 
sourceModelIndexlList() const118 QList<SourceModelIndex> AbstractMultiProxyModel::sourceModelIndexlList() const
119 {
120     Q_D(const AbstractMultiProxyModel);
121     return d->indexList;
122 }
123 
sourceModelList() const124 QList<QAbstractItemModel *> AbstractMultiProxyModel::sourceModelList() const
125 {
126     Q_D(const AbstractMultiProxyModel);
127     QList<QAbstractItemModel*> modelList;
128     foreach (SourceModelIndex i, d->indexList) {
129         modelList.push_back(i.model);
130     }
131     return modelList;
132 }
133 
134 /*!
135     \reimp
136  */
submit()137 bool AbstractMultiProxyModel::submit()
138 {
139     Q_D(AbstractMultiProxyModel);
140     if (d->indexList.isEmpty()) {
141         return false;
142     }
143     foreach (SourceModelIndex source, d->indexList) {
144         source.model->submit();
145     }
146     return true;
147 }
148 
149 /*!
150     \reimp
151  */
revert()152 void AbstractMultiProxyModel::revert()
153 {
154     Q_D(AbstractMultiProxyModel);
155     foreach (SourceModelIndex source, d->indexList) {
156         source.model->revert();
157     }
158 }
159 
160 
161 /*!
162   \fn QModelIndex AbstractMultiProxyModel::mapToSource(const QModelIndex &proxyIndex) const
163 
164   Reimplement this function to return the model index in the source model that
165   corresponds to the \a proxyIndex in the proxy model.
166 
167   \sa mapFromSource()
168 */
169 
170 /*!
171   \fn QModelIndex AbstractMultiProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
172 
173   Reimplement this function to return the model index in the proxy model that
174   corresponds to the \a sourceIndex from the source model.
175 
176   \sa mapToSource()
177 */
178 
179 /*!
180   Returns a source selection mapped from the specified \a proxySelection.
181 
182   Reimplement this method to map proxy selections to source selections.
183  */
mapSelectionToSource(const QItemSelection & proxySelection) const184 QItemSelection AbstractMultiProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
185 {
186     QModelIndexList proxyIndexes = proxySelection.indexes();
187     QItemSelection sourceSelection;
188     for (int i = 0; i < proxyIndexes.size(); ++i) {
189         const QModelIndex proxyIdx = mapToSource(proxyIndexes.at(i));
190         if (!proxyIdx.isValid())
191             continue;
192         sourceSelection << QItemSelectionRange(proxyIdx);
193     }
194     return sourceSelection;
195 }
196 
197 /*!
198   Returns a proxy selection mapped from the specified \a sourceSelection.
199 
200   Reimplement this method to map source selections to proxy selections.
201 */
mapSelectionFromSource(const QItemSelection & sourceSelection) const202 QItemSelection AbstractMultiProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
203 {
204     QModelIndexList sourceIndexes = sourceSelection.indexes();
205     QItemSelection proxySelection;
206     for (int i = 0; i < sourceIndexes.size(); ++i) {
207         const QModelIndex srcIdx = mapFromSource(sourceIndexes.at(i));
208         if (!srcIdx.isValid())
209             continue;
210         proxySelection << QItemSelectionRange(srcIdx);
211     }
212     return proxySelection;
213 }
214 
215 /*!
216     \reimp
217  */
data(const QModelIndex & proxyIndex,int role) const218 QVariant AbstractMultiProxyModel::data(const QModelIndex &proxyIndex, int role) const
219 {
220    // Q_D(const AbstractMultiProxyModel);
221     SourceModelIndex source = mapToSourceEx(proxyIndex);
222     if (!source.index.isValid() && proxyIndex.column() == 0 && role ==  Qt::DisplayRole) {
223         return "Root";
224     }
225     return source.model->data(source.index,role);
226 }
227 
228 /*!
229     \reimp
230  */
headerData(int section,Qt::Orientation orientation,int role) const231 QVariant AbstractMultiProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
232 {
233     Q_D(const AbstractMultiProxyModel);
234     if (d->indexList.isEmpty()) {
235         return QVariant();
236     }
237     return d->indexList[0].model->headerData(section,orientation,role);
238 //    int sourceSection;
239 //    SourceIndex si;
240 //    if (orientation == Qt::Horizontal) {
241 //        const QModelIndex proxyIndex = index(0, section);
242 //        si = mapToSourceEx(proxyIndex);
243 //        sourceSection = si.index.column();
244 //    } else {
245 //        const QModelIndex proxyIndex = index(section, 0);
246 //        si = mapToSourceEx(proxyIndex);
247 //        sourceSection = si.index.row();
248 //    }
249 //    if (si.model == 0) {
250 //        qDebug() << "error";
251 //        return d->modelList[0]->headerData(section,orientation,role);
252 //    }
253 //    return si.model->headerData(sourceSection, orientation, role);
254 }
255 
256 /*!
257     \reimp
258  */
itemData(const QModelIndex & proxyIndex) const259 QMap<int, QVariant> AbstractMultiProxyModel::itemData(const QModelIndex &proxyIndex) const
260 {
261     return QAbstractItemModel::itemData(proxyIndex);
262 }
263 
264 /*!
265     \reimp
266  */
flags(const QModelIndex & index) const267 Qt::ItemFlags AbstractMultiProxyModel::flags(const QModelIndex &index) const
268 {
269     //Q_D(const AbstractMultiProxyModel);
270     if (!index.isValid()) {
271         return Qt::NoItemFlags;
272     }
273     SourceModelIndex source = mapToSourceEx(index);
274     return source.model->flags(source.index);
275 }
276 
277 /*!
278     \reimp
279  */
setData(const QModelIndex & index,const QVariant & value,int role)280 bool AbstractMultiProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
281 {
282     //Q_D(AbstractMultiProxyModel);
283     SourceModelIndex source = mapToSourceEx(index);
284     return source.model->setData(source.index,value,role);
285 }
286 
287 /*!
288     \reimp
289  */
setItemData(const QModelIndex & index,const QMap<int,QVariant> & roles)290 bool AbstractMultiProxyModel::setItemData(const QModelIndex &index, const QMap< int, QVariant >& roles)
291 {
292     return QAbstractItemModel::setItemData(index, roles);
293 }
294 
295 /*!
296     \reimp
297  */
setHeaderData(int section,Qt::Orientation orientation,const QVariant & value,int role)298 bool AbstractMultiProxyModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
299 {
300     //Q_D(AbstractMultiProxyModel);
301     int sourceSection;
302     SourceModelIndex source;
303     if (orientation == Qt::Horizontal) {
304         const QModelIndex proxyIndex = index(0, section);
305         source = mapToSourceEx(proxyIndex);
306         sourceSection = source.index.column();
307     } else {
308         const QModelIndex proxyIndex = index(section, 0);
309         source = mapToSourceEx(proxyIndex);
310         sourceSection = source.index.row();
311     }
312     return source.model->setHeaderData(sourceSection, orientation, value, role);
313     //return d->model->setHeaderData(sourceSection, orientation, value, role);
314 }
315 
316 /*!
317     \reimp
318     \since 4.8
319  */
buddy(const QModelIndex & index) const320 QModelIndex AbstractMultiProxyModel::buddy(const QModelIndex &index) const
321 {
322     //Q_D(const AbstractMultiProxyModel);
323     SourceModelIndex source = mapToSourceEx(index);
324     return mapFromSourceEx(source.model,source.model->buddy(source.index));
325 }
326 
327 /*!
328     \reimp
329     \since 4.8
330  */
canFetchMore(const QModelIndex & parent) const331 bool AbstractMultiProxyModel::canFetchMore(const QModelIndex &parent) const
332 {
333     //Q_D(const AbstractMultiProxyModel);
334     SourceModelIndex source = mapToSourceEx(parent);
335     if (source.model == 0) {
336         return false;
337     }
338     return source.model->canFetchMore(source.index);
339 }
340 
341 /*!
342     \reimp
343     \since 4.8
344  */
fetchMore(const QModelIndex & parent)345 void AbstractMultiProxyModel::fetchMore(const QModelIndex &parent)
346 {
347     //Q_D(AbstractMultiProxyModel);
348     SourceModelIndex source = mapToSourceEx(parent);
349     source.model->fetchMore(source.index);
350     //d->model->fetchMore(mapToSource(parent));
351 }
352 
353 /*!
354     \reimp
355     \since 4.8
356  */
sort(int column,Qt::SortOrder order)357 void AbstractMultiProxyModel::sort(int column, Qt::SortOrder order)
358 {
359     Q_D(AbstractMultiProxyModel);
360     //d->model->sort(column, order);
361     foreach (SourceModelIndex source, d->indexList) {
362         source.model->sort(column,order);
363     }
364 }
365 
366 /*!
367     \reimp
368     \since 4.8
369  */
span(const QModelIndex & index) const370 QSize AbstractMultiProxyModel::span(const QModelIndex &index) const
371 {
372     //Q_D(const AbstractMultiProxyModel);
373     SourceModelIndex source = mapToSourceEx(index);
374     return source.model->span(source.index);
375 }
376 
377 /*!
378     \reimp
379     \since 4.8
380  */
hasChildren(const QModelIndex & parent) const381 bool AbstractMultiProxyModel::hasChildren(const QModelIndex &parent) const
382 {
383     //Q_D(const AbstractMultiProxyModel);
384     SourceModelIndex source = mapToSourceEx(parent);
385     return source.model->hasChildren(source.index);
386 }
387 
388 /*!
389     \reimp
390     \since 4.8
391  */
mimeData(const QModelIndexList & indexes) const392 QMimeData* AbstractMultiProxyModel::mimeData(const QModelIndexList &indexes) const
393 {
394     Q_D(const AbstractMultiProxyModel);
395     if (d->indexList.isEmpty()) {
396         return QAbstractItemModel::mimeData(indexes);
397     }
398 
399     QModelIndexList list;
400     foreach(const QModelIndex &index, indexes)
401         list << mapToSource(index);
402 
403     return d->indexList[0].model->mimeData(list);
404 }
405 
406 /*!
407     \reimp
408     \since 4.8
409  */
mimeTypes() const410 QStringList AbstractMultiProxyModel::mimeTypes() const
411 {
412     Q_D(const AbstractMultiProxyModel);
413     if (d->indexList.isEmpty()) {
414         return QAbstractItemModel::mimeTypes();
415     }
416     return d->indexList[0].model->mimeTypes();
417 }
418 
419 /*!
420     \reimp
421     \since 4.8
422  */
supportedDropActions() const423 Qt::DropActions AbstractMultiProxyModel::supportedDropActions() const
424 {
425     Q_D(const AbstractMultiProxyModel);
426     if (d->indexList.isEmpty()) {
427         return QAbstractItemModel::supportedDropActions();
428     }
429     return d->indexList[0].model->supportedDropActions();
430 }
431 
432 #include "moc_abstractmultiproxymodel.cpp"
433 //lite_memory_check_begin
434 #if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
435      #define _CRTDBG_MAP_ALLOC
436      #include <stdlib.h>
437      #include <crtdbg.h>
438      #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
439      #define new DEBUG_NEW
440 #endif
441 //lite_memory_check_end
442