File indexing completed on 2025-09-14 05:48:34

0001 /*
0002     This file is part of the Okteta Kasten module, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2010, 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "bytearrayviewprofilemanager.hpp"
0010 
0011 // library
0012 #include "bytearrayviewprofilelock.hpp"
0013 #include <logging.hpp>
0014 // KF
0015 #include <KConfigGroup>
0016 #include <KConfig>
0017 #include <KDirWatch>
0018 // Qt
0019 #include <QFileInfo>
0020 #include <QDir>
0021 #include <QUuid>
0022 // Std
0023 #include <utility>
0024 
0025 namespace Kasten {
0026 QStringList viewProfileFileNameFilter() { return QStringList { QStringLiteral("*.obavp"), QStringLiteral("*.olock") }; }
0027 inline QLatin1String viewProfileFileSuffix() { return QLatin1String(".obavp"); }
0028 inline QLatin1String viewProfileDirSubPath() { return QLatin1String("/okteta/viewprofiles"); }
0029 inline QLatin1String defaultViewProfileFileSubPath() { return QLatin1String("/okteta/defaultviewprofile"); }
0030 static constexpr int DefaultNoOfBytesPerLine = 16;
0031 static constexpr int DefaultNoOfBytesPerGroup = 4;
0032 static constexpr int DefaultLayoutStyle = 0;
0033 static constexpr int DefaultViewModus = 0;
0034 static constexpr int DefaultVisibleByteArrayCodings = 3;
0035 static constexpr int DefaultOffsetCoding = 0;
0036 static constexpr int DefaultValueCoding = 0;
0037 QString DefaultCharCoding() { return {}; }
0038 
0039 static QVector<ByteArrayViewProfile::Id>
0040 lockedViewProfileIds(const ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup)
0041 {
0042     QVector<ByteArrayViewProfile::Id> result;
0043 
0044     ByteArrayViewProfileFileInfoLookup::ConstIterator end =
0045         viewProfileFileInfoLookup.constEnd();
0046     for (ByteArrayViewProfileFileInfoLookup::ConstIterator it =
0047              viewProfileFileInfoLookup.constBegin();
0048          it != end;
0049          ++it) {
0050         if (it.value().isLocked()) {
0051             result.append(it.key());
0052         }
0053     }
0054 
0055     return result;
0056 }
0057 
0058 static void
0059 updateLockStatus(ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup,
0060                  const QVector<ByteArrayViewProfile::Id>& lockedViewProfileIds,
0061                  const QVector<ByteArrayViewProfile::Id>& unlockedViewProfileIds)
0062 {
0063     if (lockedViewProfileIds.isEmpty() && unlockedViewProfileIds.isEmpty()) {
0064         return;
0065     }
0066 
0067     ByteArrayViewProfileFileInfoLookup::Iterator end =
0068         viewProfileFileInfoLookup.end();
0069     for (ByteArrayViewProfileFileInfoLookup::Iterator it = viewProfileFileInfoLookup.begin();
0070          it != end;
0071          ++it) {
0072         bool isLocked;
0073 
0074         if (lockedViewProfileIds.contains(it.key())) {
0075             isLocked = true;
0076         } else if (unlockedViewProfileIds.contains(it.key())) {
0077             isLocked = false;
0078         } else {
0079             continue;
0080         }
0081 
0082         it.value().setLocked(isLocked);
0083     }
0084 }
0085 
0086 static QString
0087 defaultViewProfileFilePath()
0088 {
0089     return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + defaultViewProfileFileSubPath();
0090 }
0091 
0092 static QString
0093 viewProfileFilePath(const ByteArrayViewProfile::Id& viewProfileId)
0094 {
0095     return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
0096            + viewProfileDirSubPath() + QLatin1Char('/') + viewProfileId + viewProfileFileSuffix();
0097 }
0098 
0099 static QString
0100 viewProfileFileName(const ByteArrayViewProfile::Id& viewProfileId)
0101 {
0102     return viewProfileId + viewProfileFileSuffix();
0103 }
0104 
0105 // TODO: add global lock
0106 // TODO: make calls async
0107 // TODO: only load view profiles on demand
0108 ByteArrayViewProfileManager::ByteArrayViewProfileManager()
0109 {
0110     mViewProfileFileWatcher = new KDirWatch(this);
0111     connect(mViewProfileFileWatcher, &KDirWatch::dirty,
0112             this, &ByteArrayViewProfileManager::onViewProfilesFolderChanged);
0113 
0114     // get all folder where viewProfiles could be stored
0115     const QStringList dataFolderPaths =
0116         QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
0117 
0118     for (const QString& dataFolderPath : dataFolderPaths) {
0119         const QString viewProfileFolderPath = dataFolderPath + viewProfileDirSubPath();
0120         // watch folder for changes
0121         mViewProfileFileWatcher->addDir(viewProfileFolderPath, KDirWatch::WatchDirOnly);
0122 
0123         // read current files
0124         onViewProfilesFolderChanged(viewProfileFolderPath);
0125     }
0126 
0127     // default view profile
0128     // While there is no proper config syncing offer in the used frameworks, use a
0129     // single file with the id as content as workaround and watch for it changing
0130     auto* defaultViewProfileWatcher = new KDirWatch(this);
0131     connect(defaultViewProfileWatcher, &KDirWatch::created,
0132             this, &ByteArrayViewProfileManager::onDefaultViewProfileChanged);
0133     connect(defaultViewProfileWatcher, &KDirWatch::dirty,
0134             this, &ByteArrayViewProfileManager::onDefaultViewProfileChanged);
0135     const QString _defaultViewProfileFilePath = defaultViewProfileFilePath();
0136 
0137     defaultViewProfileWatcher->addFile(_defaultViewProfileFilePath);
0138 
0139     onDefaultViewProfileChanged(_defaultViewProfileFilePath);
0140 
0141     // report any problems with existing view profiles?
0142 }
0143 
0144 ByteArrayViewProfileManager::~ByteArrayViewProfileManager() = default;
0145 
0146 int
0147 ByteArrayViewProfileManager::viewProfilesCount() const
0148 {
0149     return mViewProfiles.size();
0150 }
0151 
0152 QVector<ByteArrayViewProfile>
0153 ByteArrayViewProfileManager::viewProfiles() const
0154 {
0155     return mViewProfiles;
0156 }
0157 
0158 ByteArrayViewProfile
0159 ByteArrayViewProfileManager::viewProfile(const ByteArrayViewProfile::Id& viewProfileId) const
0160 {
0161     ByteArrayViewProfile result;
0162 
0163     for (const ByteArrayViewProfile& viewProfile : mViewProfiles) {
0164         if (viewProfile.id() == viewProfileId) {
0165             result = viewProfile;
0166             break;
0167         }
0168     }
0169 
0170     return result;
0171 }
0172 
0173 ByteArrayViewProfile::Id
0174 ByteArrayViewProfileManager::defaultViewProfileId() const
0175 {
0176     return mDefaultViewProfileId;
0177 }
0178 
0179 ByteArrayViewProfile
0180 ByteArrayViewProfileManager::defaultViewProfile() const
0181 {
0182     return viewProfile(mDefaultViewProfileId);
0183 }
0184 
0185 bool
0186 ByteArrayViewProfileManager::isViewProfileLocked(const ByteArrayViewProfile::Id& viewProfileId) const
0187 {
0188     bool result = false;
0189 
0190     // search in all folders for the info
0191     for (const ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup : mViewProfileFileInfoLookupPerFolder) {
0192         ByteArrayViewProfileFileInfoLookup::ConstIterator it =
0193             viewProfileFileInfoLookup.find(viewProfileId);
0194         if (it != viewProfileFileInfoLookup.constEnd()) {
0195             result = it->isLocked();
0196             break;
0197         }
0198     }
0199 
0200     return result;
0201 }
0202 
0203 void ByteArrayViewProfileManager::saveViewProfiles(QVector<ByteArrayViewProfile>& viewProfiles)
0204 {
0205     // TODO: do not save if locked by someone else -> needs passing of our lock? or just registering our own and check?
0206     // create and set unique id
0207     std::for_each(viewProfiles.begin(), viewProfiles.end(), [this](ByteArrayViewProfile& viewProfile) {
0208         const ByteArrayViewProfile::Id viewProfileId = viewProfile.id();
0209 
0210         bool needsId = true;
0211         if (!viewProfileId.isEmpty()) {
0212             // already existing?
0213             auto hasViewProfileId = [&viewProfileId] (const ByteArrayViewProfile& existingProfile) {
0214                 return (viewProfileId == existingProfile.id());
0215             };
0216             if (std::any_of(mViewProfiles.constBegin(), mViewProfiles.constEnd(), hasViewProfileId)) {
0217                 needsId = false;
0218             }
0219         }
0220 
0221         // set new uuid for non-existing
0222         if (needsId) {
0223             viewProfile.setId(QUuid::createUuid().toString());
0224         }
0225 
0226         saveViewProfile(viewProfile);
0227     });
0228 }
0229 
0230 void
0231 ByteArrayViewProfileManager::removeViewProfiles(const QVector<ByteArrayViewProfile::Id>& viewProfileIds)
0232 {
0233     for (const ByteArrayViewProfile::Id& viewProfileId : viewProfileIds) {
0234         removeViewProfile(viewProfileId);
0235     }
0236 }
0237 
0238 void
0239 ByteArrayViewProfileManager::setDefaultViewProfile(const ByteArrayViewProfile::Id& viewProfileId)
0240 {
0241     QFile defaultViewProfileFile(defaultViewProfileFilePath());
0242     defaultViewProfileFile.open(QIODevice::WriteOnly);
0243 
0244     defaultViewProfileFile.write(viewProfileId.toUtf8());
0245     defaultViewProfileFile.close();
0246 }
0247 
0248 ByteArrayViewProfileLock
0249 ByteArrayViewProfileManager::createLock(const ByteArrayViewProfile::Id& viewProfileId)
0250 {
0251     const QString viewProfileFilePath = filePathOfViewProfile(viewProfileId);
0252 
0253     return ByteArrayViewProfileLock(viewProfileFilePath, viewProfileId);
0254 }
0255 
0256 /*
0257    bool
0258    ByteArrayViewProfileManager::lockViewProfile( const Kasten::ByteArrayViewProfile::Id& viewProfileId )
0259    {
0260     bool isSuccessfull;
0261 
0262     const QString viewProfileFilePath = filePathOfViewProfile( viewProfileId );
0263 
0264     // viewProfile known
0265     if( not viewProfileFilePath.isEmpty() )
0266     {
0267         const QString lockFilePath = viewProfileFileLockPath( viewProfileFilePath );
0268         KLockFile::Ptr lock = new KLockFile( lockFilePath );
0269         const KLockFile::LockResult lockResult =
0270             lock->lock(KLockFile::NoBlockFlag | KLockFile::ForceFlag);
0271         isSuccessfull = (lockResult == KLockFile::LockOK );
0272     }
0273     // if found
0274     // try to create lock file
0275     return isSuccessfull;
0276    }
0277 */
0278 // bool
0279 // ByteArrayViewProfileManager::unlockViewProfile( const Kasten::ByteArrayViewProfile::Id& viewProfileId )
0280 // {
0281 //     const QString filePath = filePathOfViewProfile( viewProfileId );
0282 //
0283 //     if( filePath.isEmpty() )
0284 //     return false;
0285 // }
0286 
0287 ByteArrayViewProfile
0288 ByteArrayViewProfileManager::loadViewProfile(const QString& absoluteFilePath) const
0289 {
0290     ByteArrayViewProfile result;
0291 
0292     KConfig configFile(absoluteFilePath, KConfig::SimpleConfig);
0293 
0294     // check version
0295     KConfigGroup formatConfigGroup = configFile.group("OBAVP");
0296     const QString formatVersion = formatConfigGroup.readEntry("Version");
0297     if (!formatVersion.startsWith(QLatin1String("1."))) {
0298         return result;
0299     }
0300 
0301     result.setId(QFileInfo(absoluteFilePath).baseName());
0302 
0303     KConfigGroup generalConfigGroup = configFile.group("General");
0304     result.setViewProfileTitle(generalConfigGroup.readEntry("Title"));
0305 
0306     KConfigGroup layoutConfigGroup = configFile.group("Layout");
0307     result.setNoOfBytesPerLine(layoutConfigGroup.readEntry("NoOfBytesPerLine", DefaultNoOfBytesPerLine));
0308     result.setNoOfGroupedBytes(layoutConfigGroup.readEntry("NoOfBytesPerGroup", DefaultNoOfBytesPerGroup));
0309     result.setLayoutStyle(layoutConfigGroup.readEntry("LayoutStyle", DefaultLayoutStyle));
0310 
0311     KConfigGroup displayConfigGroup = configFile.group("Display");
0312     result.setOffsetColumnVisible(displayConfigGroup.readEntry("OffsetColumnVisible", true));
0313     result.setOffsetCoding(displayConfigGroup.readEntry("OffsetCoding", DefaultOffsetCoding));
0314     result.setViewModus(displayConfigGroup.readEntry("ViewModus", DefaultViewModus));
0315     result.setVisibleByteArrayCodings(displayConfigGroup.readEntry("VisibleByteArrayCodings", DefaultVisibleByteArrayCodings));
0316 
0317     KConfigGroup interpretationConfigGroup = configFile.group("Interpretation");
0318 
0319     KConfigGroup valuesConfigGroup = interpretationConfigGroup.group("Values");
0320     result.setValueCoding(valuesConfigGroup.readEntry("Coding", DefaultValueCoding));
0321 
0322     KConfigGroup charsConfigGroup = interpretationConfigGroup.group("Chars");
0323     result.setCharCoding(charsConfigGroup.readEntry("Coding", DefaultCharCoding()));
0324     result.setShowsNonprinting(charsConfigGroup.readEntry("NonprintingShown", false));
0325     result.setSubstituteChar(charsConfigGroup.readEntry("SubstituteChar", ".").at(0));
0326     result.setUndefinedChar(charsConfigGroup.readEntry("UndefinedChar", "?").at(0));
0327 
0328     return result;
0329 }
0330 
0331 void
0332 ByteArrayViewProfileManager::saveViewProfile(const ByteArrayViewProfile& viewProfile) const
0333 {
0334     const QString fileName = viewProfileFilePath(viewProfile.id());
0335     KConfig configFile(fileName, KConfig::SimpleConfig);
0336 
0337     KConfigGroup formatConfigGroup = configFile.group("OBAVP");
0338     formatConfigGroup.writeEntry("Version", "1.1");
0339 
0340     KConfigGroup generalConfigGroup = configFile.group("General");
0341     generalConfigGroup.writeEntry("Title", viewProfile.viewProfileTitle());
0342 
0343     KConfigGroup layoutConfigGroup = configFile.group("Layout");
0344     layoutConfigGroup.writeEntry("NoOfBytesPerLine", viewProfile.noOfBytesPerLine());
0345     layoutConfigGroup.writeEntry("NoOfBytesPerGroup", viewProfile.noOfGroupedBytes());
0346     layoutConfigGroup.writeEntry("LayoutStyle", viewProfile.layoutStyle());
0347 
0348     KConfigGroup displayConfigGroup = configFile.group("Display");
0349     displayConfigGroup.writeEntry("OffsetColumnVisible", viewProfile.offsetColumnVisible());
0350     displayConfigGroup.writeEntry("OffsetCoding", viewProfile.offsetCoding());
0351     displayConfigGroup.writeEntry("ViewModus", viewProfile.viewModus());
0352     displayConfigGroup.writeEntry("VisibleByteArrayCodings", viewProfile.visibleByteArrayCodings());
0353 
0354     KConfigGroup interpretationConfigGroup = configFile.group("Interpretation");
0355 
0356     KConfigGroup valuesConfigGroup = interpretationConfigGroup.group("Values");
0357     valuesConfigGroup.writeEntry("Coding", viewProfile.valueCoding());
0358 
0359     KConfigGroup charsConfigGroup = interpretationConfigGroup.group("Chars");
0360     charsConfigGroup.writeEntry("Coding", viewProfile.charCodingName());
0361     charsConfigGroup.writeEntry("NonprintingShown", viewProfile.showsNonprinting());
0362     charsConfigGroup.writeEntry("SubstituteChar", QString(viewProfile.substituteChar()));
0363     charsConfigGroup.writeEntry("UndefinedChar", QString(viewProfile.undefinedChar()));
0364 }
0365 
0366 void
0367 ByteArrayViewProfileManager::removeViewProfile(const ByteArrayViewProfile::Id& viewProfileId)
0368 {
0369     const QString filePath = filePathOfViewProfile(viewProfileId);
0370     if (!filePath.isEmpty()) {
0371         QFile::remove(filePath);
0372     }
0373 }
0374 
0375 QString
0376 ByteArrayViewProfileManager::filePathOfViewProfile(const ByteArrayViewProfile::Id& viewProfileId) const
0377 {
0378     QString result;
0379 
0380     for (QHash<QString, ByteArrayViewProfileFileInfoLookup>::ConstIterator foldersIt =
0381              mViewProfileFileInfoLookupPerFolder.constBegin();
0382          foldersIt != mViewProfileFileInfoLookupPerFolder.constEnd() && result.isEmpty();
0383          ++foldersIt) {
0384         const ByteArrayViewProfileFileInfoLookup& fileInfoList = foldersIt.value();
0385         for (ByteArrayViewProfileFileInfoLookup::ConstIterator folderIt = fileInfoList.constBegin();
0386              folderIt != fileInfoList.constEnd();
0387              ++folderIt) {
0388             if (folderIt.key() == viewProfileId) {
0389                 result = foldersIt.key() + QLatin1Char('/') + viewProfileFileName(viewProfileId);
0390                 break;
0391             }
0392         }
0393     }
0394 
0395     return result;
0396 }
0397 
0398 void
0399 ByteArrayViewProfileManager::onViewProfilesFolderChanged(const QString& viewProfileFolderPath)
0400 {
0401     ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup =
0402         mViewProfileFileInfoLookupPerFolder[viewProfileFolderPath];
0403 
0404     // TODO: reparse for new, removed and changed files
0405     // assume all are removed and unlocked in the beginning
0406     QVector<ByteArrayViewProfile::Id> removedViewProfileIds = viewProfileFileInfoLookup.keys().toVector();
0407     QVector<ByteArrayViewProfile> newViewProfiles;
0408     QVector<ByteArrayViewProfile> changedViewProfiles;
0409 
0410     QVector<ByteArrayViewProfile::Id> newUnlockedViewProfileIds = lockedViewProfileIds(viewProfileFileInfoLookup);
0411     QVector<ByteArrayViewProfile::Id> newLockedViewProfileIds;
0412     // iterate all files in folder
0413     const QFileInfoList viewProfileFileInfoList =
0414         QDir(viewProfileFolderPath).entryInfoList(viewProfileFileNameFilter(), QDir::Files);
0415 
0416     for (const QFileInfo& viewProfileFileInfo : viewProfileFileInfoList) {
0417         // a lock file ?
0418         if (viewProfileFileInfo.suffix() == QLatin1String("olock")) {
0419             const ByteArrayViewProfile::Id lockedViewProfileId = viewProfileFileInfo.baseName();
0420             // if not in old locks, is a new lock
0421             if (!newUnlockedViewProfileIds.removeOne(lockedViewProfileId)) {
0422                 newLockedViewProfileIds.append(lockedViewProfileId);
0423             }
0424             continue;
0425         }
0426 
0427         // not a viewprofile file ?
0428         if (viewProfileFileInfo.suffix() != QLatin1String("obavp")) {
0429             continue;
0430         }
0431 
0432         // all other files assumed to be viewProfile files
0433         const ByteArrayViewProfile::Id viewProfileId = viewProfileFileInfo.baseName();
0434         // load file
0435         const ByteArrayViewProfile viewProfile = loadViewProfile(viewProfileFileInfo.absoluteFilePath());
0436         // loading failed? Treat as not existing
0437         if (viewProfile.id().isEmpty()) {
0438             continue;
0439         }
0440 
0441         const ByteArrayViewProfileFileInfoLookup::Iterator infoIt =
0442             viewProfileFileInfoLookup.find(viewProfileId);
0443         const bool isKnown = (infoIt != viewProfileFileInfoLookup.end());
0444         const QDateTime fileInfoLastModified = viewProfileFileInfo.lastModified();
0445         // is known?
0446         if (isKnown) {
0447             removedViewProfileIds.removeOne(viewProfileId);
0448 
0449             // check timestamp
0450             if (fileInfoLastModified == infoIt->lastModified()) {
0451                 continue;
0452             }
0453 
0454             // update timestamp
0455             infoIt->setLastModified(fileInfoLastModified);
0456         } else {
0457             ByteArrayViewProfileFileInfo info(fileInfoLastModified, false);
0458             viewProfileFileInfoLookup.insert(viewProfileId, info);
0459         }
0460 
0461         if (isKnown) {
0462             auto it = std::find_if(mViewProfiles.begin(), mViewProfiles.end(),
0463                                    [&viewProfileId](const ByteArrayViewProfile& existingProfile) {
0464                 return (existingProfile.id() == viewProfileId);
0465             });
0466             if (it != mViewProfiles.end()) {
0467                 *it = viewProfile;
0468             }
0469         } else {
0470             newViewProfiles.append(viewProfile);
0471         }
0472         changedViewProfiles.append(viewProfile);
0473     }
0474 
0475     // remove all removed viewprofiles
0476     {
0477         auto isProfileToRemove = [&removedViewProfileIds](const ByteArrayViewProfile& profile) {
0478             return removedViewProfileIds.contains(profile.id());
0479         };
0480         mViewProfiles.erase(std::remove_if(mViewProfiles.begin(), mViewProfiles.end(), isProfileToRemove),
0481                             mViewProfiles.end());
0482     }
0483 
0484     for (const ByteArrayViewProfile::Id& viewProfileId : std::as_const(removedViewProfileIds)) {
0485         viewProfileFileInfoLookup.remove(viewProfileId);
0486         if (viewProfileId == mDefaultViewProfileId) {
0487             mDefaultViewProfileId.clear();
0488         }
0489         // TODO: how to select new one?
0490     }
0491 
0492     // add new viewprofiles
0493     mViewProfiles.append(newViewProfiles);
0494     // if there was no default viewprofile before, set default to first
0495     const bool isDefaultViewProfileChanged = (mDefaultViewProfileId.isEmpty() && !mViewProfiles.isEmpty());
0496     if (isDefaultViewProfileChanged) {
0497         mDefaultViewProfileId = mViewProfiles.at(0).id();
0498     }
0499 
0500     // update lock info
0501     updateLockStatus(viewProfileFileInfoLookup, newLockedViewProfileIds, newUnlockedViewProfileIds);
0502 
0503     // signal changes
0504     if (!changedViewProfiles.isEmpty()) {
0505         Q_EMIT viewProfilesChanged(changedViewProfiles);
0506     }
0507     if (!removedViewProfileIds.isEmpty()) {
0508         Q_EMIT viewProfilesRemoved(removedViewProfileIds);
0509     }
0510 
0511     if (!newUnlockedViewProfileIds.isEmpty()) {
0512         Q_EMIT viewProfilesUnlocked(newUnlockedViewProfileIds);
0513     }
0514     if (!newLockedViewProfileIds.isEmpty()) {
0515         Q_EMIT viewProfilesLocked(newLockedViewProfileIds);
0516     }
0517     if (isDefaultViewProfileChanged) {
0518         Q_EMIT defaultViewProfileChanged(mDefaultViewProfileId);
0519     }
0520 }
0521 
0522 void ByteArrayViewProfileManager::onDefaultViewProfileChanged(const QString& path)
0523 {
0524     QFile defaultViewProfileFile(path);
0525     if (!defaultViewProfileFile.open(QIODevice::ReadOnly)) {
0526         qCDebug(LOG_KASTEN_OKTETA_GUI) << "Failed to open view profiles file " << path;
0527         return;
0528     }
0529 
0530     const QByteArray fileContent = defaultViewProfileFile.readAll();
0531     const QString viewProfileId = QString::fromUtf8(fileContent);
0532     defaultViewProfileFile.close();
0533 
0534     // no id set?
0535     if (viewProfileId.isEmpty()) {
0536         return;
0537     }
0538 
0539     // no change?
0540     if (mDefaultViewProfileId == viewProfileId) {
0541         return;
0542     }
0543 
0544     bool isExisting = false;
0545     for (const ByteArrayViewProfile& viewProfile : std::as_const(mViewProfiles)) {
0546         if (viewProfile.id() == viewProfileId) {
0547             isExisting = true;
0548             break;
0549         }
0550     }
0551 
0552     if (isExisting) {
0553         mDefaultViewProfileId = viewProfileId;
0554         Q_EMIT defaultViewProfileChanged(mDefaultViewProfileId);
0555     }
0556 }
0557 
0558 }
0559 
0560 #include "moc_bytearrayviewprofilemanager.cpp"