12 import os |
12 import os |
13 import re |
13 import re |
14 import sys |
14 import sys |
15 import json |
15 import json |
16 |
16 |
17 from PyQt4.QtCore import QFileInfo, pyqtSlot, qVersion, QProcess, QByteArray |
17 from PyQt4.QtCore import QFileInfo, pyqtSlot, QProcess, QByteArray |
18 from PyQt4.QtGui import QWidget, QDialog, QInputDialog, QApplication, \ |
18 from PyQt4.QtGui import QWidget, QDialog, QInputDialog, QApplication, \ |
19 QClipboard, QTextCursor, QDialogButtonBox, QVBoxLayout, QTableWidgetItem |
19 QClipboard, QTextCursor, QDialogButtonBox, QVBoxLayout, QTableWidgetItem |
20 |
20 |
21 from E5Gui import E5MessageBox, E5FileDialog |
21 from E5Gui import E5MessageBox, E5FileDialog |
22 from E5Gui.E5MainWindow import E5MainWindow |
22 from E5Gui.E5MainWindow import E5MainWindow |
90 response = self.__receiveResponse() |
90 response = self.__receiveResponse() |
91 if response and response["available"]: |
91 if response and response["available"]: |
92 self.__pyqt5Available = True |
92 self.__pyqt5Available = True |
93 |
93 |
94 self.saveButton = self.buttonBox.addButton( |
94 self.saveButton = self.buttonBox.addButton( |
95 self.trUtf8("Save"), QDialogButtonBox.ActionRole) |
95 self.tr("Save"), QDialogButtonBox.ActionRole) |
96 self.saveButton.setToolTip( |
96 self.saveButton.setToolTip( |
97 self.trUtf8("Save the regular expression to a file")) |
97 self.tr("Save the regular expression to a file")) |
98 self.loadButton = self.buttonBox.addButton( |
98 self.loadButton = self.buttonBox.addButton( |
99 self.trUtf8("Load"), QDialogButtonBox.ActionRole) |
99 self.tr("Load"), QDialogButtonBox.ActionRole) |
100 self.loadButton.setToolTip( |
100 self.loadButton.setToolTip( |
101 self.trUtf8("Load a regular expression from a file")) |
101 self.tr("Load a regular expression from a file")) |
102 if qVersion() >= "5.0.0" and self.__pyqt5Available: |
102 if self.__pyqt5Available: |
103 self.validateButton = self.buttonBox.addButton( |
103 self.validateButton = self.buttonBox.addButton( |
104 self.trUtf8("Validate"), QDialogButtonBox.ActionRole) |
104 self.tr("Validate"), QDialogButtonBox.ActionRole) |
105 self.validateButton.setToolTip( |
105 self.validateButton.setToolTip( |
106 self.trUtf8("Validate the regular expression")) |
106 self.tr("Validate the regular expression")) |
107 self.executeButton = self.buttonBox.addButton( |
107 self.executeButton = self.buttonBox.addButton( |
108 self.trUtf8("Execute"), QDialogButtonBox.ActionRole) |
108 self.tr("Execute"), QDialogButtonBox.ActionRole) |
109 self.executeButton.setToolTip( |
109 self.executeButton.setToolTip( |
110 self.trUtf8("Execute the regular expression")) |
110 self.tr("Execute the regular expression")) |
111 self.nextButton = self.buttonBox.addButton( |
111 self.nextButton = self.buttonBox.addButton( |
112 self.trUtf8("Next match"), QDialogButtonBox.ActionRole) |
112 self.tr("Next match"), QDialogButtonBox.ActionRole) |
113 self.nextButton.setToolTip( |
113 self.nextButton.setToolTip( |
114 self.trUtf8("Show the next match of the regular expression")) |
114 self.tr("Show the next match of the regular expression")) |
115 self.nextButton.setEnabled(False) |
115 self.nextButton.setEnabled(False) |
116 else: |
116 else: |
117 self.validateButton = None |
117 self.validateButton = None |
118 self.executeButton = None |
118 self.executeButton = None |
119 self.nextButton = None |
119 self.nextButton = None |
122 self.buttonBox.setStandardButtons( |
122 self.buttonBox.setStandardButtons( |
123 QDialogButtonBox.Cancel | QDialogButtonBox.Ok) |
123 QDialogButtonBox.Cancel | QDialogButtonBox.Ok) |
124 self.copyButton = None |
124 self.copyButton = None |
125 else: |
125 else: |
126 self.copyButton = self.buttonBox.addButton( |
126 self.copyButton = self.buttonBox.addButton( |
127 self.trUtf8("Copy"), QDialogButtonBox.ActionRole) |
127 self.tr("Copy"), QDialogButtonBox.ActionRole) |
128 self.copyButton.setToolTip( |
128 self.copyButton.setToolTip( |
129 self.trUtf8("Copy the regular expression to the clipboard")) |
129 self.tr("Copy the regular expression to the clipboard")) |
130 self.buttonBox.setStandardButtons(QDialogButtonBox.Close) |
130 self.buttonBox.setStandardButtons(QDialogButtonBox.Close) |
131 self.variableLabel.hide() |
131 self.variableLabel.hide() |
132 self.variableLineEdit.hide() |
132 self.variableLineEdit.hide() |
133 self.variableLine.hide() |
133 self.variableLine.hide() |
134 self.regexpTextEdit.setFocus() |
134 self.regexpTextEdit.setFocus() |
164 responseStr = data.decode("utf-8") |
164 responseStr = data.decode("utf-8") |
165 responseDict = json.loads(responseStr) |
165 responseDict = json.loads(responseStr) |
166 if responseDict["error"]: |
166 if responseDict["error"]: |
167 E5MessageBox.critical( |
167 E5MessageBox.critical( |
168 self, |
168 self, |
169 self.trUtf8("Communication Error"), |
169 self.tr("Communication Error"), |
170 self.trUtf8("""<p>The PyQt5 backend reported""" |
170 self.tr("""<p>The PyQt5 backend reported""" |
171 """ an error.</p><p>{0}</p>""") |
171 """ an error.</p><p>{0}</p>""") |
172 .format(responseDict["error"])) |
172 .format(responseDict["error"])) |
173 responseDict = {} |
173 responseDict = {} |
174 |
174 |
175 return responseDict |
175 return responseDict |
176 |
176 |
279 regex = self.regexpTextEdit.toPlainText()[:length] |
279 regex = self.regexpTextEdit.toPlainText()[:length] |
280 names = self.namedGroups(regex) |
280 names = self.namedGroups(regex) |
281 if not names: |
281 if not names: |
282 E5MessageBox.information( |
282 E5MessageBox.information( |
283 self, |
283 self, |
284 self.trUtf8("Named reference"), |
284 self.tr("Named reference"), |
285 self.trUtf8("""No named groups have been defined yet.""")) |
285 self.tr("""No named groups have been defined yet.""")) |
286 return |
286 return |
287 |
287 |
288 groupName, ok = QInputDialog.getItem( |
288 groupName, ok = QInputDialog.getItem( |
289 self, |
289 self, |
290 self.trUtf8("Named reference"), |
290 self.tr("Named reference"), |
291 self.trUtf8("Select group name:"), |
291 self.tr("Select group name:"), |
292 names, |
292 names, |
293 0, True) |
293 0, True) |
294 if ok and groupName: |
294 if ok and groupName: |
295 self.__insertString("(?P={0})".format(groupName)) |
295 self.__insertString("(?P={0})".format(groupName)) |
296 |
296 |
395 """ |
395 """ |
396 Private slot to save the QRegularExpression to a file. |
396 Private slot to save the QRegularExpression to a file. |
397 """ |
397 """ |
398 fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( |
398 fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( |
399 self, |
399 self, |
400 self.trUtf8("Save regular expression"), |
400 self.tr("Save regular expression"), |
401 "", |
401 "", |
402 self.trUtf8("RegExp Files (*.rx);;All Files (*)"), |
402 self.tr("RegExp Files (*.rx);;All Files (*)"), |
403 None, |
403 None, |
404 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) |
404 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) |
405 if fname: |
405 if fname: |
406 ext = QFileInfo(fname).suffix() |
406 ext = QFileInfo(fname).suffix() |
407 if not ext: |
407 if not ext: |
409 if ex: |
409 if ex: |
410 fname += ex |
410 fname += ex |
411 if QFileInfo(fname).exists(): |
411 if QFileInfo(fname).exists(): |
412 res = E5MessageBox.yesNo( |
412 res = E5MessageBox.yesNo( |
413 self, |
413 self, |
414 self.trUtf8("Save regular expression"), |
414 self.tr("Save regular expression"), |
415 self.trUtf8("<p>The file <b>{0}</b> already exists." |
415 self.tr("<p>The file <b>{0}</b> already exists." |
416 " Overwrite it?</p>").format(fname), |
416 " Overwrite it?</p>").format(fname), |
417 icon=E5MessageBox.Warning) |
417 icon=E5MessageBox.Warning) |
418 if not res: |
418 if not res: |
419 return |
419 return |
420 |
420 |
421 try: |
421 try: |
424 f.write(self.regexpTextEdit.toPlainText()) |
424 f.write(self.regexpTextEdit.toPlainText()) |
425 f.close() |
425 f.close() |
426 except IOError as err: |
426 except IOError as err: |
427 E5MessageBox.information( |
427 E5MessageBox.information( |
428 self, |
428 self, |
429 self.trUtf8("Save regular expression"), |
429 self.tr("Save regular expression"), |
430 self.trUtf8("""<p>The regular expression could not""" |
430 self.tr("""<p>The regular expression could not""" |
431 """ be saved.</p><p>Reason: {0}</p>""") |
431 """ be saved.</p><p>Reason: {0}</p>""") |
432 .format(str(err))) |
432 .format(str(err))) |
433 |
433 |
434 @pyqtSlot() |
434 @pyqtSlot() |
435 def on_loadButton_clicked(self): |
435 def on_loadButton_clicked(self): |
436 """ |
436 """ |
437 Private slot to load a QRegularExpression from a file. |
437 Private slot to load a QRegularExpression from a file. |
438 """ |
438 """ |
439 fname = E5FileDialog.getOpenFileName( |
439 fname = E5FileDialog.getOpenFileName( |
440 self, |
440 self, |
441 self.trUtf8("Load regular expression"), |
441 self.tr("Load regular expression"), |
442 "", |
442 "", |
443 self.trUtf8("RegExp Files (*.rx);;All Files (*)")) |
443 self.tr("RegExp Files (*.rx);;All Files (*)")) |
444 if fname: |
444 if fname: |
445 try: |
445 try: |
446 f = open( |
446 f = open( |
447 Utilities.toNativeSeparators(fname), "r", encoding="utf-8") |
447 Utilities.toNativeSeparators(fname), "r", encoding="utf-8") |
448 regexp = f.read() |
448 regexp = f.read() |
449 f.close() |
449 f.close() |
450 self.regexpTextEdit.setPlainText(regexp) |
450 self.regexpTextEdit.setPlainText(regexp) |
451 except IOError as err: |
451 except IOError as err: |
452 E5MessageBox.information( |
452 E5MessageBox.information( |
453 self, |
453 self, |
454 self.trUtf8("Save regular expression"), |
454 self.tr("Save regular expression"), |
455 self.trUtf8("""<p>The regular expression could not""" |
455 self.tr("""<p>The regular expression could not""" |
456 """ be saved.</p><p>Reason: {0}</p>""") |
456 """ be saved.</p><p>Reason: {0}</p>""") |
457 .format(str(err))) |
457 .format(str(err))) |
458 |
458 |
459 @pyqtSlot() |
459 @pyqtSlot() |
460 def on_copyButton_clicked(self): |
460 def on_copyButton_clicked(self): |
461 """ |
461 """ |
502 response = self.__receiveResponse() |
502 response = self.__receiveResponse() |
503 if response and "valid" in response: |
503 if response and "valid" in response: |
504 if response["valid"]: |
504 if response["valid"]: |
505 E5MessageBox.information( |
505 E5MessageBox.information( |
506 self, |
506 self, |
507 self.trUtf8("Validation"), |
507 self.tr("Validation"), |
508 self.trUtf8( |
508 self.tr( |
509 """The regular expression is valid.""")) |
509 """The regular expression is valid.""")) |
510 else: |
510 else: |
511 E5MessageBox.critical( |
511 E5MessageBox.critical( |
512 self, |
512 self, |
513 self.trUtf8("Error"), |
513 self.tr("Error"), |
514 self.trUtf8("""Invalid regular expression: {0}""") |
514 self.tr("""Invalid regular expression: {0}""") |
515 .format(response["errorMessage"])) |
515 .format(response["errorMessage"])) |
516 # move cursor to error offset |
516 # move cursor to error offset |
517 offset = response["errorOffset"] |
517 offset = response["errorOffset"] |
518 tc = self.regexpTextEdit.textCursor() |
518 tc = self.regexpTextEdit.textCursor() |
519 tc.setPosition(offset) |
519 tc.setPosition(offset) |
521 self.regexpTextEdit.setFocus() |
521 self.regexpTextEdit.setFocus() |
522 return |
522 return |
523 else: |
523 else: |
524 E5MessageBox.critical( |
524 E5MessageBox.critical( |
525 self, |
525 self, |
526 self.trUtf8("Communication Error"), |
526 self.tr("Communication Error"), |
527 self.trUtf8("""Invalid response received from""" |
527 self.tr("""Invalid response received from""" |
528 """ PyQt5 backend.""")) |
528 """ PyQt5 backend.""")) |
529 else: |
529 else: |
530 E5MessageBox.critical( |
530 E5MessageBox.critical( |
531 self, |
531 self, |
532 self.trUtf8("Communication Error"), |
532 self.tr("Communication Error"), |
533 self.trUtf8("""Communication with PyQt5 backend""" |
533 self.tr("""Communication with PyQt5 backend""" |
534 """ failed.""")) |
534 """ failed.""")) |
535 else: |
535 else: |
536 E5MessageBox.critical( |
536 E5MessageBox.critical( |
537 self, |
537 self, |
538 self.trUtf8("Error"), |
538 self.tr("Error"), |
539 self.trUtf8("""A regular expression must be given.""")) |
539 self.tr("""A regular expression must be given.""")) |
540 |
540 |
541 @pyqtSlot() |
541 @pyqtSlot() |
542 def on_executeButton_clicked(self, startpos=0): |
542 def on_executeButton_clicked(self, startpos=0): |
543 """ |
543 """ |
544 Private slot to execute the entered QRegularExpression on the test |
544 Private slot to execute the entered QRegularExpression on the test |
547 This slot will execute the entered QRegularExpression on the entered |
547 This slot will execute the entered QRegularExpression on the entered |
548 test data and will display the result in the table part of the dialog. |
548 test data and will display the result in the table part of the dialog. |
549 |
549 |
550 @param startpos starting position for the QRegularExpression matching |
550 @param startpos starting position for the QRegularExpression matching |
551 """ |
551 """ |
552 if qVersion() < "5.0.0" or not self.__pyqt5Available: |
552 if not self.__pyqt5Available: |
553 # only available for Qt5 |
553 # only available for PyQt5 |
554 return |
554 return |
555 |
555 |
556 regexp = self.regexpTextEdit.toPlainText() |
556 regexp = self.regexpTextEdit.toPlainText() |
557 text = self.textTextEdit.toPlainText() |
557 text = self.textTextEdit.toPlainText() |
558 if regexp and text: |
558 if regexp and text: |
577 response = self.__receiveResponse() |
577 response = self.__receiveResponse() |
578 if response and ("valid" in response or "matched" in response): |
578 if response and ("valid" in response or "matched" in response): |
579 if "valid" in response: |
579 if "valid" in response: |
580 E5MessageBox.critical( |
580 E5MessageBox.critical( |
581 self, |
581 self, |
582 self.trUtf8("Error"), |
582 self.tr("Error"), |
583 self.trUtf8("""Invalid regular expression: {0}""") |
583 self.tr("""Invalid regular expression: {0}""") |
584 .format(response["errorMessage"])) |
584 .format(response["errorMessage"])) |
585 # move cursor to error offset |
585 # move cursor to error offset |
586 offset = response["errorOffset"] |
586 offset = response["errorOffset"] |
587 tc = self.regexpTextEdit.textCursor() |
587 tc = self.regexpTextEdit.textCursor() |
588 tc.setPosition(offset) |
588 tc.setPosition(offset) |
596 self.resultTable.setColumnCount(0) |
596 self.resultTable.setColumnCount(0) |
597 self.resultTable.setColumnCount(3) |
597 self.resultTable.setColumnCount(3) |
598 self.resultTable.setRowCount(0) |
598 self.resultTable.setRowCount(0) |
599 self.resultTable.setRowCount(OFFSET) |
599 self.resultTable.setRowCount(OFFSET) |
600 self.resultTable.setItem( |
600 self.resultTable.setItem( |
601 row, 0, QTableWidgetItem(self.trUtf8("Regexp"))) |
601 row, 0, QTableWidgetItem(self.tr("Regexp"))) |
602 self.resultTable.setItem( |
602 self.resultTable.setItem( |
603 row, 1, QTableWidgetItem(regexp)) |
603 row, 1, QTableWidgetItem(regexp)) |
604 if response["matched"]: |
604 if response["matched"]: |
605 captures = response["captures"] |
605 captures = response["captures"] |
606 # index 0 is the complete match |
606 # index 0 is the complete match |
608 self.lastMatchEnd = captures[0][2] |
608 self.lastMatchEnd = captures[0][2] |
609 self.nextButton.setEnabled(True) |
609 self.nextButton.setEnabled(True) |
610 row += 1 |
610 row += 1 |
611 self.resultTable.setItem( |
611 self.resultTable.setItem( |
612 row, 0, |
612 row, 0, |
613 QTableWidgetItem(self.trUtf8("Offset"))) |
613 QTableWidgetItem(self.tr("Offset"))) |
614 self.resultTable.setItem( |
614 self.resultTable.setItem( |
615 row, 1, |
615 row, 1, |
616 QTableWidgetItem("{0:d}".format(offset))) |
616 QTableWidgetItem("{0:d}".format(offset))) |
617 |
617 |
618 row += 1 |
618 row += 1 |
619 self.resultTable.setItem( |
619 self.resultTable.setItem( |
620 row, 0, |
620 row, 0, |
621 QTableWidgetItem(self.trUtf8("Captures"))) |
621 QTableWidgetItem(self.tr("Captures"))) |
622 self.resultTable.setItem( |
622 self.resultTable.setItem( |
623 row, 1, |
623 row, 1, |
624 QTableWidgetItem( |
624 QTableWidgetItem( |
625 "{0:d}".format(len(captures) - 1))) |
625 "{0:d}".format(len(captures) - 1))) |
626 row += 1 |
626 row += 1 |
627 self.resultTable.setItem( |
627 self.resultTable.setItem( |
628 row, 1, |
628 row, 1, |
629 QTableWidgetItem(self.trUtf8("Text"))) |
629 QTableWidgetItem(self.tr("Text"))) |
630 self.resultTable.setItem( |
630 self.resultTable.setItem( |
631 row, 2, |
631 row, 2, |
632 QTableWidgetItem(self.trUtf8("Characters"))) |
632 QTableWidgetItem(self.tr("Characters"))) |
633 |
633 |
634 row += 1 |
634 row += 1 |
635 self.resultTable.setItem( |
635 self.resultTable.setItem( |
636 row, 0, |
636 row, 0, |
637 QTableWidgetItem(self.trUtf8("Match"))) |
637 QTableWidgetItem(self.tr("Match"))) |
638 self.resultTable.setItem( |
638 self.resultTable.setItem( |
639 row, 1, |
639 row, 1, |
640 QTableWidgetItem(captures[0][0])) |
640 QTableWidgetItem(captures[0][0])) |
641 self.resultTable.setItem( |
641 self.resultTable.setItem( |
642 row, 2, |
642 row, 2, |
672 row += 1 |
672 row += 1 |
673 if startpos > 0: |
673 if startpos > 0: |
674 self.resultTable.setItem( |
674 self.resultTable.setItem( |
675 row, 0, |
675 row, 0, |
676 QTableWidgetItem( |
676 QTableWidgetItem( |
677 self.trUtf8("No more matches"))) |
677 self.tr("No more matches"))) |
678 else: |
678 else: |
679 self.resultTable.setItem( |
679 self.resultTable.setItem( |
680 row, 0, |
680 row, 0, |
681 QTableWidgetItem( |
681 QTableWidgetItem( |
682 self.trUtf8("No matches"))) |
682 self.tr("No matches"))) |
683 |
683 |
684 # remove the highlight |
684 # remove the highlight |
685 tc = self.textTextEdit.textCursor() |
685 tc = self.textTextEdit.textCursor() |
686 tc.setPosition(0) |
686 tc.setPosition(0) |
687 self.textTextEdit.setTextCursor(tc) |
687 self.textTextEdit.setTextCursor(tc) |
691 self.resultTable.verticalHeader().hide() |
691 self.resultTable.verticalHeader().hide() |
692 self.resultTable.horizontalHeader().hide() |
692 self.resultTable.horizontalHeader().hide() |
693 else: |
693 else: |
694 E5MessageBox.critical( |
694 E5MessageBox.critical( |
695 self, |
695 self, |
696 self.trUtf8("Communication Error"), |
696 self.tr("Communication Error"), |
697 self.trUtf8("""Invalid response received from""" |
697 self.tr("""Invalid response received from""" |
698 """ PyQt5 backend.""")) |
698 """ PyQt5 backend.""")) |
699 else: |
699 else: |
700 E5MessageBox.critical( |
700 E5MessageBox.critical( |
701 self, |
701 self, |
702 self.trUtf8("Communication Error"), |
702 self.tr("Communication Error"), |
703 self.trUtf8("""Communication with PyQt5""" |
703 self.tr("""Communication with PyQt5""" |
704 """ backend failed.""")) |
704 """ backend failed.""")) |
705 else: |
705 else: |
706 E5MessageBox.critical( |
706 E5MessageBox.critical( |
707 self, |
707 self, |
708 self.trUtf8("Error"), |
708 self.tr("Error"), |
709 self.trUtf8("""A regular expression and a text must""" |
709 self.tr("""A regular expression and a text must""" |
710 """ be given.""")) |
710 """ be given.""")) |
711 |
711 |
712 @pyqtSlot() |
712 @pyqtSlot() |
713 def on_nextButton_clicked(self): |
713 def on_nextButton_clicked(self): |
714 """ |
714 """ |
715 Private slot to find the next match. |
715 Private slot to find the next match. |
794 size = self.cw.size() |
794 size = self.cw.size() |
795 self.__layout.addWidget(self.cw) |
795 self.__layout.addWidget(self.cw) |
796 self.resize(size) |
796 self.resize(size) |
797 self.setWindowTitle(self.cw.windowTitle()) |
797 self.setWindowTitle(self.cw.windowTitle()) |
798 |
798 |
799 self.cw.buttonBox.accepted[()].connect(self.accept) |
799 self.cw.buttonBox.accepted.connect(self.accept) |
800 self.cw.buttonBox.rejected[()].connect(self.reject) |
800 self.cw.buttonBox.rejected.connect(self.reject) |
801 |
801 |
802 def getCode(self, indLevel, indString): |
802 def getCode(self, indLevel, indString): |
803 """ |
803 """ |
804 Public method to get the source code. |
804 Public method to get the source code. |
805 |
805 |
842 self.setWindowTitle(self.cw.windowTitle()) |
842 self.setWindowTitle(self.cw.windowTitle()) |
843 |
843 |
844 self.setStyle( |
844 self.setStyle( |
845 Preferences.getUI("Style"), Preferences.getUI("StyleSheet")) |
845 Preferences.getUI("Style"), Preferences.getUI("StyleSheet")) |
846 |
846 |
847 self.cw.buttonBox.accepted[()].connect(self.close) |
847 self.cw.buttonBox.accepted.connect(self.close) |
848 self.cw.buttonBox.rejected[()].connect(self.close) |
848 self.cw.buttonBox.rejected.connect(self.close) |
849 |
849 |
850 def closeEvent(self, evt): |
850 def closeEvent(self, evt): |
851 """ |
851 """ |
852 Protected method handling the close event. |
852 Protected method handling the close event. |
853 |
853 |