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