|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a widget to enter an IPv4 address. |
|
8 """ |
|
9 |
|
10 import ipaddress |
|
11 |
|
12 from PyQt6.QtCore import pyqtSignal, pyqtSlot, QRegularExpression, QEvent, Qt |
|
13 from PyQt6.QtGui import QRegularExpressionValidator |
|
14 from PyQt6.QtWidgets import QWidget |
|
15 |
|
16 from eric7.EricGui import EricPixmapCache |
|
17 |
|
18 from .Ui_EricIPv4InputWidget import Ui_EricIPv4InputWidget |
|
19 |
|
20 |
|
21 class EricIPv4InputWidget(QWidget, Ui_EricIPv4InputWidget): |
|
22 """ |
|
23 Class implementing a widget to enter an IPv4 address. |
|
24 |
|
25 @signal addressChanged() emitted to indicate a change of the entered IPv4 address |
|
26 """ |
|
27 addressChanged = pyqtSignal() |
|
28 |
|
29 def __init__(self, parent=None): |
|
30 """ |
|
31 Constructor |
|
32 |
|
33 @param parent reference to the parent widget (defaults to None) |
|
34 @type QWidget (optional) |
|
35 """ |
|
36 super().__init__(parent) |
|
37 self.setupUi(self) |
|
38 |
|
39 self.clearButton.setIcon(EricPixmapCache.getIcon("clearLeft")) |
|
40 self.clearButton.clicked.connect(self.__clear) |
|
41 |
|
42 ipRange = r"(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])" |
|
43 |
|
44 self.ip1Edit.setValidator( |
|
45 QRegularExpressionValidator(QRegularExpression(ipRange)) |
|
46 ) |
|
47 self.ip2Edit.setValidator( |
|
48 QRegularExpressionValidator(QRegularExpression(ipRange)) |
|
49 ) |
|
50 self.ip3Edit.setValidator( |
|
51 QRegularExpressionValidator(QRegularExpression(ipRange)) |
|
52 ) |
|
53 self.ip4Edit.setValidator( |
|
54 QRegularExpressionValidator(QRegularExpression(ipRange)) |
|
55 ) |
|
56 |
|
57 self.ip1Edit.installEventFilter(self) |
|
58 self.ip2Edit.installEventFilter(self) |
|
59 self.ip3Edit.installEventFilter(self) |
|
60 |
|
61 self.ip1Edit.textChanged.connect(self.addressChanged) |
|
62 self.ip2Edit.textChanged.connect(self.addressChanged) |
|
63 self.ip3Edit.textChanged.connect(self.addressChanged) |
|
64 self.ip4Edit.textChanged.connect(self.addressChanged) |
|
65 |
|
66 def eventFilter(self, obj, evt): |
|
67 """ |
|
68 Public method to filter pressing '.' to give focus to the next input field. |
|
69 |
|
70 @param obj reference to the object |
|
71 @type QObject |
|
72 @param evt reference to the event object |
|
73 @type QEvent |
|
74 """ |
|
75 if evt.type() == QEvent.Type.KeyPress: |
|
76 if evt.text() == '.': |
|
77 if obj is self.ip1Edit: |
|
78 nextWidget = self.ip2Edit |
|
79 elif obj is self.ip2Edit: |
|
80 nextWidget = self.ip3Edit |
|
81 elif obj is self.ip3Edit: |
|
82 nextWidget = self.ip4Edit |
|
83 else: |
|
84 nextWidget = None |
|
85 if nextWidget: |
|
86 nextWidget.setFocus(Qt.FocusReason.TabFocusReason) |
|
87 return True |
|
88 |
|
89 return super().eventFilter(obj, evt) |
|
90 |
|
91 def hasAcceptableInput(self): |
|
92 """ |
|
93 Public method to check, if the input is acceptable. |
|
94 |
|
95 @return flag indicating acceptable input |
|
96 @rtype bool |
|
97 """ |
|
98 try: |
|
99 ipaddress.IPv4Address(self.text()) |
|
100 except ipaddress.AddressValueError: |
|
101 # leading zeros are not allowed |
|
102 return False |
|
103 |
|
104 return ( |
|
105 self.ip1Edit.hasAcceptableInput() |
|
106 and self.ip2Edit.hasAcceptableInput() |
|
107 and self.ip3Edit.hasAcceptableInput() |
|
108 and self.ip4Edit.hasAcceptableInput() |
|
109 ) |
|
110 |
|
111 def text(self): |
|
112 """ |
|
113 Public method to get the IPv4 address as a string. |
|
114 |
|
115 @return IPv4 address |
|
116 @rtype str |
|
117 """ |
|
118 return "{0}.{1}.{2}.{3}".format( |
|
119 self.ip1Edit.text(), |
|
120 self.ip2Edit.text(), |
|
121 self.ip3Edit.text(), |
|
122 self.ip4Edit.text(), |
|
123 ) |
|
124 |
|
125 def setText(self, address): |
|
126 """ |
|
127 Public method to set the IPv4 address given a string. |
|
128 |
|
129 @param address IPv4 address |
|
130 @type str |
|
131 """ |
|
132 if address: |
|
133 try: |
|
134 ipaddress.IPv4Address(address) |
|
135 except ipaddress.AddressValueError as err: |
|
136 raise ValueError(str(err)) |
|
137 |
|
138 addressParts = address.split(".") |
|
139 self.ip1Edit.setText(addressParts[0]) |
|
140 self.ip2Edit.setText(addressParts[1]) |
|
141 self.ip3Edit.setText(addressParts[2]) |
|
142 self.ip4Edit.setText(addressParts[3]) |
|
143 else: |
|
144 self.clear() |
|
145 |
|
146 def address(self): |
|
147 """ |
|
148 Public method to get the IPv4 address as an ipaddress.IPv4Address object. |
|
149 |
|
150 @return IPv4 address |
|
151 @rtype ipaddress.IPv4Address |
|
152 """ |
|
153 try: |
|
154 return ipaddress.IPv4Address(self.text()) |
|
155 except ipaddress.AddressValueError as err: |
|
156 raise ValueError(str(err)) |
|
157 |
|
158 def setAddress(self, address): |
|
159 """ |
|
160 Public method to set the IPv4 address given an ipaddress.IPv4Address object. |
|
161 |
|
162 @param address IPv4 address |
|
163 @type ipaddress.IPv4Address |
|
164 """ |
|
165 if address: |
|
166 self.setText(str(address)) |
|
167 else: |
|
168 self.clear() |
|
169 |
|
170 @pyqtSlot() |
|
171 def clear(self): |
|
172 """ |
|
173 Public slot to clear the input fields. |
|
174 """ |
|
175 self.ip1Edit.clear() |
|
176 self.ip2Edit.clear() |
|
177 self.ip3Edit.clear() |
|
178 self.ip4Edit.clear() |
|
179 |
|
180 @pyqtSlot() |
|
181 def __clear(self): |
|
182 """ |
|
183 Private slot to handle the clear button press. |
|
184 """ |
|
185 self.clear() |
|
186 self.ip1Edit.setFocus(Qt.FocusReason.OtherFocusReason) |