eric7/UI/NumbersWidget.py

branch
eric7
changeset 8312
800c432b34c8
parent 8218
7c09585bd960
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2010 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a widget to show numbers in different formats.
8 """
9
10 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QAbstractTableModel
11 from PyQt5.QtWidgets import QWidget, QHeaderView
12
13 from E5Gui.E5Application import e5App
14
15 from .Ui_NumbersWidget import Ui_NumbersWidget
16
17 import UI.PixmapCache
18
19
20 class BinaryModel(QAbstractTableModel):
21 """
22 Class implementing a model for entering binary numbers.
23 """
24 def __init__(self, parent=None):
25 """
26 Constructor
27
28 @param parent reference to the parent widget (QWidget)
29 """
30 super().__init__(parent)
31
32 self.__bits = 0
33 self.__value = 0
34
35 def rowCount(self, parent):
36 """
37 Public method to get the number of rows of the model.
38
39 @param parent parent index (QModelIndex)
40 @return number of columns (integer)
41 """
42 return 1
43
44 def columnCount(self, parent):
45 """
46 Public method to get the number of columns of the model.
47
48 @param parent parent index (QModelIndex)
49 @return number of columns (integer)
50 """
51 return self.__bits
52
53 def data(self, index, role=Qt.ItemDataRole.DisplayRole):
54 """
55 Public method to get data from the model.
56
57 @param index index to get data for (QModelIndex)
58 @param role role of the data to retrieve (integer)
59 @return requested data
60 """
61 if role == Qt.ItemDataRole.CheckStateRole:
62 return (self.__value >> (self.__bits - index.column() - 1)) & 1
63
64 elif role == Qt.ItemDataRole.DisplayRole:
65 return ""
66
67 return None
68
69 def flags(self, index):
70 """
71 Public method to get flags from the model.
72
73 @param index index to get flags for (QModelIndex)
74 @return flags (Qt.ItemFlags)
75 """
76 return (
77 Qt.ItemFlag.ItemIsUserCheckable |
78 Qt.ItemFlag.ItemIsEnabled |
79 Qt.ItemFlag.ItemIsSelectable
80 )
81
82 def headerData(self, section, orientation,
83 role=Qt.ItemDataRole.DisplayRole):
84 """
85 Public method to get header data from the model.
86
87 @param section section number (integer)
88 @param orientation orientation (Qt.Orientation)
89 @param role role of the data to retrieve (Qt.ItemDataRole)
90 @return requested data
91 """
92 if (
93 orientation == Qt.Orientation.Horizontal and
94 role == Qt.ItemDataRole.DisplayRole
95 ):
96 return str(self.__bits - section - 1)
97
98 return QAbstractTableModel.headerData(self, section, orientation, role)
99
100 def setBits(self, bits):
101 """
102 Public slot to set the number of bits.
103
104 @param bits number of bits to show (integer)
105 """
106 self.beginResetModel()
107 self.__bits = bits
108 self.endResetModel()
109
110 def setValue(self, value):
111 """
112 Public slot to set the value to show.
113
114 @param value value to show (integer)
115 """
116 self.beginResetModel()
117 self.__value = value
118 self.endResetModel()
119
120 def setBitsAndValue(self, bits, value):
121 """
122 Public slot to set the number of bits and the value to show.
123
124 @param bits number of bits to show (integer)
125 @param value value to show (integer)
126 """
127 self.__bits = bits
128 self.__value = value
129 self.beginResetModel()
130 self.endResetModel()
131
132 def getValue(self):
133 """
134 Public slot to get the current value.
135
136 @return current value of the model (integer)
137 """
138 return self.__value
139
140 def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
141 """
142 Public method to set the data of a node cell.
143
144 @param index index of the node cell (QModelIndex)
145 @param value value to be set
146 @param role role of the data (integer)
147 @return flag indicating success (boolean)
148 """
149 if role == Qt.ItemDataRole.CheckStateRole:
150 if (
151 value == Qt.CheckState.Checked and
152 not self.data(index, Qt.ItemDataRole.CheckStateRole)
153 ):
154 self.__value |= (1 << self.__bits - index.column() - 1)
155 else:
156 self.__value &= ~(1 << self.__bits - index.column() - 1)
157 self.dataChanged.emit(index, index)
158 return True
159
160 return False
161
162
163 class NumbersWidget(QWidget, Ui_NumbersWidget):
164 """
165 Class implementing a widget to show numbers in different formats.
166
167 @signal insertNumber(str) emitted after the user has entered a number
168 and selected the number format
169 """
170 insertNumber = pyqtSignal(str)
171
172 def __init__(self, parent=None):
173 """
174 Constructor
175
176 @param parent reference to the parent widget (QWidget)
177 """
178 super().__init__(parent)
179 self.setupUi(self)
180
181 self.setWindowIcon(UI.PixmapCache.getIcon("eric"))
182
183 self.__badNumberSheet = "background-color: #ffa0a0;"
184
185 self.binInButton.setIcon(UI.PixmapCache.getIcon("2downarrow"))
186 self.binOutButton.setIcon(UI.PixmapCache.getIcon("2uparrow"))
187 self.octInButton.setIcon(UI.PixmapCache.getIcon("2downarrow"))
188 self.octOutButton.setIcon(UI.PixmapCache.getIcon("2uparrow"))
189 self.decInButton.setIcon(UI.PixmapCache.getIcon("2downarrow"))
190 self.decOutButton.setIcon(UI.PixmapCache.getIcon("2uparrow"))
191 self.hexInButton.setIcon(UI.PixmapCache.getIcon("2downarrow"))
192 self.hexOutButton.setIcon(UI.PixmapCache.getIcon("2uparrow"))
193
194 self.formatBox.addItem(self.tr("Auto"), 0)
195 self.formatBox.addItem(self.tr("Dec"), 10)
196 self.formatBox.addItem(self.tr("Hex"), 16)
197 self.formatBox.addItem(self.tr("Oct"), 8)
198 self.formatBox.addItem(self.tr("Bin"), 2)
199
200 self.sizeBox.addItem("8", 8)
201 self.sizeBox.addItem("16", 16)
202 self.sizeBox.addItem("32", 32)
203 self.sizeBox.addItem("64", 64)
204
205 self.__input = 0
206 self.__inputValid = True
207 self.__bytes = 1
208
209 self.__model = BinaryModel(self)
210 self.binTable.setModel(self.__model)
211 self.binTable.horizontalHeader().setSectionResizeMode(
212 QHeaderView.ResizeMode.ResizeToContents)
213 self.__model.setBitsAndValue(self.__bytes * 8, self.__input)
214 self.__model.dataChanged.connect(self.__binModelDataChanged)
215
216 def __formatNumbers(self, numberFormat):
217 """
218 Private method to format the various number inputs.
219
220 @param numberFormat number format indicator (integer)
221 """
222 self.__block(True)
223
224 self.binEdit.setStyleSheet("")
225 self.octEdit.setStyleSheet("")
226 self.decEdit.setStyleSheet("")
227 self.hexEdit.setStyleSheet("")
228
229 # determine byte count
230 byteCount = 8
231 tmp = self.__input
232 for _ in range(8):
233 c = (tmp & 0xff00000000000000) >> 7 * 8
234 if c != 0 and self.__input >= 0:
235 break
236 if c != 0xff and self.__input < 0:
237 break
238 tmp <<= 8
239 byteCount -= 1
240 if byteCount == 0:
241 byteCount = 1
242 self.__bytes = byteCount
243
244 bytesIn = self.sizeBox.itemData(self.sizeBox.currentIndex()) // 8
245 if bytesIn and byteCount > bytesIn:
246 self.sizeBox.setStyleSheet(self.__badNumberSheet)
247 else:
248 self.sizeBox.setStyleSheet("")
249
250 # octal
251 if numberFormat != 8:
252 self.octEdit.setText("{0:0{1}o}".format(self.__input, bytesIn * 3))
253
254 # decimal
255 if numberFormat != 10:
256 self.decEdit.setText("{0:d}".format(self.__input))
257
258 # hexadecimal
259 if numberFormat != 16:
260 self.hexEdit.setText("{0:0{1}x}".format(self.__input, bytesIn * 2))
261
262 # octal
263 if numberFormat != 8:
264 self.octEdit.setText("{0:0{1}o}".format(self.__input, bytesIn * 3))
265
266 # binary
267 if numberFormat != 2:
268 num = "{0:0{1}b}".format(self.__input, bytesIn * 8)
269 self.binEdit.setText(num)
270
271 self.__model.setBitsAndValue(len(self.binEdit.text()), self.__input)
272
273 self.__block(False)
274
275 def __block(self, b):
276 """
277 Private slot to block some signals.
278
279 @param b flah indicating the blocking state (boolean)
280 """
281 self.hexEdit.blockSignals(b)
282 self.decEdit.blockSignals(b)
283 self.octEdit.blockSignals(b)
284 self.binEdit.blockSignals(b)
285 self.binTable.blockSignals(b)
286
287 @pyqtSlot(int)
288 def on_sizeBox_valueChanged(self, value):
289 """
290 Private slot handling a change of the bit size.
291
292 @param value selected bit size (integer)
293 """
294 self.__formatNumbers(10)
295
296 @pyqtSlot()
297 def on_byteOrderButton_clicked(self):
298 """
299 Private slot to swap the byte order.
300 """
301 bytesIn = self.sizeBox.itemData(self.sizeBox.currentIndex()) // 8
302 if bytesIn == 0:
303 bytesIn = self.__bytes
304
305 tmp1 = self.__input
306 tmp2 = 0
307 for _ in range(bytesIn):
308 tmp2 <<= 8
309 tmp2 |= tmp1 & 0xff
310 tmp1 >>= 8
311
312 self.__input = tmp2
313 self.__formatNumbers(0)
314
315 @pyqtSlot()
316 def on_binInButton_clicked(self):
317 """
318 Private slot to retrieve a binary number from the current editor.
319 """
320 number = e5App().getObject("ViewManager").getNumber()
321 if number == "":
322 return
323
324 self.binEdit.setText(number)
325 self.binEdit.setFocus()
326
327 @pyqtSlot(str)
328 def on_binEdit_textChanged(self, txt):
329 """
330 Private slot to handle input of a binary number.
331
332 @param txt text entered (string)
333 """
334 try:
335 self.__input = int(txt, 2)
336 self.__inputValid = True
337 except ValueError:
338 self.__inputValid = False
339
340 if self.__inputValid:
341 self.__formatNumbers(2)
342 else:
343 self.binEdit.setStyleSheet(self.__badNumberSheet)
344
345 @pyqtSlot()
346 def on_binOutButton_clicked(self):
347 """
348 Private slot to send a binary number.
349 """
350 self.insertNumber.emit(self.binEdit.text())
351
352 def __binModelDataChanged(self, start, end):
353 """
354 Private slot to handle a change of the binary model value by the user.
355
356 @param start start index (QModelIndex)
357 @param end end index (QModelIndex)
358 """
359 val = self.__model.getValue()
360 bytesIn = self.sizeBox.itemData(self.sizeBox.currentIndex()) // 8
361 num = "{0:0{1}b}".format(val, bytesIn * 8)
362 self.binEdit.setText(num)
363
364 @pyqtSlot()
365 def on_octInButton_clicked(self):
366 """
367 Private slot to retrieve an octal number from the current editor.
368 """
369 number = e5App().getObject("ViewManager").getNumber()
370 if number == "":
371 return
372
373 self.octEdit.setText(number)
374 self.octEdit.setFocus()
375
376 @pyqtSlot(str)
377 def on_octEdit_textChanged(self, txt):
378 """
379 Private slot to handle input of an octal number.
380
381 @param txt text entered (string)
382 """
383 try:
384 self.__input = int(txt, 8)
385 self.__inputValid = True
386 except ValueError:
387 self.__inputValid = False
388
389 if self.__inputValid:
390 self.__formatNumbers(8)
391 else:
392 self.octEdit.setStyleSheet(self.__badNumberSheet)
393
394 @pyqtSlot()
395 def on_octOutButton_clicked(self):
396 """
397 Private slot to send an octal number.
398 """
399 self.insertNumber.emit(self.octEdit.text())
400
401 @pyqtSlot()
402 def on_decInButton_clicked(self):
403 """
404 Private slot to retrieve a decimal number from the current editor.
405 """
406 number = e5App().getObject("ViewManager").getNumber()
407 if number == "":
408 return
409
410 self.decEdit.setText(number)
411 self.decEdit.setFocus()
412
413 @pyqtSlot(str)
414 def on_decEdit_textChanged(self, txt):
415 """
416 Private slot to handle input of a decimal number.
417
418 @param txt text entered (string)
419 """
420 try:
421 self.__input = int(txt, 10)
422 self.__inputValid = True
423 except ValueError:
424 self.__inputValid = False
425
426 if self.__inputValid:
427 self.__formatNumbers(10)
428 else:
429 self.decEdit.setStyleSheet(self.__badNumberSheet)
430
431 @pyqtSlot()
432 def on_decOutButton_clicked(self):
433 """
434 Private slot to send a decimal number.
435 """
436 self.insertNumber.emit(self.decEdit.text())
437
438 @pyqtSlot()
439 def on_hexInButton_clicked(self):
440 """
441 Private slot to retrieve a hexadecimal number from the current editor.
442 """
443 number = e5App().getObject("ViewManager").getNumber()
444 if number == "":
445 return
446
447 self.hexEdit.setText(number)
448 self.hexEdit.setFocus()
449
450 @pyqtSlot(str)
451 def on_hexEdit_textChanged(self, txt):
452 """
453 Private slot to handle input of a hexadecimal number.
454
455 @param txt text entered (string)
456 """
457 try:
458 self.__input = int(txt, 16)
459 self.__inputValid = True
460 except ValueError:
461 self.__inputValid = False
462
463 if self.__inputValid:
464 self.__formatNumbers(16)
465 else:
466 self.hexEdit.setStyleSheet(self.__badNumberSheet)
467
468 @pyqtSlot()
469 def on_hexOutButton_clicked(self):
470 """
471 Private slot to send a hexadecimal number.
472 """
473 self.insertNumber.emit(self.hexEdit.text())

eric ide

mercurial