LeechCraft  %{LEECHCRAFT_VERSION}
Modular cross-platform feature rich live environment.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
mergemodel.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2013 Georg Rudoy
4  *
5  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #include <algorithm>
31 #include <typeinfo>
32 #include <stdexcept>
33 #include <QtDebug>
34 #include "mergemodel.h"
35 
36 using namespace LeechCraft::Util;
37 
38 MergeModel::MergeModel (const QStringList& headers, QObject *parent)
39 : QAbstractItemModel (parent)
40 , DefaultAcceptsRowImpl_ (false)
41 , Headers_ (headers)
42 {
43 }
44 
46 {
47 }
48 
49 int MergeModel::columnCount (const QModelIndex& index) const
50 {
51  if (index.isValid ())
52  {
53  QModelIndex mapped = mapToSource (index);
54  return mapped.model ()->columnCount (mapped);
55  }
56  else
57  return Headers_.size ();
58 }
59 
60 QVariant MergeModel::headerData (int column, Qt::Orientation orient, int role) const
61 {
62  if (orient != Qt::Horizontal || role != Qt::DisplayRole)
63  return QVariant ();
64 
65  return Headers_.at (column);
66 }
67 
68 QVariant MergeModel::data (const QModelIndex& index, int role) const
69 {
70  if (index.isValid ())
71  {
72  QModelIndex mapped = mapToSource (index);
73  return mapped.data (role);
74  }
75  else
76  return QVariant ();
77 }
78 
79 Qt::ItemFlags MergeModel::flags (const QModelIndex& index) const
80 {
81  QModelIndex mapped = mapToSource (index);
82  return mapped.flags ();
83 }
84 
85 QModelIndex MergeModel::index (int row, int column, const QModelIndex& parent) const
86 {
87  if (parent.isValid () || !hasIndex (row, column))
88  return QModelIndex ();
89  else
90  return createIndex (row, column);
91 }
92 
93 QModelIndex MergeModel::parent (const QModelIndex&) const
94 {
95  // here goes blocker for hierarchical #1
96  return QModelIndex ();
97 }
98 
99 int MergeModel::rowCount (const QModelIndex& parent) const
100 {
101  if (!parent.isValid ())
102  {
103  int result = 0;
104  for (models_t::const_iterator i = Models_.begin (),
105  end = Models_.end ();
106  i != end; ++i)
107  result += RowCount (*i);
108  return result;
109  }
110  else
111  {
112  QModelIndex mapped = mapToSource (parent);
113  return mapped.model ()->rowCount (mapped);
114  }
115 }
116 
117 QModelIndex MergeModel::mapFromSource (const QModelIndex& sourceIndex) const
118 {
119  if (!sourceIndex.isValid ())
120  return QModelIndex ();
121 
122  const QAbstractItemModel *model = sourceIndex.model ();
123  const_iterator moditer = FindModel (model);
124 
125  int startingRow = GetStartingRow (moditer);
126 
127  int sourceRow = sourceIndex.row ();
128  int sourceColumn = sourceIndex.column ();
129  void *sourcePtr = sourceIndex.internalPointer ();
130  quint32 sourceId = sourceIndex.internalId ();
131 
132  if (sourcePtr)
133  return createIndex (sourceRow + startingRow, sourceColumn, sourcePtr);
134  else
135  return createIndex (sourceRow + startingRow, sourceColumn, sourceId);
136 }
137 
138 QModelIndex MergeModel::mapToSource (const QModelIndex& proxyIndex) const
139 {
140  if (!proxyIndex.isValid ())
141  return QModelIndex ();
142 
143  int proxyRow = proxyIndex.row ();
144  int proxyColumn = proxyIndex.column ();
145  const_iterator modIter;
146  int startingRow = 0;
147  try
148  {
149  // here goes blocker for hierarchical #2 (cause of startingRow)
150  modIter = GetModelForRow (proxyRow, &startingRow);
151  }
152  catch (const std::runtime_error& e)
153  {
154  QStringList models;
155  Q_FOREACH (QAbstractItemModel *model, Models_)
156  models << model->objectName ();
157  qWarning () << Q_FUNC_INFO
158  << "\n"
159  << objectName ()
160  << proxyIndex
161  << "\n"
162  << e.what ()
163  << "\n"
164  << models;
165  throw;
166  }
167 
168  return (*modIter)->index (proxyRow - startingRow, proxyColumn, QModelIndex ());
169 }
170 
171 void MergeModel::setSourceModel (QAbstractItemModel*)
172 {
173  throw std::runtime_error ("You should not set source model via setSourceModel()");
174 }
175 
176 void MergeModel::SetHeaders (const QStringList& headers)
177 {
178  Headers_ = headers;
179 }
180 
181 void MergeModel::AddModel (QAbstractItemModel *model)
182 {
183  if (!model)
184  return;
185 
186  int rows = RowCount (model);
187  bool wouldInsert = false;
188  if (rows > 0)
189  wouldInsert = true;
190 
191  if (wouldInsert)
192  beginInsertRows (QModelIndex (), rowCount (), rowCount () + rows - 1);
193  Models_.push_back (model);
194  connect (model,
195  SIGNAL (columnsAboutToBeInserted (const QModelIndex&, int, int)),
196  this,
197  SLOT (handleColumnsAboutToBeInserted (const QModelIndex&, int, int)));
198  connect (model,
199  SIGNAL (columnsAboutToBeRemoved (const QModelIndex&, int, int)),
200  this,
201  SLOT (handleColumnsAboutToBeRemoved (const QModelIndex&, int, int)));
202  connect (model,
203  SIGNAL (columnsInserted (const QModelIndex&, int, int)),
204  this,
205  SLOT (handleColumnsInserted (const QModelIndex&, int, int)));
206  connect (model,
207  SIGNAL (columnsRemoved (const QModelIndex&, int, int)),
208  this,
209  SLOT (handleColumnsRemoved (const QModelIndex&, int, int)));
210  connect (model,
211  SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
212  this,
213  SLOT (handleDataChanged (const QModelIndex&, const QModelIndex&)));
214  connect (model,
215  SIGNAL (layoutAboutToBeChanged ()),
216  this,
217  SIGNAL (layoutAboutToBeChanged ()));
218  connect (model,
219  SIGNAL (layoutChanged ()),
220  this,
221  SIGNAL (layoutChanged ()));
222  connect (model,
223  SIGNAL (modelAboutToBeReset ()),
224  this,
225  SIGNAL (modelAboutToBeReset ()));
226  connect (model,
227  SIGNAL (modelReset ()),
228  this,
229  SIGNAL (modelReset ()));
230  connect (model,
231  SIGNAL (rowsAboutToBeInserted (const QModelIndex&, int, int)),
232  this,
233  SLOT (handleRowsAboutToBeInserted (const QModelIndex&, int, int)));
234  connect (model,
235  SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
236  this,
237  SLOT (handleRowsAboutToBeRemoved (const QModelIndex&, int, int)));
238  connect (model,
239  SIGNAL (rowsInserted (const QModelIndex&, int, int)),
240  this,
241  SLOT (handleRowsInserted (const QModelIndex&, int, int)));
242  connect (model,
243  SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
244  this,
245  SLOT (handleRowsRemoved (const QModelIndex&, int, int)));
246  if (wouldInsert)
247  endInsertRows ();
248 }
249 
250 MergeModel::const_iterator MergeModel::FindModel (const QAbstractItemModel *model) const
251 {
252  return std::find (Models_.begin (), Models_.end (), model);
253 }
254 
255 MergeModel::iterator MergeModel::FindModel (const QAbstractItemModel *model)
256 {
257  return std::find (Models_.begin (), Models_.end (), model);
258 }
259 
260 void MergeModel::RemoveModel (QAbstractItemModel *model)
261 {
262  models_t::iterator i = FindModel (model);
263 
264  if (i == Models_.end ())
265  {
266  qWarning () << Q_FUNC_INFO << "not found model" << model;
267  return;
268  }
269 
270  int rows = RowCount (model);
271  bool wouldRemove = false;
272  if (rows > 0)
273  wouldRemove = true;
274 
275  if (wouldRemove)
276  {
277  int startingRow = GetStartingRow (i);
278  beginRemoveRows (QModelIndex (), startingRow, startingRow + rows - 1);
279  }
280  Models_.erase (i);
281  if (wouldRemove)
282  endRemoveRows ();
283 }
284 
285 size_t MergeModel::Size () const
286 {
287  return Models_.size ();
288 }
289 
291 {
292  int result = 0;
293  for (models_t::const_iterator i = Models_.begin (); i != it; ++i)
294  result += RowCount (*i);
295  return result;
296 }
297 
299 {
300  int counter = 0;
301  if (starting)
302  *starting = 0;
303  for (models_t::const_iterator i = Models_.begin (),
304  end = Models_.end (); i != end; ++i)
305  {
306  counter += RowCount (*i);
307  if (counter > row)
308  return i;
309  if (starting)
310  *starting = counter;
311  }
312  QString msg = Q_FUNC_INFO;
313  msg += ": not found ";
314  msg += QString::number (row);
315  throw std::runtime_error (qPrintable (msg));
316 }
317 
319 {
320  int counter = 0;
321  if (starting)
322  *starting = 0;
323  for (models_t::iterator i = Models_.begin (),
324  end = Models_.end (); i != end; ++i)
325  {
326  counter += RowCount (*i);
327  if (counter > row)
328  return i;
329  if (starting)
330  *starting = counter;
331  }
332  QString msg = Q_FUNC_INFO;
333  msg += ": not found ";
334  msg += QString::number (row);
335  throw std::runtime_error (qPrintable (msg));
336 }
337 
338 QList<QAbstractItemModel*> MergeModel::GetAllModels () const
339 {
340  QList<QAbstractItemModel*> result;
341  Q_FOREACH (QPointer<QAbstractItemModel> p, Models_)
342  if (p)
343  result << p.data ();
344  return result;
345 }
346 
347 void MergeModel::handleColumnsAboutToBeInserted (const QModelIndex&, int, int)
348 {
349  qWarning () << "model" << sender ()
350  << "called handleColumnsAboutToBeInserted, ignoring it";
351  return;
352 }
353 
354 void MergeModel::handleColumnsAboutToBeRemoved (const QModelIndex&, int, int)
355 {
356  qWarning () << "model" << sender ()
357  << "called handleColumnsAboutToBeRemoved, ignoring it";
358  return;
359 }
360 
361 void MergeModel::handleColumnsInserted (const QModelIndex&, int, int)
362 {
363  qWarning () << "model" << sender ()
364  << "called handleColumnsInserted, ignoring it";
365  return;
366 }
367 
368 void MergeModel::handleColumnsRemoved (const QModelIndex&, int, int)
369 {
370  qWarning () << "model" << sender ()
371  << "called handleColumnsRemoved, ignoring it";
372  return;
373 }
374 
375 void MergeModel::handleDataChanged (const QModelIndex& topLeft,
376  const QModelIndex& bottomRight)
377 {
378  emit dataChanged (mapFromSource (topLeft), mapFromSource (bottomRight));
379 }
380 
381 void MergeModel::handleRowsAboutToBeInserted (const QModelIndex& parent,
382  int first, int last)
383 {
384  QAbstractItemModel *model = static_cast<QAbstractItemModel*> (sender ());
385  int startingRow = GetStartingRow (FindModel (model));
386  beginInsertRows (mapFromSource (parent),
387  first + startingRow, last + startingRow);
388 }
389 
390 void MergeModel::handleRowsAboutToBeRemoved (const QModelIndex& parent,
391  int first, int last)
392 {
393  QAbstractItemModel *model = static_cast<QAbstractItemModel*> (sender ());
394  int startingRow = GetStartingRow (FindModel (model));
395  try
396  {
397  beginRemoveRows (mapFromSource (parent),
398  first + startingRow, last + startingRow);
399  }
400  catch (const std::exception& e)
401  {
402  qWarning () << Q_FUNC_INFO
403  << e.what ()
404  << objectName ()
405  << first
406  << last
407  << startingRow;
408  throw;
409  }
410 }
411 
412 void MergeModel::handleRowsInserted (const QModelIndex&, int, int)
413 {
414  endInsertRows ();
415 }
416 
417 void MergeModel::handleRowsRemoved (const QModelIndex&, int, int)
418 {
419  endRemoveRows ();
420 }
421 
422 bool MergeModel::AcceptsRow (QAbstractItemModel*, int) const
423 {
424  DefaultAcceptsRowImpl_ = true;
425  return true;
426 }
427 
428 int MergeModel::RowCount (QAbstractItemModel *model) const
429 {
430  if (!model)
431  return 0;
432 
433  int orig = model->rowCount ();
434  if (DefaultAcceptsRowImpl_)
435  return orig;
436 
437  int result = 0;
438  for (int i = 0; i < orig; ++i)
439  result += AcceptsRow (model, i) ? 1 : 0;
440  return result;
441 }
442 
virtual void setSourceModel(QAbstractItemModel *)
Definition: mergemodel.cpp:171
const_iterator GetModelForRow(int row, int *starting=0) const
Definition: mergemodel.cpp:298
virtual QModelIndex mapToSource(const QModelIndex &index) const
Definition: mergemodel.cpp:138
virtual QModelIndex mapFromSource(const QModelIndex &index) const
Definition: mergemodel.cpp:117
virtual bool AcceptsRow(QAbstractItemModel *model, int row) const
Definition: mergemodel.cpp:422
void SetHeaders(const QStringList &headers)
Definition: mergemodel.cpp:176
virtual QVariant headerData(int, Qt::Orientation, int=Qt::DisplayRole) const
Definition: mergemodel.cpp:60
virtual void handleRowsInserted(const QModelIndex &, int, int)
Definition: mergemodel.cpp:412
virtual int columnCount(const QModelIndex &=QModelIndex()) const
Definition: mergemodel.cpp:49
virtual void handleColumnsRemoved(const QModelIndex &, int, int)
Definition: mergemodel.cpp:368
void AddModel(QAbstractItemModel *model)
Definition: mergemodel.cpp:181
void RemoveModel(QAbstractItemModel *model)
Definition: mergemodel.cpp:260
virtual QModelIndex index(int, int, const QModelIndex &=QModelIndex()) const
Definition: mergemodel.cpp:85
virtual QVariant data(const QModelIndex &, int=Qt::DisplayRole) const
Definition: mergemodel.cpp:68
virtual void handleRowsAboutToBeInserted(const QModelIndex &, int, int)
Definition: mergemodel.cpp:381
virtual void handleColumnsAboutToBeRemoved(const QModelIndex &, int, int)
Definition: mergemodel.cpp:354
models_t::const_iterator const_iterator
Definition: mergemodel.h:65
models_t::iterator iterator
Definition: mergemodel.h:64
QList< QAbstractItemModel * > GetAllModels() const
Returns all models intalled into this one.
Definition: mergemodel.cpp:338
MergeModel(const QStringList &, QObject *=0)
Definition: mergemodel.cpp:38
int GetStartingRow(const_iterator it) const
Definition: mergemodel.cpp:290
virtual void handleColumnsAboutToBeInserted(const QModelIndex &, int, int)
Definition: mergemodel.cpp:347
virtual void handleColumnsInserted(const QModelIndex &, int, int)
Definition: mergemodel.cpp:361
const_iterator FindModel(const QAbstractItemModel *model) const
Definition: mergemodel.cpp:250
virtual Qt::ItemFlags flags(const QModelIndex &) const
Definition: mergemodel.cpp:79
virtual void handleDataChanged(const QModelIndex &, const QModelIndex &)
Definition: mergemodel.cpp:375
virtual QModelIndex parent(const QModelIndex &) const
Definition: mergemodel.cpp:93
virtual void handleRowsAboutToBeRemoved(const QModelIndex &, int, int)
Definition: mergemodel.cpp:390
virtual void handleRowsRemoved(const QModelIndex &, int, int)
Definition: mergemodel.cpp:417
virtual int rowCount(const QModelIndex &=QModelIndex()) const
Definition: mergemodel.cpp:99