1 /*
2     This file is part of the Okteta Kasten module, made within the KDE community.
3 
4     SPDX-FileCopyrightText: 2006-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 "bytearrayview.hpp"
10 
11 // lib
12 #include "bytearrayjanusview.hpp"
13 #include <bytearrayviewprofilesynchronizer.hpp>
14 // Okteta Kasten core
15 #include <Kasten/Okteta/ByteArrayDocument>
16 // Okteta gui
17 #include <Okteta/AbstractByteArrayView>
18 // Okteta core
19 #include <Okteta/AbstractByteArrayModel>
20 // Qt
21 #include <QFontDatabase>
22 
23 namespace Kasten {
24 
25 // TODO: merge into ByteArrayView on next ABI break
26 class SelectedDataCutExtension : public QObject, public If::SelectedDataCutable
27 {
28     Q_OBJECT
29     Q_INTERFACES(
30         Kasten::If::SelectedDataCutable
31     )
32 
33 public:
34     explicit SelectedDataCutExtension(ByteArrayView* view);
35 
36 public: // If::SelectedDataCutable API
37     bool canCutSelectedData() const override;
38 Q_SIGNALS:
39     void canCutSelectedDataChanged(bool canCutSelectedData) override;
40 
41 private Q_SLOTS:
42     void onOverwriteModeChanged(bool overwriteMode);
43 };
44 
SelectedDataCutExtension(ByteArrayView * view)45 SelectedDataCutExtension::SelectedDataCutExtension(ByteArrayView* view)
46     : QObject(view)
47 {
48     connect(view, &ByteArrayView::overwriteModeChanged, this, &SelectedDataCutExtension::onOverwriteModeChanged);
49 }
50 
canCutSelectedData() const51 bool SelectedDataCutExtension::canCutSelectedData() const
52 {
53     return !static_cast<ByteArrayView*>(parent())->isOverwriteMode();
54 }
55 
onOverwriteModeChanged(bool overwriteMode)56 void SelectedDataCutExtension::onOverwriteModeChanged(bool overwriteMode)
57 {
58     emit canCutSelectedDataChanged(!overwriteMode);
59 }
60 
61 
ByteArrayView(ByteArrayDocument * document,ByteArrayViewProfileSynchronizer * synchronizer)62 ByteArrayView::ByteArrayView(ByteArrayDocument* document, ByteArrayViewProfileSynchronizer* synchronizer)
63     : AbstractView(document)
64     , mDocument(document)
65     , mByteArrayViewProfileSynchronizer(synchronizer)
66 {
67     init();
68     if (synchronizer) {
69         synchronizer->setView(this);
70     }
71 }
72 
ByteArrayView(ByteArrayView * other,ByteArrayViewProfileSynchronizer * synchronizer,Qt::Alignment alignment)73 ByteArrayView::ByteArrayView(ByteArrayView* other, ByteArrayViewProfileSynchronizer* synchronizer,
74                              Qt::Alignment alignment)
75     : AbstractView(static_cast<ByteArrayDocument*>(other->baseModel()))
76     , mDocument(static_cast<ByteArrayDocument*>(other->baseModel()))
77     , mByteArrayViewProfileSynchronizer(synchronizer)
78 {
79     init();
80 
81     mWidget->setStartOffset(other->startOffset());
82     mWidget->setFirstLineOffset(other->firstLineOffset());
83 
84     setViewModus(other->viewModus());
85     setVisibleByteArrayCodings(other->visibleByteArrayCodings());
86     toggleOffsetColumn(other->offsetColumnVisible());
87     setOffsetCoding(other->offsetCoding());
88 
89     setCharCoding(other->charCodingName());
90     setShowsNonprinting(other->showsNonprinting());
91     setSubstituteChar(other->substituteChar());
92     setUndefinedChar(other->undefinedChar());
93 
94     setValueCoding(other->valueCoding());
95 
96     setNoOfGroupedBytes(other->noOfGroupedBytes());
97     setNoOfBytesPerLine(other->noOfBytesPerLine());
98     // TODO: this can lead to different layouts due to possible one-pixel difference in width!
99     setLayoutStyle(other->layoutStyle());
100 
101     const Okteta::AddressRange selection = other->selection();
102     setSelection(selection.start(), selection.end());
103     setZoomLevel(other->zoomLevel());
104     setCursorPosition(other->cursorPosition());
105 
106     setOverwriteMode(other->isOverwriteMode());
107     setReadOnly(other->isReadOnly());
108     // TODO: all width
109 
110     const QRect otherViewRect = other->mWidget->viewRect();
111 
112     QPoint viewPos = otherViewRect.topLeft();
113     if (alignment == Qt::AlignBottom) {
114         viewPos.setY(otherViewRect.bottom() + 1);
115     }
116     // TODO: care for resize style
117     else if (alignment == Qt::AlignRight) {
118         viewPos.setX(otherViewRect.right() + 1);
119     }
120     // TODO: doesn't really work at this stage, because the widget will get resized when inserted
121     // and then ensureCursorVisible destroys the fun
122     mWidget->setViewPos(viewPos);
123 
124     if (synchronizer) {
125         synchronizer->setView(this);
126     }
127 }
128 
~ByteArrayView()129 ByteArrayView::~ByteArrayView()
130 {
131     delete mByteArrayViewProfileSynchronizer;
132     delete mWidget;
133 }
134 
init()135 void ByteArrayView::init()
136 {
137     Okteta::AbstractByteArrayModel* content = mDocument->content();
138     mWidget = new Okteta::ByteArrayJanusView();
139     mWidget->setByteArrayModel(content);
140 
141     // TODO: find a signal/event emitted when fixedfont changes
142 //     connect( KGlobalSettings::self(), &KGlobalSettings::kdisplayFontChanged,
143 //              this, &ByteArrayView::setFontByGlobalSettings );
144     setFontByGlobalSettings();
145 
146     mWidget->setNoOfBytesPerLine(16);
147 
148     const bool useOverwriteAsDefault = (content->size() > 0);
149     mWidget->setOverwriteMode(useOverwriteAsDefault);
150 
151     // propagate signals
152     using Okteta::ByteArrayJanusView;
153     connect(mDocument, &ByteArrayDocument::titleChanged, this, &ByteArrayView::titleChanged);
154     connect(mWidget, &ByteArrayJanusView::hasSelectedDataChanged, this, &ByteArrayView::hasSelectedDataChanged);
155     connect(mWidget, &ByteArrayJanusView::readOnlyChanged, this, &ByteArrayView::readOnlyChanged);
156     connect(mWidget, &ByteArrayJanusView::overwriteModeChanged, this, &ByteArrayView::overwriteModeChanged);
157     connect(mWidget, &ByteArrayJanusView::selectionChanged, this, &ByteArrayView::onSelectionChanged);
158     connect(mWidget, &ByteArrayJanusView::cursorPositionChanged, this, &ByteArrayView::cursorPositionChanged);
159     connect(mWidget, &ByteArrayJanusView::valueCodingChanged, this, &ByteArrayView::valueCodingChanged);
160     connect(mWidget, &ByteArrayJanusView::charCodecChanged, this, &ByteArrayView::charCodecChanged);
161     connect(mWidget, &ByteArrayJanusView::focusChanged, this, &ByteArrayView::focusChanged);
162 
163     connect(mWidget, &ByteArrayJanusView::offsetColumnVisibleChanged, this, &ByteArrayView::offsetColumnVisibleChanged);
164     connect(mWidget, &ByteArrayJanusView::offsetCodingChanged, this, &ByteArrayView::offsetCodingChanged);
165     connect(mWidget, &ByteArrayJanusView::visibleByteArrayCodingsChanged, this, &ByteArrayView::visibleByteArrayCodingsChanged);
166     connect(mWidget, &ByteArrayJanusView::layoutStyleChanged, this, &ByteArrayView::layoutStyleChanged);
167     connect(mWidget, &ByteArrayJanusView::noOfBytesPerLineChanged, this, &ByteArrayView::noOfBytesPerLineChanged);
168     connect(mWidget, &ByteArrayJanusView::showsNonprintingChanged, this, &ByteArrayView::showsNonprintingChanged);
169     connect(mWidget, &ByteArrayJanusView::substituteCharChanged, this, &ByteArrayView::substituteCharChanged);
170     connect(mWidget, &ByteArrayJanusView::undefinedCharChanged, this, &ByteArrayView::undefinedCharChanged);
171     connect(mWidget, &ByteArrayJanusView::noOfGroupedBytesChanged, this, &ByteArrayView::noOfGroupedBytesChanged);
172     connect(mWidget, &ByteArrayJanusView::zoomLevelChanged, this, &ByteArrayView::zoomLevelChanged);
173     connect(mWidget, &ByteArrayJanusView::viewModusChanged, this, &ByteArrayView::viewModusChanged);
174 
175     connect(mWidget, &ByteArrayJanusView::viewContextMenuRequested, this, &ByteArrayView::viewContextMenuRequested);
176 
177     new SelectedDataCutExtension(this);
178 }
179 
synchronizer() const180 ByteArrayViewProfileSynchronizer* ByteArrayView::synchronizer() const { return mByteArrayViewProfileSynchronizer; }
181 
modelSelection() const182 const AbstractModelSelection* ByteArrayView::modelSelection() const { return &mSelection; }
183 
widget() const184 QWidget* ByteArrayView::widget()             const { return mWidget; }
hasFocus() const185 bool ByteArrayView::hasFocus()               const { return mWidget->focusWidget()->hasFocus(); } // TODO: does this work?
186 
title() const187 QString ByteArrayView::title()               const { return mDocument->title(); }
isModifiable() const188 bool ByteArrayView::isModifiable()           const { return true; }
isReadOnly() const189 bool ByteArrayView::isReadOnly()             const { return mWidget->isReadOnly(); }
190 
setFocus()191 void ByteArrayView::setFocus()
192 {
193     mWidget->setFocus();
194 }
195 
setReadOnly(bool isReadOnly)196 void ByteArrayView::setReadOnly(bool isReadOnly) { mWidget->setReadOnly(isReadOnly); }
197 
setZoomLevel(double Level)198 void ByteArrayView::setZoomLevel(double Level)
199 {
200     mWidget->setZoomLevel(Level);
201 }
202 
zoomLevel() const203 double ByteArrayView::zoomLevel() const
204 {
205     return mWidget->zoomLevel();
206 }
207 
selectAllData(bool selectAll)208 void ByteArrayView::selectAllData(bool selectAll)
209 {
210     mWidget->selectAll(selectAll);
211 }
212 
hasSelectedData() const213 bool ByteArrayView::hasSelectedData() const
214 {
215     return mWidget->hasSelectedData();
216 }
217 
copySelectedData() const218 QMimeData* ByteArrayView::copySelectedData() const
219 {
220     return mWidget->selectionAsMimeData();
221 }
222 
insertData(const QMimeData * data)223 void ByteArrayView::insertData(const QMimeData* data)
224 {
225     mWidget->pasteData(data);
226 }
227 
cutSelectedData()228 QMimeData* ByteArrayView::cutSelectedData()
229 {
230     QMimeData* result = mWidget->selectionAsMimeData();
231     mWidget->removeSelectedData();
232     return result;
233 }
234 
deleteSelectedData()235 void ByteArrayView::deleteSelectedData()
236 {
237     mWidget->removeSelectedData();
238 }
239 
canReadData(const QMimeData * data) const240 bool ByteArrayView::canReadData(const QMimeData* data) const
241 {
242     return mWidget->canReadData(data);
243 }
244 
onSelectionChanged(const Okteta::AddressRange & selection)245 void ByteArrayView::onSelectionChanged(const Okteta::AddressRange& selection)
246 {
247     // TODO: how to make sure the signal hasSelectedDataChanged() is not emitted before?
248     mSelection.setRange(selection);
249     emit selectedDataChanged(&mSelection);
250 }
251 
setCursorPosition(Okteta::Address cursorPosition)252 void ByteArrayView::setCursorPosition(Okteta::Address cursorPosition)
253 {
254     mWidget->setCursorPosition(cursorPosition);
255 }
256 
setSelectionCursorPosition(Okteta::Address index)257 void ByteArrayView::setSelectionCursorPosition(Okteta::Address index)
258 {
259     mWidget->setSelectionCursorPosition(index);
260 }
261 
cursorPosition() const262 Okteta::Address ByteArrayView::cursorPosition() const
263 {
264     return mWidget->cursorPosition();
265 }
cursorRect() const266 QRect ByteArrayView::cursorRect() const
267 {
268     return mWidget->cursorRect();
269 }
270 
startOffset() const271 Okteta::Address ByteArrayView::startOffset() const
272 {
273     return mWidget->startOffset();
274 }
firstLineOffset() const275 Okteta::Address ByteArrayView::firstLineOffset() const
276 {
277     return mWidget->firstLineOffset();
278 }
noOfBytesPerLine() const279 int ByteArrayView::noOfBytesPerLine() const
280 {
281     return mWidget->noOfBytesPerLine();
282 }
283 
valueCoding() const284 int ByteArrayView::valueCoding() const
285 {
286     return mWidget->valueCoding();
287 }
288 
charCodingName() const289 QString ByteArrayView::charCodingName() const
290 {
291     return mWidget->charCodingName();
292 }
293 
setValueCoding(int valueCoding)294 void ByteArrayView::setValueCoding(int valueCoding)
295 {
296     mWidget->setValueCoding((Okteta::AbstractByteArrayView::ValueCoding)valueCoding);
297 }
298 
setCharCoding(const QString & charCodingName)299 void ByteArrayView::setCharCoding(const QString& charCodingName)
300 {
301     mWidget->setCharCoding(charCodingName);
302 }
303 
selection() const304 Okteta::AddressRange ByteArrayView::selection() const
305 {
306     return mWidget->selection();
307 }
308 
setSelection(Okteta::Address start,Okteta::Address end)309 void ByteArrayView::setSelection(Okteta::Address start, Okteta::Address end)
310 {
311     mWidget->setSelection(start, end);
312 }
313 
insert(const QByteArray & byteArray)314 void ByteArrayView::insert(const QByteArray& byteArray)
315 {
316     mWidget->insert(byteArray);
317 }
318 
showsNonprinting() const319 bool ByteArrayView::showsNonprinting() const
320 {
321     return mWidget->showsNonprinting();
322 }
323 
offsetColumnVisible() const324 bool ByteArrayView::offsetColumnVisible() const
325 {
326     return mWidget->offsetColumnVisible();
327 }
328 
offsetCoding() const329 int ByteArrayView::offsetCoding() const
330 {
331     return mWidget->offsetCoding();
332 }
333 
layoutStyle() const334 int ByteArrayView::layoutStyle() const
335 {
336     return (int)mWidget->layoutStyle();
337 }
338 
visibleByteArrayCodings() const339 int ByteArrayView::visibleByteArrayCodings() const
340 {
341     return (int)mWidget->visibleCodings();
342 }
343 
isOverwriteMode() const344 bool ByteArrayView::isOverwriteMode() const
345 {
346     return mWidget->isOverwriteMode();
347 }
348 
setShowsNonprinting(bool on)349 void ByteArrayView::setShowsNonprinting(bool on)
350 {
351     mWidget->setShowsNonprinting(on);
352 }
353 
setNoOfGroupedBytes(int noOfGroupedBytes)354 void ByteArrayView::setNoOfGroupedBytes(int noOfGroupedBytes)
355 {
356     mWidget->setNoOfGroupedBytes(noOfGroupedBytes);
357 }
358 
toggleOffsetColumn(bool on)359 void ByteArrayView::toggleOffsetColumn(bool on)
360 {
361     mWidget->toggleOffsetColumn(on);
362 }
363 
setOffsetCoding(int offsetCoding)364 void ByteArrayView::setOffsetCoding(int offsetCoding)
365 {
366     mWidget->setOffsetCoding(offsetCoding);
367 }
368 
setLayoutStyle(int layoutStyle)369 void ByteArrayView::setLayoutStyle(int layoutStyle)
370 {
371     mWidget->setLayoutStyle((Okteta::AbstractByteArrayView::LayoutStyle)layoutStyle);
372 }
373 
setNoOfBytesPerLine(int noOfBytesPerLine)374 void ByteArrayView::setNoOfBytesPerLine(int noOfBytesPerLine)
375 {
376     mWidget->setNoOfBytesPerLine(noOfBytesPerLine);
377 }
378 
setVisibleByteArrayCodings(int visibleColumns)379 void ByteArrayView::setVisibleByteArrayCodings(int visibleColumns)
380 {
381     mWidget->setVisibleCodings(visibleColumns);
382 }
383 
setMarking(const Okteta::AddressRange & range,bool ensureVisible)384 void ByteArrayView::setMarking(const Okteta::AddressRange& range, bool ensureVisible)
385 {
386     mWidget->setMarking(range);
387     if (ensureVisible) {
388         mWidget->ensureVisible(range);
389     }
390 }
391 
setSubstituteChar(QChar substituteChar)392 void ByteArrayView::setSubstituteChar(QChar substituteChar)
393 {
394     mWidget->setSubstituteChar(substituteChar);
395 }
396 
setUndefinedChar(QChar undefinedChar)397 void ByteArrayView::setUndefinedChar(QChar undefinedChar)
398 {
399     mWidget->setUndefinedChar(undefinedChar);
400 }
401 
substituteChar() const402 QChar ByteArrayView::substituteChar() const
403 {
404     return mWidget->substituteChar();
405 }
undefinedChar() const406 QChar ByteArrayView::undefinedChar() const
407 {
408     return mWidget->undefinedChar();
409 }
410 
byteSpacingWidth() const411 int ByteArrayView::byteSpacingWidth() const
412 {
413     return mWidget->byteSpacingWidth();
414 }
noOfGroupedBytes() const415 int ByteArrayView::noOfGroupedBytes() const
416 {
417     return mWidget->noOfGroupedBytes();
418 }
groupSpacingWidth() const419 int ByteArrayView::groupSpacingWidth() const
420 {
421     return mWidget->groupSpacingWidth();
422 }
binaryGapWidth() const423 int ByteArrayView::binaryGapWidth() const
424 {
425     return mWidget->binaryGapWidth();
426 }
427 
isOverwriteOnly() const428 bool ByteArrayView::isOverwriteOnly() const
429 {
430     return mWidget->isOverwriteOnly();
431 }
432 
setOverwriteMode(bool overwriteMode)433 void ByteArrayView::setOverwriteMode(bool overwriteMode)
434 {
435     mWidget->setOverwriteMode(overwriteMode);
436 }
437 
setViewModus(int viewModus)438 void ByteArrayView::setViewModus(int viewModus)
439 {
440     mWidget->setViewModus(viewModus);
441 }
viewModus() const442 int ByteArrayView::viewModus() const
443 {
444     return mWidget->viewModus();
445 }
446 
setFontByGlobalSettings()447 void ByteArrayView::setFontByGlobalSettings()
448 {
449     mWidget->propagateFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
450 }
451 
452 }
453 
454 // needed for SelectedDataCutExtension
455 #include "bytearrayview.moc"
456