1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -0,0 +1,115 | |||||
|
1 | #include "commands.h" | |||
|
2 | ||||
|
3 | CharCommand::CharCommand(XByteArray * xData, Cmd cmd, int charPos, char newChar, QUndoCommand *parent) | |||
|
4 | : QUndoCommand(parent) | |||
|
5 | { | |||
|
6 | _xData = xData; | |||
|
7 | _charPos = charPos; | |||
|
8 | _newChar = newChar; | |||
|
9 | _cmd = cmd; | |||
|
10 | } | |||
|
11 | ||||
|
12 | bool CharCommand::mergeWith(const QUndoCommand *command) | |||
|
13 | { | |||
|
14 | const CharCommand *nextCommand = static_cast<const CharCommand *>(command); | |||
|
15 | bool result = false; | |||
|
16 | ||||
|
17 | if (_cmd != remove) | |||
|
18 | { | |||
|
19 | if (nextCommand->_cmd == replace) | |||
|
20 | if (nextCommand->_charPos == _charPos) | |||
|
21 | { | |||
|
22 | _newChar = nextCommand->_newChar; | |||
|
23 | result = true; | |||
|
24 | } | |||
|
25 | } | |||
|
26 | return result; | |||
|
27 | } | |||
|
28 | ||||
|
29 | void CharCommand::undo() | |||
|
30 | { | |||
|
31 | switch (_cmd) | |||
|
32 | { | |||
|
33 | case insert: | |||
|
34 | _xData->remove(_charPos, 1); | |||
|
35 | break; | |||
|
36 | case replace: | |||
|
37 | _xData->replace(_charPos, _oldChar); | |||
|
38 | _xData->setDataChanged(_charPos, _wasChanged); | |||
|
39 | break; | |||
|
40 | case remove: | |||
|
41 | _xData->insert(_charPos, _oldChar); | |||
|
42 | _xData->setDataChanged(_charPos, _wasChanged); | |||
|
43 | break; | |||
|
44 | } | |||
|
45 | } | |||
|
46 | ||||
|
47 | void CharCommand::redo() | |||
|
48 | { | |||
|
49 | switch (_cmd) | |||
|
50 | { | |||
|
51 | case insert: | |||
|
52 | _xData->insert(_charPos, _newChar); | |||
|
53 | break; | |||
|
54 | case replace: | |||
|
55 | _oldChar = _xData->data()[_charPos]; | |||
|
56 | _wasChanged = _xData->dataChanged(_charPos); | |||
|
57 | _xData->replace(_charPos, _newChar); | |||
|
58 | break; | |||
|
59 | case remove: | |||
|
60 | _oldChar = _xData->data()[_charPos]; | |||
|
61 | _wasChanged = _xData->dataChanged(_charPos); | |||
|
62 | _xData->remove(_charPos, 1); | |||
|
63 | break; | |||
|
64 | } | |||
|
65 | } | |||
|
66 | ||||
|
67 | ||||
|
68 | ||||
|
69 | ArrayCommand::ArrayCommand(XByteArray * xData, Cmd cmd, int baPos, QByteArray newBa, int len, QUndoCommand *parent) | |||
|
70 | : QUndoCommand(parent) | |||
|
71 | { | |||
|
72 | _cmd = cmd; | |||
|
73 | _xData = xData; | |||
|
74 | _baPos = baPos; | |||
|
75 | _newBa = newBa; | |||
|
76 | _len = len; | |||
|
77 | } | |||
|
78 | ||||
|
79 | void ArrayCommand::undo() | |||
|
80 | { | |||
|
81 | switch (_cmd) | |||
|
82 | { | |||
|
83 | case insert: | |||
|
84 | _xData->remove(_baPos, _newBa.length()); | |||
|
85 | break; | |||
|
86 | case replace: | |||
|
87 | _xData->replace(_baPos, _oldBa); | |||
|
88 | _xData->setDataChanged(_baPos, _wasChanged); | |||
|
89 | break; | |||
|
90 | case remove: | |||
|
91 | _xData->insert(_baPos, _oldBa); | |||
|
92 | _xData->setDataChanged(_baPos, _wasChanged); | |||
|
93 | break; | |||
|
94 | } | |||
|
95 | } | |||
|
96 | ||||
|
97 | void ArrayCommand::redo() | |||
|
98 | { | |||
|
99 | switch (_cmd) | |||
|
100 | { | |||
|
101 | case insert: | |||
|
102 | _xData->insert(_baPos, _newBa); | |||
|
103 | break; | |||
|
104 | case replace: | |||
|
105 | _oldBa = _xData->data().mid(_baPos, _len); | |||
|
106 | _wasChanged = _xData->dataChanged(_baPos, _len); | |||
|
107 | _xData->replace(_baPos, _newBa); | |||
|
108 | break; | |||
|
109 | case remove: | |||
|
110 | _oldBa = _xData->data().mid(_baPos, _len); | |||
|
111 | _wasChanged = _xData->dataChanged(_baPos, _len); | |||
|
112 | _xData->remove(_baPos, _len); | |||
|
113 | break; | |||
|
114 | } | |||
|
115 | } |
@@ -0,0 +1,70 | |||||
|
1 | #ifndef COMMANDS_H | |||
|
2 | #define COMMANDS_H | |||
|
3 | ||||
|
4 | /** \cond docNever */ | |||
|
5 | ||||
|
6 | #include <QUndoCommand> | |||
|
7 | ||||
|
8 | #include "xbytearray.h" | |||
|
9 | ||||
|
10 | /*! CharCommand is a class to prived undo/redo functionality in QHexEdit. | |||
|
11 | A QUndoCommand represents a single editing action on a document. CharCommand | |||
|
12 | is responsable for manipulations on single chars. It can insert. replace and | |||
|
13 | remove characters. A manipulation stores allways to actions | |||
|
14 | 1. redo (or do) action | |||
|
15 | 2. undo action. | |||
|
16 | ||||
|
17 | CharCommand also supports command compression via mergeWidht(). This allows | |||
|
18 | the user to execute a undo command contation e.g. 3 steps in a single command. | |||
|
19 | If you for example insert a new byt "34" this means for the editor doing 3 | |||
|
20 | steps: insert a "00", replace it with "03" and the replace it with "34". These | |||
|
21 | 3 steps are combined into a single step, insert a "34". | |||
|
22 | */ | |||
|
23 | class CharCommand : public QUndoCommand | |||
|
24 | { | |||
|
25 | public: | |||
|
26 | enum { Id = 1234 }; | |||
|
27 | enum Cmd {insert, remove, replace}; | |||
|
28 | ||||
|
29 | CharCommand(XByteArray * xData, Cmd cmd, int charPos, char newChar, | |||
|
30 | QUndoCommand *parent=0); | |||
|
31 | ||||
|
32 | void undo(); | |||
|
33 | void redo(); | |||
|
34 | bool mergeWith(const QUndoCommand *command); | |||
|
35 | int id() const { return Id; } | |||
|
36 | ||||
|
37 | private: | |||
|
38 | XByteArray * _xData; | |||
|
39 | int _charPos; | |||
|
40 | bool _wasChanged; | |||
|
41 | char _newChar; | |||
|
42 | char _oldChar; | |||
|
43 | Cmd _cmd; | |||
|
44 | }; | |||
|
45 | ||||
|
46 | /*! ArrayCommand provides undo/redo functionality for handling binary strings. It | |||
|
47 | can undo/redo insert, replace and remove binary strins (QByteArrays). | |||
|
48 | */ | |||
|
49 | class ArrayCommand : public QUndoCommand | |||
|
50 | { | |||
|
51 | public: | |||
|
52 | enum Cmd {insert, remove, replace}; | |||
|
53 | ArrayCommand(XByteArray * xData, Cmd cmd, int baPos, QByteArray newBa=QByteArray(), int len=0, | |||
|
54 | QUndoCommand *parent=0); | |||
|
55 | void undo(); | |||
|
56 | void redo(); | |||
|
57 | ||||
|
58 | private: | |||
|
59 | Cmd _cmd; | |||
|
60 | XByteArray * _xData; | |||
|
61 | int _baPos; | |||
|
62 | int _len; | |||
|
63 | QByteArray _wasChanged; | |||
|
64 | QByteArray _newBa; | |||
|
65 | QByteArray _oldBa; | |||
|
66 | }; | |||
|
67 | ||||
|
68 | /** \endcond docNever */ | |||
|
69 | ||||
|
70 | #endif // COMMANDS_H |
This diff has been collapsed as it changes many lines, (502 lines changed) Show them Hide them | |||||
@@ -0,0 +1,502 | |||||
|
1 | GNU LESSER GENERAL PUBLIC LICENSE | |||
|
2 | Version 2.1, February 1999 | |||
|
3 | ||||
|
4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. | |||
|
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
|
6 | Everyone is permitted to copy and distribute verbatim copies | |||
|
7 | of this license document, but changing it is not allowed. | |||
|
8 | ||||
|
9 | [This is the first released version of the Lesser GPL. It also counts | |||
|
10 | as the successor of the GNU Library Public License, version 2, hence | |||
|
11 | the version number 2.1.] | |||
|
12 | ||||
|
13 | Preamble | |||
|
14 | ||||
|
15 | The licenses for most software are designed to take away your | |||
|
16 | freedom to share and change it. By contrast, the GNU General Public | |||
|
17 | Licenses are intended to guarantee your freedom to share and change | |||
|
18 | free software--to make sure the software is free for all its users. | |||
|
19 | ||||
|
20 | This license, the Lesser General Public License, applies to some | |||
|
21 | specially designated software packages--typically libraries--of the | |||
|
22 | Free Software Foundation and other authors who decide to use it. You | |||
|
23 | can use it too, but we suggest you first think carefully about whether | |||
|
24 | this license or the ordinary General Public License is the better | |||
|
25 | strategy to use in any particular case, based on the explanations below. | |||
|
26 | ||||
|
27 | When we speak of free software, we are referring to freedom of use, | |||
|
28 | not price. Our General Public Licenses are designed to make sure that | |||
|
29 | you have the freedom to distribute copies of free software (and charge | |||
|
30 | for this service if you wish); that you receive source code or can get | |||
|
31 | it if you want it; that you can change the software and use pieces of | |||
|
32 | it in new free programs; and that you are informed that you can do | |||
|
33 | these things. | |||
|
34 | ||||
|
35 | To protect your rights, we need to make restrictions that forbid | |||
|
36 | distributors to deny you these rights or to ask you to surrender these | |||
|
37 | rights. These restrictions translate to certain responsibilities for | |||
|
38 | you if you distribute copies of the library or if you modify it. | |||
|
39 | ||||
|
40 | For example, if you distribute copies of the library, whether gratis | |||
|
41 | or for a fee, you must give the recipients all the rights that we gave | |||
|
42 | you. You must make sure that they, too, receive or can get the source | |||
|
43 | code. If you link other code with the library, you must provide | |||
|
44 | complete object files to the recipients, so that they can relink them | |||
|
45 | with the library after making changes to the library and recompiling | |||
|
46 | it. And you must show them these terms so they know their rights. | |||
|
47 | ||||
|
48 | We protect your rights with a two-step method: (1) we copyright the | |||
|
49 | library, and (2) we offer you this license, which gives you legal | |||
|
50 | permission to copy, distribute and/or modify the library. | |||
|
51 | ||||
|
52 | To protect each distributor, we want to make it very clear that | |||
|
53 | there is no warranty for the free library. Also, if the library is | |||
|
54 | modified by someone else and passed on, the recipients should know | |||
|
55 | that what they have is not the original version, so that the original | |||
|
56 | author's reputation will not be affected by problems that might be | |||
|
57 | introduced by others. | |||
|
58 | ||||
|
59 | Finally, software patents pose a constant threat to the existence of | |||
|
60 | any free program. We wish to make sure that a company cannot | |||
|
61 | effectively restrict the users of a free program by obtaining a | |||
|
62 | restrictive license from a patent holder. Therefore, we insist that | |||
|
63 | any patent license obtained for a version of the library must be | |||
|
64 | consistent with the full freedom of use specified in this license. | |||
|
65 | ||||
|
66 | Most GNU software, including some libraries, is covered by the | |||
|
67 | ordinary GNU General Public License. This license, the GNU Lesser | |||
|
68 | General Public License, applies to certain designated libraries, and | |||
|
69 | is quite different from the ordinary General Public License. We use | |||
|
70 | this license for certain libraries in order to permit linking those | |||
|
71 | libraries into non-free programs. | |||
|
72 | ||||
|
73 | When a program is linked with a library, whether statically or using | |||
|
74 | a shared library, the combination of the two is legally speaking a | |||
|
75 | combined work, a derivative of the original library. The ordinary | |||
|
76 | General Public License therefore permits such linking only if the | |||
|
77 | entire combination fits its criteria of freedom. The Lesser General | |||
|
78 | Public License permits more lax criteria for linking other code with | |||
|
79 | the library. | |||
|
80 | ||||
|
81 | We call this license the "Lesser" General Public License because it | |||
|
82 | does Less to protect the user's freedom than the ordinary General | |||
|
83 | Public License. It also provides other free software developers Less | |||
|
84 | of an advantage over competing non-free programs. These disadvantages | |||
|
85 | are the reason we use the ordinary General Public License for many | |||
|
86 | libraries. However, the Lesser license provides advantages in certain | |||
|
87 | special circumstances. | |||
|
88 | ||||
|
89 | For example, on rare occasions, there may be a special need to | |||
|
90 | encourage the widest possible use of a certain library, so that it becomes | |||
|
91 | a de-facto standard. To achieve this, non-free programs must be | |||
|
92 | allowed to use the library. A more frequent case is that a free | |||
|
93 | library does the same job as widely used non-free libraries. In this | |||
|
94 | case, there is little to gain by limiting the free library to free | |||
|
95 | software only, so we use the Lesser General Public License. | |||
|
96 | ||||
|
97 | In other cases, permission to use a particular library in non-free | |||
|
98 | programs enables a greater number of people to use a large body of | |||
|
99 | free software. For example, permission to use the GNU C Library in | |||
|
100 | non-free programs enables many more people to use the whole GNU | |||
|
101 | operating system, as well as its variant, the GNU/Linux operating | |||
|
102 | system. | |||
|
103 | ||||
|
104 | Although the Lesser General Public License is Less protective of the | |||
|
105 | users' freedom, it does ensure that the user of a program that is | |||
|
106 | linked with the Library has the freedom and the wherewithal to run | |||
|
107 | that program using a modified version of the Library. | |||
|
108 | ||||
|
109 | The precise terms and conditions for copying, distribution and | |||
|
110 | modification follow. Pay close attention to the difference between a | |||
|
111 | "work based on the library" and a "work that uses the library". The | |||
|
112 | former contains code derived from the library, whereas the latter must | |||
|
113 | be combined with the library in order to run. | |||
|
114 | ||||
|
115 | GNU LESSER GENERAL PUBLIC LICENSE | |||
|
116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
|
117 | ||||
|
118 | 0. This License Agreement applies to any software library or other | |||
|
119 | program which contains a notice placed by the copyright holder or | |||
|
120 | other authorized party saying it may be distributed under the terms of | |||
|
121 | this Lesser General Public License (also called "this License"). | |||
|
122 | Each licensee is addressed as "you". | |||
|
123 | ||||
|
124 | A "library" means a collection of software functions and/or data | |||
|
125 | prepared so as to be conveniently linked with application programs | |||
|
126 | (which use some of those functions and data) to form executables. | |||
|
127 | ||||
|
128 | The "Library", below, refers to any such software library or work | |||
|
129 | which has been distributed under these terms. A "work based on the | |||
|
130 | Library" means either the Library or any derivative work under | |||
|
131 | copyright law: that is to say, a work containing the Library or a | |||
|
132 | portion of it, either verbatim or with modifications and/or translated | |||
|
133 | straightforwardly into another language. (Hereinafter, translation is | |||
|
134 | included without limitation in the term "modification".) | |||
|
135 | ||||
|
136 | "Source code" for a work means the preferred form of the work for | |||
|
137 | making modifications to it. For a library, complete source code means | |||
|
138 | all the source code for all modules it contains, plus any associated | |||
|
139 | interface definition files, plus the scripts used to control compilation | |||
|
140 | and installation of the library. | |||
|
141 | ||||
|
142 | Activities other than copying, distribution and modification are not | |||
|
143 | covered by this License; they are outside its scope. The act of | |||
|
144 | running a program using the Library is not restricted, and output from | |||
|
145 | such a program is covered only if its contents constitute a work based | |||
|
146 | on the Library (independent of the use of the Library in a tool for | |||
|
147 | writing it). Whether that is true depends on what the Library does | |||
|
148 | and what the program that uses the Library does. | |||
|
149 | ||||
|
150 | 1. You may copy and distribute verbatim copies of the Library's | |||
|
151 | complete source code as you receive it, in any medium, provided that | |||
|
152 | you conspicuously and appropriately publish on each copy an | |||
|
153 | appropriate copyright notice and disclaimer of warranty; keep intact | |||
|
154 | all the notices that refer to this License and to the absence of any | |||
|
155 | warranty; and distribute a copy of this License along with the | |||
|
156 | Library. | |||
|
157 | ||||
|
158 | You may charge a fee for the physical act of transferring a copy, | |||
|
159 | and you may at your option offer warranty protection in exchange for a | |||
|
160 | fee. | |||
|
161 | ||||
|
162 | 2. You may modify your copy or copies of the Library or any portion | |||
|
163 | of it, thus forming a work based on the Library, and copy and | |||
|
164 | distribute such modifications or work under the terms of Section 1 | |||
|
165 | above, provided that you also meet all of these conditions: | |||
|
166 | ||||
|
167 | a) The modified work must itself be a software library. | |||
|
168 | ||||
|
169 | b) You must cause the files modified to carry prominent notices | |||
|
170 | stating that you changed the files and the date of any change. | |||
|
171 | ||||
|
172 | c) You must cause the whole of the work to be licensed at no | |||
|
173 | charge to all third parties under the terms of this License. | |||
|
174 | ||||
|
175 | d) If a facility in the modified Library refers to a function or a | |||
|
176 | table of data to be supplied by an application program that uses | |||
|
177 | the facility, other than as an argument passed when the facility | |||
|
178 | is invoked, then you must make a good faith effort to ensure that, | |||
|
179 | in the event an application does not supply such function or | |||
|
180 | table, the facility still operates, and performs whatever part of | |||
|
181 | its purpose remains meaningful. | |||
|
182 | ||||
|
183 | (For example, a function in a library to compute square roots has | |||
|
184 | a purpose that is entirely well-defined independent of the | |||
|
185 | application. Therefore, Subsection 2d requires that any | |||
|
186 | application-supplied function or table used by this function must | |||
|
187 | be optional: if the application does not supply it, the square | |||
|
188 | root function must still compute square roots.) | |||
|
189 | ||||
|
190 | These requirements apply to the modified work as a whole. If | |||
|
191 | identifiable sections of that work are not derived from the Library, | |||
|
192 | and can be reasonably considered independent and separate works in | |||
|
193 | themselves, then this License, and its terms, do not apply to those | |||
|
194 | sections when you distribute them as separate works. But when you | |||
|
195 | distribute the same sections as part of a whole which is a work based | |||
|
196 | on the Library, the distribution of the whole must be on the terms of | |||
|
197 | this License, whose permissions for other licensees extend to the | |||
|
198 | entire whole, and thus to each and every part regardless of who wrote | |||
|
199 | it. | |||
|
200 | ||||
|
201 | Thus, it is not the intent of this section to claim rights or contest | |||
|
202 | your rights to work written entirely by you; rather, the intent is to | |||
|
203 | exercise the right to control the distribution of derivative or | |||
|
204 | collective works based on the Library. | |||
|
205 | ||||
|
206 | In addition, mere aggregation of another work not based on the Library | |||
|
207 | with the Library (or with a work based on the Library) on a volume of | |||
|
208 | a storage or distribution medium does not bring the other work under | |||
|
209 | the scope of this License. | |||
|
210 | ||||
|
211 | 3. You may opt to apply the terms of the ordinary GNU General Public | |||
|
212 | License instead of this License to a given copy of the Library. To do | |||
|
213 | this, you must alter all the notices that refer to this License, so | |||
|
214 | that they refer to the ordinary GNU General Public License, version 2, | |||
|
215 | instead of to this License. (If a newer version than version 2 of the | |||
|
216 | ordinary GNU General Public License has appeared, then you can specify | |||
|
217 | that version instead if you wish.) Do not make any other change in | |||
|
218 | these notices. | |||
|
219 | ||||
|
220 | Once this change is made in a given copy, it is irreversible for | |||
|
221 | that copy, so the ordinary GNU General Public License applies to all | |||
|
222 | subsequent copies and derivative works made from that copy. | |||
|
223 | ||||
|
224 | This option is useful when you wish to copy part of the code of | |||
|
225 | the Library into a program that is not a library. | |||
|
226 | ||||
|
227 | 4. You may copy and distribute the Library (or a portion or | |||
|
228 | derivative of it, under Section 2) in object code or executable form | |||
|
229 | under the terms of Sections 1 and 2 above provided that you accompany | |||
|
230 | it with the complete corresponding machine-readable source code, which | |||
|
231 | must be distributed under the terms of Sections 1 and 2 above on a | |||
|
232 | medium customarily used for software interchange. | |||
|
233 | ||||
|
234 | If distribution of object code is made by offering access to copy | |||
|
235 | from a designated place, then offering equivalent access to copy the | |||
|
236 | source code from the same place satisfies the requirement to | |||
|
237 | distribute the source code, even though third parties are not | |||
|
238 | compelled to copy the source along with the object code. | |||
|
239 | ||||
|
240 | 5. A program that contains no derivative of any portion of the | |||
|
241 | Library, but is designed to work with the Library by being compiled or | |||
|
242 | linked with it, is called a "work that uses the Library". Such a | |||
|
243 | work, in isolation, is not a derivative work of the Library, and | |||
|
244 | therefore falls outside the scope of this License. | |||
|
245 | ||||
|
246 | However, linking a "work that uses the Library" with the Library | |||
|
247 | creates an executable that is a derivative of the Library (because it | |||
|
248 | contains portions of the Library), rather than a "work that uses the | |||
|
249 | library". The executable is therefore covered by this License. | |||
|
250 | Section 6 states terms for distribution of such executables. | |||
|
251 | ||||
|
252 | When a "work that uses the Library" uses material from a header file | |||
|
253 | that is part of the Library, the object code for the work may be a | |||
|
254 | derivative work of the Library even though the source code is not. | |||
|
255 | Whether this is true is especially significant if the work can be | |||
|
256 | linked without the Library, or if the work is itself a library. The | |||
|
257 | threshold for this to be true is not precisely defined by law. | |||
|
258 | ||||
|
259 | If such an object file uses only numerical parameters, data | |||
|
260 | structure layouts and accessors, and small macros and small inline | |||
|
261 | functions (ten lines or less in length), then the use of the object | |||
|
262 | file is unrestricted, regardless of whether it is legally a derivative | |||
|
263 | work. (Executables containing this object code plus portions of the | |||
|
264 | Library will still fall under Section 6.) | |||
|
265 | ||||
|
266 | Otherwise, if the work is a derivative of the Library, you may | |||
|
267 | distribute the object code for the work under the terms of Section 6. | |||
|
268 | Any executables containing that work also fall under Section 6, | |||
|
269 | whether or not they are linked directly with the Library itself. | |||
|
270 | ||||
|
271 | 6. As an exception to the Sections above, you may also combine or | |||
|
272 | link a "work that uses the Library" with the Library to produce a | |||
|
273 | work containing portions of the Library, and distribute that work | |||
|
274 | under terms of your choice, provided that the terms permit | |||
|
275 | modification of the work for the customer's own use and reverse | |||
|
276 | engineering for debugging such modifications. | |||
|
277 | ||||
|
278 | You must give prominent notice with each copy of the work that the | |||
|
279 | Library is used in it and that the Library and its use are covered by | |||
|
280 | this License. You must supply a copy of this License. If the work | |||
|
281 | during execution displays copyright notices, you must include the | |||
|
282 | copyright notice for the Library among them, as well as a reference | |||
|
283 | directing the user to the copy of this License. Also, you must do one | |||
|
284 | of these things: | |||
|
285 | ||||
|
286 | a) Accompany the work with the complete corresponding | |||
|
287 | machine-readable source code for the Library including whatever | |||
|
288 | changes were used in the work (which must be distributed under | |||
|
289 | Sections 1 and 2 above); and, if the work is an executable linked | |||
|
290 | with the Library, with the complete machine-readable "work that | |||
|
291 | uses the Library", as object code and/or source code, so that the | |||
|
292 | user can modify the Library and then relink to produce a modified | |||
|
293 | executable containing the modified Library. (It is understood | |||
|
294 | that the user who changes the contents of definitions files in the | |||
|
295 | Library will not necessarily be able to recompile the application | |||
|
296 | to use the modified definitions.) | |||
|
297 | ||||
|
298 | b) Use a suitable shared library mechanism for linking with the | |||
|
299 | Library. A suitable mechanism is one that (1) uses at run time a | |||
|
300 | copy of the library already present on the user's computer system, | |||
|
301 | rather than copying library functions into the executable, and (2) | |||
|
302 | will operate properly with a modified version of the library, if | |||
|
303 | the user installs one, as long as the modified version is | |||
|
304 | interface-compatible with the version that the work was made with. | |||
|
305 | ||||
|
306 | c) Accompany the work with a written offer, valid for at | |||
|
307 | least three years, to give the same user the materials | |||
|
308 | specified in Subsection 6a, above, for a charge no more | |||
|
309 | than the cost of performing this distribution. | |||
|
310 | ||||
|
311 | d) If distribution of the work is made by offering access to copy | |||
|
312 | from a designated place, offer equivalent access to copy the above | |||
|
313 | specified materials from the same place. | |||
|
314 | ||||
|
315 | e) Verify that the user has already received a copy of these | |||
|
316 | materials or that you have already sent this user a copy. | |||
|
317 | ||||
|
318 | For an executable, the required form of the "work that uses the | |||
|
319 | Library" must include any data and utility programs needed for | |||
|
320 | reproducing the executable from it. However, as a special exception, | |||
|
321 | the materials to be distributed need not include anything that is | |||
|
322 | normally distributed (in either source or binary form) with the major | |||
|
323 | components (compiler, kernel, and so on) of the operating system on | |||
|
324 | which the executable runs, unless that component itself accompanies | |||
|
325 | the executable. | |||
|
326 | ||||
|
327 | It may happen that this requirement contradicts the license | |||
|
328 | restrictions of other proprietary libraries that do not normally | |||
|
329 | accompany the operating system. Such a contradiction means you cannot | |||
|
330 | use both them and the Library together in an executable that you | |||
|
331 | distribute. | |||
|
332 | ||||
|
333 | 7. You may place library facilities that are a work based on the | |||
|
334 | Library side-by-side in a single library together with other library | |||
|
335 | facilities not covered by this License, and distribute such a combined | |||
|
336 | library, provided that the separate distribution of the work based on | |||
|
337 | the Library and of the other library facilities is otherwise | |||
|
338 | permitted, and provided that you do these two things: | |||
|
339 | ||||
|
340 | a) Accompany the combined library with a copy of the same work | |||
|
341 | based on the Library, uncombined with any other library | |||
|
342 | facilities. This must be distributed under the terms of the | |||
|
343 | Sections above. | |||
|
344 | ||||
|
345 | b) Give prominent notice with the combined library of the fact | |||
|
346 | that part of it is a work based on the Library, and explaining | |||
|
347 | where to find the accompanying uncombined form of the same work. | |||
|
348 | ||||
|
349 | 8. You may not copy, modify, sublicense, link with, or distribute | |||
|
350 | the Library except as expressly provided under this License. Any | |||
|
351 | attempt otherwise to copy, modify, sublicense, link with, or | |||
|
352 | distribute the Library is void, and will automatically terminate your | |||
|
353 | rights under this License. However, parties who have received copies, | |||
|
354 | or rights, from you under this License will not have their licenses | |||
|
355 | terminated so long as such parties remain in full compliance. | |||
|
356 | ||||
|
357 | 9. You are not required to accept this License, since you have not | |||
|
358 | signed it. However, nothing else grants you permission to modify or | |||
|
359 | distribute the Library or its derivative works. These actions are | |||
|
360 | prohibited by law if you do not accept this License. Therefore, by | |||
|
361 | modifying or distributing the Library (or any work based on the | |||
|
362 | Library), you indicate your acceptance of this License to do so, and | |||
|
363 | all its terms and conditions for copying, distributing or modifying | |||
|
364 | the Library or works based on it. | |||
|
365 | ||||
|
366 | 10. Each time you redistribute the Library (or any work based on the | |||
|
367 | Library), the recipient automatically receives a license from the | |||
|
368 | original licensor to copy, distribute, link with or modify the Library | |||
|
369 | subject to these terms and conditions. You may not impose any further | |||
|
370 | restrictions on the recipients' exercise of the rights granted herein. | |||
|
371 | You are not responsible for enforcing compliance by third parties with | |||
|
372 | this License. | |||
|
373 | ||||
|
374 | 11. If, as a consequence of a court judgment or allegation of patent | |||
|
375 | infringement or for any other reason (not limited to patent issues), | |||
|
376 | conditions are imposed on you (whether by court order, agreement or | |||
|
377 | otherwise) that contradict the conditions of this License, they do not | |||
|
378 | excuse you from the conditions of this License. If you cannot | |||
|
379 | distribute so as to satisfy simultaneously your obligations under this | |||
|
380 | License and any other pertinent obligations, then as a consequence you | |||
|
381 | may not distribute the Library at all. For example, if a patent | |||
|
382 | license would not permit royalty-free redistribution of the Library by | |||
|
383 | all those who receive copies directly or indirectly through you, then | |||
|
384 | the only way you could satisfy both it and this License would be to | |||
|
385 | refrain entirely from distribution of the Library. | |||
|
386 | ||||
|
387 | If any portion of this section is held invalid or unenforceable under any | |||
|
388 | particular circumstance, the balance of the section is intended to apply, | |||
|
389 | and the section as a whole is intended to apply in other circumstances. | |||
|
390 | ||||
|
391 | It is not the purpose of this section to induce you to infringe any | |||
|
392 | patents or other property right claims or to contest validity of any | |||
|
393 | such claims; this section has the sole purpose of protecting the | |||
|
394 | integrity of the free software distribution system which is | |||
|
395 | implemented by public license practices. Many people have made | |||
|
396 | generous contributions to the wide range of software distributed | |||
|
397 | through that system in reliance on consistent application of that | |||
|
398 | system; it is up to the author/donor to decide if he or she is willing | |||
|
399 | to distribute software through any other system and a licensee cannot | |||
|
400 | impose that choice. | |||
|
401 | ||||
|
402 | This section is intended to make thoroughly clear what is believed to | |||
|
403 | be a consequence of the rest of this License. | |||
|
404 | ||||
|
405 | 12. If the distribution and/or use of the Library is restricted in | |||
|
406 | certain countries either by patents or by copyrighted interfaces, the | |||
|
407 | original copyright holder who places the Library under this License may add | |||
|
408 | an explicit geographical distribution limitation excluding those countries, | |||
|
409 | so that distribution is permitted only in or among countries not thus | |||
|
410 | excluded. In such case, this License incorporates the limitation as if | |||
|
411 | written in the body of this License. | |||
|
412 | ||||
|
413 | 13. The Free Software Foundation may publish revised and/or new | |||
|
414 | versions of the Lesser General Public License from time to time. | |||
|
415 | Such new versions will be similar in spirit to the present version, | |||
|
416 | but may differ in detail to address new problems or concerns. | |||
|
417 | ||||
|
418 | Each version is given a distinguishing version number. If the Library | |||
|
419 | specifies a version number of this License which applies to it and | |||
|
420 | "any later version", you have the option of following the terms and | |||
|
421 | conditions either of that version or of any later version published by | |||
|
422 | the Free Software Foundation. If the Library does not specify a | |||
|
423 | license version number, you may choose any version ever published by | |||
|
424 | the Free Software Foundation. | |||
|
425 | ||||
|
426 | 14. If you wish to incorporate parts of the Library into other free | |||
|
427 | programs whose distribution conditions are incompatible with these, | |||
|
428 | write to the author to ask for permission. For software which is | |||
|
429 | copyrighted by the Free Software Foundation, write to the Free | |||
|
430 | Software Foundation; we sometimes make exceptions for this. Our | |||
|
431 | decision will be guided by the two goals of preserving the free status | |||
|
432 | of all derivatives of our free software and of promoting the sharing | |||
|
433 | and reuse of software generally. | |||
|
434 | ||||
|
435 | NO WARRANTY | |||
|
436 | ||||
|
437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO | |||
|
438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. | |||
|
439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | |||
|
440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY | |||
|
441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
|
443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE | |||
|
444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME | |||
|
445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |||
|
446 | ||||
|
447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN | |||
|
448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY | |||
|
449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU | |||
|
450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR | |||
|
451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE | |||
|
452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |||
|
453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |||
|
454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |||
|
455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |||
|
456 | DAMAGES. | |||
|
457 | ||||
|
458 | END OF TERMS AND CONDITIONS | |||
|
459 | ||||
|
460 | How to Apply These Terms to Your New Libraries | |||
|
461 | ||||
|
462 | If you develop a new library, and you want it to be of the greatest | |||
|
463 | possible use to the public, we recommend making it free software that | |||
|
464 | everyone can redistribute and change. You can do so by permitting | |||
|
465 | redistribution under these terms (or, alternatively, under the terms of the | |||
|
466 | ordinary General Public License). | |||
|
467 | ||||
|
468 | To apply these terms, attach the following notices to the library. It is | |||
|
469 | safest to attach them to the start of each source file to most effectively | |||
|
470 | convey the exclusion of warranty; and each file should have at least the | |||
|
471 | "copyright" line and a pointer to where the full notice is found. | |||
|
472 | ||||
|
473 | <one line to give the library's name and a brief idea of what it does.> | |||
|
474 | Copyright (C) <year> <name of author> | |||
|
475 | ||||
|
476 | This library is free software; you can redistribute it and/or | |||
|
477 | modify it under the terms of the GNU Lesser General Public | |||
|
478 | License as published by the Free Software Foundation; either | |||
|
479 | version 2.1 of the License, or (at your option) any later version. | |||
|
480 | ||||
|
481 | This library is distributed in the hope that it will be useful, | |||
|
482 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
|
484 | Lesser General Public License for more details. | |||
|
485 | ||||
|
486 | You should have received a copy of the GNU Lesser General Public | |||
|
487 | License along with this library; if not, write to the Free Software | |||
|
488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
|
489 | ||||
|
490 | Also add information on how to contact you by electronic and paper mail. | |||
|
491 | ||||
|
492 | You should also get your employer (if you work as a programmer) or your | |||
|
493 | school, if any, to sign a "copyright disclaimer" for the library, if | |||
|
494 | necessary. Here is a sample; alter the names: | |||
|
495 | ||||
|
496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the | |||
|
497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. | |||
|
498 | ||||
|
499 | <signature of Ty Coon>, 1 April 1990 | |||
|
500 | Ty Coon, President of Vice | |||
|
501 | ||||
|
502 | That's all there is to it! No newline at end of file |
@@ -0,0 +1,205 | |||||
|
1 | #include <QtGui> | |||
|
2 | ||||
|
3 | #include "qhexedit.h" | |||
|
4 | ||||
|
5 | ||||
|
6 | QHexEdit::QHexEdit(QWidget *parent) : QScrollArea(parent) | |||
|
7 | { | |||
|
8 | qHexEdit_p = new QHexEditPrivate(this); | |||
|
9 | setWidget(qHexEdit_p); | |||
|
10 | //setWidgetResizable(true); | |||
|
11 | ||||
|
12 | connect(qHexEdit_p, SIGNAL(currentAddressChanged(int)), this, SIGNAL(currentAddressChanged(int))); | |||
|
13 | connect(qHexEdit_p, SIGNAL(currentSizeChanged(int)), this, SIGNAL(currentSizeChanged(int))); | |||
|
14 | connect(qHexEdit_p, SIGNAL(dataChanged()), this, SIGNAL(dataChanged())); | |||
|
15 | connect(qHexEdit_p, SIGNAL(overwriteModeChanged(bool)), this, SIGNAL(overwriteModeChanged(bool))); | |||
|
16 | setFocusPolicy(Qt::NoFocus); | |||
|
17 | } | |||
|
18 | ||||
|
19 | int QHexEdit::indexOf(const QByteArray & ba, int from) const | |||
|
20 | { | |||
|
21 | return qHexEdit_p->indexOf(ba, from); | |||
|
22 | } | |||
|
23 | ||||
|
24 | void QHexEdit::insert(int i, const QByteArray & ba) | |||
|
25 | { | |||
|
26 | qHexEdit_p->insert(i, ba); | |||
|
27 | } | |||
|
28 | ||||
|
29 | void QHexEdit::insert(int i, char ch) | |||
|
30 | { | |||
|
31 | qHexEdit_p->insert(i, ch); | |||
|
32 | } | |||
|
33 | ||||
|
34 | int QHexEdit::lastIndexOf(const QByteArray & ba, int from) const | |||
|
35 | { | |||
|
36 | return qHexEdit_p->lastIndexOf(ba, from); | |||
|
37 | } | |||
|
38 | ||||
|
39 | void QHexEdit::remove(int pos, int len) | |||
|
40 | { | |||
|
41 | qHexEdit_p->remove(pos, len); | |||
|
42 | } | |||
|
43 | ||||
|
44 | void QHexEdit::replace( int pos, int len, const QByteArray & after) | |||
|
45 | { | |||
|
46 | qHexEdit_p->replace(pos, len, after); | |||
|
47 | } | |||
|
48 | ||||
|
49 | QString QHexEdit::toReadableString() | |||
|
50 | { | |||
|
51 | return qHexEdit_p->toRedableString(); | |||
|
52 | } | |||
|
53 | ||||
|
54 | QString QHexEdit::selectionToReadableString() | |||
|
55 | { | |||
|
56 | return qHexEdit_p->selectionToReadableString(); | |||
|
57 | } | |||
|
58 | ||||
|
59 | void QHexEdit::setAddressArea(bool addressArea) | |||
|
60 | { | |||
|
61 | qHexEdit_p->setAddressArea(addressArea); | |||
|
62 | } | |||
|
63 | ||||
|
64 | void QHexEdit::redo() | |||
|
65 | { | |||
|
66 | qHexEdit_p->redo(); | |||
|
67 | } | |||
|
68 | ||||
|
69 | void QHexEdit::undo() | |||
|
70 | { | |||
|
71 | qHexEdit_p->undo(); | |||
|
72 | } | |||
|
73 | ||||
|
74 | void QHexEdit::setAddressWidth(int addressWidth) | |||
|
75 | { | |||
|
76 | qHexEdit_p->setAddressWidth(addressWidth); | |||
|
77 | } | |||
|
78 | ||||
|
79 | void QHexEdit::setAsciiArea(bool asciiArea) | |||
|
80 | { | |||
|
81 | qHexEdit_p->setAsciiArea(asciiArea); | |||
|
82 | } | |||
|
83 | ||||
|
84 | void QHexEdit::setHighlighting(bool mode) | |||
|
85 | { | |||
|
86 | qHexEdit_p->setHighlighting(mode); | |||
|
87 | } | |||
|
88 | ||||
|
89 | void QHexEdit::setAddressOffset(int offset) | |||
|
90 | { | |||
|
91 | qHexEdit_p->setAddressOffset(offset); | |||
|
92 | } | |||
|
93 | ||||
|
94 | int QHexEdit::addressOffset() | |||
|
95 | { | |||
|
96 | return qHexEdit_p->addressOffset(); | |||
|
97 | } | |||
|
98 | ||||
|
99 | void QHexEdit::setCursorPosition(int cursorPos) | |||
|
100 | { | |||
|
101 | // cursorPos in QHexEditPrivate is the position of the textcoursor without | |||
|
102 | // blanks, means bytePos*2 | |||
|
103 | qHexEdit_p->setCursorPos(cursorPos*2); | |||
|
104 | } | |||
|
105 | ||||
|
106 | int QHexEdit::cursorPosition() | |||
|
107 | { | |||
|
108 | return qHexEdit_p->cursorPos() / 2; | |||
|
109 | } | |||
|
110 | ||||
|
111 | ||||
|
112 | void QHexEdit::setData(const QByteArray &data) | |||
|
113 | { | |||
|
114 | qHexEdit_p->setData(data); | |||
|
115 | } | |||
|
116 | ||||
|
117 | QByteArray QHexEdit::data() | |||
|
118 | { | |||
|
119 | return qHexEdit_p->data(); | |||
|
120 | } | |||
|
121 | ||||
|
122 | void QHexEdit::setAddressAreaColor(const QColor &color) | |||
|
123 | { | |||
|
124 | qHexEdit_p->setAddressAreaColor(color); | |||
|
125 | } | |||
|
126 | ||||
|
127 | QColor QHexEdit::addressAreaColor() | |||
|
128 | { | |||
|
129 | return qHexEdit_p->addressAreaColor(); | |||
|
130 | } | |||
|
131 | ||||
|
132 | void QHexEdit::setHighlightingColor(const QColor &color) | |||
|
133 | { | |||
|
134 | qHexEdit_p->setHighlightingColor(color); | |||
|
135 | } | |||
|
136 | ||||
|
137 | QColor QHexEdit::highlightingColor() | |||
|
138 | { | |||
|
139 | return qHexEdit_p->highlightingColor(); | |||
|
140 | } | |||
|
141 | ||||
|
142 | void QHexEdit::setSelectionColor(const QColor &color) | |||
|
143 | { | |||
|
144 | qHexEdit_p->setSelectionColor(color); | |||
|
145 | } | |||
|
146 | ||||
|
147 | QColor QHexEdit::selectionColor() | |||
|
148 | { | |||
|
149 | return qHexEdit_p->selectionColor(); | |||
|
150 | } | |||
|
151 | ||||
|
152 | void QHexEdit::setOverwriteMode(bool overwriteMode) | |||
|
153 | { | |||
|
154 | qHexEdit_p->setOverwriteMode(overwriteMode); | |||
|
155 | } | |||
|
156 | ||||
|
157 | bool QHexEdit::overwriteMode() | |||
|
158 | { | |||
|
159 | return qHexEdit_p->overwriteMode(); | |||
|
160 | } | |||
|
161 | ||||
|
162 | void QHexEdit::setReadOnly(bool readOnly) | |||
|
163 | { | |||
|
164 | qHexEdit_p->setReadOnly(readOnly); | |||
|
165 | } | |||
|
166 | ||||
|
167 | bool QHexEdit::isReadOnly() | |||
|
168 | { | |||
|
169 | return qHexEdit_p->isReadOnly(); | |||
|
170 | } | |||
|
171 | ||||
|
172 | void QHexEdit::setFont(const QFont &font) | |||
|
173 | { | |||
|
174 | qHexEdit_p->setFont(font); | |||
|
175 | } | |||
|
176 | ||||
|
177 | void QHexEdit::resetSelection(int pos) | |||
|
178 | { | |||
|
179 | qHexEdit_p->resetSelection(pos); | |||
|
180 | } | |||
|
181 | ||||
|
182 | void QHexEdit::resetSelection() | |||
|
183 | { | |||
|
184 | qHexEdit_p->resetSelection(); | |||
|
185 | } | |||
|
186 | ||||
|
187 | void QHexEdit::setSelection(int pos) | |||
|
188 | { | |||
|
189 | qHexEdit_p->setSelection(pos); | |||
|
190 | } | |||
|
191 | ||||
|
192 | int QHexEdit::getSelectionBegin() | |||
|
193 | { | |||
|
194 | return qHexEdit_p->getSelectionBegin(); | |||
|
195 | } | |||
|
196 | ||||
|
197 | int QHexEdit::getSelectionEnd() | |||
|
198 | { | |||
|
199 | return qHexEdit_p->getSelectionEnd(); | |||
|
200 | } | |||
|
201 | ||||
|
202 | const QFont & QHexEdit::font() const | |||
|
203 | { | |||
|
204 | return qHexEdit_p->font(); | |||
|
205 | } |
@@ -0,0 +1,243 | |||||
|
1 | #ifndef QHEXEDIT_H | |||
|
2 | #define QHEXEDIT_H | |||
|
3 | ||||
|
4 | #include <QtGui> | |||
|
5 | #include "qhexedit_p.h" | |||
|
6 | #include <QHBoxLayout> | |||
|
7 | ||||
|
8 | /** \mainpage | |||
|
9 | QHexEdit is a binary editor widget for Qt. | |||
|
10 | ||||
|
11 | \version Version 0.6.3 | |||
|
12 | \image html hexedit.png | |||
|
13 | */ | |||
|
14 | ||||
|
15 | ||||
|
16 | /*! QHexEdit is a hex editor widget written in C++ for the Qt (Qt4) framework. | |||
|
17 | It is a simple editor for binary data, just like QPlainTextEdit is for text | |||
|
18 | data. There are sip configuration files included, so it is easy to create | |||
|
19 | bindings for PyQt and you can use this widget also in python. | |||
|
20 | ||||
|
21 | QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use | |||
|
22 | the mouse or the keyboard to navigate inside the widget. If you hit the keys | |||
|
23 | (0..9, a..f) you will change the data. Changed data is highlighted and can be | |||
|
24 | accessed via data(). | |||
|
25 | ||||
|
26 | Normaly QHexEdit works in the overwrite Mode. You can set overwriteMode(false) | |||
|
27 | and insert data. In this case the size of data() increases. It is also possible | |||
|
28 | to delete bytes (del or backspace), here the size of data decreases. | |||
|
29 | ||||
|
30 | You can select data with keyboard hits or mouse movements. The copy-key will | |||
|
31 | copy the selected data into the clipboard. The cut-key copies also but delets | |||
|
32 | it afterwards. In overwrite mode, the paste function overwrites the content of | |||
|
33 | the (does not change the length) data. In insert mode, clipboard data will be | |||
|
34 | inserted. The clipboard content is expected in ASCII Hex notation. Unknown | |||
|
35 | characters will be ignored. | |||
|
36 | ||||
|
37 | QHexEdit comes with undo/redo functionality. All changes can be undone, by | |||
|
38 | pressing the undo-key (usually ctr-z). They can also be redone afterwards. | |||
|
39 | The undo/redo framework is cleared, when setData() sets up a new | |||
|
40 | content for the editor. You can search data inside the content with indexOf() | |||
|
41 | and lastIndexOf(). The replace() function is to change located subdata. This | |||
|
42 | 'replaced' data can also be undone by the undo/redo framework. | |||
|
43 | ||||
|
44 | This widget can only handle small amounts of data. The size has to be below 10 | |||
|
45 | megabytes, otherwise the scroll sliders ard not shown and you can't scroll any | |||
|
46 | more. | |||
|
47 | */ | |||
|
48 | class QHexEdit : public QScrollArea | |||
|
49 | { | |||
|
50 | Q_OBJECT | |||
|
51 | /*! Property data holds the content of QHexEdit. Call setData() to set the | |||
|
52 | content of QHexEdit, data() returns the actual content. | |||
|
53 | */ | |||
|
54 | Q_PROPERTY(QByteArray data READ data WRITE setData) | |||
|
55 | ||||
|
56 | /*! Property addressOffset is added to the Numbers of the Address Area. | |||
|
57 | A offset in the address area (left side) is sometimes usefull, whe you show | |||
|
58 | only a segment of a complete memory picture. With setAddressOffset() you set | |||
|
59 | this property - with addressOffset() you get the actual value. | |||
|
60 | */ | |||
|
61 | Q_PROPERTY(int addressOffset READ addressOffset WRITE setAddressOffset) | |||
|
62 | ||||
|
63 | /*! Property address area color sets (setAddressAreaColor()) the backgorund | |||
|
64 | color of address areas. You can also read the color (addressaAreaColor()). | |||
|
65 | */ | |||
|
66 | Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor) | |||
|
67 | ||||
|
68 | /*! Porperty cursorPosition sets or gets the position of the editor cursor | |||
|
69 | in QHexEdit. | |||
|
70 | */ | |||
|
71 | Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition) | |||
|
72 | ||||
|
73 | /*! Property highlighting color sets (setHighlightingColor()) the backgorund | |||
|
74 | color of highlighted text areas. You can also read the color | |||
|
75 | (highlightingColor()). | |||
|
76 | */ | |||
|
77 | Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor) | |||
|
78 | ||||
|
79 | /*! Property selection color sets (setSelectionColor()) the backgorund | |||
|
80 | color of selected text areas. You can also read the color | |||
|
81 | (selectionColor()). | |||
|
82 | */ | |||
|
83 | Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor) | |||
|
84 | ||||
|
85 | /*! Porperty overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode | |||
|
86 | in which the editor works. In overwrite mode the user will overwrite existing data. The | |||
|
87 | size of data will be constant. In insert mode the size will grow, when inserting | |||
|
88 | new data. | |||
|
89 | */ | |||
|
90 | Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode) | |||
|
91 | ||||
|
92 | /*! Porperty readOnly sets (setReadOnly()) or gets (isReadOnly) the mode | |||
|
93 | in which the editor works. In readonly mode the the user can only navigate | |||
|
94 | through the data and select data; modifying is not possible. This | |||
|
95 | property's default is false. | |||
|
96 | */ | |||
|
97 | Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) | |||
|
98 | ||||
|
99 | /*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/ | |||
|
100 | Q_PROPERTY(QFont font READ font WRITE setFont) | |||
|
101 | ||||
|
102 | ||||
|
103 | public: | |||
|
104 | /*! Creates an instance of QHexEdit. | |||
|
105 | \param parent Parent widget of QHexEdit. | |||
|
106 | */ | |||
|
107 | QHexEdit(QWidget *parent = 0); | |||
|
108 | ||||
|
109 | /*! Returns the index position of the first occurrence | |||
|
110 | of the byte array ba in this byte array, searching forward from index position | |||
|
111 | from. Returns -1 if ba could not be found. In addition to this functionality | |||
|
112 | of QByteArray the cursorposition is set to the end of found bytearray and | |||
|
113 | it will be selected. | |||
|
114 | ||||
|
115 | */ | |||
|
116 | int indexOf(const QByteArray & ba, int from = 0) const; | |||
|
117 | ||||
|
118 | /*! Inserts a byte array. | |||
|
119 | \param i Index position, where to insert | |||
|
120 | \param ba byte array, which is to insert | |||
|
121 | In overwrite mode, the existing data will be overwritten, in insertmode ba will be | |||
|
122 | inserted and size of data grows. | |||
|
123 | */ | |||
|
124 | void insert(int i, const QByteArray & ba); | |||
|
125 | ||||
|
126 | /*! Inserts a char. | |||
|
127 | \param i Index position, where to insert | |||
|
128 | \param ch Char, which is to insert | |||
|
129 | In overwrite mode, the existing data will be overwritten, in insertmode ba will be | |||
|
130 | inserted and size of data grows. | |||
|
131 | */ | |||
|
132 | void insert(int i, char ch); | |||
|
133 | ||||
|
134 | /*! Returns the index position of the last occurrence | |||
|
135 | of the byte array ba in this byte array, searching backwards from index position | |||
|
136 | from. Returns -1 if ba could not be found. In addition to this functionality | |||
|
137 | of QByteArray the cursorposition is set to the beginning of found bytearray and | |||
|
138 | it will be selected. | |||
|
139 | ||||
|
140 | */ | |||
|
141 | int lastIndexOf(const QByteArray & ba, int from = 0) const; | |||
|
142 | ||||
|
143 | /*! Removes len bytes from the content. | |||
|
144 | \param pos Index position, where to remove | |||
|
145 | \param len Amount of bytes to remove | |||
|
146 | In overwrite mode, the existing bytes will be overwriten with 0x00. | |||
|
147 | */ | |||
|
148 | void remove(int pos, int len=1); | |||
|
149 | ||||
|
150 | /*! Replaces len bytes from index position pos with the byte array after. | |||
|
151 | */ | |||
|
152 | void replace( int pos, int len, const QByteArray & after); | |||
|
153 | ||||
|
154 | /*! Gives back a formatted image of the content of QHexEdit | |||
|
155 | */ | |||
|
156 | QString toReadableString(); | |||
|
157 | ||||
|
158 | /*! Gives back a formatted image of the selected content of QHexEdit | |||
|
159 | */ | |||
|
160 | QString selectionToReadableString(); | |||
|
161 | ||||
|
162 | /*! \cond docNever */ | |||
|
163 | void setAddressOffset(int offset); | |||
|
164 | int addressOffset(); | |||
|
165 | void setCursorPosition(int cusorPos); | |||
|
166 | int cursorPosition(); | |||
|
167 | void setData(QByteArray const &data); | |||
|
168 | QByteArray data(); | |||
|
169 | void setAddressAreaColor(QColor const &color); | |||
|
170 | QColor addressAreaColor(); | |||
|
171 | void setHighlightingColor(QColor const &color); | |||
|
172 | QColor highlightingColor(); | |||
|
173 | void setSelectionColor(QColor const &color); | |||
|
174 | QColor selectionColor(); | |||
|
175 | void setOverwriteMode(bool); | |||
|
176 | bool overwriteMode(); | |||
|
177 | void setReadOnly(bool); | |||
|
178 | bool isReadOnly(); | |||
|
179 | const QFont &font() const; | |||
|
180 | void setFont(const QFont &); | |||
|
181 | /*! \endcond docNever */ | |||
|
182 | //Added by Alexis Jeandet to manage selection outside of qhexedit | |||
|
183 | void resetSelection(int pos); // set selectionStart and selectionEnd to pos | |||
|
184 | void resetSelection(); // set selectionEnd to selectionStart | |||
|
185 | void setSelection(int pos); // set min (if below init) or max (if greater init) | |||
|
186 | int getSelectionBegin(); | |||
|
187 | int getSelectionEnd(); | |||
|
188 | ||||
|
189 | public slots: | |||
|
190 | /*! Redoes the last operation. If there is no operation to redo, i.e. | |||
|
191 | there is no redo step in the undo/redo history, nothing happens. | |||
|
192 | */ | |||
|
193 | void redo(); | |||
|
194 | ||||
|
195 | /*! Set the minimum width of the address area. | |||
|
196 | \param addressWidth Width in characters. | |||
|
197 | */ | |||
|
198 | void setAddressWidth(int addressWidth); | |||
|
199 | ||||
|
200 | /*! Switch the address area on or off. | |||
|
201 | \param addressArea true (show it), false (hide it). | |||
|
202 | */ | |||
|
203 | void setAddressArea(bool addressArea); | |||
|
204 | ||||
|
205 | /*! Switch the ascii area on or off. | |||
|
206 | \param asciiArea true (show it), false (hide it). | |||
|
207 | */ | |||
|
208 | void setAsciiArea(bool asciiArea); | |||
|
209 | ||||
|
210 | /*! Switch the highlighting feature on or of. | |||
|
211 | \param mode true (show it), false (hide it). | |||
|
212 | */ | |||
|
213 | void setHighlighting(bool mode); | |||
|
214 | ||||
|
215 | /*! Undoes the last operation. If there is no operation to undo, i.e. | |||
|
216 | there is no undo step in the undo/redo history, nothing happens. | |||
|
217 | */ | |||
|
218 | void undo(); | |||
|
219 | ||||
|
220 | signals: | |||
|
221 | ||||
|
222 | /*! Contains the address, where the cursor is located. */ | |||
|
223 | void currentAddressChanged(int address); | |||
|
224 | ||||
|
225 | /*! Contains the size of the data to edit. */ | |||
|
226 | void currentSizeChanged(int size); | |||
|
227 | ||||
|
228 | /*! The signal is emited every time, the data is changed. */ | |||
|
229 | void dataChanged(); | |||
|
230 | ||||
|
231 | /*! The signal is emited every time, the overwrite mode is changed. */ | |||
|
232 | void overwriteModeChanged(bool state); | |||
|
233 | ||||
|
234 | private: | |||
|
235 | /*! \cond docNever */ | |||
|
236 | QHexEditPrivate *qHexEdit_p; | |||
|
237 | QHBoxLayout *layout; | |||
|
238 | QScrollArea *scrollArea; | |||
|
239 | /*! \endcond docNever */ | |||
|
240 | }; | |||
|
241 | ||||
|
242 | #endif | |||
|
243 |
This diff has been collapsed as it changes many lines, (863 lines changed) Show them Hide them | |||||
@@ -0,0 +1,863 | |||||
|
1 | #include <QtGui> | |||
|
2 | ||||
|
3 | #include "qhexedit_p.h" | |||
|
4 | #include "commands.h" | |||
|
5 | #include <QApplication> | |||
|
6 | ||||
|
7 | const int HEXCHARS_IN_LINE = 47; | |||
|
8 | const int GAP_ADR_HEX = 10; | |||
|
9 | const int GAP_HEX_ASCII = 16; | |||
|
10 | const int BYTES_PER_LINE = 16; | |||
|
11 | ||||
|
12 | QHexEditPrivate::QHexEditPrivate(QScrollArea *parent) : QWidget(parent) | |||
|
13 | { | |||
|
14 | _undoStack = new QUndoStack(this); | |||
|
15 | ||||
|
16 | _scrollArea = parent; | |||
|
17 | setAddressWidth(4); | |||
|
18 | setAddressOffset(0); | |||
|
19 | setAddressArea(true); | |||
|
20 | setAsciiArea(true); | |||
|
21 | setHighlighting(true); | |||
|
22 | setOverwriteMode(true); | |||
|
23 | setReadOnly(false); | |||
|
24 | setAddressAreaColor(QColor(0xd4, 0xd4, 0xd4, 0xff)); | |||
|
25 | setHighlightingColor(QColor(0xff, 0xff, 0x99, 0xff)); | |||
|
26 | setSelectionColor(QColor(0x6d, 0x9e, 0xff, 0xff)); | |||
|
27 | setFont(QFont("Courier", 10)); | |||
|
28 | ||||
|
29 | _size = 0; | |||
|
30 | resetSelection(0); | |||
|
31 | ||||
|
32 | setFocusPolicy(Qt::StrongFocus); | |||
|
33 | ||||
|
34 | connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor())); | |||
|
35 | _cursorTimer.setInterval(500); | |||
|
36 | _cursorTimer.start(); | |||
|
37 | } | |||
|
38 | ||||
|
39 | void QHexEditPrivate::setAddressOffset(int offset) | |||
|
40 | { | |||
|
41 | _xData.setAddressOffset(offset); | |||
|
42 | adjust(); | |||
|
43 | } | |||
|
44 | ||||
|
45 | int QHexEditPrivate::addressOffset() | |||
|
46 | { | |||
|
47 | return _xData.addressOffset(); | |||
|
48 | } | |||
|
49 | ||||
|
50 | void QHexEditPrivate::setData(const QByteArray &data) | |||
|
51 | { | |||
|
52 | _xData.setData(data); | |||
|
53 | _undoStack->clear(); | |||
|
54 | adjust(); | |||
|
55 | setCursorPos(0); | |||
|
56 | } | |||
|
57 | ||||
|
58 | QByteArray QHexEditPrivate::data() | |||
|
59 | { | |||
|
60 | return _xData.data(); | |||
|
61 | } | |||
|
62 | ||||
|
63 | void QHexEditPrivate::setAddressAreaColor(const QColor &color) | |||
|
64 | { | |||
|
65 | _addressAreaColor = color; | |||
|
66 | update(); | |||
|
67 | } | |||
|
68 | ||||
|
69 | QColor QHexEditPrivate::addressAreaColor() | |||
|
70 | { | |||
|
71 | return _addressAreaColor; | |||
|
72 | } | |||
|
73 | ||||
|
74 | void QHexEditPrivate::setHighlightingColor(const QColor &color) | |||
|
75 | { | |||
|
76 | _highlightingColor = color; | |||
|
77 | update(); | |||
|
78 | } | |||
|
79 | ||||
|
80 | QColor QHexEditPrivate::highlightingColor() | |||
|
81 | { | |||
|
82 | return _highlightingColor; | |||
|
83 | } | |||
|
84 | ||||
|
85 | void QHexEditPrivate::setSelectionColor(const QColor &color) | |||
|
86 | { | |||
|
87 | _selectionColor = color; | |||
|
88 | update(); | |||
|
89 | } | |||
|
90 | ||||
|
91 | QColor QHexEditPrivate::selectionColor() | |||
|
92 | { | |||
|
93 | return _selectionColor; | |||
|
94 | } | |||
|
95 | ||||
|
96 | void QHexEditPrivate::setReadOnly(bool readOnly) | |||
|
97 | { | |||
|
98 | _readOnly = readOnly; | |||
|
99 | } | |||
|
100 | ||||
|
101 | bool QHexEditPrivate::isReadOnly() | |||
|
102 | { | |||
|
103 | return _readOnly; | |||
|
104 | } | |||
|
105 | ||||
|
106 | XByteArray & QHexEditPrivate::xData() | |||
|
107 | { | |||
|
108 | return _xData; | |||
|
109 | } | |||
|
110 | ||||
|
111 | int QHexEditPrivate::indexOf(const QByteArray & ba, int from) | |||
|
112 | { | |||
|
113 | if (from > (_xData.data().length() - 1)) | |||
|
114 | from = _xData.data().length() - 1; | |||
|
115 | int idx = _xData.data().indexOf(ba, from); | |||
|
116 | if (idx > -1) | |||
|
117 | { | |||
|
118 | int curPos = idx*2; | |||
|
119 | setCursorPos(curPos + ba.length()*2); | |||
|
120 | resetSelection(curPos); | |||
|
121 | setSelection(curPos + ba.length()*2); | |||
|
122 | ensureVisible(); | |||
|
123 | } | |||
|
124 | return idx; | |||
|
125 | } | |||
|
126 | ||||
|
127 | void QHexEditPrivate::insert(int index, const QByteArray & ba) | |||
|
128 | { | |||
|
129 | if (ba.length() > 0) | |||
|
130 | { | |||
|
131 | if (_overwriteMode) | |||
|
132 | { | |||
|
133 | QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()); | |||
|
134 | _undoStack->push(arrayCommand); | |||
|
135 | emit dataChanged(); | |||
|
136 | } | |||
|
137 | else | |||
|
138 | { | |||
|
139 | QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::insert, index, ba, ba.length()); | |||
|
140 | _undoStack->push(arrayCommand); | |||
|
141 | emit dataChanged(); | |||
|
142 | } | |||
|
143 | } | |||
|
144 | } | |||
|
145 | ||||
|
146 | void QHexEditPrivate::insert(int index, char ch) | |||
|
147 | { | |||
|
148 | QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::insert, index, ch); | |||
|
149 | _undoStack->push(charCommand); | |||
|
150 | emit dataChanged(); | |||
|
151 | } | |||
|
152 | ||||
|
153 | int QHexEditPrivate::lastIndexOf(const QByteArray & ba, int from) | |||
|
154 | { | |||
|
155 | from -= ba.length(); | |||
|
156 | if (from < 0) | |||
|
157 | from = 0; | |||
|
158 | int idx = _xData.data().lastIndexOf(ba, from); | |||
|
159 | if (idx > -1) | |||
|
160 | { | |||
|
161 | int curPos = idx*2; | |||
|
162 | setCursorPos(curPos); | |||
|
163 | resetSelection(curPos); | |||
|
164 | setSelection(curPos + ba.length()*2); | |||
|
165 | ensureVisible(); | |||
|
166 | } | |||
|
167 | return idx; | |||
|
168 | } | |||
|
169 | ||||
|
170 | void QHexEditPrivate::remove(int index, int len) | |||
|
171 | { | |||
|
172 | if (len > 0) | |||
|
173 | { | |||
|
174 | if (len == 1) | |||
|
175 | { | |||
|
176 | if (_overwriteMode) | |||
|
177 | { | |||
|
178 | QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::replace, index, char(0)); | |||
|
179 | _undoStack->push(charCommand); | |||
|
180 | emit dataChanged(); | |||
|
181 | } | |||
|
182 | else | |||
|
183 | { | |||
|
184 | QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::remove, index, char(0)); | |||
|
185 | _undoStack->push(charCommand); | |||
|
186 | emit dataChanged(); | |||
|
187 | } | |||
|
188 | } | |||
|
189 | else | |||
|
190 | { | |||
|
191 | QByteArray ba = QByteArray(len, char(0)); | |||
|
192 | if (_overwriteMode) | |||
|
193 | { | |||
|
194 | QUndoCommand *arrayCommand = new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()); | |||
|
195 | _undoStack->push(arrayCommand); | |||
|
196 | emit dataChanged(); | |||
|
197 | } | |||
|
198 | else | |||
|
199 | { | |||
|
200 | QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::remove, index, ba, len); | |||
|
201 | _undoStack->push(arrayCommand); | |||
|
202 | emit dataChanged(); | |||
|
203 | } | |||
|
204 | } | |||
|
205 | } | |||
|
206 | } | |||
|
207 | ||||
|
208 | void QHexEditPrivate::replace(int index, char ch) | |||
|
209 | { | |||
|
210 | QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::replace, index, ch); | |||
|
211 | _undoStack->push(charCommand); | |||
|
212 | resetSelection(); | |||
|
213 | emit dataChanged(); | |||
|
214 | } | |||
|
215 | ||||
|
216 | void QHexEditPrivate::replace(int index, const QByteArray & ba) | |||
|
217 | { | |||
|
218 | QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()); | |||
|
219 | _undoStack->push(arrayCommand); | |||
|
220 | resetSelection(); | |||
|
221 | emit dataChanged(); | |||
|
222 | } | |||
|
223 | ||||
|
224 | void QHexEditPrivate::replace(int pos, int len, const QByteArray &after) | |||
|
225 | { | |||
|
226 | QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::replace, pos, after, len); | |||
|
227 | _undoStack->push(arrayCommand); | |||
|
228 | resetSelection(); | |||
|
229 | emit dataChanged(); | |||
|
230 | } | |||
|
231 | ||||
|
232 | void QHexEditPrivate::setAddressArea(bool addressArea) | |||
|
233 | { | |||
|
234 | _addressArea = addressArea; | |||
|
235 | adjust(); | |||
|
236 | ||||
|
237 | setCursorPos(_cursorPosition); | |||
|
238 | } | |||
|
239 | ||||
|
240 | void QHexEditPrivate::setAddressWidth(int addressWidth) | |||
|
241 | { | |||
|
242 | _xData.setAddressWidth(addressWidth); | |||
|
243 | ||||
|
244 | setCursorPos(_cursorPosition); | |||
|
245 | } | |||
|
246 | ||||
|
247 | void QHexEditPrivate::setAsciiArea(bool asciiArea) | |||
|
248 | { | |||
|
249 | _asciiArea = asciiArea; | |||
|
250 | adjust(); | |||
|
251 | } | |||
|
252 | ||||
|
253 | void QHexEditPrivate::setFont(const QFont &font) | |||
|
254 | { | |||
|
255 | QWidget::setFont(font); | |||
|
256 | adjust(); | |||
|
257 | } | |||
|
258 | ||||
|
259 | void QHexEditPrivate::setHighlighting(bool mode) | |||
|
260 | { | |||
|
261 | _highlighting = mode; | |||
|
262 | update(); | |||
|
263 | } | |||
|
264 | ||||
|
265 | void QHexEditPrivate::setOverwriteMode(bool overwriteMode) | |||
|
266 | { | |||
|
267 | _overwriteMode = overwriteMode; | |||
|
268 | } | |||
|
269 | ||||
|
270 | bool QHexEditPrivate::overwriteMode() | |||
|
271 | { | |||
|
272 | return _overwriteMode; | |||
|
273 | } | |||
|
274 | ||||
|
275 | void QHexEditPrivate::redo() | |||
|
276 | { | |||
|
277 | _undoStack->redo(); | |||
|
278 | emit dataChanged(); | |||
|
279 | setCursorPos(_cursorPosition); | |||
|
280 | update(); | |||
|
281 | } | |||
|
282 | ||||
|
283 | void QHexEditPrivate::undo() | |||
|
284 | { | |||
|
285 | _undoStack->undo(); | |||
|
286 | emit dataChanged(); | |||
|
287 | setCursorPos(_cursorPosition); | |||
|
288 | update(); | |||
|
289 | } | |||
|
290 | ||||
|
291 | QString QHexEditPrivate::toRedableString() | |||
|
292 | { | |||
|
293 | return _xData.toRedableString(); | |||
|
294 | } | |||
|
295 | ||||
|
296 | ||||
|
297 | QString QHexEditPrivate::selectionToReadableString() | |||
|
298 | { | |||
|
299 | return _xData.toRedableString(getSelectionBegin(), getSelectionEnd()); | |||
|
300 | } | |||
|
301 | ||||
|
302 | ||||
|
303 | ||||
|
304 | void QHexEditPrivate::keyPressEvent(QKeyEvent *event) | |||
|
305 | { | |||
|
306 | int charX = (_cursorX - _xPosHex) / _charWidth; | |||
|
307 | int posX = (charX / 3) * 2 + (charX % 3); | |||
|
308 | int posBa = (_cursorY / _charHeight) * BYTES_PER_LINE + posX / 2; | |||
|
309 | ||||
|
310 | /*****************************************************************************/ | |||
|
311 | /* Cursor movements */ | |||
|
312 | /*****************************************************************************/ | |||
|
313 | ||||
|
314 | if (event->matches(QKeySequence::MoveToNextChar)) | |||
|
315 | { | |||
|
316 | setCursorPos(_cursorPosition + 1); | |||
|
317 | resetSelection(_cursorPosition); | |||
|
318 | } | |||
|
319 | if (event->matches(QKeySequence::MoveToPreviousChar)) | |||
|
320 | { | |||
|
321 | setCursorPos(_cursorPosition - 1); | |||
|
322 | resetSelection(_cursorPosition); | |||
|
323 | } | |||
|
324 | if (event->matches(QKeySequence::MoveToEndOfLine)) | |||
|
325 | { | |||
|
326 | setCursorPos(_cursorPosition | (2 * BYTES_PER_LINE -1)); | |||
|
327 | resetSelection(_cursorPosition); | |||
|
328 | } | |||
|
329 | if (event->matches(QKeySequence::MoveToStartOfLine)) | |||
|
330 | { | |||
|
331 | setCursorPos(_cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE))); | |||
|
332 | resetSelection(_cursorPosition); | |||
|
333 | } | |||
|
334 | if (event->matches(QKeySequence::MoveToPreviousLine)) | |||
|
335 | { | |||
|
336 | setCursorPos(_cursorPosition - (2 * BYTES_PER_LINE)); | |||
|
337 | resetSelection(_cursorPosition); | |||
|
338 | } | |||
|
339 | if (event->matches(QKeySequence::MoveToNextLine)) | |||
|
340 | { | |||
|
341 | setCursorPos(_cursorPosition + (2 * BYTES_PER_LINE)); | |||
|
342 | resetSelection(_cursorPosition); | |||
|
343 | } | |||
|
344 | ||||
|
345 | if (event->matches(QKeySequence::MoveToNextPage)) | |||
|
346 | { | |||
|
347 | setCursorPos(_cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE)); | |||
|
348 | resetSelection(_cursorPosition); | |||
|
349 | } | |||
|
350 | if (event->matches(QKeySequence::MoveToPreviousPage)) | |||
|
351 | { | |||
|
352 | setCursorPos(_cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE)); | |||
|
353 | resetSelection(_cursorPosition); | |||
|
354 | } | |||
|
355 | if (event->matches(QKeySequence::MoveToEndOfDocument)) | |||
|
356 | { | |||
|
357 | setCursorPos(_xData.size() * 2); | |||
|
358 | resetSelection(_cursorPosition); | |||
|
359 | } | |||
|
360 | if (event->matches(QKeySequence::MoveToStartOfDocument)) | |||
|
361 | { | |||
|
362 | setCursorPos(0); | |||
|
363 | resetSelection(_cursorPosition); | |||
|
364 | } | |||
|
365 | ||||
|
366 | /*****************************************************************************/ | |||
|
367 | /* Select commands */ | |||
|
368 | /*****************************************************************************/ | |||
|
369 | if (event->matches(QKeySequence::SelectAll)) | |||
|
370 | { | |||
|
371 | resetSelection(0); | |||
|
372 | setSelection(2*_xData.size() + 1); | |||
|
373 | } | |||
|
374 | if (event->matches(QKeySequence::SelectNextChar)) | |||
|
375 | { | |||
|
376 | int pos = _cursorPosition + 1; | |||
|
377 | setCursorPos(pos); | |||
|
378 | setSelection(pos); | |||
|
379 | } | |||
|
380 | if (event->matches(QKeySequence::SelectPreviousChar)) | |||
|
381 | { | |||
|
382 | int pos = _cursorPosition - 1; | |||
|
383 | setSelection(pos); | |||
|
384 | setCursorPos(pos); | |||
|
385 | } | |||
|
386 | if (event->matches(QKeySequence::SelectEndOfLine)) | |||
|
387 | { | |||
|
388 | int pos = _cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)) + (2 * BYTES_PER_LINE); | |||
|
389 | setCursorPos(pos); | |||
|
390 | setSelection(pos); | |||
|
391 | } | |||
|
392 | if (event->matches(QKeySequence::SelectStartOfLine)) | |||
|
393 | { | |||
|
394 | int pos = _cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)); | |||
|
395 | setCursorPos(pos); | |||
|
396 | setSelection(pos); | |||
|
397 | } | |||
|
398 | if (event->matches(QKeySequence::SelectPreviousLine)) | |||
|
399 | { | |||
|
400 | int pos = _cursorPosition - (2 * BYTES_PER_LINE); | |||
|
401 | setCursorPos(pos); | |||
|
402 | setSelection(pos); | |||
|
403 | } | |||
|
404 | if (event->matches(QKeySequence::SelectNextLine)) | |||
|
405 | { | |||
|
406 | int pos = _cursorPosition + (2 * BYTES_PER_LINE); | |||
|
407 | setCursorPos(pos); | |||
|
408 | setSelection(pos); | |||
|
409 | } | |||
|
410 | ||||
|
411 | if (event->matches(QKeySequence::SelectNextPage)) | |||
|
412 | { | |||
|
413 | int pos = _cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE); | |||
|
414 | setCursorPos(pos); | |||
|
415 | setSelection(pos); | |||
|
416 | } | |||
|
417 | if (event->matches(QKeySequence::SelectPreviousPage)) | |||
|
418 | { | |||
|
419 | int pos = _cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE); | |||
|
420 | setCursorPos(pos); | |||
|
421 | setSelection(pos); | |||
|
422 | } | |||
|
423 | if (event->matches(QKeySequence::SelectEndOfDocument)) | |||
|
424 | { | |||
|
425 | int pos = _xData.size() * 2; | |||
|
426 | setCursorPos(pos); | |||
|
427 | setSelection(pos); | |||
|
428 | } | |||
|
429 | if (event->matches(QKeySequence::SelectStartOfDocument)) | |||
|
430 | { | |||
|
431 | int pos = 0; | |||
|
432 | setCursorPos(pos); | |||
|
433 | setSelection(pos); | |||
|
434 | } | |||
|
435 | ||||
|
436 | /*****************************************************************************/ | |||
|
437 | /* Edit Commands */ | |||
|
438 | /*****************************************************************************/ | |||
|
439 | if (!_readOnly) | |||
|
440 | { | |||
|
441 | /* Hex input */ | |||
|
442 | int key = int(event->text()[0].toLatin1()); | |||
|
443 | if ((key>='0' && key<='9') || (key>='a' && key <= 'f')) | |||
|
444 | { | |||
|
445 | if (getSelectionBegin() != getSelectionEnd()) | |||
|
446 | { | |||
|
447 | posBa = getSelectionBegin(); | |||
|
448 | remove(posBa, getSelectionEnd() - posBa); | |||
|
449 | setCursorPos(2*posBa); | |||
|
450 | resetSelection(2*posBa); | |||
|
451 | } | |||
|
452 | ||||
|
453 | // If insert mode, then insert a byte | |||
|
454 | if (_overwriteMode == false) | |||
|
455 | if ((charX % 3) == 0) | |||
|
456 | { | |||
|
457 | insert(posBa, char(0)); | |||
|
458 | } | |||
|
459 | ||||
|
460 | // Change content | |||
|
461 | if (_xData.size() > 0) | |||
|
462 | { | |||
|
463 | QByteArray hexValue = _xData.data().mid(posBa, 1).toHex(); | |||
|
464 | if ((charX % 3) == 0) | |||
|
465 | hexValue[0] = key; | |||
|
466 | else | |||
|
467 | hexValue[1] = key; | |||
|
468 | ||||
|
469 | replace(posBa, QByteArray().fromHex(hexValue)[0]); | |||
|
470 | ||||
|
471 | setCursorPos(_cursorPosition + 1); | |||
|
472 | resetSelection(_cursorPosition); | |||
|
473 | } | |||
|
474 | } | |||
|
475 | ||||
|
476 | /* Cut & Paste */ | |||
|
477 | if (event->matches(QKeySequence::Cut)) | |||
|
478 | { | |||
|
479 | QString result = QString(); | |||
|
480 | for (int idx = getSelectionBegin(); idx < getSelectionEnd(); idx++) | |||
|
481 | { | |||
|
482 | result += _xData.data().mid(idx, 1).toHex() + " "; | |||
|
483 | if ((idx % 16) == 15) | |||
|
484 | result.append("\n"); | |||
|
485 | } | |||
|
486 | remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); | |||
|
487 | QClipboard *clipboard = QApplication::clipboard(); | |||
|
488 | clipboard->setText(result); | |||
|
489 | setCursorPos(getSelectionBegin()); | |||
|
490 | resetSelection(getSelectionBegin()); | |||
|
491 | } | |||
|
492 | ||||
|
493 | if (event->matches(QKeySequence::Paste)) | |||
|
494 | { | |||
|
495 | QClipboard *clipboard = QApplication::clipboard(); | |||
|
496 | QByteArray ba = QByteArray().fromHex(clipboard->text().toLatin1()); | |||
|
497 | insert(_cursorPosition / 2, ba); | |||
|
498 | setCursorPos(_cursorPosition + 2 * ba.length()); | |||
|
499 | resetSelection(getSelectionBegin()); | |||
|
500 | } | |||
|
501 | ||||
|
502 | ||||
|
503 | /* Delete char */ | |||
|
504 | if (event->matches(QKeySequence::Delete)) | |||
|
505 | { | |||
|
506 | if (getSelectionBegin() != getSelectionEnd()) | |||
|
507 | { | |||
|
508 | posBa = getSelectionBegin(); | |||
|
509 | remove(posBa, getSelectionEnd() - posBa); | |||
|
510 | setCursorPos(2*posBa); | |||
|
511 | resetSelection(2*posBa); | |||
|
512 | } | |||
|
513 | else | |||
|
514 | { | |||
|
515 | if (_overwriteMode) | |||
|
516 | replace(posBa, char(0)); | |||
|
517 | else | |||
|
518 | remove(posBa, 1); | |||
|
519 | } | |||
|
520 | } | |||
|
521 | ||||
|
522 | /* Backspace */ | |||
|
523 | if ((event->key() == Qt::Key_Backspace) && (event->modifiers() == Qt::NoModifier)) | |||
|
524 | { | |||
|
525 | if (getSelectionBegin() != getSelectionEnd()) | |||
|
526 | { | |||
|
527 | posBa = getSelectionBegin(); | |||
|
528 | remove(posBa, getSelectionEnd() - posBa); | |||
|
529 | setCursorPos(2*posBa); | |||
|
530 | resetSelection(2*posBa); | |||
|
531 | } | |||
|
532 | else | |||
|
533 | { | |||
|
534 | if (posBa > 0) | |||
|
535 | { | |||
|
536 | if (_overwriteMode) | |||
|
537 | replace(posBa - 1, char(0)); | |||
|
538 | else | |||
|
539 | remove(posBa - 1, 1); | |||
|
540 | setCursorPos(_cursorPosition - 2); | |||
|
541 | } | |||
|
542 | } | |||
|
543 | } | |||
|
544 | ||||
|
545 | /* undo */ | |||
|
546 | if (event->matches(QKeySequence::Undo)) | |||
|
547 | { | |||
|
548 | undo(); | |||
|
549 | } | |||
|
550 | ||||
|
551 | /* redo */ | |||
|
552 | if (event->matches(QKeySequence::Redo)) | |||
|
553 | { | |||
|
554 | redo(); | |||
|
555 | } | |||
|
556 | ||||
|
557 | } | |||
|
558 | ||||
|
559 | if (event->matches(QKeySequence::Copy)) | |||
|
560 | { | |||
|
561 | QString result = QString(); | |||
|
562 | for (int idx = getSelectionBegin(); idx < getSelectionEnd(); idx++) | |||
|
563 | { | |||
|
564 | result += _xData.data().mid(idx, 1).toHex() + " "; | |||
|
565 | if ((idx % 16) == 15) | |||
|
566 | result.append('\n'); | |||
|
567 | } | |||
|
568 | QClipboard *clipboard = QApplication::clipboard(); | |||
|
569 | clipboard->setText(result); | |||
|
570 | } | |||
|
571 | ||||
|
572 | // Switch between insert/overwrite mode | |||
|
573 | if ((event->key() == Qt::Key_Insert) && (event->modifiers() == Qt::NoModifier)) | |||
|
574 | { | |||
|
575 | _overwriteMode = !_overwriteMode; | |||
|
576 | setCursorPos(_cursorPosition); | |||
|
577 | overwriteModeChanged(_overwriteMode); | |||
|
578 | } | |||
|
579 | ||||
|
580 | ensureVisible(); | |||
|
581 | update(); | |||
|
582 | } | |||
|
583 | ||||
|
584 | void QHexEditPrivate::mouseMoveEvent(QMouseEvent * event) | |||
|
585 | { | |||
|
586 | _blink = false; | |||
|
587 | update(); | |||
|
588 | int actPos = cursorPos(event->pos()); | |||
|
589 | setCursorPos(actPos); | |||
|
590 | setSelection(actPos); | |||
|
591 | } | |||
|
592 | ||||
|
593 | void QHexEditPrivate::mousePressEvent(QMouseEvent * event) | |||
|
594 | { | |||
|
595 | _blink = false; | |||
|
596 | update(); | |||
|
597 | int cPos = cursorPos(event->pos()); | |||
|
598 | resetSelection(cPos); | |||
|
599 | setCursorPos(cPos); | |||
|
600 | } | |||
|
601 | ||||
|
602 | ||||
|
603 | ||||
|
604 | void QHexEditPrivate::paintEvent(QPaintEvent *event) | |||
|
605 | { | |||
|
606 | QPainter painter(this); | |||
|
607 | ||||
|
608 | // draw some patterns if needed | |||
|
609 | painter.fillRect(event->rect(), this->palette().color(QPalette::Base)); | |||
|
610 | if (_addressArea) | |||
|
611 | painter.fillRect(QRect(_xPosAdr, event->rect().top(), _xPosHex - GAP_ADR_HEX + 2, height()), _addressAreaColor); | |||
|
612 | if (_asciiArea) | |||
|
613 | { | |||
|
614 | int linePos = _xPosAscii - (GAP_HEX_ASCII / 2); | |||
|
615 | painter.setPen(Qt::gray); | |||
|
616 | painter.drawLine(linePos, event->rect().top(), linePos, height()); | |||
|
617 | } | |||
|
618 | ||||
|
619 | painter.setPen(this->palette().color(QPalette::WindowText)); | |||
|
620 | ||||
|
621 | // calc position | |||
|
622 | int firstLineIdx = ((event->rect().top()/ _charHeight) - _charHeight) * BYTES_PER_LINE; | |||
|
623 | if (firstLineIdx < 0) | |||
|
624 | firstLineIdx = 0; | |||
|
625 | int lastLineIdx = ((event->rect().bottom() / _charHeight) + _charHeight) * BYTES_PER_LINE; | |||
|
626 | if (lastLineIdx > _xData.size()) | |||
|
627 | lastLineIdx = _xData.size(); | |||
|
628 | int yPosStart = ((firstLineIdx) / BYTES_PER_LINE) * _charHeight + _charHeight; | |||
|
629 | ||||
|
630 | // paint address area | |||
|
631 | if (_addressArea) | |||
|
632 | { | |||
|
633 | for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) | |||
|
634 | { | |||
|
635 | QString address = QString("%1") | |||
|
636 | .arg(lineIdx + _xData.addressOffset(), _xData.realAddressNumbers(), 16, QChar('0')); | |||
|
637 | painter.drawText(_xPosAdr, yPos, address); | |||
|
638 | } | |||
|
639 | } | |||
|
640 | ||||
|
641 | // paint hex area | |||
|
642 | QByteArray hexBa(_xData.data().mid(firstLineIdx, lastLineIdx - firstLineIdx + 1).toHex()); | |||
|
643 | QBrush highLighted = QBrush(_highlightingColor); | |||
|
644 | QPen colHighlighted = QPen(this->palette().color(QPalette::WindowText)); | |||
|
645 | QBrush selected = QBrush(_selectionColor); | |||
|
646 | QPen colSelected = QPen(Qt::white); | |||
|
647 | QPen colStandard = QPen(this->palette().color(QPalette::WindowText)); | |||
|
648 | ||||
|
649 | painter.setBackgroundMode(Qt::TransparentMode); | |||
|
650 | ||||
|
651 | for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) | |||
|
652 | { | |||
|
653 | QByteArray hex; | |||
|
654 | int xPos = _xPosHex; | |||
|
655 | for (int colIdx = 0; ((lineIdx + colIdx) < _xData.size() and (colIdx < BYTES_PER_LINE)); colIdx++) | |||
|
656 | { | |||
|
657 | int posBa = lineIdx + colIdx; | |||
|
658 | if ((getSelectionBegin() <= posBa) && (getSelectionEnd() > posBa)) | |||
|
659 | { | |||
|
660 | painter.setBackground(selected); | |||
|
661 | painter.setBackgroundMode(Qt::OpaqueMode); | |||
|
662 | painter.setPen(colSelected); | |||
|
663 | } | |||
|
664 | else | |||
|
665 | { | |||
|
666 | if (_highlighting) | |||
|
667 | { | |||
|
668 | // hilight diff bytes | |||
|
669 | painter.setBackground(highLighted); | |||
|
670 | if (_xData.dataChanged(posBa)) | |||
|
671 | { | |||
|
672 | painter.setPen(colHighlighted); | |||
|
673 | painter.setBackgroundMode(Qt::OpaqueMode); | |||
|
674 | } | |||
|
675 | else | |||
|
676 | { | |||
|
677 | painter.setPen(colStandard); | |||
|
678 | painter.setBackgroundMode(Qt::TransparentMode); | |||
|
679 | } | |||
|
680 | } | |||
|
681 | } | |||
|
682 | ||||
|
683 | // render hex value | |||
|
684 | if (colIdx == 0) | |||
|
685 | { | |||
|
686 | hex = hexBa.mid((lineIdx - firstLineIdx) * 2, 2); | |||
|
687 | painter.drawText(xPos, yPos, hex); | |||
|
688 | xPos += 2 * _charWidth; | |||
|
689 | } else { | |||
|
690 | hex = hexBa.mid((lineIdx + colIdx - firstLineIdx) * 2, 2).prepend(" "); | |||
|
691 | painter.drawText(xPos, yPos, hex); | |||
|
692 | xPos += 3 * _charWidth; | |||
|
693 | } | |||
|
694 | ||||
|
695 | } | |||
|
696 | } | |||
|
697 | painter.setBackgroundMode(Qt::TransparentMode); | |||
|
698 | painter.setPen(this->palette().color(QPalette::WindowText)); | |||
|
699 | ||||
|
700 | // paint ascii area | |||
|
701 | if (_asciiArea) | |||
|
702 | { | |||
|
703 | for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) | |||
|
704 | { | |||
|
705 | int xPosAscii = _xPosAscii; | |||
|
706 | for (int colIdx = 0; ((lineIdx + colIdx) < _xData.size() and (colIdx < BYTES_PER_LINE)); colIdx++) | |||
|
707 | { | |||
|
708 | painter.drawText(xPosAscii, yPos, _xData.asciiChar(lineIdx + colIdx)); | |||
|
709 | xPosAscii += _charWidth; | |||
|
710 | } | |||
|
711 | } | |||
|
712 | } | |||
|
713 | ||||
|
714 | // paint cursor | |||
|
715 | if (_blink && !_readOnly && hasFocus()) | |||
|
716 | { | |||
|
717 | if (_overwriteMode) | |||
|
718 | painter.fillRect(_cursorX, _cursorY + _charHeight - 2, _charWidth, 2, this->palette().color(QPalette::WindowText)); | |||
|
719 | else | |||
|
720 | painter.fillRect(_cursorX, _cursorY, 2, _charHeight, this->palette().color(QPalette::WindowText)); | |||
|
721 | } | |||
|
722 | ||||
|
723 | if (_size != _xData.size()) | |||
|
724 | { | |||
|
725 | _size = _xData.size(); | |||
|
726 | emit currentSizeChanged(_size); | |||
|
727 | } | |||
|
728 | } | |||
|
729 | ||||
|
730 | void QHexEditPrivate::setCursorPos(int position) | |||
|
731 | { | |||
|
732 | // delete cursor | |||
|
733 | _blink = false; | |||
|
734 | update(); | |||
|
735 | ||||
|
736 | // cursor in range? | |||
|
737 | if (_overwriteMode) | |||
|
738 | { | |||
|
739 | if (position > (_xData.size() * 2 - 1)) | |||
|
740 | position = _xData.size() * 2 - 1; | |||
|
741 | } else { | |||
|
742 | if (position > (_xData.size() * 2)) | |||
|
743 | position = _xData.size() * 2; | |||
|
744 | } | |||
|
745 | ||||
|
746 | if (position < 0) | |||
|
747 | position = 0; | |||
|
748 | ||||
|
749 | // calc position | |||
|
750 | _cursorPosition = position; | |||
|
751 | _cursorY = (position / (2 * BYTES_PER_LINE)) * _charHeight + 4; | |||
|
752 | int x = (position % (2 * BYTES_PER_LINE)); | |||
|
753 | _cursorX = (((x / 2) * 3) + (x % 2)) * _charWidth + _xPosHex; | |||
|
754 | ||||
|
755 | // immiadately draw cursor | |||
|
756 | _blink = true; | |||
|
757 | update(); | |||
|
758 | emit currentAddressChanged(_cursorPosition/2); | |||
|
759 | } | |||
|
760 | ||||
|
761 | int QHexEditPrivate::cursorPos(QPoint pos) | |||
|
762 | { | |||
|
763 | int result = -1; | |||
|
764 | // find char under cursor | |||
|
765 | if ((pos.x() >= _xPosHex) and (pos.x() < (_xPosHex + HEXCHARS_IN_LINE * _charWidth))) | |||
|
766 | { | |||
|
767 | int x = (pos.x() - _xPosHex) / _charWidth; | |||
|
768 | if ((x % 3) == 0) | |||
|
769 | x = (x / 3) * 2; | |||
|
770 | else | |||
|
771 | x = ((x / 3) * 2) + 1; | |||
|
772 | int y = ((pos.y() - 3) / _charHeight) * 2 * BYTES_PER_LINE; | |||
|
773 | result = x + y; | |||
|
774 | } | |||
|
775 | return result; | |||
|
776 | } | |||
|
777 | ||||
|
778 | int QHexEditPrivate::cursorPos() | |||
|
779 | { | |||
|
780 | return _cursorPosition; | |||
|
781 | } | |||
|
782 | ||||
|
783 | void QHexEditPrivate::resetSelection() | |||
|
784 | { | |||
|
785 | _selectionBegin = _selectionInit; | |||
|
786 | _selectionEnd = _selectionInit; | |||
|
787 | } | |||
|
788 | ||||
|
789 | void QHexEditPrivate::resetSelection(int pos) | |||
|
790 | { | |||
|
791 | if (pos < 0) | |||
|
792 | pos = 0; | |||
|
793 | pos = pos / 2; | |||
|
794 | _selectionInit = pos; | |||
|
795 | _selectionBegin = pos; | |||
|
796 | _selectionEnd = pos; | |||
|
797 | } | |||
|
798 | ||||
|
799 | void QHexEditPrivate::setSelection(int pos) | |||
|
800 | { | |||
|
801 | if (pos < 0) | |||
|
802 | pos = 0; | |||
|
803 | pos = pos / 2; | |||
|
804 | if (pos >= _selectionInit) | |||
|
805 | { | |||
|
806 | _selectionEnd = pos; | |||
|
807 | _selectionBegin = _selectionInit; | |||
|
808 | } | |||
|
809 | else | |||
|
810 | { | |||
|
811 | _selectionBegin = pos; | |||
|
812 | _selectionEnd = _selectionInit; | |||
|
813 | } | |||
|
814 | } | |||
|
815 | ||||
|
816 | int QHexEditPrivate::getSelectionBegin() | |||
|
817 | { | |||
|
818 | return _selectionBegin; | |||
|
819 | } | |||
|
820 | ||||
|
821 | int QHexEditPrivate::getSelectionEnd() | |||
|
822 | { | |||
|
823 | return _selectionEnd; | |||
|
824 | } | |||
|
825 | ||||
|
826 | ||||
|
827 | void QHexEditPrivate::updateCursor() | |||
|
828 | { | |||
|
829 | if (_blink) | |||
|
830 | _blink = false; | |||
|
831 | else | |||
|
832 | _blink = true; | |||
|
833 | update(_cursorX, _cursorY, _charWidth, _charHeight); | |||
|
834 | } | |||
|
835 | ||||
|
836 | void QHexEditPrivate::adjust() | |||
|
837 | { | |||
|
838 | _charWidth = fontMetrics().width(QLatin1Char('9')); | |||
|
839 | _charHeight = fontMetrics().height(); | |||
|
840 | ||||
|
841 | _xPosAdr = 0; | |||
|
842 | if (_addressArea) | |||
|
843 | _xPosHex = _xData.realAddressNumbers()*_charWidth + GAP_ADR_HEX; | |||
|
844 | else | |||
|
845 | _xPosHex = 0; | |||
|
846 | _xPosAscii = _xPosHex + HEXCHARS_IN_LINE * _charWidth + GAP_HEX_ASCII; | |||
|
847 | ||||
|
848 | // tell QAbstractScollbar, how big we are | |||
|
849 | setMinimumHeight(((_xData.size()/16 + 1) * _charHeight) + 5); | |||
|
850 | if(_asciiArea) | |||
|
851 | setMinimumWidth(_xPosAscii + (BYTES_PER_LINE * _charWidth)); | |||
|
852 | else | |||
|
853 | setMinimumWidth(_xPosHex + HEXCHARS_IN_LINE * _charWidth); | |||
|
854 | ||||
|
855 | update(); | |||
|
856 | } | |||
|
857 | ||||
|
858 | void QHexEditPrivate::ensureVisible() | |||
|
859 | { | |||
|
860 | // scrolls to cursorx, cusory (which are set by setCursorPos) | |||
|
861 | // x-margin is 3 pixels, y-margin is half of charHeight | |||
|
862 | _scrollArea->ensureVisible(_cursorX, _cursorY + _charHeight/2, 3, _charHeight/2 + 2); | |||
|
863 | } |
@@ -0,0 +1,132 | |||||
|
1 | #ifndef QHEXEDIT_P_H | |||
|
2 | #define QHEXEDIT_P_H | |||
|
3 | ||||
|
4 | /** \cond docNever */ | |||
|
5 | ||||
|
6 | ||||
|
7 | #include <QtGui> | |||
|
8 | #include "xbytearray.h" | |||
|
9 | #include <QWidget> | |||
|
10 | #include <QObject> | |||
|
11 | #include <QScrollArea> | |||
|
12 | #include <QUndoStack> | |||
|
13 | ||||
|
14 | ||||
|
15 | class QHexEditPrivate : public QWidget | |||
|
16 | { | |||
|
17 | Q_OBJECT | |||
|
18 | ||||
|
19 | public: | |||
|
20 | QHexEditPrivate(QScrollArea *parent); | |||
|
21 | ||||
|
22 | void setAddressAreaColor(QColor const &color); | |||
|
23 | QColor addressAreaColor(); | |||
|
24 | ||||
|
25 | void setAddressOffset(int offset); | |||
|
26 | int addressOffset(); | |||
|
27 | ||||
|
28 | void setCursorPos(int position); | |||
|
29 | int cursorPos(); | |||
|
30 | ||||
|
31 | void setData(QByteArray const &data); | |||
|
32 | QByteArray data(); | |||
|
33 | ||||
|
34 | void setHighlightingColor(QColor const &color); | |||
|
35 | QColor highlightingColor(); | |||
|
36 | ||||
|
37 | void setOverwriteMode(bool overwriteMode); | |||
|
38 | bool overwriteMode(); | |||
|
39 | ||||
|
40 | void setReadOnly(bool readOnly); | |||
|
41 | bool isReadOnly(); | |||
|
42 | ||||
|
43 | void setSelectionColor(QColor const &color); | |||
|
44 | QColor selectionColor(); | |||
|
45 | ||||
|
46 | XByteArray & xData(); | |||
|
47 | ||||
|
48 | int indexOf(const QByteArray & ba, int from = 0); | |||
|
49 | void insert(int index, const QByteArray & ba); | |||
|
50 | void insert(int index, char ch); | |||
|
51 | int lastIndexOf(const QByteArray & ba, int from = 0); | |||
|
52 | void remove(int index, int len=1); | |||
|
53 | void replace(int index, char ch); | |||
|
54 | void replace(int index, const QByteArray & ba); | |||
|
55 | void replace(int pos, int len, const QByteArray & after); | |||
|
56 | ||||
|
57 | void setAddressArea(bool addressArea); | |||
|
58 | void setAddressWidth(int addressWidth); | |||
|
59 | void setAsciiArea(bool asciiArea); | |||
|
60 | void setHighlighting(bool mode); | |||
|
61 | virtual void setFont(const QFont &font); | |||
|
62 | ||||
|
63 | void undo(); | |||
|
64 | void redo(); | |||
|
65 | ||||
|
66 | QString toRedableString(); | |||
|
67 | QString selectionToReadableString(); | |||
|
68 | ||||
|
69 | void resetSelection(int pos); // set selectionStart and selectionEnd to pos | |||
|
70 | void resetSelection(); // set selectionEnd to selectionStart | |||
|
71 | void setSelection(int pos); // set min (if below init) or max (if greater init) | |||
|
72 | int getSelectionBegin(); | |||
|
73 | int getSelectionEnd(); | |||
|
74 | ||||
|
75 | ||||
|
76 | signals: | |||
|
77 | void currentAddressChanged(int address); | |||
|
78 | void currentSizeChanged(int size); | |||
|
79 | void dataChanged(); | |||
|
80 | void overwriteModeChanged(bool state); | |||
|
81 | ||||
|
82 | protected: | |||
|
83 | void keyPressEvent(QKeyEvent * event); | |||
|
84 | void mouseMoveEvent(QMouseEvent * event); | |||
|
85 | void mousePressEvent(QMouseEvent * event); | |||
|
86 | ||||
|
87 | void paintEvent(QPaintEvent *event); | |||
|
88 | ||||
|
89 | int cursorPos(QPoint pos); // calc cursorpos from graphics position. DOES NOT STORE POSITION | |||
|
90 | ||||
|
91 | ||||
|
92 | ||||
|
93 | private slots: | |||
|
94 | void updateCursor(); | |||
|
95 | ||||
|
96 | private: | |||
|
97 | void adjust(); | |||
|
98 | void ensureVisible(); | |||
|
99 | ||||
|
100 | QColor _addressAreaColor; | |||
|
101 | QColor _highlightingColor; | |||
|
102 | QColor _selectionColor; | |||
|
103 | QScrollArea *_scrollArea; | |||
|
104 | QTimer _cursorTimer; | |||
|
105 | QUndoStack *_undoStack; | |||
|
106 | ||||
|
107 | XByteArray _xData; // Hält den Inhalt des Hex Editors | |||
|
108 | ||||
|
109 | bool _blink; // true: then cursor blinks | |||
|
110 | bool _renderingRequired; // Flag to store that rendering is necessary | |||
|
111 | bool _addressArea; // left area of QHexEdit | |||
|
112 | bool _asciiArea; // medium area | |||
|
113 | bool _highlighting; // highlighting of changed bytes | |||
|
114 | bool _overwriteMode; | |||
|
115 | bool _readOnly; // true: the user can only look and navigate | |||
|
116 | ||||
|
117 | int _charWidth, _charHeight; // char dimensions (dpendend on font) | |||
|
118 | int _cursorX, _cursorY; // graphics position of the cursor | |||
|
119 | int _cursorPosition; // character positioin in stream (on byte ends in to steps) | |||
|
120 | int _xPosAdr, _xPosHex, _xPosAscii; // graphics x-position of the areas | |||
|
121 | ||||
|
122 | int _selectionBegin; // First selected char | |||
|
123 | int _selectionEnd; // Last selected char | |||
|
124 | int _selectionInit; // That's, where we pressed the mouse button | |||
|
125 | ||||
|
126 | int _size; | |||
|
127 | }; | |||
|
128 | ||||
|
129 | /** \endcond docNever */ | |||
|
130 | ||||
|
131 | #endif | |||
|
132 |
@@ -0,0 +1,167 | |||||
|
1 | #include "xbytearray.h" | |||
|
2 | ||||
|
3 | XByteArray::XByteArray() | |||
|
4 | { | |||
|
5 | _oldSize = -99; | |||
|
6 | _addressNumbers = 4; | |||
|
7 | _addressOffset = 0; | |||
|
8 | ||||
|
9 | } | |||
|
10 | ||||
|
11 | int XByteArray::addressOffset() | |||
|
12 | { | |||
|
13 | return _addressOffset; | |||
|
14 | } | |||
|
15 | ||||
|
16 | void XByteArray::setAddressOffset(int offset) | |||
|
17 | { | |||
|
18 | _addressOffset = offset; | |||
|
19 | } | |||
|
20 | ||||
|
21 | int XByteArray::addressWidth() | |||
|
22 | { | |||
|
23 | return _addressNumbers; | |||
|
24 | } | |||
|
25 | ||||
|
26 | void XByteArray::setAddressWidth(int width) | |||
|
27 | { | |||
|
28 | if ((width >= 0) and (width<=6)) | |||
|
29 | { | |||
|
30 | _addressNumbers = width; | |||
|
31 | } | |||
|
32 | } | |||
|
33 | ||||
|
34 | QByteArray & XByteArray::data() | |||
|
35 | { | |||
|
36 | return _data; | |||
|
37 | } | |||
|
38 | ||||
|
39 | void XByteArray::setData(QByteArray data) | |||
|
40 | { | |||
|
41 | _data = data; | |||
|
42 | _changedData = QByteArray(data.length(), char(0)); | |||
|
43 | } | |||
|
44 | ||||
|
45 | bool XByteArray::dataChanged(int i) | |||
|
46 | { | |||
|
47 | return bool(_changedData[i]); | |||
|
48 | } | |||
|
49 | ||||
|
50 | QByteArray XByteArray::dataChanged(int i, int len) | |||
|
51 | { | |||
|
52 | return _changedData.mid(i, len); | |||
|
53 | } | |||
|
54 | ||||
|
55 | void XByteArray::setDataChanged(int i, bool state) | |||
|
56 | { | |||
|
57 | _changedData[i] = char(state); | |||
|
58 | } | |||
|
59 | ||||
|
60 | void XByteArray::setDataChanged(int i, const QByteArray & state) | |||
|
61 | { | |||
|
62 | int length = state.length(); | |||
|
63 | int len; | |||
|
64 | if ((i + length) > _changedData.length()) | |||
|
65 | len = _changedData.length() - i; | |||
|
66 | else | |||
|
67 | len = length; | |||
|
68 | _changedData.replace(i, len, state); | |||
|
69 | } | |||
|
70 | ||||
|
71 | int XByteArray::realAddressNumbers() | |||
|
72 | { | |||
|
73 | if (_oldSize != _data.size()) | |||
|
74 | { | |||
|
75 | // is addressNumbers wide enought? | |||
|
76 | QString test = QString("%1") | |||
|
77 | .arg(_data.size() + _addressOffset, _addressNumbers, 16, QChar('0')); | |||
|
78 | _realAddressNumbers = test.size(); | |||
|
79 | } | |||
|
80 | return _realAddressNumbers; | |||
|
81 | } | |||
|
82 | ||||
|
83 | int XByteArray::size() | |||
|
84 | { | |||
|
85 | return _data.size(); | |||
|
86 | } | |||
|
87 | ||||
|
88 | QByteArray & XByteArray::insert(int i, char ch) | |||
|
89 | { | |||
|
90 | _data.insert(i, ch); | |||
|
91 | _changedData.insert(i, char(1)); | |||
|
92 | return _data; | |||
|
93 | } | |||
|
94 | ||||
|
95 | QByteArray & XByteArray::insert(int i, const QByteArray & ba) | |||
|
96 | { | |||
|
97 | _data.insert(i, ba); | |||
|
98 | _changedData.insert(i, QByteArray(ba.length(), char(1))); | |||
|
99 | return _data; | |||
|
100 | } | |||
|
101 | ||||
|
102 | QByteArray & XByteArray::remove(int i, int len) | |||
|
103 | { | |||
|
104 | _data.remove(i, len); | |||
|
105 | _changedData.remove(i, len); | |||
|
106 | return _data; | |||
|
107 | } | |||
|
108 | ||||
|
109 | QByteArray & XByteArray::replace(int index, char ch) | |||
|
110 | { | |||
|
111 | _data[index] = ch; | |||
|
112 | _changedData[index] = char(1); | |||
|
113 | return _data; | |||
|
114 | } | |||
|
115 | ||||
|
116 | QByteArray & XByteArray::replace(int index, const QByteArray & ba) | |||
|
117 | { | |||
|
118 | int len = ba.length(); | |||
|
119 | return replace(index, len, ba); | |||
|
120 | } | |||
|
121 | ||||
|
122 | QByteArray & XByteArray::replace(int index, int length, const QByteArray & ba) | |||
|
123 | { | |||
|
124 | int len; | |||
|
125 | if ((index + length) > _data.length()) | |||
|
126 | len = _data.length() - index; | |||
|
127 | else | |||
|
128 | len = length; | |||
|
129 | _data.replace(index, len, ba.mid(0, len)); | |||
|
130 | _changedData.replace(index, len, QByteArray(len, char(1))); | |||
|
131 | return _data; | |||
|
132 | } | |||
|
133 | ||||
|
134 | QChar XByteArray::asciiChar(int index) | |||
|
135 | { | |||
|
136 | char ch = _data[index]; | |||
|
137 | if ((ch < 0x20) or (ch > 0x7e)) | |||
|
138 | ch = '.'; | |||
|
139 | return QChar(ch); | |||
|
140 | } | |||
|
141 | ||||
|
142 | QString XByteArray::toRedableString(int start, int end) | |||
|
143 | { | |||
|
144 | int adrWidth = realAddressNumbers(); | |||
|
145 | if (_addressNumbers > adrWidth) | |||
|
146 | adrWidth = _addressNumbers; | |||
|
147 | if (end < 0) | |||
|
148 | end = _data.size(); | |||
|
149 | ||||
|
150 | QString result; | |||
|
151 | for (int i=start; i < end; i += 16) | |||
|
152 | { | |||
|
153 | QString adrStr = QString("%1").arg(_addressOffset + i, adrWidth, 16, QChar('0')); | |||
|
154 | QString hexStr; | |||
|
155 | QString ascStr; | |||
|
156 | for (int j=0; j<16; j++) | |||
|
157 | { | |||
|
158 | if ((i + j) < _data.size()) | |||
|
159 | { | |||
|
160 | hexStr.append(" ").append(_data.mid(i+j, 1).toHex()); | |||
|
161 | ascStr.append(asciiChar(i+j)); | |||
|
162 | } | |||
|
163 | } | |||
|
164 | result += adrStr + " " + QString("%1").arg(hexStr, -48) + " " + QString("%1").arg(ascStr, -17) + "\n"; | |||
|
165 | } | |||
|
166 | return result; | |||
|
167 | } |
@@ -0,0 +1,66 | |||||
|
1 | #ifndef XBYTEARRAY_H | |||
|
2 | #define XBYTEARRAY_H | |||
|
3 | ||||
|
4 | /** \cond docNever */ | |||
|
5 | ||||
|
6 | #include <QtCore> | |||
|
7 | ||||
|
8 | /*! XByteArray represents the content of QHexEcit. | |||
|
9 | XByteArray comprehend the data itself and informations to store if it was | |||
|
10 | changed. The QHexEdit component uses these informations to perform nice | |||
|
11 | rendering of the data | |||
|
12 | ||||
|
13 | XByteArray also provides some functionality to insert, replace and remove | |||
|
14 | single chars and QByteArras. Additionally some functions support rendering | |||
|
15 | and converting to readable strings. | |||
|
16 | */ | |||
|
17 | class XByteArray | |||
|
18 | { | |||
|
19 | public: | |||
|
20 | explicit XByteArray(); | |||
|
21 | ||||
|
22 | int addressOffset(); | |||
|
23 | void setAddressOffset(int offset); | |||
|
24 | ||||
|
25 | int addressWidth(); | |||
|
26 | void setAddressWidth(int width); | |||
|
27 | ||||
|
28 | QByteArray & data(); | |||
|
29 | void setData(QByteArray data); | |||
|
30 | ||||
|
31 | bool dataChanged(int i); | |||
|
32 | QByteArray dataChanged(int i, int len); | |||
|
33 | void setDataChanged(int i, bool state); | |||
|
34 | void setDataChanged(int i, const QByteArray & state); | |||
|
35 | ||||
|
36 | int realAddressNumbers(); | |||
|
37 | int size(); | |||
|
38 | ||||
|
39 | QByteArray & insert(int i, char ch); | |||
|
40 | QByteArray & insert(int i, const QByteArray & ba); | |||
|
41 | ||||
|
42 | QByteArray & remove(int pos, int len); | |||
|
43 | ||||
|
44 | QByteArray & replace(int index, char ch); | |||
|
45 | QByteArray & replace(int index, const QByteArray & ba); | |||
|
46 | QByteArray & replace(int index, int length, const QByteArray & ba); | |||
|
47 | ||||
|
48 | QChar asciiChar(int index); | |||
|
49 | QString toRedableString(int start=0, int end=-1); | |||
|
50 | ||||
|
51 | signals: | |||
|
52 | ||||
|
53 | public slots: | |||
|
54 | ||||
|
55 | private: | |||
|
56 | QByteArray _data; | |||
|
57 | QByteArray _changedData; | |||
|
58 | ||||
|
59 | int _addressNumbers; // wanted width of address area | |||
|
60 | int _addressOffset; // will be added to the real addres inside bytearray | |||
|
61 | int _realAddressNumbers; // real width of address area (can be greater then wanted width) | |||
|
62 | int _oldSize; // size of data | |||
|
63 | }; | |||
|
64 | ||||
|
65 | /** \endcond docNever */ | |||
|
66 | #endif // XBYTEARRAY_H |
General Comments 0
You need to be logged in to leave comments.
Login now