Plugins/WizardPlugins/QRegExpWizard/QRegExpWizardDialog.py

changeset 0
de9c2efb9d02
child 12
1d8dd9706f46
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2004 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the QRegExp wizard dialog.
8 """
9
10 import sys
11 import os
12
13 from PyQt4.QtCore import *
14 from PyQt4.QtGui import *
15
16 from E4Gui.E4Application import e4App
17
18 from Ui_QRegExpWizardDialog import Ui_QRegExpWizardDialog
19
20 from QRegExpWizardRepeatDialog import QRegExpWizardRepeatDialog
21 from QRegExpWizardCharactersDialog import QRegExpWizardCharactersDialog
22
23 import UI.PixmapCache
24
25 import Utilities
26
27 class QRegExpWizardWidget(QWidget, Ui_QRegExpWizardDialog):
28 """
29 Class implementing the QRegExp wizard dialog.
30 """
31 def __init__(self, parent = None, fromEric = True):
32 """
33 Constructor
34
35 @param parent parent widget (QWidget)
36 @param fromEric flag indicating a call from within eric4
37 """
38 QWidget.__init__(self,parent)
39 self.setupUi(self)
40
41 # initialize icons of the tool buttons
42 self.charButton.setIcon(UI.PixmapCache.getIcon("characters.png"))
43 self.anycharButton.setIcon(UI.PixmapCache.getIcon("anychar.png"))
44 self.repeatButton.setIcon(UI.PixmapCache.getIcon("repeat.png"))
45 self.nonGroupButton.setIcon(UI.PixmapCache.getIcon("nongroup.png"))
46 self.groupButton.setIcon(UI.PixmapCache.getIcon("group.png"))
47 self.altnButton.setIcon(UI.PixmapCache.getIcon("altn.png"))
48 self.beglineButton.setIcon(UI.PixmapCache.getIcon("begline.png"))
49 self.endlineButton.setIcon(UI.PixmapCache.getIcon("endline.png"))
50 self.wordboundButton.setIcon(UI.PixmapCache.getIcon("wordboundary.png"))
51 self.nonwordboundButton.setIcon(UI.PixmapCache.getIcon("nonwordboundary.png"))
52 self.poslookaheadButton.setIcon(UI.PixmapCache.getIcon("poslookahead.png"))
53 self.neglookaheadButton.setIcon(UI.PixmapCache.getIcon("neglookahead.png"))
54 self.undoButton.setIcon(UI.PixmapCache.getIcon("editUndo.png"))
55 self.redoButton.setIcon(UI.PixmapCache.getIcon("editRedo.png"))
56
57 self.saveButton = \
58 self.buttonBox.addButton(self.trUtf8("Save"), QDialogButtonBox.ActionRole)
59 self.saveButton.setToolTip(self.trUtf8("Save the regular expression to a file"))
60 self.loadButton = \
61 self.buttonBox.addButton(self.trUtf8("Load"), QDialogButtonBox.ActionRole)
62 self.loadButton.setToolTip(self.trUtf8("Load a regular expression from a file"))
63 self.validateButton = \
64 self.buttonBox.addButton(self.trUtf8("Validate"), QDialogButtonBox.ActionRole)
65 self.validateButton.setToolTip(self.trUtf8("Validate the regular expression"))
66 self.executeButton = \
67 self.buttonBox.addButton(self.trUtf8("Execute"), QDialogButtonBox.ActionRole)
68 self.executeButton.setToolTip(self.trUtf8("Execute the regular expression"))
69 self.nextButton = \
70 self.buttonBox.addButton(self.trUtf8("Next match"),
71 QDialogButtonBox.ActionRole)
72 self.nextButton.setToolTip(\
73 self.trUtf8("Show the next match of the regular expression"))
74 self.nextButton.setEnabled(False)
75
76 if fromEric:
77 self.buttonBox.button(QDialogButtonBox.Close).hide()
78 self.copyButton = None
79 uitype = e4App().getObject("Project").getProjectType()
80 else:
81 self.copyButton = \
82 self.buttonBox.addButton(self.trUtf8("Copy"), QDialogButtonBox.ActionRole)
83 self.copyButton.setToolTip(\
84 self.trUtf8("Copy the regular expression to the clipboard"))
85 self.buttonBox.button(QDialogButtonBox.Ok).hide()
86 self.buttonBox.button(QDialogButtonBox.Cancel).hide()
87 self.variableLabel.hide()
88 self.variableLineEdit.hide()
89 self.variableLine.hide()
90 self.regexpLineEdit.setFocus()
91
92 def __insertString(self, s, steps=0):
93 """
94 Private method to insert a string into line edit and move cursor.
95
96 @param s string to be inserted into the regexp line edit
97 (string)
98 @param steps number of characters to move the cursor (integer).
99 Negative steps moves cursor back, positives forward.
100 """
101 self.regexpLineEdit.insert(s)
102 self.regexpLineEdit.cursorForward(False, steps)
103
104 @pyqtSlot()
105 def on_anycharButton_clicked(self):
106 """
107 Private slot to handle the any character toolbutton.
108 """
109 self.__insertString(".")
110
111 @pyqtSlot()
112 def on_nonGroupButton_clicked(self):
113 """
114 Private slot to handle the non group toolbutton.
115 """
116 self.__insertString("(?:)", -1)
117
118 @pyqtSlot()
119 def on_groupButton_clicked(self):
120 """
121 Private slot to handle the group toolbutton.
122 """
123 self.__insertString("()", -1)
124
125 @pyqtSlot()
126 def on_altnButton_clicked(self):
127 """
128 Private slot to handle the alternatives toolbutton.
129 """
130 self.__insertString("(|)", -2)
131
132 @pyqtSlot()
133 def on_beglineButton_clicked(self):
134 """
135 Private slot to handle the begin line toolbutton.
136 """
137 self.__insertString("^")
138
139 @pyqtSlot()
140 def on_endlineButton_clicked(self):
141 """
142 Private slot to handle the end line toolbutton.
143 """
144 self.__insertString("$")
145
146 @pyqtSlot()
147 def on_wordboundButton_clicked(self):
148 """
149 Private slot to handle the word boundary toolbutton.
150 """
151 self.__insertString("\\b")
152
153 @pyqtSlot()
154 def on_nonwordboundButton_clicked(self):
155 """
156 Private slot to handle the non word boundary toolbutton.
157 """
158 self.__insertString("\\B")
159
160 @pyqtSlot()
161 def on_poslookaheadButton_clicked(self):
162 """
163 Private slot to handle the positive lookahead toolbutton.
164 """
165 self.__insertString("(?=)", -1)
166
167 @pyqtSlot()
168 def on_neglookaheadButton_clicked(self):
169 """
170 Private slot to handle the negative lookahead toolbutton.
171 """
172 self.__insertString("(?!)", -1)
173
174 @pyqtSlot()
175 def on_repeatButton_clicked(self):
176 """
177 Private slot to handle the repeat toolbutton.
178 """
179 dlg = QRegExpWizardRepeatDialog(self)
180 if dlg.exec_() == QDialog.Accepted:
181 self.__insertString(dlg.getRepeat())
182
183 @pyqtSlot()
184 def on_charButton_clicked(self):
185 """
186 Private slot to handle the characters toolbutton.
187 """
188 dlg = QRegExpWizardCharactersDialog(self)
189 if dlg.exec_() == QDialog.Accepted:
190 self.__insertString(dlg.getCharacters())
191
192 def on_buttonBox_clicked(self, button):
193 """
194 Private slot called by a button of the button box clicked.
195
196 @param button button that was clicked (QAbstractButton)
197 """
198 if button == self.validateButton:
199 self.on_validateButton_clicked()
200 elif button == self.executeButton:
201 self.on_executeButton_clicked()
202 elif button == self.saveButton:
203 self.on_saveButton_clicked()
204 elif button == self.loadButton:
205 self.on_loadButton_clicked()
206 elif button == self.nextButton:
207 self.on_nextButton_clicked()
208 elif self.copyButton and button == self.copyButton:
209 self.on_copyButton_clicked()
210
211 @pyqtSlot()
212 def on_saveButton_clicked(self):
213 """
214 Private slot to save the regexp to a file.
215 """
216 fname, selectedFilter = QFileDialog.getSaveFileNameAndFilter(\
217 self,
218 self.trUtf8("Save regular expression"),
219 "",
220 self.trUtf8("RegExp Files (*.rx);;All Files (*)"),
221 None,
222 QFileDialog.Options(QFileDialog.DontConfirmOverwrite))
223 if fname:
224 ext = QFileInfo(fname).suffix()
225 if not ext:
226 ex = selectedFilter.split("(*")[1].split(")")[0]
227 if ex:
228 fname += ex
229 if QFileInfo(fname).exists():
230 res = QMessageBox.warning(self,
231 self.trUtf8("Save regular expression"),
232 self.trUtf8("<p>The file <b>{0}</b> already exists.</p>")
233 .format(fname),
234 QMessageBox.StandardButtons(\
235 QMessageBox.Abort | \
236 QMessageBox.Save),
237 QMessageBox.Abort)
238 if res == QMessageBox.Abort or res == QMessageBox.Cancel:
239 return
240
241 try:
242 f=open(Utilities.toNativeSeparators(fname), "wb")
243 f.write(self.regexpLineEdit.text())
244 f.close()
245 except IOError, err:
246 QMessageBox.information(self,
247 self.trUtf8("Save regular expression"),
248 self.trUtf8("""<p>The regular expression could not be saved.</p>"""
249 """<p>Reason: {0}</p>""").format(unicode(err)))
250
251 @pyqtSlot()
252 def on_loadButton_clicked(self):
253 """
254 Private slot to load a regexp from a file.
255 """
256 fname = QFileDialog.getOpenFileName(\
257 self,
258 self.trUtf8("Load regular expression"),
259 "",
260 self.trUtf8("RegExp Files (*.rx);;All Files (*)"))
261 if fname:
262 try:
263 f=open(Utilities.toNativeSeparators(fname), "rb")
264 regexp = f.read()
265 f.close()
266 self.regexpLineEdit.setText(regexp)
267 except IOError, err:
268 QMessageBox.information(self,
269 self.trUtf8("Save regular expression"),
270 self.trUtf8("""<p>The regular expression could not be saved.</p>"""
271 """<p>Reason: {0}</p>""").format(unicode(err)))
272
273 @pyqtSlot()
274 def on_copyButton_clicked(self):
275 """
276 Private slot to copy the regexp string into the clipboard.
277
278 This slot is only available, if not called from within eric4.
279 """
280 escaped = self.regexpLineEdit.text()
281 if escaped:
282 escaped = escaped.replace("\\", "\\\\")
283 cb = QApplication.clipboard()
284 cb.setText(escaped, QClipboard.Clipboard)
285 if cb.supportsSelection():
286 cb.setText(escaped, QClipboard.Selection)
287
288 @pyqtSlot()
289 def on_validateButton_clicked(self):
290 """
291 Private slot to validate the entered regexp.
292 """
293 regex = self.regexpLineEdit.text()
294 if regex:
295 re = QRegExp(regex)
296 if self.caseSensitiveCheckBox.isChecked():
297 re.setCaseSensitivity(Qt.CaseSensitive)
298 else:
299 re.setCaseSensitivity(Qt.CaseInsensitive)
300 re.setMinimal(self.minimalCheckBox.isChecked())
301 if self.wildcardCheckBox.isChecked():
302 re.setPatternSyntax(QRegExp.Wildcard)
303 else:
304 re.setPatternSyntax(QRegExp.RegExp)
305 if re.isValid():
306 QMessageBox.information(None,
307 self.trUtf8(""),
308 self.trUtf8("""The regular expression is valid."""))
309 else:
310 QMessageBox.critical(None,
311 self.trUtf8("Error"),
312 self.trUtf8("""Invalid regular expression: {0}""")
313 .format(re.errorString()))
314 return
315 else:
316 QMessageBox.critical(None,
317 self.trUtf8("Error"),
318 self.trUtf8("""A regular expression must be given."""))
319
320 @pyqtSlot()
321 def on_executeButton_clicked(self, startpos = 0):
322 """
323 Private slot to execute the entered regexp on the test text.
324
325 This slot will execute the entered regexp on the entered test
326 data and will display the result in the table part of the dialog.
327
328 @param startpos starting position for the regexp matching
329 """
330 regex = self.regexpLineEdit.text()
331 text = self.textTextEdit.toPlainText()
332 if regex and text:
333 re = QRegExp(regex)
334 if self.caseSensitiveCheckBox.isChecked():
335 re.setCaseSensitivity(Qt.CaseSensitive)
336 else:
337 re.setCaseSensitivity(Qt.CaseInsensitive)
338 re.setMinimal(self.minimalCheckBox.isChecked())
339 wildcard = self.wildcardCheckBox.isChecked()
340 if wildcard:
341 re.setPatternSyntax(QRegExp.Wildcard)
342 else:
343 re.setPatternSyntax(QRegExp.RegExp)
344 if not re.isValid():
345 QMessageBox.critical(None,
346 self.trUtf8("Error"),
347 self.trUtf8("""Invalid regular expression: {0}""")
348 .format(re.errorString()))
349 return
350 offset = re.indexIn(text, startpos)
351 captures = re.numCaptures()
352 row = 0
353 OFFSET = 5
354
355 self.resultTable.setColumnCount(0)
356 self.resultTable.setColumnCount(3)
357 self.resultTable.setRowCount(0)
358 self.resultTable.setRowCount(OFFSET)
359 self.resultTable.setItem(row, 0, QTableWidgetItem(self.trUtf8("Regexp")))
360 self.resultTable.setItem(row, 1, QTableWidgetItem(regex))
361
362 if offset != -1:
363 self.lastMatchEnd = offset + re.matchedLength()
364 self.nextButton.setEnabled(True)
365 row += 1
366 self.resultTable.setItem(row, 0, QTableWidgetItem(self.trUtf8("Offset")))
367 self.resultTable.setItem(row, 1, QTableWidgetItem("%d" % offset))
368
369 if not wildcard:
370 row += 1
371 self.resultTable.setItem(row, 0,
372 QTableWidgetItem(self.trUtf8("Captures")))
373 self.resultTable.setItem(row, 1,
374 QTableWidgetItem("%d" % captures))
375 row += 1
376 self.resultTable.setItem(row, 1,
377 QTableWidgetItem(self.trUtf8("Text")))
378 self.resultTable.setItem(row, 2,
379 QTableWidgetItem(self.trUtf8("Characters")))
380
381 row += 1
382 self.resultTable.setItem(row, 0,
383 QTableWidgetItem(self.trUtf8("Match")))
384 self.resultTable.setItem(row, 1,
385 QTableWidgetItem(re.cap(0)))
386 self.resultTable.setItem(row, 2,
387 QTableWidgetItem("%d" % re.matchedLength()))
388
389 if not wildcard:
390 for i in range(1, captures + 1):
391 if len(re.cap(i)) > 0:
392 row += 1
393 self.resultTable.insertRow(row)
394 self.resultTable.setItem(row, 0,
395 QTableWidgetItem(self.trUtf8("Capture #{0}").format(i)))
396 self.resultTable.setItem(row, 1,
397 QTableWidgetItem(re.cap(i)))
398 self.resultTable.setItem(row, 2,
399 QTableWidgetItem("%d" % len(re.cap(i))))
400 else:
401 self.resultTable.setRowCount(3)
402
403 # highlight the matched text
404 tc = self.textTextEdit.textCursor()
405 tc.setPosition(offset)
406 tc.setPosition(self.lastMatchEnd, QTextCursor.KeepAnchor)
407 self.textTextEdit.setTextCursor(tc)
408 else:
409 self.nextButton.setEnabled(False)
410 self.resultTable.setRowCount(2)
411 row += 1
412 if startpos > 0:
413 self.resultTable.setItem(row, 0,
414 QTableWidgetItem(self.trUtf8("No more matches")))
415 else:
416 self.resultTable.setItem(row, 0,
417 QTableWidgetItem(self.trUtf8("No matches")))
418
419 # remove the highlight
420 tc = self.textTextEdit.textCursor()
421 tc.setPosition(0)
422 self.textTextEdit.setTextCursor(tc)
423
424 self.resultTable.resizeColumnsToContents()
425 self.resultTable.resizeRowsToContents()
426 self.resultTable.verticalHeader().hide()
427 self.resultTable.horizontalHeader().hide()
428 else:
429 QMessageBox.critical(None,
430 self.trUtf8("Error"),
431 self.trUtf8("""A regular expression and a text must be given."""))
432
433 @pyqtSlot()
434 def on_nextButton_clicked(self):
435 """
436 Private slot to find the next match.
437 """
438 self.on_executeButton_clicked(self.lastMatchEnd)
439
440 def on_regexpLineEdit_textChanged(self, txt):
441 """
442 Private slot called when the regexp changes.
443
444 @param txt the new text of the line edit (string)
445 """
446 self.nextButton.setEnabled(False)
447
448 def getCode(self, indLevel, indString):
449 """
450 Public method to get the source code.
451
452 @param indLevel indentation level (int)
453 @param indString string used for indentation (space or tab) (string)
454 @return generated code (string)
455 """
456 # calculate the indentation string
457 istring = indLevel * indString
458
459 # now generate the code
460 reVar = self.variableLineEdit.text()
461 if not reVar:
462 reVar = "regexp"
463
464 regexp = self.regexpLineEdit.text()
465
466 code = '%s = QRegExp(r"""%s""")%s' % \
467 (reVar, regexp.replace('"', '\\"'), os.linesep)
468 if not self.caseSensitiveCheckBox.isChecked():
469 code += '%s%s.setCaseSensitivity(Qt.CaseInsensitive)%s' % \
470 (istring, reVar, os.linesep)
471 if self.minimalCheckBox.isChecked():
472 code += '%s%s.setMinimal(1)%s' % (istring, reVar, os.linesep)
473 if self.wildcardCheckBox.isChecked():
474 code += '%s%s.setPatternSyntax(QRegExp.Wildcard)%s' % \
475 (istring, reVar, os.linesep)
476 return code
477
478 class QRegExpWizardDialog(QDialog):
479 """
480 Class for the dialog variant.
481 """
482 def __init__(self, parent = None, fromEric = True):
483 """
484 Constructor
485
486 @param parent parent widget (QWidget)
487 @param fromEric flag indicating a call from within eric4
488 """
489 QDialog.__init__(self, parent)
490 self.setModal(fromEric)
491 self.setSizeGripEnabled(True)
492
493 self.__layout = QVBoxLayout(self)
494 self.__layout.setMargin(0)
495 self.setLayout(self.__layout)
496
497 self.cw = QRegExpWizardWidget(self, fromEric)
498 size = self.cw.size()
499 self.__layout.addWidget(self.cw)
500 self.resize(size)
501
502 self.connect(self.cw.buttonBox, SIGNAL("accepted()"), self.accept)
503 self.connect(self.cw.buttonBox, SIGNAL("rejected()"), self.reject)
504
505 def getCode(self, indLevel, indString):
506 """
507 Public method to get the source code.
508
509 @param indLevel indentation level (int)
510 @param indString string used for indentation (space or tab) (string)
511 @return generated code (string)
512 """
513 return self.cw.getCode(indLevel, indString)
514
515 class QRegExpWizardWindow(QMainWindow):
516 """
517 Main window class for the standalone dialog.
518 """
519 def __init__(self, parent = None):
520 """
521 Constructor
522
523 @param parent reference to the parent widget (QWidget)
524 """
525 QMainWindow.__init__(self, parent)
526 self.cw = QRegExpWizardWidget(self, fromEric = False)
527 size = self.cw.size()
528 self.setCentralWidget(self.cw)
529 self.resize(size)
530
531 self.connect(self.cw.buttonBox, SIGNAL("accepted()"), self.close)
532 self.connect(self.cw.buttonBox, SIGNAL("rejected()"), self.close)

eric ide

mercurial