LCOV - code coverage report
Current view: top level - src/models - ListModel.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 34.3 % 169 58
Test Date: 2026-03-23 10:19:47 Functions: 39.3 % 28 11

            Line data    Source code
       1              : /*
       2              :  * Author: Christophe Dumez <dchris@gmail.com>
       3              :  * License: Public domain (No attribution required)
       4              :  * Website: http://cdumez.blogspot.com/
       5              :  * Version: 1.0
       6              :  */
       7              : 
       8              : #include "ListModel.h"
       9              : 
      10              : #include "../utilities/FangLogging.h"
      11              :  
      12           70 : ListModel::ListModel(ListItem* prototype, QObject *parent) :
      13           70 :     QAbstractListModel(parent), m_prototype(prototype), _selected(nullptr)
      14              : {
      15              :     // Populate our _roleNames reverse lookup map.
      16           70 :     QHash<int, QByteArray> roleNames = m_prototype->roleNames();
      17         1470 :     for (int roleIndex : roleNames.keys()) {
      18         1400 :         _roleNames[ roleNames[roleIndex] ] = roleIndex;
      19           70 :     }
      20           70 : }
      21              :  
      22          630 : int ListModel::rowCount(const QModelIndex &parent) const
      23              : {
      24              :     Q_UNUSED(parent);
      25          630 :     return m_list.size();
      26              : }
      27              : 
      28            0 : QVariant ListModel::data(const QModelIndex &index, int role) const
      29              : {
      30            0 :     if(index.row() < 0 || index.row() >= m_list.size()) {
      31            0 :         return QVariant();
      32              :     }
      33              : 
      34            0 :     int indexRow = index.row();
      35            0 :     int maxRows = rowCount();
      36            0 :     return m_list.at(indexRow)->data(role);
      37              : }
      38              : 
      39            0 : QVariant ListModel::dataByField(int row, const QString &field_name) const
      40              : {
      41            0 :     if(row < 0 || row >= m_list.size()) {
      42            0 :       return QVariant();
      43              :     }
      44              : 
      45            0 :     int roleIndex = roleNameToRole(field_name);
      46            0 :     if (roleIndex < 0) {
      47            0 :         qCCritical(logModel) << "ListModel::dataByField: Invalid field name" << field_name;
      48            0 :         return QVariant();
      49              :     }
      50              : 
      51            0 :     return m_list.at(row)->data(roleIndex);
      52              : }
      53              : 
      54            0 : bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
      55              : {
      56            0 :     if(index.row() < 0 || index.row() >= m_list.size()) {
      57            0 :       return false;
      58              :     }
      59              :     
      60            0 :     return m_list.at(index.row())->setData(value, role);
      61              : }
      62              : 
      63            0 : void ListModel::setData(int row, const QString &field_name, QVariant new_value)
      64              : {
      65            0 :     if (row < 0 || row >= m_list.size()) {
      66            0 :       return;
      67              :     }
      68              :     
      69            0 :     QHash<int, QByteArray> roleNames = m_list.at(row)->roleNames();
      70            0 :     for (int roleIndex : roleNames.keys()) {
      71            0 :         if (field_name == roleNames[roleIndex]) {
      72            0 :              m_list.at(row)->setData(new_value, roleIndex);
      73              : 
      74            0 :             return;
      75              :         }
      76            0 :     }
      77              : 
      78            0 :     int roleIndex = roleNameToRole(field_name);
      79            0 :     if (roleIndex < 0) {
      80            0 :         qCCritical(logModel) << "ListModel::setData: Invalid field name" << field_name;
      81            0 :         return;
      82              :     }
      83            0 :     m_list.at(row)->setData(new_value, roleIndex);
      84            0 : }
      85              : 
      86            0 : Qt::ItemFlags ListModel::flags(const QModelIndex &index) const
      87              : {
      88            0 :     if(index.row() < 0 || index.row() >= m_list.size()) {
      89            0 :       return Qt::NoItemFlags;
      90              :     }
      91              :     
      92            0 :     return m_list.at(index.row())->flags();
      93              : }
      94              : 
      95            0 : void ListModel::move(int from, int to, int count)
      96              : {
      97              :     // From: https://qt.gitorious.org/qt-labs/qml-object-model/source/7c2207640a65dc59a420ebf71a45e38350840313:qobjectlistmodel.cpp
      98              :     // Move count items one at a time to match QML ListModel behavior.
      99            0 :     for (int i = 0; i < count; ++i) {
     100            0 :         int src = (to > from) ? from : from + i;
     101            0 :         int dst = (to > from) ? to + i : to + i;
     102            0 :         if (src < 0 || src >= m_list.size() || dst < 0 || dst >= m_list.size() || src == dst) {
     103            0 :             continue;
     104              :         }
     105              : 
     106            0 :         int dest = (dst > src) ? dst + 1 : dst;
     107            0 :         if (!beginMoveRows(QModelIndex(), src, src, QModelIndex(), dest)) {
     108            0 :             continue;
     109              :         }
     110              : 
     111            0 :         m_list.move(src, dst);
     112            0 :         endMoveRows();
     113              :     }
     114            0 : }
     115              : 
     116            0 : QVariantMap ListModel::get(int row) const
     117              : {
     118            0 :     QVariantMap map;
     119            0 :     if (row < 0 || row >= m_list.size()) {
     120            0 :         return map;
     121              :     }
     122              : 
     123            0 :     const ListItem* item = m_list.at(row);
     124            0 :     QHash<int, QByteArray> roles = m_prototype->roleNames();
     125            0 :     for (auto it = roles.constBegin(); it != roles.constEnd(); ++it) {
     126            0 :         map[QString::fromUtf8(it.value())] = item->data(it.key());
     127              :     }
     128            0 :     return map;
     129            0 : }
     130              : 
     131            0 : void ListModel::setProperty(int row, const QString &name, QVariant value)
     132              : {
     133            0 :     setData(row, name, value);
     134            0 : }
     135              : 
     136            0 : void ListModel::remove(int row, int count)
     137              : {
     138            0 :     removeRows(row, count);
     139            0 : }
     140              :  
     141          132 : ListModel::~ListModel() {
     142           70 :   delete m_prototype;
     143           70 :   clear();
     144          132 : }
     145              :  
     146           54 : void ListModel::appendRow(ListItem *item)
     147              : {
     148           54 :   appendRows(QList<ListItem*>() << item);
     149           54 : }
     150              :  
     151           54 : void ListModel::appendRows(const QList<ListItem *> &items)
     152              : {
     153           54 :   beginInsertRows(QModelIndex(), rowCount(), rowCount()+items.size()-1);
     154          108 :   for (ListItem *item : items) {
     155           54 :     connect(item, &ListItem::dataChanged, this, &ListModel::handleItemChange);
     156           54 :     m_list.append(item);
     157              :   }
     158           54 :   endInsertRows();
     159              :   
     160          108 :   for (ListItem* item : items) {
     161           54 :       emit added(item);
     162              :   }
     163              :   
     164           54 :   emit countChanged(count());
     165           54 : }
     166              :  
     167            0 : void ListModel::insertRow(int row, ListItem *item)
     168              : {
     169            0 :   beginInsertRows(QModelIndex(), row, row);
     170            0 :   connect(item, &ListItem::dataChanged, this, &ListModel::handleItemChange);
     171            0 :   m_list.insert(row, item);
     172            0 :   endInsertRows();
     173              :   
     174            0 :   emit added(item);
     175              :   
     176            0 :   emit countChanged(count());
     177            0 : }
     178              :  
     179           92 : void ListModel::handleItemChange()
     180              : {
     181           92 :   ListItem* item = static_cast<ListItem*>(sender());
     182           92 :   QModelIndex index = indexFromItem(item);
     183           92 :   if(index.isValid()) {
     184           88 :     emit dataChanged(index, index);
     185              :   }
     186           92 : }
     187              :  
     188            0 : ListItem * ListModel::find(const QString &id) const
     189              : {
     190            0 :   for (ListItem* item : m_list) {
     191            0 :     if(item->id() == id) return item;
     192              :   }
     193            0 :   return 0;
     194              : }
     195              :  
     196           96 : QModelIndex ListModel::indexFromItem(const ListItem *item) const
     197              : {
     198           96 :   if (!item) {
     199            0 :       qCCritical(logModel) << "ListModel::indexFromItem: item is null";
     200            0 :       return QModelIndex();
     201              :   }
     202          219 :   for(int row=0; row<m_list.size(); ++row) {
     203          215 :       if(m_list.at(row) == item) return index(row);
     204              :   }
     205            4 :   return QModelIndex();
     206              : }
     207              :  
     208           70 : void ListModel::clear()
     209              : {
     210          120 :     for (ListItem* item : m_list) {
     211           50 :         emit removed(item);
     212              :     }
     213              :     
     214           70 :     m_list.clear();
     215              :     
     216           70 :     emit countChanged(count());
     217           70 : }
     218              : 
     219            0 : void ListModel::setSelected(ListItem *selected)
     220              : {
     221            0 :     _selected = selected;
     222            0 :     emit selectedChanged(_selected);
     223            0 :     emit selectedIndexChanged(selectedIndex());
     224            0 : }
     225              : 
     226            0 : int ListModel::selectedIndex()
     227              : {
     228            0 :     return m_list.indexOf(_selected);
     229              : }
     230              : 
     231            0 : void ListModel::setSelectedIndex(int selectedIndex)
     232              : {
     233            0 :     setSelected(m_list.at(selectedIndex));
     234            0 : }
     235              : 
     236            0 : int ListModel::roleNameToRole(const QString &field_name) const
     237              : {
     238            0 :     return _roleNames.contains(field_name) ? _roleNames[field_name] : -1;
     239              : }
     240              :  
     241            4 : bool ListModel::removeRow(int row, const QModelIndex &parent)
     242              : {
     243              :   Q_UNUSED(parent);
     244            4 :   ListItem* toRemove = nullptr;
     245            4 :   if(row < 0 || row >= m_list.size()) return false;
     246            4 :   beginRemoveRows(QModelIndex(), row, row);
     247            4 :   toRemove = m_list.takeAt(row);
     248            4 :   endRemoveRows();
     249              :   
     250            4 :   emit removed(toRemove);
     251            4 :   emit countChanged(count());
     252              :   
     253            4 :   return true;
     254              : }
     255              :  
     256            0 : bool ListModel::removeRows(int row, int count, const QModelIndex &parent)
     257              : {
     258              :   Q_UNUSED(parent);
     259            0 :   QList<ListItem*> toRemove;
     260              :   
     261            0 :   if(row < 0 || (row+count) >= m_list.size()) return false;
     262            0 :   beginRemoveRows(QModelIndex(), row, row+count-1);
     263            0 :   for(int i=0; i<count; ++i) {
     264            0 :       toRemove.append(m_list.takeAt(row));
     265              :   }
     266            0 :   endRemoveRows();
     267              :   
     268            0 :   for (ListItem* item : toRemove) {
     269            0 :       emit removed(item);
     270              :   }
     271              :   
     272            0 :   emit countChanged(this->count());
     273              :   
     274            0 :   return true;
     275            0 : }
     276              : 
     277            4 : bool ListModel::removeItem(const ListItem *item)
     278              : {
     279            4 :     QModelIndex index = indexFromItem(item);
     280            4 :     int row = index.row();
     281              :     
     282            8 :     qCDebug(logModel) << "Remove item at: " << row;
     283              :     
     284            4 :     if (row == -1) {
     285            0 :         return false; // Not found.
     286              :     }
     287              :     
     288            4 :     return removeRow(row);
     289              : }
     290              :  
     291            0 : ListItem * ListModel::takeRow(int row)
     292              : {
     293            0 :   beginRemoveRows(QModelIndex(), row, row);
     294            0 :   ListItem* item = m_list.takeAt(row);
     295            0 :   endRemoveRows();
     296              :   
     297            0 :   emit removed(item);
     298            0 :   emit countChanged(count());
     299              :   
     300            0 :   return item;
     301              : }
        

Generated by: LCOV version 2.0-1