eric6/UI/NumbersWidget.py

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

eric ide

mercurial