/* Copyright 2006-2026 The QElectroTech Team This file is part of QElectroTech. QElectroTech is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. QElectroTech is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with QElectroTech. If not, see . */ #include "elementcollectionitem.h" #include #include /** @brief ElementCollectionItem::ElementCollectionItem Constructor */ ElementCollectionItem::ElementCollectionItem() {} /** @brief ElementCollectionItem::clearData Reset the data */ void ElementCollectionItem::clearData() { setText(QString()); setToolTip(QString()); setIcon(QIcon()); setData(QString()); } /** @brief ElementCollectionItem::lastItemForPath Return the last existing item in this ElementCollectionItem hierarchy according to the given path. Next_item is the first non existing item in this hierarchy according to the given path. @param path : The path to find last item. The path must be in form : path/otherPath/.../.../myElement.elmt. @param no_found_path : The first item that not exist in this hierarchy @return : The last item that exist in this hierarchy, or nullptr can't find (an error was occurred, or path already exist) */ ElementCollectionItem *ElementCollectionItem::lastItemForPath( const QString &path, QString &no_found_path) { QStringList str_list = path.split("/"); if (str_list.isEmpty()) return nullptr; ElementCollectionItem *return_eci = this; foreach (QString str, str_list) { ElementCollectionItem *eci = return_eci->childWithCollectionName(str); if (!eci) { no_found_path = str; return return_eci; } else return_eci = eci; } return nullptr; } /** @brief ElementCollectionItem::childWithCollectionName Return the child with the collection name name, else return nullptr @param name @return */ ElementCollectionItem *ElementCollectionItem::childWithCollectionName( const QString& name) const { rowCount(); foreach (QStandardItem *qsi, directChilds()) { ElementCollectionItem *eci = static_cast(qsi); if (eci->name() == name) return eci; } return nullptr; } /** @brief ElementCollectionItem::directChilds Return the direct child of this item @return */ QList ElementCollectionItem::directChilds() const { QList item_list; for (int i=0 ; i child; //The item to insert is an element/template we search from element child if (name.endsWith(".elmt") || name.endsWith(".qetmak")) { child = elementsDirectChild(); //There isn't element, we insert at last position if (child.isEmpty()) return rowCount(); } //The item is a directory, we search from directory child else { child = directoriesDirectChild(); //There isn't directory, we insert at first position if(child.isEmpty()) return 0; } foreach (ElementCollectionItem *eci, child) if (eci->name() > name) return model()->indexFromItem(eci).row(); return (model()->indexFromItem(child.last()).row() + 1); } /** @brief ElementCollectionItem::itemAtPath @param path @return the item at path or nullptr if doesn't exist */ ElementCollectionItem *ElementCollectionItem::itemAtPath(const QString &path) { QStringList str_list = path.split("/"); if (str_list.isEmpty()) return nullptr; ElementCollectionItem *match_eci = this; foreach (QString str, str_list) { ElementCollectionItem *eci = match_eci->childWithCollectionName(str); if (!eci) return nullptr; else match_eci = eci; } return match_eci; } /** @brief ElementCollectionItem::elementsDirectChild @return The direct element child of this item */ QList ElementCollectionItem::elementsDirectChild() const { QList element_child; foreach (QStandardItem *qsi, directChilds()) { ElementCollectionItem *eci = static_cast(qsi); if (eci->isElement()) element_child.append(eci); } return element_child; } /** @brief ElementCollectionItem::directoriesDirectChild @return the direct directory child of this item */ QList ElementCollectionItem::directoriesDirectChild() const { QList dir_child; foreach (QStandardItem *qsi, directChilds()) { ElementCollectionItem *eci = static_cast(qsi); if (eci->isDir()) dir_child.append(eci); } return dir_child; } /** @brief ElementCollectionItem::elementsChild @return Every elements child (direct and indirect) of this item */ QList ElementCollectionItem::elementsChild() const { QList list = elementsDirectChild(); foreach (ElementCollectionItem *eci, directoriesChild()) list.append(eci->elementsDirectChild()); return list; } /** @brief ElementCollectionItem::directoriesChild @return Every directories child (direct and indirect) of this item */ QList ElementCollectionItem::directoriesChild() const { QList list = directoriesDirectChild(); QList child_list; foreach (ElementCollectionItem *eci, list) { child_list.append(eci->directoriesChild()); } list.append(child_list); return list; } /** @brief ElementCollectionItem::items @return every childs of this item (direct and indirect childs) */ QList ElementCollectionItem::items() const { QList list; for (int i=0 ; i(child(i)); list.append(eci); list.append(eci->items()); } return list; } /** @brief onGuiThread @return true when called from the thread the application lives in */ static bool onGuiThread() { return QThread::currentThread() == QCoreApplication::instance()->thread(); } /** @brief ElementCollectionItem::setData ElementsCollectionModel::loadCollections() runs setUpData() for every item on worker threads (QtConcurrent::map), while the items are already in the model. QStandardItem::setData() updates the model and emits its dataChanged() signal, which is not safe from a worker thread. So a value set from a worker thread is kept on the item, and the model applies it on the GUI thread with applyDeferredData() once every item is set up. setText(), setFlags(), setToolTip() and setIcon() all end up here. @param value @param role */ void ElementCollectionItem::setData(const QVariant &value, int role) { if (role == Qt::EditRole) role = Qt::DisplayRole; if (onGuiThread()) QStandardItem::setData(value, role); else m_deferred_data.insert(role, value); } /** @brief ElementCollectionItem::data On a worker thread, a value set by setData() but not applied yet is returned, so setUpData() reads back what it has just set (localName() tests text() for example). @param role @return */ QVariant ElementCollectionItem::data(int role) const { if (role == Qt::EditRole) role = Qt::DisplayRole; if (!onGuiThread()) { const auto it = m_deferred_data.constFind(role); if (it != m_deferred_data.constEnd()) return it.value(); } return QStandardItem::data(role); } /** @brief ElementCollectionItem::applyDeferredData Apply the values set from a worker thread, see setData(). Must be called on the GUI thread, after the worker is done. */ void ElementCollectionItem::applyDeferredData() { for (auto it = m_deferred_data.constBegin() ; it != m_deferred_data.constEnd() ; ++it) QStandardItem::setData(it.value(), it.key()); m_deferred_data.clear(); } void setUpData(ElementCollectionItem *eci) { eci->setUpData(); }