diff --git a/picard/plugin.py b/picard/plugin.py index 841bdea9c..a71cfb15d 100644 --- a/picard/plugin.py +++ b/picard/plugin.py @@ -20,15 +20,27 @@ from PyQt4 import QtCore import imp import os.path +import shutil import picard.plugins import traceback +_suffixes = [s[0] for s in imp.get_suffixes()] +_package_entries = ["__init__.py", "__init__.pyc", "__init__.pyo"] -def plugin_name_from_module(module): - name = module.__name__ - if name.startswith("picard.plugins"): - return name[15:] + +def plugin_name_from_path(path): + path = os.path.normpath(path) + file = os.path.basename(path) + if os.path.isdir(path): + for entry in _package_entries: + if os.path.isfile(os.path.join(path, entry)): + return file else: + if file in _package_entries: + return None + name, ext = os.path.splitext(file) + if ext in _suffixes: + return name return None @@ -41,6 +53,10 @@ class ExtensionPoint(QtCore.QObject): def register(self, module, item): if module.startswith("picard.plugins"): module = module[15:] + for i, (module_, item_) in enumerate(self.__items): + if module == module_: + self.__items[i] = (module, item) + return else: module = None self.__items.append((module, item)) @@ -56,15 +72,23 @@ class PluginWrapper(object): def __init__(self, module, plugindir): self.module = module + self.compatible = False self.dir = plugindir def __get_name(self): try: return self.module.PLUGIN_NAME except AttributeError: - return self.module.__name__ + return self.module_name name = property(__get_name) + def __get_module_name(self): + name = self.module.__name__ + if name.startswith("picard.plugins"): + name = name[15:] + return name + module_name = property(__get_module_name) + def __get_author(self): try: return self.module.PLUGIN_AUTHOR @@ -104,57 +128,67 @@ class PluginManager(QtCore.QObject): QtCore.QObject.__init__(self) self.plugins = [] - def load(self, plugindir): + def load_plugindir(self, plugindir): if not os.path.isdir(plugindir): self.log.debug("Plugin directory %r doesn't exist", plugindir) return - names = set() - suffixes = [s[0] for s in imp.get_suffixes()] - package_entries = ["__init__.py", "__init__.pyc", "__init__.pyo"] - for name in os.listdir(plugindir): - if name in package_entries: - continue - path = os.path.join(plugindir, name) - if os.path.isdir(path): - for entry in package_entries: - if os.path.isfile(os.path.join(path, entry)): - break - else: - continue - else: - name, suffix = os.path.splitext(name) - if suffix not in suffixes: - continue - if hasattr(picard.plugins, name): - self.log.debug("Plugin %r already loaded!", name) - else: + for path in [os.path.join(plugindir, file) for file in os.listdir(plugindir)]: + name = plugin_name_from_path(path) + if name: names.add(name) - for name in names: - self.log.debug("Loading plugin %r", name) - info = imp.find_module(name, [plugindir]) - try: - plugin_module = imp.load_module('picard.plugins.' + name, *info) - plugin = PluginWrapper(plugin_module, plugindir) - for version in list(plugin.api_versions): - found = False - for api_version in picard.api_versions: - if api_version.startswith(version): - setattr(picard.plugins, name, plugin_module) + self.load_plugin(name, plugindir) + + def load_plugin(self, name, plugindir): + self.log.debug("Loading plugin %r", name) + info = imp.find_module(name, [plugindir]) + plugin = None + try: + plugin_module = imp.load_module("picard.plugins." + name, *info) + plugin = PluginWrapper(plugin_module, plugindir) + for version in list(plugin.api_versions): + for api_version in picard.api_versions: + if api_version.startswith(version): + plugin.compatible = True + setattr(picard.plugins, name, plugin_module) + for i, p in enumerate(self.plugins): + if name == p.module_name: + self.plugins[i] = plugin + break + else: self.plugins.append(plugin) - found = True - break - if found: break else: - self.log.info("Plugin '%s' from '%s' is not compatible " - "with this version of Picard." % - (plugin.name, plugin.file)) - except: - self.log.error(traceback.format_exc()) - if info[0] is not None: - info[0].close() + continue + break + else: + self.log.info("Plugin '%s' from '%s' is not compatible" + " with this version of Picard." % (plugin.name, plugin.file)) + except: + self.log.error(traceback.format_exc()) + if info[0] is not None: + info[0].close() + return plugin + + def install_plugin(self, path, dest): + plugin_name = plugin_name_from_path(path) + plugin_dir = self.tagger.user_plugin_dir + if plugin_name: + try: + dest_exists = os.path.exists(dest) + same_file = os.path.samefile(path, dest) if dest_exists else False + if os.path.isfile(path) and not (dest_exists and same_file): + shutil.copy(path, dest) + elif os.path.isdir(path) and not same_file: + if dest_exists: + shutil.rmtree(dest) + shutil.copytree(path, dest) + plugin = self.load_plugin(plugin_name, plugin_dir) + if plugin is not None: + self.emit(QtCore.SIGNAL("plugin_installed"), plugin, False) + except OSError, IOError: + self.tagger.log.debug("Unable to copy %s to plugin folder %s" % (path, plugin_dir)) def enabled(self, name): return True diff --git a/picard/tagger.py b/picard/tagger.py index fb2346572..1eaa667c7 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -185,14 +185,14 @@ class Tagger(QtGui.QApplication): # Load plugins self.pluginmanager = PluginManager() - user_plugin_dir = os.path.join(self.userdir, "plugins") - if not os.path.exists(user_plugin_dir): - os.makedirs(user_plugin_dir) - self.pluginmanager.load(user_plugin_dir) + self.user_plugin_dir = os.path.join(self.userdir, "plugins") + if not os.path.exists(self.user_plugin_dir): + os.makedirs(self.user_plugin_dir) + self.pluginmanager.load_plugindir(self.user_plugin_dir) if hasattr(sys, "frozen"): - self.pluginmanager.load(os.path.join(os.path.dirname(sys.argv[0]), "plugins")) + self.pluginmanager.load_plugindir(os.path.join(os.path.dirname(sys.argv[0]), "plugins")) else: - self.pluginmanager.load(os.path.join(os.path.dirname(__file__), "plugins")) + self.pluginmanager.load_plugindir(os.path.join(os.path.dirname(__file__), "plugins")) self.puidmanager = PUIDManager() diff --git a/picard/ui/options/plugins.py b/picard/ui/options/plugins.py index 71512f397..ee0a02f0f 100644 --- a/picard/ui/options/plugins.py +++ b/picard/ui/options/plugins.py @@ -22,7 +22,6 @@ import os.path import sys from PyQt4 import QtCore, QtGui from picard.config import TextOption -from picard.plugin import plugin_name_from_module from picard.ui.options import OptionsPage, register_options_page from picard.ui.ui_options_plugins import Ui_PluginsOptionsPage @@ -47,40 +46,65 @@ class PluginsOptionsPage(OptionsPage): super(PluginsOptionsPage, self).__init__(parent) self.ui = Ui_PluginsOptionsPage() self.ui.setupUi(self) + self.items = {} self.connect(self.ui.plugins, QtCore.SIGNAL("itemSelectionChanged()"), self.change_details) - self.user_plugin_dir = os.path.join(self.tagger.userdir, "plugins") + self.ui.plugins.__class__.mimeTypes = self.mimeTypes + self.ui.plugins.__class__.dropEvent = self.dropEvent if sys.platform == "win32": - self.loader="file:///%s" + self.loader="file:///%s" else: self.loader="file://%s" + self.connect(self.ui.install_plugin, QtCore.SIGNAL("clicked()"), self.open_plugins) self.connect(self.ui.folder_open, QtCore.SIGNAL("clicked()"), self.open_plugin_dir) self.connect(self.ui.plugin_download, QtCore.SIGNAL("clicked()"), self.open_plugin_site) + self.connect(self.tagger.pluginmanager, QtCore.SIGNAL("plugin_installed"), self.plugin_installed) def load(self): plugins = sorted(self.tagger.pluginmanager.plugins, cmp=cmp_plugins) enabled_plugins = self.config.setting["enabled_plugins"].split() - self.items = {} firstitem = None for plugin in plugins: - item = QtGui.QTreeWidgetItem(self.ui.plugins) - item.setText(0, plugin.name) - if plugin_name_from_module(plugin.module) in enabled_plugins: - item.setCheckState(0, QtCore.Qt.Checked) - else: - item.setCheckState(0, QtCore.Qt.Unchecked) - item.setText(1, plugin.version) - item.setText(2, plugin.author) + enabled = plugin.module_name in enabled_plugins + item = self.add_plugin_item(plugin, enabled=enabled) if not firstitem: firstitem = item - self.items[item] = plugin - self.ui.plugins.header().resizeSections(QtGui.QHeaderView.ResizeToContents) self.ui.plugins.setCurrentItem(firstitem) + def plugin_installed(self, plugin): + if not plugin.compatible: + msgbox = QtGui.QMessageBox(self) + msgbox.setText(u"The plugin ‘%s’ is not compatible with this version of Picard." % plugin.name) + msgbox.setStandardButtons(QtGui.QMessageBox.Ok) + msgbox.setDefaultButton(QtGui.QMessageBox.Ok) + msgbox.exec_() + return + for i, p in self.items.items(): + if plugin.module_name == p.module_name: + enabled = i.checkState(0) == QtCore.Qt.Checked + self.add_plugin_item(plugin, enabled=enabled, item=i) + break + else: + self.add_plugin_item(plugin) + + def add_plugin_item(self, plugin, enabled=False, item=None): + if item is None: + item = QtGui.QTreeWidgetItem(self.ui.plugins) + item.setText(0, plugin.name) + if enabled: + item.setCheckState(0, QtCore.Qt.Checked) + else: + item.setCheckState(0, QtCore.Qt.Unchecked) + item.setText(1, plugin.version) + item.setText(2, plugin.author) + self.ui.plugins.header().resizeSections(QtGui.QHeaderView.ResizeToContents) + self.items[item] = plugin + return item + def save(self): enabled_plugins = [] for item, plugin in self.items.iteritems(): if item.checkState(0) == QtCore.Qt.Checked: - enabled_plugins.append(plugin_name_from_module(plugin.module)) + enabled_plugins.append(plugin.module_name) self.config.setting["enabled_plugins"] = " ".join(enabled_plugins) def change_details(self): @@ -99,11 +123,38 @@ class PluginsOptionsPage(OptionsPage): text.append("" + _("File") + ": " + plugin.file[len(plugin.dir)+1:]) self.ui.details.setText("

%s

" % "
\n".join(text)) + def open_plugins(self): + files = QtGui.QFileDialog.getOpenFileNames(self, "", "/", "Picard plugin (*.py *.pyc)") + if files: + files = map(unicode, files) + for path in files: + self.install_plugin(path) + + def install_plugin(self, path): + file = os.path.basename(path) + dest = os.path.join(self.tagger.user_plugin_dir, file) + if os.path.exists(dest): + msgbox = QtGui.QMessageBox(self) + msgbox.setText("A plugin named %s is already installed." % file) + msgbox.setInformativeText("Do you want to overwrite the existing plugin?") + msgbox.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + msgbox.setDefaultButton(QtGui.QMessageBox.No) + if msgbox.exec_() == QtGui.QMessageBox.No: + return + self.tagger.pluginmanager.install_plugin(path, dest) + def open_plugin_dir(self): - QtGui.QDesktopServices.openUrl(QtCore.QUrl(self.loader % self.user_plugin_dir, QtCore.QUrl.TolerantMode)) + QtGui.QDesktopServices.openUrl(QtCore.QUrl(self.loader % self.tagger.user_plugin_dir, QtCore.QUrl.TolerantMode)) def open_plugin_site(self): QtGui.QDesktopServices.openUrl(QtCore.QUrl("http://musicbrainz.org/doc/Picard_Plugins", QtCore.QUrl.TolerantMode)) + def mimeTypes(self): + return ["text/uri-list"] + + def dropEvent(self, event): + for path in [os.path.normpath(unicode(u.toLocalFile())) for u in event.mimeData().urls()]: + self.install_plugin(path) + register_options_page(PluginsOptionsPage) diff --git a/picard/ui/ui_options_plugins.py b/picard/ui/ui_options_plugins.py index bdf1e6b2e..cc5e56c64 100644 --- a/picard/ui/ui_options_plugins.py +++ b/picard/ui/ui_options_plugins.py @@ -1,126 +1,117 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'ui\options_plugins.ui' -# -# Created: Thu Oct 22 00:04:48 2009 -# by: PyQt4 UI code generator 4.6 -# -# WARNING! All changes made in this file will be lost! - -from PyQt4 import QtCore, QtGui - -class Ui_PluginsOptionsPage(object): - def setupUi(self, PluginsOptionsPage): - PluginsOptionsPage.setObjectName("PluginsOptionsPage") - PluginsOptionsPage.resize(406, 297) - self.vboxlayout = QtGui.QVBoxLayout(PluginsOptionsPage) - self.vboxlayout.setSpacing(6) - self.vboxlayout.setMargin(9) - self.vboxlayout.setObjectName("vboxlayout") - self.splitter = QtGui.QSplitter(PluginsOptionsPage) - self.splitter.setOrientation(QtCore.Qt.Vertical) - self.splitter.setHandleWidth(2) - self.splitter.setObjectName("splitter") - self.groupBox_2 = QtGui.QGroupBox(self.splitter) - self.groupBox_2.setObjectName("groupBox_2") - self.vboxlayout1 = QtGui.QVBoxLayout(self.groupBox_2) - self.vboxlayout1.setSpacing(2) - self.vboxlayout1.setMargin(9) - self.vboxlayout1.setObjectName("vboxlayout1") - self.plugins = QtGui.QTreeWidget(self.groupBox_2) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.plugins.sizePolicy().hasHeightForWidth()) - self.plugins.setSizePolicy(sizePolicy) - self.plugins.setRootIsDecorated(False) - self.plugins.setObjectName("plugins") - self.vboxlayout1.addWidget(self.plugins) - self.horizontalLayout = QtGui.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") - self.folder_open = QtGui.QPushButton(self.groupBox_2) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.folder_open.sizePolicy().hasHeightForWidth()) - self.folder_open.setSizePolicy(sizePolicy) - self.folder_open.setObjectName("folder_open") - self.horizontalLayout.addWidget(self.folder_open) - self.plugin_download = QtGui.QPushButton(self.groupBox_2) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.plugin_download.sizePolicy().hasHeightForWidth()) - self.plugin_download.setSizePolicy(sizePolicy) - self.plugin_download.setObjectName("plugin_download") - self.horizontalLayout.addWidget(self.plugin_download) - self.vboxlayout1.addLayout(self.horizontalLayout) - self.groupBox = QtGui.QGroupBox(self.splitter) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) - self.groupBox.setSizePolicy(sizePolicy) - self.groupBox.setObjectName("groupBox") - self.vboxlayout2 = QtGui.QVBoxLayout(self.groupBox) - self.vboxlayout2.setSpacing(0) - self.vboxlayout2.setMargin(9) - self.vboxlayout2.setObjectName("vboxlayout2") - self.scrollArea = QtGui.QScrollArea(self.groupBox) - self.scrollArea.setEnabled(True) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth()) - self.scrollArea.setSizePolicy(sizePolicy) - self.scrollArea.setFrameShape(QtGui.QFrame.HLine) - self.scrollArea.setFrameShadow(QtGui.QFrame.Plain) - self.scrollArea.setLineWidth(0) - self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) - self.scrollArea.setWidgetResizable(True) - self.scrollArea.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) - self.scrollArea.setObjectName("scrollArea") - self.scrollAreaWidgetContents = QtGui.QWidget(self.scrollArea) - self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 368, 69)) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.scrollAreaWidgetContents.sizePolicy().hasHeightForWidth()) - self.scrollAreaWidgetContents.setSizePolicy(sizePolicy) - self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") - self.verticalLayout = QtGui.QVBoxLayout(self.scrollAreaWidgetContents) - self.verticalLayout.setSizeConstraint(QtGui.QLayout.SetNoConstraint) - self.verticalLayout.setContentsMargins(0, 0, 6, 0) - self.verticalLayout.setObjectName("verticalLayout") - self.details = QtGui.QLabel(self.scrollAreaWidgetContents) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.details.sizePolicy().hasHeightForWidth()) - self.details.setSizePolicy(sizePolicy) - self.details.setMinimumSize(QtCore.QSize(0, 0)) - self.details.setFrameShape(QtGui.QFrame.Box) - self.details.setLineWidth(0) - self.details.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) - self.details.setWordWrap(True) - self.details.setIndent(0) - self.details.setOpenExternalLinks(True) - self.details.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) - self.details.setObjectName("details") - self.verticalLayout.addWidget(self.details) - self.scrollArea.setWidget(self.scrollAreaWidgetContents) - self.vboxlayout2.addWidget(self.scrollArea) - self.vboxlayout.addWidget(self.splitter) - - self.retranslateUi(PluginsOptionsPage) - QtCore.QMetaObject.connectSlotsByName(PluginsOptionsPage) - - def retranslateUi(self, PluginsOptionsPage): - self.groupBox_2.setTitle(_("Plugins")) - self.plugins.headerItem().setText(0, _("Name")) - self.plugins.headerItem().setText(1, _("Version")) - self.plugins.headerItem().setText(2, _("Author")) - self.folder_open.setText(_("Open plugin folder")) - self.plugin_download.setText(_("Download plugins")) - self.groupBox.setTitle(_("Details")) - +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui/options_plugins.ui' +# +# Created: Mon Jun 20 19:52:58 2011 +# by: PyQt4 UI code generator 4.8.4 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_PluginsOptionsPage(object): + def setupUi(self, PluginsOptionsPage): + PluginsOptionsPage.setObjectName("PluginsOptionsPage") + PluginsOptionsPage.resize(513, 312) + self.vboxlayout = QtGui.QVBoxLayout(PluginsOptionsPage) + self.vboxlayout.setObjectName("vboxlayout") + self.splitter = QtGui.QSplitter(PluginsOptionsPage) + self.splitter.setOrientation(QtCore.Qt.Vertical) + self.splitter.setHandleWidth(2) + self.splitter.setObjectName("splitter") + self.groupBox_2 = QtGui.QGroupBox(self.splitter) + self.groupBox_2.setObjectName("groupBox_2") + self.vboxlayout1 = QtGui.QVBoxLayout(self.groupBox_2) + self.vboxlayout1.setSpacing(2) + self.vboxlayout1.setObjectName("vboxlayout1") + self.plugins = QtGui.QTreeWidget(self.groupBox_2) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding) + sizePolicy.setHeightForWidth(self.plugins.sizePolicy().hasHeightForWidth()) + self.plugins.setSizePolicy(sizePolicy) + self.plugins.setAcceptDrops(True) + self.plugins.setDragDropMode(QtGui.QAbstractItemView.DropOnly) + self.plugins.setRootIsDecorated(False) + self.plugins.setObjectName("plugins") + self.vboxlayout1.addWidget(self.plugins) + self.horizontalLayout = QtGui.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.install_plugin = QtGui.QPushButton(self.groupBox_2) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) + sizePolicy.setHeightForWidth(self.install_plugin.sizePolicy().hasHeightForWidth()) + self.install_plugin.setSizePolicy(sizePolicy) + self.install_plugin.setObjectName("install_plugin") + self.horizontalLayout.addWidget(self.install_plugin) + self.folder_open = QtGui.QPushButton(self.groupBox_2) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) + sizePolicy.setHeightForWidth(self.folder_open.sizePolicy().hasHeightForWidth()) + self.folder_open.setSizePolicy(sizePolicy) + self.folder_open.setObjectName("folder_open") + self.horizontalLayout.addWidget(self.folder_open) + self.plugin_download = QtGui.QPushButton(self.groupBox_2) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) + sizePolicy.setHeightForWidth(self.plugin_download.sizePolicy().hasHeightForWidth()) + self.plugin_download.setSizePolicy(sizePolicy) + self.plugin_download.setObjectName("plugin_download") + self.horizontalLayout.addWidget(self.plugin_download) + self.vboxlayout1.addLayout(self.horizontalLayout) + self.groupBox = QtGui.QGroupBox(self.splitter) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) + sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) + self.groupBox.setSizePolicy(sizePolicy) + self.groupBox.setObjectName("groupBox") + self.vboxlayout2 = QtGui.QVBoxLayout(self.groupBox) + self.vboxlayout2.setSpacing(0) + self.vboxlayout2.setObjectName("vboxlayout2") + self.scrollArea = QtGui.QScrollArea(self.groupBox) + self.scrollArea.setEnabled(True) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) + sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth()) + self.scrollArea.setSizePolicy(sizePolicy) + self.scrollArea.setFrameShape(QtGui.QFrame.HLine) + self.scrollArea.setFrameShadow(QtGui.QFrame.Plain) + self.scrollArea.setLineWidth(0) + self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents = QtGui.QWidget() + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 459, 76)) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) + sizePolicy.setHeightForWidth(self.scrollAreaWidgetContents.sizePolicy().hasHeightForWidth()) + self.scrollAreaWidgetContents.setSizePolicy(sizePolicy) + self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") + self.verticalLayout = QtGui.QVBoxLayout(self.scrollAreaWidgetContents) + self.verticalLayout.setSizeConstraint(QtGui.QLayout.SetNoConstraint) + self.verticalLayout.setContentsMargins(0, 0, 6, 0) + self.verticalLayout.setObjectName("verticalLayout") + self.details = QtGui.QLabel(self.scrollAreaWidgetContents) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) + sizePolicy.setHeightForWidth(self.details.sizePolicy().hasHeightForWidth()) + self.details.setSizePolicy(sizePolicy) + self.details.setFrameShape(QtGui.QFrame.Box) + self.details.setLineWidth(0) + self.details.setText("") + self.details.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.details.setWordWrap(True) + self.details.setIndent(0) + self.details.setOpenExternalLinks(True) + self.details.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.details.setObjectName("details") + self.verticalLayout.addWidget(self.details) + self.scrollArea.setWidget(self.scrollAreaWidgetContents) + self.vboxlayout2.addWidget(self.scrollArea) + self.vboxlayout.addWidget(self.splitter) + + self.retranslateUi(PluginsOptionsPage) + QtCore.QMetaObject.connectSlotsByName(PluginsOptionsPage) + + def retranslateUi(self, PluginsOptionsPage): + self.groupBox_2.setTitle(_("Plugins")) + self.plugins.headerItem().setText(0, _("Name")) + self.plugins.headerItem().setText(1, _("Version")) + self.plugins.headerItem().setText(2, _("Author")) + self.install_plugin.setText(_(u"Install plugin…")) + self.folder_open.setText(_("Open plugin folder")) + self.plugin_download.setText(_("Download plugins")) + self.groupBox.setTitle(_("Details")) + diff --git a/ui/options_plugins.ui b/ui/options_plugins.ui index 845d2cd38..03300535b 100644 --- a/ui/options_plugins.ui +++ b/ui/options_plugins.ui @@ -6,17 +6,11 @@ 0 0 - 406 - 297 + 513 + 312 - - 6 - - - 9 - @@ -33,9 +27,6 @@ 2 - - 9 - @@ -44,6 +35,12 @@ 0 + + true + + + QAbstractItemView::DropOnly + false @@ -66,6 +63,19 @@ + + + + + 0 + 0 + + + + Install plugin… + + + @@ -110,9 +120,6 @@ 0 - - 9 - @@ -147,8 +154,8 @@ 0 0 - 368 - 69 + 459 + 76