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