1 /*
2     This file is part of the Okteta Kasten module, made within the KDE community.
3 
4     SPDX-FileCopyrightText: 2009 Friedrich W. H. Kossebau <kossebau@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 
9 #include "replacetool.hpp"
10 
11 // controller
12 #include "replacejob.hpp"
13 // Okteta Kasten gui
14 #include <Kasten/Okteta/ByteArrayView>
15 // Okteta Kasten core
16 #include <Kasten/Okteta/ByteArrayDocument>
17 // Okteta core
18 #include <Okteta/AbstractByteArrayModel>
19 // KF
20 #include <KLocalizedString>
21 
22 namespace Kasten {
23 
ReplaceTool()24 ReplaceTool::ReplaceTool()
25 {
26     setObjectName(QStringLiteral("Replace"));
27 }
28 
29 ReplaceTool::~ReplaceTool() = default;
30 
isApplyable() const31 bool ReplaceTool::isApplyable() const
32 {
33     return (mByteArrayView && mByteArrayModel && !mByteArrayView->isReadOnly()) && !mReplaceJob;
34 //     const int newPosition = finalTargetOffset();
35 
36 //     return ( mByteArrayView && mByteArrayModel
37 //              && (0 <= newPosition) && (newPosition <= mByteArrayModel->size()) );
38 }
39 
title() const40 QString ReplaceTool::title() const { return i18nc("@title", "Replace"); }
41 
hasSelectedData() const42 bool ReplaceTool::hasSelectedData()   const { return mByteArrayView->hasSelectedData(); }
charCodingName() const43 QString ReplaceTool::charCodingName() const { return mByteArrayView->charCodingName(); }
44 
setTargetModel(AbstractModel * model)45 void ReplaceTool::setTargetModel(AbstractModel* model)
46 {
47     const bool oldIsApplyable = isApplyable();
48 
49     if (mByteArrayView) {
50         mByteArrayView->disconnect(this);
51     }
52     if (mByteArrayModel) {
53         mByteArrayModel->disconnect(this);
54     }
55 
56     mByteArrayView = model ? model->findBaseModel<ByteArrayView*>() : nullptr;
57 
58     ByteArrayDocument* document =
59         mByteArrayView ? qobject_cast<ByteArrayDocument*>(mByteArrayView->baseModel()) : nullptr;
60     mByteArrayModel = document ? document->content() : nullptr;
61 
62     if (mByteArrayView && mByteArrayModel) {
63         connect(mByteArrayView, &ByteArrayView::readOnlyChanged, this, &ReplaceTool::onReadOnlyChanged);
64         // TODO: update isApplyable on cursor movement and size changes
65     }
66 
67     const bool newIsApplyable = isApplyable();
68     if (oldIsApplyable != newIsApplyable) {
69         emit isApplyableChanged(newIsApplyable);
70     }
71 }
72 
setUserQueryAgent(QObject * userQueryAgent)73 void ReplaceTool::setUserQueryAgent(QObject* userQueryAgent)
74 {
75     mUserQueryAgent = userQueryAgent;
76 }
77 
setSearchData(const QByteArray & searchData)78 void ReplaceTool::setSearchData(const QByteArray& searchData)
79 {
80 //     const bool oldIsApplyable = isApplyable();
81 
82     mSearchData = searchData;
83 
84 //     const bool newIsApplyable = isApplyable();
85 //     if( oldIsApplyable != newIsApplyable )
86 //         emit isApplyableChanged( newIsApplyable );
87 }
88 
setReplaceData(const QByteArray & replaceData)89 void ReplaceTool::setReplaceData(const QByteArray& replaceData)
90 {
91 //     const bool oldIsApplyable = isApplyable();
92 
93     mReplaceData = replaceData;
94 
95 //     const bool newIsApplyable = isApplyable();
96 //     if( oldIsApplyable != newIsApplyable )
97 //         emit isApplyableChanged( newIsApplyable );
98 }
99 
setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)100 void ReplaceTool::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
101 {
102 //     const bool oldIsApplyable = isApplyable();
103 
104     mCaseSensitivity = caseSensitivity;
105 
106 //     const bool newIsApplyable = isApplyable();
107 //     if( oldIsApplyable != newIsApplyable )
108 //         emit isApplyableChanged( newIsApplyable );
109 }
110 
setDoPrompt(bool doPrompt)111 void ReplaceTool::setDoPrompt(bool doPrompt)
112 {
113     mDoPrompt = doPrompt;
114 }
115 
replace(FindDirection direction,bool fromCursor,bool inSelection)116 void ReplaceTool::replace(FindDirection direction, bool fromCursor, bool inSelection)
117 {
118     Okteta::Address replaceRangeStartIndex;
119     Okteta::Address replaceRangeEndIndex;
120 
121     if (inSelection) {
122         const Okteta::AddressRange selection = mByteArrayView->selection();
123         if (!selection.isValid()) {
124             mReplaceJob = nullptr;
125             // nothing selected, so skip any search and finish now
126             emit finished(false, 0);
127             return;
128         }
129 
130         replaceRangeStartIndex = selection.start();
131         replaceRangeEndIndex =  selection.end();
132         // TODO: support finding following selection direction
133         direction = FindForward;
134     } else {
135         const Okteta::Address cursorPosition = mByteArrayView->cursorPosition();
136         if (fromCursor && (cursorPosition != 0)) {
137             replaceRangeStartIndex = cursorPosition;
138             replaceRangeEndIndex =  cursorPosition - 1;
139         } else {
140             replaceRangeStartIndex = 0;
141             replaceRangeEndIndex =  mByteArrayModel->size() - 1;
142         }
143     }
144 
145     mReplaceJob = new ReplaceJob(mByteArrayView, mByteArrayModel, mUserQueryAgent, this);
146     mReplaceJob->setSearchData(mSearchData);
147     mReplaceJob->setReplaceData(mReplaceData);
148     mReplaceJob->setCaseSensitivity(mCaseSensitivity);
149     mReplaceJob->setDoPrompt(mDoPrompt);
150     mReplaceJob->setRange(replaceRangeStartIndex, replaceRangeEndIndex, direction);
151     connect(mReplaceJob, &ReplaceJob::finished, this, &ReplaceTool::onJobFinished);
152 
153     emit isApplyableChanged(isApplyable());
154 
155     mReplaceJob->start();
156 }
157 
onReadOnlyChanged(bool isReadOnly)158 void ReplaceTool::onReadOnlyChanged(bool isReadOnly)
159 {
160     Q_UNUSED(isReadOnly)
161 
162     // TODO: find out if isApplyable really changed, perhaps by caching the readonly state?
163     emit isApplyableChanged(isApplyable());
164 }
165 
onJobFinished(bool previousFound,int noOfReplacements)166 void ReplaceTool::onJobFinished(bool previousFound, int noOfReplacements)
167 {
168     delete mReplaceJob;
169     mReplaceJob = nullptr;
170 
171     emit finished(previousFound, noOfReplacements);
172     emit isApplyableChanged(isApplyable());
173 }
174 
175 }
176