Пример #1
0
 def slotButtonShowDiff(self):
     """Called when the user clicks Show Difference."""
     docs = self.selectedDocuments() or self.allDocuments()
     if not docs:
         return
     d = docs[0]
     if documentwatcher.DocumentWatcher.instance(d).isdeleted():
         return
     
     filename = d.url().toLocalFile()
     try:
         with open(filename, 'rb') as f:
             disktext = util.decode(f.read())
     except (IOError, OSError):
         return
     
     currenttext = d.toPlainText()
     
     html = htmldiff.htmldiff(
         currenttext, disktext, 
         _("Current Document"), _("Document on Disk"), numlines=5)
     dlg = widgets.dialog.Dialog(self, buttons=('close',))
     view = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
     view.setHtml(html)
     dlg.setMainWidget(view)
     dlg.setWindowTitle(app.caption("Differences"))
     dlg.setMessage(_(
         "Document: {url}\n"
         "Difference between the current document and the file on disk:").format(
             url=filename))
     dlg.setWindowModality(Qt.NonModal)
     dlg.setAttribute(Qt.WA_QuitOnClose, False)
     dlg.setAttribute(Qt.WA_DeleteOnClose)
     qutil.saveDialogSize(dlg, "externalchanges/diff/dialog/size", QSize(600, 300))
     dlg.show()
Пример #2
0
 def __createVersioning( self ):
     " Creates the versioning section "
     components = getComponentInfo()
     text = "<p>The major Codimension components are listed below:</p>" \
            "<ul>"
     for (prettyName, version, homeURL,
          patched, license, licenseLink) in components:
         text += "<li><a href='" + homeURL + "'>" + prettyName + "</a><br>" \
                 "Version: "
         if version is not None and version[ 0 ].isdigit():
             text += version
         elif version is not None and version.lower() == "not installed":
             text += version.lower()
         elif version is None:
             text += "n/a"
         else:
             text += str( version )
         if patched:
             text += " (patched for codimension)"
         text += "<br>"
         text += "License: "
         if licenseLink.startswith( "http" ):
             text += "<a href='" + licenseLink + "'>" + license + "</a>"
         else:
             text += license + " (" + licenseLink + ")"
         text += "<br></li>"
     text += "</ul>"
     browser = QTextBrowser()
     browser.setHtml( text )
     browser.setOpenExternalLinks( True )
     return browser
Пример #3
0
 def __createVersioning(self):
     " Creates the versioning section "
     components = getComponentInfo()
     text = "<p>The major Codimension components are listed below:</p>" \
            "<ul>"
     for (prettyName, version, homeURL, patched, license, licenseLink,
          localPath) in components:
         text += "<li><a href='" + homeURL + "'>" + prettyName + "</a><br>" \
                 "Version: "
         if version is not None and version[0].isdigit():
             text += version
         elif version is not None and version.lower() == "not installed":
             text += version.lower()
         elif version is None:
             text += "n/a"
         else:
             text += str(version)
         if patched:
             text += " (patched for codimension)"
         text += "<br>"
         text += "License: "
         if licenseLink.startswith("http"):
             text += "<a href='" + licenseLink + "'>" + license + "</a>"
         else:
             text += license + " (" + licenseLink + ")"
         if localPath:
             text += "<br/>Local path: " + localPath
         text += "<br></li>"
     text += "</ul>"
     browser = QTextBrowser()
     browser.setHtml(text)
     browser.setOpenExternalLinks(True)
     return browser
Пример #4
0
    def __createDescription( self ):
        " Creates the description browser "
        browser = QTextBrowser()
        browser.setHtml( """
<p align="justify">
Codimension is a free experimental Python IDE.
</p>
<p align="justify">
Codimension aims to provide an integrated system for:
<ul>
<li>traditional text-based code editing, and</li>
<li>diagram-based code analysis (e.g. imports and classes diagrams,
    profiling results etc).</li>
</ul>
</p>

<p align="justify">
Many Python developers will find codimension useful as-is, even though not all
of its features have been implemented yet.
</p>
<p align="justify">
More information could be found on <a href='http://satsky.spb.ru/codimension/'>
Codimension home page</a>.<br> Happy coding with Codimension!
</p>
""" )
        browser.setOpenExternalLinks( True )
        return browser
Пример #5
0
    def __createDescription(self):
        " Creates the description browser "
        browser = QTextBrowser()
        browser.setHtml("""
<p align="justify">
Codimension is a free experimental Python IDE.
</p>
<p align="justify">
Codimension aims to provide an integrated system for:
<ul>
<li>traditional text-based code editing, and</li>
<li>diagram-based code analysis (e.g. imports and classes diagrams,
    profiling results etc).</li>
</ul>
</p>

<p align="justify">
Many Python developers will find codimension useful as-is, even though not all
of its features have been implemented yet.
</p>
<p align="justify">
More information could be found on <a href='http://codimension.org'>
Codimension home page</a>.<br> Happy coding with Codimension!
</p>
""")
        browser.setOpenExternalLinks(True)
        return browser
Пример #6
0
 def __createAuthors( self ):
     " Creates the authors section "
     addr1 = "<a href='mailto:[email protected]'>[email protected]</a>"
     addr2 = "<a href='mailto:[email protected]'>[email protected]</a>"
     addr3 = "<a href='mailto:[email protected]'>[email protected]</a>"
     text = "<p>Author: Sergey Satskiy &lt;" + addr1 + "&gt;</p>" \
            "<p>Packaging: Ilya Loginov &lt;" + addr2 + "&gt;</p>" \
            "<p>Initial packaging and logo: Dmitry Kazimirov &lt;" + addr3 + "&gt;</p>" \
            "<p align='justify'>Special thanks: Detlev Offenbach - the author of the Eric Python IDE." \
            " Codimension borrows some code and some ideas from Eric 4.</p>"
     browser = QTextBrowser()
     browser.setHtml( text )
     browser.setOpenExternalLinks( True )
     return browser
Пример #7
0
 def __init__(self, parent=None, text=""):
     #super(HelpForm, self).__init__(parent)
     self.setAttribute(Qt.WA_GroupLeader)
     self.setAttribute(Qt.WA_DeleteOnClose)
     browser = QTextBrowser()
     browser.setOpenExternalLinks(True)
     browser.setHtml(text)
     layout = QVBoxLayout()
     layout.setMargin(0)
     layout.addWidget(browser)
     self.setLayout(layout)
     self.resize(400, 200)
     QShortcut(QKeySequence("Escape"), self, self.close)
     self.setWindowTitle("R plugin - Help")
Пример #8
0
    def setHtml(self, html):
        # convert special tags :)
        html = unicode(html).replace(
            '<warning>', '<img src=":/db_manager/warning">&nbsp;&nbsp; ')

        # add default style
        html = u"""
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<style type="text/css">
        .section { margin-top: 25px; }
        table.header th { background-color: #dddddd; }
        table.header td { background-color: #f5f5f5; }
        table.header th, table.header td { padding: 0px 10px; }
        table td { padding-right: 20px; }
        .underline { text-decoration:underline; }
</style>
</head>
<body>
%s <br>
</body>
</html>
""" % html

        # print ">>>>>\n", html, "\n<<<<<<"
        return QTextBrowser.setHtml(self, html)
Пример #9
0
    def setHtml(self, html):
        # convert special tags :)
        html = unicode(html).replace('<warning>', '<img src=":/db_manager/warning">&nbsp;&nbsp; ')

        # add default style
        html = u"""
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<style type="text/css">
        .section { margin-top: 25px; }
        table.header th { background-color: #dddddd; }
        table.header td { background-color: #f5f5f5; }
        table.header th, table.header td { padding: 0px 10px; }
        table td { padding-right: 20px; }
        .underline { text-decoration:underline; }
</style>
</head>
<body>
%s <br>
</body>
</html>
""" % html

        # print ">>>>>\n", html, "\n<<<<<<"
        return QTextBrowser.setHtml(self, html)
Пример #10
0
 def __createAuthors(self):
     " Creates the authors section "
     addr1 = "<a href='mailto:[email protected]'>[email protected]</a>"
     addr2 = "<a href='mailto:[email protected]'>[email protected]</a>"
     addr3 = "<a href='mailto:[email protected]'>[email protected]</a>"
     addr4 = "<a href='mailto:[email protected]'>[email protected]</a>"
     addr5 = "<a href='mailto:[email protected]'>[email protected]</a>"
     text = "<p>Author: Sergey Satskiy &lt;" + addr1 + "&gt;</p>" \
            "<p>Packaging and CI (travis): Sergey Fukanchik &lt;" + addr5 + "&gt;</p>" \
            "<p>Packaging: Ilya Loginov &lt;" + addr2 + "&gt;</p>" \
            "<p>Discussions, ideas, testing: David McElhany &lt;" + addr4 + "&gt;</p>" \
            "<p>Initial packaging and logo: Dmitry Kazimirov &lt;" + addr3 + "&gt;</p>" \
            "<p align='justify'>Special thanks: Detlev Offenbach - the author of the Eric Python IDE." \
            " Codimension borrows some code and some ideas from Eric 4.</p>"
     browser = QTextBrowser()
     browser.setHtml(text)
     browser.setOpenExternalLinks(True)
     return browser
Пример #11
0
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        p = parent.addPage(self, i18n("Titles and Headers"))

        l = QHBoxLayout(self)
        # The html view with the score layout example
        t = QTextBrowser(self)
        t.setOpenLinks(False)
        t.setOpenExternalLinks(False)

        # ensure that the full HTML example page is displayed
        t.setContentsMargins(2, 2, 2, 2)
        t.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        t.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        t.setMinimumSize(QSize(350, 350))
        #t.document().documentLayout().documentSizeChanged.connect(
            #lambda size: t.setMinimumSize(size.toSize() + QSize(4, 4)))

        headers = ly.headers(i18n)
        msg = i18n("Click to enter a value.")
        t.setHtml(titles_html.format(
            copyrightmsg = i18n("bottom of first page"),
            taglinemsg = i18n("bottom of last page"),
            **dict((k, "<a title='{0}' href='{1}'>{2}</a>".format(msg, k, v))
                    for k, v in headers)))
        l.addWidget(t)
        t.anchorClicked.connect(lambda qurl:
            self.findChild(KLineEdit, qurl.toString()).setFocus())

        g = QGridLayout()
        g.setVerticalSpacing(1)
        g.setColumnMinimumWidth(1, 200)
        l.addLayout(g)

        for row, (name, title) in enumerate(headers):
            l = QLabel(title + ":", self)
            e = KLineEdit(self)
            e.setObjectName(name)
            l.setBuddy(e)
            g.addWidget(l, row, 0)
            g.addWidget(e, row, 1)
            # set completion items
            parent.complete(e)
Пример #12
0
    def __createVersionWidget(self):
        " Creates the version tab content "
        ver = pysvn.svn_version
        svnVersion = ".".join([str(ver[0]), str(ver[1]), str(ver[2])])
        ver = pysvn.version
        pysvnVersion = ".".join([str(ver[0]), str(ver[1]), str(ver[2])])

        text = "<p>The major Codimension SVN plugin components are listed below:</p>" \
               "<ul>" \
               "<li><a href='http://subversion.apache.org/'>Subversion</a><br>" \
               "Version: " + svnVersion + "<br></li>" \
               "<li><a href='http://pysvn.tigris.org/docs/pysvn.html'>PySvn</a><br>" \
               "Version: " + pysvnVersion + "<br>" \
               "License: <a href='http://www.apache.org/licenses/LICENSE-1.1'>Apache License 1.1</a>" \
               "<br></li>" \
               "</ul>"

        browser = QTextBrowser()
        browser.setHtml(text)
        browser.setOpenExternalLinks(True)
        return browser
Пример #13
0
    def slotButtonShowDiff(self):
        """Called when the user clicks Show Difference."""
        docs = self.selectedDocuments() or self.allDocuments()
        if not docs:
            return
        d = docs[0]
        if documentwatcher.DocumentWatcher.instance(d).isdeleted():
            return

        filename = d.url().toLocalFile()
        try:
            with open(filename, 'rb') as f:
                disktext = util.decode(f.read())
        except (IOError, OSError):
            return

        currenttext = d.toPlainText()

        html = htmldiff.htmldiff(currenttext,
                                 disktext,
                                 _("Current Document"),
                                 _("Document on Disk"),
                                 numlines=5)
        dlg = widgets.dialog.Dialog(self, buttons=('close', ))
        view = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
        view.setHtml(html)
        dlg.setMainWidget(view)
        dlg.setWindowTitle(app.caption("Differences"))
        dlg.setMessage(
            _("Document: {url}\n"
              "Difference between the current document and the file on disk:").
            format(url=filename))
        dlg.setWindowModality(Qt.NonModal)
        dlg.setAttribute(Qt.WA_QuitOnClose, False)
        dlg.setAttribute(Qt.WA_DeleteOnClose)
        qutil.saveDialogSize(dlg, "externalchanges/diff/dialog/size",
                             QSize(600, 300))
        dlg.show()
Пример #14
0
    def __createVersionWidget( self ):
        " Creates the version tab content "
        ver = pysvn.svn_version
        svnVersion = ".".join( [ str( ver[ 0 ] ), str( ver[ 1 ] ),
                                 str( ver[ 2 ] ) ] )
        ver = pysvn.version
        pysvnVersion = ".".join( [ str( ver[ 0 ] ), str( ver[ 1 ] ),
                                   str( ver[ 2 ] ) ] )

        text = "<p>The major Codimension SVN plugin components are listed below:</p>" \
               "<ul>" \
               "<li><a href='http://subversion.apache.org/'>Subversion</a><br>" \
               "Version: " + svnVersion + "<br></li>" \
               "<li><a href='http://pysvn.tigris.org/docs/pysvn.html'>PySvn</a><br>" \
               "Version: " + pysvnVersion + "<br>" \
               "License: <a href='http://www.apache.org/licenses/LICENSE-1.1'>Apache License 1.1</a>" \
               "<br></li>" \
               "</ul>"

        browser = QTextBrowser()
        browser.setHtml( text )
        browser.setOpenExternalLinks( True )
        return browser
Пример #15
0
class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)
        
        self._info = None
        self._text = ''
        self._convertedtext = ''
        self._encoding = None
        
        self.fromVersionLabel = QLabel()
        self.fromVersion = QLineEdit()
        self.reason = QLabel()
        self.toVersionLabel = QLabel()
        self.toVersion = QLineEdit()
        self.messages = QTextBrowser()
        self.diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
        self.copyCheck = QCheckBox(checked=
            QSettings().value('convert_ly/copy_messages', True, bool))
        self.tabw = QTabWidget()
        
        self.tabw.addTab(self.messages, '')
        self.tabw.addTab(self.diff, '')
        
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Reset |
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        self.buttons.button(QDialogButtonBox.Reset).clicked.connect(self.run)
        
        layout = QVBoxLayout()
        self.setLayout(layout)
        
        top = QHBoxLayout()
        top.addWidget(self.fromVersionLabel)
        top.addWidget(self.fromVersion)
        top.addWidget(self.reason)
        top.addStretch()
        top.addWidget(self.toVersionLabel)
        top.addWidget(self.toVersion)
        
        layout.addLayout(top)
        layout.addWidget(self.tabw)
        layout.addWidget(self.copyCheck)
        layout.addWidget(widgets.Separator())
        layout.addWidget(self.buttons)
        
        app.translateUI(self)
        qutil.saveDialogSize(self, 'convert_ly/dialog/size', QSize(600, 300))
        app.settingsChanged.connect(self.readSettings)
        self.readSettings()
        self.finished.connect(self.saveCopyCheckSetting)
        
    def translateUI(self):
        self.fromVersionLabel.setText(_("From version:"))
        self.toVersionLabel.setText(_("To version:"))
        self.copyCheck.setText(_("Save convert-ly messages in document"))
        self.copyCheck.setToolTip(_(
            "If checked, the messages of convert-ly are appended as a "
            "comment to the end of the document."))
        self.tabw.setTabText(0, _("&Messages"))
        self.tabw.setTabText(1, _("&Changes"))
        self.buttons.button(QDialogButtonBox.Reset).setText(_("Run Again"))
        self.setCaption()
    
    def saveCopyCheckSetting(self):
        QSettings().setValue('convert_ly/copy_messages', self.copyCheck.isChecked())
    
    def readSettings(self):
        font = textformats.formatData('editor').font
        self.diff.setFont(font)
        
    def setCaption(self):
        version = self._info and self._info.versionString() or _("<unknown>")
        title = _("Convert-ly from LilyPond {version}").format(version=version)
        self.setWindowTitle(app.caption(title))

    def setLilyPondInfo(self, info):
        self._info = info
        self.setCaption()
        self.toVersion.setText(info.versionString())
        self.setConvertedText()
    
    def setConvertedText(self, text=''):
        self._convertedtext = text
        self.buttons.button(QDialogButtonBox.Ok).setEnabled(bool(text))
        if text:
            self.diff.setHtml(htmldiff.htmldiff(
                self._text, text,
                _("Current Document"), _("Converted Document"),
                wrapcolumn=100))
        else:
            self.diff.clear()
    
    def convertedText(self):
        return self._convertedtext or ''
    
    def setDocument(self, doc):
        v = documentinfo.docinfo(doc).version_string()
        if v:
            self.fromVersion.setText(v)
            self.reason.setText(_("(set in document)"))
        else:
            self.reason.clear()
        self._text = doc.toPlainText()
        self._encoding = doc.encoding() or 'UTF-8'
        self.setConvertedText()
        
    def run(self):
        """Runs convert-ly (again)."""
        fromVersion = self.fromVersion.text()
        toVersion = self.toVersion.text()
        if not fromVersion or not toVersion:
            self.messages.setPlainText(_(
                "Both 'from' and 'to' versions need to be set."))
            return
        info = self._info
        command = info.toolcommand(info.convert_ly)
        command += ['-f', fromVersion, '-t', toVersion, '-']
        
        # if the user wants english messages, do it also here: LANGUAGE=C
        env = None
        if QSettings().value("lilypond_settings/no_translation", False, bool):
            if os.name == "nt":
                # Python 2.7 subprocess on Windows chokes on unicode in env
                env = util.bytes_environ()
                env[b'LANGUAGE'] = b'C'
            else:
                env = dict(os.environ)
                env['LANGUAGE'] = 'C'
        
        with qutil.busyCursor():
            try:
                proc = subprocess.Popen(command,
                    universal_newlines = True,
                    env = env,
                    stdin = subprocess.PIPE,
                    stdout = subprocess.PIPE,
                    stderr = subprocess.PIPE)
                out, err = proc.communicate(self._text.encode(self._encoding))
            except OSError as e:
                self.messages.setPlainText(_(
                    "Could not start {convert_ly}:\n\n"
                    "{message}\n").format(convert_ly = convert_ly, message = e))
                return
            self.messages.setPlainText(err.decode('UTF-8'))
            self.setConvertedText(out.decode('UTF-8'))
            if not out or self._convertedtext == self._text:
                self.messages.append('\n' + _("The document has not been changed."))
Пример #16
0
class PluginsManagerWidget(QDialog):
    """Plugin Manager widget"""
    def __init__(self, parent):
        QDialog.__init__(self, parent, Qt.Dialog)
        self.setWindowTitle(translations.TR_PLUGIN_MANAGER)
        self.resize(700, 600)

        vbox = QVBoxLayout(self)
        self._tabs = QTabWidget()
        vbox.addWidget(self._tabs)
        self._txt_data = QTextBrowser()
        self._txt_data.setOpenLinks(False)
        vbox.addWidget(QLabel(translations.TR_PROJECT_DESCRIPTION))
        vbox.addWidget(self._txt_data)
        # Footer
        hbox = QHBoxLayout()
        btn_close = QPushButton(translations.TR_CLOSE)
        btnReload = QPushButton(translations.TR_RELOAD)
        hbox.addWidget(btn_close)
        hbox.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding))
        hbox.addWidget(btnReload)
        vbox.addLayout(hbox)
        self.overlay = ui_tools.Overlay(self)
        self.overlay.hide()

        self._oficial_available = []
        self._community_available = []
        self._locals = []
        self._updates = []
        self._loading = True
        self._requirements = {}

        self.connect(btnReload, SIGNAL("clicked()"), self._reload_plugins)
        self.thread = ThreadLoadPlugins(self)
        self.connect(self.thread, SIGNAL("finished()"),
                     self._load_plugins_data)
        self.connect(self.thread, SIGNAL("plugin_downloaded(PyQt_PyObject)"),
                     self._after_download_plugin)
        self.connect(self.thread,
                     SIGNAL("plugin_manually_installed(PyQt_PyObject)"),
                     self._after_manual_install_plugin)
        self.connect(self.thread, SIGNAL("plugin_uninstalled(PyQt_PyObject)"),
                     self._after_uninstall_plugin)
        self.connect(self._txt_data, SIGNAL("anchorClicked(const QUrl&)"),
                     self._open_link)
        self.connect(btn_close, SIGNAL('clicked()'), self.close)
        self.overlay.show()
        self._reload_plugins()

    def show_plugin_info(self, data):
        """Takes data argument, format for HTML and display it"""
        plugin_description = data[2].replace('\n', '<br>')
        html = HTML_STYLE.format(name=data[0],
                                 version=data[1],
                                 description=plugin_description,
                                 author=data[3],
                                 link=data[4])
        self._txt_data.setHtml(html)

    def _open_link(self, url):
        """Takes an url argument and open the link on web browser"""
        link = url.toString()
        if link.startswith('/plugins/'):
            link = 'http://ninja-ide.org' + link
        webbrowser.open(link)

    def _reload_plugins(self):
        """Reload all plugins"""
        self.overlay.show()
        self._loading = True
        self.thread.runnable = self.thread.collect_data_thread
        self.thread.start()

    def _after_manual_install_plugin(self, plugin):
        """After installing, take plugin and add it to installedWidget items"""
        data = {}
        data['name'] = plugin[0]
        data['version'] = plugin[1]
        data['description'] = ''
        data['authors'] = ''
        data['home'] = ''
        self._installedWidget.add_table_items([data])

    def _after_download_plugin(self, plugin):
        """After installing, take plugin and add it to installedWidget items"""
        oficial_plugin = _get_plugin(plugin[0], self._oficial_available)
        community_plugin = _get_plugin(plugin[0], self._community_available)
        if oficial_plugin:
            self._installedWidget.add_table_items([oficial_plugin])
            self._availableOficialWidget.remove_item(plugin[0])
        elif community_plugin:
            self._installedWidget.add_table_items([community_plugin])
            self._availableCommunityWidget.remove_item(plugin[0])

    def _after_uninstall_plugin(self, plugin):
        """After uninstall plugin,make available plugin corresponding to type"""
        oficial_plugin = _get_plugin(plugin[0], self._oficial_available)
        community_plugin = _get_plugin(plugin[0], self._community_available)
        if oficial_plugin:
            self._availableOficialWidget.add_table_items([oficial_plugin])
            self._installedWidget.remove_item(plugin[0])
        elif community_plugin:
            self._availableCommunityWidget.add_table_items([community_plugin])
            self._installedWidget.remove_item(plugin[0])

    def _load_plugins_data(self):
        """Load all the plugins data"""
        if self._loading:
            self._tabs.clear()
            self._updatesWidget = UpdatesWidget(self, copy(self._updates))
            self._availableOficialWidget = AvailableWidget(
                self, copy(self._oficial_available))
            self._availableCommunityWidget = AvailableWidget(
                self, copy(self._community_available))
            self._installedWidget = InstalledWidget(self, copy(self._locals))
            self._tabs.addTab(self._availableOficialWidget,
                              translations.TR_OFFICIAL_AVAILABLE)
            self._tabs.addTab(self._availableCommunityWidget,
                              translations.TR_COMMUNITY_AVAILABLE)
            self._tabs.addTab(self._updatesWidget, translations.TR_UPDATE)
            self._tabs.addTab(self._installedWidget, translations.TR_INSTALLED)
            self._manualWidget = ManualInstallWidget(self)
            self._tabs.addTab(self._manualWidget,
                              translations.TR_MANUAL_INSTALL)
            self._loading = False
        self.overlay.hide()
        self.thread.wait()

    def download_plugins(self, plugs):
        """
        Install
        """
        self.overlay.show()
        self.thread.plug = plugs
        # set the function to run in the thread
        self.thread.runnable = self.thread.download_plugins_thread
        self.thread.start()

    def install_plugins_manually(self, plug):
        """Install plugin from local zip."""
        self.overlay.show()
        self.thread.plug = plug
        # set the function to run in the thread
        self.thread.runnable = self.thread.manual_install_plugins_thread
        self.thread.start()

    def mark_as_available(self, plugs):
        """
        Uninstall
        """
        self.overlay.show()
        self.thread.plug = plugs
        # set the function to run in the thread
        self.thread.runnable = self.thread.uninstall_plugins_thread
        self.thread.start()

    def update_plugin(self, plugs):
        """
        Update
        """
        self.overlay.show()
        self.thread.plug = plugs
        # set the function to run in the thread
        self.thread.runnable = self.thread.update_plugin_thread
        self.thread.start()

    def reset_installed_plugins(self):
        """Reset all the installed plugins"""
        local_plugins = plugin_manager.local_plugins()
        plugins = _format_for_table(local_plugins)
        self._installedWidget.reset_table(plugins)

    def resizeEvent(self, event):
        """Handle Resize events"""
        self.overlay.resize(event.size())
        event.accept()
Пример #17
0
class PluginsManagerWidget(QDialog):

    def __init__(self, parent):
        QDialog.__init__(self, parent, Qt.Dialog)
        self.setWindowTitle(self.tr("Plugins Manager"))
        self.resize(700, 600)

        vbox = QVBoxLayout(self)
        self._tabs = QTabWidget()
        vbox.addWidget(self._tabs)
        self._txt_data = QTextBrowser()
        self._txt_data.setOpenLinks(False)
        vbox.addWidget(QLabel(self.tr("Description:")))
        vbox.addWidget(self._txt_data)
        # Footer
        hbox = QHBoxLayout()
        btn_close = QPushButton(self.tr('Close'))
        btnReload = QPushButton(self.tr("Reload"))
        hbox.addWidget(btn_close)
        hbox.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding))
        hbox.addWidget(btnReload)
        vbox.addLayout(hbox)
        self.overlay = ui_tools.Overlay(self)
        self.overlay.hide()

        self._oficial_available = []
        self._community_available = []
        self._locals = []
        self._updates = []
        self._loading = True
        self._requirements = {}

        self.connect(btnReload, SIGNAL("clicked()"), self._reload_plugins)
        self.thread = ThreadLoadPlugins(self)
        self.connect(self.thread, SIGNAL("finished()"),
            self._load_plugins_data)
        self.connect(self.thread, SIGNAL("plugin_downloaded(PyQt_PyObject)"),
            self._after_download_plugin)
        self.connect(self.thread, SIGNAL("plugin_uninstalled(PyQt_PyObject)"),
            self._after_uninstall_plugin)
        self.connect(self._txt_data, SIGNAL("anchorClicked(const QUrl&)"),
            self._open_link)
        self.connect(btn_close, SIGNAL('clicked()'), self.close)
        self.overlay.show()
        self._reload_plugins()

    def show_plugin_info(self, data):
        plugin_description = data[2].replace('\n', '<br>')
        html = HTML_STYLE.format(name=data[0],
            version=data[1], description=plugin_description,
            author=data[3], link=data[4])
        self._txt_data.setHtml(html)

    def _open_link(self, url):
        link = url.toString()
        if link.startswith('/plugins/'):
            link = 'http://ninja-ide.org' + link
        webbrowser.open(link)

    def _reload_plugins(self):
        self.overlay.show()
        self._loading = True
        self.thread.runnable = self.thread.collect_data_thread
        self.thread.start()

    def _after_download_plugin(self, plugin):
        oficial_plugin = _get_plugin(plugin[0], self._oficial_available)
        community_plugin = _get_plugin(plugin[0], self._community_available)
        if oficial_plugin:
            self._installedWidget.add_table_items([oficial_plugin])
            self._availableOficialWidget.remove_item(plugin[0])
        elif community_plugin:
            self._installedWidget.add_table_items([community_plugin])
            self._availableCommunityWidget.remove_item(plugin[0])

    def _after_uninstall_plugin(self, plugin):
        #make available the plugin corresponding to the type
        oficial_plugin = _get_plugin(plugin[0], self._oficial_available)
        community_plugin = _get_plugin(plugin[0], self._community_available)
        if oficial_plugin:
            self._availableOficialWidget.add_table_items([oficial_plugin])
            self._installedWidget.remove_item(plugin[0])
        elif community_plugin:
            self._availableCommunityWidget.add_table_items([community_plugin])
            self._installedWidget.remove_item(plugin[0])

    def _load_plugins_data(self):
        if self._loading:
            self._tabs.clear()
            self._updatesWidget = UpdatesWidget(self, copy(self._updates))
            self._availableOficialWidget = AvailableWidget(self,
                copy(self._oficial_available))
            self._availableCommunityWidget = AvailableWidget(self,
                copy(self._community_available))
            self._installedWidget = InstalledWidget(self, copy(self._locals))
            self._tabs.addTab(self._availableOficialWidget,
                self.tr("Official Available"))
            self._tabs.addTab(self._availableCommunityWidget,
                self.tr("Community Available"))
            self._tabs.addTab(self._updatesWidget, self.tr("Updates"))
            self._tabs.addTab(self._installedWidget, self.tr("Installed"))
            self._loading = False
        self.overlay.hide()

    def download_plugins(self, plugs):
        """
        Install
        """
        self.overlay.show()
        self.thread.plug = plugs
        #set the function to run in the thread
        self.thread.runnable = self.thread.download_plugins_thread
        self.thread.start()

    def mark_as_available(self, plugs):
        """
        Uninstall
        """
        self.overlay.show()
        self.thread.plug = plugs
        #set the function to run in the thread
        self.thread.runnable = self.thread.uninstall_plugins_thread
        self.thread.start()

    def update_plugin(self, plugs):
        """
        Update
        """
        self.overlay.show()
        self.thread.plug = plugs
        #set the function to run in the thread
        self.thread.runnable = self.thread.update_plugin_thread
        self.thread.start()

    def reset_installed_plugins(self):
        local_plugins = plugin_manager.local_plugins()
        plugins = _format_for_table(local_plugins)
        self._installedWidget.reset_table(plugins)

    def resizeEvent(self, event):
        self.overlay.resize(event.size())
        event.accept()
Пример #18
0
class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)

        self._info = None
        self._text = ""
        self._convertedtext = ""
        self._encoding = None

        self.fromVersionLabel = QLabel()
        self.fromVersion = QLineEdit()
        self.reason = QLabel()
        self.toVersionLabel = QLabel()
        self.toVersion = QLineEdit()
        self.messages = QTextBrowser()
        self.diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
        self.copyCheck = QCheckBox(checked=QSettings().value("convert_ly/copy_messages", True) not in (False, "false"))
        self.tabw = QTabWidget()

        self.tabw.addTab(self.messages, "")
        self.tabw.addTab(self.diff, "")

        self.buttons = QDialogButtonBox(QDialogButtonBox.Reset | QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        self.buttons.button(QDialogButtonBox.Reset).clicked.connect(self.run)

        layout = QVBoxLayout()
        self.setLayout(layout)

        top = QHBoxLayout()
        top.addWidget(self.fromVersionLabel)
        top.addWidget(self.fromVersion)
        top.addWidget(self.reason)
        top.addStretch()
        top.addWidget(self.toVersionLabel)
        top.addWidget(self.toVersion)

        layout.addLayout(top)
        layout.addWidget(self.tabw)
        layout.addWidget(self.copyCheck)
        layout.addWidget(widgets.Separator())
        layout.addWidget(self.buttons)

        app.translateUI(self)
        util.saveDialogSize(self, "convert_ly/dialog/size", QSize(600, 300))
        app.settingsChanged.connect(self.readSettings)
        self.readSettings()
        self.finished.connect(self.saveCopyCheckSetting)

    def translateUI(self):
        self.fromVersionLabel.setText(_("From version:"))
        self.toVersionLabel.setText(_("To version:"))
        self.copyCheck.setText(_("Save convert-ly messages in document"))
        self.copyCheck.setToolTip(
            _("If checked, the messages of convert-ly are appended as a " "comment to the end of the document.")
        )
        self.tabw.setTabText(0, _("&Messages"))
        self.tabw.setTabText(1, _("&Changes"))
        self.buttons.button(QDialogButtonBox.Reset).setText(_("Run Again"))
        self.setCaption()

    def saveCopyCheckSetting(self):
        QSettings().setValue("convert_ly/copy_messages", self.copyCheck.isChecked())

    def readSettings(self):
        font = textformats.formatData("editor").font
        self.diff.setFont(font)

    def setCaption(self):
        version = self._info and self._info.versionString() or _("<unknown>")
        title = _("Convert-ly from LilyPond {version}").format(version=version)
        self.setWindowTitle(app.caption(title))

    def setLilyPondInfo(self, info):
        self._info = info
        self.setCaption()
        self.toVersion.setText(info.versionString())
        self.setConvertedText()

    def setConvertedText(self, text=""):
        self._convertedtext = text
        self.buttons.button(QDialogButtonBox.Ok).setEnabled(bool(text))
        if text:
            self.diff.setHtml(makeHtmlDiff(self._text, text))
        else:
            self.diff.clear()

    def convertedText(self):
        return self._convertedtext or ""

    def setDocument(self, doc):
        v = documentinfo.info(doc).versionString()
        if v:
            self.fromVersion.setText(v)
            self.reason.setText(_("(set in document)"))
        else:
            self.reason.clear()
        self._text = doc.toPlainText()
        self._encoding = doc.encoding() or "UTF-8"
        self.setConvertedText()

    def run(self):
        """Runs convert-ly (again)."""
        fromVersion = self.fromVersion.text()
        toVersion = self.toVersion.text()
        if not fromVersion or not toVersion:
            self.messages.setPlainText(_("Both 'from' and 'to' versions need to be set."))
            return
        info = self._info
        convert_ly = os.path.join(info.bindir(), info.convert_ly)

        # on Windows the convert-ly command is not directly executable, but
        # must be started using the LilyPond-provided Python interpreter
        if os.name == "nt":
            if not os.access(convert_ly, os.R_OK) and not convert_ly.endswith(".py"):
                convert_ly += ".py"
            command = [info.python(), convert_ly]
        else:
            command = [convert_ly]
        command += ["-f", fromVersion, "-t", toVersion, "-"]

        # if the user wants english messages, do it also here
        env = None
        if QSettings().value("lilypond_settings/no_translation", False) in (True, "true"):
            env = dict(os.environ)
            env["LANGUAGE"] = "C"

        with util.busyCursor():
            try:
                proc = subprocess.Popen(
                    command, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
                )
                out, err = proc.communicate(self._text.encode(self._encoding))
            except OSError as e:
                self.messages.setPlainText(
                    _("Could not start {convert_ly}:\n\n" "{message}\n").format(convert_ly=convert_ly, message=e)
                )
                return
            self.messages.setPlainText(err.decode("UTF-8"))
            self.setConvertedText(out.decode("UTF-8"))
            if not out or self._convertedtext == self._text:
                self.messages.append("\n" + _("The document has not been changed."))
Пример #19
0
    def __init__(self, parent=None, version=0.1, license="", currentdir="."):
        QDialog.__init__(self, parent)
        iconLabel = QLabel()
        icon = QPixmap(":logo.png")
        iconLabel.setPixmap(icon)
        nameLabel = QLabel(
            "<font size=8 color=#0066CC>&nbsp;<b>manageR</b></font>")
        versionLabel = QLabel(
            "<font color=#0066CC>%s on %s<br>manageR %s</font>" % (
            robjects.r.version[12][0], sys.platform, version))
        aboutBrowser = QTextBrowser()
        aboutBrowser.setOpenExternalLinks(True)
        aboutBrowser.setHtml(
            "<h3>Interface to the R statistical programming environment</h3>"
            "Copyright &copy; 2009-2010 Carson J. Q. Farmer"
            "<br/>[email protected]"
            "<br/><a href='http://www.ftools.ca/manageR'>http://www.ftools.ca/manageR</a>")
        licenseBrowser = QTextBrowser()
        licenseBrowser.setOpenExternalLinks(True)
        licenseBrowser.setHtml((license.replace("\n\n", "<p>").replace("(C)", "&copy;")))
        helpBrowser = QTextBrowser()
        helpBrowser.setOpenExternalLinks(True)
        helpBrowser.setHtml(
            "<center><h2>manageR version %s documentation</h2></center>"
            "<h4>Description:</h4>"
            "<b>manageR</b> adds comprehensive statistical capabilities to ..."
            "<h4>Features:</h4>"
            "<ul><li>Syntax highlighting</li><li>Minimal R script editor</li><li>Code checking/debuging</li>"
            "<li>Extensible GUI for common R functions</li>"
            "<li>Aides in building complex R scripts via an integrated console and editor</li>"
            "<li>Tools and widgets for exploring the R workspace, history, file system, working directory, "
            "plotting devices, library, help system, and online package repository</li></ul>"
            "<h4>Usage:</h4>"
            "<p>Use <tt>Ctrl+Return</tt> to send commands from an <b>EditR</b> window to the <b>manageR</b>"
            "console. If an <b>EditR</b> window contains selected text, only this text will be sent"
            "to the <b>manageR</b> console, otherwise, all text is sent. The <b>EditR</b> window"
            "also contains tools for creating, loading, editing, and saving R scripts. The suite of"
            "available tools is outlined in detail in the <b>Key bindings</b> section.</p>"
            "<p><i>Autocompletion</i><br>"
            "If enabled, command completion suggestions are automatically shown after a given time interval"
            "based on the current work. This can also be manually activated using <b>Ctrl+Space</b>."
            "In addition, a tooltip will appear if one is available for the selected command."
            "It is possible to turn off autocompletion (and tooltips)"
            "by unchecking File &rarr; Configure &rarr;"
            "General tab &rarr; Enable autocompletion.</p>"
            "<p><i>Search and Replace</i><br>"
            "A Search and Replace toolbar is available for both the <b>manageR</b> console and <b>EditR</b>"
            "window (the replace functionality is only available in <b>EditR</b>). When activated (see"
            "<b>Key Bindings</b> section below), if any text is selected in the parent dialog, this text"
            "will be placed in the 'Find toolbar' for searching. To search for"
            "the next occurrence of the text or phrase in the toolbar, type <tt>Enter</tt>"
            "or click the 'Next' button. Conversely, click the 'Previous' button to search backwards. To"
            "replace text as it is found, simply type the replacement text in the 'Replace' line edit and"
            "click 'Replace'. To replace all occurrences of the found text, click 'Replace all'. All"
            "searches can be refined by using the 'Case sensitive' and 'Whole words' check boxes.</p>"
            "<p><i>Workspace Manager</i></i><br>"
            "The Workspace Tree displays the name, type, and dimentions f all currently loaded variables "
            "in your global R environment (globalEnv). From here, it is possible to remove, save, and load "
            "R variables, as well as export R variables to file.</p>"
            "<p><i>Graphic Device Manager</i><br>"
            "The graphic devices table stores the ID and device type of all current R graphic devices. From here,"
            "it is possible to refresh the list of graphic devices, create a new empty graphic window, and remove"
            "existing devices. In addition, it is possible to export the selected graphic device to file in both raster"
            "and vector formats.</p>"
            "<p><i>History Manager</i><br>"
            "The command history displays a list of all previously executed commands (including commands loaded from a"
            ".RHistory file). From here it is possible to run a command in the <b>manageR</b> console by"
            "double clicking an item. Similarly, multiple commands can be selected, and copied"
            "using the popup menu. Individual commands can be selected or unselected simply by"
            "clicking on them using the left mouse button. To run all selected commands, right click anywhere within"
            "the command history widget, and select run from the popup menu.</p>"
            "<p><i>Working Directory Browser</i><br>"
            "The working directory widget is a simple toolbar to help browse to different working directories, making it"
            "simple to change the current R working directory.</p>"
            "<p><i>File System Browser</i><br>"
            "The file system browser widget is a simple tool to help browse to different directories, making it"
            "simple to view, load, delete, and manage your folders.</p>"
            "<p><i>Analysis</i><br>"
            "<b>manageR</b> supports simple plugins which help to streamline tedious R functions by providing a"
            "plugin framework for creating simple graphical user interfaces (GUI) to commonly used R functions."
            "These functions can be specified using an XML ('tools.xml') file stored in the <b>manageR</b>"
            "installation folder (%s). The format of the XML file should be as follows:"
            "<font color=green><i>"
            "<pre>&lt;?xml version='1.0'?&gt;"
            "&lt;manageRTools&gt;<br>"
            "  &lt;RTool name='Insert random R commands' query='|1|'&gt;<br>"
            "    &lt;Parameter label='R commands:' type='textEdit' default='ls()' notnull='true'/&gt;<br>"
            "  &lt;/RTool&gt;<br>"
            "&lt;manageRTools&gt;</i></font></pre>"
            "where each RTool specifies a unique R function. In the above example, the GUI will consist of a simple"
            "dialog with a text editing region to input user-defined R commands, and an OK and CLOSE button. When"
            "OK is clicked, the R commands in the text editing region will be run, and when CLOSE is clicked,"
            "the dialog will be closed. In the example above, query is set to <tt>|1|</tt>, which means take the"
            "output from the first parameter, and place here. In other words, in this case the entire query is"
            "equal to whatever is input into the text editing region (default here is <tt>ls()</tt>). Other GUI"
            "parameters that may be entered include:"
            "<ul><li>comboBox: Drop-down list box</li><li>doubleSpinBox: Widget for entering numerical values</li>"
            "<li>textEdit: Text editing region</li>"
            "<li>spComboBox: Combobox widget for displaying a dropdown list of variables (e.g. numeric,"
            "data.frame, Spatial*DataFrame)</li>"
            "<li>spListWidget: Widget for displaying lists of variables (e.g. numeric, data.frame, Spatial*DataFrame)</li>"
            "<li>helpString: Non-graphical parameter that is linked to the help button on the dialog"
            "(can use 'topic:help_topic' or custom html based help text)</li></ul>"
            "Default values for all of the above GUI parameters can be specified in the XML file, using semi-colons"
            "to separate multiple options. For the spComboBox, the default string should specify the type(s) of"
            "variables to display (e.g. numeric;data,frame;SpatialPointsDataFrame)."
            "<b>manageR</b> comes with several default R GUI functions which can be used as examples for creating"
            "custom R functions.</p>"
            "<h4>Key bindings:</h4>"
            "<ul>"
            "<li><tt>&uarr;</tt> : In the <b>manageR</b> console, show the previous command"
            "from the command history. In the <b>EditR</b> windows, move up one line."
            "<li><tt>&darr;</tt> : In the <b>manageR</b> console, show the next command"
            "from the command history. In the <b>EditR</b> windows, move down one line."
            "<li><tt>&larr;</tt> : Move the cursor left one character"
            "<li><tt>Ctrl+&larr;</tt> : Move the cursor left one word"
            "<li><tt>&rarr;</tt> : Move the cursor right one character"
            "<li><tt>Ctrl+&rarr;</tt> : Move the cursor right one word"
            "<li><tt>Tab</tt> : Indent the selected text (or the current line)"
            "<li><tt>Shift+Tab</tt> : Unindent the selected text (or the current line)"
            "<li><tt>Ctrl+A</tt> : Select all the text"
            "<li><tt>Backspace</tt> : Delete the character to the left of the cursor"
            "<li><tt>Ctrl+C</tt> : In the <b>manageR</b> console, if the cursor is in the command line, clear"
            "current command(s), otherwise copy the selected text to the clipboard (same for <b>EditR</b>"
            "windows."
            "<li><tt>Delete</tt> : Delete the character to the right of the cursor"
            "<li><tt>End</tt> : Move the cursor to the end of the line"
            "<li><tt>Ctrl+End</tt> : Move the cursor to the end of the file"
            "<li><tt>Ctrl+Return</tt> : In an <b>EditR</b> window, execute the (selected) code/text"
            "<li><tt>Ctrl+F</tt> : Pop up the Find toolbar"
            "<li><tt>Ctrl+R</tt> : In an <b>EditR</b> window, pop up the Find and Replace toolbar"
            "<li><tt>Home</tt> : Move the cursor to the beginning of the line"
            "<li><tt>Ctrl+Home</tt> : Move the cursor to the beginning of the file"
            "<li><tt>Ctrl+K</tt> : Delete to the end of the line"
            "<li><tt>Ctrl+G</tt> : Pop up the 'Goto line' dialog"
            "<li><tt>Ctrl+N</tt> : Open a new editor window"
            "<li><tt>Ctrl+O</tt> : Open a file open dialog to open an R script"
            "<li><tt>Ctrl+Space</tt> : Pop up a list of possible completions for"
            "the current word. Use the up and down arrow keys and the page up and page"
            "up keys (or the mouse) to navigate; click <tt>Enter</tt> to accept a"
            "completion or <tt>Esc</tt> to cancel."
            "<li><tt>PageUp</tt> : Move up one screen"
            "<li><tt>PageDown</tt> : Move down one screen"
            "<li><tt>Ctrl+Q</tt> : Terminate manageR; prompting to save any unsaved changes"
            "for every <b>EditR</b> window for which this is necessary. If the user cancels"
            "any 'save unsaved changes' message box, manageR will not terminate."
            "<li><tt>Ctrl+S</tt> : Save the current file"
            "<li><tt>Ctrl+V</tt> : Paste the clipboards text"
            "<li><tt>Ctrl+W</tt> : Close the current file; prompting to save any unsaved"
            "changes if necessary"
            "<li><tt>Ctrl+X</tt> : Cut the selected text to the clipboard"
            "<li><tt>Ctrl+Z</tt> : Undo the last editing action"
            "<li><tt>Ctrl+Shift+Z</tt> : Redo the last editing action</ul>"
            "Hold down <tt>Shift</tt> when pressing movement keys to select the text moved over.<br>" % (version, currentdir))

        tabWidget = QTabWidget()
        tabWidget.addTab(aboutBrowser, "&About")
        tabWidget.addTab(licenseBrowser, "&License")
        tabWidget.addTab(helpBrowser, "&Help")

        layout = QVBoxLayout(self)
        hbox = QHBoxLayout()
        hbox.addWidget(iconLabel)
        hbox.addWidget(nameLabel)
        hbox.addStretch()
        hbox.addWidget(versionLabel)
        layout.addLayout(hbox)
        layout.addWidget(tabWidget)

        self.setMinimumSize(min(self.width(),
            int(QApplication.desktop().availableGeometry().width() / 2)),
            int(QApplication.desktop().availableGeometry().height() / 2))
        self.setWindowTitle("manageR - About")
Пример #20
0
class AdvancedObjectWidget(QWidget):
    def __init__(self,
                 index,
                 currentTemplate="classic.html",
                 parent=None,
                 entryTemplate=None):
        QWidget.__init__(self, parent)

        w = 24
        h = 24
        self.entryModel = None

        # Standard pixmaps used by the widget
        self.reloadPixmap = pixmapFromTheme("view-refresh",
                                            ":/icons/32/view-refresh", w, h)
        self.savePixmap = pixmapFromTheme("document-save",
                                          ":/icons/32/document-save", w, h)
        self.addPixmap = pixmapFromTheme("list-add", ":/icons/32/list-add", w,
                                         h)
        self.deleteSmallPixmap = pixmapFromTheme("list-remove",
                                                 ":/icons/32/list-remove", w,
                                                 h)

        self.treeIndex = index

        self.setLayout(QVBoxLayout(self))
        self.layout().setSpacing(0)
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        # create the widget containing the data
        self.textBrowser = QTextBrowser()
        self.textBrowser.setOpenLinks(False)
        self.textBrowser.setWordWrapMode(QTextOption.WrapAnywhere)
        self.layout().addWidget(self.textBrowser)
        self.textBrowser.anchorClicked.connect(self.anchorClicked)

        self.currentDocument = ''
        self.addingToComboBox = False

        # create the combobox containing the different views
        self.comboBox = QComboBox()
        self.currentTemplate = currentTemplate
        self.errorTemplate = "error.html"
        self.usedTemplates = []
        # FIXED: Need a more robust way for locating the path used in
        #        the TemplateFactory for locating the template view
        #        files
        # >>>    with base.util.Paths.getLumaRoot this should work.
        #        Probably needs some validation testing on platforms
        #        other than Linux
        # Another issue occured when running Luma after a installation
        # from a source distribution. Because the site-packages is only
        # intended for pure python modules, the html templates is not
        # installed, resulting in an Exception when trying to view an
        # entry in the Browser plugin. The setup.py script is modified
        # such that the needed html templates is copied into a folder
        # in the path returned by `base.util.Paths.getConfigPrefix`.
        s = QtCore.QSettings()
        configPrefix = s.value('application/config_prefix').toString()
        templatesPath = os.path.join(
            unicode(configPrefix).encode('utf-8'), 'browser-templates')
        # If we run Luma from a development environment the isntalled
        # templatesPath do most likely not exist. We therefore use the
        # directory in the repository
        if not os.path.isdir(templatesPath):
            templatesPath = unicode(
                os.path.join(getLumaRoot(), 'plugins', 'browser', 'templates'))

        self.templateFactory = TemplateFactory(templatesPath)

        self.htmlParser = HtmlParser(self.textBrowser)

        self.str_RELOAD = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Reload")
        self.str_SAVE = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Save entry")
        self.str_SAVE_CONTINUE = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget",
            "Do you want to save the entry before continuing?")
        self.str_SAVE_FAILED = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Saving failed, continue anyway?")
        self.str_DELETE = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Delete object")
        self.str_DELETE_CONFIRM = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Do you really want to delete the object?")
        self.str_ADD = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Add attribute")
        self.str_SWITCH_VIEWS = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Switch between views")
        self.str_REASON = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Reason:")
        self.str_EXPORT_BINARY = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Export binary attribute to file")
        self.str_EXPORT_BINARY_EXCEPT = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Could not export binary data to file.")
        self.str_SELECT_ANOTHER_FILE = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "Please select another filename.")
        self.str_NO_TEMPLATE = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget", "No templates available")
        self.str_MISSING_ENTRY = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget",
            "Did'nt receive a ldap-object, it might have been deleted")
        self.str_ENTRY_INVALID = QtCore.QCoreApplication.translate(
            "AdvancedObjectWidget",
            "The ldap object is not valid\nClick Yes to view the object anyway\nNo to view the errors \nIgnore to view the object and ignore this message in later attempts."
        )

        self.buildToolBar()

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

    @staticmethod
    def smartObjectCopy(smartObject):
        return SmartDataObject(
            copy.deepcopy([smartObject.dn, smartObject.data]),
            copy.deepcopy(smartObject.serverMeta))

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

    def getSmartObject(self):
        return self.entryModel.getSmartObject()

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

    def initModel(self, smartObject, create=False, entryTemplate=None):
        """ sets up the model, and connects it to this object
        """
        if not create:
            # use a copy of the smartObject
            smartObject = AdvancedObjectWidget.smartObjectCopy(smartObject)
        self.baseDN = smartObject.getDN()
        self.entryModel = EntryModel(smartObject, self, entryTemplate)
        self.htmlParser.setModel(self.entryModel)
        self.entryModel.modelChangedSignal.connect(self.modelChanged)
        success, exceptionMsg, exceptionObject = self.entryModel.initModel(
            create)
        if not success:
            errorMsg = "%s<br><br>%s: %s" % (exceptionMsg, self.str_REASON,
                                             str(exceptionObject))
            QMessageBox.critical(self, self.trUtf8(""), self.trUtf8(errorMsg))

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

    def loadTemplates(self):
        """ Loads all templates that matches with the current objectclasses
        """
        self.usedTemplates = []
        objectClasses = self.getSmartObject().getObjectClasses()
        newIndex = -1
        i = 0
        for objectClass, fileName in self.templateFactory.getTemplateList():
            if objectClass == '' or objectClass in objectClasses:
                if fileName == self.currentTemplate:
                    newIndex = i
                self.usedTemplates.append(fileName)
                i += 1
        if newIndex == -1:
            newIndex = 0
        self.currentTemplate = self.usedTemplates[newIndex]
        #TODO do this properly, signals ignored
        self.addingToComboBox = True
        self.comboBox.clear()
        self.comboBox.addItems(self.usedTemplates)
        self.comboBox.setCurrentIndex(newIndex)
        self.addingToComboBox = False

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

    @pyqtSlot(bool)
    def modelChanged(self, reload):
        if reload:
            item = None
            if self.treeIndex and self.treeIndex.isValid():
                row = self.treeIndex.row()
                column = self.treeIndex.column()
                # QPersistenIndex doesn't have internalPointer()
                # so we aquire a QModelIndex which does
                item = self.treeIndex.sibling(row, column).internalPointer()
            if not (self.entryModel.VALID):
                if item == None or not (item.serverParent.ignoreItemErrors):
                    result = QMessageBox.question(
                        self, self.trUtf8(""), self.str_ENTRY_INVALID,
                        QMessageBox.Yes | QMessageBox.No | QMessageBox.Ignore,
                        QMessageBox.No)
                    if result == QMessageBox.No:
                        self.currentTemplate = self.errorTemplate
                    elif result == QMessageBox.Ignore:
                        if not (item == None):
                            item.serverParent.ignoreItemErrors = True
        self.displayValues()

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

    def displayValues(self):
        # Something went wrong. We have no data object.
        # This might happen if we want to refresh an item and
        # it might be deleted already.
        if None == self.entryModel.getSmartObject():
            QMessageBox.critical(self, self.str_MISSING_ENTRY)
            self.enableToolButtons(False)
            return

        self.loadTemplates()
        if self.currentTemplate == None:
            selt.textBrowser.setHtml(self.str_NO_TEMPLATE)
            return
        htmlTemplate = self.templateFactory.getTemplateFile(
            self.currentTemplate)
        self.currentDocument = self.htmlParser.parseHtml(htmlTemplate)
        self.textBrowser.setHtml(self.currentDocument)

        self.enableToolButtons(True)

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

    def enableToolButtons(self, enable):
        if None == self.entryModel:
            self.saveButton.setEnabled(False)
            self.deleteObjectButton.setEnabled(False)
            self.reloadButton.setEnabled(True)
            self.addAttributeButton.setEnabled(False)
            return
        if self.entryModel.EDITED and not self.entryModel.CREATE:
            self.saveButton.setEnabled(enable)
        else:
            self.saveButton.setEnabled(False)

        if self.entryModel.ISLEAF:
            self.deleteObjectButton.setEnabled(enable)
        else:
            self.deleteObjectButton.setEnabled(False)

        if self.entryModel.CREATE:
            self.reloadButton.setEnabled(False)
        else:
            self.reloadButton.setEnabled(enable)

        self.addAttributeButton.setEnabled(enable)

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

    def buildToolBar(self):
        self.toolBar = QToolBar()
        self.toolBar.layout().setContentsMargins(0, 0, 0, 0)

        # Reload button
        self.reloadButton = QToolButton(self.toolBar)
        self.reloadButton.setIcon(QIcon(self.reloadPixmap))
        self.reloadButton.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.reloadButton.setAutoRaise(True)
        self.reloadButton.setBackgroundRole(self.backgroundRole())
        self.reloadButton.setToolTip(self.str_RELOAD)
        self.connect(self.reloadButton, SIGNAL("clicked()"), self.refreshView)
        self.toolBar.addWidget(self.reloadButton)

        # Save button
        self.saveButton = QToolButton(self.toolBar)
        self.saveButton.setIcon(QIcon(self.savePixmap))
        self.saveButton.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.saveButton.setAutoRaise(True)
        self.saveButton.setBackgroundRole(self.backgroundRole())
        self.saveButton.setToolTip(self.str_SAVE)
        self.connect(self.saveButton, SIGNAL("clicked()"), self.saveObject)
        self.toolBar.addWidget(self.saveButton)

        self.toolBar.addSeparator()

        # Add attribute button
        self.addAttributeButton = QToolButton(self.toolBar)
        self.addAttributeButton.setIcon(QIcon(self.addPixmap))
        self.addAttributeButton.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.addAttributeButton.setAutoRaise(True)
        self.addAttributeButton.setBackgroundRole(self.backgroundRole())
        self.addAttributeButton.setToolTip(self.str_ADD)
        self.connect(self.addAttributeButton, SIGNAL("clicked()"),
                     self.addAttribute)
        self.toolBar.addWidget(self.addAttributeButton)

        # Delete button
        self.deleteObjectButton = QToolButton(self.toolBar)
        self.deleteObjectButton.setIcon(QIcon(self.deleteSmallPixmap))
        self.deleteObjectButton.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.deleteObjectButton.setAutoRaise(True)
        self.deleteObjectButton.setBackgroundRole(self.backgroundRole())
        self.deleteObjectButton.setToolTip(self.str_DELETE)
        self.connect(self.deleteObjectButton, SIGNAL("clicked()"),
                     self.deleteObject)
        self.toolBar.addWidget(self.deleteObjectButton)

        self.comboBox.setToolTip(self.str_SWITCH_VIEWS)
        self.connect(self.comboBox, SIGNAL("currentIndexChanged(int)"),
                     self.changeView)
        self.toolBar.addWidget(self.comboBox)

        self.enableToolButtons(False)
        self.layout().insertWidget(0, self.toolBar)

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

    @pyqtSlot("int")
    def changeView(self, index):
        """
        change between different views
        """
        if index == -1 or self.addingToComboBox:
            return
        self.currentTemplate = self.usedTemplates[index]
        self.displayValues()

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

    def aboutToChange(self):
        """
        Asks the user whether changes should be saved
        returns True if changes were saved, or discarded
        """
        if not self.entryModel.EDITED:
            return True

        result = QMessageBox.warning(
            self, self.str_SAVE, self.str_SAVE_CONTINUE,
            QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel,
            QMessageBox.Cancel)

        # TODO add exception message
        if result == QMessageBox.Save:
            if not self.saveObject():
                # Saving failed
                result = QMessageBox.question(
                    None, self.trUtf8(""), self.str_SAVE_FAILED,
                    QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel)
        return not (result == QMessageBox.Cancel)

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

# TODO: add logging for each error

    @pyqtSlot()
    def refreshView(self):
        """ Refreshes the LDAP data from server and displays values.
        """
        if self.aboutToChange():
            success, exceptionMsg, exceptionObject = self.entryModel.reloadModel(
            )
            if not success:
                errorMsg = "%s<br><br>%s: %s" % (exceptionMsg, self.str_REASON,
                                                 str(exceptionObject))
                QMessageBox.critical(self, self.trUtf8(""),
                                     self.trUtf8(errorMsg))
            else:
                self.displayValues()

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

# TODO: add logging for each error

    @pyqtSlot()
    def saveObject(self):
        success, exceptionMsg, exceptionObject = self.entryModel.saveModel()
        if not success:
            # Saving failed
            errorMsg = "%s<br><br>%s: %s" % (exceptionMsg, self.str_REASON,
                                             str(exceptionObject))

            QMessageBox.critical(self, self.trUtf8(""), self.trUtf8(errorMsg))
            return False
        else:
            # update the smartObject in the tree
            if self.entryModel.CREATE:
                pass
            elif self.treeIndex and self.treeIndex.isValid():
                row = self.treeIndex.row()
                column = self.treeIndex.column()
                # QPersistenIndex doesn't have internalPointer()
                # so we aquire a QModelIndex which does
                index = self.treeIndex.sibling(row, column)
                index.internalPointer().itemData = self.getSmartObject()
            return True

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

    @pyqtSlot()
    def addAttribute(self):
        """ Add attributes to the current object.
        """

        dialog = AddAttributeWizard(self)
        dialog.setData(self.smartObjectCopy(self.entryModel.getSmartObject()))

        dialog.exec_()

        if dialog.result() == QDialog.Rejected:
            return

        attribute = str(dialog.attributeBox.currentText())
        showAll = dialog.enableAllBox.isChecked()
        if dialog.binaryBox.isChecked():
            attributeSet = set([attribute + ";binary"])
        else:
            attributeSet = set([attribute])

        if showAll and not (attribute.lower() in dialog.possibleAttributes):
            objectClass = str(dialog.classBox.currentItem().text())
            self.entryModel.addObjectClass(objectClass)

            serverSchema = ObjectClassAttributeInfo(
                self.entryModel.smartObject.getServerMeta())
            mustAttributes = serverSchema.getAllMusts([objectClass])
            mustAttributes = mustAttributes.difference(
                set(self.entryModel.smartObject.getAttributeList()))
            attributeSet = mustAttributes.union(set([attribute]))

        for x in attributeSet:
            self.entryModel.addAttributeValue(x, None)

        self.displayValues()

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

# TODO: add logging for each error, remove tab and node from parent

    @pyqtSlot()
    def deleteObject(self):
        buttonClicked = QMessageBox.critical(self, self.str_DELETE,
                                             self.str_DELETE_CONFIRM,
                                             QMessageBox.Yes, QMessageBox.No)
        if not (buttonClicked == QMessageBox.Yes):
            return
        # If we have an index, use it tell the item to delete itself
        # so that the view is updated
        if self.treeIndex and self.treeIndex.isValid():
            row = self.treeIndex.row()
            column = self.treeIndex.column()
            # QPersistenIndex doesn't have internalPointer()
            # so we aquire a QModelIndex which does
            index = self.treeIndex.sibling(row, column)
            success, message = index.model().deleteItem(index)
            if success:
                self.enableToolButtons(False)
                self.deleteLater()
            else:
                errorMsg = "%s" % (message)
                QMessageBox.critical(self, self.trUtf8(""),
                                     self.trUtf8(errorMsg))
        # if not, we just delete it ourselves since there's not view on the object
        else:
            success, message, exceptionObject = self.entryModel.deleteObject()
            if success:
                self.enableToolButtons(False)
                self.deleteLater()
            else:
                errorMsg = "%s<br><br>%s: %s" % (message, self.str_REASON,
                                                 str(exceptionObject))
                QMessageBox.critical(self, self.trUtf8(""),
                                     self.trUtf8(errorMsg))

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

    @pyqtSlot("QUrl")
    def anchorClicked(self, url):
        """ Called when an anchor (<a href=".." /> is clicked
        """
        nameString = unicode(url.toString())
        tmpList = nameString.split("__")

        if tmpList[0] in self.entryModel.getSmartObject().getObjectClasses():
            self.entryModel.deleteObjectClass(tmpList[0])
        else:
            if not len(tmpList) == 3:
                return
            attributeName, index, operation = tmpList[0], int(
                tmpList[1]), tmpList[2]
            if operation == "edit":
                self.editAttribute(attributeName, index)
            elif operation == "delete":
                self.deleteAttribute(attributeName, index)
            elif operation == "export":
                self.exportAttribute(attributeName, index)

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

    def editAttribute(self, attributeName, index):
        smartObject = self.entryModel.getSmartObject()
        oldDN = smartObject.getDN()

        addAttribute = False
        if attributeName == 'RDN':
            # TODO correct this, used on creation?
            oldValue = oldDN
            smartObject.setDN(self.baseDN)
        else:
            if smartObject.hasAttribute(attributeName):
                addValue = False
                oldValue = smartObject.getAttributeValue(attributeName, index)
                if oldValue == None:
                    oldValue = ''
            else:
                addValue = True
                oldValue = ''
        dialog = getEditorWidget(self, smartObject, attributeName, index)
        dialog.exec_()

        if dialog.result() == QDialog.Accepted:
            # TODO check attribute types
            newValue = dialog.getValue()
            if not (newValue == None):
                if attributeName == 'RDN':
                    self.entryModel.setDN(newValue)
                    if dialog.addAttributeBox.isChecked():
                        addAttribute = unicode(
                            dialog.attributeBox.currentText())
                        addValue = unicode(dialog.valueEdit.text())
                        self.entryModel.addAttributeValue(
                            addAttribute, [addValue])
                else:
                    if addValue:
                        self.entryModel.addAttributeValue(
                            attributeName, [newValue])
                    else:
                        self.entryModel.editAttribute(attributeName, index,
                                                      newValue)
        else:
            if attributeName == 'RDN':
                smartObject.setDN(oldDN.decode('utf-8'))

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

    def deleteAttribute(self, attributeName, index):
        self.entryModel.deleteAttribute(attributeName, index)

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

    def exportAttribute(self, attributeName, index):
        """ Show the dialog for exporting binary attribute data.
        """
        value = self.getSmartObject().getAttributeValue(attributeName, index)


        fileName = unicode(QFileDialog.getSaveFileName(\
                            self,
                            self.str_EXPORT_BINARY,
                            QString(""),
                            "All files (*)",
                            None))

        if unicode(fileName) == "":
            return

        try:
            fileHandler = open(fileName, "w")
            fileHandler.write(value)
            fileHandler.close()
            SAVED = True
        except IOError, e:
            msg = "%s %s:\n\n%s\n\n%s" % (self.str_EXPORT_BINARY_EXCEPT,
                                          self.str_REASON, str(e),
                                          self.str_SELECT_ANOTHER_FILE)
            result = QMessageBox.warning(\
                    self,
                    self.str_EXPORT_BINARY,
                    msg,
                    QMessageBox.Cancel | QMessageBox.Ok,
                    QMessageBox.Cancel)
Пример #21
0
class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)
        
        self._info = None
        self._text = ''
        self._convertedtext = ''
        self._encoding = None
        self.mainwindow = parent
        
        self.fromVersionLabel = QLabel()
        self.fromVersion = QLineEdit()
        self.reason = QLabel()
        self.toVersionLabel = QLabel()
        self.toVersion = QLineEdit()
        self.lilyChooser = lilychooser.LilyChooser()
        self.messages = QTextBrowser()
        self.diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
        self.uni_diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
        self.copyCheck = QCheckBox(checked=
            QSettings().value('convert_ly/copy_messages', True, bool))
        self.tabw = QTabWidget()
        
        self.tabw.addTab(self.messages, '')
        self.tabw.addTab(self.diff, '')
        self.tabw.addTab(self.uni_diff, '')
        
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Reset | QDialogButtonBox.Save |
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.buttons.button(QDialogButtonBox.Ok).clicked    .connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        self.buttons.button(QDialogButtonBox.Reset).clicked.connect(self.run)
        self.buttons.button(QDialogButtonBox.Save).clicked.connect(self.saveFile)
        
        layout = QVBoxLayout()
        self.setLayout(layout)
        
        grid = QGridLayout()
        grid.addWidget(self.fromVersionLabel, 0, 0)
        grid.addWidget(self.fromVersion, 0, 1)
        grid.addWidget(self.reason, 0, 2, 1, 3)
        grid.addWidget(self.toVersionLabel, 1, 0)
        grid.addWidget(self.toVersion, 1, 1)
        grid.addWidget(self.lilyChooser, 1, 3, 1, 2)
        
        layout.addLayout(grid)
        layout.addWidget(self.tabw)
        layout.addWidget(self.copyCheck)
        layout.addWidget(widgets.Separator())
        layout.addWidget(self.buttons)
        
        app.translateUI(self)
        qutil.saveDialogSize(self, 'convert_ly/dialog/size', QSize(600, 300))
        app.settingsChanged.connect(self.readSettings)
        self.readSettings()
        self.finished.connect(self.saveCopyCheckSetting)
        self.lilyChooser.currentIndexChanged.connect(self.slotLilyPondVersionChanged)
        self.slotLilyPondVersionChanged()
        
    def translateUI(self):
        self.fromVersionLabel.setText(_("From version:"))
        self.toVersionLabel.setText(_("To version:"))
        self.copyCheck.setText(_("Save convert-ly messages in document"))
        self.copyCheck.setToolTip(_(
            "If checked, the messages of convert-ly are appended as a "
            "comment to the end of the document."))
        self.tabw.setTabText(0, _("&Messages"))
        self.tabw.setTabText(1, _("&Changes"))
        self.tabw.setTabText(2, _("&Diff"))
        self.buttons.button(QDialogButtonBox.Reset).setText(_("Run Again"))
        self.buttons.button(QDialogButtonBox.Save).setText(_("Save as file"))
        self.setCaption()
    
    def saveCopyCheckSetting(self):
        QSettings().setValue('convert_ly/copy_messages', self.copyCheck.isChecked())
    
    def readSettings(self):
        font = textformats.formatData('editor').font
        self.diff.setFont(font)
        diffFont = QFont("Monospace")
        diffFont.setStyleHint(QFont.TypeWriter)
        self.uni_diff.setFont(diffFont)
    
    def slotLilyPondVersionChanged(self):
        self.setLilyPondInfo(self.lilyChooser.lilyPondInfo())
    
    def setCaption(self):
        version = self._info and self._info.versionString() or _("<unknown>")
        title = _("Convert-ly from LilyPond {version}").format(version=version)
        self.setWindowTitle(app.caption(title))

    def setLilyPondInfo(self, info):
        self._info = info
        self.setCaption()
        self.toVersion.setText(info.versionString())
        self.setConvertedText()
        self.setDiffText()
        self.messages.clear()
    
    def setConvertedText(self, text=''):
        self._convertedtext = text
        self.buttons.button(QDialogButtonBox.Ok).setEnabled(bool(text))
        if text:
            self.diff.setHtml(htmldiff.htmldiff(
                self._text, text,
                _("Current Document"), _("Converted Document"),
                wrapcolumn=100))
        else:
            self.diff.clear()
            
    def setDiffText(self, text=''):
        if text:
            difflist = list(difflib.unified_diff(
                    self._text.split('\n'), text.split('\n'), 
                    _("Current Document"), _("Converted Document")))
            diffHLstr = self.diffHighl(difflist)
            self.uni_diff.setHtml(diffHLstr)
        else:
            self.uni_diff.clear()
    
    def convertedText(self):
        return self._convertedtext or ''
    
    def setDocument(self, doc):
        v = documentinfo.docinfo(doc).version_string()
        if v:
            self.fromVersion.setText(v)
            self.reason.setText(_("(set in document)"))
        else:
            self.reason.clear()
        self._text = doc.toPlainText()
        self._encoding = doc.encoding() or 'UTF-8'
        self.setConvertedText()
        self.setDiffText()
        
    def run(self):
        """Runs convert-ly (again)."""
        fromVersion = self.fromVersion.text()
        toVersion = self.toVersion.text()
        if not fromVersion or not toVersion:
            self.messages.setPlainText(_(
                "Both 'from' and 'to' versions need to be set."))
            return
        info = self._info
        command = info.toolcommand(info.convert_ly)
        command += ['-f', fromVersion, '-t', toVersion, '-']
        
        # if the user wants english messages, do it also here: LANGUAGE=C
        env = None
        if QSettings().value("lilypond_settings/no_translation", False, bool):
            if os.name == "nt":
                # Python 2.7 subprocess on Windows chokes on unicode in env
                env = util.bytes_environ()
                env[b'LANGUAGE'] = b'C'
            else:
                env = dict(os.environ)
                env['LANGUAGE'] = 'C'
        
        with qutil.busyCursor():
            try:
                proc = subprocess.Popen(command,
                    universal_newlines = True,
                    env = env,
                    stdin = subprocess.PIPE,
                    stdout = subprocess.PIPE,
                    stderr = subprocess.PIPE)
                out, err = proc.communicate(self._text.encode(self._encoding))
            except OSError as e:
                self.messages.setPlainText(_(
                    "Could not start {convert_ly}:\n\n"
                    "{message}\n").format(convert_ly = convert_ly, message = e))
                return
            self.messages.setPlainText(err.decode('UTF-8'))
            self.setConvertedText(out.decode('UTF-8'))
            self.setDiffText(out.decode('UTF-8'))
            if not out or self._convertedtext == self._text:
                self.messages.append('\n' + _("The document has not been changed."))

    def saveFile(self):
        """Save content in tab as file"""
        tabdata = self.getTabData(self.tabw.currentIndex())
        doc = self.mainwindow.currentDocument()
        orgname = doc.url().toLocalFile()
        filename = os.path.splitext(orgname)[0] + '['+tabdata.filename+']'+'.'+tabdata.ext
        caption = app.caption(_("dialog title", "Save File"))
        filetypes = '{0} (*.txt);;{1} (*.htm);;{2} (*)'.format(_("Text Files"), _("HTML Files"), _("All Files"))
        filename = QFileDialog.getSaveFileName(self.mainwindow, caption, filename, filetypes)
        if not filename:
            return False # cancelled
        f = open(filename, 'w')
        f.write(tabdata.text.encode('utf-8'))
        f.close()
		
    def getTabData(self, index):
        """Get content of current tab from current index"""
        if index == 0:
            return FileInfo('message', 'txt', self.messages.toPlainText())
        elif index == 1:
            return FileInfo('html-diff', 'html', self.diff.toHtml())
        elif index == 2:
            return FileInfo('uni-diff', 'diff', self.uni_diff.toPlainText())
            
    def diffHighl(self, difflist):
        """Return highlighted version of input."""
        result = []
        for l in difflist:
            if l.startswith('-'):
                s = '<span style="color: red; white-space: pre-wrap;">'
            elif l.startswith('+'):
                s = '<span style="color: green; white-space: pre-wrap;">'
            else:
                s = '<span style="white-space: pre-wrap;">'
            h = l.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
            result.append(s + h + '</span>')
        return '<br>'.join(result)
Пример #22
0
class PluginsManagerWidget(QDialog):
    """Plugin Manager widget"""

    def __init__(self, parent):
        QDialog.__init__(self, parent, Qt.Dialog)
        self.setWindowTitle(translations.TR_PLUGIN_MANAGER)
        self.resize(700, 600)

        vbox = QVBoxLayout(self)
        self._tabs = QTabWidget()
        vbox.addWidget(self._tabs)
        self._txt_data = QTextBrowser()
        self._txt_data.setOpenLinks(False)
        vbox.addWidget(QLabel(translations.TR_PROJECT_DESCRIPTION))
        vbox.addWidget(self._txt_data)
        # Footer
        hbox = QHBoxLayout()
        btn_close = QPushButton(translations.TR_CLOSE)
        btnReload = QPushButton(translations.TR_RELOAD)
        hbox.addWidget(btn_close)
        hbox.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding))
        hbox.addWidget(btnReload)
        vbox.addLayout(hbox)
        self.overlay = ui_tools.Overlay(self)
        self.overlay.hide()

        self._oficial_available = []
        self._community_available = []
        self._locals = []
        self._updates = []
        self._loading = True
        self._requirements = {}

        self.connect(btnReload, SIGNAL("clicked()"), self._reload_plugins)
        self.thread = ThreadLoadPlugins(self)
        self.connect(self.thread, SIGNAL("finished()"),
            self._load_plugins_data)
        self.connect(self.thread, SIGNAL("plugin_downloaded(PyQt_PyObject)"),
            self._after_download_plugin)
        self.connect(self.thread,
            SIGNAL("plugin_manually_installed(PyQt_PyObject)"),
            self._after_manual_install_plugin)
        self.connect(self.thread, SIGNAL("plugin_uninstalled(PyQt_PyObject)"),
            self._after_uninstall_plugin)
        self.connect(self._txt_data, SIGNAL("anchorClicked(const QUrl&)"),
            self._open_link)
        self.connect(btn_close, SIGNAL('clicked()'), self.close)
        self.overlay.show()
        self._reload_plugins()

    def show_plugin_info(self, data):
        """Takes data argument, format for HTML and display it"""
        plugin_description = data[2].replace('\n', '<br>')
        html = HTML_STYLE.format(name=data[0],
            version=data[1], description=plugin_description,
            author=data[3], link=data[4])
        self._txt_data.setHtml(html)

    def _open_link(self, url):
        """Takes an url argument and open the link on web browser"""
        link = url.toString()
        if link.startswith('/plugins/'):
            link = 'http://ninja-ide.org' + link
        webbrowser.open(link)

    def _reload_plugins(self):
        """Reload all plugins"""
        self.overlay.show()
        self._loading = True
        self.thread.runnable = self.thread.collect_data_thread
        self.thread.start()

    def _after_manual_install_plugin(self, plugin):
        """After installing, take plugin and add it to installedWidget items"""
        data = {}
        data['name'] = plugin[0]
        data['version'] = plugin[1]
        data['description'] = ''
        data['authors'] = ''
        data['home'] = ''
        self._installedWidget.add_table_items([data])

    def _after_download_plugin(self, plugin):
        """After installing, take plugin and add it to installedWidget items"""
        oficial_plugin = _get_plugin(plugin[0], self._oficial_available)
        community_plugin = _get_plugin(plugin[0], self._community_available)
        if oficial_plugin:
            self._installedWidget.add_table_items([oficial_plugin])
            self._availableOficialWidget.remove_item(plugin[0])
        elif community_plugin:
            self._installedWidget.add_table_items([community_plugin])
            self._availableCommunityWidget.remove_item(plugin[0])

    def _after_uninstall_plugin(self, plugin):
        """After uninstall plugin,make available plugin corresponding to type"""
        oficial_plugin = _get_plugin(plugin[0], self._oficial_available)
        community_plugin = _get_plugin(plugin[0], self._community_available)
        if oficial_plugin:
            self._availableOficialWidget.add_table_items([oficial_plugin])
            self._installedWidget.remove_item(plugin[0])
        elif community_plugin:
            self._availableCommunityWidget.add_table_items([community_plugin])
            self._installedWidget.remove_item(plugin[0])

    def _load_plugins_data(self):
        """Load all the plugins data"""
        if self._loading:
            self._tabs.clear()
            self._updatesWidget = UpdatesWidget(self, copy(self._updates))
            self._availableOficialWidget = AvailableWidget(self,
                copy(self._oficial_available))
            self._availableCommunityWidget = AvailableWidget(self,
                copy(self._community_available))
            self._installedWidget = InstalledWidget(self, copy(self._locals))
            self._tabs.addTab(self._availableOficialWidget,
                translations.TR_OFFICIAL_AVAILABLE)
            self._tabs.addTab(self._availableCommunityWidget,
                translations.TR_COMMUNITY_AVAILABLE)
            self._tabs.addTab(self._updatesWidget, translations.TR_UPDATE)
            self._tabs.addTab(self._installedWidget, translations.TR_INSTALLED)
            self._manualWidget = ManualInstallWidget(self)
            self._tabs.addTab(self._manualWidget,
                translations.TR_MANUAL_INSTALL)
            self._loading = False
        self.overlay.hide()
        self.thread.wait()

    def download_plugins(self, plugs):
        """
        Install
        """
        self.overlay.show()
        self.thread.plug = plugs
        #set the function to run in the thread
        self.thread.runnable = self.thread.download_plugins_thread
        self.thread.start()

    def install_plugins_manually(self, plug):
        """Install plugin from local zip."""
        self.overlay.show()
        self.thread.plug = plug
        #set the function to run in the thread
        self.thread.runnable = self.thread.manual_install_plugins_thread
        self.thread.start()

    def mark_as_available(self, plugs):
        """
        Uninstall
        """
        self.overlay.show()
        self.thread.plug = plugs
        #set the function to run in the thread
        self.thread.runnable = self.thread.uninstall_plugins_thread
        self.thread.start()

    def update_plugin(self, plugs):
        """
        Update
        """
        self.overlay.show()
        self.thread.plug = plugs
        #set the function to run in the thread
        self.thread.runnable = self.thread.update_plugin_thread
        self.thread.start()

    def reset_installed_plugins(self):
        """Reset all the installed plugins"""
        local_plugins = plugin_manager.local_plugins()
        plugins = _format_for_table(local_plugins)
        self._installedWidget.reset_table(plugins)

    def resizeEvent(self, event):
        """Handle Resize events"""
        self.overlay.resize(event.size())
        event.accept()
Пример #23
0
class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)

        self._info = None
        self._text = ''
        self._convertedtext = ''
        self._encoding = None
        self.mainwindow = parent

        self.fromVersionLabel = QLabel()
        self.fromVersion = QLineEdit()
        self.reason = QLabel()
        self.toVersionLabel = QLabel()
        self.toVersion = QLineEdit()
        self.lilyChooser = lilychooser.LilyChooser()
        self.messages = QTextBrowser()
        self.diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
        self.uni_diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
        self.copyCheck = QCheckBox(
            checked=QSettings().value('convert_ly/copy_messages', True, bool))
        self.tabw = QTabWidget()

        self.tabw.addTab(self.messages, '')
        self.tabw.addTab(self.diff, '')
        self.tabw.addTab(self.uni_diff, '')

        self.buttons = QDialogButtonBox(QDialogButtonBox.Reset
                                        | QDialogButtonBox.Save
                                        | QDialogButtonBox.Ok
                                        | QDialogButtonBox.Cancel)
        self.buttons.button(QDialogButtonBox.Ok).clicked.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        self.buttons.button(QDialogButtonBox.Reset).clicked.connect(self.run)
        self.buttons.button(QDialogButtonBox.Save).clicked.connect(
            self.saveFile)

        layout = QVBoxLayout()
        self.setLayout(layout)

        grid = QGridLayout()
        grid.addWidget(self.fromVersionLabel, 0, 0)
        grid.addWidget(self.fromVersion, 0, 1)
        grid.addWidget(self.reason, 0, 2, 1, 3)
        grid.addWidget(self.toVersionLabel, 1, 0)
        grid.addWidget(self.toVersion, 1, 1)
        grid.addWidget(self.lilyChooser, 1, 3, 1, 2)

        layout.addLayout(grid)
        layout.addWidget(self.tabw)
        layout.addWidget(self.copyCheck)
        layout.addWidget(widgets.Separator())
        layout.addWidget(self.buttons)

        app.translateUI(self)
        qutil.saveDialogSize(self, 'convert_ly/dialog/size', QSize(600, 300))
        app.settingsChanged.connect(self.readSettings)
        self.readSettings()
        self.finished.connect(self.saveCopyCheckSetting)
        self.lilyChooser.currentIndexChanged.connect(
            self.slotLilyPondVersionChanged)
        self.slotLilyPondVersionChanged()

    def translateUI(self):
        self.fromVersionLabel.setText(_("From version:"))
        self.toVersionLabel.setText(_("To version:"))
        self.copyCheck.setText(_("Save convert-ly messages in document"))
        self.copyCheck.setToolTip(
            _("If checked, the messages of convert-ly are appended as a "
              "comment to the end of the document."))
        self.tabw.setTabText(0, _("&Messages"))
        self.tabw.setTabText(1, _("&Changes"))
        self.tabw.setTabText(2, _("&Diff"))
        self.buttons.button(QDialogButtonBox.Reset).setText(_("Run Again"))
        self.buttons.button(QDialogButtonBox.Save).setText(_("Save as file"))
        self.setCaption()

    def saveCopyCheckSetting(self):
        QSettings().setValue('convert_ly/copy_messages',
                             self.copyCheck.isChecked())

    def readSettings(self):
        font = textformats.formatData('editor').font
        self.diff.setFont(font)
        diffFont = QFont("Monospace")
        diffFont.setStyleHint(QFont.TypeWriter)
        self.uni_diff.setFont(diffFont)

    def slotLilyPondVersionChanged(self):
        self.setLilyPondInfo(self.lilyChooser.lilyPondInfo())

    def setCaption(self):
        version = self._info and self._info.versionString() or _("<unknown>")
        title = _("Convert-ly from LilyPond {version}").format(version=version)
        self.setWindowTitle(app.caption(title))

    def setLilyPondInfo(self, info):
        self._info = info
        self.setCaption()
        self.toVersion.setText(info.versionString())
        self.setConvertedText()
        self.setDiffText()
        self.messages.clear()

    def setConvertedText(self, text=''):
        self._convertedtext = text
        self.buttons.button(QDialogButtonBox.Ok).setEnabled(bool(text))
        if text:
            self.diff.setHtml(
                htmldiff.htmldiff(self._text,
                                  text,
                                  _("Current Document"),
                                  _("Converted Document"),
                                  wrapcolumn=100))
        else:
            self.diff.clear()

    def setDiffText(self, text=''):
        if text:
            difflist = list(
                difflib.unified_diff(self._text.split('\n'), text.split('\n'),
                                     _("Current Document"),
                                     _("Converted Document")))
            diffHLstr = self.diffHighl(difflist)
            self.uni_diff.setHtml(diffHLstr)
        else:
            self.uni_diff.clear()

    def convertedText(self):
        return self._convertedtext or ''

    def setDocument(self, doc):
        v = documentinfo.docinfo(doc).version_string()
        if v:
            self.fromVersion.setText(v)
            self.reason.setText(_("(set in document)"))
        else:
            self.reason.clear()
        self._text = doc.toPlainText()
        self._encoding = doc.encoding() or 'UTF-8'
        self.setConvertedText()
        self.setDiffText()

    def run(self):
        """Runs convert-ly (again)."""
        fromVersion = self.fromVersion.text()
        toVersion = self.toVersion.text()
        if not fromVersion or not toVersion:
            self.messages.setPlainText(
                _("Both 'from' and 'to' versions need to be set."))
            return
        info = self._info
        command = info.toolcommand(info.ly_tool('convert-ly'))
        command += ['-f', fromVersion, '-t', toVersion, '-']

        # if the user wants english messages, do it also here: LANGUAGE=C
        env = None
        if os.name == "nt":
            # Python 2.7 subprocess on Windows chokes on unicode in env
            env = util.bytes_environ()
        else:
            env = dict(os.environ)
        if sys.platform.startswith('darwin'):
            try:
                del env['PYTHONHOME']
            except KeyError:
                pass
            try:
                del env['PYTHONPATH']
            except KeyError:
                pass
        if QSettings().value("lilypond_settings/no_translation", False, bool):
            if os.name == "nt":
                # Python 2.7 subprocess on Windows chokes on unicode in env
                env[b'LANGUAGE'] = b'C'
            else:
                env['LANGUAGE'] = 'C'

        with qutil.busyCursor():
            try:
                proc = subprocess.Popen(command,
                                        env=env,
                                        stdin=subprocess.PIPE,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)
                out, err = proc.communicate(
                    util.platform_newlines(self._text).encode(self._encoding))
            except OSError as e:
                self.messages.setPlainText(
                    _("Could not start {convert_ly}:\n\n"
                      "{message}\n").format(convert_ly=command[0], message=e))
                return
            out = util.universal_newlines(out.decode('UTF-8'))
            err = util.universal_newlines(err.decode('UTF-8'))
            self.messages.setPlainText(err)
            self.setConvertedText(out)
            self.setDiffText(out)
            if not out or self._convertedtext == self._text:
                self.messages.append('\n' +
                                     _("The document has not been changed."))

    def saveFile(self):
        """Save content in tab as file"""
        tabdata = self.getTabData(self.tabw.currentIndex())
        doc = self.mainwindow.currentDocument()
        orgname = doc.url().toLocalFile()
        filename = os.path.splitext(
            orgname)[0] + '[' + tabdata.filename + ']' + '.' + tabdata.ext
        caption = app.caption(_("dialog title", "Save File"))
        filetypes = '{0} (*.txt);;{1} (*.htm);;{2} (*)'.format(
            _("Text Files"), _("HTML Files"), _("All Files"))
        filename = QFileDialog.getSaveFileName(self.mainwindow, caption,
                                               filename, filetypes)
        if not filename:
            return False  # cancelled
        with open(filename, 'wb') as f:
            f.write(tabdata.text.encode('utf-8'))

    def getTabData(self, index):
        """Get content of current tab from current index"""
        if index == 0:
            return FileInfo('message', 'txt', self.messages.toPlainText())
        elif index == 1:
            return FileInfo('html-diff', 'html', self.diff.toHtml())
        elif index == 2:
            return FileInfo('uni-diff', 'diff', self.uni_diff.toPlainText())

    def diffHighl(self, difflist):
        """Return highlighted version of input."""
        result = []
        for l in difflist:
            if l.startswith('-'):
                s = '<span style="color: red; white-space: pre-wrap;">'
            elif l.startswith('+'):
                s = '<span style="color: green; white-space: pre-wrap;">'
            else:
                s = '<span style="white-space: pre-wrap;">'
            h = l.replace('&', '&amp;').replace('<',
                                                '&lt;').replace('>', '&gt;')
            result.append(s + h + '</span>')
        return '<br>'.join(result)
Пример #24
0
class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)

        self._info = None
        self._text = ''
        self._convertedtext = ''
        self._encoding = None

        self.fromVersionLabel = QLabel()
        self.fromVersion = QLineEdit()
        self.reason = QLabel()
        self.toVersionLabel = QLabel()
        self.toVersion = QLineEdit()
        self.lilyChooser = lilychooser.LilyChooser()
        self.messages = QTextBrowser()
        self.diff = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)
        self.copyCheck = QCheckBox(
            checked=QSettings().value('convert_ly/copy_messages', True, bool))
        self.tabw = QTabWidget()

        self.tabw.addTab(self.messages, '')
        self.tabw.addTab(self.diff, '')

        self.buttons = QDialogButtonBox(QDialogButtonBox.Reset
                                        | QDialogButtonBox.Ok
                                        | QDialogButtonBox.Cancel)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        self.buttons.button(QDialogButtonBox.Reset).clicked.connect(self.run)

        layout = QVBoxLayout()
        self.setLayout(layout)

        grid = QGridLayout()
        grid.addWidget(self.fromVersionLabel, 0, 0)
        grid.addWidget(self.fromVersion, 0, 1)
        grid.addWidget(self.reason, 0, 2, 1, 3)
        grid.addWidget(self.toVersionLabel, 1, 0)
        grid.addWidget(self.toVersion, 1, 1)
        grid.addWidget(self.lilyChooser, 1, 3, 1, 2)

        layout.addLayout(grid)
        layout.addWidget(self.tabw)
        layout.addWidget(self.copyCheck)
        layout.addWidget(widgets.Separator())
        layout.addWidget(self.buttons)

        app.translateUI(self)
        qutil.saveDialogSize(self, 'convert_ly/dialog/size', QSize(600, 300))
        app.settingsChanged.connect(self.readSettings)
        self.readSettings()
        self.finished.connect(self.saveCopyCheckSetting)
        self.lilyChooser.currentIndexChanged.connect(
            self.slotLilyPondVersionChanged)
        self.slotLilyPondVersionChanged()

    def translateUI(self):
        self.fromVersionLabel.setText(_("From version:"))
        self.toVersionLabel.setText(_("To version:"))
        self.copyCheck.setText(_("Save convert-ly messages in document"))
        self.copyCheck.setToolTip(
            _("If checked, the messages of convert-ly are appended as a "
              "comment to the end of the document."))
        self.tabw.setTabText(0, _("&Messages"))
        self.tabw.setTabText(1, _("&Changes"))
        self.buttons.button(QDialogButtonBox.Reset).setText(_("Run Again"))
        self.setCaption()

    def saveCopyCheckSetting(self):
        QSettings().setValue('convert_ly/copy_messages',
                             self.copyCheck.isChecked())

    def readSettings(self):
        font = textformats.formatData('editor').font
        self.diff.setFont(font)

    def slotLilyPondVersionChanged(self):
        self.setLilyPondInfo(self.lilyChooser.lilyPondInfo())

    def setCaption(self):
        version = self._info and self._info.versionString() or _("<unknown>")
        title = _("Convert-ly from LilyPond {version}").format(version=version)
        self.setWindowTitle(app.caption(title))

    def setLilyPondInfo(self, info):
        self._info = info
        self.setCaption()
        self.toVersion.setText(info.versionString())
        self.setConvertedText()
        self.messages.clear()

    def setConvertedText(self, text=''):
        self._convertedtext = text
        self.buttons.button(QDialogButtonBox.Ok).setEnabled(bool(text))
        if text:
            self.diff.setHtml(
                htmldiff.htmldiff(self._text,
                                  text,
                                  _("Current Document"),
                                  _("Converted Document"),
                                  wrapcolumn=100))
        else:
            self.diff.clear()

    def convertedText(self):
        return self._convertedtext or ''

    def setDocument(self, doc):
        v = documentinfo.docinfo(doc).version_string()
        if v:
            self.fromVersion.setText(v)
            self.reason.setText(_("(set in document)"))
        else:
            self.reason.clear()
        self._text = doc.toPlainText()
        self._encoding = doc.encoding() or 'UTF-8'
        self.setConvertedText()

    def run(self):
        """Runs convert-ly (again)."""
        fromVersion = self.fromVersion.text()
        toVersion = self.toVersion.text()
        if not fromVersion or not toVersion:
            self.messages.setPlainText(
                _("Both 'from' and 'to' versions need to be set."))
            return
        info = self._info
        command = info.toolcommand(info.convert_ly)
        command += ['-f', fromVersion, '-t', toVersion, '-']

        # if the user wants english messages, do it also here: LANGUAGE=C
        env = None
        if QSettings().value("lilypond_settings/no_translation", False, bool):
            if os.name == "nt":
                # Python 2.7 subprocess on Windows chokes on unicode in env
                env = util.bytes_environ()
                env[b'LANGUAGE'] = b'C'
            else:
                env = dict(os.environ)
                env['LANGUAGE'] = 'C'

        with qutil.busyCursor():
            try:
                proc = subprocess.Popen(command,
                                        universal_newlines=True,
                                        env=env,
                                        stdin=subprocess.PIPE,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)
                out, err = proc.communicate(self._text.encode(self._encoding))
            except OSError as e:
                self.messages.setPlainText(
                    _("Could not start {convert_ly}:\n\n"
                      "{message}\n").format(convert_ly=convert_ly, message=e))
                return
            self.messages.setPlainText(err.decode('UTF-8'))
            self.setConvertedText(out.decode('UTF-8'))
            if not out or self._convertedtext == self._text:
                self.messages.append('\n' +
                                     _("The document has not been changed."))
Пример #25
0
class AdvancedObjectWidget(QWidget):

    def __init__(self, index, currentTemplate="classic.html", parent=None, entryTemplate = None):
        QWidget.__init__(self, parent)

        w = 24
        h = 24
        self.entryModel = None

        # Standard pixmaps used by the widget
        self.reloadPixmap = pixmapFromTheme(
            "view-refresh", ":/icons/32/view-refresh", w, h)
        self.savePixmap = pixmapFromTheme(
            "document-save", ":/icons/32/document-save",w, h)
        self.addPixmap = pixmapFromTheme(
            "list-add", ":/icons/32/list-add", w, h)
        self.deleteSmallPixmap = pixmapFromTheme(
            "list-remove", ":/icons/32/list-remove", w, h)

        self.treeIndex = index

        self.setLayout(QVBoxLayout(self))
        self.layout().setSpacing(0)
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        # create the widget containing the data
        self.textBrowser = QTextBrowser()
        self.textBrowser.setOpenLinks(False)
        self.textBrowser.setWordWrapMode(QTextOption.WrapAnywhere)
        self.layout().addWidget(self.textBrowser)
        self.textBrowser.anchorClicked.connect(self.anchorClicked)

        self.currentDocument = ''
        self.addingToComboBox = False

        # create the combobox containing the different views
        self.comboBox = QComboBox()
        self.currentTemplate = currentTemplate
        self.errorTemplate = "error.html"
        self.usedTemplates = []
        # FIXED: Need a more robust way for locating the path used in
        #        the TemplateFactory for locating the template view
        #        files
        # >>>    with base.util.Paths.getLumaRoot this should work.
        #        Probably needs some validation testing on platforms
        #        other than Linux
        # Another issue occured when running Luma after a installation
        # from a source distribution. Because the site-packages is only
        # intended for pure python modules, the html templates is not
        # installed, resulting in an Exception when trying to view an
        # entry in the Browser plugin. The setup.py script is modified
        # such that the needed html templates is copied into a folder
        # in the path returned by `base.util.Paths.getConfigPrefix`.
        s = QtCore.QSettings()
        configPrefix = s.value('application/config_prefix').toString()
        templatesPath = os.path.join(unicode(configPrefix).encode('utf-8'),
                                     'browser-templates')
        # If we run Luma from a development environment the isntalled
        # templatesPath do most likely not exist. We therefore use the
        # directory in the repository
        if not os.path.isdir(templatesPath):
            templatesPath = unicode(
                os.path.join(
                    getLumaRoot(), 'plugins', 'browser', 'templates')
            )

        self.templateFactory = TemplateFactory(templatesPath)

        self.htmlParser = HtmlParser(self.textBrowser)

        self.str_RELOAD= QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Reload")
        self.str_SAVE = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Save entry")
        self.str_SAVE_CONTINUE = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Do you want to save the entry before continuing?")
        self.str_SAVE_FAILED = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Saving failed, continue anyway?")
        self.str_DELETE = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Delete object")
        self.str_DELETE_CONFIRM = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Do you really want to delete the object?")
        self.str_ADD = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Add attribute")
        self.str_SWITCH_VIEWS = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Switch between views")
        self.str_REASON = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Reason:")
        self.str_EXPORT_BINARY = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Export binary attribute to file")
        self.str_EXPORT_BINARY_EXCEPT = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Could not export binary data to file.")
        self.str_SELECT_ANOTHER_FILE = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Please select another filename.")
        self.str_NO_TEMPLATE = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "No templates available")
        self.str_MISSING_ENTRY = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "Did'nt receive a ldap-object, it might have been deleted")
        self.str_ENTRY_INVALID = QtCore.QCoreApplication.translate("AdvancedObjectWidget",
            "The ldap object is not valid\nClick Yes to view the object anyway\nNo to view the errors \nIgnore to view the object and ignore this message in later attempts.")

        self.buildToolBar()

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

    @staticmethod
    def smartObjectCopy(smartObject):
        return SmartDataObject(copy.deepcopy([smartObject.dn, smartObject.data]), copy.deepcopy(smartObject.serverMeta))

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

    def getSmartObject(self):
        return self.entryModel.getSmartObject()

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

    def initModel(self, smartObject, create=False, entryTemplate = None):
        """ sets up the model, and connects it to this object
        """
        if not create:
            # use a copy of the smartObject
            smartObject = AdvancedObjectWidget.smartObjectCopy(smartObject)
        self.baseDN = smartObject.getDN()
        self.entryModel = EntryModel(smartObject, self, entryTemplate)
        self.htmlParser.setModel(self.entryModel)
        self.entryModel.modelChangedSignal.connect(self.modelChanged)
        success, exceptionMsg, exceptionObject = self.entryModel.initModel(create)
        if not success:
            errorMsg = "%s<br><br>%s: %s" % (exceptionMsg, self.str_REASON, str(exceptionObject))
            QMessageBox.critical(self,
                                self.trUtf8(""),
                                self.trUtf8(errorMsg))

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

    def loadTemplates(self):
        """ Loads all templates that matches with the current objectclasses
        """
        self.usedTemplates = []
        objectClasses = self.getSmartObject().getObjectClasses()
        newIndex = -1
        i = 0
        for objectClass, fileName in self.templateFactory.getTemplateList():
            if objectClass == '' or objectClass in objectClasses:
                if fileName == self.currentTemplate:
                    newIndex = i
                self.usedTemplates.append(fileName)
                i += 1
        if newIndex == -1:
            newIndex = 0
        self.currentTemplate = self.usedTemplates[newIndex]
        #TODO do this properly, signals ignored
        self.addingToComboBox = True
        self.comboBox.clear()
        self.comboBox.addItems(self.usedTemplates)
        self.comboBox.setCurrentIndex(newIndex)
        self.addingToComboBox = False


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

    @pyqtSlot(bool)
    def modelChanged(self, reload):
        if reload:
            item = None
            if self.treeIndex and self.treeIndex.isValid():
                row = self.treeIndex.row()
                column = self.treeIndex.column()
                # QPersistenIndex doesn't have internalPointer()
                # so we aquire a QModelIndex which does
                item = self.treeIndex.sibling(row,column).internalPointer()
            if not(self.entryModel.VALID):
                if item == None or not(item.serverParent.ignoreItemErrors):
                    result = QMessageBox.question(self,
                                        self.trUtf8(""),
                                        self.str_ENTRY_INVALID,
                                        QMessageBox.Yes | QMessageBox.No | QMessageBox.Ignore,
                                        QMessageBox.No)
                    if result == QMessageBox.No:
                        self.currentTemplate = self.errorTemplate
                    elif result == QMessageBox.Ignore:
                        if not(item == None):
                            item.serverParent.ignoreItemErrors = True
        self.displayValues()

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

    def displayValues(self):
        # Something went wrong. We have no data object.
        # This might happen if we want to refresh an item and
        # it might be deleted already.
        if None == self.entryModel.getSmartObject():
            QMessageBox.critical(self, self.str_MISSING_ENTRY)
            self.enableToolButtons(False)
            return

        self.loadTemplates()
        if self.currentTemplate == None:
            selt.textBrowser.setHtml(self.str_NO_TEMPLATE)
            return
        htmlTemplate = self.templateFactory.getTemplateFile(self.currentTemplate)
        self.currentDocument = self.htmlParser.parseHtml(htmlTemplate)
        self.textBrowser.setHtml(self.currentDocument)

        self.enableToolButtons(True)

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

    def enableToolButtons(self, enable):
        if None == self.entryModel:
            self.saveButton.setEnabled(False)
            self.deleteObjectButton.setEnabled(False)
            self.reloadButton.setEnabled(True)
            self.addAttributeButton.setEnabled(False)
            return
        if self.entryModel.EDITED and not self.entryModel.CREATE:
            self.saveButton.setEnabled(enable)
        else:
            self.saveButton.setEnabled(False)

        if self.entryModel.ISLEAF:
            self.deleteObjectButton.setEnabled(enable)
        else:
            self.deleteObjectButton.setEnabled(False)

        if self.entryModel.CREATE:
            self.reloadButton.setEnabled(False)
        else:
            self.reloadButton.setEnabled(enable)

        self.addAttributeButton.setEnabled(enable)



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

    def buildToolBar(self):
        self.toolBar = QToolBar()
        self.toolBar.layout().setContentsMargins(0, 0, 0, 0)

        # Reload button
        self.reloadButton = QToolButton(self.toolBar)
        self.reloadButton.setIcon(QIcon(self.reloadPixmap))
        self.reloadButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.reloadButton.setAutoRaise(True)
        self.reloadButton.setBackgroundRole(self.backgroundRole())
        self.reloadButton.setToolTip(self.str_RELOAD)
        self.connect(self.reloadButton, SIGNAL("clicked()"), self.refreshView)
        self.toolBar.addWidget(self.reloadButton)


        # Save button
        self.saveButton = QToolButton(self.toolBar)
        self.saveButton.setIcon(QIcon(self.savePixmap))
        self.saveButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.saveButton.setAutoRaise(True)
        self.saveButton.setBackgroundRole(self.backgroundRole())
        self.saveButton.setToolTip(self.str_SAVE)
        self.connect(self.saveButton, SIGNAL("clicked()"), self.saveObject)
        self.toolBar.addWidget(self.saveButton)

        self.toolBar.addSeparator()

        # Add attribute button
        self.addAttributeButton = QToolButton(self.toolBar)
        self.addAttributeButton.setIcon(QIcon(self.addPixmap))
        self.addAttributeButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.addAttributeButton.setAutoRaise(True)
        self.addAttributeButton.setBackgroundRole(self.backgroundRole())
        self.addAttributeButton.setToolTip(self.str_ADD)
        self.connect(self.addAttributeButton, SIGNAL("clicked()"), self.addAttribute)
        self.toolBar.addWidget(self.addAttributeButton)

        # Delete button
        self.deleteObjectButton = QToolButton(self.toolBar)
        self.deleteObjectButton.setIcon(QIcon(self.deleteSmallPixmap))
        self.deleteObjectButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.deleteObjectButton.setAutoRaise(True)
        self.deleteObjectButton.setBackgroundRole(self.backgroundRole())
        self.deleteObjectButton.setToolTip(self.str_DELETE)
        self.connect(self.deleteObjectButton, SIGNAL("clicked()"), self.deleteObject)
        self.toolBar.addWidget(self.deleteObjectButton)

        self.comboBox.setToolTip(self.str_SWITCH_VIEWS)
        self.connect(self.comboBox, SIGNAL("currentIndexChanged(int)"), self.changeView)
        self.toolBar.addWidget(self.comboBox)

        self.enableToolButtons(False)
        self.layout().insertWidget(0, self.toolBar)

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

    @pyqtSlot("int")
    def changeView(self, index):
        """
        change between different views
        """
        if index == -1 or self.addingToComboBox:
            return
        self.currentTemplate = self.usedTemplates[index]
        self.displayValues()

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

    def aboutToChange(self):
        """
        Asks the user whether changes should be saved
        returns True if changes were saved, or discarded
        """
        if not self.entryModel.EDITED:
            return True

        result = QMessageBox.warning(self,
            self.str_SAVE,
            self.str_SAVE_CONTINUE,
            QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel,
            QMessageBox.Cancel)


        # TODO add exception message
        if result == QMessageBox.Save:
            if not self.saveObject():
                # Saving failed
                result = QMessageBox.question(None,
                            self.trUtf8(""),
                            self.str_SAVE_FAILED,
                            QMessageBox.Ok | QMessageBox.Cancel,
                            QMessageBox.Cancel)
        return not(result == QMessageBox.Cancel)

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

    # TODO: add logging for each error
    @pyqtSlot()
    def refreshView(self):
        """ Refreshes the LDAP data from server and displays values.
        """
        if self.aboutToChange():
            success, exceptionMsg, exceptionObject = self.entryModel.reloadModel()
            if not success:
                errorMsg = "%s<br><br>%s: %s" % (exceptionMsg, self.str_REASON, str(exceptionObject))
                QMessageBox.critical(self, self.trUtf8(""), self.trUtf8(errorMsg))
            else:
                self.displayValues()

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

    # TODO: add logging for each error
    @pyqtSlot()
    def saveObject(self):
        success, exceptionMsg, exceptionObject = self.entryModel.saveModel()
        if not success:
            # Saving failed
            errorMsg = "%s<br><br>%s: %s" % (exceptionMsg, self.str_REASON, str(exceptionObject))

            QMessageBox.critical(self, self.trUtf8(""), self.trUtf8(errorMsg))
            return False
        else:
            # update the smartObject in the tree
            if self.entryModel.CREATE:
                pass
            elif self.treeIndex and self.treeIndex.isValid():
                row = self.treeIndex.row()
                column = self.treeIndex.column()
                # QPersistenIndex doesn't have internalPointer()
                # so we aquire a QModelIndex which does
                index = self.treeIndex.sibling(row,column)
                index.internalPointer().itemData = self.getSmartObject()
            return True

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

    @pyqtSlot()
    def addAttribute(self):
        """ Add attributes to the current object.
        """

        dialog = AddAttributeWizard(self)
        dialog.setData(self.smartObjectCopy(self.entryModel.getSmartObject()))

        dialog.exec_()

        if dialog.result() == QDialog.Rejected:
            return

        attribute = str(dialog.attributeBox.currentText())
        showAll = dialog.enableAllBox.isChecked()
        if dialog.binaryBox.isChecked():
            attributeSet = set([attribute + ";binary"])
        else:
            attributeSet = set([attribute])

        if showAll and not(attribute.lower() in dialog.possibleAttributes):
            objectClass = str(dialog.classBox.currentItem().text())
            self.entryModel.addObjectClass(objectClass)

            serverSchema = ObjectClassAttributeInfo(self.entryModel.smartObject.getServerMeta())
            mustAttributes = serverSchema.getAllMusts([objectClass])
            mustAttributes = mustAttributes.difference(set(self.entryModel.smartObject.getAttributeList()))
            attributeSet = mustAttributes.union(set([attribute]))

        for x in attributeSet:
            self.entryModel.addAttributeValue(x, None)

        self.displayValues()


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

    # TODO: add logging for each error, remove tab and node from parent
    @pyqtSlot()
    def deleteObject(self):
        buttonClicked = QMessageBox.critical(self,
                            self.str_DELETE,
                            self.str_DELETE_CONFIRM,
                            QMessageBox.Yes,
                            QMessageBox.No)
        if not (buttonClicked == QMessageBox.Yes):
            return
        # If we have an index, use it tell the item to delete itself
        # so that the view is updated
        if self.treeIndex and self.treeIndex.isValid():
            row = self.treeIndex.row()
            column = self.treeIndex.column()
            # QPersistenIndex doesn't have internalPointer()
            # so we aquire a QModelIndex which does
            index = self.treeIndex.sibling(row,column)
            success, message = index.model().deleteItem(index)
            if success:
                self.enableToolButtons(False)
                self.deleteLater()
            else:
                errorMsg = "%s" % (message)
                QMessageBox.critical(self, self.trUtf8(""), self.trUtf8(errorMsg))
        # if not, we just delete it ourselves since there's not view on the object
        else:
            success, message, exceptionObject = self.entryModel.deleteObject()
            if success:
                self.enableToolButtons(False)
                self.deleteLater()
            else:
                errorMsg = "%s<br><br>%s: %s" % (message, self.str_REASON, str(exceptionObject))
                QMessageBox.critical(self, self.trUtf8(""), self.trUtf8(errorMsg))

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

    @pyqtSlot("QUrl")
    def anchorClicked(self, url):
        """ Called when an anchor (<a href=".." /> is clicked
        """
        nameString = unicode(url.toString())
        tmpList = nameString.split("__")

        if tmpList[0] in self.entryModel.getSmartObject().getObjectClasses():
            self.entryModel.deleteObjectClass(tmpList[0])
        else:
            if not len(tmpList) == 3:
                return
            attributeName, index, operation = tmpList[0], int(tmpList[1]), tmpList[2]
            if operation == "edit":
                self.editAttribute(attributeName, index)
            elif operation == "delete":
                self.deleteAttribute(attributeName, index)
            elif operation == "export":
                self.exportAttribute(attributeName, index)

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

    def editAttribute(self, attributeName, index):
        smartObject = self.entryModel.getSmartObject()
        oldDN = smartObject.getDN()

        addAttribute = False
        if attributeName == 'RDN':
            # TODO correct this, used on creation?
            oldValue = oldDN
            smartObject.setDN(self.baseDN)
        else:
            if smartObject.hasAttribute(attributeName):
                addValue = False
                oldValue = smartObject.getAttributeValue(attributeName, index)
                if oldValue == None:
                    oldValue = ''
            else:
                addValue = True
                oldValue = ''
        dialog = getEditorWidget(self, smartObject, attributeName, index)
        dialog.exec_()

        if dialog.result() == QDialog.Accepted:
            # TODO check attribute types
            newValue = dialog.getValue()
            if not (newValue == None):
                if attributeName == 'RDN':
                    self.entryModel.setDN(newValue)
                    if dialog.addAttributeBox.isChecked():
                        addAttribute = unicode(dialog.attributeBox.currentText())
                        addValue = unicode(dialog.valueEdit.text())
                        self.entryModel.addAttributeValue(addAttribute, [addValue])
                else:
                    if addValue:
                        self.entryModel.addAttributeValue(attributeName, [newValue])
                    else:
                        self.entryModel.editAttribute(attributeName, index, newValue)
        else:
            if attributeName == 'RDN':
                smartObject.setDN(oldDN.decode('utf-8'))

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

    def deleteAttribute(self, attributeName, index):
        self.entryModel.deleteAttribute(attributeName, index)

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

    def exportAttribute(self, attributeName, index):
        """ Show the dialog for exporting binary attribute data.
        """
        value = self.getSmartObject().getAttributeValue(attributeName, index)


        fileName = unicode(QFileDialog.getSaveFileName(\
                            self,
                            self.str_EXPORT_BINARY,
                            QString(""),
                            "All files (*)",
                            None))

        if unicode(fileName) == "":
            return

        try:
            fileHandler = open(fileName, "w")
            fileHandler.write(value)
            fileHandler.close()
            SAVED = True
        except IOError, e:
            msg = "%s %s:\n\n%s\n\n%s" % (self.str_EXPORT_BINARY_EXCEPT,
                                          self.str_REASON,
                                          str(e),
                                          self.str_SELECT_ANOTHER_FILE)
            result = QMessageBox.warning(\
                    self,
                    self.str_EXPORT_BINARY,
                    msg,
                    QMessageBox.Cancel | QMessageBox.Ok,
                    QMessageBox.Cancel)
Пример #26
0
class filexplorerPluginMain(plugin.Plugin):
    ' main class for plugin '
    def initialize(self, *args, **kwargs):
        ' class init '
        global CONFIG_DIR
        ec = ExplorerContainer()
        super(filexplorerPluginMain, self).initialize(*args, **kwargs)

        self.dock = QDockWidget()
        self.dock.setAllowedAreas(Qt.LeftDockWidgetArea |
                                  Qt.RightDockWidgetArea)
        self.dock.setFeatures(QDockWidget.DockWidgetFloatable |
                              QDockWidget.DockWidgetMovable)
        self.dock.setWindowTitle("fileXplorer")
        self.dock.setStyleSheet('QDockWidget::title { text-align: center; }')

        # search for the truth
        self.srch = QLineEdit()
        #self.srch.resize(self.srch.size().height(), self.dock.size().width())
        self.srch.setPlaceholderText(' Search for Python files Local or PyPI ')
        self.srch.returnPressed.connect(self.search)

        # Disk Usage Bar
        self.hdbar = QProgressBar()
        if sys.platform != 'win32':
            self.hdbar.setMaximum(statvfs(HOME).f_blocks *
                statvfs(HOME).f_frsize / 1024 / 1024 / 1024)
            self.hdbar.setValue(statvfs(HOME).f_bfree *
                statvfs(HOME).f_frsize / 1024 / 1024 / 1024)
        self.hdbar.setToolTip(str(self.hdbar.value()) + '% Total Disk Use ')
        #self.hdbar.setStyleSheet('''QProgressBar{background-color:
        #QLinearGradient(spread:pad,x1:0,y1:0,x2:1,y2:1,stop:0 rgba(255,0,0,99),
        #stop:1 rgba(9,255,9,200));color:#fff;border:none;border-radius:9px;}
        #QProgressBar::chunk{background-color:QLinearGradient(spread:pad,y1:0,
        #x1:0,y2:1,x2:0.27,stop:0 rgb(0,0,0),stop:1 rgb(9,99,255));padding:0;
        #border:none;border-radius:9px;height:9px;margin:1px;}''')

        self.model = QDirModel()
        self.fileView = QColumnView(self.dock)
        self.fileView.setAlternatingRowColors(True)
        # self.fileView.setFont(QFont(self.fileView.font().setBold(True)))
        self.fileView.setIconSize(QSize(32, 32))
        self.fileView.setModel(self.model)
        self.fileView.updatePreviewWidget.connect(self.runfile)

        self.sli = QSlider()
        self.sli.setRange(16, 128)
        self.sli.setValue(32)
        self.sli.setToolTip('Icon Size: 32 px. Move Slider to change.')
        self.sli.setOrientation(Qt.Horizontal)
        self.sli.valueChanged.connect(lambda: self.fileView.setIconSize(
            QSize(self.sli.value(), self.sli.value())))
        self.sli.sliderReleased.connect(lambda:
            self.sli.setToolTip('Icon Size: ' + str(self.sli.value())))

        class TransientWidget(QWidget):
            ' persistant widget thingy '
            def __init__(self, widget_list):
                ' init sub class '
                super(TransientWidget, self).__init__()
                vbox = QVBoxLayout(self)
                for each_widget in widget_list:
                    vbox.addWidget(each_widget)

        tw = TransientWidget((self.srch, self.dock, self.sli, self.hdbar))
        ec.addTab(tw, "fileXplorer")

        ####

        self.process = QProcess()
        self.process.finished.connect(self.processFinished)

        self.preview = QLabel(self.fileView)
        self.preview.setTextFormat(0)
        self.preview.setStyleSheet('QLabel{font-size:9px;}')
        self.preview.setAutoFillBackground(True)
        self.fileView.setPreviewWidget(self.preview)
        self.dock.setWidget(self.fileView)

        # take a shot
        self.pic = QAction(QIcon.fromTheme("camera-photo"), 'Screenshot', self)
        self.pic.triggered.connect(lambda: QPixmap.grabWindow(
            QApplication.desktop().winId()).save(QFileDialog.getSaveFileName(
            self.dock, " Save Screenshot As ... ", HOME, ';;(*.png)')))

        # copy time
        self.tim = QAction(QIcon.fromTheme("user-away"),
                           'Date and Time to Clipboard', self)
        self.tim.triggered.connect(lambda: QApplication.clipboard().setText(
            datetime.now().strftime(" %A %B %d-%m-%Y %H:%M:%S %p ")))

        # color chooser
        self.cl = QAction(QIcon.fromTheme("applications-graphics"),
                          'Color Chooser to Clipboard', self)
        self.cl.triggered.connect(lambda: QApplication.clipboard().setText(
            '{}'.format(QColorDialog.getColor().name())))

        # icon chooser
        self.icn = QAction(QIcon.fromTheme("insert-image"),
                          'Icon Chooser to Clipboard', self)
        self.icn.triggered.connect(self.iconChooser)

        # tool bar with actions
        QToolBar(self.dock).addActions((self.cl, self.icn, self.tim, self.pic))

        self.textBrowser = QTextBrowser(self.dock)
        self.textBrowser.setAutoFillBackground(True)
        self.textBrowser.setGeometry(self.dock.geometry())
        self.textBrowser.hide()

    def processFinished(self):
        ' print info of finished processes '
        print(" INFO: OK: QProcess finished . . . ")

    def search(self):
        ' function to search python files '
        # get search results of python filenames local or remote
        pypi_url = 'http://pypi.python.org/pypi'
        # pypi query
        pypi = xmlrpclib.ServerProxy(pypi_url, transport=ProxyTransport())
        try:
            pypi_query = pypi.search({'name': str(self.srch.text()).lower()})
            pypi_fls = list(set(['pypi.python.org/pypi/' + a['name'] +
                   ' | pip install ' + a['name'] for a in pypi_query]))
        except:
            pypi_fls = '<b> ERROR: Internet not available! ಠ_ಠ </b>'
        s_out = ('<br> <br> <br> <h3> Search Local Python files: </h3> <hr> ' +
        # Jedi list comprehension for LOCAL search
        str(["{}/{}".format(root, f) for root, f in list(itertools.chain(*
            [list(itertools.product([root], files))
            for root, dirs, files in walk(str(
            QFileDialog.getExistingDirectory(self.dock,
            'Open Directory to Search', path.expanduser("~"))))]))
            if f.endswith(('.py', '.pyw', '.pth')) and not f.startswith('.')
            and str(self.srch.text()).lower().strip() in f]
        ).replace(',', '<br>') + '<hr><h3> Search PyPI Python files: </h3>' +
        # wraped pypi query REMOTE search
        str(pypi_fls).replace(',', '<br>') + '<hr>Auto-Proxy:ON,DoNotTrack:ON')
        # print(s_out)
        try:
            call('notify-send fileXplorer Searching...', shell=True)
        except:
            pass
        self.srch.clear()
        self.textBrowser.setGeometry(self.dock.geometry())
        self.textBrowser.setHtml(s_out)
        self.textBrowser.show()
        tmr = QTimer(self.fileView)
        tmr.timeout.connect(self.textBrowser.hide)
        tmr.start(20000)

    def iconChooser(self):
        ' Choose a Icon and copy it to clipboard '
        #
        from .std_icon_naming import std_icon_naming as a
        #
        prv = QDialog(self.dock)
        prv.setWindowFlags(Qt.FramelessWindowHint)
        prv.setAutoFillBackground(True)
        prv.setGeometry(self.fileView.geometry())
        table = QTableWidget(prv)
        table.setColumnCount(1)
        table.setRowCount(len(a))
        table.verticalHeader().setVisible(True)
        table.horizontalHeader().setVisible(False)
        table.setShowGrid(True)
        table.setIconSize(QSize(128, 128))
        for index, icon in enumerate(a):
            item = QTableWidgetItem(QIcon.fromTheme(icon), '')
            # item.setData(Qt.UserRole, '')
            item.setToolTip(icon)
            table.setItem(index, 0, item)
        table.clicked.connect(lambda: QApplication.clipboard().setText(
          'QtGui.QIcon.fromTheme("{}")'.format(table.currentItem().toolTip())))
        table.doubleClicked.connect(prv.close)
        table.resizeColumnsToContents()
        table.resizeRowsToContents()
        QLabel('<h3> <br> 1 Click Copy, 2 Clicks Close </h3>', table)
        table.resize(prv.size())
        prv.exec_()

    def runfile(self, index):
        ' run the choosed file '
        s = str(file(self.model.filePath(index), 'r').read().strip())
        f = str(self.model.filePath(index))
        # ctime is NOT crossplatform,metadata change on *nix,creation on Window
        # http://docs.python.org/library/os.path.html#os.path.getctime
        m = ''.join((f, N, str(path.getsize(f) / 1024), ' Kilobytes', N,
            str(len(file(f, 'r').readlines())), ' Lines', N,
            str(len(s.replace(N, ''))), ' Characters', N,
            str(len([a for a in sub('[^a-zA-Z0-9 ]', '', s).split(' ')
                if a != ''])), ' Words', N,
            str(len([a for a in s if a in punctuation])), ' Punctuation', N,
            oct(stat(f).st_mode)[-3:], ' Permissions', N,
            time.ctime(path.getatime(f)), ' Accessed', N,
            time.ctime(path.getmtime(f)), ' Modified', N,
            'Owner: ', str(self.model.fileInfo(index).owner()), N,
            'Is Writable: ', str(self.model.fileInfo(index).isWritable()), N,
            'Is Executable: ', str(self.model.fileInfo(index).isExecutable()),
            N, 'Is Hidden: ', str(self.model.fileInfo(index).isHidden()), N,
            'Is SymLink: ', str(self.model.fileInfo(index).isSymLink()), N,
            'File Extension: ', str(self.model.fileInfo(index).suffix())
        ))
        #print(m)
        self.preview.setToolTip(m)
        self.preview.setText(s)
        self.preview.resize(self.preview.size().width(),
                            self.dock.size().height())
        self.process.start('xdg-open {}'.format(f))
        if not self.process.waitForStarted():
            print((" ERROR: Process {} Failed ! ".format(str(f))))
            return