8 """ |
8 """ |
9 |
9 |
10 from PyQt6.QtCore import QRegularExpression |
10 from PyQt6.QtCore import QRegularExpression |
11 from PyQt6.QtGui import QRegularExpressionValidator |
11 from PyQt6.QtGui import QRegularExpressionValidator |
12 from PyQt6.QtWidgets import ( |
12 from PyQt6.QtWidgets import ( |
13 QWidget, QDialog, QVBoxLayout, QHBoxLayout, QScrollArea, QPushButton, |
13 QWidget, |
14 QSpacerItem, QSizePolicy, QComboBox, QLineEdit, QLabel |
14 QDialog, |
|
15 QVBoxLayout, |
|
16 QHBoxLayout, |
|
17 QScrollArea, |
|
18 QPushButton, |
|
19 QSpacerItem, |
|
20 QSizePolicy, |
|
21 QComboBox, |
|
22 QLineEdit, |
|
23 QLabel, |
15 ) |
24 ) |
16 |
25 |
17 from .Ui_QRegularExpressionWizardCharactersDialog import ( |
26 from .Ui_QRegularExpressionWizardCharactersDialog import ( |
18 Ui_QRegularExpressionWizardCharactersDialog |
27 Ui_QRegularExpressionWizardCharactersDialog, |
19 ) |
28 ) |
20 |
29 |
21 |
30 |
22 class QRegularExpressionWizardCharactersDialog( |
31 class QRegularExpressionWizardCharactersDialog( |
23 QDialog, Ui_QRegularExpressionWizardCharactersDialog): |
32 QDialog, Ui_QRegularExpressionWizardCharactersDialog |
|
33 ): |
24 """ |
34 """ |
25 Class implementing a dialog for entering character classes. |
35 Class implementing a dialog for entering character classes. |
26 """ |
36 """ |
|
37 |
27 def __init__(self, parent=None): |
38 def __init__(self, parent=None): |
28 """ |
39 """ |
29 Constructor |
40 Constructor |
30 |
41 |
31 @param parent reference to the parent widget (QWidget) |
42 @param parent reference to the parent widget (QWidget) |
32 """ |
43 """ |
33 super().__init__(parent) |
44 super().__init__(parent) |
34 self.setupUi(self) |
45 self.setupUi(self) |
35 |
46 |
36 self.__initCharacterSelectors() |
47 self.__initCharacterSelectors() |
37 |
48 |
38 self.comboItems = [] |
49 self.comboItems = [] |
39 self.singleComboItems = [] # these are in addition to the above |
50 self.singleComboItems = [] # these are in addition to the above |
40 self.comboItems.append((self.tr("Normal character"), "-c")) |
51 self.comboItems.append((self.tr("Normal character"), "-c")) |
41 self.comboItems.append((self.tr( |
52 self.comboItems.append( |
42 "Unicode character in hexadecimal notation"), "-h")) |
53 (self.tr("Unicode character in hexadecimal notation"), "-h") |
43 self.comboItems.append((self.tr( |
54 ) |
44 "ASCII/Latin1 character in octal notation"), "-o")) |
55 self.comboItems.append( |
45 self.singleComboItems.extend([ |
56 (self.tr("ASCII/Latin1 character in octal notation"), "-o") |
46 ("---", "-i"), |
57 ) |
47 (self.tr("Bell character (\\a)"), "\\a"), |
58 self.singleComboItems.extend( |
48 (self.tr("Escape character (\\e)"), "\\e"), |
59 [ |
49 (self.tr("Page break (\\f)"), "\\f"), |
60 ("---", "-i"), |
50 (self.tr("Line feed (\\n)"), "\\n"), |
61 (self.tr("Bell character (\\a)"), "\\a"), |
51 (self.tr("Carriage return (\\r)"), "\\r"), |
62 (self.tr("Escape character (\\e)"), "\\e"), |
52 (self.tr("Horizontal tabulator (\\t)"), "\\t"), |
63 (self.tr("Page break (\\f)"), "\\f"), |
53 ("---", "-i"), |
64 (self.tr("Line feed (\\n)"), "\\n"), |
54 (self.tr("Character Category"), "-ccp"), |
65 (self.tr("Carriage return (\\r)"), "\\r"), |
55 (self.tr("Special Character Category"), "-csp"), |
66 (self.tr("Horizontal tabulator (\\t)"), "\\t"), |
56 (self.tr("Character Block"), "-cbp"), |
67 ("---", "-i"), |
57 (self.tr("POSIX Named Set"), "-psp"), |
68 (self.tr("Character Category"), "-ccp"), |
58 (self.tr("Not Character Category"), "-ccn"), |
69 (self.tr("Special Character Category"), "-csp"), |
59 (self.tr("Not Character Block"), "-cbn"), |
70 (self.tr("Character Block"), "-cbp"), |
60 (self.tr("Not Special Character Category"), "-csn"), |
71 (self.tr("POSIX Named Set"), "-psp"), |
61 (self.tr("Not POSIX Named Set"), "-psn"), |
72 (self.tr("Not Character Category"), "-ccn"), |
62 ]) |
73 (self.tr("Not Character Block"), "-cbn"), |
63 |
74 (self.tr("Not Special Character Category"), "-csn"), |
|
75 (self.tr("Not POSIX Named Set"), "-psn"), |
|
76 ] |
|
77 ) |
|
78 |
64 self.charValidator = QRegularExpressionValidator( |
79 self.charValidator = QRegularExpressionValidator( |
65 QRegularExpression(".{0,1}"), self) |
80 QRegularExpression(".{0,1}"), self |
|
81 ) |
66 self.hexValidator = QRegularExpressionValidator( |
82 self.hexValidator = QRegularExpressionValidator( |
67 QRegularExpression("[0-9a-fA-F]{0,4}"), self) |
83 QRegularExpression("[0-9a-fA-F]{0,4}"), self |
|
84 ) |
68 self.octValidator = QRegularExpressionValidator( |
85 self.octValidator = QRegularExpressionValidator( |
69 QRegularExpression("[0-3]?[0-7]{0,2}"), self) |
86 QRegularExpression("[0-3]?[0-7]{0,2}"), self |
70 |
87 ) |
|
88 |
71 # generate dialog part for single characters |
89 # generate dialog part for single characters |
72 self.singlesBoxLayout = QVBoxLayout(self.singlesBox) |
90 self.singlesBoxLayout = QVBoxLayout(self.singlesBox) |
73 self.singlesBoxLayout.setObjectName("singlesBoxLayout") |
91 self.singlesBoxLayout.setObjectName("singlesBoxLayout") |
74 self.singlesBoxLayout.setSpacing(6) |
92 self.singlesBoxLayout.setSpacing(6) |
75 self.singlesBoxLayout.setContentsMargins(6, 6, 6, 6) |
93 self.singlesBoxLayout.setContentsMargins(6, 6, 6, 6) |
76 self.singlesBox.setLayout(self.singlesBoxLayout) |
94 self.singlesBox.setLayout(self.singlesBoxLayout) |
77 self.singlesView = QScrollArea(self.singlesBox) |
95 self.singlesView = QScrollArea(self.singlesBox) |
78 self.singlesView.setObjectName("singlesView") |
96 self.singlesView.setObjectName("singlesView") |
79 self.singlesBoxLayout.addWidget(self.singlesView) |
97 self.singlesBoxLayout.addWidget(self.singlesView) |
80 |
98 |
81 self.singlesItemsBox = QWidget(self) |
99 self.singlesItemsBox = QWidget(self) |
82 self.singlesView.setWidget(self.singlesItemsBox) |
100 self.singlesView.setWidget(self.singlesItemsBox) |
83 self.singlesItemsBox.setObjectName("singlesItemsBox") |
101 self.singlesItemsBox.setObjectName("singlesItemsBox") |
84 self.singlesItemsBox.setMinimumWidth(1000) |
102 self.singlesItemsBox.setMinimumWidth(1000) |
85 self.singlesItemsBoxLayout = QVBoxLayout(self.singlesItemsBox) |
103 self.singlesItemsBoxLayout = QVBoxLayout(self.singlesItemsBox) |
86 self.singlesItemsBoxLayout.setContentsMargins(6, 6, 6, 6) |
104 self.singlesItemsBoxLayout.setContentsMargins(6, 6, 6, 6) |
87 self.singlesItemsBoxLayout.setSpacing(6) |
105 self.singlesItemsBoxLayout.setSpacing(6) |
88 self.singlesItemsBox.setLayout(self.singlesItemsBoxLayout) |
106 self.singlesItemsBox.setLayout(self.singlesItemsBoxLayout) |
89 self.singlesEntries = [] |
107 self.singlesEntries = [] |
90 self.__addSinglesLine() |
108 self.__addSinglesLine() |
91 |
109 |
92 hlayout0 = QHBoxLayout() |
110 hlayout0 = QHBoxLayout() |
93 hlayout0.setContentsMargins(0, 0, 0, 0) |
111 hlayout0.setContentsMargins(0, 0, 0, 0) |
94 hlayout0.setSpacing(6) |
112 hlayout0.setSpacing(6) |
95 hlayout0.setObjectName("hlayout0") |
113 hlayout0.setObjectName("hlayout0") |
96 self.moreSinglesButton = QPushButton( |
114 self.moreSinglesButton = QPushButton( |
97 self.tr("Additional Entries"), self.singlesBox) |
115 self.tr("Additional Entries"), self.singlesBox |
|
116 ) |
98 self.moreSinglesButton.setObjectName("moreSinglesButton") |
117 self.moreSinglesButton.setObjectName("moreSinglesButton") |
99 hlayout0.addWidget(self.moreSinglesButton) |
118 hlayout0.addWidget(self.moreSinglesButton) |
100 hspacer0 = QSpacerItem( |
119 hspacer0 = QSpacerItem( |
101 30, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) |
120 30, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum |
|
121 ) |
102 hlayout0.addItem(hspacer0) |
122 hlayout0.addItem(hspacer0) |
103 self.singlesBoxLayout.addLayout(hlayout0) |
123 self.singlesBoxLayout.addLayout(hlayout0) |
104 self.moreSinglesButton.clicked.connect(self.__addSinglesLine) |
124 self.moreSinglesButton.clicked.connect(self.__addSinglesLine) |
105 |
125 |
106 # generate dialog part for character ranges |
126 # generate dialog part for character ranges |
107 self.rangesBoxLayout = QVBoxLayout(self.rangesBox) |
127 self.rangesBoxLayout = QVBoxLayout(self.rangesBox) |
108 self.rangesBoxLayout.setObjectName("rangesBoxLayout") |
128 self.rangesBoxLayout.setObjectName("rangesBoxLayout") |
109 self.rangesBoxLayout.setSpacing(6) |
129 self.rangesBoxLayout.setSpacing(6) |
110 self.rangesBoxLayout.setContentsMargins(6, 6, 6, 6) |
130 self.rangesBoxLayout.setContentsMargins(6, 6, 6, 6) |
111 self.rangesBox.setLayout(self.rangesBoxLayout) |
131 self.rangesBox.setLayout(self.rangesBoxLayout) |
112 self.rangesView = QScrollArea(self.rangesBox) |
132 self.rangesView = QScrollArea(self.rangesBox) |
113 self.rangesView.setObjectName("rangesView") |
133 self.rangesView.setObjectName("rangesView") |
114 self.rangesBoxLayout.addWidget(self.rangesView) |
134 self.rangesBoxLayout.addWidget(self.rangesView) |
115 |
135 |
116 self.rangesItemsBox = QWidget(self) |
136 self.rangesItemsBox = QWidget(self) |
117 self.rangesView.setWidget(self.rangesItemsBox) |
137 self.rangesView.setWidget(self.rangesItemsBox) |
118 self.rangesItemsBox.setObjectName("rangesItemsBox") |
138 self.rangesItemsBox.setObjectName("rangesItemsBox") |
119 self.rangesItemsBox.setMinimumWidth(1000) |
139 self.rangesItemsBox.setMinimumWidth(1000) |
120 self.rangesItemsBoxLayout = QVBoxLayout(self.rangesItemsBox) |
140 self.rangesItemsBoxLayout = QVBoxLayout(self.rangesItemsBox) |
121 self.rangesItemsBoxLayout.setContentsMargins(6, 6, 6, 6) |
141 self.rangesItemsBoxLayout.setContentsMargins(6, 6, 6, 6) |
122 self.rangesItemsBoxLayout.setSpacing(6) |
142 self.rangesItemsBoxLayout.setSpacing(6) |
123 self.rangesItemsBox.setLayout(self.rangesItemsBoxLayout) |
143 self.rangesItemsBox.setLayout(self.rangesItemsBoxLayout) |
124 self.rangesEntries = [] |
144 self.rangesEntries = [] |
125 self.__addRangesLine() |
145 self.__addRangesLine() |
126 |
146 |
127 hlayout1 = QHBoxLayout() |
147 hlayout1 = QHBoxLayout() |
128 hlayout1.setContentsMargins(0, 0, 0, 0) |
148 hlayout1.setContentsMargins(0, 0, 0, 0) |
129 hlayout1.setSpacing(6) |
149 hlayout1.setSpacing(6) |
130 hlayout1.setObjectName("hlayout1") |
150 hlayout1.setObjectName("hlayout1") |
131 self.moreRangesButton = QPushButton( |
151 self.moreRangesButton = QPushButton( |
132 self.tr("Additional Entries"), self.rangesBox) |
152 self.tr("Additional Entries"), self.rangesBox |
|
153 ) |
133 self.moreSinglesButton.setObjectName("moreRangesButton") |
154 self.moreSinglesButton.setObjectName("moreRangesButton") |
134 hlayout1.addWidget(self.moreRangesButton) |
155 hlayout1.addWidget(self.moreRangesButton) |
135 hspacer1 = QSpacerItem( |
156 hspacer1 = QSpacerItem( |
136 30, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) |
157 30, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum |
|
158 ) |
137 hlayout1.addItem(hspacer1) |
159 hlayout1.addItem(hspacer1) |
138 self.rangesBoxLayout.addLayout(hlayout1) |
160 self.rangesBoxLayout.addLayout(hlayout1) |
139 self.moreRangesButton.clicked.connect(self.__addRangesLine) |
161 self.moreRangesButton.clicked.connect(self.__addRangesLine) |
140 |
162 |
141 def __initCharacterSelectors(self): |
163 def __initCharacterSelectors(self): |
142 """ |
164 """ |
143 Private method to initialize the W3C character selector entries. |
165 Private method to initialize the W3C character selector entries. |
144 """ |
166 """ |
145 self.__characterCategories = ( |
167 self.__characterCategories = ( |
398 hboxLayout.addWidget(l2) |
418 hboxLayout.addWidget(l2) |
399 le2 = QLineEdit(hbox) |
419 le2 = QLineEdit(hbox) |
400 le2.setValidator(self.charValidator) |
420 le2.setValidator(self.charValidator) |
401 hboxLayout.addWidget(le2) |
421 hboxLayout.addWidget(le2) |
402 self.rangesItemsBoxLayout.addWidget(hbox) |
422 self.rangesItemsBoxLayout.addWidget(hbox) |
403 |
423 |
404 cb1.activated[int].connect( |
424 cb1.activated[int].connect(lambda i: self.__rangesCharTypeSelected(i, cb1)) |
405 lambda i: self.__rangesCharTypeSelected(i, cb1)) |
425 |
406 |
|
407 hbox.show() |
426 hbox.show() |
408 |
427 |
409 self.rangesItemsBox.adjustSize() |
428 self.rangesItemsBox.adjustSize() |
410 |
429 |
411 self.rangesEntries.append([cb1, le1, le2]) |
430 self.rangesEntries.append([cb1, le1, le2]) |
412 |
431 |
413 def __populateCharacterCombo(self, combo, formatIdentifier): |
432 def __populateCharacterCombo(self, combo, formatIdentifier): |
414 """ |
433 """ |
415 Private method to populate a character selection combo. |
434 Private method to populate a character selection combo. |
416 |
435 |
417 @param combo combo box to be populated (QComboBox) |
436 @param combo combo box to be populated (QComboBox) |
418 @param formatIdentifier format identifier (one of "-ccp", "-ccn", |
437 @param formatIdentifier format identifier (one of "-ccp", "-ccn", |
419 "-cbp", "-cbn", "-csp", "-csn", "-psp", "-psn") |
438 "-cbp", "-cbn", "-csp", "-csn", "-psp", "-psn") |
420 """ |
439 """ |
421 combo.clear() |
440 combo.clear() |
422 |
441 |
423 if formatIdentifier in ["-ccp", "-ccn"]: |
442 if formatIdentifier in ["-ccp", "-ccn"]: |
424 items = self.__characterCategories |
443 items = self.__characterCategories |
425 elif formatIdentifier in ["-csp", "-csn"]: |
444 elif formatIdentifier in ["-csp", "-csn"]: |
426 items = self.__specialCharacterCategories |
445 items = self.__specialCharacterCategories |
427 elif formatIdentifier in ["-cbp", "-cbn"]: |
446 elif formatIdentifier in ["-cbp", "-cbn"]: |
428 items = self.__characterBlocks |
447 items = self.__characterBlocks |
429 elif formatIdentifier in ["-psp", "-psn"]: |
448 elif formatIdentifier in ["-psp", "-psn"]: |
430 items = self.__posixNamedSets |
449 items = self.__posixNamedSets |
431 |
450 |
432 comboLen = 0 |
451 comboLen = 0 |
433 for txt, code in items: |
452 for txt, code in items: |
434 combo.addItem(txt, code) |
453 combo.addItem(txt, code) |
435 comboLen = max(comboLen, len(txt)) |
454 comboLen = max(comboLen, len(txt)) |
436 combo.setMinimumContentsLength(comboLen) |
455 combo.setMinimumContentsLength(comboLen) |
437 |
456 |
438 def __performSelectedAction(self, formatIdentifier, lineedit, combo): |
457 def __performSelectedAction(self, formatIdentifier, lineedit, combo): |
439 """ |
458 """ |
440 Private method performing some actions depending on the input. |
459 Private method performing some actions depending on the input. |
441 |
460 |
442 @param formatIdentifier format of the selected entry (string) |
461 @param formatIdentifier format of the selected entry (string) |
443 @param lineedit line edit widget to act on (QLineEdit) |
462 @param lineedit line edit widget to act on (QLineEdit) |
444 @param combo combo box widget to act on (QComboBox) |
463 @param combo combo box widget to act on (QComboBox) |
445 """ |
464 """ |
446 if formatIdentifier == "-i": |
465 if formatIdentifier == "-i": |
447 return |
466 return |
448 |
467 |
449 if formatIdentifier in ["-c", "-h", "-o"]: |
468 if formatIdentifier in ["-c", "-h", "-o"]: |
450 lineedit.show() |
469 lineedit.show() |
451 lineedit.setEnabled(True) |
470 lineedit.setEnabled(True) |
452 if combo is not None: |
471 if combo is not None: |
453 combo.hide() |
472 combo.hide() |
468 lineedit.setEnabled(False) |
495 lineedit.setEnabled(False) |
469 lineedit.hide() |
496 lineedit.hide() |
470 if combo is not None: |
497 if combo is not None: |
471 combo.hide() |
498 combo.hide() |
472 lineedit.clear() |
499 lineedit.clear() |
473 |
500 |
474 def __singlesCharTypeSelected(self, index, combo): |
501 def __singlesCharTypeSelected(self, index, combo): |
475 """ |
502 """ |
476 Private slot to handle the activated(int) signal of the single chars |
503 Private slot to handle the activated(int) signal of the single chars |
477 combo boxes. |
504 combo boxes. |
478 |
505 |
479 @param index selected list index |
506 @param index selected list index |
480 @type int |
507 @type int |
481 @param combo reference to the combo box |
508 @param combo reference to the combo box |
482 @type QComboBox |
509 @type QComboBox |
483 """ |
510 """ |
484 for entriesList in self.singlesEntries: |
511 for entriesList in self.singlesEntries: |
485 if combo == entriesList[0]: |
512 if combo == entriesList[0]: |
486 formatIdentifier = combo.itemData(index) |
513 formatIdentifier = combo.itemData(index) |
487 self.__performSelectedAction( |
514 self.__performSelectedAction( |
488 formatIdentifier, entriesList[1], entriesList[2]) |
515 formatIdentifier, entriesList[1], entriesList[2] |
|
516 ) |
489 break |
517 break |
490 |
518 |
491 def __rangesCharTypeSelected(self, index, combo): |
519 def __rangesCharTypeSelected(self, index, combo): |
492 """ |
520 """ |
493 Private slot to handle the activated(int) signal of the char ranges |
521 Private slot to handle the activated(int) signal of the char ranges |
494 combo boxes. |
522 combo boxes. |
495 |
523 |
496 @param index selected list index |
524 @param index selected list index |
497 @type int |
525 @type int |
498 @param combo reference to the combo box |
526 @param combo reference to the combo box |
499 @type QComboBox |
527 @type QComboBox |
500 """ |
528 """ |
501 for entriesList in self.rangesEntries: |
529 for entriesList in self.rangesEntries: |
502 if combo == entriesList[0]: |
530 if combo == entriesList[0]: |
503 formatIdentifier = combo.itemData(index) |
531 formatIdentifier = combo.itemData(index) |
504 self.__performSelectedAction(formatIdentifier, entriesList[1], |
532 self.__performSelectedAction(formatIdentifier, entriesList[1], None) |
505 None) |
533 self.__performSelectedAction(formatIdentifier, entriesList[2], None) |
506 self.__performSelectedAction(formatIdentifier, entriesList[2], |
|
507 None) |
|
508 break |
534 break |
509 |
535 |
510 def __formatCharacter(self, char, formatIdentifier): |
536 def __formatCharacter(self, char, formatIdentifier): |
511 """ |
537 """ |
512 Private method to format the characters entered into the dialog. |
538 Private method to format the characters entered into the dialog. |
513 |
539 |
514 @param char character string entered into the dialog (string) |
540 @param char character string entered into the dialog (string) |
515 @param formatIdentifier string giving a special format (-c, -h, -i or |
541 @param formatIdentifier string giving a special format (-c, -h, -i or |
516 -o) or the already formatted character (string) |
542 -o) or the already formatted character (string) |
517 @return formatted character string (string) |
543 @return formatted character string (string) |
518 """ |
544 """ |
519 if formatIdentifier == "-c": |
545 if formatIdentifier == "-c": |
520 return char |
546 return char |
521 elif formatIdentifier == "-i": |
547 elif formatIdentifier == "-i": |
522 return "" |
548 return "" |
523 |
549 |
524 if formatIdentifier == "-h": |
550 if formatIdentifier == "-h": |
525 while len(char) < 2: |
551 while len(char) < 2: |
526 char = "0" + char |
552 char = "0" + char |
527 if len(char) > 2: |
553 if len(char) > 2: |
528 return "\\x{{{0}}}".format(char.lower()) |
554 return "\\x{{{0}}}".format(char.lower()) |