File: numedit.py

package info (click to toggle)
convertall 0.8.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,820 kB
  • sloc: python: 2,952; makefile: 7
file content (134 lines) | stat: -rw-r--r-- 5,094 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

#****************************************************************************
# numedit.py, provides a number entry editor
#
# ConvertAll, a units conversion program
# Copyright (C) 2019, Douglas W. Bell
#
# This is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License, either Version 2 or any later
# version.  This program is distributed in the hope that it will be useful,
# but WITTHOUT ANY WARRANTY.  See the included LICENSE file for details.
#*****************************************************************************

import re
import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QValidator
from PyQt5.QtWidgets import (QLineEdit, QMessageBox)
import unitdata


class NumEdit(QLineEdit):
    """Number entry editor.
    """
    convertRqd = pyqtSignal()
    convertNum = pyqtSignal(str)
    gotFocus = pyqtSignal()
    def __init__(self, thisUnit, otherUnit, label, status, recentUnits,
                 primary, parent=None):
        super().__init__(parent)
        self.thisUnit = thisUnit
        self.otherUnit = otherUnit
        self.label = label
        self.status = status
        self.recentUnits = recentUnits
        self.primary = primary
        self.onLeft = primary
        self.setValidator(FloatExprValidator(self))
        self.setText(self.thisUnit.formatNumStr(1.0))
        self.textEdited.connect(self.convert)

    def unitUpdate(self):
        """Update the editor and labels based on a unit change.
        """
        if self.thisUnit.groupValid():
            self.label.setText(self.thisUnit.unitString())
            if self.otherUnit.groupValid():
                try:
                    self.thisUnit.reduceGroup()
                    self.otherUnit.reduceGroup()
                except unitdata.UnitDataError as text:
                    QMessageBox.warning(self, 'ConvertAll',
                                              _('Error in unit data - {0}').
                                              format(text))
                    return
                if self.thisUnit.categoryMatch(self.otherUnit):
                    self.status.setText(_('Converting...'))
                    if self.primary:
                        self.convert()
                    else:
                        self.convertRqd.emit()
                    return
                if self.onLeft:
                    self.status.setText(_('Units are not compatible '
                                          '({0}  vs.  {1})').
                                        format(self.thisUnit.compatStr(),
                                               self.otherUnit.compatStr()))
                else:
                    self.status.setText(_('Units are not compatible '
                                          '({0}  vs.  {1})').
                                        format(self.otherUnit.compatStr(),
                                               self.thisUnit.compatStr()))
            else:
                self.status.setText(_('Set units'))
        else:
            self.status.setText(_('Set units'))
            self.label.setText(_('No Unit Set'))
        self.setEnabled(False)
        self.convertNum.emit('')

    def convert(self):
        """Do conversion with self primary.
        """
        self.primary = True
        self.setEnabled(True)
        if self.onLeft:
            self.recentUnits.addEntry(self.otherUnit.unitString())
            self.recentUnits.addEntry(self.thisUnit.unitString())
        else:
            self.recentUnits.addEntry(self.thisUnit.unitString())
            self.recentUnits.addEntry(self.otherUnit.unitString())
        try:
            num = float(eval(self.text()))
        except:
            self.convertNum.emit('')
            return
        try:
            numText = self.thisUnit.convertStr(num, self.otherUnit)
            self.convertNum.emit(numText)
        except unitdata.UnitDataError as text:
            QMessageBox.warning(self, 'ConvertAll',
                                      _('Error in unit data - {0}').
                                      format(text))

    def setNum(self, numText):
        """Set text based on conversion from other number editor.
        """
        if not numText:
            self.setEnabled(False)
        else:
            self.primary = False
            self.setEnabled(True)
            self.setText(numText)

    def focusInEvent(self, event):
        """Signal that this number editor received focus.
        """
        super().focusInEvent(event)
        self.gotFocus.emit()


class FloatExprValidator(QValidator):
    """Validator for float python expressions typed into NumEdit.
    """
    invalidRe = re.compile(r'[^\d\.eE\+\-\*/\(\) ]')
    def __init__(self, parent):
        super().__init__(parent)

    def validate(self, inputStr, pos):
        """Check for valid characters in entry.
        """
        if FloatExprValidator.invalidRe.search(inputStr):
            return (QValidator.Invalid, inputStr, pos)
        return (QValidator.Acceptable, inputStr, pos)