LCOV - code coverage report
Current view: top level - src/models - ListModel.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 95.3 % 169 161
Test Date: 2026-04-19 00:35:54 Functions: 100.0 % 28 28

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

Generated by: LCOV version 2.0-1