1 /*
2     This file is part of the Okteta Kasten module, made within the KDE community.
3 
4     SPDX-FileCopyrightText: 2007-2009, 2012 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 "stringsextracttool.hpp"
10 
11 // lib
12 #include "extractstringsjob.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/CharCodec>
19 #include <Okteta/AbstractByteArrayModel>
20 #include <Okteta/ArrayChangeMetricsList>
21 // KF
22 #include <KLocalizedString>
23 // Qt
24 #include <QApplication>
25 
26 namespace Kasten {
27 
28 static constexpr int DefaultMinLength = 3;
29 
StringsExtractTool()30 StringsExtractTool::StringsExtractTool()
31     : mExtractedStringsUptodate(false)
32     , mSourceByteArrayModelUptodate(false)
33     , mMinLength(DefaultMinLength)
34 {
35     setObjectName(QStringLiteral("Strings"));
36 }
37 
38 StringsExtractTool::~StringsExtractTool() = default;
39 
isApplyable() const40 bool StringsExtractTool::isApplyable() const
41 {
42     return (mByteArrayModel && mByteArrayView && mByteArrayView->hasSelectedData() && mMinLength > 0);
43 }
44 
canHighlightString() const45 bool StringsExtractTool::canHighlightString() const
46 {
47     return (mSourceByteArrayModel == mByteArrayModel
48             && mByteArrayView && mSourceByteArrayModelUptodate);
49 }
50 
title() const51 QString StringsExtractTool::title() const { return i18nc("@title:window of the tool to extract strings", "Strings"); }
52 
53 // TODO: add model with offset and string
54 // doubleclick moves cursor to offset
55 // filter für Suche, inkl. Regulärausdrücke
56 // groß/kleinschreibung
57 // voll strings, auch mit Leerzeichen
setTargetModel(AbstractModel * model)58 void StringsExtractTool::setTargetModel(AbstractModel* model)
59 {
60     if (mByteArrayView) {
61         mByteArrayView->disconnect(this);
62     }
63 
64     mByteArrayView = model ? model->findBaseModel<ByteArrayView*>() : nullptr;
65 
66     ByteArrayDocument* document =
67         mByteArrayView ? qobject_cast<ByteArrayDocument*>(mByteArrayView->baseModel()) : nullptr;
68     mByteArrayModel = document ? document->content() : nullptr;
69 
70     if (mByteArrayView && mByteArrayModel) {
71         connect(mByteArrayView,  &ByteArrayView::selectedDataChanged,
72                 this, &StringsExtractTool::onSelectionChanged);
73 
74         // if strings are from same model, adapt offsetcoding
75         if (mSourceByteArrayModel == mByteArrayModel) {
76             connect(mByteArrayView, &ByteArrayView::offsetCodingChanged,
77                     this, &StringsExtractTool::offsetCodingChanged);
78         }
79     }
80 
81     // TODO: if there is no view, there is nothing to extract.
82     // or this could be the view where we got the strings from and it did not change
83     checkUptoDate();
84     emit uptodateChanged(mExtractedStringsUptodate);
85     emit isApplyableChanged(isApplyable());
86     emit canHighlightStringChanged(canHighlightString());
87     if (mSourceByteArrayModel == mByteArrayModel && mByteArrayView) {
88         emit offsetCodingChanged(mByteArrayView->offsetCoding());
89     }
90 }
91 
offsetCoding() const92 int StringsExtractTool::offsetCoding() const { return (mByteArrayView ? mByteArrayView->offsetCoding() : 0); }
93 
setMinLength(int minLength)94 void StringsExtractTool::setMinLength(int minLength)
95 {
96     mMinLength = minLength;
97     checkUptoDate();
98     emit uptodateChanged(mExtractedStringsUptodate);
99 }
100 
checkUptoDate()101 void StringsExtractTool::checkUptoDate()
102 {
103     mExtractedStringsUptodate =
104         (mSourceByteArrayModel == mByteArrayModel
105          && mByteArrayView && mSourceSelection == mByteArrayView->selection()
106          && mSourceMinLength == mMinLength
107          && mSourceByteArrayModelUptodate);
108 }
109 
markString(int stringId)110 void StringsExtractTool::markString(int stringId)
111 {
112     if (mSourceByteArrayView != mByteArrayView) {
113         if (mSourceByteArrayView) {
114             mSourceByteArrayView->disconnect(this);
115         }
116         mSourceByteArrayView = mByteArrayView;
117         connect(mSourceByteArrayView,  &ByteArrayView::destroyed,
118                 this, &StringsExtractTool::onSourceViewDestroyed);
119     }
120     const ContainedString& containedString = mContainedStringList.at(stringId);
121     const Okteta::Address offset = containedString.offset();
122     const int length = containedString.string().length();
123     const Okteta::AddressRange markingRange = Okteta::AddressRange::fromWidth(offset, length);
124     mSourceByteArrayView->setMarking(markingRange, true);
125 }
126 
unmarkString()127 void StringsExtractTool::unmarkString()
128 {
129 // TODO: marked region is property of document, not view?
130     if (mSourceByteArrayView) {
131         mSourceByteArrayView->setMarking(Okteta::AddressRange());
132     }
133 }
134 
onSelectionChanged()135 void StringsExtractTool::onSelectionChanged()
136 {
137 // TODO: could be quicker using the selection data
138     checkUptoDate();
139     emit uptodateChanged(mExtractedStringsUptodate);
140     emit isApplyableChanged(isApplyable());
141 }
142 
onSourceChanged()143 void StringsExtractTool::onSourceChanged()
144 {
145     mExtractedStringsUptodate = false;
146     mSourceByteArrayModelUptodate = false;
147     emit uptodateChanged(false);
148     emit canHighlightStringChanged(false);
149 }
150 
onSourceDestroyed()151 void StringsExtractTool::onSourceDestroyed()
152 {
153     mSourceByteArrayModel = nullptr;
154     onSourceChanged();
155 }
156 
onSourceViewDestroyed()157 void StringsExtractTool::onSourceViewDestroyed()
158 {
159     mSourceByteArrayView = nullptr;
160 }
161 
162 // TODO: use TextByteArrayAnalyzer
extractStrings()163 void StringsExtractTool::extractStrings()
164 {
165     // forget old string source
166     if (mSourceByteArrayModel) {
167         mSourceByteArrayModel->disconnect(this);
168     }
169 
170     QApplication::setOverrideCursor(Qt::WaitCursor);
171 
172     Okteta::CharCodec* charCodec = Okteta::CharCodec::createCodec(mByteArrayView->charCodingName());
173     ExtractStringsJob* extractStringsJob =
174         new ExtractStringsJob(mByteArrayModel, mByteArrayView->selection(), charCodec, mMinLength,
175                               &mContainedStringList);
176     extractStringsJob->exec();
177     delete charCodec;
178 
179     QApplication::restoreOverrideCursor();
180 
181     // remember new string source
182     mSourceByteArrayModel = mByteArrayModel;
183     mSourceSelection = mByteArrayView->selection();
184     mSourceMinLength = mMinLength;
185     connect(mSourceByteArrayModel,  &Okteta::AbstractByteArrayModel::contentsChanged,
186             this, &StringsExtractTool::onSourceChanged);
187     connect(mSourceByteArrayModel,  &Okteta::AbstractByteArrayModel::destroyed,
188             this, &StringsExtractTool::onSourceDestroyed);
189     connect(mByteArrayView, &ByteArrayView::offsetCodingChanged,
190             this, &StringsExtractTool::offsetCodingChanged);
191 
192     mExtractedStringsUptodate = true;
193     mSourceByteArrayModelUptodate = true;
194     emit uptodateChanged(true);
195     emit canHighlightStringChanged(true);
196     emit offsetCodingChanged(mByteArrayView->offsetCoding());
197 }
198 
199 }
200