コード例 #1
0
ファイル: reStInPeace.py プロジェクト: ver007/reStInPeace
    def tableCreate(self):
        """ This function creates a QTableWidgetItem out of a 2-dimension nested list which contains numbers, and then uses it to "paint" the someTbl object, which is a QTableWidget """
        dial = QtGui.QDialog(self)
        dial.setWindowTitle("Table creator")
        self.tabledialog = dial
        self.tbl_dial = Ui_ArrayDialog()
        self.tbl_dial.setupUi(dial)


        #ArrayDialog.show()
        tbl = self.tbl_dial.tableWidget
        col = self.tbl_dial.spinBoxColumns
        lin = self.tbl_dial.spinBoxRows
        but = self.tbl_dial.okButton

        # Connexions
        self.connect(col, QtCore.SIGNAL("valueChanged(int)"), self.actualiseTable)
        self.connect(lin, QtCore.SIGNAL("valueChanged(int)"), self.actualiseTable)
        #dial.connect(but, QtCore.SIGNAL("cliked()"), self.insertRestTable)
        QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), self.insertRestTable)
        tbl.setColumnCount(col.value())
        tbl.setRowCount(lin.value())

        dial.show()
コード例 #2
0
ファイル: reStInPeace.py プロジェクト: jimmykuu/reStInPeace
    def tableCreate(self):
        """ This function creates a QTableWidgetItem out of a 2-dimension nested list which contains numbers, and then uses it to "paint" the someTbl object, which is a QTableWidget """
        dial = QtGui.QDialog(self)
        dial.setWindowTitle("Table creator")
        self.tabledialog = dial
        self.tbl_dial = Ui_ArrayDialog()
        self.tbl_dial.setupUi(dial)

        # ArrayDialog.show()
        tbl = self.tbl_dial.tableWidget
        col = self.tbl_dial.spinBoxColumns
        lin = self.tbl_dial.spinBoxRows
        but = self.tbl_dial.okButton

        # Connexions
        self.connect(col, QtCore.SIGNAL("valueChanged(int)"), self.actualiseTable)
        self.connect(lin, QtCore.SIGNAL("valueChanged(int)"), self.actualiseTable)
        # dial.connect(but, QtCore.SIGNAL("cliked()"), self.insertRestTable)
        QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), self.insertRestTable)
        tbl.setColumnCount(col.value())
        tbl.setRowCount(lin.value())

        dial.show()
コード例 #3
0
ファイル: reStInPeace.py プロジェクト: jimmykuu/reStInPeace
class MonAppli(QtGui.QMainWindow, Ui_MainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)

        # Configure the user interface.
        self.setupUi(self)

        # Snippets special Variables
        # snippet
        self.insideSnippet = False
        self.start_snip = 0
        # Field courant
        self.snippets = []
        self.field = None
        self.field_start = 0
        self.field_long = 0
        self.oldsnip = None

        # Editor
        # Editor tabs = 4 chars
        self.tab_long = 4
        self.setTabEditorWidth(self.tab_long)
        # Coloration syntaxique
        self.highlighter = highlighter.Highlighter(self.editor)
        self.highlighter.modeRest()

        # Browser (viewer)
        # Set permissions to open external links
        # by clicking on them
        self.viewer.openExternalLinks = True
        self.viewer.setOpenExternalLinks(True)

        # Big Hack not to have to create a particluar
        # classe for the browser.
        # TODO : clean derivation
        self.viewer.loadResource = imageBrowser().loadResource

        ## Special attributes :
        # name of the current edited file
        self.fileName = "Noname.rst"
        # absolute path
        self.filePath = INREP
        # boolean to know if file has been saved or not
        self.isSaved = False
        # default directory
        self.default_dir = INREP  # or APPLIREP (up to you)

        ## Conversion Dialog
        self.ConvDialog = QtGui.QDialog(self)
        ui = Ui_Converter()
        ui.setupUi(self.ConvDialog)
        self.converterdial = ui

        ## SIGNALS/SLOTS
        # we need to know if source as changed
        self.connect(self.editor, QtCore.SIGNAL("textChanged()"), self.needSave)

        ## ScrollBars editor-viewer
        # scrollbar editor
        self.esb = self.editor.verticalScrollBar()
        # scrollbar viewer
        self.vsb = self.viewer.verticalScrollBar()
        # connexions scrollbar editor --> synchronise view in browser
        self.connect(self.esb, QtCore.SIGNAL("valueChanged(int) "), self.actualiseBSlider)
        # connexions scrollbar viewer --> synchronise view in editor
        self.connect(self.vsb, QtCore.SIGNAL("valueChanged(int) "), self.actualiseESlider)

        ## zoom event for editor and viewer
        import types

        self.editor.wheelEvent = types.MethodType(zoomEditor, self.editor, self.editor.__class__)
        self.viewer.wheelEvent = types.MethodType(zoomViewer, self.viewer, self.viewer.__class__)

        ## MENU ACTIONS
        self.createActions()

        ## BUTTONS
        self.actionSave.setEnabled(self.isSaved)

        ## APPLY SAVED APP SETTINGS
        self.readSettings()

        ## KEYBOARD SHORTCUTS
        keyTab = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Tab")), self)
        self.connect(keyTab, QtCore.SIGNAL("activated()"), self.whatToDoOnTab)

        QtGui.QShortcut(QtGui.QKeySequence("F1"), self, self.showHelp)
        QtGui.QShortcut(QtGui.QKeySequence("F2"), self, self.indentRegion)
        QtGui.QShortcut(QtGui.QKeySequence("F3"), self, self.unindentRegion)
        QtGui.QShortcut(QtGui.QKeySequence("F4"), self, self.chooseFont)
        QtGui.QShortcut(QtGui.QKeySequence("F5"), self, self.tableCreate)
        QtGui.QShortcut(QtGui.QKeySequence("F6"), self, self.columnMode)

        self.connect(self.editor, QtCore.SIGNAL("textChanged()"), self.updateChilds)

        ## STATUSBAR
        self.statusBar().showMessage("Welcome to reStInPeace, press F1 for Help.")

    ## ------------------------------------------
    ##                  Snippets
    ##
    ## Methods used by the editor :
    ##
    ## - insertSnippet
    ## - whatToDoOnTab
    ## - nextField
    ## - endSnip
    ## - updateChilds
    ## ------------------------------------------
    def columnMode(self):
        deb = self.editor.textCursor()
        selection = deb.selectedText()
        lines = unicode(selection).split()
        print lines

        for i in lines:
            c = self.editor.textCursor()
            # on se positionne au debut
            c.movePosition(QtGui.QTextCursor.Down)
            c.insertText(i)
            c.movePosition(QtGui.QTextCursor.Left, len(i))
            self.editor.setTextCursor(c)

        # on repositionne alors le curseur
        self.editor.setTextCursor(deb)

    def insertSnippet(self):
        """ Called from whatToDoOnTab's method
        
        Takes the word before the cursor thanks to wordLeftExtend's
        method and tries to find the word in the snippet dictionary
        DICSNIP.
        
        If so, the snippet is added to the stack and expanded, returning True.
        """
        # r�cup�re le curseur et sa position
        tc = self.editor.textCursor()
        p = tc.position()

        # recup�re le mot le plus � gauche de celui-ci
        word = self.wordLeftExtend(tc)

        # position de depart du snippet
        # [Si on tape en (0,0) le mot 'link', le curseur
        # est alors en pos (4,0). Il faut alors corriger
        # ceci en enlevant la longeur du raccourci tap�.]

        # On essaye de r�cup�rer dans le dico des snippets
        # celui qui correspond au raccourci tap�.
        try:
            # le mot est dans le dico
            tpl = DICSNIP[word][1]
            helptpl = DICSNIP[word][0]
            self.snippet = Snippet(unicode(tpl))
            self.snippet.help = helptpl
            self.snippet.start = p - len(word)
            ##
            self.snippets.append(self.snippet)

            self.snippet.fielditer = self.snippet.fieldIter()
            rendu = self.snippet.expanded()
            self.snippet.long = len(rendu)

            # tc.beginEditBlock()
            self.editor.blockSignals(True)
            tc.insertText(rendu)
            self.editor.blockSignals(False)
            # tc.endEditBlock()

            return True
        except:
            # word is not in DICSNIP
            self.removeSelection()
            return False

    def whatToDoOnTab(self):
        """ Slot called when 'Tab' is pressed.

           - Tries to expand the word before the cursor;
           
           - if return value is True in insertSnippet's method:
                - the snipped has been added to the stack and is expanded,
                  we then go to the next snippet's field, if any.
             
           - if return value is False in insertSnippet's method:
                - if there are already snippets in stack, pass to the next one.
                - if there are no snippet in stack : stop and insert a tab char.
        """
        expanded = self.insertSnippet()  # boolean

        if expanded:  # if a snippet has been entered previously
            self.nextField()
        else:  # the word entered wasn't a shortcut
            if len(self.snippets) > 0:
                self.nextField()
            else:
                self.statusBar().showMessage("insert spaces as no more snippet in stack %s" % (self.snippets))
                self.editor.textCursor().insertText(" " * self.tab_long)

    def nextField(self):

        try:  # to go to next field
            self.field = self.snippet.fielditer.next()
            self.snippet.current_field = self.field

            self.field.start = self.snippet.getFieldPos(self.field)
            self.field.long = self.field.getLengh()
            self.statusBar().showMessage(
                "Field=%s--Snippet=%s--Start=%s--Long=%s"
                % (self.field.code, self.snippet, self.field.start, self.field.long)
            )
            self.selectFromTo(self.snippet.start + self.field.start, self.field.long)

            if self.field.isEnd:
                self.endSnip()
        except:
            self.statusBar().showMessage("ds nextField %s %s" % (self.snippet, self.snippet.current_field))

    def endSnip(self):
        self.removeSelection()
        if len(self.snippets) < 1:
            self.snippets = []
            return

        oldval = self.snippet.expanded()
        self.snippets.pop()  # the old snippet
        self.snippet = self.snippets[-1]  # new snippet= last entry
        self.field = self.snippet.current_field
        self.updateChilds(given=oldval)
        self.whatToDoOnTab()

    def updateChilds(self, given=None):
        """ Slot called when textarea is modified.
        """
        if len(self.snippets) > 0:
            ## curseur
            c = self.editor.textCursor()
            cursor_pos = c.position()

            ## variables utiles
            # pos de depart du snippet
            debut_snip = self.snippet.start
            old_long = self.snippet.long
            # le champ
            f = self.snippet.current_field

            # le nbr d'esclaves
            nslaves = len(f.slaves)
            # la valeur de l'ancien champ (si existence)
            old_field_val = f.content
            # l'ancien champ
            self.oldfield = f

            ## Capture le texte du champ actuel
            # l'affiche dans la statusbar
            newpos = c.selectionStart()
            # c.setPosition(debutsnip+st, QtGui.QTextCursor.MoveAnchor)
            c.setPosition(self.field.start + self.snippet.start, QtGui.QTextCursor.MoveAnchor)
            c.setPosition(cursor_pos, QtGui.QTextCursor.KeepAnchor)
            if not given:
                self.exp = c.selectedText()
            else:
                self.exp = given
            self.statusBar().showMessage("Field %s replaced by '%s'" % (f.code, unicode(self.exp)))

            ## Selectionne et remplace le snippet

            # update du champ avec la valeur calculee
            f.content = unicode(self.exp)

            # nouveau contenu du snippet
            cont = self.snippet.expanded()

            # self.snip_long est l'ancienne longueur
            offset = len(f.content) - len(old_field_val)
            self.selectFromTo(self.snippet.start, self.snippet.long + offset)
            # time.sleep(1)

            # on update la longueur du snippet
            self.snippet.long = len(cont)

            # On doit faire attention a bloquer
            # l'emission du signal
            self.editor.blockSignals(True)
            self.editor.textCursor().insertText(cont)
            self.editor.blockSignals(False)

            # Should I prefer this one-liner ?
            # self.selectFromTo(self.start_snip+f.start+len(self.exp), 0)

            c = self.editor.textCursor()
            c.setPosition(self.field.start + self.snippet.start + len(self.exp))
            self.editor.setTextCursor(c)

    ## ------------------------------------------
    ## Editor's functions
    ## ------------------------------------------
    # Find the word before the cursor and select it
    def wordLeftExtend(self, my_cursor):
        """ Recup�re le mot le plus � gauche
            d'un curseur donn� et le s�lectionne.
        """
        oldpos = my_cursor.position()

        # manips curseur
        my_cursor.select(QtGui.QTextCursor.WordUnderCursor)
        # self.editor.setTextCursor(my_cursor)

        newpos = my_cursor.selectionStart()

        my_cursor.setPosition(newpos, QtGui.QTextCursor.MoveAnchor)
        my_cursor.setPosition(oldpos, QtGui.QTextCursor.KeepAnchor)
        self.editor.setTextCursor(my_cursor)
        return str(my_cursor.selectedText())

    def showCursorPos(self):
        tc = self.editor.textCursor()
        self.statusBar().showMessage("Position: %s" % (tc.position()))

    # selectionne le texte de pos � pos + nbr_car
    def selectFromTo(self, pos, nbr_car):
        """ Selectionne la partie de texte comprise
            entre pos et pos + nbr_car
        """
        # print "Je dois Selectionner de ", pos," a ",lon
        c = self.editor.textCursor()
        # on se positionne au debut
        c.setPosition(pos)
        # on va vers la droite de nbr_car caract�res
        c.movePosition(QtGui.QTextCursor.Right, QtGui.QTextCursor.KeepAnchor, nbr_car)
        # on repositionne alors le curseur
        self.editor.setTextCursor(c)

    # enleve toute selection
    def removeSelection(self):
        """ Enleve la selection et deplace le
            curseur � la fin de celle-ci.
        """
        p = self.editor.textCursor().position()
        self.selectFromTo(p, 0)

    ## ------------------------------------------
    ## Nombre de caract�res maximum sur une ligne
    ## ------------------------------------------
    def setTabEditorWidth(self, tw):
        e = self.editor
        e.setTabStopWidth(e.fontMetrics().width("x") * tw)

    ## Sliders verticaux
    def actualiseBSlider(self, val_ed):
        # Essaye d'actualiser le scrolling du Browser
        # de fa�on proportionnelle � celui de l'
        # �diteur.
        #
        # val est la valeur du slider de l'editeur
        val_view = self.vsb.sliderPosition()

        max_ed = self.esb.maximum()
        max_view = self.vsb.maximum()

        prop_ed = float(val_ed) / float(max_ed)
        prop_view = float(val_view) / float(max_view)

        if not (prop_ed - 0.01 <= prop_view <= prop_ed + 0.01):
            self.vsb.setSliderPosition(prop_ed * max_view)

    def actualiseESlider(self, val_view):
        val_ed = self.esb.sliderPosition()

        max_ed = self.esb.maximum()
        max_view = self.vsb.maximum()

        prop_ed = float(val_ed) / float(max_ed)
        prop_view = float(val_view) / float(max_view)

        if not (prop_view - 0.01 <= prop_ed <= prop_view + 0.01):
            self.esb.setSliderPosition(prop_view * max_ed)

    def newFile(self, path=""):
        """ Create a new reSTructuredText file UTF-8 encoded
        """
        if self.isSaved:
            self.editor.clear()
            self.fileName = "Noname.rst"
            self.filePath = INREP
            self.isSaved = False
            self.toBrowser()
            self.actionSave.setEnabled(self.isSaved)
            self.actionSaveAs.setEnabled(self.isSaved)
        else:
            self.Attention("Your document has not yet been saved, please save it before !")
            # self.saveFile()

    def openFile(self, path=""):
        """ Open a reSTructuredText file UTF-8 encoded
        """

        fileName = QtCore.QString(path)

        if fileName.isEmpty():
            fileName = QtGui.QFileDialog.getOpenFileName(
                self, self.tr("Open the file"), self.default_dir, "reST Files (*.rst *.txt )"
            )
        codec = QtCore.QTextCodec.codecForName("UTF-8")
        if not fileName.isEmpty():
            # le nom du fichier brut
            self.fileName = str(QtCore.QFileInfo(fileName).fileName())
            self.filePath = str(QtCore.QFileInfo(fileName).path())
            self.editor.clear()
            # update de la statusbar
            self.statusBar().showMessage("File %s has been loaded correctly." % (self.fileName))

            inFile = QtCore.QFile(fileName)
            # print inFile.fileName()
            if inFile.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text):
                data = QtCore.QTextStream(inFile)
                data.setAutoDetectUnicode(True)
                data.setCodec(codec)
                self.decodedStr = data.readAll()
                self.editor.setPlainText(self.decodedStr)
        self.isSaved = True
        self.toBrowser()
        self.actionSave.setEnabled(self.isSaved)
        self.actionSaveAs.setEnabled(self.isSaved)

    def saveFileAs(self):
        """ Save actual file in default dir
        """

        fileName = QtGui.QFileDialog.getSaveFileName(
            self, self.tr("Save the file as..."), self.filePath, "reST Files (*.rst *.txt )"
        )
        if not fileName.isEmpty():
            outFile = QtCore.QFile(fileName)
            if not outFile.open(QtCore.QFile.WriteOnly):
                print "A problem has occured with your file..."
                return
            out = QtCore.QTextStream(outFile)
            out.setCodec("UTF-8")
            out << self.editor.toPlainText()
            # update de self.filename :
            self.fileName = QtCore.QFileInfo(outFile).fileName()
            # update de la statusbar
            self.statusBar().showMessage("File %s has been saved correctly." % (self.fileName))

            # flag de sauvegarde
            self.isSaved = True
            self.actionSave.setEnabled(self.isSaved)

    # Why reinvent the wheel ? It has been taken and adapted from M.Summerfield's demo
    def saveFile(self):
        fp = self.filePath + "/"
        if self.fileName == "Noname.rst":
            self.saveFileAs()
            return
        if QtCore.QFile.exists(self.fileName):
            backup = self.fileName + ".rst_old"
            ok = True
            if QtCore.QFile.exists(fp + backup):
                ok = QtCore.QFile.remove(fp + backup)
                if not ok:
                    QtGui.QMessageBox.information(
                        self, "reSTinPeace - Save Warning", "Failed to remove the old backup %s"
                    )
            if ok:
                # Must use copy rather than rename to preserve file
                # permissions; could use rename on Windows though
                if not QtCore.QFile.copy(fp + self.fileName, fp + backup):
                    QtGui.QMessageBox.information(self, "reSTinPeace - Save Warning", "Failed to save a backup %s")

        try:
            try:
                fh = QtCore.QFile(fp + self.fileName)
                if not fh.open(QtCore.QIODevice.WriteOnly):
                    raise IOError, unicode(fh.errorString())
                stream = QtCore.QTextStream(fh)
                stream.setCodec("UTF-8")
                stream << self.editor.toPlainText()
                self.editor.document().setModified(False)
                self.setWindowModified(False)
                self.setWindowTitle("reSTinPeace - %s[*]" % QtCore.QFileInfo(fp + self.fileName).fileName())
                self.statusBar().showMessage("Saved %s" % self.fileName, 5000)
                self.isSaved = True
            except (IOError, OSError), e:
                QtGui.QMessageBox.warning(
                    self, "reSTinPeace - Save Error", "Failed to save %s: %s" % (fp + self.fileName, e)
                )
        finally:
            if fh is not None:
                fh.close()
        return True

    def toBrowser(self):
        """ Transforme le texte de l'editeur en HTML
            pour le voir dans la partie browser.
        """
        self.viewer.document().setDefaultStyleSheet(open(os.getcwd() + "/browser.css", "r").read())
        sortie = core.publish_string(
            unicode(self.editor.document().toPlainText()).encode("utf-8"),
            writer_name="html",
            settings_overrides={"input_encoding": "utf-8", "output_encoding": "latin-1", "language": "en"},
        )
        self.viewer.setSearchPaths([os.path.expanduser(self.filePath)])
        self.viewer.setHtml(sortie)

    def showConverterDialog(self):
        """ Affiche le dialogue de conversion
        """
        self.ConvDialog.show()
        self.connect(self.converterdial.but_process, QtCore.SIGNAL("clicked()"), self.processOutput)

    def processOutput(self):
        """ Transforme l'entree au format demand�
        """

        dic_formats = {
            "(X)HTML": ("to_html", "css"),
            "LaTeX": ("to_tex", "sty"),
            "OpenOffice": ("to_odt", "odt"),
            "Lout": ("to_lout", "lout"),
        }
        dial = self.converterdial
        format = dic_formats[str(dial.combo_out.currentText())][0]

        opt = ""
        if format == "to_odt":
            opt = " --add-syntax-highlighting "

        Tstylesheet = OUTREP + "/default." + dic_formats[str(dial.combo_out.currentText())][1]
        extension = "." + format[3:]
        format += ".py"

        cmd = string.Template(
            'python ${to_format} %s --stylesheet-path=${stylesheet} --language=en "${restfile}" "${outfile}"' % (opt)
        )

        out_file = OUTREP + "/" + self.fileName[:-4] + extension

        # raccourci pour la commande lanc�e
        text_cmd = cmd.substitute(
            to_format=format, stylesheet=Tstylesheet, restfile=self.filePath + "/" + self.fileName, outfile=out_file
        )

        if format == "to_lout.py":
            cmd = string.Template('python ${to_format} %s --language=fr "${restfile}" "${outfile}"' % (opt))
            text_cmd = cmd.substitute(to_format=format, restfile=self.filePath + "/" + self.fileName, outfile=out_file)
        # debbuging :
        print text_cmd

        # lance la commande syst�me
        try:
            os.popen2(text_cmd)
            self.statusBar().showMessage('Command :  "%s"' % (text_cmd))
        except:
            self.statusBar().showMessage("Command failed")

        # update de la statusbar
        self.statusBar().showMessage('Command :  "%s"' % (text_cmd))

        # Ouvre t-on le document le document dans
        # le navigateur par d�faut ?
        # self.askIfShowInDefaultBrowser(html_file)

    def showInWB(self):
        html_file_name = OUTREP + "/" + self.fileName[:-4] + ".html"
        if os.path.isfile(html_file_name):
            QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(html_file_name))
        else:
            self.Attention("You don't have converted your document to HTML yet.")
        return

    def Attention(self, mess):
        message = QtGui.QMessageBox(self)
        message.setText(mess)
        message.setWindowTitle("Attention")
        message.setIcon(QtGui.QMessageBox.Warning)
        message.addButton("Ok", QtGui.QMessageBox.AcceptRole)
        message.exec_()

    def askIfShowInDefaultBrowser(self, name):
        """ Demande � l'utilisateur s'il veut visualiser
            la sortie dans son navigateur par d�faut.
        """
        reply = QtGui.QMessageBox.question(
            self,
            "Message",
            "Do you want to view your document in your default browser ?",
            QtGui.QMessageBox.Yes,
            QtGui.QMessageBox.No,
        )

        if reply == QtGui.QMessageBox.Yes:
            QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(name))
        else:
            return

    def closeEvent(self, event):
        if self.isSaved or self.editor.toPlainText() == "":
            self.writeSettings()
            message = QtGui.QMessageBox(self)
            message.setText("Are you sure you want to quit reStInPeace ?")
            message.setWindowTitle("reSTinPeace")
            message.setIcon(QtGui.QMessageBox.Question)
            message.addButton("Yes", QtGui.QMessageBox.AcceptRole)
            message.addButton("No", QtGui.QMessageBox.RejectRole)
            message.exec_()
        else:
            self.Attention("Your document has not yet been saved, please save it before !")

    def needSave(self):
        self.isSaved = False
        self.actionSave.setEnabled(True)
        self.actionSaveAs.setEnabled(True)
        self.setWindowTitle(
            "reSTinPeace %s -- File :%s* -- Directory: %s " % (__version__, self.fileName, self.filePath)
        )

    def showPrefs(self):
        """ Preferences dialog
        """
        Dialog = QtGui.QDialog(self)
        ui = Ui_preferences()
        ui.setupUi(Dialog)
        Dialog.show()
        self.connect(ui.editorFontButton, QtCore.SIGNAL("clicked()"), self.chooseFont)

    def showAbout(self):
        """ Dialogue a propos
        """
        Dialog = QtGui.QDialog(self)
        ui = Ui_About()
        ui.setupUi(Dialog)
        Dialog.show()

    ## Application Settings
    def readSettings(self):
        # lire les settings
        settings = QtCore.QSettings("Kib", "reSTinPeace")
        pos = settings.value("pos", QtCore.QVariant(QtCore.QPoint(200, 200))).toPoint()
        size = settings.value("size", QtCore.QVariant(QtCore.QSize(600, 400))).toSize()
        # textSize = settings.value("pointSize", 12).toInt()

        # applique les settings
        self.resize(size)
        self.move(pos)

    def writeSettings(self):
        # ecrire les settings
        settings = QtCore.QSettings("Kib", "reSTinPeace")
        settings.setValue("pos", QtCore.QVariant(self.pos()))
        settings.setValue("size", QtCore.QVariant(self.size()))

    def afficheMessage(self, mess):
        self.statusBar().showMessage(mess)

    def createActions(self):
        # actions du menu et raccourcis clavier

        # Ouvrir un fichier
        self.actionOpen.setShortcut(self.tr("Ctrl+O"))
        QtCore.QObject.connect(self.actionOpen, QtCore.SIGNAL("triggered()"), self.openFile)

        # Nouveau fichier
        self.actionNew.setShortcut(self.tr("Ctrl+N"))
        QtCore.QObject.connect(self.actionNew, QtCore.SIGNAL("triggered()"), self.newFile)

        # Enregistrer fichier
        self.actionSaveAs.setShortcut(self.tr("Ctrl+Alt+S"))
        QtCore.QObject.connect(self.actionSaveAs, QtCore.SIGNAL("triggered()"), self.saveFileAs)

        # Enregistrer sous fichier
        self.actionSave.setShortcut(self.tr("Ctrl+S"))
        QtCore.QObject.connect(self.actionSave, QtCore.SIGNAL("triggered()"), self.saveFile)

        # Rafraichir le browser
        self.actionRefresh.setShortcut(self.tr("Ctrl+R"))
        QtCore.QObject.connect(self.actionRefresh, QtCore.SIGNAL("triggered()"), self.toBrowser)

        # Dialogue de pr�f�rences
        self.actionSettings.setShortcut(self.tr("Ctrl+Alt+P"))
        QtCore.QObject.connect(self.actionSettings, QtCore.SIGNAL("triggered()"), self.showPrefs)

        # Dialogue a propos
        QtCore.QObject.connect(self.actionAbout, QtCore.SIGNAL("triggered()"), self.showAbout)

        # Dialogue a propos
        QtCore.QObject.connect(self.actionHelp, QtCore.SIGNAL("triggered()"), self.showHelp)

        # Voir dans le navigateur par defaut
        self.actionSeeInDefaultBrowser.setShortcut(self.tr("Ctrl+Alt+V"))
        QtCore.QObject.connect(self.actionSeeInDefaultBrowser, QtCore.SIGNAL("triggered()"), self.showInWB)

        # Appelle le dialogue de conversion en HTML, LaTeX, etc.
        self.actionConversionDialog.setShortcut(self.tr("Ctrl+Alt+C"))
        QtCore.QObject.connect(self.actionConversionDialog, QtCore.SIGNAL("triggered()"), self.showConverterDialog)

        # Quitter l'application
        self.actionQuit.setShortcut(self.tr("Ctrl+Alt+Q"))
        QtCore.QObject.connect(self.actionQuit, QtCore.SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("quit()"))

    def chooseFont(self):
        font, ok = QtGui.QFontDialog.getFont(self.editor.font())
        if ok:
            self.editor.setFont(font)

    # Internationalisation taken from PyQt4 demo
    def findQmFiles(self):
        trans_dir = QtCore.QDir(APPLIREP + "/translations")
        fileNames = trans_dir.entryList(QtCore.QStringList("*.qm"), QtCore.QDir.Files, QtCore.QDir.Name)

        for i in fileNames:
            fileNames.replaceInStrings(i, trans_dir.filePath(i))

        return fileNames

    def languageName(self):
        files = self.findQmFiles()
        translator = QtCore.QTranslator()
        translator.load(files[0])

        QtGui.qApp.installTranslator(translator)
        translator.translate("MonAppli", "en_US")
        return

    def showHelp(self):
        """Shows a Help dialog that can be closed by 'Esc' key.
        """
        h = HelpForm(parent=self)
        h.show()

    def addEditorMethod(self, methodname):
        # self.editor.methodname = methodname
        setattr(self.editor, method.__name__, method)

    ## This part of code has been taken and adapted
    ## from Sanbox thanks to Mark Summerfield for the GPL 2.0 licence.

    def indentRegion(self):
        self._walkTheLines(True, " " * self.tab_long)

    def unindentRegion(self):
        self._walkTheLines(False, " " * self.tab_long)

    def _walkTheLines(self, insert, text):
        userCursor = self.editor.textCursor()
        userCursor.beginEditBlock()
        start = userCursor.position()
        end = userCursor.anchor()
        if start > end:
            start, end = end, start
        block = self.editor.document().findBlock(start)
        while block.isValid():
            cursor = QtGui.QTextCursor(block)
            cursor.movePosition(QtGui.QTextCursor.StartOfBlock)
            if insert:
                cursor.insertText(text)
            else:
                cursor.movePosition(QtGui.QTextCursor.NextCharacter, QtGui.QTextCursor.KeepAnchor, len(text))
                if cursor.selectedText() == text:
                    cursor.removeSelectedText()
            block = block.next()
            if block.position() > end:
                break
        userCursor.endEditBlock()

    def tableCreate(self):
        """ This function creates a QTableWidgetItem out of a 2-dimension nested list which contains numbers, and then uses it to "paint" the someTbl object, which is a QTableWidget """
        dial = QtGui.QDialog(self)
        dial.setWindowTitle("Table creator")
        self.tabledialog = dial
        self.tbl_dial = Ui_ArrayDialog()
        self.tbl_dial.setupUi(dial)

        # ArrayDialog.show()
        tbl = self.tbl_dial.tableWidget
        col = self.tbl_dial.spinBoxColumns
        lin = self.tbl_dial.spinBoxRows
        but = self.tbl_dial.okButton

        # Connexions
        self.connect(col, QtCore.SIGNAL("valueChanged(int)"), self.actualiseTable)
        self.connect(lin, QtCore.SIGNAL("valueChanged(int)"), self.actualiseTable)
        # dial.connect(but, QtCore.SIGNAL("cliked()"), self.insertRestTable)
        QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), self.insertRestTable)
        tbl.setColumnCount(col.value())
        tbl.setRowCount(lin.value())

        dial.show()

    def actualiseTable(self, int_number):
        tbl = self.tbl_dial.tableWidget
        col = self.tbl_dial.spinBoxColumns
        lin = self.tbl_dial.spinBoxRows

        tbl.setColumnCount(col.value())
        tbl.setRowCount(lin.value())

    def insertRestTable(self):
        lines = self.tbl_dial.tableWidget.rowCount()
        cols = self.tbl_dial.tableWidget.columnCount()
        mylist = []
        for col in range(cols):
            poorlist = []
            for line in range(lines):
                try:
                    text = self.tbl_dial.tableWidget.item(line, col).text()
                except:
                    text = ""
                truc = unicode(text)
                poorlist.append(truc)
            mylist.append(poorlist)
        self.traiteListe(mylist)
        self.tabledialog.close()

    def traiteListe(self, laliste):
        # see new changes in Python 2.5 max function
        # http://www.onlamp.com/pub/a/python/2006/10/26/python-25.html?page=3
        output = []

        def myord(astr):
            return len(astr)

        nbr_lines = len(laliste[0])
        for lin in range(nbr_lines):
            textcell, deco = [], []

            for col in laliste:
                largeur = len(max(col, key=myord))
                spaces = largeur - len(col[lin])
                if lin == 1:
                    deco.append("+" + (largeur + 2) * "=")
                else:
                    deco.append("+" + (largeur + 2) * "-")
                textcell.append("| " + col[lin] + (spaces + 1) * " ")
            deco.append("+")
            textcell.append("|")
            # print "".join(deco)
            # print "".join(koala)
            output.append("".join(deco))
            output.append("".join(textcell))
        output.append(output[0])

        c = self.editor.textCursor()
        c.insertText("\n".join(output))
        self.toBrowser()
コード例 #4
0
ファイル: reStInPeace.py プロジェクト: ver007/reStInPeace
class MonAppli(QtGui.QMainWindow, Ui_MainWindow):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)

        # Configure the user interface.
        self.setupUi(self)

        # Snippets special Variables
            # snippet
        self.insideSnippet = False
        self.start_snip = 0
            # Field courant
        self.snippets = []
        self.field = None
        self.field_start = 0
        self.field_long = 0
        self.oldsnip = None

        # Editor
            # Editor tabs = 4 chars
        self.tab_long = 4
        self.setTabEditorWidth(self.tab_long)
            # Coloration syntaxique
        self.highlighter = highlighter.Highlighter(self.editor)
        self.highlighter.modeRest()

        # Browser (viewer)
            # Set permissions to open external links
            # by clicking on them
        self.viewer.openExternalLinks = True
        self.viewer.setOpenExternalLinks(True)

            # Big Hack not to have to create a particluar
            # classe for the browser.
            # TODO : clean derivation
        self.viewer.loadResource = imageBrowser().loadResource

        ## Special attributes :
            # name of the current edited file
        self.fileName = "Noname.rst"
            # absolute path
        self.filePath = INREP
            # boolean to know if file has been saved or not
        self.isSaved = False
            # default directory
        self.default_dir = INREP # or APPLIREP (up to you)

        ## Conversion Dialog
        self.ConvDialog = QtGui.QDialog(self)
        ui = Ui_Converter()
        ui.setupUi(self.ConvDialog)
        self.converterdial = ui

        ## SIGNALS/SLOTS
            # we need to know if source as changed
        self.connect(self.editor, QtCore.SIGNAL("textChanged()"), self.needSave)

        ## ScrollBars editor-viewer
            # scrollbar editor
        self.esb = self.editor.verticalScrollBar()
            # scrollbar viewer
        self.vsb = self.viewer.verticalScrollBar()
            # connexions scrollbar editor --> synchronise view in browser
        self.connect(self.esb, QtCore.SIGNAL("valueChanged(int) "), self.actualiseBSlider)
            # connexions scrollbar viewer --> synchronise view in editor 
        self.connect(self.vsb, QtCore.SIGNAL("valueChanged(int) "), self.actualiseESlider)

        ## zoom event for editor and viewer
        import types
        self.editor.wheelEvent = types.MethodType(zoomEditor, self.editor, self.editor.__class__)
        self.viewer.wheelEvent = types.MethodType(zoomViewer, self.viewer, self.viewer.__class__)

        ## MENU ACTIONS
        self.createActions()

        ## BUTTONS
        self.actionSave.setEnabled(self.isSaved)

        ## APPLY SAVED APP SETTINGS
        self.readSettings()

        ## KEYBOARD SHORTCUTS
        keyTab = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Tab")), self)
        self.connect(keyTab, QtCore.SIGNAL("activated()"), self.whatToDoOnTab)

        QtGui.QShortcut(QtGui.QKeySequence("F1"), self, self.showHelp)
        QtGui.QShortcut(QtGui.QKeySequence("F2"), self, self.indentRegion)
        QtGui.QShortcut(QtGui.QKeySequence("F3"), self, self.unindentRegion)
        QtGui.QShortcut(QtGui.QKeySequence("F4"), self, self.chooseFont)
        QtGui.QShortcut(QtGui.QKeySequence("F5"), self, self.tableCreate)
        QtGui.QShortcut(QtGui.QKeySequence("F6"), self, self.columnMode)


        self.connect(self.editor, QtCore.SIGNAL("textChanged()"), self.updateChilds)

        ## STATUSBAR
        self.statusBar().showMessage("Welcome to reStInPeace, press F1 for Help.")

    ## ------------------------------------------
    ##                  Snippets
    ## 
    ## Methods used by the editor :
    ## 
    ## - insertSnippet
    ## - whatToDoOnTab
    ## - nextField
    ## - endSnip
    ## - updateChilds
    ## ------------------------------------------
    def columnMode(self):
        deb = self.editor.textCursor()
        selection = deb.selectedText()
        lines = unicode(selection).split()
        print lines

        for i in lines :
            c = self.editor.textCursor()
            # on se positionne au debut
            c.movePosition(QtGui.QTextCursor.Down)
            c.insertText(i)
            c.movePosition(QtGui.QTextCursor.Left, len(i))
            self.editor.setTextCursor(c)

        # on repositionne alors le curseur
        self.editor.setTextCursor(deb)
    def insertSnippet(self):
        """ Called from whatToDoOnTab's method
        
        Takes the word before the cursor thanks to wordLeftExtend's
        method and tries to find the word in the snippet dictionary
        DICSNIP.
        
        If so, the snippet is added to the stack and expanded, returning True.
        """
        # r�cup�re le curseur et sa position
        tc = self.editor.textCursor()
        p = tc.position()

        # recup�re le mot le plus � gauche de celui-ci
        word = self.wordLeftExtend(tc)

        # position de depart du snippet
        # [Si on tape en (0,0) le mot 'link', le curseur
        # est alors en pos (4,0). Il faut alors corriger
        # ceci en enlevant la longeur du raccourci tap�.]


        # On essaye de r�cup�rer dans le dico des snippets
        # celui qui correspond au raccourci tap�.
        try:
            # le mot est dans le dico
            tpl = DICSNIP[word][1]
            helptpl = DICSNIP[word][0]
            self.snippet = Snippet(unicode(tpl))
            self.snippet.help = helptpl
            self.snippet.start = p - len(word)
            ##
            self.snippets.append(self.snippet)

            self.snippet.fielditer = self.snippet.fieldIter()
            rendu = self.snippet.expanded()
            self.snippet.long = len(rendu)

            #tc.beginEditBlock()
            self.editor.blockSignals(True)
            tc.insertText(rendu)
            self.editor.blockSignals(False)
            #tc.endEditBlock()

            return True
        except :
            # word is not in DICSNIP
            self.removeSelection()
            return False

    def whatToDoOnTab(self):
        """ Slot called when 'Tab' is pressed.

           - Tries to expand the word before the cursor;
           
           - if return value is True in insertSnippet's method:
                - the snipped has been added to the stack and is expanded,
                  we then go to the next snippet's field, if any.
             
           - if return value is False in insertSnippet's method:
                - if there are already snippets in stack, pass to the next one.
                - if there are no snippet in stack : stop and insert a tab char.
        """
        expanded = self.insertSnippet() # boolean

        if expanded : # if a snippet has been entered previously
            self.nextField()
        else : # the word entered wasn't a shortcut
            if len(self.snippets) > 0:
                self.nextField()
            else:
                self.statusBar().showMessage('insert spaces as no more snippet in stack %s' % (self.snippets))
                self.editor.textCursor().insertText(" "*self.tab_long)

    def nextField(self):

        try: # to go to next field
            self.field = self.snippet.fielditer.next()
            self.snippet.current_field = self.field

            self.field.start = self.snippet.getFieldPos(self.field)
            self.field.long = self.field.getLengh()
            self.statusBar().showMessage('Field=%s--Snippet=%s--Start=%s--Long=%s' % (self.field.code, self.snippet, self.field.start, self.field.long))
            self.selectFromTo(self.snippet.start + self.field.start, self.field.long)

            if self.field.isEnd:
                self.endSnip()
        except :
            self.statusBar().showMessage('ds nextField %s %s' % (self.snippet, self.snippet.current_field))


    def endSnip(self):
        self.removeSelection()
        if len(self.snippets) < 1:
            self.snippets = []
            return

        oldval = self.snippet.expanded()
        self.snippets.pop() # the old snippet
        self.snippet = self.snippets[-1] # new snippet= last entry
        self.field = self.snippet.current_field
        self.updateChilds(given=oldval)
        self.whatToDoOnTab()

    def updateChilds(self, given=None):
        """ Slot called when textarea is modified.
        """
        if len(self.snippets) > 0:
            ## curseur
            c = self.editor.textCursor()
            cursor_pos = c.position()

            ## variables utiles
            # pos de depart du snippet
            debut_snip = self.snippet.start
            old_long = self.snippet.long
            # le champ
            f = self.snippet.current_field

            # le nbr d'esclaves
            nslaves = len(f.slaves)
            # la valeur de l'ancien champ (si existence)
            old_field_val = f.content
            # l'ancien champ
            self.oldfield = f

            ## Capture le texte du champ actuel
            # l'affiche dans la statusbar
            newpos = c.selectionStart()
            #c.setPosition(debutsnip+st, QtGui.QTextCursor.MoveAnchor)
            c.setPosition(self.field.start + self.snippet.start, QtGui.QTextCursor.MoveAnchor)
            c.setPosition(cursor_pos, QtGui.QTextCursor.KeepAnchor)
            if not given :
                self.exp = c.selectedText()
            else:
                self.exp = given
            self.statusBar().showMessage("Field %s replaced by '%s'" % (f.code, unicode(self.exp)))

            ## Selectionne et remplace le snippet

            # update du champ avec la valeur calculee
            f.content = unicode(self.exp)

            # nouveau contenu du snippet
            cont = self.snippet.expanded()

            # self.snip_long est l'ancienne longueur
            offset = len(f.content) - len(old_field_val)
            self.selectFromTo(self.snippet.start, self.snippet.long + offset)
            #time.sleep(1)

            # on update la longueur du snippet
            self.snippet.long = len(cont)

            # On doit faire attention a bloquer
            # l'emission du signal
            self.editor.blockSignals(True)
            self.editor.textCursor().insertText(cont)
            self.editor.blockSignals(False)

            # Should I prefer this one-liner ?
            #self.selectFromTo(self.start_snip+f.start+len(self.exp), 0)

            c = self.editor.textCursor()
            c.setPosition(self.field.start + self.snippet.start + len(self.exp))
            self.editor.setTextCursor(c)

    ## ------------------------------------------
    ## Editor's functions
    ## ------------------------------------------
    # Find the word before the cursor and select it
    def wordLeftExtend(self, my_cursor):
        """ Recup�re le mot le plus � gauche
            d'un curseur donn� et le s�lectionne.
        """
        oldpos = my_cursor.position()

        # manips curseur
        my_cursor.select(QtGui.QTextCursor.WordUnderCursor)
        #self.editor.setTextCursor(my_cursor)

        newpos = my_cursor.selectionStart()

        my_cursor.setPosition(newpos, QtGui.QTextCursor.MoveAnchor)
        my_cursor.setPosition(oldpos, QtGui.QTextCursor.KeepAnchor)
        self.editor.setTextCursor(my_cursor)
        return str(my_cursor.selectedText())

    def showCursorPos(self):
        tc = self.editor.textCursor()
        self.statusBar().showMessage("Position: %s" % (tc.position()))

    # selectionne le texte de pos � pos + nbr_car
    def selectFromTo(self, pos, nbr_car) :
        """ Selectionne la partie de texte comprise
            entre pos et pos + nbr_car
        """
        #print "Je dois Selectionner de ", pos," a ",lon
        c = self.editor.textCursor()
        # on se positionne au debut
        c.setPosition(pos)
        # on va vers la droite de nbr_car caract�res
        c.movePosition(QtGui.QTextCursor.Right, QtGui.QTextCursor.KeepAnchor, nbr_car)
        # on repositionne alors le curseur
        self.editor.setTextCursor(c)

    # enleve toute selection
    def removeSelection(self):
        """ Enleve la selection et deplace le
            curseur � la fin de celle-ci.
        """
        p = self.editor.textCursor().position()
        self.selectFromTo(p, 0)

    ## ------------------------------------------
    ## Nombre de caract�res maximum sur une ligne
    ## ------------------------------------------
    def setTabEditorWidth(self, tw):
        e = self.editor
        e.setTabStopWidth(e.fontMetrics().width("x") * tw)

    ## Sliders verticaux
    def actualiseBSlider(self, val_ed):
        # Essaye d'actualiser le scrolling du Browser
        # de fa�on proportionnelle � celui de l'
        # �diteur.
        #
        # val est la valeur du slider de l'editeur
        val_view = self.vsb.sliderPosition()

        max_ed = self.esb.maximum()
        max_view = self.vsb.maximum()

        prop_ed = float(val_ed) / float(max_ed)
        prop_view = float(val_view) / float(max_view)

        if not (prop_ed - 0.01 <= prop_view <= prop_ed + 0.01):
            self.vsb.setSliderPosition(prop_ed * max_view)

    def actualiseESlider(self, val_view):
        val_ed = self.esb.sliderPosition()

        max_ed = self.esb.maximum()
        max_view = self.vsb.maximum()

        prop_ed = float(val_ed) / float(max_ed)
        prop_view = float(val_view) / float(max_view)

        if not (prop_view - 0.01 <= prop_ed <= prop_view + 0.01):
            self.esb.setSliderPosition(prop_view * max_ed)

    def newFile(self, path=""):
        """ Create a new reSTructuredText file UTF-8 encoded
        """
        if self.isSaved :
            self.editor.clear()
            self.fileName = "Noname.rst"
            self.filePath = INREP
            self.isSaved = False
            self.toBrowser()
            self.actionSave.setEnabled(self.isSaved)
            self.actionSaveAs.setEnabled(self.isSaved)
        else:
            self.Attention("Your document has not yet been saved, please save it before !")
            #self.saveFile()

    def openFile(self, path=""):
        """ Open a reSTructuredText file UTF-8 encoded
        """

        fileName = QtCore.QString(path)

        if fileName.isEmpty():
            fileName = QtGui.QFileDialog.getOpenFileName(self, self.tr("Open the file"), self.default_dir, "reST Files (*.rst *.txt )")
        codec = QtCore.QTextCodec.codecForName("UTF-8")
        if not fileName.isEmpty():
            # le nom du fichier brut
            self.fileName = str(QtCore.QFileInfo(fileName).fileName())
            self.filePath = str(QtCore.QFileInfo(fileName).path())
            self.editor.clear()
            # update de la statusbar
            self.statusBar().showMessage('File %s has been loaded correctly.' % (self.fileName))

            inFile = QtCore.QFile(fileName)
            #print inFile.fileName()
            if inFile.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text):
                data = QtCore.QTextStream(inFile)
                data.setAutoDetectUnicode(True)
                data.setCodec(codec)
                self.decodedStr = data.readAll()
                self.editor.setPlainText(self.decodedStr)
        self.isSaved = True
        self.toBrowser()
        self.actionSave.setEnabled(self.isSaved)
        self.actionSaveAs.setEnabled(self.isSaved)

    def saveFileAs(self):
        """ Save actual file in default dir
        """

        fileName = QtGui.QFileDialog.getSaveFileName(self, self.tr("Save the file as..."), self.filePath, "reST Files (*.rst *.txt )")
        if not fileName.isEmpty():
            outFile = QtCore.QFile(fileName)
            if not outFile.open(QtCore.QFile.WriteOnly):
                print "A problem has occured with your file..."
                return
            out = QtCore.QTextStream(outFile)
            out.setCodec("UTF-8")
            out << self.editor.toPlainText()
            # update de self.filename :
            self.fileName = QtCore.QFileInfo(outFile).fileName()
            # update de la statusbar
            self.statusBar().showMessage('File %s has been saved correctly.' % (self.fileName))

            # flag de sauvegarde
            self.isSaved = True
            self.actionSave.setEnabled(self.isSaved)

    # Why reinvent the wheel ? It has been taken and adapted from M.Summerfield's demo
    def saveFile(self):
        fp = self.filePath + '/'
        if self.fileName == "Noname.rst":
            self.saveFileAs()
            return
        if QtCore.QFile.exists(self.fileName):
            backup = self.fileName + '.rst_old'
            ok = True
            if QtCore.QFile.exists(fp + backup):
                ok = QtCore.QFile.remove(fp + backup)
                if not ok:
                    QtGui.QMessageBox.information(self, "reSTinPeace - Save Warning",
                            "Failed to remove the old backup %s")
            if ok:
                # Must use copy rather than rename to preserve file
                # permissions; could use rename on Windows though
                if not QtCore.QFile.copy(fp + self.fileName, fp + backup):
                    QtGui.QMessageBox.information(self, "reSTinPeace - Save Warning",
                            "Failed to save a backup %s")

        try:
            try:
                fh = QtCore.QFile(fp + self.fileName)
                if not fh.open(QtCore.QIODevice.WriteOnly):
                    raise IOError, unicode(fh.errorString())
                stream = QtCore.QTextStream(fh)
                stream.setCodec("UTF-8")
                stream << self.editor.toPlainText()
                self.editor.document().setModified(False)
                self.setWindowModified(False)
                self.setWindowTitle("reSTinPeace - %s[*]" % \
                        QtCore.QFileInfo(fp + self.fileName).fileName())
                self.statusBar().showMessage("Saved %s" % self.fileName,
                        5000)
                self.isSaved = True
            except (IOError, OSError), e:
                QtGui.QMessageBox.warning(self, "reSTinPeace - Save Error",
                        "Failed to save %s: %s" % (fp + self.fileName, e))
        finally:
            if fh is not None:
                fh.close()
        return True

    def toBrowser(self):
        """ Transforme le texte de l'editeur en HTML
            pour le voir dans la partie browser.
        """
        self.viewer.document().setDefaultStyleSheet(open(os.getcwd() + "/browser.css", "r").read())
        sortie = core.publish_string(unicode(self.editor.document().toPlainText()).encode("utf-8"),
                writer_name='html',
                settings_overrides={'input_encoding': 'utf-8',
                                    'output_encoding': 'latin-1',
                                    'language': 'en',
                                    },
                            )
        self.viewer.setSearchPaths([os.path.expanduser(self.filePath)])
        self.viewer.setHtml(sortie)

    def showConverterDialog(self):
        """ Affiche le dialogue de conversion
        """
        self.ConvDialog.show()
        self.connect(self.converterdial.but_process, QtCore.SIGNAL("clicked()"), self.processOutput)

    def processOutput(self):
        """ Transforme l'entree au format demand�
        """

        dic_formats = {'(X)HTML': ('to_html', 'css'),
                        'LaTeX' : ('to_tex', 'sty'),
                        'OpenOffice' : ('to_odt', 'odt'),
                        'Lout' : ('to_lout', 'lout'),
                        }
        dial = self.converterdial
        format = dic_formats[str(dial.combo_out.currentText())][0]

        opt = ''
        if format == 'to_odt' :
            opt = ' --add-syntax-highlighting '

        Tstylesheet = OUTREP + "/default." + dic_formats[str(dial.combo_out.currentText())][1]
        extension = "." + format[3:]
        format += ".py"

        cmd = string.Template('python ${to_format} %s --stylesheet-path=${stylesheet} --language=en "${restfile}" "${outfile}"' % (opt))


        out_file = OUTREP + "/" + self.fileName[:-4] + extension

        # raccourci pour la commande lanc�e
        text_cmd = cmd.substitute(to_format=format,
                                  stylesheet=Tstylesheet,
                                  restfile=self.filePath + "/" + self.fileName,
                                  outfile=out_file)

        if format == 'to_lout.py' :
            cmd = string.Template('python ${to_format} %s --language=fr "${restfile}" "${outfile}"' % (opt))
            text_cmd = cmd.substitute(to_format=format,
                                  restfile=self.filePath + "/" + self.fileName,
                                  outfile=out_file)
        # debbuging :
        print text_cmd

        # lance la commande syst�me
        try:
            os.popen2(text_cmd)
            self.statusBar().showMessage('Command :  "%s"' % (text_cmd))
        except:
            self.statusBar().showMessage('Command failed')

        # update de la statusbar
        self.statusBar().showMessage('Command :  "%s"' % (text_cmd))

        # Ouvre t-on le document le document dans
        # le navigateur par d�faut ?
        # self.askIfShowInDefaultBrowser(html_file)

    def showInWB(self):
        html_file_name = OUTREP + "/" + self.fileName[:-4] + '.html'
        if os.path.isfile(html_file_name) :
            QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(html_file_name))
        else :
            self.Attention("You don't have converted your document to HTML yet.")
        return

    def Attention(self, mess):
        message = QtGui.QMessageBox(self)
        message.setText(mess)
        message.setWindowTitle('Attention')
        message.setIcon(QtGui.QMessageBox.Warning)
        message.addButton('Ok', QtGui.QMessageBox.AcceptRole)
        message.exec_()

    def askIfShowInDefaultBrowser(self, name):
        """ Demande � l'utilisateur s'il veut visualiser
            la sortie dans son navigateur par d�faut.
        """
        reply = QtGui.QMessageBox.question(self, 'Message',
            "Do you want to view your document in your default browser ?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes:
            QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(name))
        else:
            return

    def closeEvent(self, event):
        if self.isSaved or self.editor.toPlainText() == "":
            self.writeSettings()
            message = QtGui.QMessageBox(self)
            message.setText('Are you sure you want to quit reStInPeace ?')
            message.setWindowTitle('reSTinPeace')
            message.setIcon(QtGui.QMessageBox.Question)
            message.addButton('Yes', QtGui.QMessageBox.AcceptRole)
            message.addButton('No', QtGui.QMessageBox.RejectRole)
            message.exec_()
        else:
            self.Attention("Your document has not yet been saved, please save it before !")

    def needSave(self):
        self.isSaved = False
        self.actionSave.setEnabled(True)
        self.actionSaveAs.setEnabled(True)
        self.setWindowTitle("reSTinPeace %s -- File :%s* -- Directory: %s " \
                            % (__version__,
                            self.fileName,
                            self.filePath,
                            ))

    def showPrefs(self):
        """ Preferences dialog
        """
        Dialog = QtGui.QDialog(self)
        ui = Ui_preferences()
        ui.setupUi(Dialog)
        Dialog.show()
        self.connect(ui.editorFontButton, QtCore.SIGNAL('clicked()'), self.chooseFont)

    def showAbout(self):
        """ Dialogue a propos
        """
        Dialog = QtGui.QDialog(self)
        ui = Ui_About()
        ui.setupUi(Dialog)
        Dialog.show()

    ## Application Settings
    def readSettings(self):
        # lire les settings
        settings = QtCore.QSettings("Kib", "reSTinPeace")
        pos = settings.value("pos", QtCore.QVariant(QtCore.QPoint(200, 200))).toPoint()
        size = settings.value("size", QtCore.QVariant(QtCore.QSize(600, 400))).toSize()
        #textSize = settings.value("pointSize", 12).toInt()

        # applique les settings
        self.resize(size)
        self.move(pos)

    def writeSettings(self):
        # ecrire les settings
        settings = QtCore.QSettings("Kib", "reSTinPeace")
        settings.setValue("pos", QtCore.QVariant(self.pos()))
        settings.setValue("size", QtCore.QVariant(self.size()))

    def afficheMessage(self, mess):
        self.statusBar().showMessage(mess)

    def createActions(self):
        # actions du menu et raccourcis clavier

        # Ouvrir un fichier
        self.actionOpen.setShortcut(self.tr("Ctrl+O"))
        QtCore.QObject.connect(self.actionOpen,
            QtCore.SIGNAL("triggered()"),
            self.openFile)

        # Nouveau fichier
        self.actionNew.setShortcut(self.tr("Ctrl+N"))
        QtCore.QObject.connect(self.actionNew,
            QtCore.SIGNAL("triggered()"),
            self.newFile)

        # Enregistrer fichier
        self.actionSaveAs.setShortcut(self.tr("Ctrl+Alt+S"))
        QtCore.QObject.connect(self.actionSaveAs,
            QtCore.SIGNAL("triggered()"),
            self.saveFileAs)

        # Enregistrer sous fichier
        self.actionSave.setShortcut(self.tr("Ctrl+S"))
        QtCore.QObject.connect(self.actionSave,
            QtCore.SIGNAL("triggered()"),
            self.saveFile)

        # Rafraichir le browser
        self.actionRefresh.setShortcut(self.tr("Ctrl+R"))
        QtCore.QObject.connect(self.actionRefresh,
            QtCore.SIGNAL("triggered()"),
            self.toBrowser)

        # Dialogue de pr�f�rences
        self.actionSettings.setShortcut(self.tr("Ctrl+Alt+P"))
        QtCore.QObject.connect(self.actionSettings,
            QtCore.SIGNAL("triggered()"),
            self.showPrefs)

        # Dialogue a propos
        QtCore.QObject.connect(self.actionAbout,
            QtCore.SIGNAL("triggered()"),
            self.showAbout)

        # Dialogue a propos
        QtCore.QObject.connect(self.actionHelp,
            QtCore.SIGNAL("triggered()"),
            self.showHelp)

        # Voir dans le navigateur par defaut
        self.actionSeeInDefaultBrowser.setShortcut(self.tr("Ctrl+Alt+V"))
        QtCore.QObject.connect(self.actionSeeInDefaultBrowser,
            QtCore.SIGNAL("triggered()"),
            self.showInWB)

        # Appelle le dialogue de conversion en HTML, LaTeX, etc.
        self.actionConversionDialog.setShortcut(self.tr("Ctrl+Alt+C"))
        QtCore.QObject.connect(self.actionConversionDialog,
            QtCore.SIGNAL("triggered()"),
            self.showConverterDialog)

        # Quitter l'application
        self.actionQuit.setShortcut(self.tr("Ctrl+Alt+Q"))
        QtCore.QObject.connect(self.actionQuit,
            QtCore.SIGNAL("triggered()"),
            QtGui.qApp, QtCore.SLOT('quit()'))

    def chooseFont(self):
        font, ok = QtGui.QFontDialog.getFont(self.editor.font())
        if ok:
            self.editor.setFont(font)


    # Internationalisation taken from PyQt4 demo
    def findQmFiles(self):
        trans_dir = QtCore.QDir(APPLIREP + "/translations")
        fileNames = trans_dir.entryList(QtCore.QStringList("*.qm"), QtCore.QDir.Files, QtCore.QDir.Name)

        for i in fileNames:
            fileNames.replaceInStrings(i, trans_dir.filePath(i))

        return fileNames

    def languageName(self):
        files = self.findQmFiles()
        translator = QtCore.QTranslator()
        translator.load(files[0])

        QtGui.qApp.installTranslator(translator)
        translator.translate("MonAppli", "en_US")
        return

    def showHelp(self):
        """Shows a Help dialog that can be closed by 'Esc' key.
        """
        h = HelpForm(parent=self)
        h.show()


    def addEditorMethod(self, methodname):
        #self.editor.methodname = methodname
        setattr(self.editor, method.__name__, method)

    ## This part of code has been taken and adapted 
    ## from Sanbox thanks to Mark Summerfield for the GPL 2.0 licence.

    def indentRegion(self):
        self._walkTheLines(True, " " * self.tab_long)

    def unindentRegion(self):
        self._walkTheLines(False, " " * self.tab_long)

    def _walkTheLines(self, insert, text):
        userCursor = self.editor.textCursor()
        userCursor.beginEditBlock()
        start = userCursor.position()
        end = userCursor.anchor()
        if start > end:
            start, end = end, start
        block = self.editor.document().findBlock(start)
        while block.isValid():
            cursor = QtGui.QTextCursor(block)
            cursor.movePosition(QtGui.QTextCursor.StartOfBlock)
            if insert:
                cursor.insertText(text)
            else:
                cursor.movePosition(QtGui.QTextCursor.NextCharacter,
                        QtGui.QTextCursor.KeepAnchor, len(text))
                if cursor.selectedText() == text:
                    cursor.removeSelectedText()
            block = block.next()
            if block.position() > end:
                break
        userCursor.endEditBlock()


    def tableCreate(self):
        """ This function creates a QTableWidgetItem out of a 2-dimension nested list which contains numbers, and then uses it to "paint" the someTbl object, which is a QTableWidget """
        dial = QtGui.QDialog(self)
        dial.setWindowTitle("Table creator")
        self.tabledialog = dial
        self.tbl_dial = Ui_ArrayDialog()
        self.tbl_dial.setupUi(dial)


        #ArrayDialog.show()
        tbl = self.tbl_dial.tableWidget
        col = self.tbl_dial.spinBoxColumns
        lin = self.tbl_dial.spinBoxRows
        but = self.tbl_dial.okButton

        # Connexions
        self.connect(col, QtCore.SIGNAL("valueChanged(int)"), self.actualiseTable)
        self.connect(lin, QtCore.SIGNAL("valueChanged(int)"), self.actualiseTable)
        #dial.connect(but, QtCore.SIGNAL("cliked()"), self.insertRestTable)
        QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), self.insertRestTable)
        tbl.setColumnCount(col.value())
        tbl.setRowCount(lin.value())

        dial.show()

    def actualiseTable(self, int_number):
        tbl = self.tbl_dial.tableWidget
        col = self.tbl_dial.spinBoxColumns
        lin = self.tbl_dial.spinBoxRows

        tbl.setColumnCount(col.value())
        tbl.setRowCount(lin.value())

    def insertRestTable(self):
        lines = self.tbl_dial.tableWidget.rowCount()
        cols = self.tbl_dial.tableWidget.columnCount()
        mylist = []
        for col in range(cols) :
            poorlist = []
            for line in range(lines) :
                try :
                    text = self.tbl_dial.tableWidget.item(line, col).text()
                except:
                    text = ''
                truc = unicode(text)
                poorlist.append(truc)
            mylist.append(poorlist)
        self.traiteListe(mylist)
        self.tabledialog.close()

    def traiteListe(self, laliste):
        # see new changes in Python 2.5 max function
        # http://www.onlamp.com/pub/a/python/2006/10/26/python-25.html?page=3
        output = []

        def myord(astr):
            return len(astr)

        nbr_lines = len(laliste[0])
        for lin in range(nbr_lines):
            textcell, deco = [], []

            for col in laliste:
                largeur = len(max(col, key=myord))
                spaces = largeur - len(col[lin])
                if lin == 1:
                    deco.append('+' + (largeur + 2) * '=')
                else:
                    deco.append('+' + (largeur + 2) * '-')
                textcell.append("| " + col[lin] + (spaces + 1) * " ")
            deco.append("+")
            textcell.append("|")
            #print "".join(deco)
            #print "".join(koala)
            output.append("".join(deco))
            output.append("".join(textcell))
        output.append(output[0])

        c = self.editor.textCursor()
        c.insertText("\n".join(output))
        self.toBrowser()