modules/pymol/plugins/managergui_qt.py (343 lines of code) (raw):
from pymol.gui import get_qtwindow as getPyMOLWindow
from pymol.plugins import installation, repository
from pymol.Qt import QtGui, QtCore
from pymol.Qt import QtWidgets
from . import pref_get
Qt = QtCore.Qt
def confirm_network_access():
'''
Popup dialog with network access notification (only once per session)
'''
self = confirm_network_access
if self.ok < 0:
check = QtWidgets.QMessageBox.information(None, 'Info',
'Network download has been disabled, sorry!')
return False
if self.ok > 0:
return True
if QtWidgets.QMessageBox.question(None, 'Confirm',
'PyMOL will now download executable code from the internet!'
' Proceed?') == QtWidgets.QMessageBox.Yes:
self.ok = 1
else:
self.ok = 0
return self.ok
# valid values: 1=never ask, 0=ask once per session, -1=network access disabled
confirm_network_access.ok = pref_get('network_access_ok', 0)
class PluginManager(QtCore.QObject):
def __init__(self, cmd):
super(PluginManager, self).__init__(None)
window = getPyMOLWindow()
self.form = window.load_form('pluginmanager')
self.form.b_wiki.pressed.connect(self.fetchplugin)
self.form.e_wiki.returnPressed.connect(self.fetchplugin)
self.form.b_local.pressed.connect(self.installplugin)
self.form.b_startup_all.pressed.connect(self.startup_all)
self.form.b_startup_none.pressed.connect(self.startup_none)
self.form.e_filter.textChanged.connect(self.filter_plugins)
self.form.c_loaded.stateChanged.connect(self.filter_plugins)
self.form.c_startup.stateChanged.connect(self.filter_plugins)
self.form.l_repositories.itemClicked.connect(self.repo_changed)
self.form.bb_path_add.pressed.connect(self.add_path)
self.form.bb_path_up.pressed.connect(self.move_path_up)
self.form.bb_path_down.pressed.connect(self.move_path_down)
self.form.bb_path_remove.pressed.connect(self.remove_path)
self.form.b_add_repo.pressed.connect(self.add_repository)
self.form.b_remove_repo.pressed.connect(self.remove_repository)
self.reload_plugins()
self.form.l_repo_plugins.setSelectionMode(
QtWidgets.QAbstractItemView.ExtendedSelection)
self.form.b_install.pressed.connect(self.install_repo_plugins)
self.form.b_info.pressed.connect(self.info_repo_plugin)
self.populate_repositories()
self.populate_startup_paths()
self.populate_preferences()
self.form._dialog.show()
def populate_repositories(self):
repos = [
'http://pldserver1.biochem.queensu.ca/~rlc/work/pymol/',
'https://github.com/Pymol-Scripts/Pymol-script-repo',
# for testing
'http://www.thomas-holder.de/projects/pymol/repository/'
]
for rep in repos:
self.form.l_repositories.addItem(rep)
def populate_startup_paths(self):
from . import get_startup_path
items = get_startup_path(True)
self.form.slb_path.addItems(items)
def update_startup_paths(self):
from . import set_startup_path
items = []
for index in range(self.form.slb_path.count()):
items.append(self.form.slb_path.item(index).text())
set_startup_path(items)
def populate_preferences(self):
from . import preferences
self.t_preferences_keys = list(preferences)
w = self.form.t_preferences
w.horizontalHeader().setStretchLastSection(True)
w.setRowCount(len(self.t_preferences_keys))
for row, key in enumerate(self.t_preferences_keys):
item = QtWidgets.QTableWidgetItem(key)
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
w.setItem(row, 0, item)
item = QtWidgets.QTableWidgetItem()
value = preferences[key]
if isinstance(value, bool):
item.setCheckState(Qt.Checked if value else Qt.Unchecked)
else:
item.setFlags(item.flags() & ~Qt.ItemIsUserCheckable)
item.setText(str(value))
w.setItem(row, 1, item)
w.itemChanged.connect(self.update_preferences_item)
def update_preferences_item(self, item):
from . import pref_get, pref_set
key = self.t_preferences_keys[item.row()]
if item.flags() & Qt.ItemIsUserCheckable:
value = item.checkState() == Qt.Checked
else:
value = item.data(0)
if hasattr(value, 'toString'): # PyQt4
value = value.toString()
try:
value = type(pref_get(key, ''))(value)
except BaseException as e:
print(e)
pref_set(key, value)
def install_repo_plugins(self):
from .installation import installPluginFromFile, get_plugdir
items = self.form.l_repo_plugins.selectedItems()
if len(items) == 0:
return
plugdir = get_plugdir(None)
if not plugdir:
return
import sys, tempfile, shutil, os
from .legacysupport import tkMessageBox
from .repository import guess
tmpdir = tempfile.mkdtemp()
try:
for item in items:
name = item.text()
filename = self.repo_r.copy(name, tmpdir)
installPluginFromFile(filename, None, plugdir)
except:
err = str(sys.exc_info()[1])
tkMessageBox.showinfo('Error', 'Could not install plugin ' + name + '\n\n' + err)
finally:
shutil.rmtree(tmpdir)
self.reload_plugins()
def info_repo_plugin(self):
from . import PluginInfo
from .installation import get_name_and_ext, extract_zipfile, zip_extensions
from .legacysupport import tkMessageBox
items = self.form.l_repo_plugins.selectedItems()
if len(items) == 0:
return
import tempfile, shutil, os
tmpdir = tempfile.mkdtemp()
tmpdirs = [tmpdir]
try:
name = items[0].text()
filename = self.repo_r.copy(name, tmpdir)
name, ext = get_name_and_ext(filename)
if ext in zip_extensions:
tmpdir, dirnames = extract_zipfile(filename, ext)
tmpdirs.append(tmpdir)
name = dirnames[-1]
filename = os.path.join(os.path.join(tmpdir, *dirnames), '__init__.py')
info = PluginInfo(name, filename)
self.show_plugin_info_dialog(info)
except:
tkMessageBox.showinfo('Error', 'Could not get plugin info')
finally:
for tmpdir in tmpdirs:
shutil.rmtree(tmpdir)
def repo_changed(self, item):
from .repository import guess
url = item.text()
self.repo_r = guess(url)
plist = self.repo_r.list()
self.form.l_repo_plugins.clear()
for p in plist:
self.form.l_repo_plugins.addItem(p)
def add_repository(self):
repo, result = QtWidgets.QInputDialog.getText(None,
'Add repository', 'Enter repository URL')
if result and repo.startswith('http'):
self.form.l_repositories.addItem(repo)
def remove_repository(self):
items = self.form.l_repositories.selecteditems()
if len(items) == 0:
return
row = self.form.l_repositories.row(items[0])
self.form.l_repositories.takeItem(row)
items = self.form.l_repositories.selecteditems()
if len(items) > 0:
self.repo_changed(items[0])
def show(self):
self.form._dialog.show()
self.form._dialog.raise_()
def w_startup_changed(self, state):
item = self.sender().parent()._form
info = self.plugin_info[item]
info.autoload = state
def reload_plugins(self, setting=None):
from . import plugins
window = getPyMOLWindow()
self.clear_plugins()
for info in sorted(plugins.values(), key=lambda i: i.name.lower()):
item = window.load_form('pluginitem', QtWidgets.QFrame())
item._widget = item._dialog
item._widget.setFrameStyle(QtWidgets.QFrame.Sunken)
item._widget.setFrameShape(QtWidgets.QFrame.Panel)
item.w_title.setText(info.name)
item.w_version.setText(info.get_version())
item.w_startup.setChecked(info.autoload)
item.w_startup.stateChanged.connect(self.w_startup_changed)
item.w_enable.pressed.connect(info.load)
item.w_enable.pressed.connect(self.disable_load_button)
item.w_uninstall.pressed.connect(info.uninstall)
item.w_uninstall.pressed.connect(self.reload_plugins)
if info.loaded:
item.w_enable.setEnabled(False)
if hasattr(info.module, 'settings_dialog'):
item.w_settings.setVisible(True)
else:
item.w_settings.setVisible(False)
item.w_info.pressed.connect(self.show_info)
if info.loadtime:
item.w_loadtime.setText("Took %.3f seconds to load" % info.loadtime)
else:
item.w_loadtime.setText("Not loaded")
item._widget._form = item
self.plugin_info[item] = info
self.form.f_installed_layout.addWidget(item._widget)
self.filter_plugins()
self.form.f_installed_layout.addStretch()
def clear_plugins(self):
self.plugin_info = {}
layout = self.form.f_installed_layout
while layout.count():
child = layout.takeAt(0)
if child.widget() is not None:
child.widget().deleteLater()
def filter_plugins(self):
filter_loaded = self.form.c_loaded.isChecked()
filter_startup = self.form.c_startup.isChecked()
filter_name = self.form.e_filter.text().lower()
for (item, info) in self.plugin_info.items():
if filter_name not in info.name.lower():
vis = False
elif filter_loaded and not info.loaded:
vis = False
elif filter_startup and not info.autoload:
vis = False
else:
vis = True
item._widget.setVisible(vis)
def startup_all(self):
for item, info in self.plugin_info.items():
item.w_startup.setChecked(True)
info.autoload = True
def startup_none(self):
for item, info in self.plugin_info.items():
item.w_startup.setChecked(False)
info.autoload = False
def installplugin(self):
from .legacysupport import installPlugin
installPlugin(self)
def fetchplugin(self):
if not confirm_network_access():
return
from .installation import installPluginFromFile
from .repository import fetchscript
from pymol import CmdException
url = self.form.e_wiki.text()
if not len(url):
return
import tempfile, shutil
tmpdir = tempfile.mkdtemp()
try:
filename = fetchscript(url, tmpdir, False)
except BaseException as e:
QtWidgets.QMessageBox.critical(None, 'Error',
'Fetching Plugin failed.\n' + str(e))
return
if filename:
installPluginFromFile(filename)
shutil.rmtree(tmpdir)
self.reload_plugins()
def show_info(self):
item = self.sender().parent()._form
info = self.plugin_info[item]
self.show_plugin_info_dialog(info)
def disable_load_button(self):
item = self.sender().parent()._form
item.w_enable.setEnabled(False)
def show_plugin_info_dialog(self, info):
dialog = QtWidgets.QDialog(None)
dialog.setWindowTitle('Plugin Information')
layout = QtWidgets.QVBoxLayout()
table = QtWidgets.QTableWidget(0, 2)
table.verticalHeader().hide()
table.horizontalHeader().hide()
table.horizontalHeader().setStretchLastSection(True)
layout.addWidget(table)
dialog.setLayout(layout)
def add_line(label, text):
row = table.rowCount()
table.insertRow(table.rowCount())
table_item = QtWidgets.QTableWidgetItem(label)
table_item.setFlags(table_item.flags() &
~(Qt.ItemIsEditable))
table.setItem(row, 0, table_item)
table_item = QtWidgets.QTableWidgetItem(text)
table_item.setFlags(table_item.flags() &
~(Qt.ItemIsEditable))
table.setItem(row, 1, table_item)
add_line('Name', info.name)
if not info.is_temporary:
add_line('Python Module Name', info.mod_name)
add_line('Filename', info.filename)
metadata = info.get_metadata()
for label, value in metadata.items():
add_line(label, value)
if not info.is_temporary:
if info.loaded:
add_line('commands', ', '.join(info.commands))
docstring = info.get_docstring() or 'No documentation available.'
browser = QtWidgets.QTextBrowser()
browser.setPlainText(docstring)
layout.addWidget(browser)
table.resizeColumnsToContents()
dialog.resize(600, dialog.height())
dialog.exec_()
def add_path(self):
from .installation import get_default_user_plugin_path as userpath
d = QtWidgets.QFileDialog.getExistingDirectory(None,
'Add plugin directory', userpath())
if len(d) > 0:
self.form.slb_path.addItem(d)
self.update_startup_paths()
def move_path_up(self):
items = self.form.slb_path.selectedItems()
if len(items) > 0:
row = self.form.slb_path.row(items[0])
if row > 0:
item = self.form.slb_path.takeItem(row)
self.form.slb_path.insertItem(row-1, item)
self.update_startup_paths()
def move_path_down(self):
items = self.form.slb_path.selectedItems()
if len(items) > 0:
row = self.form.slb_path.row(items[0])
if row < self.form.slb_path.rowCount() - 1:
item = self.form.slb_path.takeItem(row)
self.form.slb_path.insertItem(row+1, item)
self.update_startup_paths()
def remove_path(self):
items = self.form.slb_path.selectedItems()
if len(items) > 0:
row = self.form.slb_path.row(items[0])
self.form.slb_path.takeItem(row)
self.update_startup_paths()