Plugins/WizardPlugins/QRegularExpressionWizard/QRegularExpressionWizardDialog.py

branch
Py2 comp.
changeset 2791
a9577f248f04
parent 2771
281c9b30dd91
child 2847
1843ef6e2656
equal deleted inserted replaced
2790:6686a3326df8 2791:a9577f248f04
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the QRegularExpression wizard dialog.
8 """
9
10 from __future__ import unicode_literals # __IGNORE_WARNING__
11
12 import os
13 import re
14 import sys
15 import json
16
17 from PyQt4.QtCore import QFileInfo, pyqtSlot, qVersion, QProcess, QByteArray
18 from PyQt4.QtGui import QWidget, QDialog, QInputDialog, QApplication, QClipboard, \
19 QTextCursor, QDialogButtonBox, QVBoxLayout, QTableWidgetItem
20
21 from E5Gui import E5MessageBox, E5FileDialog
22 from E5Gui.E5MainWindow import E5MainWindow
23
24 from .Ui_QRegularExpressionWizardDialog import Ui_QRegularExpressionWizardDialog
25
26 import UI.PixmapCache
27
28 import Utilities
29 import Preferences
30
31
32 class QRegularExpressionWizardWidget(QWidget, Ui_QRegularExpressionWizardDialog):
33 """
34 Class implementing the QRegularExpression wizard dialog.
35 """
36 def __init__(self, parent=None, fromEric=True):
37 """
38 Constructor
39
40 @param parent parent widget (QWidget)
41 @param fromEric flag indicating a call from within eric5
42 """
43 super(QRegularExpressionWizardWidget, self).__init__(parent)
44 self.setupUi(self)
45
46 # initialize icons of the tool buttons
47 self.commentButton.setIcon(UI.PixmapCache.getIcon("comment.png"))
48 self.charButton.setIcon(UI.PixmapCache.getIcon("characters.png"))
49 self.anycharButton.setIcon(UI.PixmapCache.getIcon("anychar.png"))
50 self.repeatButton.setIcon(UI.PixmapCache.getIcon("repeat.png"))
51 self.nonGroupButton.setIcon(UI.PixmapCache.getIcon("nongroup.png"))
52 self.atomicGroupButton.setIcon(UI.PixmapCache.getIcon("atomicgroup.png"))
53 self.groupButton.setIcon(UI.PixmapCache.getIcon("group.png"))
54 self.namedGroupButton.setIcon(UI.PixmapCache.getIcon("namedgroup.png"))
55 self.namedReferenceButton.setIcon(UI.PixmapCache.getIcon("namedreference.png"))
56 self.altnButton.setIcon(UI.PixmapCache.getIcon("altn.png"))
57 self.beglineButton.setIcon(UI.PixmapCache.getIcon("begline.png"))
58 self.endlineButton.setIcon(UI.PixmapCache.getIcon("endline.png"))
59 self.wordboundButton.setIcon(UI.PixmapCache.getIcon("wordboundary.png"))
60 self.nonwordboundButton.setIcon(UI.PixmapCache.getIcon("nonwordboundary.png"))
61 self.poslookaheadButton.setIcon(UI.PixmapCache.getIcon("poslookahead.png"))
62 self.neglookaheadButton.setIcon(UI.PixmapCache.getIcon("neglookahead.png"))
63 self.poslookbehindButton.setIcon(UI.PixmapCache.getIcon("poslookbehind.png"))
64 self.neglookbehindButton.setIcon(UI.PixmapCache.getIcon("neglookbehind.png"))
65 self.undoButton.setIcon(UI.PixmapCache.getIcon("editUndo.png"))
66 self.redoButton.setIcon(UI.PixmapCache.getIcon("editRedo.png"))
67
68 self.namedGroups = re.compile(r"""\(?P<([^>]+)>""").findall
69
70 # start the PyQt5 server part
71 self.__pyqt5Available = False
72 self.__pyqt5Server = QProcess(self)
73 self.__pyqt5Server.start(sys.executable, [
74 os.path.join(os.path.dirname(__file__), "QRegularExpressionWizardServer.py")])
75 if self.__pyqt5Server.waitForStarted(5000):
76 self.__pyqt5Server.setReadChannel(QProcess.StandardOutput)
77 if self.__sendCommand("available"):
78 response = self.__receiveResponse()
79 if response and response["available"]:
80 self.__pyqt5Available = True
81
82 self.saveButton = \
83 self.buttonBox.addButton(self.trUtf8("Save"), QDialogButtonBox.ActionRole)
84 self.saveButton.setToolTip(self.trUtf8("Save the regular expression to a file"))
85 self.loadButton = \
86 self.buttonBox.addButton(self.trUtf8("Load"), QDialogButtonBox.ActionRole)
87 self.loadButton.setToolTip(self.trUtf8("Load a regular expression from a file"))
88 if qVersion() >= "5.0.0" and self.__pyqt5Available:
89 self.validateButton = self.buttonBox.addButton(
90 self.trUtf8("Validate"), QDialogButtonBox.ActionRole)
91 self.validateButton.setToolTip(self.trUtf8("Validate the regular expression"))
92 self.executeButton = self.buttonBox.addButton(
93 self.trUtf8("Execute"), QDialogButtonBox.ActionRole)
94 self.executeButton.setToolTip(self.trUtf8("Execute the regular expression"))
95 self.nextButton = self.buttonBox.addButton(
96 self.trUtf8("Next match"), QDialogButtonBox.ActionRole)
97 self.nextButton.setToolTip(
98 self.trUtf8("Show the next match of the regular expression"))
99 self.nextButton.setEnabled(False)
100 else:
101 self.validateButton = None
102 self.executeButton = None
103 self.nextButton = None
104
105 if fromEric:
106 self.buttonBox.setStandardButtons(
107 QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
108 self.copyButton = None
109 else:
110 self.copyButton = \
111 self.buttonBox.addButton(self.trUtf8("Copy"), QDialogButtonBox.ActionRole)
112 self.copyButton.setToolTip(
113 self.trUtf8("Copy the regular expression to the clipboard"))
114 self.buttonBox.setStandardButtons(QDialogButtonBox.Close)
115 self.variableLabel.hide()
116 self.variableLineEdit.hide()
117 self.variableLine.hide()
118 self.regexpTextEdit.setFocus()
119
120 def __sendCommand(self, command, **kw):
121 """
122 Private method to send a command to the PyQt5 server.
123
124 @param commandDict dictionary with command string and related data (dict)
125 @return flag indicating a successful transmission (boolean)
126 """
127 result = False
128 if command:
129 commandDict = {"command": command}
130 commandDict.update(kw)
131 commandStr = json.dumps(commandDict) + "\n"
132 data = QByteArray(commandStr.encode("utf-8"))
133 self.__pyqt5Server.write(data)
134 result = self.__pyqt5Server.waitForBytesWritten(10000)
135 return result
136
137 def __receiveResponse(self):
138 """
139 Private method to receive a response from the PyQt5 server.
140
141 @return response dictionary (dict)
142 """
143 responseDict = {}
144 if self.__pyqt5Server.waitForReadyRead(10000):
145 data = bytes(self.__pyqt5Server.readAllStandardOutput())
146 responseStr = data.decode("utf-8")
147 responseDict = json.loads(responseStr)
148 if responseDict["error"]:
149 E5MessageBox.critical(self,
150 self.trUtf8("Communication Error"),
151 self.trUtf8("""<p>The PyQt5 backend reported an error.</p>"""
152 """<p>{0}</p>""").format(responseDict["error"]))
153 responseDict = {}
154
155 return responseDict
156
157 def shutdown(self):
158 """
159 Public method to shut down the PyQt5 server part.
160 """
161 self.__sendCommand("exit")
162 self.__pyqt5Server.waitForFinished(5000)
163
164 def __insertString(self, s, steps=0):
165 """
166 Private method to insert a string into line edit and move cursor.
167
168 @param s string to be inserted into the regexp line edit
169 (string)
170 @param steps number of characters to move the cursor (integer).
171 Negative steps moves cursor back, positives forward.
172 """
173 self.regexpTextEdit.insertPlainText(s)
174 tc = self.regexpTextEdit.textCursor()
175 if steps != 0:
176 if steps < 0:
177 act = QTextCursor.Left
178 steps = abs(steps)
179 else:
180 act = QTextCursor.Right
181 for i in range(steps):
182 tc.movePosition(act)
183 self.regexpTextEdit.setTextCursor(tc)
184
185 @pyqtSlot()
186 def on_commentButton_clicked(self):
187 """
188 Private slot to handle the comment toolbutton.
189 """
190 self.__insertString("(?#)", -1)
191
192 @pyqtSlot()
193 def on_charButton_clicked(self):
194 """
195 Private slot to handle the characters toolbutton.
196 """
197 from .QRegularExpressionWizardCharactersDialog import \
198 QRegularExpressionWizardCharactersDialog
199 dlg = QRegularExpressionWizardCharactersDialog(self)
200 if dlg.exec_() == QDialog.Accepted:
201 self.__insertString(dlg.getCharacters())
202
203 @pyqtSlot()
204 def on_anycharButton_clicked(self):
205 """
206 Private slot to handle the any character toolbutton.
207 """
208 self.__insertString(".")
209
210 @pyqtSlot()
211 def on_repeatButton_clicked(self):
212 """
213 Private slot to handle the repeat toolbutton.
214 """
215 from .QRegularExpressionWizardRepeatDialog import \
216 QRegularExpressionWizardRepeatDialog
217 dlg = QRegularExpressionWizardRepeatDialog(self)
218 if dlg.exec_() == QDialog.Accepted:
219 self.__insertString(dlg.getRepeat())
220
221 @pyqtSlot()
222 def on_nonGroupButton_clicked(self):
223 """
224 Private slot to handle the non group toolbutton.
225 """
226 self.__insertString("(?:)", -1)
227
228 @pyqtSlot()
229 def on_atomicGroupButton_clicked(self):
230 """
231 Private slot to handle the atomic non group toolbutton.
232 """
233 self.__insertString("(?>)", -1)
234
235 @pyqtSlot()
236 def on_groupButton_clicked(self):
237 """
238 Private slot to handle the group toolbutton.
239 """
240 self.__insertString("()", -1)
241
242 @pyqtSlot()
243 def on_namedGroupButton_clicked(self):
244 """
245 Private slot to handle the named group toolbutton.
246 """
247 self.__insertString("(?P<>)", -2)
248
249 @pyqtSlot()
250 def on_namedReferenceButton_clicked(self):
251 """
252 Private slot to handle the named reference toolbutton.
253 """
254 # determine cursor position as length into text
255 length = self.regexpTextEdit.textCursor().position()
256
257 # only present group names that occur before the current cursor position
258 regex = self.regexpTextEdit.toPlainText()[:length]
259 names = self.namedGroups(regex)
260 if not names:
261 E5MessageBox.information(self,
262 self.trUtf8("Named reference"),
263 self.trUtf8("""No named groups have been defined yet."""))
264 return
265
266 groupName, ok = QInputDialog.getItem(
267 self,
268 self.trUtf8("Named reference"),
269 self.trUtf8("Select group name:"),
270 names,
271 0, True)
272 if ok and groupName:
273 self.__insertString("(?P={0})".format(groupName))
274
275 @pyqtSlot()
276 def on_altnButton_clicked(self):
277 """
278 Private slot to handle the alternatives toolbutton.
279 """
280 self.__insertString("(|)", -2)
281
282 @pyqtSlot()
283 def on_beglineButton_clicked(self):
284 """
285 Private slot to handle the begin line toolbutton.
286 """
287 self.__insertString("^")
288
289 @pyqtSlot()
290 def on_endlineButton_clicked(self):
291 """
292 Private slot to handle the end line toolbutton.
293 """
294 self.__insertString("$")
295
296 @pyqtSlot()
297 def on_wordboundButton_clicked(self):
298 """
299 Private slot to handle the word boundary toolbutton.
300 """
301 self.__insertString("\\b")
302
303 @pyqtSlot()
304 def on_nonwordboundButton_clicked(self):
305 """
306 Private slot to handle the non word boundary toolbutton.
307 """
308 self.__insertString("\\B")
309
310 @pyqtSlot()
311 def on_poslookaheadButton_clicked(self):
312 """
313 Private slot to handle the positive lookahead toolbutton.
314 """
315 self.__insertString("(?=)", -1)
316
317 @pyqtSlot()
318 def on_neglookaheadButton_clicked(self):
319 """
320 Private slot to handle the negative lookahead toolbutton.
321 """
322 self.__insertString("(?!)", -1)
323
324 @pyqtSlot()
325 def on_poslookbehindButton_clicked(self):
326 """
327 Private slot to handle the positive lookbehind toolbutton.
328 """
329 self.__insertString("(?<=)", -1)
330
331 @pyqtSlot()
332 def on_neglookbehindButton_clicked(self):
333 """
334 Private slot to handle the negative lookbehind toolbutton.
335 """
336 self.__insertString("(?<!)", -1)
337
338 @pyqtSlot()
339 def on_undoButton_clicked(self):
340 """
341 Private slot to handle the undo action.
342 """
343 self.regexpTextEdit.document().undo()
344
345 @pyqtSlot()
346 def on_redoButton_clicked(self):
347 """
348 Private slot to handle the redo action.
349 """
350 self.regexpTextEdit.document().redo()
351
352 def on_buttonBox_clicked(self, button):
353 """
354 Private slot called by a button of the button box clicked.
355
356 @param button button that was clicked (QAbstractButton)
357 """
358 if button == self.validateButton:
359 self.on_validateButton_clicked()
360 elif button == self.executeButton:
361 self.on_executeButton_clicked()
362 elif button == self.saveButton:
363 self.on_saveButton_clicked()
364 elif button == self.loadButton:
365 self.on_loadButton_clicked()
366 elif button == self.nextButton:
367 self.on_nextButton_clicked()
368 elif self.copyButton and button == self.copyButton:
369 self.on_copyButton_clicked()
370
371 @pyqtSlot()
372 def on_saveButton_clicked(self):
373 """
374 Private slot to save the QRegularExpression to a file.
375 """
376 fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
377 self,
378 self.trUtf8("Save regular expression"),
379 "",
380 self.trUtf8("RegExp Files (*.rx);;All Files (*)"),
381 None,
382 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
383 if fname:
384 ext = QFileInfo(fname).suffix()
385 if not ext:
386 ex = selectedFilter.split("(*")[1].split(")")[0]
387 if ex:
388 fname += ex
389 if QFileInfo(fname).exists():
390 res = E5MessageBox.yesNo(self,
391 self.trUtf8("Save regular expression"),
392 self.trUtf8("<p>The file <b>{0}</b> already exists."
393 " Overwrite it?</p>").format(fname),
394 icon=E5MessageBox.Warning)
395 if not res:
396 return
397
398 try:
399 f = open(Utilities.toNativeSeparators(fname), "w", encoding="utf-8")
400 f.write(self.regexpTextEdit.toPlainText())
401 f.close()
402 except IOError as err:
403 E5MessageBox.information(self,
404 self.trUtf8("Save regular expression"),
405 self.trUtf8("""<p>The regular expression could not be saved.</p>"""
406 """<p>Reason: {0}</p>""").format(str(err)))
407
408 @pyqtSlot()
409 def on_loadButton_clicked(self):
410 """
411 Private slot to load a QRegularExpression from a file.
412 """
413 fname = E5FileDialog.getOpenFileName(
414 self,
415 self.trUtf8("Load regular expression"),
416 "",
417 self.trUtf8("RegExp Files (*.rx);;All Files (*)"))
418 if fname:
419 try:
420 f = open(Utilities.toNativeSeparators(fname), "r", encoding="utf-8")
421 regexp = f.read()
422 f.close()
423 self.regexpTextEdit.setPlainText(regexp)
424 except IOError as err:
425 E5MessageBox.information(self,
426 self.trUtf8("Save regular expression"),
427 self.trUtf8("""<p>The regular expression could not be saved.</p>"""
428 """<p>Reason: {0}</p>""").format(str(err)))
429
430 @pyqtSlot()
431 def on_copyButton_clicked(self):
432 """
433 Private slot to copy the QRegularExpression string into the clipboard.
434
435 This slot is only available, if not called from within eric5.
436 """
437 escaped = self.regexpTextEdit.toPlainText()
438 if escaped:
439 escaped = escaped.replace("\\", "\\\\")
440 cb = QApplication.clipboard()
441 cb.setText(escaped, QClipboard.Clipboard)
442 if cb.supportsSelection():
443 cb.setText(escaped, QClipboard.Selection)
444
445 @pyqtSlot()
446 def on_validateButton_clicked(self):
447 """
448 Private slot to validate the entered QRegularExpression.
449 """
450 if qVersion() < "5.0.0" or not self.__pyqt5Available:
451 # only available for Qt5
452 return
453
454 regexp = self.regexpTextEdit.toPlainText()
455 if regexp:
456 options = []
457 if self.caseInsensitiveCheckBox.isChecked():
458 options.append("CaseInsensitiveOption")
459 if self.multilineCheckBox.isChecked():
460 options.append("MultilineOption")
461 if self.dotallCheckBox.isChecked():
462 options.append("DotMatchesEverythingOption")
463 if self.extendedCheckBox.isChecked():
464 options.append("ExtendedPatternSyntaxOption")
465 if self.greedinessCheckBox.isChecked():
466 options.append("InvertedGreedinessOption")
467 if self.unicodeCheckBox.isChecked():
468 options.append("UseUnicodePropertiesOption")
469 if self.captureCheckBox.isChecked():
470 options.append("DontCaptureOption")
471
472 if self.__sendCommand("validate", options=options, regexp=regexp):
473 response = self.__receiveResponse()
474 if response and "valid" in response:
475 if response["valid"]:
476 E5MessageBox.information(self,
477 self.trUtf8("Validation"),
478 self.trUtf8("""The regular expression is valid."""))
479 else:
480 E5MessageBox.critical(self,
481 self.trUtf8("Error"),
482 self.trUtf8("""Invalid regular expression: {0}""")
483 .format(response["errorMessage"]))
484 # move cursor to error offset
485 offset = response["errorOffset"]
486 tc = self.regexpTextEdit.textCursor()
487 tc.setPosition(offset)
488 self.regexpTextEdit.setTextCursor(tc)
489 self.regexpTextEdit.setFocus()
490 return
491 else:
492 E5MessageBox.critical(self,
493 self.trUtf8("Communication Error"),
494 self.trUtf8("""Invalid response received from PyQt5 backend."""))
495 else:
496 E5MessageBox.critical(self,
497 self.trUtf8("Communication Error"),
498 self.trUtf8("""Communication with PyQt5 backend failed."""))
499 else:
500 E5MessageBox.critical(self,
501 self.trUtf8("Error"),
502 self.trUtf8("""A regular expression must be given."""))
503
504 @pyqtSlot()
505 def on_executeButton_clicked(self, startpos=0):
506 """
507 Private slot to execute the entered QRegularExpression on the test text.
508
509 This slot will execute the entered QRegularExpression on the entered test
510 data and will display the result in the table part of the dialog.
511
512 @param startpos starting position for the QRegularExpression matching
513 """
514 if qVersion() < "5.0.0" or not self.__pyqt5Available:
515 # only available for Qt5
516 return
517
518 regexp = self.regexpTextEdit.toPlainText()
519 text = self.textTextEdit.toPlainText()
520 if regexp and text:
521 options = []
522 if self.caseInsensitiveCheckBox.isChecked():
523 options.append("CaseInsensitiveOption")
524 if self.multilineCheckBox.isChecked():
525 options.append("MultilineOption")
526 if self.dotallCheckBox.isChecked():
527 options.append("DotMatchesEverythingOption")
528 if self.extendedCheckBox.isChecked():
529 options.append("ExtendedPatternSyntaxOption")
530 if self.greedinessCheckBox.isChecked():
531 options.append("InvertedGreedinessOption")
532 if self.unicodeCheckBox.isChecked():
533 options.append("UseUnicodePropertiesOption")
534 if self.captureCheckBox.isChecked():
535 options.append("DontCaptureOption")
536
537 if self.__sendCommand("execute", options=options, regexp=regexp,
538 text=text, startpos=startpos):
539 response = self.__receiveResponse()
540 if response and ("valid" in response or "matched" in response):
541 if "valid" in response:
542 E5MessageBox.critical(self,
543 self.trUtf8("Error"),
544 self.trUtf8("""Invalid regular expression: {0}""")
545 .format(response["errorMessage"]))
546 # move cursor to error offset
547 offset = response["errorOffset"]
548 tc = self.regexpTextEdit.textCursor()
549 tc.setPosition(offset)
550 self.regexpTextEdit.setTextCursor(tc)
551 self.regexpTextEdit.setFocus()
552 return
553 else:
554 row = 0
555 OFFSET = 5
556
557 self.resultTable.setColumnCount(0)
558 self.resultTable.setColumnCount(3)
559 self.resultTable.setRowCount(0)
560 self.resultTable.setRowCount(OFFSET)
561 self.resultTable.setItem(
562 row, 0, QTableWidgetItem(self.trUtf8("Regexp")))
563 self.resultTable.setItem(
564 row, 1, QTableWidgetItem(regexp))
565 if response["matched"]:
566 captures = response["captures"]
567 # index 0 is the complete match
568 offset = captures[0][1]
569 self.lastMatchEnd = captures[0][2]
570 self.nextButton.setEnabled(True)
571 row += 1
572 self.resultTable.setItem(row, 0,
573 QTableWidgetItem(self.trUtf8("Offset")))
574 self.resultTable.setItem(row, 1,
575 QTableWidgetItem("{0:d}".format(offset)))
576
577 row += 1
578 self.resultTable.setItem(row, 0,
579 QTableWidgetItem(self.trUtf8("Captures")))
580 self.resultTable.setItem(row, 1,
581 QTableWidgetItem("{0:d}".format(len(captures) - 1)))
582 row += 1
583 self.resultTable.setItem(row, 1,
584 QTableWidgetItem(self.trUtf8("Text")))
585 self.resultTable.setItem(row, 2,
586 QTableWidgetItem(self.trUtf8("Characters")))
587
588 row += 1
589 self.resultTable.setItem(row, 0,
590 QTableWidgetItem(self.trUtf8("Match")))
591 self.resultTable.setItem(row, 1,
592 QTableWidgetItem(captures[0][0]))
593 self.resultTable.setItem(row, 2,
594 QTableWidgetItem("{0:d}".format(captures[0][3])))
595
596 for i in range(1, len(captures)):
597 if captures[i][0]:
598 row += 1
599 self.resultTable.insertRow(row)
600 self.resultTable.setItem(row, 0,
601 QTableWidgetItem(
602 self.trUtf8("Capture #{0}").format(i)))
603 self.resultTable.setItem(row, 1,
604 QTableWidgetItem(captures[i][0]))
605 self.resultTable.setItem(row, 2,
606 QTableWidgetItem("{0:d}".format(captures[i][3])))
607
608 # highlight the matched text
609 tc = self.textTextEdit.textCursor()
610 tc.setPosition(offset)
611 tc.setPosition(self.lastMatchEnd, QTextCursor.KeepAnchor)
612 self.textTextEdit.setTextCursor(tc)
613 else:
614 self.nextButton.setEnabled(False)
615 self.resultTable.setRowCount(2)
616 row += 1
617 if startpos > 0:
618 self.resultTable.setItem(row, 0,
619 QTableWidgetItem(self.trUtf8("No more matches")))
620 else:
621 self.resultTable.setItem(row, 0,
622 QTableWidgetItem(self.trUtf8("No matches")))
623
624 # remove the highlight
625 tc = self.textTextEdit.textCursor()
626 tc.setPosition(0)
627 self.textTextEdit.setTextCursor(tc)
628
629 self.resultTable.resizeColumnsToContents()
630 self.resultTable.resizeRowsToContents()
631 self.resultTable.verticalHeader().hide()
632 self.resultTable.horizontalHeader().hide()
633 else:
634 E5MessageBox.critical(self,
635 self.trUtf8("Communication Error"),
636 self.trUtf8("""Invalid response received from PyQt5 backend."""))
637 else:
638 E5MessageBox.critical(self,
639 self.trUtf8("Communication Error"),
640 self.trUtf8("""Communication with PyQt5 backend failed."""))
641 else:
642 E5MessageBox.critical(self,
643 self.trUtf8("Error"),
644 self.trUtf8("""A regular expression and a text must be given."""))
645
646 @pyqtSlot()
647 def on_nextButton_clicked(self):
648 """
649 Private slot to find the next match.
650 """
651 self.on_executeButton_clicked(self.lastMatchEnd)
652
653 @pyqtSlot()
654 def on_regexpTextEdit_textChanged(self):
655 """
656 Private slot called when the regexp changes.
657 """
658 if self.nextButton:
659 self.nextButton.setEnabled(False)
660
661 def getCode(self, indLevel, indString):
662 """
663 Public method to get the source code.
664
665 @param indLevel indentation level (int)
666 @param indString string used for indentation (space or tab) (string)
667 @return generated code (string)
668 """
669 # calculate the indentation string
670 i1string = (indLevel + 1) * indString
671 estring = os.linesep + indLevel * indString
672
673 # now generate the code
674 reVar = self.variableLineEdit.text()
675 if not reVar:
676 reVar = "regexp"
677
678 regexp = self.regexpTextEdit.toPlainText()
679
680 options = []
681 if self.caseInsensitiveCheckBox.isChecked():
682 options.append("QRegularExpression.CaseInsensitiveOption")
683 if self.multilineCheckBox.isChecked():
684 options.append("QRegularExpression.MultilineOption")
685 if self.dotallCheckBox.isChecked():
686 options.append("QRegularExpression.DotMatchesEverythingOption")
687 if self.extendedCheckBox.isChecked():
688 options.append("QRegularExpression.ExtendedPatternSyntaxOption")
689 if self.greedinessCheckBox.isChecked():
690 options.append("QRegularExpression.InvertedGreedinessOption")
691 if self.unicodeCheckBox.isChecked():
692 options.append("QRegularExpression.UseUnicodePropertiesOption")
693 if self.captureCheckBox.isChecked():
694 options.append("QRegularExpression.DontCaptureOption")
695 options = " | \\{0}{1}".format(os.linesep, i1string).join(options)
696
697 code = '{0} = QRegularExpression(r"""{1}"""'.format(
698 reVar, regexp.replace('"', '\\"'))
699 if options:
700 code += ', {0}{1}{2}'.format(os.linesep, i1string, options)
701 code += '){0}'.format(estring)
702 return code
703
704
705 class QRegularExpressionWizardDialog(QDialog):
706 """
707 Class for the dialog variant.
708 """
709 def __init__(self, parent=None, fromEric=True):
710 """
711 Constructor
712
713 @param parent parent widget (QWidget)
714 @param fromEric flag indicating a call from within eric5
715 """
716 super(QRegularExpressionWizardDialog, self).__init__(parent)
717 self.setModal(fromEric)
718 self.setSizeGripEnabled(True)
719
720 self.__layout = QVBoxLayout(self)
721 self.__layout.setMargin(0)
722 self.setLayout(self.__layout)
723
724 self.cw = QRegularExpressionWizardWidget(self, fromEric)
725 size = self.cw.size()
726 self.__layout.addWidget(self.cw)
727 self.resize(size)
728 self.setWindowTitle(self.cw.windowTitle())
729
730 self.cw.buttonBox.accepted[()].connect(self.accept)
731 self.cw.buttonBox.rejected[()].connect(self.reject)
732
733 def getCode(self, indLevel, indString):
734 """
735 Public method to get the source code.
736
737 @param indLevel indentation level (int)
738 @param indString string used for indentation (space or tab) (string)
739 @return generated code (string)
740 """
741 return self.cw.getCode(indLevel, indString)
742
743 def accept(self):
744 """
745 Public slot to hide the dialog and set the result code to Accepted.
746 """
747 self.cw.shutdown()
748 super(QRegularExpressionWizardDialog, self).accept()
749
750 def reject(self):
751 """
752 Public slot to hide the dialog and set the result code to Rejected.
753 """
754 self.cw.shutdown()
755 super(QRegularExpressionWizardDialog, self).reject()
756
757
758 class QRegularExpressionWizardWindow(E5MainWindow):
759 """
760 Main window class for the standalone dialog.
761 """
762 def __init__(self, parent=None):
763 """
764 Constructor
765
766 @param parent reference to the parent widget (QWidget)
767 """
768 super(QRegularExpressionWizardWindow, self).__init__(parent)
769 self.cw = QRegularExpressionWizardWidget(self, fromEric=False)
770 size = self.cw.size()
771 self.setCentralWidget(self.cw)
772 self.resize(size)
773 self.setWindowTitle(self.cw.windowTitle())
774
775 self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet"))
776
777 self.cw.buttonBox.accepted[()].connect(self.close)
778 self.cw.buttonBox.rejected[()].connect(self.close)
779
780 def closeEvent(self, evt):
781 """
782 Protected method handling the close event.
783
784 @param evt close event (QCloseEvent)
785 """
786 self.cw.shutdown()
787 super(QRegularExpressionWizardWindow, self).closeEvent(evt)

eric ide

mercurial