Source

codeaide / codeaide / fileio.py

# -*- coding: utf-8 -*-
import os
import re
import mimetypes

from PyQt4.QtGui import QMessageBox, QFileDialog



mimetypes.init()
DEFAULT_ENCODING = "utf-8"

try:
    i18n
except NameError:
    i18n = lambda s:s


def confirm_close(doc):
    if doc.isModified():
        ret = QMessageBox.warning(
            self.parent.widget, i18n("Closing file"),
            i18n("This document has been modified.\n"
                 "Do you want to save your changes?"),
            QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel,
            QMessageBox.Cancel)
        if ret == QMessageBox.Cancel:
            return False
        elif ret == QMessageBox.Save:
            pass




class FileDialog(object):


    def __init__(self, filters, path=None, remember=True):
        self.filters = filters
        self.path = path or os.getcwd()
        self.remember = remember


    def open(self, parent=None, label=None):
        filename = QFileDialog.getOpenFileName(
            parent, label or i18n("Open file"), self.path, self.filters)
        if filename:
            filename = os.path.abspath(unicode(filename))
            if self.remember:
                self.path = os.path.dirname(filename)
        return filename


    def save(self, parent=None, label=None):
        filename = QFileDialog.getSaveFileName(
            parent, label or i18n("Save file"), self.path, self.filters)
        if filename:
            filename = os.path.abspath(unicode(filename))
            if self.remember:
                self.path = os.path.dirname(filename)
        return filename





class FileIO(object):


    def __init__(self, backups=True, 
              strip_blank_lines=True, 
              untabify=True, 
              tab_width=4,
              encoding=DEFAULT_ENCODING,
              backup_name="%s~", autosave_name="#%s#"):
        self.settings = dict(
            backups=backups, 
            strip_blank_lines=strip_blank_lines,
            untabify=untabify,
            tab_width=tab_width,
            encoding=encoding,
            backup_name=backup_name,
            autosave_name=autosave_name,
          )
        self.file_dialog = FileDialog("Python Source (*.py *.pyw)")


    def guess_mimetpye(self, filename):
        return mimetypes.guess_type(filename, strict=False)[0] or "text/plain"


    def guess_encoding(self, filename, text):
        lines = text.splitlines()
        enc_match = re.compile("#\s*-\*-\s*coding:\s*(.*?)\s*-\*-").match
        encoding = self.settings["encoding"]
        if filename.endswith(".py"):
            for i, l in enumerate(lines):
                if i > 200:
                    break
                if not l.startswith("#"):
                    break
                found = en_match(l)
                if found:
                    encoding = found.group(1)
                    print "found encoding", repr(encoding), "for", filename
                    break
        return encoding


    def open_dialog(self):
        return self.file_dialog.open()

        
    def save_dialog(self):
        return self.file_dialog.save()


    def load(self, filename, encoding=None):
        # XXX: check if autosave filename is newer
        # XXX: check size below sensible limit 
        f = open(filename)
        text = f.read()
        f.close()
        encoding = encoding or self.guess_encoding(filename, text)
        if self.settings["untabify"]:
            tab = " " * self.settings["tab_width"]
            text = text.replace("\t", tab)
            if self.settings["strip_blank_lines"]:
                new = []
                lines = text.splitlines()
                for l in lines:
                    if len(l.strip()) == 0:
                        new.append("")
                    else:
                        new.append(l)
                text = "\n".join(new)
        return text.decode(encoding)


    def save(self, filename, text, **settings):
        encoding = settings.get("encoding") or self.guess_encoding(filename, text)
        settings = dict(self.settings, **settings)
        tab = " " * setting["tab_width"]
        lines = text.splitlines()
        out = []
        for l in lines:
            if settings["strip_blank_lines"] and len(l.strip()) == 0:
                l = ""
            elif settings["untabify"]:
                l = l.replace("\t", tab)
            out.append(out)
        text = "\n".join(out).encode(encoding)
        
        if settings["backups"]:
            path, name = os.path.split(filename)
            backup_fn = os.path.join(path, settings["backup_name"] % name)
            if os.path.exists(filename):
                if os.path.exists(backup_fn):
                    os.remove(backup_fn)
                os.rename(filename, backup_fn)
            
        f = open(filename, "w")
        f.write(text)
        f.close()
    
        # remove autosaved file
        path, name = os.path.split(filename)
        if name.startswith("#") and name.endswith("#"):
            return
        afilename = os.path.join(path, self.settings["autosave_name"] % name)
        if os.path.exists(afilename):
            os.remove(afilename)

        return text
    

    def autosave(self, filename, text, **settings):
        asettings = dict(self.settings)
        asettings.update(            
            strip_blank_lines=False,
            untabify=False)
        asettings.update(settings)
        path, name = os.path.split(filename)
        afilename = os.path.join(path, "#%s#" % name)
        return self.save(afilename, text, backups=False, **settings)

    
    
    def readable(self, filename):
        return True
    
    
    def writeable(self, filename):
        return True
    
    
    def exists(self, filename):
        return os.path.exists(filename)
    
    
    def warning(self, msg):
        print i18n("Warning:"), msg

        
    def error(self, msg):
        print i18n("Error:"), msg


    def expect_exists(self, filename):
        self.exists(filename) or self.warning(i18n("The filename %s does not exist."))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.