File indexing completed on 2025-01-05 05:23:37

0001 /*
0002     This file is part of the Okteta Kasten module, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2009, 2023 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 "replacetool.hpp"
0010 
0011 // controller
0012 #include "replacejob.hpp"
0013 // libconfigentries
0014 #include <casesensitivityconfigentry.hpp>
0015 // libbytearraysearch
0016 #include <bytearraysearchutils.hpp>
0017 // Okteta Kasten gui
0018 #include <Kasten/Okteta/ByteArrayView>
0019 // Okteta Kasten core
0020 #include <Kasten/Okteta/ByteArrayDocument>
0021 // Okteta core
0022 #include <Okteta/AbstractByteArrayModel>
0023 // KF
0024 #include <KConfigGroup>
0025 #include <KSharedConfig>
0026 #include <KLocalizedString>
0027 
0028 
0029 namespace Kasten {
0030 
0031 ReplaceTool::ReplaceTool()
0032 {
0033     setObjectName(QStringLiteral("Replace"));
0034 
0035     const KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId);
0036     mCaseSensitivity = configGroup.readEntry(CaseSensitivityConfigKey, DefaultCaseSensitivity);
0037     mDoPrompt = configGroup.readEntry(PromptConfigKey, DefaultDoPrompt);
0038 }
0039 
0040 ReplaceTool::~ReplaceTool() = default;
0041 
0042 bool ReplaceTool::isApplyable() const
0043 {
0044     return (mByteArrayView && mByteArrayModel && !mByteArrayView->isReadOnly()) && !mReplaceJob;
0045 //     const int newPosition = finalTargetOffset();
0046 
0047 //     return ( mByteArrayView && mByteArrayModel
0048 //              && (0 <= newPosition) && (newPosition <= mByteArrayModel->size()) );
0049 }
0050 
0051 QString ReplaceTool::title() const { return i18nc("@title", "Replace"); }
0052 
0053 bool ReplaceTool::hasSelectedData()   const { return mByteArrayView->hasSelectedData(); }
0054 QString ReplaceTool::charCodingName() const { return mByteArrayView->charCodingName(); }
0055 
0056 void ReplaceTool::setTargetModel(AbstractModel* model)
0057 {
0058     const bool oldIsApplyable = isApplyable();
0059 
0060     if (mByteArrayView) {
0061         mByteArrayView->disconnect(this);
0062     }
0063     if (mByteArrayModel) {
0064         mByteArrayModel->disconnect(this);
0065     }
0066 
0067     mByteArrayView = model ? model->findBaseModel<ByteArrayView*>() : nullptr;
0068 
0069     ByteArrayDocument* document =
0070         mByteArrayView ? qobject_cast<ByteArrayDocument*>(mByteArrayView->baseModel()) : nullptr;
0071     mByteArrayModel = document ? document->content() : nullptr;
0072 
0073     if (mByteArrayView && mByteArrayModel) {
0074         connect(mByteArrayView, &ByteArrayView::readOnlyChanged, this, &ReplaceTool::onReadOnlyChanged);
0075         // TODO: update isApplyable on cursor movement and size changes
0076     }
0077 
0078     const bool newIsApplyable = isApplyable();
0079     if (oldIsApplyable != newIsApplyable) {
0080         Q_EMIT isApplyableChanged(newIsApplyable);
0081     }
0082 }
0083 
0084 void ReplaceTool::setUserQueryAgent(QObject* userQueryAgent)
0085 {
0086     mUserQueryAgent = userQueryAgent;
0087 }
0088 
0089 void ReplaceTool::setSearchData(const QByteArray& searchData)
0090 {
0091 //     const bool oldIsApplyable = isApplyable();
0092 
0093     mSearchData = searchData;
0094 
0095 //     const bool newIsApplyable = isApplyable();
0096 //     if( oldIsApplyable != newIsApplyable )
0097 //         Q_EMIT isApplyableChanged( newIsApplyable );
0098 }
0099 
0100 void ReplaceTool::setReplaceData(const QByteArray& replaceData)
0101 {
0102 //     const bool oldIsApplyable = isApplyable();
0103 
0104     mReplaceData = replaceData;
0105 
0106 //     const bool newIsApplyable = isApplyable();
0107 //     if( oldIsApplyable != newIsApplyable )
0108 //         Q_EMIT isApplyableChanged( newIsApplyable );
0109 }
0110 
0111 void ReplaceTool::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
0112 {
0113     if (mCaseSensitivity == caseSensitivity) {
0114         return;
0115     }
0116 
0117 //     const bool oldIsApplyable = isApplyable();
0118 
0119     mCaseSensitivity = caseSensitivity;
0120 
0121     KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId);
0122     configGroup.writeEntry(CaseSensitivityConfigKey, mCaseSensitivity);
0123 
0124 //     const bool newIsApplyable = isApplyable();
0125 //     if( oldIsApplyable != newIsApplyable )
0126 //         Q_EMIT isApplyableChanged( newIsApplyable );
0127 }
0128 
0129 void ReplaceTool::setDoPrompt(bool doPrompt)
0130 {
0131     if (mDoPrompt == doPrompt) {
0132         return;
0133     }
0134 
0135     mDoPrompt = doPrompt;
0136 
0137     KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId);
0138     configGroup.writeEntry(PromptConfigKey, mDoPrompt);
0139 }
0140 
0141 void ReplaceTool::replace(FindDirection direction, bool fromCursor, bool inSelection)
0142 {
0143     Okteta::Address replaceRangeStartIndex;
0144     Okteta::Address replaceRangeEndIndex;
0145 
0146     if (!ByteArraySearchUtils::getSearchIndexes(&replaceRangeStartIndex, &replaceRangeEndIndex,
0147                                                 mByteArrayModel,
0148                                                 mByteArrayView->selection(),
0149                                                 mByteArrayView->cursorPosition(),
0150                                                 mSearchData,
0151                                                 direction,
0152                                                 fromCursor, inSelection)) {
0153         // no search doable, so skip any search and finish now
0154         mReplaceJob = nullptr;
0155         Q_EMIT finished(false, 0);
0156         return;
0157     }
0158 
0159     mReplaceJob = new ReplaceJob(mByteArrayView, mByteArrayModel, mUserQueryAgent, this);
0160     mReplaceJob->setSearchData(mSearchData);
0161     mReplaceJob->setReplaceData(mReplaceData);
0162     mReplaceJob->setCaseSensitivity(mCaseSensitivity);
0163     mReplaceJob->setDoPrompt(mDoPrompt);
0164     mReplaceJob->setRange(replaceRangeStartIndex, replaceRangeEndIndex, direction);
0165     connect(mReplaceJob, &ReplaceJob::finished, this, &ReplaceTool::onJobFinished);
0166 
0167     Q_EMIT isApplyableChanged(isApplyable());
0168 
0169     mReplaceJob->start();
0170 }
0171 
0172 void ReplaceTool::onReadOnlyChanged(bool isReadOnly)
0173 {
0174     Q_UNUSED(isReadOnly)
0175 
0176     // TODO: find out if isApplyable really changed, perhaps by caching the readonly state?
0177     Q_EMIT isApplyableChanged(isApplyable());
0178 }
0179 
0180 void ReplaceTool::onJobFinished(bool previousFound, int noOfReplacements)
0181 {
0182     delete mReplaceJob;
0183     mReplaceJob = nullptr;
0184 
0185     Q_EMIT finished(previousFound, noOfReplacements);
0186     Q_EMIT isApplyableChanged(isApplyable());
0187 }
0188 
0189 }
0190 
0191 #include "moc_replacetool.cpp"