1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #pragma once
27
28 #include "bineditor_global.h"
29 #include "markup.h"
30 #include "bineditorservice.h"
31
32 #include <utils/optional.h>
33
34 #include <QBasicTimer>
35 #include <QMap>
36 #include <QSet>
37 #include <QStack>
38 #include <QString>
39
40 #include <QAbstractScrollArea>
41 #include <QTextDocument>
42 #include <QTextFormat>
43
44 QT_FORWARD_DECLARE_CLASS(QMenu)
QT_FORWARD_DECLARE_CLASS(QHelpEvent)45 QT_FORWARD_DECLARE_CLASS(QHelpEvent)
46
47 namespace Core { class IEditor; }
48
49 namespace TextEditor { class FontSettings; }
50
51 namespace BinEditor {
52 namespace Internal {
53
54 class BinEditorWidgetPrivate;
55
56 class BinEditorWidget : public QAbstractScrollArea
57 {
58 Q_OBJECT
59 Q_PROPERTY(bool modified READ isModified WRITE setModified DESIGNABLE false)
60 Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE false)
61 Q_PROPERTY(QList<BinEditor::Markup> markup READ markup WRITE setMarkup DESIGNABLE false)
62 Q_PROPERTY(bool newWindowRequestAllowed READ newWindowRequestAllowed WRITE setNewWindowRequestAllowed DESIGNABLE false)
63
64 public:
65 BinEditorWidget(QWidget *parent = nullptr);
66 ~BinEditorWidget() override;
67
68 EditorService *editorService() const;
69
baseAddress()70 quint64 baseAddress() const { return m_baseAddr; }
71
72 void setSizes(quint64 startAddr, qint64 range, int blockSize = 4096);
dataBlockSize()73 int dataBlockSize() const { return m_blockSize; }
contents()74 QByteArray contents() const { return dataMid(0, m_size); }
75
76 void addData(quint64 addr, const QByteArray &data);
77
newWindowRequestAllowed()78 bool newWindowRequestAllowed() const { return m_canRequestNewWindow; }
79
80 void updateContents();
81 bool save(QString *errorString, const QString &oldFileName, const QString &newFileName);
82
83 void zoomF(float delta);
84
85 enum MoveMode {
86 MoveAnchor,
87 KeepAnchor
88 };
89
90 qint64 cursorPosition() const;
91 void setCursorPosition(qint64 pos, MoveMode moveMode = MoveAnchor);
92 void jumpToAddress(quint64 address);
93
94 void setModified(bool);
95 bool isModified() const;
96
97 void setReadOnly(bool);
98 bool isReadOnly() const;
99
100 int find(const QByteArray &pattern, qint64 from = 0, QTextDocument::FindFlags findFlags = {});
101
102 void selectAll();
103 void clear();
104
105 void undo();
106 void redo();
107
editor()108 Core::IEditor *editor() const { return m_ieditor; }
setEditor(Core::IEditor * ieditor)109 void setEditor(Core::IEditor *ieditor) { m_ieditor = ieditor; }
110
selectionStart()111 int selectionStart() const { return qMin(m_anchorPosition, m_cursorPosition); }
selectionEnd()112 int selectionEnd() const { return qMax(m_anchorPosition, m_cursorPosition); }
113
114 bool event(QEvent*) override;
115
isUndoAvailable()116 bool isUndoAvailable() const { return !m_undoStack.isEmpty(); }
isRedoAvailable()117 bool isRedoAvailable() const { return !m_redoStack.isEmpty(); }
118
119 QString addressString(quint64 address);
120
121 static const int SearchStride = 1024 * 1024;
122
markup()123 QList<Markup> markup() const { return m_markup; }
124
125 void setFontSettings(const TextEditor::FontSettings &fs);
126 void highlightSearchResults(const QByteArray &pattern, QTextDocument::FindFlags findFlags = {});
127 void copy(bool raw = false);
128 void setMarkup(const QList<Markup> &markup);
129 void setNewWindowRequestAllowed(bool c);
130
131 signals:
132 void modificationChanged(bool modified);
133 void undoAvailable(bool);
134 void redoAvailable(bool);
135 void cursorPositionChanged(int position);
136
137 private:
138 void scrollContentsBy(int dx, int dy) override;
139 void paintEvent(QPaintEvent *e) override;
140 void resizeEvent(QResizeEvent *) override;
141 void changeEvent(QEvent *) override;
142 void wheelEvent(QWheelEvent *e) override;
143 void mousePressEvent(QMouseEvent *e) override;
144 void mouseMoveEvent(QMouseEvent *e) override;
145 void mouseReleaseEvent(QMouseEvent *e) override;
146 void keyPressEvent(QKeyEvent *e) override;
147 void focusInEvent(QFocusEvent *) override;
148 void focusOutEvent(QFocusEvent *) override;
149 void timerEvent(QTimerEvent *) override;
150 void contextMenuEvent(QContextMenuEvent *event) override;
151
152 friend class BinEditorWidgetPrivate;
153 BinEditorWidgetPrivate *d;
154
155 using BlockMap = QMap<qint64, QByteArray>;
156 BlockMap m_data;
157 BlockMap m_oldData;
158 int m_blockSize;
159 BlockMap m_modifiedData;
160 mutable QSet<qint64> m_requests;
161 QByteArray m_emptyBlock;
162 QByteArray m_lowerBlock;
163 qint64 m_size;
164
165 int dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const;
166 int dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const;
167
168 bool requestDataAt(qint64 pos) const;
169 bool requestOldDataAt(qint64 pos) const;
170 char dataAt(qint64 pos, bool old = false) const;
171 char oldDataAt(qint64 pos) const;
172 void changeDataAt(qint64 pos, char c);
173 QByteArray dataMid(qint64 from, int length, bool old = false) const;
174 QByteArray blockData(qint64 block, bool old = false) const;
175
176 QPoint offsetToPos(qint64 offset) const;
177 void asIntegers(qint64 offset, int count, quint64 &bigEndianValue, quint64 &littleEndianValue,
178 bool old = false) const;
179 void asFloat(qint64 offset, float &value, bool old) const;
180 void asDouble(qint64 offset, double &value, bool old) const;
181 QString toolTip(const QHelpEvent *helpEvent) const;
182
183 int m_bytesPerLine;
184 int m_unmodifiedState;
185 int m_readOnly;
186 int m_margin;
187 int m_descent;
188 int m_ascent;
189 int m_lineHeight;
190 int m_charWidth;
191 int m_labelWidth;
192 int m_textWidth;
193 int m_columnWidth;
194 qint64 m_numLines;
195 qint64 m_numVisibleLines;
196
197 quint64 m_baseAddr;
198
199 bool m_cursorVisible;
200 qint64 m_cursorPosition;
201 qint64 m_anchorPosition;
202 bool m_hexCursor;
203 bool m_lowNibble;
204 bool m_isMonospacedFont;
205
206 QByteArray m_searchPattern;
207 QByteArray m_searchPatternHex;
208 bool m_caseSensitiveSearch;
209
210 QBasicTimer m_cursorBlinkTimer;
211
212 void init();
213 Utils::optional<qint64> posAt(const QPoint &pos, bool includeEmptyArea = true) const;
214 bool inTextArea(const QPoint &pos) const;
215 QRect cursorRect() const;
216 void updateLines();
217 void updateLines(int fromPosition, int toPosition);
218 void ensureCursorVisible();
219 void setBlinkingCursorEnabled(bool enable);
220
221 void changeData(int position, uchar character, bool highNibble = false);
222
223 int findPattern(const QByteArray &data, const QByteArray &dataHex,
224 int from, int offset, int *match);
225 void drawItems(QPainter *painter, int x, int y, const QString &itemString);
226 void drawChanges(QPainter *painter, int x, int y, const char *changes);
227
228 void setupJumpToMenuAction(QMenu *menu, QAction *actionHere, QAction *actionNew,
229 quint64 addr);
230
231 struct BinEditorEditCommand {
232 int position;
233 uchar character;
234 bool highNibble;
235 };
236 QStack<BinEditorEditCommand> m_undoStack, m_redoStack;
237
238 QBasicTimer m_autoScrollTimer;
239 Core::IEditor *m_ieditor;
240 QString m_addressString;
241 int m_addressBytes;
242 bool m_canRequestNewWindow;
243 QList<Markup> m_markup;
244 };
245
246 } // namespace Internal
247 } // namespace BinEditor
248