src/eric7/Plugins/WizardPlugins/PyRegExpWizard/PyRegExpWizardCharactersDialog.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2004 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog for entering character classes.
8 """
9
10 from PyQt6.QtCore import QRegularExpression
11 from PyQt6.QtGui import QRegularExpressionValidator
12 from PyQt6.QtWidgets import (
13 QSizePolicy, QSpacerItem, QWidget, QHBoxLayout, QLineEdit, QPushButton,
14 QDialog, QScrollArea, QComboBox, QVBoxLayout, QLabel
15 )
16
17 from .Ui_PyRegExpWizardCharactersDialog import (
18 Ui_PyRegExpWizardCharactersDialog
19 )
20
21
22 class PyRegExpWizardCharactersDialog(
23 QDialog, Ui_PyRegExpWizardCharactersDialog):
24 """
25 Class implementing a dialog for entering character classes.
26 """
27 specialChars = {
28 4: "\\a",
29 5: "\\f",
30 6: "\\n",
31 7: "\\r",
32 8: "\\t",
33 9: "\\v"
34 }
35
36 predefinedClasses = ["\\s", "\\S", "\\w", "\\W", "\\d", "\\D"]
37
38 def __init__(self, parent=None):
39 """
40 Constructor
41
42 @param parent parent widget (QWidget)
43 """
44 super().__init__(parent)
45 self.setupUi(self)
46
47 self.comboItems = []
48 self.singleComboItems = [] # these are in addition to the above
49 self.comboItems.append(self.tr("Normal character"))
50 self.comboItems.append(
51 self.tr("Unicode character in hexadecimal notation"))
52 self.comboItems.append(
53 self.tr("Unicode character in octal notation"))
54 self.singleComboItems.append(self.tr("---"))
55 self.singleComboItems.append(self.tr("Bell character (\\a)"))
56 self.singleComboItems.append(self.tr("Page break (\\f)"))
57 self.singleComboItems.append(self.tr("Line feed (\\n)"))
58 self.singleComboItems.append(self.tr("Carriage return (\\r)"))
59 self.singleComboItems.append(self.tr("Horizontal tabulator (\\t)"))
60 self.singleComboItems.append(self.tr("Vertical tabulator (\\v)"))
61
62 self.charValidator = QRegularExpressionValidator(
63 QRegularExpression(".{0,1}"), self)
64 self.hexValidator = QRegularExpressionValidator(
65 QRegularExpression("[0-9a-fA-F]{0,4}"), self)
66 self.octValidator = QRegularExpressionValidator(
67 QRegularExpression("[0-3]?[0-7]{0,2}"), self)
68
69 # generate dialog part for single characters
70 self.singlesBoxLayout = QVBoxLayout(self.singlesBox)
71 self.singlesBoxLayout.setObjectName("singlesBoxLayout")
72 self.singlesBoxLayout.setSpacing(6)
73 self.singlesBoxLayout.setContentsMargins(6, 6, 6, 6)
74 self.singlesBox.setLayout(self.singlesBoxLayout)
75 self.singlesView = QScrollArea(self.singlesBox)
76 self.singlesView.setObjectName("singlesView")
77 self.singlesBoxLayout.addWidget(self.singlesView)
78
79 self.singlesItemsBox = QWidget(self)
80 self.singlesView.setWidget(self.singlesItemsBox)
81 self.singlesItemsBox.setObjectName("singlesItemsBox")
82 self.singlesItemsBoxLayout = QVBoxLayout(self.singlesItemsBox)
83 self.singlesItemsBoxLayout.setContentsMargins(6, 6, 6, 6)
84 self.singlesItemsBoxLayout.setSpacing(6)
85 self.singlesItemsBox.setLayout(self.singlesItemsBoxLayout)
86 self.singlesEntries = []
87 self.__addSinglesLine()
88
89 hlayout0 = QHBoxLayout()
90 hlayout0.setContentsMargins(0, 0, 0, 0)
91 hlayout0.setSpacing(6)
92 hlayout0.setObjectName("hlayout0")
93 self.moreSinglesButton = QPushButton(
94 self.tr("Additional Entries"), self.singlesBox)
95 self.moreSinglesButton.setObjectName("moreSinglesButton")
96 hlayout0.addWidget(self.moreSinglesButton)
97 hspacer0 = QSpacerItem(
98 30, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
99 hlayout0.addItem(hspacer0)
100 self.singlesBoxLayout.addLayout(hlayout0)
101 self.moreSinglesButton.clicked.connect(self.__addSinglesLine)
102
103 # generate dialog part for character ranges
104 self.rangesBoxLayout = QVBoxLayout(self.rangesBox)
105 self.rangesBoxLayout.setObjectName("rangesBoxLayout")
106 self.rangesBoxLayout.setSpacing(6)
107 self.rangesBoxLayout.setContentsMargins(6, 6, 6, 6)
108 self.rangesBox.setLayout(self.rangesBoxLayout)
109 self.rangesView = QScrollArea(self.rangesBox)
110 self.rangesView.setObjectName("rangesView")
111 self.rangesBoxLayout.addWidget(self.rangesView)
112
113 self.rangesItemsBox = QWidget(self)
114 self.rangesView.setWidget(self.rangesItemsBox)
115 self.rangesItemsBox.setObjectName("rangesItemsBox")
116 self.rangesItemsBoxLayout = QVBoxLayout(self.rangesItemsBox)
117 self.rangesItemsBoxLayout.setContentsMargins(6, 6, 6, 6)
118 self.rangesItemsBoxLayout.setSpacing(6)
119 self.rangesItemsBox.setLayout(self.rangesItemsBoxLayout)
120 self.rangesEntries = []
121 self.__addRangesLine()
122
123 hlayout1 = QHBoxLayout()
124 hlayout1.setContentsMargins(0, 0, 0, 0)
125 hlayout1.setSpacing(6)
126 hlayout1.setObjectName("hlayout1")
127 self.moreRangesButton = QPushButton(
128 self.tr("Additional Entries"), self.rangesBox)
129 self.moreSinglesButton.setObjectName("moreRangesButton")
130 hlayout1.addWidget(self.moreRangesButton)
131 hspacer1 = QSpacerItem(
132 30, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
133 hlayout1.addItem(hspacer1)
134 self.rangesBoxLayout.addLayout(hlayout1)
135 self.moreRangesButton.clicked.connect(self.__addRangesLine)
136
137 def __addSinglesLine(self):
138 """
139 Private slot to add a line of entry widgets for single characters.
140 """
141 hbox = QWidget(self.singlesItemsBox)
142 hboxLayout = QHBoxLayout(hbox)
143 hboxLayout.setContentsMargins(0, 0, 0, 0)
144 hboxLayout.setSpacing(6)
145 hbox.setLayout(hboxLayout)
146 cb1 = QComboBox(hbox)
147 cb1.setEditable(False)
148 cb1.addItems(self.comboItems)
149 cb1.addItems(self.singleComboItems)
150 hboxLayout.addWidget(cb1)
151 le1 = QLineEdit(hbox)
152 le1.setValidator(self.charValidator)
153 hboxLayout.addWidget(le1)
154 cb2 = QComboBox(hbox)
155 cb2.setEditable(False)
156 cb2.addItems(self.comboItems)
157 cb2.addItems(self.singleComboItems)
158 hboxLayout.addWidget(cb2)
159 le2 = QLineEdit(hbox)
160 le2.setValidator(self.charValidator)
161 hboxLayout.addWidget(le2)
162 self.singlesItemsBoxLayout.addWidget(hbox)
163
164 cb1.activated[int].connect(
165 lambda i: self.__singlesCharTypeSelected(i, cb1))
166 cb2.activated[int].connect(
167 lambda i: self.__singlesCharTypeSelected(i, cb2))
168 hbox.show()
169
170 self.singlesItemsBox.adjustSize()
171
172 self.singlesEntries.append([cb1, le1])
173 self.singlesEntries.append([cb2, le2])
174
175 def __addRangesLine(self):
176 """
177 Private slot to add a line of entry widgets for character ranges.
178 """
179 hbox = QWidget(self.rangesItemsBox)
180 hboxLayout = QHBoxLayout(hbox)
181 hboxLayout.setContentsMargins(0, 0, 0, 0)
182 hboxLayout.setSpacing(6)
183 hbox.setLayout(hboxLayout)
184 cb1 = QComboBox(hbox)
185 cb1.setEditable(False)
186 cb1.addItems(self.comboItems)
187 hboxLayout.addWidget(cb1)
188 l1 = QLabel(self.tr("Between:"), hbox)
189 hboxLayout.addWidget(l1)
190 le1 = QLineEdit(hbox)
191 le1.setValidator(self.charValidator)
192 hboxLayout.addWidget(le1)
193 l2 = QLabel(self.tr("And:"), hbox)
194 hboxLayout.addWidget(l2)
195 le2 = QLineEdit(hbox)
196 le2.setValidator(self.charValidator)
197 hboxLayout.addWidget(le2)
198 self.rangesItemsBoxLayout.addWidget(hbox)
199
200 cb1.activated[int].connect(
201 lambda i: self.__rangesCharTypeSelected(i, cb1))
202
203 hbox.show()
204
205 self.rangesItemsBox.adjustSize()
206
207 self.rangesEntries.append([cb1, le1, le2])
208
209 def __performSelectedAction(self, index, lineedit):
210 """
211 Private method performing some actions depending on the input.
212
213 @param index selected list index (integer)
214 @param lineedit line edit widget to act on (QLineEdit)
215 """
216 if index < 3:
217 lineedit.setEnabled(True)
218 if index == 0:
219 lineedit.setValidator(self.charValidator)
220 elif index == 1:
221 lineedit.setValidator(self.hexValidator)
222 elif index == 2:
223 lineedit.setValidator(self.octValidator)
224 elif index > 3:
225 lineedit.setEnabled(False)
226 lineedit.clear()
227
228 def __singlesCharTypeSelected(self, index, combo):
229 """
230 Private slot to handle the activated(int) signal of the single chars
231 combo boxes.
232
233 @param index selected list index
234 @type int
235 @param combo reference to the combo box
236 @type QComboBox
237 """
238 for entriesList in self.singlesEntries:
239 if combo == entriesList[0]:
240 self.__performSelectedAction(index, entriesList[1])
241 break
242
243 def __rangesCharTypeSelected(self, index, combo):
244 """
245 Private slot to handle the activated(int) signal of the char ranges
246 combo boxes.
247
248 @param index selected list index
249 @type int
250 @param combo reference to the combo box
251 @type QComboBox
252 """
253 for entriesList in self.rangesEntries:
254 if combo == entriesList[0]:
255 self.__performSelectedAction(index, entriesList[1])
256 self.__performSelectedAction(index, entriesList[2])
257 break
258
259 def __formatCharacter(self, index, char):
260 """
261 Private method to format the characters entered into the dialog.
262
263 @param index selected list index (integer)
264 @param char character string enetered into the dialog (string)
265 @return formated character string (string)
266 """
267 if index == 0:
268 return char
269 elif index == 1:
270 return "\\x{0}".format(char.lower())
271 elif index == 2:
272 return "\\0{0}".format(char)
273 else:
274 try:
275 return self.specialChars[index]
276 except KeyError:
277 return ""
278
279 def getCharacters(self):
280 """
281 Public method to return the character string assembled via the dialog.
282
283 @return formatted string for character classes (string)
284 """
285 regexp = ""
286
287 # negative character range
288 if self.negativeCheckBox.isChecked():
289 regexp += "^"
290
291 # predefined character ranges
292 if self.wordCharCheckBox.isChecked():
293 regexp += "\\w"
294 if self.nonWordCharCheckBox.isChecked():
295 regexp += "\\W"
296 if self.digitsCheckBox.isChecked():
297 regexp += "\\d"
298 if self.nonDigitsCheckBox.isChecked():
299 regexp += "\\D"
300 if self.whitespaceCheckBox.isChecked():
301 regexp += "\\s"
302 if self.nonWhitespaceCheckBox.isChecked():
303 regexp += "\\S"
304
305 # single characters
306 for entrieslist in self.singlesEntries:
307 index = entrieslist[0].currentIndex()
308 char = entrieslist[1].text()
309 regexp += self.__formatCharacter(index, char)
310
311 # character ranges
312 for entrieslist in self.rangesEntries:
313 if (
314 entrieslist[1].text() == "" or
315 entrieslist[2].text() == ""
316 ):
317 continue
318 index = entrieslist[0].currentIndex()
319 char1 = entrieslist[1].text()
320 char2 = entrieslist[2].text()
321 regexp += "{0}-{1}".format(
322 self.__formatCharacter(index, char1),
323 self.__formatCharacter(index, char2))
324
325 if regexp:
326 if (
327 (len(regexp) == 2 and
328 (regexp in self.predefinedClasses or
329 regexp in self.specialChars)) or
330 len(regexp) == 1
331 ):
332 return regexp
333 else:
334 return "[{0}]".format(regexp)
335 else:
336 return ""

eric ide

mercurial