New tabbed configuration for KoboTouch driver. With the new files.

This commit is contained in:
David 2016-04-11 20:36:34 +10:00
parent 5665f5e57e
commit adc9535714
2 changed files with 894 additions and 0 deletions

View File

@ -0,0 +1,486 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, #division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import textwrap
from PyQt5.Qt import (QLabel, QGridLayout, QLineEdit, QVBoxLayout,
QDialog, QDialogButtonBox, QCheckBox)
from calibre.gui2.device_drivers.tabbed_device_config import TabbedDeviceConfig, DeviceConfigTab, DeviceOptionsGroupBox
from calibre.devices.usbms.driver import debug_print
def wrap_msg(msg):
return textwrap.fill(msg.strip(), 100)
def setToolTipFor(widget, tt):
widget.setToolTip(wrap_msg(tt))
def create_checkbox(title, tt, state):
cb = QCheckBox(title)
cb.setToolTip(wrap_msg(tt))
cb.setChecked(bool(state))
return cb
class KOBOTOUCHConfig(TabbedDeviceConfig):
def __init__(self, device_settings, all_formats, supports_subdirs,
must_read_metadata, supports_use_author_sort,
extra_customization_message, device, extra_customization_choices=None, parent=None):
super(KOBOTOUCHConfig, self).__init__(device_settings, all_formats, supports_subdirs,
must_read_metadata, supports_use_author_sort,
extra_customization_message, device, extra_customization_choices, parent)
self.device_settings = device_settings
self.all_formats = all_formats
self.supports_subdirs = supports_subdirs
self.must_read_metadata = must_read_metadata
self.supports_use_author_sort = supports_use_author_sort
self.extra_customization_message = extra_customization_message
self.extra_customization_choices = extra_customization_choices
self.current_device_key = device.device_defaults_key
self.tab1 = Tab1Config(self, self.device)
self.tab2 = Tab2Config(self, self.device)
extra_tab_pos = self.indexOf(self.extra_tab)
last_tab_pos = self.insertTab(extra_tab_pos, self.tab1, _("Collections, Covers && Uploads"))
last_tab_pos = self.insertTab(last_tab_pos + 1, self.tab2, _('Metadata && Advanced'))
def get_pref(self, key):
return self.device.get_pref(key)
@property
def device(self):
return self._device()
def validate(self):
if hasattr(self, 'formats'):
if not self.formats.validate():
return False
if not self.template.validate():
return False
return True
@property
def book_uploads_options(self):
return self.tab1.book_uploads_options
@property
def collections_options(self):
return self.tab1.collections_options
@property
def cover_options(self):
return self.tab1.covers_options
@property
def device_list_options(self):
return self.tab2.device_list_options
@property
def advanced_options(self):
return self.tab2.advanced_options
@property
def metadata_options(self):
return self.tab2.metadata_options
def commit(self):
debug_print("KOBOTOUCHConfig::commit: start")
p = super(KOBOTOUCHConfig, self).commit()
p['manage_collections'] = self.manage_collections
p['create_collections'] = self.create_collections
p['collections_columns'] = self.collections_columns
p['delete_empty_collections'] = self.delete_empty_collections
p['upload_covers'] = self.upload_covers
p['keep_cover_aspect'] = self.keep_cover_aspect
p['upload_grayscale'] = self.upload_grayscale
p['show_recommendations'] = self.show_recommendations
p['show_previews'] = self.show_previews
p['show_archived_books'] = self.show_archived_books
p['update_series'] = self.update_series
p['modify_css'] = self.modify_css
p['support_newer_firmware'] = self.support_newer_firmware
p['debugging_title'] = self.debugging_title
p['extra_customization'] = self.extra_tab.extra_customization()
return p
class Tab1Config(DeviceConfigTab): # {{{
def __init__(self, parent, device):
super(Tab1Config, self).__init__(parent)
self.l = QVBoxLayout(self)
self.setLayout(self.l)
self.collections_options = CollectionsGroupBox(self, device)
self.l.addWidget(self.collections_options)
self.add_widget(self.collections_options)
self.covers_options = CoversGroupBox(self, device)
self.l.addWidget(self.covers_options)
self.add_widget(self.covers_options)
self.book_uploads_options = BookUploadsGroupBox(self, device)
self.l.addWidget(self.book_uploads_options)
self.add_widget(self.book_uploads_options)
# }}}
class Tab2Config(DeviceConfigTab): # {{{
def __init__(self, parent, device):
super(Tab2Config, self).__init__(parent)
self.l = QVBoxLayout(self)
self.setLayout(self.l)
self.metadata_options = MetadataGroupBox(self, device)
self.l.addWidget(self.metadata_options)
self.add_widget(self.metadata_options)
self.device_list_options = DeviceListGroupBox(self, device)
self.l.addWidget(self.device_list_options)
self.add_widget(self.device_list_options)
self.advanced_options = AdvancedGroupBox(self, device)
self.l.addWidget(self.advanced_options)
self.add_widget(self.advanced_options)
# }}}
class BookUploadsGroupBox(DeviceOptionsGroupBox):
def __init__(self, parent, device):
super(BookUploadsGroupBox, self).__init__(parent, device)
self.setTitle(_("Book Uploading"))
self.options_layout = QGridLayout()
self.options_layout.setObjectName("options_layout")
self.setLayout(self.options_layout)
self.modify_css_checkbox = create_checkbox(
_("Modify CSS"),
_('This allows addition of user CSS rules and removal of some CSS. '
'When sending a book, the driver adds the contents of {0} to all stylesheets in the ePub. '
'This file is searched for in the root directory of the main memory of the device. '
'As well as this, if the file contains settings for the "orphans" or "widows", '
'these are removed for all styles in the original stylesheet.').format(device.KOBO_EXTRA_CSSFILE),
device.get_pref('modify_css')
)
self.options_layout.addWidget(self.modify_css_checkbox, 0, 0, 1, 2)
self.options_layout.setRowStretch(1, 1)
@property
def modify_css(self):
return self.modify_css_checkbox.isChecked()
class CollectionsGroupBox(DeviceOptionsGroupBox):
def __init__(self, parent, device):
super(CollectionsGroupBox, self).__init__(parent, device)
self.setTitle(_("Collections"))
self.options_layout = QGridLayout()
self.options_layout.setObjectName("options_layout")
self.setLayout(self.options_layout)
self.manage_collections_checkbox = create_checkbox(
_("Manage Collections"),
_('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.'),
device.get_pref('manage_collections')
)
self.manage_collections_checkbox.clicked.connect(self.manage_collections_checkbox_clicked)
self.collections_columns_label = QLabel(_('Collections Columns'))
self.collections_columns_edit = QLineEdit(self)
self.collections_columns_edit.setToolTip(_('The Kobo from firmware V2.0.0 supports bookshelves.'
' These are created on the Kobo. ' +
'Specify a tags type column for automatic management.'))
debug_print("CollectionsGroupBox::__init__ - device.settings()=", device.settings())
self.collections_columns_edit.setText(device.get_pref('collections_columns'))
self.create_collections_checkbox = create_checkbox(
_("Create Collections"),
_('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.'),
device.get_pref('create_collections')
)
self.delete_empty_collections_checkbox = create_checkbox(
_('Delete Empty Bookshelves'),
_('Delete any empty bookshelves from the Kobo when syncing is finished. This is only for firmware V2.0.0 or later.'),
device.get_pref('delete_empty_collections')
)
self.options_layout.addWidget(self.manage_collections_checkbox, 0, 0, 1, 1)
self.options_layout.addWidget(self.collections_columns_label, 1, 0, 1, 1)
self.options_layout.addWidget(self.collections_columns_edit, 1, 1, 1, 1)
self.options_layout.addWidget(self.create_collections_checkbox, 2, 0, 1, 1)
self.options_layout.addWidget(self.delete_empty_collections_checkbox, 2, 1, 1, 1)
self.options_layout.setRowStretch(5, 1)
self.manage_collections_checkbox_clicked(self.manage_collections)
@property
def manage_collections(self):
return self.manage_collections_checkbox.isChecked()
@property
def collections_columns(self):
return self.collections_columns_edit.text().strip()
@property
def create_collections(self):
return self.create_collections_checkbox.isChecked()
@property
def delete_empty_collections(self):
return self.delete_empty_collections_checkbox.isChecked()
def manage_collections_checkbox_clicked(self, checked):
self.collections_columns_label.setEnabled(checked)
self.collections_columns_edit.setEnabled(checked)
self.create_collections_checkbox.setEnabled(checked)
self.delete_empty_collections_checkbox.setEnabled(checked)
class CoversGroupBox(DeviceOptionsGroupBox):
def __init__(self, parent, device):
super(CoversGroupBox, self).__init__(parent, device)
self.setTitle(_("Covers"))
self.options_layout = QGridLayout()
self.options_layout.setObjectName("options_layout")
self.setLayout(self.options_layout)
self.upload_covers_checkbox = create_checkbox(
_("Upload covers for books"),
_('Upload cover images from the calibre library when sending books to the device.'),
device.get_pref('upload_covers')
)
self.upload_covers_checkbox.clicked.connect(self.upload_covers_checkbox_clicked)
self.upload_grayscale_checkbox = create_checkbox(
_('Upload Black and White Covers'),
_('Convert covers to Black and White when uploading'),
device.get_pref('upload_grayscale')
)
self.keep_cover_aspect_checkbox = create_checkbox(
_('Keep cover aspect ratio'),
_('When uploading covers, do not change the aspect ratio when resizing for the device.'
' This is for firmware versions 2.3.1 and later.'),
device.get_pref('keep_cover_aspect'))
self.options_layout.addWidget(self.upload_covers_checkbox, 0, 0, 1, 2)
self.options_layout.addWidget(self.keep_cover_aspect_checkbox, 1, 0, 1, 1)
self.options_layout.addWidget(self.upload_grayscale_checkbox, 1, 1, 1, 1)
self.options_layout.setRowStretch(2, 1)
self.upload_covers_checkbox_clicked(self.upload_covers)
@property
def upload_covers(self):
return self.upload_covers_checkbox.isChecked()
@property
def upload_grayscale(self):
return self.upload_grayscale_checkbox.isChecked()
@property
def keep_cover_aspect(self):
return self.keep_cover_aspect_checkbox.isChecked()
def upload_covers_checkbox_clicked(self, checked):
self.upload_grayscale_checkbox.setEnabled(checked)
self.keep_cover_aspect_checkbox.setEnabled(checked)
class DeviceListGroupBox(DeviceOptionsGroupBox):
def __init__(self, parent, device):
super(DeviceListGroupBox, self).__init__(parent, device)
self.setTitle(_("Show as on device"))
self.options_layout = QGridLayout()
self.options_layout.setObjectName("options_layout")
self.setLayout(self.options_layout)
self.show_recommendations_checkbox = create_checkbox(
_("Show Recommendations"),
_('Kobo shows recommendations on the device. In some cases these have '
'files but in other cases they are just pointers to the web site to buy. '
'Enable if you wish to see/delete them.'),
device.get_pref('show_recommendations')
)
self.show_archived_books_checkbox = create_checkbox(
_("Show archived books"),
_('Archived books are listed on the device but need to be downloaded to read.'
' Use this option to show these books and match them with books in the calibre library.'),
device.get_pref('show_archived_books')
)
self.show_previews_checkbox = create_checkbox(
_('Show Previews'),
_('Kobo previews are included on the Touch and some other versions'
' by default they are no longer displayed as there is no good reason to '
'see them. Enable if you wish to see/delete them.'),
device.get_pref('show_previews')
)
self.options_layout.addWidget(self.show_recommendations_checkbox, 0, 0, 1, 1)
self.options_layout.addWidget(self.show_archived_books_checkbox, 0, 1, 1, 1)
self.options_layout.addWidget(self.show_previews_checkbox, 1, 0, 1, 1)
self.options_layout.setRowStretch(1, 1)
@property
def show_recommendations(self):
return self.show_recommendations_checkbox.isChecked()
@property
def show_archived_books(self):
return self.show_archived_books_checkbox.isChecked()
@property
def show_previews(self):
return self.show_previews_checkbox.isChecked()
class AdvancedGroupBox(DeviceOptionsGroupBox):
def __init__(self, parent, device):
super(AdvancedGroupBox, self).__init__(parent, device, _("Advanced Options"))
# self.setTitle(_("Advanced Options"))
self.options_layout = QGridLayout()
self.options_layout.setObjectName("options_layout")
self.setLayout(self.options_layout)
self.support_newer_firmware_checkbox = create_checkbox(
_("Attempt to support newer firmware"),
_('Kobo routinely updates the firmware and the '
'database version. With this option Calibre will attempt '
'to perform full read-write functionality - Here be Dragons!! '
'Enable only if you are comfortable with restoring your kobo '
'to factory defaults and testing software. '
'This driver supports firmware V2.x.x and DBVersion up to ') + unicode(device.supported_dbversion),
device.get_pref('support_newer_firmware')
)
self.debugging_title_checkbox = create_checkbox(
_("Title to test when debugging"),
_('Part of title of a book that can be used when doing some tests for debugging. '
'The test is to see if the string is contained in the title of a book. '
'The better the match, the less extraneous output.'),
device.get_pref('debugging_title')
)
self.debugging_title_label = QLabel(_('Title to test when debugging'))
self.debugging_title_edit = QLineEdit(self)
self.debugging_title_edit.setToolTip(_('Part of title of a book that can be used when doing some tests for debugging. '
'The test is to see if the string is contained in the title of a book. '
'The better the match, the less extraneous output.'))
self.debugging_title_edit.setText(device.get_pref('debugging_title'))
self.debugging_title_label.setBuddy(self.debugging_title_edit)
self.options_layout.addWidget(self.support_newer_firmware_checkbox, 0, 0, 1, 2)
self.options_layout.addWidget(self.debugging_title_label, 1, 0, 1, 1)
self.options_layout.addWidget(self.debugging_title_edit, 1, 1, 1, 1)
self.options_layout.setRowStretch(1, 2)
@property
def support_newer_firmware(self):
return self.support_newer_firmware_checkbox.isChecked()
@property
def debugging_title(self):
return self.debugging_title_edit.text().strip()
class MetadataGroupBox(DeviceOptionsGroupBox):
def __init__(self, parent, device):
super(MetadataGroupBox, self).__init__(parent, device)
self.setTitle(_("Metadata Options"))
self.options_layout = QGridLayout()
self.options_layout.setObjectName("options_layout")
self.setLayout(self.options_layout)
self.update_device_metadata_checkbox = create_checkbox(
_("Update metadata on the device"),
_('Update the metadata on the device when it is connected. '
'Be careful when doing this as it will take time and could make the initial connection take a long time.'),
device.get_pref('update_device_metadata')
)
self.options_layout.addWidget(self.update_device_metadata_checkbox, 0, 0, 1, 2)
self.update_device_metadata_checkbox.clicked.connect(self.update_device_metadata_checkbox_clicked)
self.update_series_checkbox = create_checkbox(
_("Set Series information"),
_('The book lists on the Kobo devices can display series information. '
'This is not read by the device from the sideloaded books. '
'Series information can only be added to the device after the book has been processed by the device. '
'Enable if you wish to set series information.'),
device.get_pref('update_series')
)
self.options_layout.addWidget(self.update_series_checkbox, 1, 0, 1, 2)
self.options_layout.setRowStretch(1, 1)
@property
def update_series(self):
return self.update_series_checkbox.isChecked()
@property
def update_device_metadata(self):
return self.update_series_checkbox.isChecked()
def update_device_metadata_checkbox_clicked(self, checked):
self.update_series_checkbox.setEnabled(checked)
if __name__ == '__main__':
from calibre.gui2 import Application
from calibre.devices.kobo.driver import KOBOTOUCH
from calibre.devices.scanner import DeviceScanner
s = DeviceScanner()
s.scan()
app = Application([])
debug_print("KOBOTOUCH:", KOBOTOUCH)
dev = KOBOTOUCH(None)
# dev.startup()
# cd = dev.detect_managed_devices(s.devices)
# dev.open(cd, 'test')
cw = dev.config_widget()
d = QDialog()
d.l = QVBoxLayout()
d.setLayout(d.l)
d.l.addWidget(cw)
bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
d.l.addWidget(bb)
bb.accepted.connect(d.accept)
bb.rejected.connect(d.reject)
if d.exec_() == d.Accepted:
cw.commit()
dev.shutdown()

View File

@ -0,0 +1,408 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, #division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import weakref, textwrap
from PyQt5.Qt import (QWidget, QListWidgetItem, Qt, QToolButton, QLabel,
QTabWidget, QGridLayout, QListWidget, QIcon, QLineEdit, QVBoxLayout,
QPushButton, QGroupBox, QScrollArea, QHBoxLayout, QComboBox,
pyqtSignal, QSizePolicy, QDialog, QDialogButtonBox, QPlainTextEdit,
QApplication, QSize, QCheckBox, QSpacerItem)
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.gui2.device_drivers.mtp_config import (FormatsConfig, TemplateConfig)
from calibre.devices.usbms.driver import debug_print
def wrap_msg(msg):
return textwrap.fill(msg.strip(), 100)
def setToolTipFor(widget, tt):
widget.setToolTip(wrap_msg(tt))
def create_checkbox(title, tt, state):
cb = QCheckBox(title)
cb.setToolTip(wrap_msg(tt))
cb.setChecked(bool(state))
return cb
class TabbedDeviceConfig(QTabWidget):
"""
This is a generic Tabbed Device config widget. It designed for devices with more
complex configuration. But, it is backwards compatible to the standard device
configuration widget.
The configuration made up of two default tabs plus extra tabs as needed for the
device. The extra tabs are defined as part of the subclass of this widget for
the device.
The two default tabs are the "File Formats" and "Extra Customization". These
tabs are the same as the two sections of the standard device configuration
widget. The second of these tabs will only be created if the device driver has
extra configuration options. All options on these tabs work the same way as for
the standard device configuration widget.
When implementing a subclass for a device driver, create tabs, subclassed from
DeviceConfigTab, for each set of options. Within the tabs, group boxes, subclassed
from DeviceOptionsGroupBox, are created to further group the options. The group
boxes can be coded to support any control type and dependencies between them.
"""
def __init__(self, device_settings, all_formats, supports_subdirs,
must_read_metadata, supports_use_author_sort,
extra_customization_message, device,
extra_customization_choices=None, parent=None):
QTabWidget.__init__(self, parent)
self._device = weakref.ref(device)
self.device_settings = device_settings
self.all_formats = set(all_formats)
self.supports_subdirs = supports_subdirs
self.must_read_metadata = must_read_metadata
self.supports_use_author_sort = supports_use_author_sort
self.extra_customization_message = extra_customization_message
self.extra_customization_choices = extra_customization_choices
try:
self.device_name = device.get_gui_name()
except TypeError:
self.device_name = getattr(device, 'gui_name', None) or _('Device')
if device.USER_CAN_ADD_NEW_FORMATS:
self.all_formats = set(self.all_formats) | set(BOOK_EXTENSIONS)
self.base = QWidget(self)
# self.insertTab(0, self.base, _('Configure %s') % self.device.current_friendly_name)
self.insertTab(0, self.base, _("File Formats"))
l = self.base.l = QGridLayout(self.base)
self.base.setLayout(l)
self.formats = FormatsConfig(self.all_formats, device_settings.format_map)
if device.HIDE_FORMATS_CONFIG_BOX:
self.formats.hide()
self.opt_use_subdirs = create_checkbox(
_("Use sub-directories"),
_('Place files in sub-directories if the device supports them'),
device_settings.use_subdirs
)
self.opt_read_metadata = create_checkbox(
_("Read metadata from files on device"),
_('Read metadata from files on device'),
device_settings.read_metadata
)
self.template = TemplateConfig(device_settings.save_template)
self.opt_use_author_sort = create_checkbox(
_("Use author sort for author"),
_("Use author sort for author"),
device_settings.read_metadata
)
self.opt_use_author_sort.setObjectName("opt_use_author_sort")
self.base.la = la = QLabel(_(
'Choose the formats to send to the %s')%self.device_name)
la.setWordWrap(True)
l.addWidget(la, 1, 0, 1, 1)
l.addWidget(self.formats, 2, 0, 1, 1)
l.addWidget(self.opt_read_metadata, 3, 0, 1, 1)
l.addWidget(self.opt_use_subdirs, 4, 0, 1, 1)
l.addWidget(self.opt_use_author_sort, 5, 0, 1, 1)
l.addWidget(self.template, 6, 0, 1, 1)
l.setRowStretch(2, 10)
if device.HIDE_FORMATS_CONFIG_BOX:
self.formats.hide()
if supports_subdirs:
self.opt_use_subdirs.setChecked(device_settings.use_subdirs)
else:
self.opt_use_subdirs.hide()
if not must_read_metadata:
self.opt_read_metadata.setChecked(device_settings.read_metadata)
else:
self.opt_read_metadata.hide()
if supports_use_author_sort:
self.opt_use_author_sort.setChecked(device_settings.use_author_sort)
else:
self.opt_use_author_sort.hide()
self.extra_tab = ExtraCustomization(self.extra_customization_message,
self.extra_customization_choices,
self.device_settings)
# Only display the extra customization tab if there are options on it.
if self.extra_tab.has_extra_customizations:
self.addTab(self.extra_tab, _('Extra Customization'))
self.setCurrentIndex(0)
def __getattr__(self, attr_name):
"If the object doesn't have an attribute, then check each tab."
try:
return super(TabbedDeviceConfig, self).__getattr__(attr_name)
except AttributeError as ae:
for i in range(0, self.count()):
atab = self.widget(i)
try:
return getattr(atab, attr_name)
except AttributeError:
pass
raise ae
def get_pref(self, key):
debug_print("get_pref - self.device.prefs", self.device.prefs)
p = self.device.prefs.get(self.current_device_key, {})
if not p:
self.device.prefs[self.current_device_key] = p
debug_print("get_pref - self.device.get_pref(key)", self.device.get_pref(key))
return self.device.get_pref(key)
@property
def device(self):
return self._device()
def format_map(self):
# formats = [unicode(self.columns.item(i).data(Qt.UserRole) or '') for i in range(self.columns.count()) if self.columns.item(i).checkState()==Qt.Checked]
return self.formats.format_map
def use_subdirs(self):
return self.opt_use_subdirs.isChecked()
def read_metadata(self):
return self.opt_read_metadata.isChecked()
def use_author_sort(self):
return self.opt_use_author_sort.isChecked()
@property
def opt_save_template(self):
# Really shouldn't be accessing the template this way
return self.template.t
def text(self):
# Really shouldn't be accessing the template this way
return self.template.t.text()
@property
def opt_extra_customization(self):
return self.extra_tab.opt_extra_customization
@property
def label(self):
return self.opt_save_template
def validate(self):
if hasattr(self, 'formats'):
if not self.formats.validate():
return False
if not self.template.validate():
return False
return True
def commit(self):
debug_print("TabbedDeviceConfig::commit: start")
p = self.device._configProxy()
debug_print("commit: starting setting=%s" % (p, ))
f = self.formats.format_map
debug_print("commit: self.formats.format_map=", self.formats.format_map)
debug_print("commit: self.device.prefs['format_map']=", self.device.prefs['format_map'])
if f and f != self.device.prefs['format_map']:
p['format_map'] = f
f = self.use_subdirs()
if f != self.get_pref('use_subdirs'):
p['use_subdirs'] = f
f = self.read_metadata()
if f != self.get_pref('read_metadata'):
p['read_metadata'] = f
t = self.template.template
if t and t != self.device.prefs['save_template']:
p['save_template'] = t
p['extra_customization'] = self.extra_tab.extra_customization()
return p
class DeviceConfigTab(QWidget): # {{{
'''
This is an abstraction for a tab in the configuration. The main reason for it is to
abstract the properties of the configuration tab. When a property is accessed, it
will iterate over all known widgets looking for the property.
'''
def __init__(self, parent=None):
QWidget.__init__(self)
self.parent = parent
self.widgets = []
def add_widget(self, widget):
self.widgets.append(widget)
def __getattr__(self, attr_name):
try:
return super(DeviceConfigTab, self).__getattr__(attr_name)
except AttributeError as ae:
for awidget in self.widgets:
try:
return getattr(awidget, attr_name)
except AttributeError:
pass
raise ae
class ExtraCustomization(DeviceConfigTab): # {{{
def __init__(self, extra_customization_message, extra_customization_choices, device_settings):
super(ExtraCustomization, self).__init__()
debug_print("ExtraCustomization.__init__ - extra_customization_message=", extra_customization_message)
debug_print("ExtraCustomization.__init__ - extra_customization_choices=", extra_customization_choices)
debug_print("ExtraCustomization.__init__ - device_settings.extra_customization=", device_settings.extra_customization)
debug_print("ExtraCustomization.__init__ - device_settings=", device_settings)
self.extra_customization_message = extra_customization_message
self.l = QVBoxLayout(self)
self.setLayout(self.l)
options_group = QGroupBox(_("Extra driver customization options"), self)
self.l.addWidget(options_group)
self.extra_layout = QGridLayout()
self.extra_layout.setObjectName("extra_layout")
options_group.setLayout(self.extra_layout)
if extra_customization_message:
extra_customization_choices = extra_customization_choices or {}
def parse_msg(m):
msg, _, tt = m.partition(':::') if m else ('', '', '')
return msg.strip(), textwrap.fill(tt.strip(), 100)
if isinstance(extra_customization_message, list):
self.opt_extra_customization = []
if len(extra_customization_message) > 6:
row_func = lambda x, y: ((x/2) * 2) + y
col_func = lambda x: x%2
else:
row_func = lambda x, y: x*2 + y
col_func = lambda x: 0
for i, m in enumerate(extra_customization_message):
label_text, tt = parse_msg(m)
if not label_text:
self.opt_extra_customization.append(None)
continue
if isinstance(device_settings.extra_customization[i], bool):
self.opt_extra_customization.append(QCheckBox(label_text))
self.opt_extra_customization[-1].setToolTip(tt)
self.opt_extra_customization[i].setChecked(bool(device_settings.extra_customization[i]))
elif i in extra_customization_choices:
cb = QComboBox(self)
self.opt_extra_customization.append(cb)
l = QLabel(label_text)
l.setToolTip(tt), cb.setToolTip(tt), l.setBuddy(cb), cb.setToolTip(tt)
for li in sorted(extra_customization_choices[i]):
self.opt_extra_customization[i].addItem(li)
cb.setCurrentIndex(max(0, cb.findText(device_settings.extra_customization[i])))
else:
self.opt_extra_customization.append(QLineEdit(self))
l = QLabel(label_text)
l.setToolTip(tt)
self.opt_extra_customization[i].setToolTip(tt)
l.setBuddy(self.opt_extra_customization[i])
l.setWordWrap(True)
self.opt_extra_customization[i].setText(device_settings.extra_customization[i])
self.opt_extra_customization[i].setCursorPosition(0)
self.extra_layout.addWidget(l, row_func(i + 2, 0), col_func(i))
self.extra_layout.addWidget(self.opt_extra_customization[i],
row_func(i + 2, 1), col_func(i))
spacerItem1 = QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.extra_layout.addItem(spacerItem1, row_func(i + 2 + 2, 1), 0, 1, 2)
self.extra_layout.setRowStretch(row_func(i + 2 + 2, 1), 2)
else:
self.opt_extra_customization = QLineEdit()
label_text, tt = parse_msg(extra_customization_message)
l = QLabel(label_text)
l.setToolTip(tt)
l.setBuddy(self.opt_extra_customization)
l.setWordWrap(True)
if device_settings.extra_customization:
self.opt_extra_customization.setText(device_settings.extra_customization)
self.opt_extra_customization.setCursorPosition(0)
self.opt_extra_customization.setCursorPosition(0)
self.extra_layout.addWidget(l, 0, 0)
self.extra_layout.addWidget(self.opt_extra_customization, 1, 0)
def extra_customization(self):
ec = []
if self.extra_customization_message:
if isinstance(self.extra_customization_message, list):
for i in range(0, len(self.extra_customization_message)):
if self.opt_extra_customization[i] is None:
ec.append(None)
continue
if hasattr(self.opt_extra_customization[i], 'isChecked'):
ec.append(self.opt_extra_customization[i].isChecked())
elif hasattr(self.opt_extra_customization[i], 'currentText'):
ec.append(unicode(self.opt_extra_customization[i].currentText()).strip())
else:
ec.append(unicode(self.opt_extra_customization[i].text()).strip())
else:
ec = unicode(self.opt_extra_customization.text()).strip()
if not ec:
ec = None
return ec
@property
def has_extra_customizations(self):
debug_print("ExtraCustomization::has_extra_customizations - self.extra_customization_message", self.extra_customization_message)
return self.extra_customization_message and len(self.extra_customization_message) > 0
# }}}
class DeviceOptionsGroupBox(QGroupBox):
"""
This is a container for the individual options for a device driver.
"""
def __init__(self, parent, device=None, title=_("Unknown")):
QGroupBox.__init__(self, parent)
self.device = device
self.setTitle(title)
if __name__ == '__main__':
from calibre.gui2 import Application
from calibre.devices.kobo.driver import KOBO
from calibre.devices.scanner import DeviceScanner
s = DeviceScanner()
s.scan()
app = Application([])
dev = KOBO(None)
debug_print("KOBO:", KOBO)
# dev.startup()
# cd = dev.detect_managed_devices(s.devices)
# dev.open(cd, 'test')
cw = dev.config_widget()
d = QDialog()
d.l = QVBoxLayout()
d.setLayout(d.l)
d.l.addWidget(cw)
bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
d.l.addWidget(bb)
bb.accepted.connect(d.accept)
bb.rejected.connect(d.reject)
if d.exec_() == d.Accepted:
cw.commit()
dev.shutdown()