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 "gotooffsettool.hpp"
10 
11 // Okteta Kasten gui
12 #include <Kasten/Okteta/ByteArrayView>
13 // Okteta Kasten core
14 #include <Kasten/Okteta/ByteArrayDocument>
15 // Okteta core
16 #include <Okteta/AbstractByteArrayModel>
17 #include <Okteta/ArrayChangeMetricsList>
18 // KF
19 #include <KLocalizedString>
20 
21 namespace Kasten {
22 
GotoOffsetTool()23 GotoOffsetTool::GotoOffsetTool()
24 {
25     setObjectName(QStringLiteral("GotoOffset"));
26 }
27 
28 GotoOffsetTool::~GotoOffsetTool() = default;
29 
currentOffset() const30 int GotoOffsetTool::currentOffset() const
31 {
32     return mByteArrayView ?
33            mByteArrayView->startOffset() + mByteArrayView->cursorPosition() :
34            -1;
35 }
36 
isUsable() const37 bool GotoOffsetTool::isUsable() const
38 {
39     return (mByteArrayView && mByteArrayModel && (mByteArrayModel->size() > 0));
40 }
41 
isApplyable() const42 bool GotoOffsetTool::isApplyable() const
43 {
44     const int newPosition = finalTargetOffset();
45 
46     return (mByteArrayView && mByteArrayModel
47             && (0 <= newPosition) && (newPosition <= mByteArrayModel->size()));
48 }
49 
title() const50 QString GotoOffsetTool::title() const { return i18nc("@title:window of the tool to set a new offset for the cursor", "Goto"); }
51 
setTargetModel(AbstractModel * model)52 void GotoOffsetTool::setTargetModel(AbstractModel* model)
53 {
54     const bool oldIsUsable = isUsable();
55     const bool oldIsApplyable = isApplyable();
56 
57     if (mByteArrayView) {
58         mByteArrayView->disconnect(this);
59     }
60     if (mByteArrayModel) {
61         mByteArrayModel->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(mByteArrayModel, &Okteta::AbstractByteArrayModel::contentsChanged,
72                 this, &GotoOffsetTool::onContentsChanged);
73         // TODO: update isApplyable on cursor movement and size changes
74     }
75 
76     const bool newIsUsable = isUsable();
77     const bool newIsApplyable = isApplyable();
78     if (oldIsUsable != newIsUsable) {
79         emit isUsableChanged(newIsUsable);
80     }
81     if (oldIsApplyable != newIsApplyable) {
82         emit isApplyableChanged(newIsApplyable);
83     }
84 }
85 
setTargetOffset(Okteta::Address targetOffset)86 void GotoOffsetTool::setTargetOffset(Okteta::Address targetOffset)
87 {
88     const bool oldIsApplyable = isApplyable();
89 
90     mTargetOffset = targetOffset;
91 
92     const bool newIsApplyable = isApplyable();
93     if (oldIsApplyable != newIsApplyable) {
94         emit isApplyableChanged(newIsApplyable);
95     }
96 }
97 
setIsRelative(bool isRelative)98 void GotoOffsetTool::setIsRelative(bool isRelative)
99 {
100     const bool oldIsApplyable = isApplyable();
101 
102     mIsRelative = isRelative;
103 
104     const bool newIsApplyable = isApplyable();
105     if (oldIsApplyable != newIsApplyable) {
106         emit isApplyableChanged(newIsApplyable);
107     }
108 }
109 
setIsSelectionToExtent(bool isSelectionToExtent)110 void GotoOffsetTool::setIsSelectionToExtent(bool isSelectionToExtent)
111 {
112     const bool oldIsApplyable = isApplyable();
113 
114     mIsSelectionToExtent = isSelectionToExtent;
115 
116     const bool newIsApplyable = isApplyable();
117     if (oldIsApplyable != newIsApplyable) {
118         emit isApplyableChanged(newIsApplyable);
119     }
120 }
121 
setIsBackwards(bool isBackwards)122 void GotoOffsetTool::setIsBackwards(bool isBackwards)
123 {
124     const bool oldIsApplyable = isApplyable();
125 
126     mIsBackwards = isBackwards;
127 
128     const bool newIsApplyable = isApplyable();
129     if (oldIsApplyable != newIsApplyable) {
130         emit isApplyableChanged(newIsApplyable);
131     }
132 }
133 
gotoOffset()134 void GotoOffsetTool::gotoOffset()
135 {
136     const int newPosition = finalTargetOffset();
137 
138     if (mIsSelectionToExtent) {
139         mByteArrayView->setSelectionCursorPosition(newPosition);
140     } else {
141         mByteArrayView->setCursorPosition(newPosition);
142     }
143     mByteArrayView->setFocus();
144 }
145 
finalTargetOffset() const146 int GotoOffsetTool::finalTargetOffset() const
147 {
148     const int newPosition =
149         (!mByteArrayView) ? -1 :
150         mIsRelative ?
151             (mIsBackwards ? mByteArrayView->cursorPosition() - mTargetOffset :
152                             mByteArrayView->cursorPosition() + mTargetOffset) :
153             (mIsBackwards ? mByteArrayModel->size() - mTargetOffset :
154                             mTargetOffset);
155 
156     return newPosition;
157 }
158 
onContentsChanged()159 void GotoOffsetTool::onContentsChanged()
160 {
161     // TODO: find status before content changed, e.g. by caching
162     emit isUsableChanged(isUsable());
163 }
164 
165 }
166