From 7a526fcb131bd67da3090073f2d6427281f8532c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 9 Aug 2012 20:16:38 +0200 Subject: [PATCH 01/26] Use the github page for the kodos project page url --- kodos | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kodos b/kodos index 8446047..5a433ae 100755 --- a/kodos +++ b/kodos @@ -983,7 +983,8 @@ class Kodos(KodosBA): def kodos_website(self): - self.launch_browser_wrapper("http://kodos.sourceforge.net") + self.launch_browser_wrapper('https://github.com/luksan/kodos', + message=self.tr('Launch web browser to go to the kodos project page?')) def check_for_update(self): From 0db86656064c8a9a530463b3866c2cd1ff4c3107 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 9 Aug 2012 19:23:21 +0200 Subject: [PATCH 02/26] Remove the check_for_updates functionality --- kodos | 42 ------------------------------------------ modules/kodosBA.ui | 17 ----------------- 2 files changed, 59 deletions(-) diff --git a/kodos b/kodos index 5a433ae..f7797ed 100755 --- a/kodos +++ b/kodos @@ -987,48 +987,6 @@ class Kodos(KodosBA): message=self.tr('Launch web browser to go to the kodos project page?')) - def check_for_update(self): - url = "http://sourceforge.net/project/showfiles.php?group_id=43860" - try: - fp = urllib.urlopen(url) - except: - self.status_bar.set_message(self.tr("Failed to open url"), - 5, - TRUE) - return - - lines = fp.readlines() - html = string.join(lines) - - rawstr = r"""kodos-(?P.*?)\.\w{3,4}\<""" - match_obj = re.search(rawstr, html) - if match_obj: - latest_version = match_obj.group('version') - if latest_version == VERSION: - QMessageBox.information(None, - self.tr("No Update is Available"), - unicode(self.tr("You are currently using the latest version of Kodos")) + " (%s)" % VERSION) - else: - message = "%s\n\n%s: %s.\n%s: %s.\n\n%s\n" % \ - (unicode(self.tr("There is a newer version of Kodos available.")), - unicode(self.tr("You are using version:")), - VERSION, - unicode(self.tr("The latest version is:")), - latest_version, - unicode(self.tr("Press OK to launch browser"))) - - self.launch_browser_wrapper(url, - self.tr("Kodos Update Available"), - message) - else: - message = "%s.\n\n%s" % \ - (unicode(self.tr("Unable to get version info from Sourceforge")), - unicode(self.tr("Press OK to launch browser"))) - self.launch_browser_wrapper(url, - self.tr("Unknown version available"), - message) - - def launch_browser_wrapper(self, url, caption=None, message=None): if launch_browser(url, caption, message): self.status_bar.set_message(self.tr("Launching web browser"), diff --git a/modules/kodosBA.ui b/modules/kodosBA.ui index a600de2..14139b3 100644 --- a/modules/kodosBA.ui +++ b/modules/kodosBA.ui @@ -406,7 +406,6 @@ database. New in Python version 2.0. - @@ -1285,22 +1284,6 @@ database. New in Python version 2.0. - - helpCheckForUpdateAction - activated() - KodosBA - check_for_update() - - - -1 - -1 - - - 20 - 20 - - - replaceTextEdit textChanged() From 1aa7811ddf46b66c6b682d903a719e05bfc5b6ae Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 9 Aug 2012 19:53:21 +0200 Subject: [PATCH 03/26] Remove the reportbug functionality and send the user to github instead --- kodos | 4 +- modules/reportBug.py | 104 --------------- modules/reportBugBA.ui | 290 ----------------------------------------- 3 files changed, 2 insertions(+), 396 deletions(-) delete mode 100644 modules/reportBug.py delete mode 100644 modules/reportBugBA.ui diff --git a/kodos b/kodos index f7797ed..49ead1b 100755 --- a/kodos +++ b/kodos @@ -33,7 +33,6 @@ import modules.help as help from modules.status_bar import * from modules.reference import * from modules.prefs import * -from modules.reportBug import reportBugWindow from modules.version import VERSION from modules.recent_files import RecentFiles from modules.urlDialog import URLDialog @@ -1005,7 +1004,8 @@ class Kodos(KodosBA): def report_bug(self): - self.bug_report_win = reportBugWindow(self) + self.launch_browser_wrapper('https://github.com/luksan/kodos/issues', + message=self.tr("Launch web browser to report a bug in kodos?")) ############################################################################## diff --git a/modules/reportBug.py b/modules/reportBug.py deleted file mode 100644 index e4351e4..0000000 --- a/modules/reportBug.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- coding: utf-8 -*- -# reportBug.py: -*- Python -*- DESCRIPTIVE TEXT. - -from reportBugBA import reportBugBA -from util import * -from PyQt4.QtGui import * -from PyQt4.QtCore import * -from PyQt4 import * -import sys -import string -import smtplib -from version import VERSION - -AUTHOR_ADDR = "phil_schwartz@users.sourceforge.net" - -class reportBug(reportBugBA): - def __init__(self, parent=None, name=None): - reportBugBA.__init__(self, parent) - self.parent = parent - self.kodos_main = parent.kodos_main - self.populate() - - - def populate(self): - self.OSEdit.setText(sys.platform) - pyvers = string.replace(sys.version, "\n", " - ") - self.pythonVersionEdit.setText(pyvers) - self.PyQtVersionEdit.setText(QT_VERSION_STR) - self.regexMultiLineEdit.setPlainText(self.kodos_main.regexMultiLineEdit.toPlainText()) - self.stringMultiLineEdit.setPlainText(self.kodos_main.stringMultiLineEdit.toPlainText()) - - - def cancel_slot(self): - self.parent.close() - - def submit_slot(self): - addr = str(self.emailAddressEdit.text()) - if not addr: - msg = self.tr( - "An email address is necessary so that the author " - "can contact you. Your email address will not " - "be used for any other purposes.") - - QMessageBox.information(None, - self.tr("You must supply a valid email address"), - msg) - return - - msg = "Subject: Kodos bug report\n\n" - msg += "Kodos Version: %s\n" % VERSION - msg += "Operating System: %s\n" % unicode(self.OSEdit.text()) - msg += "Python Version: %s\n" % unicode(self.pythonVersionEdit.text()) - msg += "PyQt Version: %s\n" % unicode(self.PyQtVersionEdit.text()) - msg += "\n" + "=" * 70 + "\n" - msg += "Regex:\n%s\n" % unicode(self.regexMultiLineEdit.text()) - msg += "=" * 70 + "\n" - msg += "String:\n%s\n" % unicode(self.stringMultiLineEdit.text()) - msg += "=" * 70 + "\n" - msg += "Comments:\n%s\n" % unicode(self.commentsMultiLineEdit.text()) - email_server = unicode(self.kodos_main.prefs.emailServerEdit.text()) or "localhost" - try: - server = smtplib.SMTP(email_server) - server.sendmail(addr, AUTHOR_ADDR, msg) - server.quit() - QMessageBox.information(None, - self.tr("Bug report sent"), - self.tr("Your bug report has been sent.")) - self.parent.close() - except Exception, e: - QMessageBox.information(None, - self.tr("An exception occurred sending bug report"), - str(e)) - - -class reportBugWindow(QMainWindow): - def __init__(self, kodos_main): - self.kodos_main = kodos_main - QMainWindow.__init__(self, kodos_main)#, Qt.Window | Qt.WA_DeleteOnClose) - - self.setGeometry(100, 50, 800, 600) - self.setWindowTitle(self.tr("Report a Bug")) - self.setWindowIcon(QIcon(QPixmap(":images/kodos_icon.png"))) - - self.bug_report = reportBug(self) - self.setCentralWidget(self.bug_report) - - - self.createMenu() - self.createToolBar() - - self.show() - - - def createMenu(self): - self.menubar = self.menuBar() - self.filemenu = self.menubar.addMenu(self.tr("&File")) - self.filemenu.addAction(self.tr("&Close"), self, SLOT("close()")) - - - def createToolBar(self): - toolbar = QToolBar() - self.addToolBar(toolbar) - self.logolabel = kodos_toolbar_logo(toolbar) - diff --git a/modules/reportBugBA.ui b/modules/reportBugBA.ui deleted file mode 100644 index 74b2eec..0000000 --- a/modules/reportBugBA.ui +++ /dev/null @@ -1,290 +0,0 @@ - - - reportBugBA - - - - 0 - 0 - 750 - 653 - - - - Form1 - - - - 11 - - - 6 - - - - - 6 - - - 0 - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - Submit Bug Report - - - - - - - Cancel - - - - - - - - - Kodos State Information - - - - 11 - - - 6 - - - - - 6 - - - 0 - - - - - Regular Expression: - - - false - - - - - - - Match String: - - - false - - - - - - - - - 6 - - - 0 - - - - - true - - - - - - - true - - - - - - - - - - - - System Information - - - - 11 - - - 6 - - - - - Operating System: - - - false - - - - - - - PyQt Version: - - - false - - - - - - - Python Version: - - - false - - - - - - - - - - - - - - - - - - - Comments - - - - 11 - - - 6 - - - - - 0 - - - 6 - - - - - Comments: - - - false - - - - - - - - - - - 0 - 0 - - - - Email address: - - - false - - - - - - - - - - - - - - - qPixmapFromMimeSource - - OSEdit - pythonVersionEdit - PyQtVersionEdit - emailAddressEdit - submitButton - cancelButton - - - - - submitButton - clicked() - reportBugBA - submit_slot() - - - 20 - 20 - - - 20 - 20 - - - - - cancelButton - clicked() - reportBugBA - cancel_slot() - - - 20 - 20 - - - 20 - 20 - - - - - From 888d127686628989ab7958a3a5f151b8f157488c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 13 Aug 2012 12:18:26 +0200 Subject: [PATCH 04/26] Remove the email server config item and the associated code --- modules/prefs.py | 3 --- modules/prefsBA.ui | 26 +++----------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/modules/prefs.py b/modules/prefs.py index 56ea409..3112d49 100644 --- a/modules/prefs.py +++ b/modules/prefs.py @@ -27,8 +27,6 @@ def load(self): self.parent.setfont(setting.toPyObject()) if preference == 'Match Font': self.parent.setMatchFont(setting.toPyObject()) - if preference == 'Email Server': - self.emailServerEdit.setText(setting.toPyObject()) if preference == 'Recent Files Count': self.recentFilesSpinBox.setValue(int(setting.toPyObject())) except Exception, e: @@ -39,7 +37,6 @@ def load(self): def save(self): self.settings.setValue('Font', self.parent.getfont()) self.settings.setValue('Match Font', self.parent.getMatchFont()) - self.settings.setValue('Email Server', self.emailServerEdit.text()) self.settings.setValue('Recent Files Count', self.recentFilesSpinBox.text()) self.settings.sync() diff --git a/modules/prefsBA.ui b/modules/prefsBA.ui index c5c8586..6b3b40a 100644 --- a/modules/prefsBA.ui +++ b/modules/prefsBA.ui @@ -68,26 +68,7 @@ - - - - - - - - 0 - 0 - - - - Email Server: - - - false - - - - + @@ -103,7 +84,7 @@ - + Qt::Horizontal @@ -119,7 +100,7 @@ - + @@ -228,7 +209,6 @@ fontButton - emailServerEdit recentFilesSpinBox buttonHelp buttonApply From b2fb9528903ca32dcdb85d92e94aa411afe009fe Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 13 Aug 2012 12:29:48 +0200 Subject: [PATCH 05/26] Fix the layout of the preferences window --- modules/prefsBA.ui | 73 ++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/modules/prefsBA.ui b/modules/prefsBA.ui index 6b3b40a..d2f2290 100644 --- a/modules/prefsBA.ui +++ b/modules/prefsBA.ui @@ -7,7 +7,7 @@ 0 0 540 - 268 + 145 @@ -22,7 +22,7 @@ 11 6 519 - 246 + 131 @@ -44,13 +44,6 @@ - - - - - - - @@ -61,14 +54,21 @@ - + - + + + + + + + + @@ -84,23 +84,7 @@ - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 380 - 20 - - - - - + @@ -116,24 +100,24 @@ + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 380 + 20 + + + + - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - @@ -209,7 +193,6 @@ fontButton - recentFilesSpinBox buttonHelp buttonApply buttonOk From 881d9f3d6cbb568373d2e7a0c9eff27b51045f5d Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 13 Aug 2012 13:36:03 +0200 Subject: [PATCH 06/26] Remove the web browser and mail server paragraphs from the help --- help/prefs.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/help/prefs.html b/help/prefs.html index 06baaf2..793bfc3 100644 --- a/help/prefs.html +++ b/help/prefs.html @@ -77,12 +77,8 @@

Kodos - Help

Preferences

-Set your Web Browser path. You can use the ... button to use a file dialog to help locate your browser. The web browser is necessary to access external links within the Python Regex documentation.

- The Editor Font allows you to select a desirable font for use within the Kodos editor

-The Email Server is required for sending bug reports to the author. You can submit a bug report under the main Help menu

- You can control the number of Recent Files that are displayed at the bottom of the File menu. The default value is 5. To display more or less recent files, set this value accordingly. The recent file list is maintained independtly of this value such that applying a lower value and then a higher value will not purge entries. That is, if you have 10 files and then set this value to 3 and later set this value to 10, the 10 files will be immediately available for selection .

From 360b3442db3b70b2ccf2727b77a937affecfeb07 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 13 Aug 2012 13:31:22 +0200 Subject: [PATCH 07/26] Split the kodos file into a small launcher and modules.main --- kodos | 1007 +---------------------------------------------- modules/main.py | 991 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 998 insertions(+), 1000 deletions(-) create mode 100644 modules/main.py diff --git a/kodos b/kodos index 49ead1b..b742888 100755 --- a/kodos +++ b/kodos @@ -4,1014 +4,21 @@ import sys import os -import string -import re -import cPickle -import types import getopt -import urllib -import signal try: - from PyQt4.QtGui import * - from PyQt4.QtCore import * + from PyQt4 import QtGui + from PyQt4 import QtCore except: sys.exit("""Could not locate the PyQt module. Please make sure that you have installed PyQt for the version of Python that you are running.""") ### make sure that this script can find kodos specific modules ### from distutils.sysconfig import get_python_lib - sys.path.append(os.path.join(get_python_lib(), "kodos")) -################################################################### - -from modules.kodosBA import * -from modules.util import * -from modules.about import * -import modules.help as help -from modules.status_bar import * -from modules.reference import * -from modules.prefs import * -from modules.version import VERSION -from modules.recent_files import RecentFiles -from modules.urlDialog import URLDialog -from modules.regexLibrary import RegexLibrary -from modules.newUserDialogBA import NewUserDialog -from modules.flags import reFlag, reFlagList - - -# match status -MATCH_NA = 0 -MATCH_OK = 1 -MATCH_FAIL = 2 -MATCH_PAUSED = 3 -MATCH_EXAMINED = 4 - -TRUE = 1 -FALSE = 0 - -TIMEOUT = 3 - -# regex to find special flags which must begin at beginning of line -# or after some spaces -EMBEDDED_FLAGS = r"^ *\(\?(?P[iLmsux]*)\)" - -RX_BACKREF = re.compile(r"""\\\d""") - -STATE_UNEDITED = 0 -STATE_EDITED = 1 - -GEO = "kodos_geometry" - -# colors for normal & examination mode -QCOLOR_WHITE = QColor(Qt.white) # normal -QCOLOR_YELLOW = QColor(255,255,127) # examine - -try: - signal.SIGALRM - HAS_ALARM = 1 -except: - HAS_ALARM = 0 - - -############################################################################## -# -# The Kodos class which defines the main functionality and user interaction -# -############################################################################## - -class Kodos(KodosBA): - def __init__(self, filename, debug): - KodosBA.__init__(self) - - self.debug = debug - self.regex = "" - self.matchstring = "" - self.replace = "" - self.is_paused = 0 - self.is_examined = 0 - self.filename = "" - self.match_num = 1 # matches are labeled 1..n - self.replace_num = 0 # replace all - self.url = None - self.group_tuples = None - self.editstate = STATE_UNEDITED - - self.ref_win = None - self.regexlibwin = None - - self.embedded_flags_obj = re.compile(EMBEDDED_FLAGS) - self.regex_embedded_flags_removed = "" - - self.createStatusBar() - - self.MSG_NA = self.tr("Enter a regular expression and a string to match against") - self.MSG_PAUSED = self.tr("Kodos regex processing is paused. Click the pause icon to unpause") - self.MSG_FAIL = self.tr("Pattern does not match") - - - self.statusPixmapsDict = { MATCH_NA: QPixmap(":images/yellow.png"), - MATCH_OK: QPixmap(":images/green.png"), - MATCH_FAIL: QPixmap(":images/red.png"), - MATCH_PAUSED: QPixmap(":images/pause.png"), - } - - - self.updateStatus(self.MSG_NA, MATCH_NA) - - self.reFlags = reFlagList([ - reFlag("re.IGNORECASE", "i", self.ignorecaseCheckBox), - reFlag("re.MULTILINE", "m", self.multilineCheckBox), - reFlag("re.DOTALL", "s", self.dotallCheckBox), - reFlag("re.VERBOSE", "x", self.verboseCheckBox), - reFlag("re.LOCALE", "L", self.localeCheckBox), - reFlag("re.UNICODE", "u", self.unicodeCheckBox), - ]) - self.reFlags.clearAll() - - restoreWindowSettings(self, GEO) - - self.show() - - self.prefs = Preferences(self, 1) - self.recent_files = RecentFiles(self, - self.prefs.recentFilesSpinBox.value(), - self.debug) - - if filename and self.openFile(filename): - qApp.processEvents() - - self.fileMenu.triggered.connect(self.fileMenuHandler) - - kodos_toolbar_logo(self.toolBar) - if self.replace: self.show_replace_widgets() - else: self.hide_replace_widgets() - - self.checkIfNewUser() - - - def checkIfNewUser(self): - s = QSettings() - if s.value('New User', "true").toPyObject() != "false": - self.newuserdialog = NewUserDialog() - self.newuserdialog.show() - s.setValue('New User', "false") - - - def createStatusBar(self): - self.status_bar = Status_Bar(self, FALSE, "") - - - def updateStatus(self, status_string, status_value, duration=0, replace=FALSE, tooltip=''): - pixmap = self.statusPixmapsDict.get(status_value) - - self.status_bar.set_message(status_string, duration, replace, tooltip, pixmap) - - - def fileMenuHandler(self, menuid): - if self.recent_files.isRecentFile(menuid): - fn = str(menuid.text()) - if self.openFile(fn): - self.recent_files.add(fn) - - def prefsSaved(self): - if self.debug: print "prefsSaved slot" - self.recent_files.setNumShown(self.prefs.recentFilesSpinBox.value()) - - - def kodos_edited_slot(self): - # invoked whenever the user has edited something - self.editstate = STATE_EDITED - - - def checkbox_slot(self): - self.process_regex() - - - def set_flags(self, flags): - # from the given integer value of flags, set the checkboxes - # this is used when loading a saved file - for f in self.reFlags: - f.checkBox.setChecked(flags & f.reFlag) - - - def get_flags_string(self): - flags_str = "" - - for f in self.reFlags: - if f.checkBox.isChecked(): - flags_str += "| " + f.flagName - - if flags_str: - flags_str = ", " + flags_str[1:] - return flags_str - - - def get_embedded_flags_string(self): - flags_str = flags = "" - - for f in self.reFlags: - if f.checkBox.isChecked(): - flags += f.shortFlag - - if flags: - flags_str = "(?" + flags + ")" - - return flags_str - - - def pause(self): - self.is_paused = not self.is_paused - if self.debug: print "is_paused:", self.is_paused - - if self.is_paused: - self.update_results(self.MSG_PAUSED, MATCH_PAUSED) - self.matchNumberSpinBox.setDisabled(1) - - else: - self.process_regex() - self.matchNumberSpinBox.setEnabled(1) - - - def examine(self): - self.is_examined = not self.is_examined - if self.debug: print "is_examined:", self.is_examined - - if self.is_examined: - color = QCOLOR_YELLOW - regex = self.regex - self.regex_saved = self.regex - length = len(regex) - self.regexMultiLineEdit.setReadOnly(1) - self.stringMultiLineEdit.setReadOnly(1) - self.replaceTextEdit.setReadOnly(1) - for i in range(length, 0, -1): - regex = regex[:i] - self.process_embedded_flags(self.regex) - try: - m = re.search(regex, self.matchstring, self.reFlags.allFlagsORed()) - if m: - if self.debug: print "examined regex:", regex - self.__refresh_regex_widget(color, regex) - return - except: - pass - - self.__refresh_regex_widget(color, "") - else: - regex = self.regex_saved - color = QCOLOR_WHITE - self.regexMultiLineEdit.setReadOnly(0) - self.stringMultiLineEdit.setReadOnly(0) - self.replaceTextEdit.setReadOnly(0) - self.__refresh_regex_widget(color, regex) - - - def __refresh_regex_widget(self, base_qcolor, regex): - pal = QPalette() - pal.setColor(pal.Base, base_qcolor) - self.regexMultiLineEdit.setPalette(pal) - - self.regexMultiLineEdit.blockSignals(1) - self.regexMultiLineEdit.clear() - self.regexMultiLineEdit.blockSignals(0) - self.regexMultiLineEdit.setPlainText(regex) - - - def match_num_slot(self, num): - self.match_num = num - self.process_regex() - - - def replace_num_slot(self, num): - self.replace_num = num - self.process_regex() - - - def regex_changed_slot(self): - self.regex = unicode(self.regexMultiLineEdit.toPlainText()) - self.process_regex() - - - def string_changed_slot(self): - self.matchstring = unicode(self.stringMultiLineEdit.toPlainText()) - self.process_regex() - - def helpContents(self, x = None): - pass #FIXME - def helpIndex(self, x = None): - pass #FIXME - - def hide_replace_widgets(self): - self.spacerLabel.hide() - self.replaceLabel.hide() - self.replaceNumberSpinBox.hide() - self.replaceTextBrowser.clear() - self.replaceTextBrowser.setDisabled(TRUE) - - def show_replace_widgets(self): - self.spacerLabel.show() - self.replaceLabel.show() - self.replaceNumberSpinBox.show() - self.replaceNumberSpinBox.setEnabled(TRUE) - self.replaceTextBrowser.setEnabled(TRUE) - - def replace_changed_slot(self): - self.replace = unicode(self.replaceTextEdit.toPlainText()) - self.process_regex() - if not self.replace: - self.hide_replace_widgets() - else: - self.show_replace_widgets() - - - def update_results(self, msg, val): - self.updateStatus(msg, val) - - - def populate_group_table(self, tuples): - rows = len(tuples) - # Remove old rows for groups that no longer exist - for i in range(rows, self.groupTable.rowCount()): - self.groupTable.removeRow(i) - - self.groupTable.setRowCount(rows) - row = 0 - for t in tuples: - self.groupTable.setItem(row, 0, QTableWidgetItem(t[1])) - self.groupTable.setItem(row, 1, QTableWidgetItem(t[2])) - row += 1 - - - def populate_code_textbrowser(self): - self.codeTextBrowser.clear() - - code = "import re\n\n" - code += "# common variables\n\n" - code += "rawstr = r\"\"\"" + self.regex_embedded_flags_removed + "\"\"\"\n" - code += "embedded_rawstr = r\"\"\"" + self.get_embedded_flags_string() + \ - self.regex_embedded_flags_removed + "\"\"\"\n" - code += 'matchstr = \"\"\"' + self.matchstring + '\"\"\"' - code += "\n\n" - code += "# method 1: using a compile object\n" - code += "compile_obj = re.compile(rawstr" - code += self.get_flags_string() - code += ")\n" - code += "match_obj = compile_obj.search(matchstr)\n\n" - - code += "# method 2: using search function (w/ external flags)\n" - code += "match_obj = re.search(rawstr, matchstr" - code += self.get_flags_string() - code += ")\n\n" - - code += "# method 3: using search function (w/ embedded flags)\n" - code += "match_obj = re.search(embedded_rawstr, matchstr)\n\n" - - - if self.group_tuples: - code += "# Retrieve group(s) from match_obj\n" - code += "all_groups = match_obj.groups()\n\n" - code += "# Retrieve group(s) by index\n" - i = 0 - named_grps = 0 - for grp in self.group_tuples: - i += 1 - code += "group_%d = match_obj.group(%d)\n" % (i, i) - if grp[1]: named_grps = 1 - - if named_grps: - code += "\n# Retrieve group(s) by name\n" - for grp in self.group_tuples: - if grp[1]: - code += "%s = match_obj.group('%s')\n" % (grp[1], grp[1]) - - code += "\n" - - if self.replace: - code += "# Replace string\n" - code += "newstr = compile_obj.subn('%s', %d)\n" % (self.replace, - self.replace_num) - - self.codeTextBrowser.setPlainText(code) - - - def colorize_strings(self, strings, widget, cursorOffset=0): - widget.clear() - - colors = (QBrush(QColor(Qt.black)), QBrush(QColor(Qt.blue)) ) - cur = widget.textCursor() - format = cur.charFormat() - - pos = cur.position() - i = 0 - for s in strings: - format.setForeground(colors[i%2]) - cur.insertText(s, format) - if i == cursorOffset: - pos = cur.position() - i += 1 - - cur.setPosition(pos) - widget.setTextCursor(cur) - widget.centerCursor() - - - def populate_match_textbrowser(self, startpos, endpos): - pre = post = match = "" - - match = self.matchstring[startpos:endpos] - - # prepend the beginning that didn't match - if startpos > 0: - pre = self.matchstring[0:startpos] - - # append the end that didn't match - if endpos < len(self.matchstring): - post = self.matchstring[endpos:] - - strings = [pre, match, post] - self.colorize_strings(strings, self.matchTextBrowser, 1) - - - def populate_replace_textbrowser(self, spans, nummatches, compile_obj): - self.replaceTextBrowser.clear() - if not spans: return - - num = self.replaceNumberSpinBox.value() - if num == 0: num = nummatches - text = self.matchstring - - replace_text = unicode(self.replaceTextEdit.toPlainText()) - if RX_BACKREF.search(replace_text): - # if the replace string contains a backref we just use the - # python regex methods for the substitution - replaced = compile_obj.subn(replace_text, text, num)[0] - self.replaceTextBrowser.setPlainText(replaced) - return - - numreplaced = idx = 0 - - strings = [] - - for span in spans: - if span[0] != 0: - s = text[idx:span[0]] - else: - s = "" - - idx = span[1] - numreplaced += 1 - - strings.append(s) - strings.append(self.replace) - - if numreplaced >= num: - strings.append(text[span[1]:]) - break - - self.colorize_strings(strings, self.replaceTextBrowser) - - - def populate_matchAll_textbrowser(self, spans): - self.matchAllTextBrowser.clear() - if not spans: return - - idx = 0 - text = self.matchstring - strings = [] - for span in spans: - if span[0] != 0: - s = text[idx:span[0]] - else: - s = "" - - idx = span[1] - strings.append(s) - strings.append(text[span[0]:span[1]]) - - if 0 <= idx <= len(text): - strings.append(text[span[1]:]) - - self.colorize_strings(strings, self.matchAllTextBrowser) - - - def clear_results(self): - # .clear() destroys the headers, and .clearContents() doesn't do - # anything at all, so remove the rows one by one - for i in range(self.groupTable.rowCount()): - self.groupTable.removeRow(i) - - self.codeTextBrowser.clear() - self.matchTextBrowser.clear() - self.matchNumberSpinBox.setEnabled(FALSE) - self.replaceNumberSpinBox.setEnabled(FALSE) - self.replaceTextBrowser.clear() - self.matchAllTextBrowser.clear() - - - def process_regex(self): - def timeout(signum, frame): - return - - if self.is_paused: - return - - self.process_embedded_flags(self.regex) - - if not self.regex or not self.matchstring: - self.update_results(self.MSG_NA, MATCH_NA) - self.clear_results() - return - - if HAS_ALARM: - signal.signal(signal.SIGALRM, timeout) - signal.alarm(TIMEOUT) - - try: - compile_obj = re.compile(self.regex, self.reFlags.allFlagsORed()) - allmatches = compile_obj.findall(self.matchstring) - - if allmatches and len(allmatches): - self.matchNumberSpinBox.setMaximum(len(allmatches)) - self.matchNumberSpinBox.setEnabled(TRUE) - self.replaceNumberSpinBox.setMaximum(len(allmatches)) - self.replaceNumberSpinBox.setEnabled(TRUE) - else: - self.matchNumberSpinBox.setEnabled(FALSE) - self.replaceNumberSpinBox.setEnabled(FALSE) - - match_obj = compile_obj.search(self.matchstring) - - except Exception, e: - self.update_results(unicode(e), MATCH_FAIL) - return - - if HAS_ALARM: - signal.alarm(0) - - if not match_obj: - self.update_results(self.MSG_FAIL, MATCH_FAIL) - - self.clear_results() - return - - # match_index is the list element for match_num. - # Therefor match_num is for ui display - # and match_index is for application logic. - match_index = self.match_num - 1 - - if match_index > 0: - for i in range(match_index): - match_obj = compile_obj.search(self.matchstring, - match_obj.end()) - - self.populate_match_textbrowser(match_obj.start(), match_obj.end()) - - self.group_tuples = [] - - if match_obj.groups(): - group_nums = {} - if compile_obj.groupindex: - keys = compile_obj.groupindex.keys() - for key in keys: - group_nums[compile_obj.groupindex[key]] = key - - if self.debug: - print "group_nums:", group_nums - print "grp index: ", compile_obj.groupindex - print "groups:", match_obj.groups() - print "span: ", match_obj.span() - - # create group_tuple in the form: (group #, group name, group matches) - g = allmatches[match_index] - if type(g) == types.TupleType: - for i in range(len(g)): - group_tuple = (i+1, group_nums.get(i+1, ""), g[i]) - self.group_tuples.append(group_tuple) - else: - self.group_tuples.append( (1, group_nums.get(1, ""), g) ) - - self.populate_group_table(self.group_tuples) - else: - # clear the group table - self.populate_group_table([]) - - str_pattern_matches = unicode(self.tr("Pattern matches")) - str_found = unicode(self.tr("found")) - str_match = unicode(self.tr("match")) - str_matches = unicode(self.tr("matches")) - - if len(allmatches) == 1: - status = "%s (%s 1 %s)" % (str_pattern_matches, - str_found, - str_match) - else: - status = "%s (%s %d %s)" % (str_pattern_matches, - str_found, - len(allmatches), - str_matches) - - self.update_results(status, MATCH_OK) - self.populate_code_textbrowser() - - spans = self.findAllSpans(compile_obj) - if self.replace: - self.populate_replace_textbrowser(spans, len(allmatches), compile_obj) - self.populate_matchAll_textbrowser(spans) - - - def findAllSpans(self, compile_obj): - spans = [] - - match_obj = compile_obj.search(self.matchstring) - - last_span = None - - while match_obj: - start = match_obj.start() - end = match_obj.end() - span = (start, end) - if last_span == span: break - - spans.append(span) - - last_span = span - match_obj = compile_obj.search(self.matchstring, end) - - return spans - - - def closeEvent(self, ev): - if not self.checkEditState(): - ev.ignore() - return - - saveWindowSettings(self, GEO) - - try: - self.regexlibwin.close() - except: - pass - - try: - self.ref_win.close() - except: - pass - ev.accept() - - - def fileNew(self): - if not self.checkEditState(): - return - self.filename = "" - - self.regexMultiLineEdit.setPlainText("") - self.stringMultiLineEdit.setPlainText("") - self.replaceTextEdit.setPlainText("") - self.set_flags(0) - self.editstate = STATE_UNEDITED - - - def importURL(self): - self.urldialog = URLDialog(self, self.url) - self.urldialog.urlImported.connect(self.urlImported) - - - def urlImported(self, html, url): - self.url = url - self.stringMultiLineEdit.setPlainText(html) - - - def importFile(self): - fn = QFileDialog.getOpenFileName(self, - self.tr("Import File"), - self.filename, - self.tr("All (*)")) - - if fn.isEmpty(): - self.updateStatus(self.tr("A file was not selected for import"), - -1, - 5, - TRUE) - return None - - filename = str(fn) - - try: - fp = open(filename, "r") - except: - msg = self.tr("Could not open file for reading: ") + filename - self.updateStatus(msg, -1, 5, TRUE) - return None - - data = fp.read() - fp.close() - self.stringMultiLineEdit.setPlainText(data) - - - def fileOpen(self): - filename = self.filename - if filename == None: - filename = "" - fn = QFileDialog.getOpenFileName(self, - self.tr("Open Kodos File"), - filename, - self.tr("Kodos file (*.kds);;All (*)")) - if not fn.isEmpty(): - filename = str(fn) - if self.openFile(filename): - self.recent_files.add(filename) - - - def openFile(self, filename): - if not self.checkEditState(): - return - - self.filename = None - - try: - fp = open(filename, "r") - except: - msg = self.tr("Could not open file for reading: ") + filename - self.updateStatus(msg, -1, 5, TRUE) - return None - - try: - u = cPickle.Unpickler(fp) - self.regex = u.load() - self.matchstring = u.load() - flags = u.load() - except Exception, e: #FIXME: don't catch everything - if self.debug: - print unicode(e) - msg = "%s %s" % (unicode(self.tr("Error reading from file:")), - filename) - self.updateStatus(msg, -1, 5, TRUE) - return 0 - - self.matchNumberSpinBox.setValue(1) - self.regexMultiLineEdit.setPlainText(self.regex) - self.stringMultiLineEdit.setPlainText(self.matchstring) - - self.set_flags(flags) - - try: - replace = u.load() - except: - # versions prior to 1.7 did not have replace functionality - # so kds files saved w/ these versions will throw exception - # here. - replace = "" - self.replaceTextEdit.setPlainText(replace) - - self.filename = filename - msg = "%s %s" % (filename, unicode(self.tr("loaded successfully"))) - self.updateStatus(msg, -1, 5, TRUE) - self.editstate = STATE_UNEDITED - return 1 - - - def fileSaveAs(self): - filename = self.filename - if filename == None: - filename = "" - filedialog = QFileDialog(self, - self.tr("Save Kodos File"), - filename, - "Kodos file (*.kds);;All (*)") - filedialog.setAcceptMode(QFileDialog.AcceptSave) - filedialog.setDefaultSuffix("kds") - ok = filedialog.exec_() - - if ok == QDialog.Rejected: - self.updateStatus(self.tr("No file selected to save"), -1, 5, TRUE) - return - - filename = os.path.normcase(unicode(filedialog.selectedFiles().first())) - - self.filename = filename - self.fileSave() - - - def fileSave(self): - if not self.filename: - self.fileSaveAs() - return - - try: - fp = open(self.filename, "w") - except: - msg = "%s: %s" % (unicode(self.tr("Could not open file for writing:")), - self.filename) - self.updateStatus(msg, -1, 5, TRUE) - return None - - self.editstate = STATE_UNEDITED - p = cPickle.Pickler(fp) - p.dump(self.regex) - p.dump(self.matchstring) - p.dump(self.reFlags.allFlagsORed()) - p.dump(self.replace) - - fp.close() - msg = "%s %s" % (unicode(self.filename), - unicode(self.tr("successfully saved"))) - self.updateStatus(msg, -1, 5, TRUE) - self.recent_files.add(self.filename) - - - def paste_symbol(self, symbol): - self.regexMultiLineEdit.insertPlainText(symbol) - - - def process_embedded_flags(self, regex): - # determine if the regex contains embedded regex flags. - # if it does, set the appropriate checkboxes on the UI to reflect the flags that are embedded - match = self.embedded_flags_obj.match(regex) - if not match: - embedded_flags = "" - self.regex_embedded_flags_removed = regex - else: - embedded_flags = match.group('flags') - self.regex_embedded_flags_removed = self.embedded_flags_obj.sub("", regex, 1) - - for f in self.reFlags: - if f.shortFlag in embedded_flags: - f.embed() - else: - f.deembed() - - - def checkEditState(self): - if self.editstate == STATE_EDITED: - message = self.tr("You have made changes. Would you like to save them before continuing?") - - prompt = QMessageBox.warning(None, - self.tr("Save changes?"), - message, - QMessageBox.Save | - QMessageBox.Cancel | - QMessageBox.Discard) - - if prompt == QMessageBox.Cancel: - return False - - if prompt == QMessageBox.Save: - self.fileSave() - if not self.filename: self.checkEditState() - - return True - - - def pasteFromRegexLib(self, d): - if not self.checkEditState(): - return - - self.filename = "" - - self.regexMultiLineEdit.setPlainText(d.get('regex', "")) - self.stringMultiLineEdit.setPlainText(d.get('text', "")) - self.replaceTextEdit.setPlainText(d.get('replace', "")) - - try: - # set the current page if applicable - self.resultTabWidget.setCurrentIndex(int(d['tab'])) - except KeyError: - pass - self.editstate = STATE_UNEDITED - - - def revert_file_slot(self): - if not self.filename: - self.updateStatus(self.tr("There is no filename to revert"), - -1, - 5, - TRUE) - return - - self.openFile(self.filename) - - - def getWidget(self): - widget = qApp.focusWidget() - if (widget == self.regexMultiLineEdit or - widget == self.stringMultiLineEdit or - widget == self.replaceTextEdit or - widget == self.codeTextBrowser): - return widget - else: - return None - - - def widgetMethod(self, methodstr, anywidget=0): - # execute the methodstr of widget only if widget - # is one of the editable widgets OR if the method - # may be applied to any widget. - widget = qApp.focusWidget() - if anywidget or ( - widget == self.regexMultiLineEdit or - widget == self.stringMultiLineEdit or - widget == self.replaceTextEdit or - widget == self.codeTextBrowser): - try: - eval("widget.%s" % methodstr) - except: - pass - - - def editUndo(self): - self.widgetMethod("undo()") - - def editRedo(self): - self.widgetMethod("redo()") - - def editCopy(self): - self.widgetMethod("copy()", 1) - - def editCut(self): - self.widgetMethod("cut()") - - def editPaste(self): - self.widgetMethod("paste()") - - - def preferences(self): - self.prefs.showPrefsDialog() - self.prefs.prefsSaved.connect(self.prefsSaved) - - def setfont(self, font): - self.regexMultiLineEdit.setFont(font) - self.stringMultiLineEdit.setFont(font) - self.replaceTextEdit.setFont(font) - - def setMatchFont(self, font): - self.groupTable.setFont(font) - self.matchTextBrowser.setFont(font) - self.matchAllTextBrowser.setFont(font) - self.replaceTextBrowser.setFont(font) - self.codeTextBrowser.setFont(font) - - - def getfont(self): - return self.regexMultiLineEdit.font() - - - def getMatchFont(self): - return self.groupTable.font() - - - def helpHelp(self): - self.helpWindow = help.Help(self, "kodos.html") - - - def helpPythonRegex(self): - self.helpWindow = help.Help(self, os.path.join("python", "module-re.html")) - - - def helpRegexLib(self): - f = os.path.join("help", "regex-lib.xml") - self.regexlibwin = RegexLibrary(f) - self.regexlibwin.pasteRegexLib.connect(self.pasteFromRegexLib) - self.regexlibwin.show() - - - def helpAbout(self): - self.aboutWindow = About() - self.aboutWindow.show() - - - def kodos_website(self): - self.launch_browser_wrapper('https://github.com/luksan/kodos', - message=self.tr('Launch web browser to go to the kodos project page?')) - - - def launch_browser_wrapper(self, url, caption=None, message=None): - if launch_browser(url, caption, message): - self.status_bar.set_message(self.tr("Launching web browser"), - 3, - TRUE) - else: - self.status_bar.set_message(self.tr("Cancelled web browser launch"), - 3, - TRUE) - - - def reference_guide(self): - self.ref_win = Reference(self) - self.ref_win.pasteSymbol.connect(self.paste_symbol) - self.ref_win.show() - - - def report_bug(self): - self.launch_browser_wrapper('https://github.com/luksan/kodos/issues', - message=self.tr("Launch web browser to report a bug in kodos?")) - - -############################################################################## -# -# -############################################################################## +from modules.main import Kodos +from modules.util import findFile def usage(): print "kodos.py [-f filename | --file=filename ] [ -d debug | --debug=debug ] [ -k kodos_dir ]" @@ -1056,20 +63,20 @@ def main(): os.environ['KODOS_DIR'] = kodos_dir - qApp = QApplication(sys.argv) + qApp = QtGui.QApplication(sys.argv) qApp.setOrganizationName("kodos") qApp.setApplicationName("kodos") qApp.setOrganizationDomain("kodos.sourceforge.net") if locale not in (None, 'en'): - localefile = "kodos_%s.qm" % (locale or QTextCodec.locale()) + localefile = "kodos_%s.qm" % (locale or QtCore.QTextCodec.locale()) localepath = findFile(os.path.join("translations", localefile)) if debug: print "locale changed to:", locale print localefile print localepath - translator = QTranslator(qApp) + translator = QtCore.QTranslator(qApp) translator.load(localepath) qApp.installTranslator(translator) diff --git a/modules/main.py b/modules/main.py new file mode 100644 index 0000000..e97f498 --- /dev/null +++ b/modules/main.py @@ -0,0 +1,991 @@ +# -*- coding: utf-8 -*- + +import re +import types +import signal +import string +import urllib +import cPickle + +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +from kodosBA import * +from util import * +from about import * +from . import help +from status_bar import * +from reference import * +from prefs import * +from version import VERSION +from recent_files import RecentFiles +from urlDialog import URLDialog +from regexLibrary import RegexLibrary +from newUserDialogBA import NewUserDialog +from flags import reFlag, reFlagList + +# match status +MATCH_NA = 0 +MATCH_OK = 1 +MATCH_FAIL = 2 +MATCH_PAUSED = 3 +MATCH_EXAMINED = 4 + +TRUE = 1 +FALSE = 0 + +TIMEOUT = 3 + +# regex to find special flags which must begin at beginning of line +# or after some spaces +EMBEDDED_FLAGS = r"^ *\(\?(?P[iLmsux]*)\)" + +RX_BACKREF = re.compile(r"""\\\d""") + +STATE_UNEDITED = 0 +STATE_EDITED = 1 + +GEO = "kodos_geometry" + +# colors for normal & examination mode +QCOLOR_WHITE = QColor(Qt.white) # normal +QCOLOR_YELLOW = QColor(255,255,127) # examine + +try: + signal.SIGALRM + HAS_ALARM = 1 +except: + HAS_ALARM = 0 + + +############################################################################## +# +# The Kodos class which defines the main functionality and user interaction +# +############################################################################## + +class Kodos(KodosBA): + def __init__(self, filename, debug): + KodosBA.__init__(self) + + self.debug = debug + self.regex = "" + self.matchstring = "" + self.replace = "" + self.is_paused = 0 + self.is_examined = 0 + self.filename = "" + self.match_num = 1 # matches are labeled 1..n + self.replace_num = 0 # replace all + self.url = None + self.group_tuples = None + self.editstate = STATE_UNEDITED + + self.ref_win = None + self.regexlibwin = None + + self.embedded_flags_obj = re.compile(EMBEDDED_FLAGS) + self.regex_embedded_flags_removed = "" + + self.createStatusBar() + + self.MSG_NA = self.tr("Enter a regular expression and a string to match against") + self.MSG_PAUSED = self.tr("Kodos regex processing is paused. Click the pause icon to unpause") + self.MSG_FAIL = self.tr("Pattern does not match") + + + self.statusPixmapsDict = { MATCH_NA: QPixmap(":images/yellow.png"), + MATCH_OK: QPixmap(":images/green.png"), + MATCH_FAIL: QPixmap(":images/red.png"), + MATCH_PAUSED: QPixmap(":images/pause.png"), + } + + + self.updateStatus(self.MSG_NA, MATCH_NA) + + self.reFlags = reFlagList([ + reFlag("re.IGNORECASE", "i", self.ignorecaseCheckBox), + reFlag("re.MULTILINE", "m", self.multilineCheckBox), + reFlag("re.DOTALL", "s", self.dotallCheckBox), + reFlag("re.VERBOSE", "x", self.verboseCheckBox), + reFlag("re.LOCALE", "L", self.localeCheckBox), + reFlag("re.UNICODE", "u", self.unicodeCheckBox), + ]) + self.reFlags.clearAll() + + restoreWindowSettings(self, GEO) + + self.show() + + self.prefs = Preferences(self, 1) + self.recent_files = RecentFiles(self, + self.prefs.recentFilesSpinBox.value(), + self.debug) + + if filename and self.openFile(filename): + qApp.processEvents() + + self.fileMenu.triggered.connect(self.fileMenuHandler) + + kodos_toolbar_logo(self.toolBar) + if self.replace: self.show_replace_widgets() + else: self.hide_replace_widgets() + + self.checkIfNewUser() + + + def checkIfNewUser(self): + s = QSettings() + if s.value('New User', "true").toPyObject() != "false": + self.newuserdialog = NewUserDialog() + self.newuserdialog.show() + s.setValue('New User', "false") + + + def createStatusBar(self): + self.status_bar = Status_Bar(self, FALSE, "") + + + def updateStatus(self, status_string, status_value, duration=0, replace=FALSE, tooltip=''): + pixmap = self.statusPixmapsDict.get(status_value) + + self.status_bar.set_message(status_string, duration, replace, tooltip, pixmap) + + + def fileMenuHandler(self, menuid): + if self.recent_files.isRecentFile(menuid): + fn = str(menuid.text()) + if self.openFile(fn): + self.recent_files.add(fn) + + def prefsSaved(self): + if self.debug: print "prefsSaved slot" + self.recent_files.setNumShown(self.prefs.recentFilesSpinBox.value()) + + + def kodos_edited_slot(self): + # invoked whenever the user has edited something + self.editstate = STATE_EDITED + + + def checkbox_slot(self): + self.process_regex() + + + def set_flags(self, flags): + # from the given integer value of flags, set the checkboxes + # this is used when loading a saved file + for f in self.reFlags: + f.checkBox.setChecked(flags & f.reFlag) + + + def get_flags_string(self): + flags_str = "" + + for f in self.reFlags: + if f.checkBox.isChecked(): + flags_str += "| " + f.flagName + + if flags_str: + flags_str = ", " + flags_str[1:] + return flags_str + + + def get_embedded_flags_string(self): + flags_str = flags = "" + + for f in self.reFlags: + if f.checkBox.isChecked(): + flags += f.shortFlag + + if flags: + flags_str = "(?" + flags + ")" + + return flags_str + + + def pause(self): + self.is_paused = not self.is_paused + if self.debug: print "is_paused:", self.is_paused + + if self.is_paused: + self.update_results(self.MSG_PAUSED, MATCH_PAUSED) + self.matchNumberSpinBox.setDisabled(1) + + else: + self.process_regex() + self.matchNumberSpinBox.setEnabled(1) + + + def examine(self): + self.is_examined = not self.is_examined + if self.debug: print "is_examined:", self.is_examined + + if self.is_examined: + color = QCOLOR_YELLOW + regex = self.regex + self.regex_saved = self.regex + length = len(regex) + self.regexMultiLineEdit.setReadOnly(1) + self.stringMultiLineEdit.setReadOnly(1) + self.replaceTextEdit.setReadOnly(1) + for i in range(length, 0, -1): + regex = regex[:i] + self.process_embedded_flags(self.regex) + try: + m = re.search(regex, self.matchstring, self.reFlags.allFlagsORed()) + if m: + if self.debug: print "examined regex:", regex + self.__refresh_regex_widget(color, regex) + return + except: + pass + + self.__refresh_regex_widget(color, "") + else: + regex = self.regex_saved + color = QCOLOR_WHITE + self.regexMultiLineEdit.setReadOnly(0) + self.stringMultiLineEdit.setReadOnly(0) + self.replaceTextEdit.setReadOnly(0) + self.__refresh_regex_widget(color, regex) + + + def __refresh_regex_widget(self, base_qcolor, regex): + pal = QPalette() + pal.setColor(pal.Base, base_qcolor) + self.regexMultiLineEdit.setPalette(pal) + + self.regexMultiLineEdit.blockSignals(1) + self.regexMultiLineEdit.clear() + self.regexMultiLineEdit.blockSignals(0) + self.regexMultiLineEdit.setPlainText(regex) + + + def match_num_slot(self, num): + self.match_num = num + self.process_regex() + + + def replace_num_slot(self, num): + self.replace_num = num + self.process_regex() + + + def regex_changed_slot(self): + self.regex = unicode(self.regexMultiLineEdit.toPlainText()) + self.process_regex() + + + def string_changed_slot(self): + self.matchstring = unicode(self.stringMultiLineEdit.toPlainText()) + self.process_regex() + + def helpContents(self, x = None): + pass #FIXME + def helpIndex(self, x = None): + pass #FIXME + + def hide_replace_widgets(self): + self.spacerLabel.hide() + self.replaceLabel.hide() + self.replaceNumberSpinBox.hide() + self.replaceTextBrowser.clear() + self.replaceTextBrowser.setDisabled(TRUE) + + def show_replace_widgets(self): + self.spacerLabel.show() + self.replaceLabel.show() + self.replaceNumberSpinBox.show() + self.replaceNumberSpinBox.setEnabled(TRUE) + self.replaceTextBrowser.setEnabled(TRUE) + + def replace_changed_slot(self): + self.replace = unicode(self.replaceTextEdit.toPlainText()) + self.process_regex() + if not self.replace: + self.hide_replace_widgets() + else: + self.show_replace_widgets() + + + def update_results(self, msg, val): + self.updateStatus(msg, val) + + + def populate_group_table(self, tuples): + rows = len(tuples) + # Remove old rows for groups that no longer exist + for i in range(rows, self.groupTable.rowCount()): + self.groupTable.removeRow(i) + + self.groupTable.setRowCount(rows) + row = 0 + for t in tuples: + self.groupTable.setItem(row, 0, QTableWidgetItem(t[1])) + self.groupTable.setItem(row, 1, QTableWidgetItem(t[2])) + row += 1 + + + def populate_code_textbrowser(self): + self.codeTextBrowser.clear() + + code = "import re\n\n" + code += "# common variables\n\n" + code += "rawstr = r\"\"\"" + self.regex_embedded_flags_removed + "\"\"\"\n" + code += "embedded_rawstr = r\"\"\"" + self.get_embedded_flags_string() + \ + self.regex_embedded_flags_removed + "\"\"\"\n" + code += 'matchstr = \"\"\"' + self.matchstring + '\"\"\"' + code += "\n\n" + code += "# method 1: using a compile object\n" + code += "compile_obj = re.compile(rawstr" + code += self.get_flags_string() + code += ")\n" + code += "match_obj = compile_obj.search(matchstr)\n\n" + + code += "# method 2: using search function (w/ external flags)\n" + code += "match_obj = re.search(rawstr, matchstr" + code += self.get_flags_string() + code += ")\n\n" + + code += "# method 3: using search function (w/ embedded flags)\n" + code += "match_obj = re.search(embedded_rawstr, matchstr)\n\n" + + + if self.group_tuples: + code += "# Retrieve group(s) from match_obj\n" + code += "all_groups = match_obj.groups()\n\n" + code += "# Retrieve group(s) by index\n" + i = 0 + named_grps = 0 + for grp in self.group_tuples: + i += 1 + code += "group_%d = match_obj.group(%d)\n" % (i, i) + if grp[1]: named_grps = 1 + + if named_grps: + code += "\n# Retrieve group(s) by name\n" + for grp in self.group_tuples: + if grp[1]: + code += "%s = match_obj.group('%s')\n" % (grp[1], grp[1]) + + code += "\n" + + if self.replace: + code += "# Replace string\n" + code += "newstr = compile_obj.subn('%s', %d)\n" % (self.replace, + self.replace_num) + + self.codeTextBrowser.setPlainText(code) + + + def colorize_strings(self, strings, widget, cursorOffset=0): + widget.clear() + + colors = (QBrush(QColor(Qt.black)), QBrush(QColor(Qt.blue)) ) + cur = widget.textCursor() + format = cur.charFormat() + + pos = cur.position() + i = 0 + for s in strings: + format.setForeground(colors[i%2]) + cur.insertText(s, format) + if i == cursorOffset: + pos = cur.position() + i += 1 + + cur.setPosition(pos) + widget.setTextCursor(cur) + widget.centerCursor() + + + def populate_match_textbrowser(self, startpos, endpos): + pre = post = match = "" + + match = self.matchstring[startpos:endpos] + + # prepend the beginning that didn't match + if startpos > 0: + pre = self.matchstring[0:startpos] + + # append the end that didn't match + if endpos < len(self.matchstring): + post = self.matchstring[endpos:] + + strings = [pre, match, post] + self.colorize_strings(strings, self.matchTextBrowser, 1) + + + def populate_replace_textbrowser(self, spans, nummatches, compile_obj): + self.replaceTextBrowser.clear() + if not spans: return + + num = self.replaceNumberSpinBox.value() + if num == 0: num = nummatches + text = self.matchstring + + replace_text = unicode(self.replaceTextEdit.toPlainText()) + if RX_BACKREF.search(replace_text): + # if the replace string contains a backref we just use the + # python regex methods for the substitution + replaced = compile_obj.subn(replace_text, text, num)[0] + self.replaceTextBrowser.setPlainText(replaced) + return + + numreplaced = idx = 0 + + strings = [] + + for span in spans: + if span[0] != 0: + s = text[idx:span[0]] + else: + s = "" + + idx = span[1] + numreplaced += 1 + + strings.append(s) + strings.append(self.replace) + + if numreplaced >= num: + strings.append(text[span[1]:]) + break + + self.colorize_strings(strings, self.replaceTextBrowser) + + + def populate_matchAll_textbrowser(self, spans): + self.matchAllTextBrowser.clear() + if not spans: return + + idx = 0 + text = self.matchstring + strings = [] + for span in spans: + if span[0] != 0: + s = text[idx:span[0]] + else: + s = "" + + idx = span[1] + strings.append(s) + strings.append(text[span[0]:span[1]]) + + if 0 <= idx <= len(text): + strings.append(text[span[1]:]) + + self.colorize_strings(strings, self.matchAllTextBrowser) + + + def clear_results(self): + # .clear() destroys the headers, and .clearContents() doesn't do + # anything at all, so remove the rows one by one + for i in range(self.groupTable.rowCount()): + self.groupTable.removeRow(i) + + self.codeTextBrowser.clear() + self.matchTextBrowser.clear() + self.matchNumberSpinBox.setEnabled(FALSE) + self.replaceNumberSpinBox.setEnabled(FALSE) + self.replaceTextBrowser.clear() + self.matchAllTextBrowser.clear() + + + def process_regex(self): + def timeout(signum, frame): + return + + if self.is_paused: + return + + self.process_embedded_flags(self.regex) + + if not self.regex or not self.matchstring: + self.update_results(self.MSG_NA, MATCH_NA) + self.clear_results() + return + + if HAS_ALARM: + signal.signal(signal.SIGALRM, timeout) + signal.alarm(TIMEOUT) + + try: + compile_obj = re.compile(self.regex, self.reFlags.allFlagsORed()) + allmatches = compile_obj.findall(self.matchstring) + + if allmatches and len(allmatches): + self.matchNumberSpinBox.setMaximum(len(allmatches)) + self.matchNumberSpinBox.setEnabled(TRUE) + self.replaceNumberSpinBox.setMaximum(len(allmatches)) + self.replaceNumberSpinBox.setEnabled(TRUE) + else: + self.matchNumberSpinBox.setEnabled(FALSE) + self.replaceNumberSpinBox.setEnabled(FALSE) + + match_obj = compile_obj.search(self.matchstring) + + except Exception, e: + self.update_results(unicode(e), MATCH_FAIL) + return + + if HAS_ALARM: + signal.alarm(0) + + if not match_obj: + self.update_results(self.MSG_FAIL, MATCH_FAIL) + + self.clear_results() + return + + # match_index is the list element for match_num. + # Therefor match_num is for ui display + # and match_index is for application logic. + match_index = self.match_num - 1 + + if match_index > 0: + for i in range(match_index): + match_obj = compile_obj.search(self.matchstring, + match_obj.end()) + + self.populate_match_textbrowser(match_obj.start(), match_obj.end()) + + self.group_tuples = [] + + if match_obj.groups(): + group_nums = {} + if compile_obj.groupindex: + keys = compile_obj.groupindex.keys() + for key in keys: + group_nums[compile_obj.groupindex[key]] = key + + if self.debug: + print "group_nums:", group_nums + print "grp index: ", compile_obj.groupindex + print "groups:", match_obj.groups() + print "span: ", match_obj.span() + + # create group_tuple in the form: (group #, group name, group matches) + g = allmatches[match_index] + if type(g) == types.TupleType: + for i in range(len(g)): + group_tuple = (i+1, group_nums.get(i+1, ""), g[i]) + self.group_tuples.append(group_tuple) + else: + self.group_tuples.append( (1, group_nums.get(1, ""), g) ) + + self.populate_group_table(self.group_tuples) + else: + # clear the group table + self.populate_group_table([]) + + str_pattern_matches = unicode(self.tr("Pattern matches")) + str_found = unicode(self.tr("found")) + str_match = unicode(self.tr("match")) + str_matches = unicode(self.tr("matches")) + + if len(allmatches) == 1: + status = "%s (%s 1 %s)" % (str_pattern_matches, + str_found, + str_match) + else: + status = "%s (%s %d %s)" % (str_pattern_matches, + str_found, + len(allmatches), + str_matches) + + self.update_results(status, MATCH_OK) + self.populate_code_textbrowser() + + spans = self.findAllSpans(compile_obj) + if self.replace: + self.populate_replace_textbrowser(spans, len(allmatches), compile_obj) + self.populate_matchAll_textbrowser(spans) + + + def findAllSpans(self, compile_obj): + spans = [] + + match_obj = compile_obj.search(self.matchstring) + + last_span = None + + while match_obj: + start = match_obj.start() + end = match_obj.end() + span = (start, end) + if last_span == span: break + + spans.append(span) + + last_span = span + match_obj = compile_obj.search(self.matchstring, end) + + return spans + + + def closeEvent(self, ev): + if not self.checkEditState(): + ev.ignore() + return + + saveWindowSettings(self, GEO) + + try: + self.regexlibwin.close() + except: + pass + + try: + self.ref_win.close() + except: + pass + ev.accept() + + + def fileNew(self): + if not self.checkEditState(): + return + self.filename = "" + + self.regexMultiLineEdit.setPlainText("") + self.stringMultiLineEdit.setPlainText("") + self.replaceTextEdit.setPlainText("") + self.set_flags(0) + self.editstate = STATE_UNEDITED + + + def importURL(self): + self.urldialog = URLDialog(self, self.url) + self.urldialog.urlImported.connect(self.urlImported) + + + def urlImported(self, html, url): + self.url = url + self.stringMultiLineEdit.setPlainText(html) + + + def importFile(self): + fn = QFileDialog.getOpenFileName(self, + self.tr("Import File"), + self.filename, + self.tr("All (*)")) + + if fn.isEmpty(): + self.updateStatus(self.tr("A file was not selected for import"), + -1, + 5, + TRUE) + return None + + filename = str(fn) + + try: + fp = open(filename, "r") + except: + msg = self.tr("Could not open file for reading: ") + filename + self.updateStatus(msg, -1, 5, TRUE) + return None + + data = fp.read() + fp.close() + self.stringMultiLineEdit.setPlainText(data) + + + def fileOpen(self): + filename = self.filename + if filename == None: + filename = "" + fn = QFileDialog.getOpenFileName(self, + self.tr("Open Kodos File"), + filename, + self.tr("Kodos file (*.kds);;All (*)")) + if not fn.isEmpty(): + filename = str(fn) + if self.openFile(filename): + self.recent_files.add(filename) + + + def openFile(self, filename): + if not self.checkEditState(): + return + + self.filename = None + + try: + fp = open(filename, "r") + except: + msg = self.tr("Could not open file for reading: ") + filename + self.updateStatus(msg, -1, 5, TRUE) + return None + + try: + u = cPickle.Unpickler(fp) + self.regex = u.load() + self.matchstring = u.load() + flags = u.load() + except Exception, e: #FIXME: don't catch everything + if self.debug: + print unicode(e) + msg = "%s %s" % (unicode(self.tr("Error reading from file:")), + filename) + self.updateStatus(msg, -1, 5, TRUE) + return 0 + + self.matchNumberSpinBox.setValue(1) + self.regexMultiLineEdit.setPlainText(self.regex) + self.stringMultiLineEdit.setPlainText(self.matchstring) + + self.set_flags(flags) + + try: + replace = u.load() + except: + # versions prior to 1.7 did not have replace functionality + # so kds files saved w/ these versions will throw exception + # here. + replace = "" + self.replaceTextEdit.setPlainText(replace) + + self.filename = filename + msg = "%s %s" % (filename, unicode(self.tr("loaded successfully"))) + self.updateStatus(msg, -1, 5, TRUE) + self.editstate = STATE_UNEDITED + return 1 + + + def fileSaveAs(self): + filename = self.filename + if filename == None: + filename = "" + filedialog = QFileDialog(self, + self.tr("Save Kodos File"), + filename, + "Kodos file (*.kds);;All (*)") + filedialog.setAcceptMode(QFileDialog.AcceptSave) + filedialog.setDefaultSuffix("kds") + ok = filedialog.exec_() + + if ok == QDialog.Rejected: + self.updateStatus(self.tr("No file selected to save"), -1, 5, TRUE) + return + + filename = os.path.normcase(unicode(filedialog.selectedFiles().first())) + + self.filename = filename + self.fileSave() + + + def fileSave(self): + if not self.filename: + self.fileSaveAs() + return + + try: + fp = open(self.filename, "w") + except: + msg = "%s: %s" % (unicode(self.tr("Could not open file for writing:")), + self.filename) + self.updateStatus(msg, -1, 5, TRUE) + return None + + self.editstate = STATE_UNEDITED + p = cPickle.Pickler(fp) + p.dump(self.regex) + p.dump(self.matchstring) + p.dump(self.reFlags.allFlagsORed()) + p.dump(self.replace) + + fp.close() + msg = "%s %s" % (unicode(self.filename), + unicode(self.tr("successfully saved"))) + self.updateStatus(msg, -1, 5, TRUE) + self.recent_files.add(self.filename) + + + def paste_symbol(self, symbol): + self.regexMultiLineEdit.insertPlainText(symbol) + + + def process_embedded_flags(self, regex): + # determine if the regex contains embedded regex flags. + # if it does, set the appropriate checkboxes on the UI to reflect the flags that are embedded + match = self.embedded_flags_obj.match(regex) + if not match: + embedded_flags = "" + self.regex_embedded_flags_removed = regex + else: + embedded_flags = match.group('flags') + self.regex_embedded_flags_removed = self.embedded_flags_obj.sub("", regex, 1) + + for f in self.reFlags: + if f.shortFlag in embedded_flags: + f.embed() + else: + f.deembed() + + + def checkEditState(self): + if self.editstate == STATE_EDITED: + message = self.tr("You have made changes. Would you like to save them before continuing?") + + prompt = QMessageBox.warning(None, + self.tr("Save changes?"), + message, + QMessageBox.Save | + QMessageBox.Cancel | + QMessageBox.Discard) + + if prompt == QMessageBox.Cancel: + return False + + if prompt == QMessageBox.Save: + self.fileSave() + if not self.filename: self.checkEditState() + + return True + + + def pasteFromRegexLib(self, d): + if not self.checkEditState(): + return + + self.filename = "" + + self.regexMultiLineEdit.setPlainText(d.get('regex', "")) + self.stringMultiLineEdit.setPlainText(d.get('text', "")) + self.replaceTextEdit.setPlainText(d.get('replace', "")) + + try: + # set the current page if applicable + self.resultTabWidget.setCurrentIndex(int(d['tab'])) + except KeyError: + pass + self.editstate = STATE_UNEDITED + + + def revert_file_slot(self): + if not self.filename: + self.updateStatus(self.tr("There is no filename to revert"), + -1, + 5, + TRUE) + return + + self.openFile(self.filename) + + + def getWidget(self): + widget = qApp.focusWidget() + if (widget == self.regexMultiLineEdit or + widget == self.stringMultiLineEdit or + widget == self.replaceTextEdit or + widget == self.codeTextBrowser): + return widget + else: + return None + + + def widgetMethod(self, methodstr, anywidget=0): + # execute the methodstr of widget only if widget + # is one of the editable widgets OR if the method + # may be applied to any widget. + widget = qApp.focusWidget() + if anywidget or ( + widget == self.regexMultiLineEdit or + widget == self.stringMultiLineEdit or + widget == self.replaceTextEdit or + widget == self.codeTextBrowser): + try: + eval("widget.%s" % methodstr) + except: + pass + + + def editUndo(self): + self.widgetMethod("undo()") + + def editRedo(self): + self.widgetMethod("redo()") + + def editCopy(self): + self.widgetMethod("copy()", 1) + + def editCut(self): + self.widgetMethod("cut()") + + def editPaste(self): + self.widgetMethod("paste()") + + + def preferences(self): + self.prefs.showPrefsDialog() + self.prefs.prefsSaved.connect(self.prefsSaved) + + def setfont(self, font): + self.regexMultiLineEdit.setFont(font) + self.stringMultiLineEdit.setFont(font) + self.replaceTextEdit.setFont(font) + + def setMatchFont(self, font): + self.groupTable.setFont(font) + self.matchTextBrowser.setFont(font) + self.matchAllTextBrowser.setFont(font) + self.replaceTextBrowser.setFont(font) + self.codeTextBrowser.setFont(font) + + + def getfont(self): + return self.regexMultiLineEdit.font() + + + def getMatchFont(self): + return self.groupTable.font() + + + def helpHelp(self): + self.helpWindow = help.Help(self, "kodos.html") + + + def helpPythonRegex(self): + self.helpWindow = help.Help(self, os.path.join("python", "module-re.html")) + + + def helpRegexLib(self): + f = os.path.join("help", "regex-lib.xml") + self.regexlibwin = RegexLibrary(f) + self.regexlibwin.pasteRegexLib.connect(self.pasteFromRegexLib) + self.regexlibwin.show() + + + def helpAbout(self): + self.aboutWindow = About() + self.aboutWindow.show() + + + def kodos_website(self): + self.launch_browser_wrapper('https://github.com/luksan/kodos', + message=self.tr('Launch web browser to go to the kodos project page?')) + + + def launch_browser_wrapper(self, url, caption=None, message=None): + if launch_browser(url, caption, message): + self.status_bar.set_message(self.tr("Launching web browser"), + 3, + TRUE) + else: + self.status_bar.set_message(self.tr("Cancelled web browser launch"), + 3, + TRUE) + + + def reference_guide(self): + self.ref_win = Reference(self) + self.ref_win.pasteSymbol.connect(self.paste_symbol) + self.ref_win.show() + + + def report_bug(self): + self.launch_browser_wrapper('https://github.com/luksan/kodos/issues', + message=self.tr("Launch web browser to report a bug in kodos?")) From ba7af44f6845fcf4a3a05de9127d877a5c58adc6 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 17 Aug 2012 16:04:59 +0200 Subject: [PATCH 08/26] Move kodos loader script to bin directory Also fix the util.getAppPath function that is used to find additional data files if kodos is run directly from the git checkout accordingly. --- kodos => bin/kodos | 0 modules/util.py | 2 +- setup.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename kodos => bin/kodos (100%) diff --git a/kodos b/bin/kodos similarity index 100% rename from kodos rename to bin/kodos diff --git a/modules/util.py b/modules/util.py index 2fca4f0..b024c7d 100644 --- a/modules/util.py +++ b/modules/util.py @@ -18,7 +18,7 @@ def getAppPath(): "Convenience function so that we can find the necessary images" - fullpath = os.path.abspath(sys.argv[0]) + fullpath = os.path.abspath(os.path.join(sys.argv[0], '..')) path = os.path.dirname(fullpath) return path diff --git a/setup.py b/setup.py index 10d62ed..0acc967 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ def run(self): author="Phil Schwartz", author_email="phil_schwartz@users.sourceforge.net", url="http://kodos.sourceforge.net", - scripts=['kodos'], + scripts=['bin/kodos'], ##package_dir={'': 'modules'}, packages=['modules', "."], data_files=[(HELP_DIR, glob(os.path.join("help", "*.*ml"))), From f5aedd28a618300d511b4c0a3151d2a6659e2602 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 17 Aug 2012 16:11:33 +0200 Subject: [PATCH 09/26] Use subprocess.check_call instead of os.system The use of os.system should be replaced by the means of the subprocess module. This also makes sure that any non zero exit status of make is fatal. --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0acc967..3ea400e 100644 --- a/setup.py +++ b/setup.py @@ -8,6 +8,7 @@ import os.path import sys from glob import glob +import subprocess args = sys.argv[1:] @@ -32,7 +33,7 @@ class MyInstall(DistutilsInstall): def run(self): - os.system('make') + subprocess.check_call(['make']) DistutilsInstall.run(self) ######################################################################### From 45e47df8fbb24d0827f558b7b6febe7894ea0ca8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 17 Aug 2012 17:00:15 +0200 Subject: [PATCH 10/26] Execute `make` in the build_py rather than in the install phase --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 3ea400e..928fc0a 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- from modules.version import VERSION from distutils.core import setup -from distutils.command.install import install as DistutilsInstall +from distutils.command.build_py import build_py as _build_py #from distutils.sysconfig import get_python_lib import os import os.path @@ -31,10 +31,10 @@ MODULES_DIR = os.path.join(libpath, "modules") TRANSLATIONS_DIR = os.path.join(libpath, "translations") -class MyInstall(DistutilsInstall): +class build_py(_build_py): def run(self): subprocess.check_call(['make']) - DistutilsInstall.run(self) + _build_py.run(self) ######################################################################### @@ -59,6 +59,6 @@ def run(self): long_description=""" Kodos is a visual regular expression editor and debugger. """, - cmdclass={'install':MyInstall}, + cmdclass={'build_py': build_py}, ) From 20bd5abaf01d29e373a9dc86d36b9dc2dbe431b8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 17 Aug 2012 17:09:27 +0200 Subject: [PATCH 11/26] Remove commented out code and superfluous comments --- setup.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 928fc0a..7136033 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,7 @@ from modules.version import VERSION from distutils.core import setup from distutils.command.build_py import build_py as _build_py -#from distutils.sysconfig import get_python_lib import os -import os.path import sys from glob import glob import subprocess @@ -16,8 +14,7 @@ # libpath = '.\\' libpath = r"lib\site-packages\kodos" else: - #libpath = "/usr/local/kodos" # 2.4.0 and prior - libpath = "/usr/share/kodos" # as of 2.4.1 + libpath = "/usr/share/kodos" for arg in args: if arg == "--formats=wininst": @@ -36,8 +33,6 @@ def run(self): subprocess.check_call(['make']) _build_py.run(self) -######################################################################### - setup(name="kodos", version=VERSION, description="Kodos is a visual regular expression editor", @@ -45,7 +40,6 @@ def run(self): author_email="phil_schwartz@users.sourceforge.net", url="http://kodos.sourceforge.net", scripts=['bin/kodos'], - ##package_dir={'': 'modules'}, packages=['modules', "."], data_files=[(HELP_DIR, glob(os.path.join("help", "*.*ml"))), (HELP_PY_DIR, glob(os.path.join("help", "python", "*.html"))), @@ -61,4 +55,3 @@ def run(self): """, cmdclass={'build_py': build_py}, ) - From 9257c390f66ece9b13257dd5df3290bf7497ed78 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 17 Aug 2012 17:58:35 +0200 Subject: [PATCH 12/26] Rename the `modules` directory to `kodos` --- MANIFEST.in | 4 +-- Makefile | 10 +++--- bin/kodos | 4 +-- kodos.pro | 50 +++++++++++++-------------- {modules => kodos}/.gitignore | 0 {modules => kodos}/Makefile | 0 {modules => kodos}/__init__.py | 0 {modules => kodos}/about.py | 0 {modules => kodos}/aboutBA.ui | 0 {modules => kodos}/debug.py | 0 {modules => kodos}/flags.py | 0 {modules => kodos}/help.py | 0 {modules => kodos}/helpBA.ui | 0 {modules => kodos}/kodosBA.ui | 0 {modules => kodos}/main.py | 0 {modules => kodos}/newUserDialogBA.ui | 0 {modules => kodos}/parseRegexLib.py | 0 {modules => kodos}/prefs.py | 0 {modules => kodos}/prefsBA.ui | 0 {modules => kodos}/recent_files.py | 0 {modules => kodos}/reference.py | 0 {modules => kodos}/referenceBA.ui | 0 {modules => kodos}/regexLibrary.py | 0 {modules => kodos}/regexLibraryBA.ui | 0 {modules => kodos}/resultsBA.ui | 0 {modules => kodos}/status_bar.py | 0 {modules => kodos}/tooltip.py | 0 {modules => kodos}/urlDialog.py | 0 {modules => kodos}/urlDialogBA.ui | 0 {modules => kodos}/util.py | 0 {modules => kodos}/version.py | 0 setup.py | 7 ++-- 32 files changed, 37 insertions(+), 38 deletions(-) rename {modules => kodos}/.gitignore (100%) rename {modules => kodos}/Makefile (100%) rename {modules => kodos}/__init__.py (100%) rename {modules => kodos}/about.py (100%) rename {modules => kodos}/aboutBA.ui (100%) rename {modules => kodos}/debug.py (100%) rename {modules => kodos}/flags.py (100%) rename {modules => kodos}/help.py (100%) rename {modules => kodos}/helpBA.ui (100%) rename {modules => kodos}/kodosBA.ui (100%) rename {modules => kodos}/main.py (100%) rename {modules => kodos}/newUserDialogBA.ui (100%) rename {modules => kodos}/parseRegexLib.py (100%) rename {modules => kodos}/prefs.py (100%) rename {modules => kodos}/prefsBA.ui (100%) rename {modules => kodos}/recent_files.py (100%) rename {modules => kodos}/reference.py (100%) rename {modules => kodos}/referenceBA.ui (100%) rename {modules => kodos}/regexLibrary.py (100%) rename {modules => kodos}/regexLibraryBA.ui (100%) rename {modules => kodos}/resultsBA.ui (100%) rename {modules => kodos}/status_bar.py (100%) rename {modules => kodos}/tooltip.py (100%) rename {modules => kodos}/urlDialog.py (100%) rename {modules => kodos}/urlDialogBA.ui (100%) rename {modules => kodos}/util.py (100%) rename {modules => kodos}/version.py (100%) diff --git a/MANIFEST.in b/MANIFEST.in index dfa0425..8372b26 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -8,8 +8,8 @@ include screenshots/*.png include MANIFEST.in include LICENSE.txt include README.txt -include modules/*.ui -include modules/*.py +include kodos/*.ui +include kodos/*.py include windows/build.bat include windows/installer.iss include CHANGELOG.txt diff --git a/Makefile b/Makefile index d03d8b0..2d3486e 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ -all: modules/kodos_rc.py - $(MAKE) -C modules +all: kodos/kodos_rc.py + $(MAKE) -C kodos pylupdate4 kodos.pro $(MAKE) -C translations clean: - $(RM) -fv modules/kodos_rc.py - $(MAKE) clean -C modules + $(RM) -fv kodos/kodos_rc.py + $(MAKE) clean -C kodos -modules/kodos_rc.py: kodos.qrc +kodos/kodos_rc.py: kodos.qrc pyrcc4 -o $@ $< diff --git a/bin/kodos b/bin/kodos index b742888..c6490f1 100755 --- a/bin/kodos +++ b/bin/kodos @@ -17,8 +17,8 @@ you have installed PyQt for the version of Python that you are running.""") from distutils.sysconfig import get_python_lib sys.path.append(os.path.join(get_python_lib(), "kodos")) -from modules.main import Kodos -from modules.util import findFile +from kodos.main import Kodos +from kodos.util import findFile def usage(): print "kodos.py [-f filename | --file=filename ] [ -d debug | --debug=debug ] [ -k kodos_dir ]" diff --git a/kodos.pro b/kodos.pro index 1e375b9..287437c 100644 --- a/kodos.pro +++ b/kodos.pro @@ -1,31 +1,31 @@ SOURCES = kodos - modules/about.py - modules/debug.py - modules/help.py - modules/__init__.py - modules/parseRegexLib.py - modules/prefs.py - modules/recent_files.py - modules/reference.py - modules/regexLibrary.py - modules/reportBug.py - modules/status_bar.py - modules/tooltip.py - modules/urlDialog.py - modules/util.py - modules/version.py + kodos/about.py + kodos/debug.py + kodos/help.py + kodos/__init__.py + kodos/parseRegexLib.py + kodos/prefs.py + kodos/recent_files.py + kodos/reference.py + kodos/regexLibrary.py + kodos/reportBug.py + kodos/status_bar.py + kodos/tooltip.py + kodos/urlDialog.py + kodos/util.py + kodos/version.py TRANSLATIONS = translations/kodos_en.ts \ translations/kodos_pl.ts \ translations/kodos_sv.ts -FORMS = modules/aboutBA.ui \ - modules/helpBA.ui \ - modules/kodosBA.ui \ - modules/newUserDialogBA.ui - modules/prefsBA.ui \ - modules/referenceBA.ui \ - modules/regexLibraryBA.ui \ - modules/reportBugBA.ui \ - modules/resultsBA.ui \ - modules/urlDialogBA.ui +FORMS = kodos/aboutBA.ui \ + kodos/helpBA.ui \ + kodos/kodosBA.ui \ + kodos/newUserDialogBA.ui + kodos/prefsBA.ui \ + kodos/referenceBA.ui \ + kodos/regexLibraryBA.ui \ + kodos/reportBugBA.ui \ + kodos/resultsBA.ui \ + kodos/urlDialogBA.ui diff --git a/modules/.gitignore b/kodos/.gitignore similarity index 100% rename from modules/.gitignore rename to kodos/.gitignore diff --git a/modules/Makefile b/kodos/Makefile similarity index 100% rename from modules/Makefile rename to kodos/Makefile diff --git a/modules/__init__.py b/kodos/__init__.py similarity index 100% rename from modules/__init__.py rename to kodos/__init__.py diff --git a/modules/about.py b/kodos/about.py similarity index 100% rename from modules/about.py rename to kodos/about.py diff --git a/modules/aboutBA.ui b/kodos/aboutBA.ui similarity index 100% rename from modules/aboutBA.ui rename to kodos/aboutBA.ui diff --git a/modules/debug.py b/kodos/debug.py similarity index 100% rename from modules/debug.py rename to kodos/debug.py diff --git a/modules/flags.py b/kodos/flags.py similarity index 100% rename from modules/flags.py rename to kodos/flags.py diff --git a/modules/help.py b/kodos/help.py similarity index 100% rename from modules/help.py rename to kodos/help.py diff --git a/modules/helpBA.ui b/kodos/helpBA.ui similarity index 100% rename from modules/helpBA.ui rename to kodos/helpBA.ui diff --git a/modules/kodosBA.ui b/kodos/kodosBA.ui similarity index 100% rename from modules/kodosBA.ui rename to kodos/kodosBA.ui diff --git a/modules/main.py b/kodos/main.py similarity index 100% rename from modules/main.py rename to kodos/main.py diff --git a/modules/newUserDialogBA.ui b/kodos/newUserDialogBA.ui similarity index 100% rename from modules/newUserDialogBA.ui rename to kodos/newUserDialogBA.ui diff --git a/modules/parseRegexLib.py b/kodos/parseRegexLib.py similarity index 100% rename from modules/parseRegexLib.py rename to kodos/parseRegexLib.py diff --git a/modules/prefs.py b/kodos/prefs.py similarity index 100% rename from modules/prefs.py rename to kodos/prefs.py diff --git a/modules/prefsBA.ui b/kodos/prefsBA.ui similarity index 100% rename from modules/prefsBA.ui rename to kodos/prefsBA.ui diff --git a/modules/recent_files.py b/kodos/recent_files.py similarity index 100% rename from modules/recent_files.py rename to kodos/recent_files.py diff --git a/modules/reference.py b/kodos/reference.py similarity index 100% rename from modules/reference.py rename to kodos/reference.py diff --git a/modules/referenceBA.ui b/kodos/referenceBA.ui similarity index 100% rename from modules/referenceBA.ui rename to kodos/referenceBA.ui diff --git a/modules/regexLibrary.py b/kodos/regexLibrary.py similarity index 100% rename from modules/regexLibrary.py rename to kodos/regexLibrary.py diff --git a/modules/regexLibraryBA.ui b/kodos/regexLibraryBA.ui similarity index 100% rename from modules/regexLibraryBA.ui rename to kodos/regexLibraryBA.ui diff --git a/modules/resultsBA.ui b/kodos/resultsBA.ui similarity index 100% rename from modules/resultsBA.ui rename to kodos/resultsBA.ui diff --git a/modules/status_bar.py b/kodos/status_bar.py similarity index 100% rename from modules/status_bar.py rename to kodos/status_bar.py diff --git a/modules/tooltip.py b/kodos/tooltip.py similarity index 100% rename from modules/tooltip.py rename to kodos/tooltip.py diff --git a/modules/urlDialog.py b/kodos/urlDialog.py similarity index 100% rename from modules/urlDialog.py rename to kodos/urlDialog.py diff --git a/modules/urlDialogBA.ui b/kodos/urlDialogBA.ui similarity index 100% rename from modules/urlDialogBA.ui rename to kodos/urlDialogBA.ui diff --git a/modules/util.py b/kodos/util.py similarity index 100% rename from modules/util.py rename to kodos/util.py diff --git a/modules/version.py b/kodos/version.py similarity index 100% rename from modules/version.py rename to kodos/version.py diff --git a/setup.py b/setup.py index 7136033..93b33b5 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from modules.version import VERSION +from kodos.version import VERSION from distutils.core import setup from distutils.command.build_py import build_py as _build_py import os @@ -40,16 +40,15 @@ def run(self): author_email="phil_schwartz@users.sourceforge.net", url="http://kodos.sourceforge.net", scripts=['bin/kodos'], - packages=['modules', "."], + packages=['kodos'], data_files=[(HELP_DIR, glob(os.path.join("help", "*.*ml"))), (HELP_PY_DIR, glob(os.path.join("help", "python", "*.html"))), (IMAGES_DIR, glob(os.path.join("images", "*.png"))), (SCREENSHOTS_DIR, glob(os.path.join("screenshots", "*.png"))), (TRANSLATIONS_DIR, glob(os.path.join("translations", "*"))), - (MODULES_DIR, glob("modules/*.ui")) + (MODULES_DIR, glob("kodos/*.ui")) ], license="GPL", - extra_path='kodos', long_description=""" Kodos is a visual regular expression editor and debugger. """, From 6032e0366def155a7a434ea8bd71bf60fc90e1c6 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 17 Aug 2012 17:59:31 +0200 Subject: [PATCH 13/26] Remove the now superfluous extension of sys.path --- bin/kodos | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/kodos b/bin/kodos index c6490f1..cbd1590 100755 --- a/bin/kodos +++ b/bin/kodos @@ -13,10 +13,6 @@ except: sys.exit("""Could not locate the PyQt module. Please make sure that you have installed PyQt for the version of Python that you are running.""") -### make sure that this script can find kodos specific modules ### -from distutils.sysconfig import get_python_lib -sys.path.append(os.path.join(get_python_lib(), "kodos")) - from kodos.main import Kodos from kodos.util import findFile From 547a19f9e50b8ac4556f65ffbab2c152c732e6ac Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Aug 2012 22:27:56 +0200 Subject: [PATCH 14/26] Do not install the .ui files The .ui files are not used at runtime, so there is no need to install them. --- setup.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.py b/setup.py index 93b33b5..822db89 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,6 @@ HELP_PY_DIR = os.path.join(libpath, "help", "python") IMAGES_DIR = os.path.join(libpath, "images") SCREENSHOTS_DIR = os.path.join(libpath, "screenshots") -MODULES_DIR = os.path.join(libpath, "modules") TRANSLATIONS_DIR = os.path.join(libpath, "translations") class build_py(_build_py): @@ -46,7 +45,6 @@ def run(self): (IMAGES_DIR, glob(os.path.join("images", "*.png"))), (SCREENSHOTS_DIR, glob(os.path.join("screenshots", "*.png"))), (TRANSLATIONS_DIR, glob(os.path.join("translations", "*"))), - (MODULES_DIR, glob("kodos/*.ui")) ], license="GPL", long_description=""" From e463a31a3f81b629eea3b1af594755a9f25ead77 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Aug 2012 23:50:40 +0200 Subject: [PATCH 15/26] Use optparse instead of getopt --- bin/kodos | 109 ++++++++++++++++++------------------------------------ 1 file changed, 37 insertions(+), 72 deletions(-) diff --git a/bin/kodos b/bin/kodos index cbd1590..6e98211 100755 --- a/bin/kodos +++ b/bin/kodos @@ -4,7 +4,7 @@ import sys import os -import getopt +import optparse try: from PyQt4 import QtGui @@ -16,74 +16,39 @@ you have installed PyQt for the version of Python that you are running.""") from kodos.main import Kodos from kodos.util import findFile -def usage(): - print "kodos.py [-f filename | --file=filename ] [ -d debug | --debug=debug ] [ -k kodos_dir ]" - print - print " -f filename | --filename=filename : Load filename on startup" - print " -d debug | --debug=debug : Set debug to this debug level" - print " -k kodos_dir : Path containing Kodos images & help subdirs" - print " -l locale | --locale=locale : 2-letter locale (eg. en)" - print - sys.exit(0) - -def main(): - filename = None - debug = 0 - kodos_dir = os.path.join(sys.prefix, "kodos") - locale = None - - args = sys.argv[1:] - try: - (opts, getopts) = getopt.getopt(args, 'd:f:k:l:?h', - ["file=", "debug=", - "help", "locale="]) - except: - print "\nInvalid command line option detected." - usage() - - for opt, arg in opts: - if opt in ('-h', '-?', '--help'): - usage() - if opt == '-k': - kodos_dir = arg - if opt in ('-d', '--debug'): - try: - debug = int(arg) - except: - print "debug value must be an integer" - usage() - if opt in ('-f', '--file'): - filename = arg - if opt in ('-l', '--locale'): - locale = arg - - os.environ['KODOS_DIR'] = kodos_dir - - qApp = QtGui.QApplication(sys.argv) - qApp.setOrganizationName("kodos") - qApp.setApplicationName("kodos") - qApp.setOrganizationDomain("kodos.sourceforge.net") - - if locale not in (None, 'en'): - localefile = "kodos_%s.qm" % (locale or QtCore.QTextCodec.locale()) - localepath = findFile(os.path.join("translations", localefile)) - if debug: - print "locale changed to:", locale - print localefile - print localepath - - translator = QtCore.QTranslator(qApp) - translator.load(localepath) - - qApp.installTranslator(translator) - - kodos = Kodos(filename, debug) - - kodos.show() - - sys.exit(qApp.exec_()) - - - -if __name__ == '__main__': - main() +parser = optparse.OptionParser() +parser.add_option('-f', '--filename', dest='filename', + help='Load filename on startup', metavar='FILE') +parser.add_option('-d', '--debug', dest='debug', type='int', + help='Set debug to LEVEL', metavar='LEVEL') +parser.add_option('-k', dest='kodos_dir', type='string', + default=os.path.join(sys.prefix, "kodos"), + help='Set path containing Kodos images & help subdirs', + metavar='DIR') +parser.add_option('-l', '--locale', dest='locale', type='string', + default='en', + help='2-letter locale', metavar='LEVEL') +options, args = parser.parse_args() + +os.environ['KODOS_DIR'] = options.kodos_dir + +qApp = QtGui.QApplication(sys.argv) +qApp.setOrganizationName("kodos") +qApp.setApplicationName("kodos") +qApp.setOrganizationDomain("kodos.sourceforge.net") + +if options.locale != 'en': + localefile = "kodos_%s.qm" % (options.locale or QtCore.QTextCodec.locale()) + localepath = findFile(os.path.join("translations", localefile)) + if debug: + print "locale changed to:", locale + print localefile + print localepath + + translator = QtCore.QTranslator(qApp) + translator.load(localepath) + qApp.installTranslator(translator) + +kodos = Kodos(options.filename, options.debug) +kodos.show() +sys.exit(qApp.exec_()) From 2fa3ab0a2f403ac6190d517730d1ebacee49f949 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 08:08:42 +0200 Subject: [PATCH 16/26] Remove all debug related code from util.py The debug module is not used anywhere besides util.py and the variable `debug` from that module is initialized to `DEBUG_NONE` effectively disabling all debug related events in util.py anyway. --- kodos/util.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/kodos/util.py b/kodos/util.py index b024c7d..c8458a0 100644 --- a/kodos/util.py +++ b/kodos/util.py @@ -4,7 +4,6 @@ import os import os.path import sys -from debug import * import webbrowser from PyQt4.QtGui import * @@ -14,8 +13,6 @@ FALSE = 0 TRUE = 1 -global debug - def getAppPath(): "Convenience function so that we can find the necessary images" fullpath = os.path.abspath(os.path.join(sys.argv[0], '..')) @@ -28,9 +25,6 @@ def getPixmap(fileStr, fileType="PNG", dir="images"): to the binary location and residing in it's 'images' subdirectory""" image = getAppPath() + os.sep + dir + os.sep + fileStr - - if debug & DEBUG_PIXMAP: print "image:", image - pixmap = QPixmap(image, fileType) pixmap.setMask(pixmap.createHeuristicMask(1)) @@ -78,8 +72,6 @@ def launch_browser(url, caption=None, message=None): try: webbrowser.open(url) except webbrowser.Error, e: - if debug: - print e print "Couldn't open URL:", url return False return True From b2ba6b99113623df30d25575d01199d658a7228e Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 08:14:39 +0200 Subject: [PATCH 17/26] Remove the unused debug module --- kodos/debug.py | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100755 kodos/debug.py diff --git a/kodos/debug.py b/kodos/debug.py deleted file mode 100755 index 32fd790..0000000 --- a/kodos/debug.py +++ /dev/null @@ -1,34 +0,0 @@ -# debug.py: -*- Python -*- DESCRIPTIVE TEXT. - -################################# DEBUGGING CONSTANTS ###################################### - -# debugging constants ... set debug to one of these -# if adding new debug levels make sure the new ones are -# a unique power of 2 (1, 2, 4, 8, 16...). Also, the new -# ones should be added to DEBUG_ALL -DEBUG_NONE = 0 -DEBUG_AUTO_COMPLETE = 1 -DEBUG_ANIMATE = 2 -DEBUG_CONNECT = 4 -DEBUG_SESSION = 8 -DEBUG_PIXMAP = 16 -DEBUG_HISTORY = 32 -DEBUG_SSTM = 64 -DEBUG_MISC = 128 -DEBUG_CMDLINE_ARGS = 256 -DEBUG_PRINT = 512 -DEBUG_PREFS = 1024 -DEBUG_PS_TPL = 2048 - -# convenience constant -DEBUG_ALL = ( - DEBUG_AUTO_COMPLETE | DEBUG_ANIMATE | - DEBUG_CONNECT | DEBUG_SESSION | - DEBUG_PIXMAP | DEBUG_HISTORY | - DEBUG_SSTM | DEBUG_MISC | DEBUG_CMDLINE_ARGS | - DEBUG_PRINT | DEBUG_PREFS | DEBUG_PS_TPL - ) - -# use a bitwise or (|) to use multiple debug levels -# debug = DEBUG_AUTO_COMPLETE | DEBUG_SESSION -debug = DEBUG_NONE From 378e036b08c3329329285296baca1fe2112cff72 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 08:48:31 +0200 Subject: [PATCH 18/26] Use the logging framework instead of conditional prints --- bin/kodos | 20 +++++++++++++------- kodos/main.py | 28 +++++++++++++--------------- kodos/recent_files.py | 12 +++++++----- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/bin/kodos b/bin/kodos index 6e98211..12abc85 100755 --- a/bin/kodos +++ b/bin/kodos @@ -4,6 +4,7 @@ import sys import os +import logging import optparse try: @@ -19,8 +20,8 @@ from kodos.util import findFile parser = optparse.OptionParser() parser.add_option('-f', '--filename', dest='filename', help='Load filename on startup', metavar='FILE') -parser.add_option('-d', '--debug', dest='debug', type='int', - help='Set debug to LEVEL', metavar='LEVEL') +parser.add_option('-d', '--debug', dest='debug', action='store_true', + help='Set log level to debug') parser.add_option('-k', dest='kodos_dir', type='string', default=os.path.join(sys.prefix, "kodos"), help='Set path containing Kodos images & help subdirs', @@ -30,6 +31,12 @@ parser.add_option('-l', '--locale', dest='locale', type='string', help='2-letter locale', metavar='LEVEL') options, args = parser.parse_args() +if options.debug: + logging.basicConfig(level=logging.DEBUG) +else: + logging.basicConfig(level=logging.WARNING) +log = logging.getLogger('kodos') + os.environ['KODOS_DIR'] = options.kodos_dir qApp = QtGui.QApplication(sys.argv) @@ -40,15 +47,14 @@ qApp.setOrganizationDomain("kodos.sourceforge.net") if options.locale != 'en': localefile = "kodos_%s.qm" % (options.locale or QtCore.QTextCodec.locale()) localepath = findFile(os.path.join("translations", localefile)) - if debug: - print "locale changed to:", locale - print localefile - print localepath + log.debug('locale changed to: %s, file: %s, path: %s' % (locale, + localefile, + localepath)) translator = QtCore.QTranslator(qApp) translator.load(localepath) qApp.installTranslator(translator) -kodos = Kodos(options.filename, options.debug) +kodos = Kodos(options.filename) kodos.show() sys.exit(qApp.exec_()) diff --git a/kodos/main.py b/kodos/main.py index e97f498..0b210c4 100644 --- a/kodos/main.py +++ b/kodos/main.py @@ -6,6 +6,7 @@ import string import urllib import cPickle +import logging from PyQt4.QtGui import * from PyQt4.QtCore import * @@ -65,10 +66,10 @@ ############################################################################## class Kodos(KodosBA): - def __init__(self, filename, debug): + def __init__(self, filename): KodosBA.__init__(self) - self.debug = debug + self.log = logging.getLogger('kodos.main') self.regex = "" self.matchstring = "" self.replace = "" @@ -119,8 +120,7 @@ def __init__(self, filename, debug): self.prefs = Preferences(self, 1) self.recent_files = RecentFiles(self, - self.prefs.recentFilesSpinBox.value(), - self.debug) + self.prefs.recentFilesSpinBox.value()) if filename and self.openFile(filename): qApp.processEvents() @@ -159,7 +159,7 @@ def fileMenuHandler(self, menuid): self.recent_files.add(fn) def prefsSaved(self): - if self.debug: print "prefsSaved slot" + self.log.debug("prefsSaved slot") self.recent_files.setNumShown(self.prefs.recentFilesSpinBox.value()) @@ -206,7 +206,7 @@ def get_embedded_flags_string(self): def pause(self): self.is_paused = not self.is_paused - if self.debug: print "is_paused:", self.is_paused + self.log.debug("is_paused: %s" % self.is_paused) if self.is_paused: self.update_results(self.MSG_PAUSED, MATCH_PAUSED) @@ -219,7 +219,7 @@ def pause(self): def examine(self): self.is_examined = not self.is_examined - if self.debug: print "is_examined:", self.is_examined + self.log.debug("is_examined: %s" % self.is_examined) if self.is_examined: color = QCOLOR_YELLOW @@ -235,7 +235,7 @@ def examine(self): try: m = re.search(regex, self.matchstring, self.reFlags.allFlagsORed()) if m: - if self.debug: print "examined regex:", regex + self.log.debug("examined regex: %s" % regex) self.__refresh_regex_widget(color, regex) return except: @@ -560,11 +560,10 @@ def timeout(signum, frame): for key in keys: group_nums[compile_obj.groupindex[key]] = key - if self.debug: - print "group_nums:", group_nums - print "grp index: ", compile_obj.groupindex - print "groups:", match_obj.groups() - print "span: ", match_obj.span() + self.log.debug("group_nums: %s" % group_nums) + self.log.debug("grp index: %s" % compile_obj.groupindex) + self.log.debug("groups: %s" % (match_obj.groups(), )) + self.log.debug("span: %s" % (match_obj.span(), )) # create group_tuple in the form: (group #, group name, group matches) g = allmatches[match_index] @@ -726,8 +725,7 @@ def openFile(self, filename): self.matchstring = u.load() flags = u.load() except Exception, e: #FIXME: don't catch everything - if self.debug: - print unicode(e) + self.log.error('Error unpickling data from file: %s' % e) msg = "%s %s" % (unicode(self.tr("Error reading from file:")), filename) self.updateStatus(msg, -1, 5, TRUE) diff --git a/kodos/recent_files.py b/kodos/recent_files.py index 31b7dc8..d6e1fa7 100644 --- a/kodos/recent_files.py +++ b/kodos/recent_files.py @@ -1,15 +1,17 @@ # -*- coding: utf-8 -*- +import logging + from PyQt4.QtGui import QIcon, QPixmap from PyQt4.QtCore import QSettings MAX_SIZE = 50 # max number of files to retain class RecentFiles: - def __init__(self, parent, numShown=5, debug=None): + def __init__(self, parent, numShown=5): + self.log = logging.getLogger('kodos.recent_files') self.parent = parent self.numShown = int(numShown) - self.debug = debug self.__recent_files = [] self.__indecies = [] self.load() @@ -28,13 +30,13 @@ def load(self): break self.__recent_files.append(str(s)) except Exception, e: - print "Loading of recent file entry", i, "failed." - if self.debug: print e + self.log.error('Loading of recent file entry %i failed: %s' % + (i, e)) settings.remove("Filename") settings.endArray() - if self.debug: print "recent_files:", self.__recent_files + self.log.debug("recent_files: %s" % self.__recent_files) self.addToMenu() From a3db334e9351d3dc9ee6775a5e4ef8613eb595b0 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 08:56:47 +0200 Subject: [PATCH 19/26] Use the logging framework instead of unconditional prints --- kodos/prefs.py | 6 +++++- kodos/util.py | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/kodos/prefs.py b/kodos/prefs.py index 3112d49..d99048c 100644 --- a/kodos/prefs.py +++ b/kodos/prefs.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # prefs.py: -*- Python -*- DESCRIPTIVE TEXT. +import logging + from PyQt4.QtCore import pyqtSignal, QSettings from PyQt4.QtGui import QDialog, QFontDialog from prefsBA import PrefsBA @@ -11,6 +13,7 @@ class Preferences(PrefsBA): prefsSaved = pyqtSignal() def __init__(self, parent, autoload=0): + self.log = logging.getLogger('kodos.prefs') self.parent = parent PrefsBA.__init__(self, parent) @@ -30,7 +33,8 @@ def load(self): if preference == 'Recent Files Count': self.recentFilesSpinBox.setValue(int(setting.toPyObject())) except Exception, e: - print "Loading of configuration key", preference, "failed." + self.log.error('Loading of configuration key %s failed: %s' % + (preference, e)) self.settings.remove(preference) diff --git a/kodos/util.py b/kodos/util.py index c8458a0..fcc4b62 100644 --- a/kodos/util.py +++ b/kodos/util.py @@ -4,11 +4,14 @@ import os import os.path import sys +import logging import webbrowser from PyQt4.QtGui import * from PyQt4.QtCore import * +log = logging.getLogger('kodos.util') + # QT constants that should be defined FALSE = 0 TRUE = 1 @@ -72,6 +75,6 @@ def launch_browser(url, caption=None, message=None): try: webbrowser.open(url) except webbrowser.Error, e: - print "Couldn't open URL:", url + log.error("Couldn't open URL %r: %s" % (url, e)) return False return True From b737c628411651a362fb8df6446e8e8ecc2b41a1 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 11:19:01 +0200 Subject: [PATCH 20/26] Hand the qApp object to the main `Kodos` class Formerly the code used the qApp imported from PyQt4.QtGui which also seems to work but it is not obviously clear why. It seems like the qApp there points to the right (the most recent created?) QApplication object. Hand a reference to our QApplication object to the `Kodos` class to make this explicit and more robust. --- bin/kodos | 2 +- kodos/main.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bin/kodos b/bin/kodos index 12abc85..9ddbf20 100755 --- a/bin/kodos +++ b/bin/kodos @@ -55,6 +55,6 @@ if options.locale != 'en': translator.load(localepath) qApp.installTranslator(translator) -kodos = Kodos(options.filename) +kodos = Kodos(qApp, options.filename) kodos.show() sys.exit(qApp.exec_()) diff --git a/kodos/main.py b/kodos/main.py index 0b210c4..8c3d868 100644 --- a/kodos/main.py +++ b/kodos/main.py @@ -66,10 +66,11 @@ ############################################################################## class Kodos(KodosBA): - def __init__(self, filename): + def __init__(self, qApp, filename): KodosBA.__init__(self) self.log = logging.getLogger('kodos.main') + self.qApp = qApp self.regex = "" self.matchstring = "" self.replace = "" @@ -123,7 +124,7 @@ def __init__(self, filename): self.prefs.recentFilesSpinBox.value()) if filename and self.openFile(filename): - qApp.processEvents() + self.qApp.processEvents() self.fileMenu.triggered.connect(self.fileMenuHandler) @@ -875,7 +876,7 @@ def revert_file_slot(self): def getWidget(self): - widget = qApp.focusWidget() + widget = self.qApp.focusWidget() if (widget == self.regexMultiLineEdit or widget == self.stringMultiLineEdit or widget == self.replaceTextEdit or @@ -889,7 +890,7 @@ def widgetMethod(self, methodstr, anywidget=0): # execute the methodstr of widget only if widget # is one of the editable widgets OR if the method # may be applied to any widget. - widget = qApp.focusWidget() + widget = self.qApp.focusWidget() if anywidget or ( widget == self.regexMultiLineEdit or widget == self.stringMultiLineEdit or From 510d3440201c166439cff110611fa19cf29ec998 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 11:16:47 +0200 Subject: [PATCH 21/26] Use relative imports and avoid * imports --- kodos/main.py | 80 ++++++++++++++++++++++++------------------------ kodos/tooltip.py | 31 +++++++++---------- kodos/util.py | 23 +++++++------- 3 files changed, 66 insertions(+), 68 deletions(-) diff --git a/kodos/main.py b/kodos/main.py index 8c3d868..033b86d 100644 --- a/kodos/main.py +++ b/kodos/main.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import os import re import types import signal @@ -8,16 +9,15 @@ import cPickle import logging -from PyQt4.QtGui import * -from PyQt4.QtCore import * +from PyQt4 import Qt, QtCore -from kodosBA import * -from util import * -from about import * +from . import kodosBA +from . import util +from . import about from . import help -from status_bar import * -from reference import * -from prefs import * +from . import status_bar +from . import reference +from . import prefs from version import VERSION from recent_files import RecentFiles from urlDialog import URLDialog @@ -49,8 +49,8 @@ GEO = "kodos_geometry" # colors for normal & examination mode -QCOLOR_WHITE = QColor(Qt.white) # normal -QCOLOR_YELLOW = QColor(255,255,127) # examine +QCOLOR_WHITE = QtCore.Qt.white # normal +QCOLOR_YELLOW = Qt.QColor(255,255,127) # examine try: signal.SIGALRM @@ -65,9 +65,9 @@ # ############################################################################## -class Kodos(KodosBA): +class Kodos(kodosBA.KodosBA): def __init__(self, qApp, filename): - KodosBA.__init__(self) + kodosBA.KodosBA.__init__(self) self.log = logging.getLogger('kodos.main') self.qApp = qApp @@ -96,10 +96,10 @@ def __init__(self, qApp, filename): self.MSG_FAIL = self.tr("Pattern does not match") - self.statusPixmapsDict = { MATCH_NA: QPixmap(":images/yellow.png"), - MATCH_OK: QPixmap(":images/green.png"), - MATCH_FAIL: QPixmap(":images/red.png"), - MATCH_PAUSED: QPixmap(":images/pause.png"), + self.statusPixmapsDict = { MATCH_NA: Qt.QPixmap(":images/yellow.png"), + MATCH_OK: Qt.QPixmap(":images/green.png"), + MATCH_FAIL: Qt.QPixmap(":images/red.png"), + MATCH_PAUSED: Qt.QPixmap(":images/pause.png"), } @@ -115,11 +115,11 @@ def __init__(self, qApp, filename): ]) self.reFlags.clearAll() - restoreWindowSettings(self, GEO) + util.restoreWindowSettings(self, GEO) self.show() - self.prefs = Preferences(self, 1) + self.prefs = prefs.Preferences(self, 1) self.recent_files = RecentFiles(self, self.prefs.recentFilesSpinBox.value()) @@ -128,7 +128,7 @@ def __init__(self, qApp, filename): self.fileMenu.triggered.connect(self.fileMenuHandler) - kodos_toolbar_logo(self.toolBar) + util.kodos_toolbar_logo(self.toolBar) if self.replace: self.show_replace_widgets() else: self.hide_replace_widgets() @@ -136,7 +136,7 @@ def __init__(self, qApp, filename): def checkIfNewUser(self): - s = QSettings() + s = Qt.QSettings() if s.value('New User', "true").toPyObject() != "false": self.newuserdialog = NewUserDialog() self.newuserdialog.show() @@ -144,7 +144,7 @@ def checkIfNewUser(self): def createStatusBar(self): - self.status_bar = Status_Bar(self, FALSE, "") + self.status_bar = status_bar.Status_Bar(self, FALSE, "") def updateStatus(self, status_string, status_value, duration=0, replace=FALSE, tooltip=''): @@ -253,7 +253,7 @@ def examine(self): def __refresh_regex_widget(self, base_qcolor, regex): - pal = QPalette() + pal = Qt.QPalette() pal.setColor(pal.Base, base_qcolor) self.regexMultiLineEdit.setPalette(pal) @@ -323,8 +323,8 @@ def populate_group_table(self, tuples): self.groupTable.setRowCount(rows) row = 0 for t in tuples: - self.groupTable.setItem(row, 0, QTableWidgetItem(t[1])) - self.groupTable.setItem(row, 1, QTableWidgetItem(t[2])) + self.groupTable.setItem(row, 0, Qt.QTableWidgetItem(t[1])) + self.groupTable.setItem(row, 1, Qt.QTableWidgetItem(t[2])) row += 1 @@ -383,7 +383,7 @@ def populate_code_textbrowser(self): def colorize_strings(self, strings, widget, cursorOffset=0): widget.clear() - colors = (QBrush(QColor(Qt.black)), QBrush(QColor(Qt.blue)) ) + colors = (Qt.QBrush(Qt.QColor(QtCore.Qt.black)), Qt.QBrush(Qt.QColor(QtCore.Qt.blue)) ) cur = widget.textCursor() format = cur.charFormat() @@ -630,7 +630,7 @@ def closeEvent(self, ev): ev.ignore() return - saveWindowSettings(self, GEO) + util.saveWindowSettings(self, GEO) try: self.regexlibwin.close() @@ -667,7 +667,7 @@ def urlImported(self, html, url): def importFile(self): - fn = QFileDialog.getOpenFileName(self, + fn = Qt.QFileDialog.getOpenFileName(self, self.tr("Import File"), self.filename, self.tr("All (*)")) @@ -697,7 +697,7 @@ def fileOpen(self): filename = self.filename if filename == None: filename = "" - fn = QFileDialog.getOpenFileName(self, + fn = Qt.QFileDialog.getOpenFileName(self, self.tr("Open Kodos File"), filename, self.tr("Kodos file (*.kds);;All (*)")) @@ -758,15 +758,15 @@ def fileSaveAs(self): filename = self.filename if filename == None: filename = "" - filedialog = QFileDialog(self, + filedialog = Qt.QFileDialog(self, self.tr("Save Kodos File"), filename, "Kodos file (*.kds);;All (*)") - filedialog.setAcceptMode(QFileDialog.AcceptSave) + filedialog.setAcceptMode(Qt.QFileDialog.AcceptSave) filedialog.setDefaultSuffix("kds") ok = filedialog.exec_() - if ok == QDialog.Rejected: + if ok == Qt.QDialog.Rejected: self.updateStatus(self.tr("No file selected to save"), -1, 5, TRUE) return @@ -829,17 +829,17 @@ def checkEditState(self): if self.editstate == STATE_EDITED: message = self.tr("You have made changes. Would you like to save them before continuing?") - prompt = QMessageBox.warning(None, + prompt = Qt.QMessageBox.warning(None, self.tr("Save changes?"), message, - QMessageBox.Save | - QMessageBox.Cancel | - QMessageBox.Discard) + Qt.QMessageBox.Save | + Qt.QMessageBox.Cancel | + Qt.QMessageBox.Discard) - if prompt == QMessageBox.Cancel: + if prompt == Qt.QMessageBox.Cancel: return False - if prompt == QMessageBox.Save: + if prompt == Qt.QMessageBox.Save: self.fileSave() if not self.filename: self.checkEditState() @@ -959,7 +959,7 @@ def helpRegexLib(self): def helpAbout(self): - self.aboutWindow = About() + self.aboutWindow = about.About() self.aboutWindow.show() @@ -969,7 +969,7 @@ def kodos_website(self): def launch_browser_wrapper(self, url, caption=None, message=None): - if launch_browser(url, caption, message): + if util.launch_browser(url, caption, message): self.status_bar.set_message(self.tr("Launching web browser"), 3, TRUE) @@ -980,7 +980,7 @@ def launch_browser_wrapper(self, url, caption=None, message=None): def reference_guide(self): - self.ref_win = Reference(self) + self.ref_win = reference.Reference(self) self.ref_win.pasteSymbol.connect(self.paste_symbol) self.ref_win.show() diff --git a/kodos/tooltip.py b/kodos/tooltip.py index ae3dd8e..99e5872 100644 --- a/kodos/tooltip.py +++ b/kodos/tooltip.py @@ -1,29 +1,28 @@ # -*- coding: utf-8 -*- # tooltip.py: -*- Python -*- DESCRIPTIVE TEXT. -from PyQt4.QtGui import * -from PyQt4.QtCore import * -from util import * +from PyQt4 import Qt, QtCore +from util import FALSE -class Tooltip(QLabel): +class Tooltip(Qt.QLabel): def __init__(self, text, bgcolor="#ffd700",fgcolor="#000000",delay=1000): self.delay = delay - QLabel.__init__(self, None, Qt.WindowStaysOnTopHint - | Qt.FramelessWindowHint - | Qt.Tool) + Qt.QLabel.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint + | QtCore.Qt.FramelessWindowHint + | QtCore.Qt.Tool) self.setMargin(1) self.setIndent(0) - self.setFrameStyle(QFrame.Plain | QFrame.Box) + self.setFrameStyle(Qt.QFrame.Plain | Qt.QFrame.Box) self.setLineWidth(1) self.setText(text) self.adjustSize() # set the pallete... - pal = QPalette() - pal.setColor(QPalette.Active, QPalette.Window, QColor(bgcolor)) - pal.setColor(QPalette.Active, QPalette.WindowText, QColor(fgcolor)) - pal.setColor(QPalette.Inactive, QPalette.Window, QColor(bgcolor)) - pal.setColor(QPalette.Inactive, QPalette.WindowText, QColor(fgcolor)) + pal = Qt.QPalette() + pal.setColor(Qt.QPalette.Active, Qt.QPalette.Window, Qt.QColor(bgcolor)) + pal.setColor(Qt.QPalette.Active, Qt.QPalette.WindowText, Qt.QColor(fgcolor)) + pal.setColor(Qt.QPalette.Inactive, Qt.QPalette.Window, Qt.QColor(bgcolor)) + pal.setColor(Qt.QPalette.Inactive, Qt.QPalette.WindowText, Qt.QColor(fgcolor)) self.setPalette(pal) self.enter_timer_id = None @@ -67,11 +66,11 @@ def timerEvent( self, ev ): def eventFilter(self, obj, ev): type = ev.type() - if type == QEvent.Enter: + if type == Qt.QEvent.Enter: self.killCustomTimers() self.enter_timer_id = self.startTimer(self.delay) self.event_widget = obj - elif type == QEvent.Leave: + elif type == Qt.QEvent.Leave: self.killCustomTimers() self.leave_timer_id = self.startTimer(self.delay) self.event_widget = None @@ -84,7 +83,7 @@ def tooltip_open(self): try: pos = self.event_widget.mapToGlobal( - QPoint(0, self.event_widget.height())) + Qt.QPoint(0, self.event_widget.height())) self.move(pos.x(), pos.y()) self.show() self.setFixedSize( self.sizeHint() ) diff --git a/kodos/util.py b/kodos/util.py index fcc4b62..43fc93e 100644 --- a/kodos/util.py +++ b/kodos/util.py @@ -7,8 +7,7 @@ import logging import webbrowser -from PyQt4.QtGui import * -from PyQt4.QtCore import * +from PyQt4 import Qt log = logging.getLogger('kodos.util') @@ -24,22 +23,22 @@ def getAppPath(): def getPixmap(fileStr, fileType="PNG", dir="images"): - """Return a QPixmap instance for the file fileStr relative + """Return a Qt.QPixmap instance for the file fileStr relative to the binary location and residing in it's 'images' subdirectory""" image = getAppPath() + os.sep + dir + os.sep + fileStr - pixmap = QPixmap(image, fileType) + pixmap = Qt.QPixmap(image, fileType) pixmap.setMask(pixmap.createHeuristicMask(1)) return pixmap def kodos_toolbar_logo(toolbar): # hack to move logo to right - blanklabel = QLabel() - blanklabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + blanklabel = Qt.QLabel() + blanklabel.setSizePolicy(Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Preferred) - logolabel = QLabel("kodos_logo") - logolabel.setPixmap(QPixmap(":/images/kodos_icon.png")) + logolabel = Qt.QLabel("kodos_logo") + logolabel.setPixmap(Qt.QPixmap(":/images/kodos_icon.png")) toolbar.addWidget(blanklabel) toolbar.addWidget(logolabel) @@ -47,11 +46,11 @@ def kodos_toolbar_logo(toolbar): return logolabel def saveWindowSettings(window, filename): - settings = QSettings() + settings = Qt.QSettings() settings.setValue(window.objectName(), window.saveGeometry()) def restoreWindowSettings(window, filename): - settings = QSettings() + settings = Qt.QSettings() window.restoreGeometry(settings.value(window.objectName()).toByteArray()) def findFile(filename): @@ -69,8 +68,8 @@ def launch_browser(url, caption=None, message=None): if not caption: caption = "Info" if not message: message = "Launch web browser?" - button = QMessageBox.information(None, caption, message, QMessageBox.Ok | QMessageBox.Cancel) - if button == QMessageBox.Cancel: + button = Qt.QMessageBox.information(None, caption, message, Qt.QMessageBox.Ok | Qt.QMessageBox.Cancel) + if button == Qt.QMessageBox.Cancel: return False try: webbrowser.open(url) From 9e7b6ec99731cceec08f55e4a492c9bf4ecc6b1b Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 12:06:54 +0200 Subject: [PATCH 22/26] Remove unused imports --- kodos/main.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/kodos/main.py b/kodos/main.py index 033b86d..ae74511 100644 --- a/kodos/main.py +++ b/kodos/main.py @@ -4,8 +4,6 @@ import re import types import signal -import string -import urllib import cPickle import logging @@ -18,7 +16,6 @@ from . import status_bar from . import reference from . import prefs -from version import VERSION from recent_files import RecentFiles from urlDialog import URLDialog from regexLibrary import RegexLibrary From 3563bac84891287f18e59dd274c0faa61cf9acf1 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 12:08:06 +0200 Subject: [PATCH 23/26] Remove RecentFiles.move(..) There is no QIconSet in Qt4. Simply remove the method RecentFiles.move since that this method is unused. --- kodos/recent_files.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/kodos/recent_files.py b/kodos/recent_files.py index d6e1fa7..cd6d55f 100644 --- a/kodos/recent_files.py +++ b/kodos/recent_files.py @@ -99,19 +99,3 @@ def setNumShown(self, numShown): def isRecentFile(self, menuid): return menuid in self.__indecies - - def move(self, filename, menuid): - # fix me.... - menu = self.parent.fileMenu - idx = menu.indexOf(self.__indecies[0]) - menu.removeItem(menuid) - menu.insertItem(QIconSet(QPixmap(":images/document-open-recent.png")), - filename, - -1, - idx) - try: - self.__recent_files.remove(filename) - except: - pass - self.__indecies.insert(0, filename) - From 561f2ae08bae0504e60075c0f8ef9d48e1599b2c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 12:11:21 +0200 Subject: [PATCH 24/26] Remove superfluous import of os.path --- kodos/util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/kodos/util.py b/kodos/util.py index 43fc93e..1d90edb 100644 --- a/kodos/util.py +++ b/kodos/util.py @@ -2,7 +2,6 @@ # util.py: -*- Python -*- DESCRIPTIVE TEXT. import os -import os.path import sys import logging import webbrowser From 0e45c3613651098eb0664bc52b3a27f59ba25579 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 12:26:44 +0200 Subject: [PATCH 25/26] Use package relative imports --- kodos/help.py | 6 +++--- kodos/main.py | 20 ++++++++++---------- kodos/parseRegexLib.py | 6 +++--- kodos/prefs.py | 8 ++++---- kodos/reference.py | 8 ++++---- kodos/regexLibrary.py | 12 ++++++------ kodos/status_bar.py | 6 +++--- kodos/tooltip.py | 2 +- kodos/urlDialog.py | 9 +++++---- 9 files changed, 39 insertions(+), 38 deletions(-) diff --git a/kodos/help.py b/kodos/help.py index b8b79c8..990478d 100755 --- a/kodos/help.py +++ b/kodos/help.py @@ -7,7 +7,7 @@ from PyQt4 import QtCore from . import util -from helpBA import HelpBA +from . import helpBA class textbrowser(QtGui.QTextBrowser): # reimplemented textbrowser that filters out external sources @@ -28,9 +28,9 @@ def setSource(self, src): -class Help(HelpBA): +class Help(helpBA.HelpBA): def __init__(self, parent, filename): - HelpBA.__init__(self, parent) + helpBA.HelpBA.__init__(self, parent) self.setGeometry(100, 50, 800, 600) diff --git a/kodos/main.py b/kodos/main.py index ae74511..4c240eb 100644 --- a/kodos/main.py +++ b/kodos/main.py @@ -16,11 +16,11 @@ from . import status_bar from . import reference from . import prefs -from recent_files import RecentFiles -from urlDialog import URLDialog -from regexLibrary import RegexLibrary -from newUserDialogBA import NewUserDialog -from flags import reFlag, reFlagList +from . import recent_files +from . import urlDialog +from . import regexLibrary +from . import newUserDialogBA +from .flags import reFlag, reFlagList # match status MATCH_NA = 0 @@ -117,8 +117,8 @@ def __init__(self, qApp, filename): self.show() self.prefs = prefs.Preferences(self, 1) - self.recent_files = RecentFiles(self, - self.prefs.recentFilesSpinBox.value()) + self.recent_files = recent_files.RecentFiles(self, + self.prefs.recentFilesSpinBox.value()) if filename and self.openFile(filename): self.qApp.processEvents() @@ -135,7 +135,7 @@ def __init__(self, qApp, filename): def checkIfNewUser(self): s = Qt.QSettings() if s.value('New User', "true").toPyObject() != "false": - self.newuserdialog = NewUserDialog() + self.newuserdialog = newUserDialogBA.NewUserDialog() self.newuserdialog.show() s.setValue('New User', "false") @@ -654,7 +654,7 @@ def fileNew(self): def importURL(self): - self.urldialog = URLDialog(self, self.url) + self.urldialog = urlDialog.URLDialog(self, self.url) self.urldialog.urlImported.connect(self.urlImported) @@ -950,7 +950,7 @@ def helpPythonRegex(self): def helpRegexLib(self): f = os.path.join("help", "regex-lib.xml") - self.regexlibwin = RegexLibrary(f) + self.regexlibwin = regexLibrary.RegexLibrary(f) self.regexlibwin.pasteRegexLib.connect(self.pasteFromRegexLib) self.regexlibwin.show() diff --git a/kodos/parseRegexLib.py b/kodos/parseRegexLib.py index d58c233..da81b9d 100644 --- a/kodos/parseRegexLib.py +++ b/kodos/parseRegexLib.py @@ -1,6 +1,6 @@ import re import os -from util import findFile +from . import util rx_entry = re.compile(r"(?P.*?)", re.DOTALL) @@ -25,7 +25,7 @@ class ParseRegexLib: def __init__(self, filename): if filename: - path = findFile(os.path.join("help", "regex-lib.xml")) + path = util.findFile(os.path.join("help", "regex-lib.xml")) data = open(path).read() self.data = data else: @@ -52,7 +52,7 @@ def parse(self, data=""): if __name__ == '__main__': - path = findFile(os.path.join("help", "regex-lib.xml")) + path = util.findFile(os.path.join("help", "regex-lib.xml")) x = ParseRegexLib(path) dicts = x.parse() diff --git a/kodos/prefs.py b/kodos/prefs.py index d99048c..e8e874d 100644 --- a/kodos/prefs.py +++ b/kodos/prefs.py @@ -5,17 +5,17 @@ from PyQt4.QtCore import pyqtSignal, QSettings from PyQt4.QtGui import QDialog, QFontDialog -from prefsBA import PrefsBA -import help +from . import prefsBA +from . import help -class Preferences(PrefsBA): +class Preferences(prefsBA.PrefsBA): prefsSaved = pyqtSignal() def __init__(self, parent, autoload=0): self.log = logging.getLogger('kodos.prefs') self.parent = parent - PrefsBA.__init__(self, parent) + prefsBA.PrefsBA.__init__(self, parent) self.settings = QSettings() diff --git a/kodos/reference.py b/kodos/reference.py index 85c2627..927ce41 100644 --- a/kodos/reference.py +++ b/kodos/reference.py @@ -2,17 +2,17 @@ # reference.py: -*- Python -*- DESCRIPTIVE TEXT. from PyQt4.QtCore import pyqtSignal -from referenceBA import ReferenceBA -from util import kodos_toolbar_logo, restoreWindowSettings, saveWindowSettings +from . import referenceBA +from .util import kodos_toolbar_logo, restoreWindowSettings, saveWindowSettings GEO = "regex-ref_geometry" -class Reference(ReferenceBA): +class Reference(referenceBA.ReferenceBA): pasteSymbol = pyqtSignal(str) def __init__(self, parent): - ReferenceBA.__init__(self, None) + referenceBA.ReferenceBA.__init__(self, None) self.parent = parent restoreWindowSettings(self, GEO) diff --git a/kodos/regexLibrary.py b/kodos/regexLibrary.py index 13af979..abce53b 100644 --- a/kodos/regexLibrary.py +++ b/kodos/regexLibrary.py @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- from PyQt4.QtCore import pyqtSignal -from regexLibraryBA import RegexLibraryBA -from parseRegexLib import ParseRegexLib -from util import restoreWindowSettings, saveWindowSettings, kodos_toolbar_logo +from . import regexLibraryBA +from . import parseRegexLib +from .util import restoreWindowSettings, saveWindowSettings, kodos_toolbar_logo GEO = "regex-lib_geometry" -class RegexLibrary(RegexLibraryBA): +class RegexLibrary(regexLibraryBA.RegexLibraryBA): pasteRegexLib = pyqtSignal(dict) def __init__(self, filename): - RegexLibraryBA.__init__(self, None) + regexLibraryBA.RegexLibraryBA.__init__(self, None) self.filename = filename self.selected = None @@ -28,7 +28,7 @@ def closeEvent(self, ev): def parseXML(self): - parser = ParseRegexLib(self.filename) + parser = parseRegexLib.ParseRegexLib(self.filename) self.xml_dicts = parser.parse() diff --git a/kodos/status_bar.py b/kodos/status_bar.py index e0ba25a..1e378e8 100644 --- a/kodos/status_bar.py +++ b/kodos/status_bar.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- # status_bar.py: -*- Python -*- DESCRIPTIVE TEXT. -from tooltip import Tooltip -from util import TRUE, FALSE +from . import tooltip +from .util import TRUE, FALSE from PyQt4.QtCore import QTimer from PyQt4.QtGui import QPixmap, QLabel, QProgressBar @@ -16,7 +16,7 @@ def __init__(self, parent, progress_bar=FALSE, message=''): self.__statusTimer.timeout.connect(self.reset_message) self.__statusLabel = QLabel("msg", self.statusBar) - self.tooltip = Tooltip('') + self.tooltip = tooltip.Tooltip('') self.tooltip.addWidget(self.__statusLabel) self.last_status_message = '' diff --git a/kodos/tooltip.py b/kodos/tooltip.py index 99e5872..35a6f46 100644 --- a/kodos/tooltip.py +++ b/kodos/tooltip.py @@ -2,7 +2,7 @@ # tooltip.py: -*- Python -*- DESCRIPTIVE TEXT. from PyQt4 import Qt, QtCore -from util import FALSE +from .util import FALSE class Tooltip(Qt.QLabel): def __init__(self, text, bgcolor="#ffd700",fgcolor="#000000",delay=1000): diff --git a/kodos/urlDialog.py b/kodos/urlDialog.py index 1900bf2..7ea64db 100644 --- a/kodos/urlDialog.py +++ b/kodos/urlDialog.py @@ -1,17 +1,18 @@ # -*- coding: utf-8 -*- + from PyQt4.QtCore import pyqtSignal from PyQt4.QtGui import QMessageBox -from urlDialogBA import URLDialogBA -import help +from . import urlDialogBA +from . import help import urllib -class URLDialog(URLDialogBA): +class URLDialog(urlDialogBA.URLDialogBA): urlImported = pyqtSignal(str, str) def __init__(self, parent, url=None): - URLDialogBA.__init__(self, parent) + urlDialogBA.URLDialogBA.__init__(self, parent) if url: self.URLTextEdit.setPlainText(url) From 4ab2ca9c456bd21f3e726889188a5383b2dfda0f Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Aug 2012 12:33:39 +0200 Subject: [PATCH 26/26] Use True and False instead of TRUE and FALSE The PyQt4 bindings handle python booleans seamlessly. In fact, True and False are numeric values in python with the same values (isinstance(True, int) and True == 1). --- kodos/main.py | 47 +++++++++++++++++++++------------------------ kodos/status_bar.py | 7 +++---- kodos/tooltip.py | 3 +-- kodos/util.py | 4 ---- 4 files changed, 26 insertions(+), 35 deletions(-) diff --git a/kodos/main.py b/kodos/main.py index 4c240eb..180699c 100644 --- a/kodos/main.py +++ b/kodos/main.py @@ -29,9 +29,6 @@ MATCH_PAUSED = 3 MATCH_EXAMINED = 4 -TRUE = 1 -FALSE = 0 - TIMEOUT = 3 # regex to find special flags which must begin at beginning of line @@ -141,10 +138,10 @@ def checkIfNewUser(self): def createStatusBar(self): - self.status_bar = status_bar.Status_Bar(self, FALSE, "") + self.status_bar = status_bar.Status_Bar(self, False, "") - def updateStatus(self, status_string, status_value, duration=0, replace=FALSE, tooltip=''): + def updateStatus(self, status_string, status_value, duration=0, replace=False, tooltip=''): pixmap = self.statusPixmapsDict.get(status_value) self.status_bar.set_message(status_string, duration, replace, tooltip, pixmap) @@ -289,14 +286,14 @@ def hide_replace_widgets(self): self.replaceLabel.hide() self.replaceNumberSpinBox.hide() self.replaceTextBrowser.clear() - self.replaceTextBrowser.setDisabled(TRUE) + self.replaceTextBrowser.setDisabled(True) def show_replace_widgets(self): self.spacerLabel.show() self.replaceLabel.show() self.replaceNumberSpinBox.show() - self.replaceNumberSpinBox.setEnabled(TRUE) - self.replaceTextBrowser.setEnabled(TRUE) + self.replaceNumberSpinBox.setEnabled(True) + self.replaceTextBrowser.setEnabled(True) def replace_changed_slot(self): self.replace = unicode(self.replaceTextEdit.toPlainText()) @@ -485,8 +482,8 @@ def clear_results(self): self.codeTextBrowser.clear() self.matchTextBrowser.clear() - self.matchNumberSpinBox.setEnabled(FALSE) - self.replaceNumberSpinBox.setEnabled(FALSE) + self.matchNumberSpinBox.setEnabled(False) + self.replaceNumberSpinBox.setEnabled(False) self.replaceTextBrowser.clear() self.matchAllTextBrowser.clear() @@ -515,12 +512,12 @@ def timeout(signum, frame): if allmatches and len(allmatches): self.matchNumberSpinBox.setMaximum(len(allmatches)) - self.matchNumberSpinBox.setEnabled(TRUE) + self.matchNumberSpinBox.setEnabled(True) self.replaceNumberSpinBox.setMaximum(len(allmatches)) - self.replaceNumberSpinBox.setEnabled(TRUE) + self.replaceNumberSpinBox.setEnabled(True) else: - self.matchNumberSpinBox.setEnabled(FALSE) - self.replaceNumberSpinBox.setEnabled(FALSE) + self.matchNumberSpinBox.setEnabled(False) + self.replaceNumberSpinBox.setEnabled(False) match_obj = compile_obj.search(self.matchstring) @@ -673,7 +670,7 @@ def importFile(self): self.updateStatus(self.tr("A file was not selected for import"), -1, 5, - TRUE) + True) return None filename = str(fn) @@ -682,7 +679,7 @@ def importFile(self): fp = open(filename, "r") except: msg = self.tr("Could not open file for reading: ") + filename - self.updateStatus(msg, -1, 5, TRUE) + self.updateStatus(msg, -1, 5, True) return None data = fp.read() @@ -714,7 +711,7 @@ def openFile(self, filename): fp = open(filename, "r") except: msg = self.tr("Could not open file for reading: ") + filename - self.updateStatus(msg, -1, 5, TRUE) + self.updateStatus(msg, -1, 5, True) return None try: @@ -726,7 +723,7 @@ def openFile(self, filename): self.log.error('Error unpickling data from file: %s' % e) msg = "%s %s" % (unicode(self.tr("Error reading from file:")), filename) - self.updateStatus(msg, -1, 5, TRUE) + self.updateStatus(msg, -1, 5, True) return 0 self.matchNumberSpinBox.setValue(1) @@ -746,7 +743,7 @@ def openFile(self, filename): self.filename = filename msg = "%s %s" % (filename, unicode(self.tr("loaded successfully"))) - self.updateStatus(msg, -1, 5, TRUE) + self.updateStatus(msg, -1, 5, True) self.editstate = STATE_UNEDITED return 1 @@ -764,7 +761,7 @@ def fileSaveAs(self): ok = filedialog.exec_() if ok == Qt.QDialog.Rejected: - self.updateStatus(self.tr("No file selected to save"), -1, 5, TRUE) + self.updateStatus(self.tr("No file selected to save"), -1, 5, True) return filename = os.path.normcase(unicode(filedialog.selectedFiles().first())) @@ -783,7 +780,7 @@ def fileSave(self): except: msg = "%s: %s" % (unicode(self.tr("Could not open file for writing:")), self.filename) - self.updateStatus(msg, -1, 5, TRUE) + self.updateStatus(msg, -1, 5, True) return None self.editstate = STATE_UNEDITED @@ -796,7 +793,7 @@ def fileSave(self): fp.close() msg = "%s %s" % (unicode(self.filename), unicode(self.tr("successfully saved"))) - self.updateStatus(msg, -1, 5, TRUE) + self.updateStatus(msg, -1, 5, True) self.recent_files.add(self.filename) @@ -866,7 +863,7 @@ def revert_file_slot(self): self.updateStatus(self.tr("There is no filename to revert"), -1, 5, - TRUE) + True) return self.openFile(self.filename) @@ -969,11 +966,11 @@ def launch_browser_wrapper(self, url, caption=None, message=None): if util.launch_browser(url, caption, message): self.status_bar.set_message(self.tr("Launching web browser"), 3, - TRUE) + True) else: self.status_bar.set_message(self.tr("Cancelled web browser launch"), 3, - TRUE) + True) def reference_guide(self): diff --git a/kodos/status_bar.py b/kodos/status_bar.py index 1e378e8..b895b74 100644 --- a/kodos/status_bar.py +++ b/kodos/status_bar.py @@ -2,12 +2,11 @@ # status_bar.py: -*- Python -*- DESCRIPTIVE TEXT. from . import tooltip -from .util import TRUE, FALSE from PyQt4.QtCore import QTimer from PyQt4.QtGui import QPixmap, QLabel, QProgressBar class Status_Bar: - def __init__(self, parent, progress_bar=FALSE, message=''): + def __init__(self, parent, progress_bar=False, message=''): self.parent = parent self.statusBar = parent.statusBar() @@ -30,13 +29,13 @@ def __init__(self, parent, progress_bar=FALSE, message=''): self.statusBar.addWidget(self.__statusLabel) if progress_bar: self.progressBar = QProgressBar(self.statusBar) - self.statusBar.addWidget(self.progressBar, 1, TRUE) + self.statusBar.addWidget(self.progressBar, 1, True) if message: self.set_message(message) - def set_message(self, message='', duration=0, replace=FALSE, tooltip='', pixmap=''): + def set_message(self, message='', duration=0, replace=False, tooltip='', pixmap=''): """sets the status bar message label to message. if duration is > 0 than the message is displayed for duration seconds. diff --git a/kodos/tooltip.py b/kodos/tooltip.py index 35a6f46..539051f 100644 --- a/kodos/tooltip.py +++ b/kodos/tooltip.py @@ -2,7 +2,6 @@ # tooltip.py: -*- Python -*- DESCRIPTIVE TEXT. from PyQt4 import Qt, QtCore -from .util import FALSE class Tooltip(Qt.QLabel): def __init__(self, text, bgcolor="#ffd700",fgcolor="#000000",delay=1000): @@ -74,7 +73,7 @@ def eventFilter(self, obj, ev): self.killCustomTimers() self.leave_timer_id = self.startTimer(self.delay) self.event_widget = None - return FALSE ## Always return unhandled for this kind of filter!!! + return False ## Always return unhandled for this kind of filter!!! def tooltip_open(self): diff --git a/kodos/util.py b/kodos/util.py index 1d90edb..da53882 100644 --- a/kodos/util.py +++ b/kodos/util.py @@ -10,10 +10,6 @@ log = logging.getLogger('kodos.util') -# QT constants that should be defined -FALSE = 0 -TRUE = 1 - def getAppPath(): "Convenience function so that we can find the necessary images" fullpath = os.path.abspath(os.path.join(sys.argv[0], '..'))