kodos.py :  » GUI » Kodos » kodos-2.4.9 » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » GUI » Kodos 
Kodos » kodos 2.4.9 » kodos.py
#!/usr/bin/env python
#  kodos.py: -*- Python -*-  DESCRIPTIVE TEXT.

import sys
import os
import string
import re
import copy
import cPickle
import types
import getopt
import urllib
import signal

try:
    from qt import *
except:
    print """Could not locate the PyQt module.  Please make sure that
you have installed PyQt for the version of Python that you are running."""
    sys.exit(1)
    
### make sure that this script can find kodos specific modules ###
import os.path
from distutils.sysconfig import get_python_lib

sys.path.insert(0, 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.webbrowser import launch_browser
from modules.reportBug import reportBugWindow
from modules.version import VERSION
from modules.recent_files import RecentFiles
import modules.xpm as xpm
from modules.urlDialog import URLDialog
from modules.migrate_settings import MigrateSettings
from modules.regexLibrary import RegexLibrary
from modules.newUserDialogBA import NewUserDialog


# 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<flags>[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

QT_VERS = int(QT_VERSION_STR[0])

if QT_VERS < 3:
    print "Qt versions prior to 3.0 are no longer supported"
    sys.exit(0)

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.flags = 0
        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.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(xpm.yellowStatusIcon),
                                  MATCH_OK: QPixmap(xpm.greenStatusIcon),
                                  MATCH_FAIL: QPixmap(xpm.redStatusIcon),
                                  MATCH_PAUSED: QPixmap(xpm.pauseStatusIcon)}

        
        self.updateStatus(self.MSG_NA, MATCH_NA)

        restoreWindowSettings(self, GEO)
        
        self.show()

        self.prefs = Preferences(self, 1)
        self.recent_files = RecentFiles(self,
                                        self.prefs.recentFilesSpinBox.value(),
                                        self.debug)

        self.matchTextBrowser.setTextFormat(QTextEdit.PlainText)

        if filename and self.openFile(filename):
            qApp.processEvents()

        self.connect(self, PYSIGNAL('prefsSaved()'), self.prefsSaved)

        self.connect(self.fileMenu,
                     SIGNAL('activated(int)'),
                     self.fileMenuHandler)
        
        self.connect(self, PYSIGNAL('pasteSymbol()'), self.paste_symbol)

        self.connect(self, PYSIGNAL('urlImported()'), self.urlImported)

        self.connect(self, PYSIGNAL('pasteRegexLib()'), self.pasteFromRegexLib)

        kodos_toolbar_logo(self.toolBar)
        if self.replace:  self.show_replace_widgets()
        else:             self.hide_replace_widgets()

        self.checkForKodosDir()


    def checkForKodosDir(self):
        kdir = os.path.join(getHomeDirectory(), ".kodos")
        if os.access(kdir, os.X_OK):
            return

        try:
            os.mkdir(kdir, 0755)
        except:
            print "Failed to create:", kdir

        self.newuserdialog = NewUserDialog()
        self.newuserdialog.show()
        

    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(self.fileMenu.text(menuid))
            self.recent_files.add(fn)
            self.openFile(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.flags = 0
        
        if self.ignorecaseCheckBox.isChecked():
            self.flags = self.flags + re.IGNORECASE

        if self.multilineCheckBox.isChecked():
            self.flags = self.flags + re.MULTILINE

        if self.dotallCheckBox.isChecked():
            self.flags = self.flags + re.DOTALL

        if self.verboseCheckBox.isChecked():
            self.flags = self.flags + re.VERBOSE

        if self.localeCheckBox.isChecked():
            self.flags = self.flags + re.LOCALE

        if self.unicodeCheckBox.isChecked():
            self.flags = self.flags + re.UNICODE

        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
        if flags & re.IGNORECASE:
            self.ignorecaseCheckBox.setChecked(1)
        else:
            self.ignorecaseCheckBox.setChecked(0)

        if flags & re.MULTILINE:
            self.multilineCheckBox.setChecked(1)
        else:
            self.multilineCheckBox.setChecked(0)
            
        if flags & re.DOTALL:
            self.dotallCheckBox.setChecked(1)
        else:
            self.dotallCheckBox.setChecked(0)
            
        if flags & re.VERBOSE:
            self.verboseCheckBox.setChecked(1)
        else:
            self.verboseCheckBox.setChecked(0)

        if flags & re.LOCALE:
            self.localeCheckBox.setChecked(1)
        else:
            self.localeCheckBox.setChecked(0)

        if flags & re.UNICODE:
            self.unicodeCheckBox.setChecked(1)
        else:
            self.unicodeCheckBox.setChecked(0)


    def get_flags_string(self):
        flags_str = ""
        
        if self.ignorecaseCheckBox.isChecked():
            flags_str += "| re.IGNORECASE"

        if self.multilineCheckBox.isChecked():
            flags_str += "| re.MULTILINE"

        if self.dotallCheckBox.isChecked():
            flags_str += "| re.DOTALL"

        if self.verboseCheckBox.isChecked():
            flags_str += "| re.VERBOSE"

        if self.localeCheckBox.isChecked():
            flags_str += "| re.LOCALE"

        if self.unicodeCheckBox.isChecked():
            flags_str += "| re.UNICODE"

        if flags_str: flags_str = ", " + flags_str[1:]
        return flags_str


    def get_embedded_flags_string(self):
        flags_str = flags = ""
        
        if self.ignorecaseCheckBox.isChecked():
            flags += "i"

        if self.multilineCheckBox.isChecked():
            flags += "m"

        if self.dotallCheckBox.isChecked():
            flags += "s"

        if self.verboseCheckBox.isChecked():
            flags += "x"

        if self.localeCheckBox.isChecked():
            flags += "L"

        if self.unicodeCheckBox.isChecked():
            flags += "u"

        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)
            found = 0
            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.flags)
                    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):
        self.regexMultiLineEdit.setPaletteBackgroundColor(base_qcolor)
        
        self.regexMultiLineEdit.blockSignals(1)
        self.regexMultiLineEdit.clear()
        self.regexMultiLineEdit.blockSignals(0)
        self.regexMultiLineEdit.setText(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):
        try:
            self.regex = str(self.regexMultiLineEdit.text())
        except UnicodeError:
            self.regex = unicode(self.regexMultiLineEdit.text())
            
        self.process_regex()


    def string_changed_slot(self):
        try:
            self.matchstring = str(self.stringMultiLineEdit.text())
        except UnicodeError:
            self.matchstring = unicode(self.stringMultiLineEdit.text())
        self.process_regex()


    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):
        try:
            self.replace = str(self.replaceTextEdit.text())
        except UnicodeError:
            self.replace = unicode(self.replaceTextEdit.text())
            
        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_listview(self, tuples):
        # deprecated as of 2.4.0 - now uses QTable instead of QListView
        self.groupListView.clear()

        num_cols = 3
        for t in tuples:
            item = QListViewItem(self.groupListView)
            for col in range(num_cols):
                try:
                    item.setText(col, str(t[col]))
                except UnicodeError:
                    item.setText(col, unicode(t[col]))


    def populate_group_table(self, tuples):
        self.groupTable.setNumRows(len(tuples))

        row = 0
        for t in tuples:
            self.groupTable.setText(row, 0, unicode(t[1]))
            self.groupTable.setText(row, 1, unicode(t[2]))
            self.groupTable.adjustRow(row)
            row += 1
            
        self.groupTable.adjustColumn(0)
        self.groupTable.adjustColumn(1)


    def populate_code_textbrowser(self):
        self.codeTextBrowser.setText("")

        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"
        if self.flags != 0:
            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"
        if self.flags != 0:
            code += self.get_flags_string()
        code += ")\n\n"

        code += "# method 3: using search function (w/ embedded flags)\n"
        embedded_str = self.get_embedded_flags_string() + self.regex_embedded_flags_removed
        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.setText(code)


    def colorize_strings(self, strings, widget, cursorOffset=0):
        widget.clear()

        colors = (QColor(Qt.black), QColor(Qt.blue) )
        i = 0
        pos = widget.getCursorPosition()
        for s in strings:
            widget.setColor(colors[i%2])            
            widget.insert(s)
            if i == cursorOffset: pos = widget.getCursorPosition()
            i += 1
            
        widget.setCursorPosition(pos[0], pos[1])
        

    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.text())
        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.setText(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):
        #self.groupListView.clear()
        self.groupTable.setNumRows(0)
        self.codeTextBrowser.setText("")
        self.matchTextBrowser.setText("")
        self.matchNumberSpinBox.setEnabled(FALSE)
        self.replaceNumberSpinBox.setEnabled(FALSE)
        self.replaceTextBrowser.setText("")
        self.matchAllTextBrowser.setText("")
        

    def process_regex(self):
        def timeout(signum, frame):
            return

        if self.is_paused:
            return
        
        if not self.regex or not self.matchstring:
            self.update_results(self.MSG_NA, MATCH_NA)
            self.clear_results()
            return

        self.process_embedded_flags(self.regex)
        #print self.resultTabWidget.currentPageIndex()
        
        if HAS_ALARM:
            signal.signal(signal.SIGALRM, timeout)
            signal.alarm(TIMEOUT)

        try:
            compile_obj = re.compile(self.regex, self.flags)
            allmatches = compile_obj.findall(self.matchstring)

            replace_spans = []
            if allmatches and len(allmatches):
                self.matchNumberSpinBox.setMaxValue(len(allmatches))
                self.matchNumberSpinBox.setEnabled(TRUE)
                self.replaceNumberSpinBox.setMaxValue(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(str(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():
            #print match_obj.groups()
            s = "<font color=blue>"
            num_groups = len(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) )
                        
            #print group_tuples
            self.populate_group_table(self.group_tuples)
            #self.populate_group_listview(self.group_tuples)

        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_match)
            
        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):
        self.checkEditState(self.tr("&No, Just Exit Kodos"))
        saveWindowSettings(self, GEO)

        try:
            self.regexlibwin.close()
        except:
            pass

        try:
            self.ref_win.close()
        except:
            pass
        ev.accept()


    def fileNew(self):
        self.checkEditState()
        self.filename = ""
        
        self.regexMultiLineEdit.setText("")
        self.stringMultiLineEdit.setText("")
        self.replaceTextEdit.setText("")
        self.set_flags(0)
        self.editstate = 0


    def importURL(self):
        self.urldialog = URLDialog(self, self.url)


    def urlImported(self, html, url):
        self.url = url
        self.stringMultiLineEdit.setText(html)
        

    def importFile(self):
        fn = QFileDialog.getOpenFileName(self.filename, "All (*)",
                                         self, "Import File")
        
        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.setText(data)

        
    def fileOpen(self):       
        fn = QFileDialog.getOpenFileName(self.filename,
                                         "*.kds\nAll (*)",
                                         self,
                                         "Open",
                                         self.tr("Open Kodos File"))        
        if not fn.isEmpty():
            filename = str(fn)
            if self.openFile(filename):
                self.recent_files.add(filename)


    def openFile(self, filename):
        self.checkEditState()

        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.matchNumberSpinBox.setValue(1)
            self.regex = u.load()
            self.regexMultiLineEdit.setText(self.regex)

            self.matchstring = u.load()
            self.stringMultiLineEdit.setText(self.matchstring)
            
            flags = u.load()
            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.setText(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
        except Exception, e:
            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


    def fileSaveAs(self):
        while 1:
            self.filedialog = QFileDialog(self.filename,
                                          "*.kds\nAll (*)",
                                          self,
                                          "Save",
                                          TRUE)
            self.filedialog.setCaption(self.tr("Save Kodos File"))
            self.filedialog.setMode(QFileDialog.AnyFile)
            #self.filedialog.show()
            ok = self.filedialog.exec_loop()

            filename = unicode(self.filedialog.selectedFile())
            if not ok or not filename:
                self.updateStatus(self.tr("No file selected to save"), -1, 5, TRUE)
                return
            filename = os.path.normcase(filename)

            basename = os.path.basename(filename)
            if basename.find(".") == -1:
                filename += ".kds"

            if os.access(filename, os.F_OK):
                message = "%s, %s %s\n%s" % (unicode(self.tr("The file")),
                                         filename,
                                         unicode(self.tr("already exists.")),
                                         unicode(self.tr("Would you like to replace it?")))
                cancel = QMessageBox.information(None,
                                                 self.tr("Replace file?"),
                                                 message,
                                                 self.tr("&Replace"),
                                                 self.tr("&Cancel"))
                if cancel:
                    # allow user to choose another filename
                    continue

            self.filename = filename
            self.fileSave()
            break


    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.flags)
        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.insert(symbol)


    def process_embedded_flags(self, regex):
        # determine if the regex contains embedded regex flags.
        # if not, return 0 -- inidicating that the regex has no embedded flags
        # if it does, set the appropriate checkboxes on the UI to reflect the flags that are embedded
        #   and return 1 to indicate that the string has embedded flags
        match = self.embedded_flags_obj.match(regex)
        if not match:
            self.embedded_flags = ""
            self.regex_embedded_flags_removed = regex
            return 0

        self.embedded_flags = match.group('flags')
        self.regex_embedded_flags_removed = self.embedded_flags_obj.sub("", regex, 1)
        
        for flag in self.embedded_flags:
            if flag == 'i':
                self.ignorecaseCheckBox.setChecked(1)
            elif flag == 'L':
                self.localeCheckBox.setChecked(1)
            elif flag == 'm':
                self.multilineCheckBox.setChecked(1)
            elif flag == 's':
                self.dotallCheckBox.setChecked(1)
            elif flag == 'u':
                self.unicodeCheckBox.setChecked(1)
            elif flag == 'x':
                self.verboseCheckBox.setChecked(1)

        return 1


    def checkEditState(self, noButtonStr=None):
        if not noButtonStr: noButtonStr = self.tr("&No")
        
        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,
                                         self.tr("&Yes, Save Changes"),
                                         noButtonStr)
            
            if prompt == 0:
                self.fileSave()
                if not self.filename: self.checkEditState(noButtonStr)


    def pasteFromRegexLib(self, d):
        self.filename = ""
        self.checkEditState()

        self.regexMultiLineEdit.setText(d.get('regex'), "")
        self.stringMultiLineEdit.setText(d.get('text'), "")
        self.replaceTextEdit.setText(d.get('replace'), "")

        try:
            # set the current page if applicable
            self.resultTabWidget.setCurrentPage(int(d['tab']))
        except:
            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()
            
    def setfont(self, font):
        #print "font: ",  font
        #return
        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,
                                    "python" + os.sep + "module-re.html",
                                    str(self.prefs.browserEdit.text()))
        

    def helpRegexLib(self):
        f = os.path.join("help", "regex-lib.xml")
        self.regexlibwin = RegexLibrary(self, f)
        self.regexlibwin.show()

        
    def helpAbout(self):
        self.aboutWindow = About()
        self.aboutWindow.show()


    def kodos_website(self):
        self.launch_browser_wrapper("http://kodos.sourceforge.net")

            
    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<version>.*?)\<"""
        #rawstr = r"""release_id=.*\">.*(kodos-)(?P<version>.*?)</[aA]>"""
        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):
        browser = str(self.prefs.browserEdit.text())
        if launch_browser(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.show()
        

    def report_bug(self):
        self.bug_report_win = reportBugWindow(self)
        

##############################################################################
#
#
##############################################################################

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

    MigrateSettings()

    qApp = QApplication(sys.argv)

    if locale not in (None, 'en'):
        localefile = "kodos_%s.qm" % (locale or QTextCodec.locale())
        localepath = findFile(os.path.join("translations", localefile))
        if debug:
            print "locale changed to:", locale
            print localefile
            print localepath
    
        translator = QTranslator(qApp)
        translator.load(localepath)

        qApp.installTranslator(translator)

    kodos = Kodos(filename, debug)

    qApp.setMainWidget(kodos)

    qApp.exec_loop()    



if __name__ == '__main__':
    main()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.