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