%PDF- %PDF-
| Direktori : /proc/thread-self/root/usr/lib/calibre/calibre/gui2/preferences/ |
| Current File : //proc/thread-self/root/usr/lib/calibre/calibre/gui2/preferences/main.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import re
import textwrap
from collections import OrderedDict
from functools import partial
from qt.core import (
QApplication, QDialog, QDialogButtonBox, QFont, QFrame, QHBoxLayout, QIcon,
QLabel, QPainter, QPointF, QPushButton, QScrollArea, QSize, QSizePolicy,
QStackedWidget, QStatusTipEvent, Qt, QTabWidget, QTextLayout, QToolBar,
QVBoxLayout, QWidget, pyqtSignal
)
from calibre.constants import __appname__, __version__, islinux
from calibre.customize.ui import preferences_plugins
from calibre.gui2 import (
available_width, gprefs, min_available_height, show_restart_warning
)
from calibre.gui2.dialogs.message_box import Icon
from calibre.gui2.preferences import (
AbortCommit, AbortInitialize, get_plugin, init_gui
)
ICON_SIZE = 32
# Title Bar {{{
class Message(QWidget):
def __init__(self, parent):
QWidget.__init__(self, parent)
self.layout = QTextLayout()
self.layout.setFont(self.font())
self.layout.setCacheEnabled(True)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
self.last_layout_rect = None
def setText(self, text):
self.layout.setText(text)
self.last_layout_rect = None
self.update()
def sizeHint(self):
return QSize(10, 10)
def do_layout(self):
ly = self.layout
ly.beginLayout()
w = self.width() - 5
height = 0
leading = self.fontMetrics().leading()
while True:
line = ly.createLine()
if not line.isValid():
break
line.setLineWidth(w)
height += leading
line.setPosition(QPointF(5, height))
height += line.height()
ly.endLayout()
def paintEvent(self, ev):
if self.last_layout_rect != self.rect():
self.do_layout()
p = QPainter(self)
br = self.layout.boundingRect()
y = 0
if br.height() < self.height():
y = (self.height() - br.height()) / 2
self.layout.draw(p, QPointF(0, y))
class TitleBar(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.l = l = QHBoxLayout(self)
self.icon = Icon(self, size=ICON_SIZE)
l.addWidget(self.icon)
self.title = QLabel('')
self.title.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
l.addWidget(self.title)
l.addStrut(25)
self.msg = la = Message(self)
l.addWidget(la)
self.default_message = __appname__ + ' ' + _('version') + ' ' + \
__version__ + ' ' + _('created by Kovid Goyal')
self.show_plugin()
self.show_msg()
def show_plugin(self, plugin=None):
self.icon.set_icon(QIcon(I('lt.png') if plugin is None else plugin.icon))
self.title.setText('<h1>' + (_('Preferences') if plugin is None else plugin.gui_name))
def show_msg(self, msg=None):
msg = msg or self.default_message
self.msg.setText(' '.join(msg.splitlines()).strip())
# }}}
class Category(QWidget): # {{{
plugin_activated = pyqtSignal(object)
def __init__(self, name, plugins, gui_name, parent=None):
QWidget.__init__(self, parent)
self._layout = QVBoxLayout()
self.setLayout(self._layout)
self.label = QLabel(gui_name)
self.sep = QFrame(self)
self.bf = QFont()
self.bf.setBold(True)
self.label.setFont(self.bf)
self.sep.setFrameShape(QFrame.Shape.HLine)
self._layout.addWidget(self.label)
self._layout.addWidget(self.sep)
self.plugins = plugins
self.bar = QToolBar(self)
self.bar.setStyleSheet(
'QToolBar { border: none; background: none }')
lh = QApplication.instance().line_height
self.bar.setIconSize(QSize(2*lh, 2*lh))
self.bar.setMovable(False)
self.bar.setFloatable(False)
self.bar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)
self._layout.addWidget(self.bar)
self.actions = []
for p in plugins:
target = partial(self.triggered, p)
ac = self.bar.addAction(QIcon(p.icon), p.gui_name.replace('&', '&&'), target)
ac.setToolTip(textwrap.fill(p.description))
ac.setWhatsThis(textwrap.fill(p.description))
ac.setStatusTip(p.description)
self.actions.append(ac)
w = self.bar.widgetForAction(ac)
w.setCursor(Qt.CursorShape.PointingHandCursor)
if hasattr(w, 'setAutoRaise'):
w.setAutoRaise(True)
w.setMinimumWidth(100)
def triggered(self, plugin, *args):
self.plugin_activated.emit(plugin)
# }}}
class Browser(QScrollArea): # {{{
show_plugin = pyqtSignal(object)
def __init__(self, parent=None):
QScrollArea.__init__(self, parent)
self.setWidgetResizable(True)
category_map, category_names = {}, {}
for plugin in preferences_plugins():
if plugin.category not in category_map:
category_map[plugin.category] = plugin.category_order
if category_map[plugin.category] < plugin.category_order:
category_map[plugin.category] = plugin.category_order
if plugin.category not in category_names:
category_names[plugin.category] = (plugin.gui_category if
plugin.gui_category else plugin.category)
self.category_names = category_names
categories = list(category_map.keys())
categories.sort(key=lambda x: category_map[x])
self.category_map = OrderedDict()
for c in categories:
self.category_map[c] = []
for plugin in preferences_plugins():
self.category_map[plugin.category].append(plugin)
for plugins in self.category_map.values():
plugins.sort(key=lambda x: x.name_order)
self.widgets = []
self._layout = QVBoxLayout()
self.container = QWidget(self)
self.container.setLayout(self._layout)
self.setWidget(self.container)
for name, plugins in self.category_map.items():
w = Category(name, plugins, self.category_names[name], parent=self)
self.widgets.append(w)
self._layout.addWidget(w)
w.plugin_activated.connect(self.show_plugin.emit)
self._layout.addStretch(1)
# }}}
class Preferences(QDialog):
run_wizard_requested = pyqtSignal()
def __init__(self, gui, initial_plugin=None, close_after_initial=False):
QDialog.__init__(self, gui)
self.gui = gui
self.must_restart = False
self.do_restart = False
self.committed = False
self.close_after_initial = close_after_initial
self.resize(930, 720)
nh, nw = min_available_height()-25, available_width()-10
if nh < 0:
nh = 800
if nw < 0:
nw = 600
nh = min(self.height(), nh)
nw = min(self.width(), nw)
self.resize(nw, nh)
geom = gprefs.get('preferences dialog geometry', None)
if geom is not None:
QApplication.instance().safe_restore_geometry(self, geom)
# Center
if islinux:
self.move(gui.rect().center() - self.rect().center())
self.setWindowModality(Qt.WindowModality.ApplicationModal)
self.setWindowTitle(__appname__ + ' — ' + _('Preferences'))
self.setWindowIcon(QIcon(I('config.png')))
self.l = l = QVBoxLayout(self)
self.stack = QStackedWidget(self)
self.bb = QDialogButtonBox(
QDialogButtonBox.StandardButton.Close | QDialogButtonBox.StandardButton.Apply |
QDialogButtonBox.StandardButton.Cancel
)
self.bb.button(QDialogButtonBox.StandardButton.Apply).clicked.connect(self.accept)
self.wizard_button = QPushButton(QIcon(I('wizard.png')), _('Run Welcome &wizard'))
self.wizard_button.clicked.connect(self.run_wizard, type=Qt.ConnectionType.QueuedConnection)
self.wizard_button.setAutoDefault(False)
self.restore_defaults_button = rdb = QPushButton(QIcon(I('clear_left.png')), _('Restore &defaults'))
rdb.clicked.connect(self.restore_defaults, type=Qt.ConnectionType.QueuedConnection)
rdb.setAutoDefault(False)
rdb.setVisible(False)
self.bb.rejected.connect(self.reject)
self.browser = Browser(self)
self.browser.show_plugin.connect(self.show_plugin)
self.stack.addWidget(self.browser)
self.scroll_area = QScrollArea(self)
self.stack.addWidget(self.scroll_area)
self.scroll_area.setWidgetResizable(True)
self.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu)
self.title_bar = TitleBar(self)
for ac, tt in [(QDialogButtonBox.StandardButton.Apply, _('Save changes')),
(QDialogButtonBox.StandardButton.Cancel, _('Cancel and return to overview'))]:
self.bb.button(ac).setToolTip(tt)
l.addWidget(self.title_bar), l.addWidget(self.stack)
h = QHBoxLayout()
l.addLayout(h)
h.addWidget(self.wizard_button), h.addWidget(self.restore_defaults_button), h.addStretch(10), h.addWidget(self.bb)
if initial_plugin is not None:
category, name = initial_plugin[:2]
plugin = get_plugin(category, name)
if plugin is not None:
self.show_plugin(plugin)
if len(initial_plugin) > 2:
w = self.findChild(QWidget, initial_plugin[2])
if w is not None:
for c in self.showing_widget.children():
if isinstance(c, QTabWidget):
idx = c.indexOf(w)
if idx > -1:
c.setCurrentIndex(idx)
break
else:
self.hide_plugin()
def event(self, ev):
if isinstance(ev, QStatusTipEvent):
msg = re.sub(r'</?[a-z1-6]+>', ' ', ev.tip())
self.title_bar.show_msg(msg)
return QDialog.event(self, ev)
def run_wizard(self):
self.run_wizard_requested.emit()
self.accept()
def set_tooltips_for_labels(self):
def process_child(child):
for g in child.children():
if isinstance(g, QLabel):
buddy = g.buddy()
if buddy is not None and hasattr(buddy, 'toolTip'):
htext = str(buddy.toolTip()).strip()
etext = str(g.toolTip()).strip()
if htext and not etext:
g.setToolTip(htext)
g.setWhatsThis(htext)
else:
process_child(g)
process_child(self.showing_widget)
def show_plugin(self, plugin):
self.showing_widget = plugin.create_widget(self.scroll_area)
self.showing_widget.genesis(self.gui)
try:
self.showing_widget.initialize()
except AbortInitialize:
return
self.set_tooltips_for_labels()
self.scroll_area.setWidget(self.showing_widget)
self.stack.setCurrentIndex(1)
self.showing_widget.show()
self.setWindowTitle(__appname__ + ' - ' + _('Preferences') + ' - ' + plugin.gui_name)
self.showing_widget.restart_now.connect(self.restart_now)
self.title_bar.show_plugin(plugin)
self.setWindowIcon(QIcon(plugin.icon))
self.bb.button(QDialogButtonBox.StandardButton.Close).setVisible(False)
self.wizard_button.setVisible(False)
for button in (QDialogButtonBox.StandardButton.Apply, QDialogButtonBox.StandardButton.Cancel):
button = self.bb.button(button)
button.setVisible(True)
self.bb.button(QDialogButtonBox.StandardButton.Apply).setEnabled(False)
self.bb.button(QDialogButtonBox.StandardButton.Apply).setDefault(False), self.bb.button(QDialogButtonBox.StandardButton.Apply).setDefault(True)
self.restore_defaults_button.setEnabled(self.showing_widget.supports_restoring_to_defaults)
self.restore_defaults_button.setVisible(self.showing_widget.supports_restoring_to_defaults)
self.restore_defaults_button.setToolTip(
self.showing_widget.restore_defaults_desc if self.showing_widget.supports_restoring_to_defaults else
(_('Restoring to defaults not supported for') + ' ' + plugin.gui_name))
self.restore_defaults_button.setText(_('Restore &defaults'))
self.showing_widget.changed_signal.connect(self.changed_signal)
def changed_signal(self):
b = self.bb.button(QDialogButtonBox.StandardButton.Apply)
b.setEnabled(True)
def hide_plugin(self):
for sig in 'changed_signal restart_now'.split():
try:
getattr(self.showing_widget, sig).disconnect(getattr(self, sig))
except Exception:
pass
self.showing_widget = QWidget(self.scroll_area)
self.scroll_area.setWidget(self.showing_widget)
self.setWindowTitle(__appname__ + ' - ' + _('Preferences'))
self.stack.setCurrentIndex(0)
self.title_bar.show_plugin()
self.setWindowIcon(QIcon(I('config.png')))
for button in (QDialogButtonBox.StandardButton.Apply, QDialogButtonBox.StandardButton.Cancel):
button = self.bb.button(button)
button.setVisible(False)
self.restore_defaults_button.setVisible(False)
self.bb.button(QDialogButtonBox.StandardButton.Close).setVisible(True)
self.bb.button(QDialogButtonBox.StandardButton.Close).setDefault(False), self.bb.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
self.wizard_button.setVisible(True)
def restart_now(self):
try:
self.showing_widget.commit()
except AbortCommit:
return
self.do_restart = True
self.hide_plugin()
self.accept()
def commit(self, *args):
must_restart = self.showing_widget.commit()
rc = self.showing_widget.restart_critical
self.committed = True
do_restart = False
if must_restart:
self.must_restart = True
msg = _('Some of the changes you made require a restart.'
' Please restart calibre as soon as possible.')
if rc:
msg = _('The changes you have made require calibre be '
'restarted immediately. You will not be allowed to '
'set any more preferences, until you restart.')
do_restart = show_restart_warning(msg, parent=self)
self.showing_widget.refresh_gui(self.gui)
if do_restart:
self.do_restart = True
return self.close_after_initial or (must_restart and rc) or do_restart
def restore_defaults(self, *args):
self.showing_widget.restore_defaults()
def on_shutdown(self):
gprefs.set('preferences dialog geometry', bytearray(self.saveGeometry()))
if self.committed:
self.gui.must_restart_before_config = self.must_restart
self.gui.tags_view.recount()
self.gui.create_device_menu()
self.gui.set_device_menu_items_state(bool(self.gui.device_connected))
self.gui.bars_manager.apply_settings()
self.gui.bars_manager.update_bars()
self.gui.build_context_menus()
def accept(self):
if self.stack.currentIndex() == 0:
self.on_shutdown()
return QDialog.accept(self)
try:
close = self.commit()
except AbortCommit:
return
if close:
self.on_shutdown()
return QDialog.accept(self)
self.hide_plugin()
def reject(self):
if self.stack.currentIndex() == 0 or self.close_after_initial:
self.on_shutdown()
return QDialog.reject(self)
self.hide_plugin()
if __name__ == '__main__':
from calibre.gui2 import Application
app = Application([])
app
gui = init_gui()
p = Preferences(gui)
p.exec()
gui.shutdown()