File indexing completed on 2024-06-23 05:48:59

0001 /*
0002     This file is part of the Okteta Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2009, 2010, 2011, 2012 Alex Richardson <alex.richardson@gmx.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "datainformationwithchildren.hpp"
0010 
0011 #include "topleveldatainformation.hpp"
0012 #include "../parsers/scriptvalueconverter.hpp"
0013 #include "../script/scripthandlerinfo.hpp"
0014 #include "../script/classes/structunionscriptclass.hpp"
0015 #include "../script/scriptlogger.hpp"
0016 // KF
0017 #include <KLocalizedString>
0018 // Qt
0019 #include <QLineEdit>
0020 // Std
0021 #include <utility>
0022 
0023 DataInformationWithChildren::DataInformationWithChildren(const QString& name,
0024                                                          const QVector<DataInformation*>& children, DataInformation* parent)
0025     : DataInformation(name, parent)
0026     , mChildren(children)
0027 {
0028     for (auto* child : std::as_const(mChildren)) {
0029         child->setParent(this);
0030     }
0031 }
0032 
0033 DataInformationWithChildren::DataInformationWithChildren(const DataInformationWithChildren& d)
0034     : DataInformation(d)
0035     , mChildren(cloneList(d.mChildren, this))
0036 {
0037 }
0038 
0039 DataInformationWithChildren::~DataInformationWithChildren()
0040 {
0041     qDeleteAll(mChildren);
0042 }
0043 
0044 DataInformation* DataInformationWithChildren::childAt(unsigned int index) const
0045 {
0046     if (index >= (unsigned) mChildren.size()) {
0047         return nullptr;
0048     }
0049     return mChildren[index];
0050 }
0051 
0052 bool DataInformationWithChildren::setData(const QVariant&, Okteta::AbstractByteArrayModel*,
0053                                           Okteta::Address, BitCount64, quint8)
0054 {
0055     Q_ASSERT_X(false, "DataInformationWithChildren::setData()", "this should never be called");
0056     return false;
0057 }
0058 
0059 QWidget* DataInformationWithChildren::createEditWidget(QWidget* parent) const
0060 {
0061     Q_ASSERT(false);
0062     auto* editWidget = new QLineEdit(parent);
0063     editWidget->setClearButtonEnabled(true);
0064     return editWidget;
0065 }
0066 
0067 QVariant DataInformationWithChildren::dataFromWidget(const QWidget* w) const
0068 {
0069     Q_UNUSED(w);
0070     Q_ASSERT(false);
0071     return {};
0072 }
0073 
0074 void DataInformationWithChildren::setWidgetData(QWidget* w) const
0075 {
0076     Q_ASSERT(false);
0077     Q_UNUSED(w)
0078 }
0079 
0080 BitCount32 DataInformationWithChildren::size() const
0081 {
0082     BitCount32 size = 0;
0083     for (unsigned int i = 0; i < childCount(); ++i) {
0084         size += childAt(i)->size();
0085     }
0086 
0087     return size;
0088 }
0089 
0090 void DataInformationWithChildren::resetValidationState()
0091 {
0092     DataInformation::resetValidationState();
0093     for (auto* child : std::as_const(mChildren)) {
0094         child->resetValidationState();
0095     }
0096 }
0097 
0098 void DataInformationWithChildren::calculateValidationState()
0099 {
0100     if (childCount() > 0) {
0101         bool hasValidatedChildren = false;
0102         bool allChildrenValid = true;
0103         for (uint i = 0; i < childCount(); ++i) {
0104             DataInformation* child = childAt(i);
0105             DataInformationWithChildren* childWithChildren = child->asDataInformationWithChildren();
0106             if (childWithChildren) {
0107                 childWithChildren->calculateValidationState();
0108             }
0109             // first make sure the child item validation state has been set
0110             if (child->hasBeenValidated()) {
0111                 hasValidatedChildren = true;
0112                 if (!child->validationSuccessful()) {
0113                     allChildrenValid = false;
0114                     break; // one is invalid -> whole structure is invalid
0115                 }
0116             }
0117         }
0118 
0119         if (hasValidatedChildren) {
0120             mValidationSuccessful = allChildrenValid;
0121         }
0122     }
0123 }
0124 
0125 void DataInformationWithChildren::setChildren(const QVector<DataInformation*>& newChildren)
0126 {
0127     // since we are replacing the children and the first few may be different emit
0128     // change to length zero and then to new length so that model gets updated correctly
0129     uint numChildren = childCount();
0130     topLevelDataInformation()->_childCountAboutToChange(this, numChildren, 0);
0131     qDeleteAll(mChildren);
0132     mChildren.clear();
0133     topLevelDataInformation()->_childCountChanged(this, numChildren, 0);
0134 
0135     const uint count = newChildren.size();
0136     topLevelDataInformation()->_childCountAboutToChange(this, 0, count);
0137     mChildren = newChildren;
0138     for (auto* child : std::as_const(mChildren)) {
0139         child->setParent(this);
0140     }
0141 
0142     topLevelDataInformation()->_childCountChanged(this, 0, count);
0143 }
0144 
0145 void DataInformationWithChildren::setChildren(const QScriptValue& children)
0146 {
0147     if (children.isNull() || children.isUndefined()) {
0148         logError() << "attempting to set children to null/undefined.";
0149         return;
0150     }
0151     QVector<DataInformation*> convertedVals =
0152         ScriptValueConverter::convertValues(children, topLevelDataInformation()->logger());
0153     setChildren(convertedVals);
0154 }
0155 
0156 int DataInformationWithChildren::indexOf(const DataInformation* const data) const
0157 {
0158     const int size = mChildren.size();
0159     for (int i = 0; i < size; ++i) {
0160         if (mChildren.at(i) == data) {
0161             return i;
0162         }
0163     }
0164 
0165     Q_ASSERT(false); // should never reach this
0166     return -1;
0167 }
0168 
0169 QVariant DataInformationWithChildren::childData(int row, int column, int role) const
0170 {
0171     Q_ASSERT(row >= 0 && row < mChildren.size());
0172     // just delegate to child
0173     return mChildren.at(row)->data(column, role);
0174 }
0175 
0176 void DataInformationWithChildren::appendChild(DataInformation* newChild, bool emitSignal)
0177 {
0178     if (emitSignal) {
0179         topLevelDataInformation()->_childCountAboutToChange(this, mChildren.size(), mChildren.size() + 1);
0180     }
0181     newChild->setParent(this);
0182     mChildren.append(newChild);
0183     if (emitSignal) {
0184         topLevelDataInformation()->_childCountChanged(this, mChildren.size(), mChildren.size() + 1);
0185     }
0186 }
0187 
0188 void DataInformationWithChildren::appendChildren(const QVector<DataInformation*>& newChildren, bool emitSignal)
0189 {
0190     if (newChildren.isEmpty()) {
0191         return;
0192     }
0193     const int added = newChildren.size();
0194     if (emitSignal) {
0195         topLevelDataInformation()->_childCountAboutToChange(this, mChildren.size(), mChildren.size() + added);
0196     }
0197     for (auto* child : newChildren) {
0198         child->setParent(this);
0199     }
0200 
0201     mChildren << newChildren;
0202     if (emitSignal) {
0203         topLevelDataInformation()->_childCountChanged(this, mChildren.size(), mChildren.size() + added);
0204     }
0205 }
0206 
0207 bool DataInformationWithChildren::replaceChildAt(unsigned int index, DataInformation* newChild)
0208 {
0209     Q_ASSERT(index < uint(mChildren.size()));
0210     Q_CHECK_PTR(newChild);
0211     if (index >= uint(mChildren.size())) {
0212         return false;
0213     }
0214 
0215     delete mChildren.at(index);
0216     mChildren[index] = newChild;
0217     return true;
0218 }
0219 
0220 QScriptClass* DataInformationWithChildren::scriptClass(ScriptHandlerInfo* handlerInfo) const
0221 {
0222     return handlerInfo->mStructUnionClass.get();
0223 }
0224 
0225 QString DataInformationWithChildren::tooltipString() const
0226 {
0227     QString valueStr = mWasAbleToRead ? valueString() : eofReachedData(Qt::DisplayRole).toString();
0228     QString validationMsg;
0229     if (mHasBeenValidated && !mValidationSuccessful) {
0230         validationMsg = validationError();
0231         if (validationMsg.isEmpty()) {
0232             validationMsg = i18nc("not all values in this structure"
0233                                   " are as they should be", "Validation failed.");
0234         } else {
0235             validationMsg = i18nc("not all values in this structure"
0236                                   " are as they should be", "Validation failed: \"%1\"", validationMsg);
0237         }
0238     }
0239 
0240     return DataInformation::tooltipString(name(), valueStr, typeName(), sizeString(), childCount(),
0241                                           validationMsg);
0242 }
0243 
0244 QVector<DataInformation*> DataInformationWithChildren::cloneList(const QVector<DataInformation*>& other,
0245                                                                  DataInformation* parent)
0246 {
0247     int count = other.size();
0248     QVector<DataInformation*> ret;
0249     ret.reserve(count);
0250     for (int i = 0; i < count; ++i) {
0251         DataInformation* dat = other.at(i);
0252         DataInformation* newChild = dat->clone();
0253         newChild->setParent(parent);
0254         ret.append(newChild);
0255     }
0256 
0257     return ret;
0258 }
0259 
0260 unsigned int DataInformationWithChildren::childCount() const
0261 {
0262     return mChildren.size();
0263 }
0264 
0265 bool DataInformationWithChildren::isDataInformationWithChildren() const
0266 {
0267     return true;
0268 }