%PDF- %PDF-
Direktori : /proc/thread-self/root/usr/lib/calibre/calibre/gui2/wizard/ |
Current File : //proc/thread-self/root/usr/lib/calibre/calibre/gui2/wizard/__init__.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __docformat__ = 'restructuredtext en' import os import re import traceback from contextlib import closing, suppress from qt.core import ( QAbstractListModel, QDir, QIcon, QItemSelection, QItemSelectionModel, Qt, QWizard, QWizardPage, pyqtSignal ) from calibre import __appname__ from calibre.constants import filesystem_encoding, isportable, iswindows from calibre.gui2 import choose_dir, error_dialog from calibre.gui2.wizard.device_ui import Ui_WizardPage as DeviceUI from calibre.gui2.wizard.finish_ui import Ui_WizardPage as FinishUI from calibre.gui2.wizard.kindle_ui import Ui_WizardPage as KindleUI from calibre.gui2.wizard.library_ui import Ui_WizardPage as LibraryUI from calibre.gui2.wizard.send_email import smtp_prefs from calibre.gui2.wizard.stanza_ui import Ui_WizardPage as StanzaUI from calibre.utils.config import dynamic, prefs from calibre.utils.localization import localize_user_manual_link from polyglot.builtins import iteritems # Devices {{{ def gettext(name): return name, __builtins__['_'](name) class Device: output_profile = 'generic_eink' output_format = 'EPUB' untranslated_name, name = gettext('Generic e-ink device') manufacturer = 'Generic' id = 'default' supports_color = False @classmethod def set_output_profile(cls): if cls.output_profile: from calibre.ebooks.conversion.config import load_defaults, save_defaults recs = load_defaults('page_setup') recs['output_profile'] = cls.output_profile save_defaults('page_setup', recs) @classmethod def set_output_format(cls): if cls.output_format: prefs.set('output_format', cls.output_format.lower()) @classmethod def commit(cls): cls.set_output_profile() cls.set_output_format() if cls.supports_color: from calibre.ebooks.conversion.config import load_defaults, save_defaults recs = load_defaults('comic_input') recs['dont_grayscale'] = True save_defaults('comic_input', recs) class Smartphone(Device): id = 'smartphone' untranslated_name, name = gettext('Smartphone') supports_color = True class Tablet(Device): id = 'tablet' untranslated_name, name = gettext('iPad like tablet') output_profile = 'tablet' supports_color = True class Kindle(Device): output_profile = 'kindle' output_format = 'MOBI' untranslated_name, name = gettext('Kindle Basic (all models)') manufacturer = 'Amazon' id = 'kindle' class JetBook(Device): output_profile = 'jetbook5' output_format = 'EPUB' name = 'JetBook' manufacturer = 'Ectaco' id = 'jetbook' class JetBookMini(Device): output_profile = 'jetbook5' output_format = 'FB2' name = 'JetBook Mini' manufacturer = 'Ectaco' id = 'jetbookmini' class KindleDX(Kindle): output_profile = 'kindle_dx' output_format = 'MOBI' name = 'Kindle DX' id = 'kindledx' class KindleFire(KindleDX): untranslated_name, name = gettext('Kindle Fire and Fire HD') id = 'kindle_fire' output_profile = 'kindle_fire' supports_color = True class KindlePW(Kindle): name = 'Kindle PaperWhite' id = 'kindle_pw' output_profile = 'kindle_pw3' class KindleVoyage(Kindle): name = 'Kindle Voyage/Oasis' id = 'kindle_voyage' output_profile = 'kindle_voyage' class Sony505(Device): output_profile = 'sony' untranslated_name, name = gettext('All other SONY devices') output_format = 'EPUB' manufacturer = 'SONY' id = 'prs505' class Kobo(Device): untranslated_name, name = gettext('Kobo and Kobo Touch Readers') manufacturer = 'Kobo' output_profile = 'kobo' output_format = 'EPUB' id = 'kobo' class KoboVox(Kobo): untranslated_name, name = gettext('Kobo Vox, Aura and Glo families') output_profile = 'tablet' id = 'kobo_vox' class Booq(Device): name = 'bq Classic' manufacturer = 'Booq' output_profile = 'sony' output_format = 'EPUB' id = 'booq' class TheBook(Device): name = 'The Book' manufacturer = 'Augen' output_profile = 'sony' output_format = 'EPUB' id = 'thebook' class Avant(Booq): name = 'bq Avant' class AvantXL(Booq): name = 'bq Avant XL' output_profile = 'ipad' class BooqPocketPlus(Booq): name = 'bq Pocket Plus' output_profile = 'sony300' class BooqCervantes(Booq): name = 'bq Cervantes' class BOOX(Device): untranslated_name, name = gettext('BOOX MAX, N96, i86, C67ML, M96, etc.') manufacturer = 'Onyx' output_profile = 'generic_eink_hd' output_format = 'EPUB' id = 'boox_eink' class Sony300(Sony505): name = 'SONY Reader Pocket Edition' id = 'prs300' output_profile = 'sony300' class Sony900(Sony505): name = 'SONY Reader Daily Edition' id = 'prs900' output_profile = 'sony900' class SonyT3(Sony505): name = 'SONY Reader T3' id = 'prst3' output_profile = 'sonyt3' class Nook(Sony505): id = 'nook' untranslated_name, name = gettext('Nook and Nook Simple Reader') manufacturer = 'Barnes & Noble' output_profile = 'nook' class NookColor(Nook): id = 'nook_color' name = 'Nook Color' output_profile = 'nook_color' supports_color = True class NookTablet(NookColor): id = 'nook_tablet' name = 'Nook Tablet/HD' output_profile = 'nook_hd_plus' class CybookG3(Device): name = 'Cybook Gen 3' output_format = 'MOBI' output_profile = 'cybookg3' manufacturer = 'Bookeen' id = 'cybookg3' class CybookOpus(CybookG3): name = 'Cybook Opus' output_format = 'EPUB' output_profile = 'cybook_opus' id = 'cybook_opus' class CybookOrizon(CybookOpus): name = 'Cybook Orizon' id = 'cybook_orizon' class CybookOdyssey(CybookOpus): name = 'Cybook Odyssey' id = 'cybook_odyssey' class CybookMuse(CybookOpus): name = 'Cybook Muse' id = 'cybook_muse' output_profile = 'tablet' class BookeenDiva(CybookOpus): name = 'Bookeen Diva HD' id = 'bookeen_diva' output_profile = 'tablet' class PocketBook360(CybookOpus): manufacturer = 'PocketBook' name = _('PocketBook 360 and newer models') id = 'pocketbook360' output_profile = 'cybook_opus' class PocketBook(CybookG3): manufacturer = 'PocketBook' name = 'PocketBook 301/302' id = 'pocketbook' output_profile = 'cybookg3' class PocketBook900(PocketBook): name = 'PocketBook 900' id = 'pocketbook900' output_profile = 'pocketbook_900' class PocketBookPro912(PocketBook): name = 'PocketBook Pro 912' id = 'pocketbookpro912' output_profile = 'pocketbook_pro_912' class PocketBookLux(PocketBook): untranslated_name, name = gettext('PocketBook Lux (1-5) and Basic 4') id = 'pocketbooklux' short_name = 'pocketbook_lux' class PocketBookHD(PocketBook): name = 'PocketBook PocketBook HD Touch (1-3)' id = 'pocketbookhd' short_name = 'pocketbook_hd' class PocketBookInkpad3(PocketBook): untranslated_name, name = gettext('PocketBook Inkpad 3 (Pro) and X') id = 'pocketbookinkpad3' short_name = 'pocketbook_inkpad3' class iPhone(Device): name = 'iPhone/iPad/iPod Touch' output_format = 'EPUB' manufacturer = 'Apple' id = 'iphone' supports_color = True output_profile = 'ipad3' class Android(Device): untranslated_name, name = gettext('Android phone') output_format = 'EPUB' manufacturer = 'Android' id = 'android' supports_color = True @classmethod def commit(cls): from calibre.customize.ui import device_plugins super().commit() for plugin in device_plugins(include_disabled=True): if hasattr(plugin, 'configure_for_generic_epub_app'): plugin.configure_for_generic_epub_app() class AndroidTablet(Android): untranslated_name, name = gettext('Android tablet') id = 'android_tablet' output_profile = 'tablet' class AndroidPhoneWithKindle(Android): untranslated_name, name = gettext('Android phone with Kindle reader') output_format = 'MOBI' id = 'android_phone_with_kindle' output_profile = 'kindle' @classmethod def commit(cls): from calibre.customize.ui import device_plugins super(Android, cls).commit() for plugin in device_plugins(include_disabled=True): if hasattr(plugin, 'configure_for_kindle_app'): plugin.configure_for_kindle_app() class AndroidTabletWithKindle(AndroidPhoneWithKindle): untranslated_name, name = gettext('Android tablet with Kindle reader') id = 'android_tablet_with_kindle' output_profile = 'kindle_fire' class HanlinV3(Device): name = 'Hanlin V3' output_format = 'EPUB' output_profile = 'hanlinv3' manufacturer = 'Jinke' id = 'hanlinv3' class HanlinV5(HanlinV3): name = 'Hanlin V5' output_profile = 'hanlinv5' id = 'hanlinv5' class BeBook(HanlinV3): name = 'BeBook' manufacturer = 'BeBook' id = 'bebook' class BeBookMini(HanlinV5): name = 'BeBook Mini' manufacturer = 'BeBook' id = 'bebook_mini' class EZReader(HanlinV3): name = 'EZReader' manufacturer = 'Astak' id = 'ezreader' class EZReaderPP(HanlinV5): name = 'EZReader Pocket Pro' manufacturer = 'Astak' id = 'ezreader_pp' # }}} def get_devices(): for x in globals().values(): if isinstance(x, type) and issubclass(x, Device): yield x def get_manufacturers(): mans = set() for x in get_devices(): mans.add(x.manufacturer) if Device.manufacturer in mans: mans.remove(Device.manufacturer) return [Device.manufacturer] + sorted(mans) def get_devices_of(manufacturer): ans = [d for d in get_devices() if d.manufacturer == manufacturer] return sorted(ans, key=lambda x: x.name) class ManufacturerModel(QAbstractListModel): def __init__(self): QAbstractListModel.__init__(self) self.manufacturers = get_manufacturers() def rowCount(self, p): return len(self.manufacturers) def columnCount(self, p): return 1 def data(self, index, role): if role == Qt.ItemDataRole.DisplayRole: ans = self.manufacturers[index.row()] if ans == Device.manufacturer: ans = _('Generic') return ans if role == Qt.ItemDataRole.UserRole: return self.manufacturers[index.row()] return None def index_of(self, man): for i, x in enumerate(self.manufacturers): if x == man: return self.index(i) class DeviceModel(QAbstractListModel): def __init__(self, manufacturer): QAbstractListModel.__init__(self) self.devices = get_devices_of(manufacturer) def rowCount(self, p): return len(self.devices) def columnCount(self, p): return 1 def data(self, index, role): if role == Qt.ItemDataRole.DisplayRole: return (self.devices[index.row()].name) if role == Qt.ItemDataRole.UserRole: return self.devices[index.row()] return None def index_of(self, dev): for i, device in enumerate(self.devices): if device is dev: return self.index(i) class KindlePage(QWizardPage, KindleUI): ID = 3 def __init__(self): QWizardPage.__init__(self) self.setupUi(self) def initializePage(self): opts = smtp_prefs().parse() accs = [] has_default = False for x, ac in iteritems(opts.accounts): default = ac[2] if x.strip().endswith('@kindle.com'): accs.append((x, default)) if default: has_default = True if has_default: accs = [x for x in accs if x[1]] if accs: self.to_address.setText(accs[0][0]) def x(): t = str(self.to_address.text()) if t.strip(): return t.strip() self.send_email_widget.initialize(x) def commit(self): x = str(self.to_address.text()).strip() parts = x.split('@') if (len(parts) >= 2 and parts[0] and self.send_email_widget.set_email_settings(True)): conf = smtp_prefs() accounts = conf.parse().accounts if not accounts: accounts = {} for y in accounts.values(): y[2] = False accounts[x] = ['AZW, MOBI, TPZ, PRC, AZW1', True, True] conf.set('accounts', accounts) def nextId(self): return FinishPage.ID def retranslateUi(self, widget): KindleUI.retranslateUi(self, widget) if hasattr(self, 'send_email_widget'): self.send_email_widget.retranslateUi(self.send_email_widget) class StanzaPage(QWizardPage, StanzaUI): ID = 5 def __init__(self): QWizardPage.__init__(self) self.setupUi(self) try: self.instructions.setText(self.instructions.text() % localize_user_manual_link( 'https://manual.calibre-ebook.com/faq.html#how-do-i-use-calibre-with-my-ipad-iphone-ipod-touch')) except TypeError: pass # user manual link was already replaced self.instructions.setOpenExternalLinks(True) self.content_server.stateChanged[(int)].connect(self.set_port) def initializePage(self): from calibre.gui2 import config yes = config['autolaunch_server'] self.content_server.setChecked(yes) self.set_port() def nextId(self): return FinishPage.ID def commit(self): p = self.set_port() if p is not None: from calibre.srv.opts import change_settings change_settings(port=p) def set_port(self, *args): if not self.content_server.isChecked(): return import socket s = socket.socket() with closing(s): for p in range(8080, 8100): try: s.bind(('0.0.0.0', p)) t = str(self.instructions.text()) t = re.sub(r':\d+', ':'+str(p), t) self.instructions.setText(t) return p except: continue class DevicePage(QWizardPage, DeviceUI): ID = 2 def __init__(self): QWizardPage.__init__(self) self.setupUi(self) self.registerField("manufacturer", self.manufacturer_view) self.registerField("device", self.device_view) def initializePage(self): self.label.setText(_('Choose your e-book device. If your device is' ' not in the list, choose a "Generic" device.')) self.man_model = ManufacturerModel() self.manufacturer_view.setModel(self.man_model) previous = dynamic.get('welcome_wizard_device', False) if previous: previous = [x for x in get_devices() if x.id == previous] if not previous: previous = [Device] previous = previous[0] else: previous = Device idx = self.man_model.index_of(previous.manufacturer) if idx is None: idx = self.man_model.index_of(Device.manufacturer) previous = Device self.manufacturer_view.selectionModel().select(idx, QItemSelectionModel.SelectionFlag.Select) self.dev_model = DeviceModel(self.man_model.data(idx, Qt.ItemDataRole.UserRole)) idx = self.dev_model.index_of(previous) self.device_view.setModel(self.dev_model) self.device_view.selectionModel().select(idx, QItemSelectionModel.SelectionFlag.Select) self.manufacturer_view.selectionModel().selectionChanged[(QItemSelection, QItemSelection)].connect(self.manufacturer_changed) def manufacturer_changed(self, current, previous): new = list(current.indexes())[0] man = self.man_model.data(new, Qt.ItemDataRole.UserRole) self.dev_model = DeviceModel(man) self.device_view.setModel(self.dev_model) self.device_view.selectionModel().select(self.dev_model.index(0), QItemSelectionModel.SelectionFlag.Select) def commit(self): idx = list(self.device_view.selectionModel().selectedIndexes())[0] dev = self.dev_model.data(idx, Qt.ItemDataRole.UserRole) dev.commit() dynamic.set('welcome_wizard_device', dev.id) def nextId(self): idx = list(self.device_view.selectionModel().selectedIndexes())[0] dev = self.dev_model.data(idx, Qt.ItemDataRole.UserRole) if dev in (Kindle, KindleDX, KindleFire, KindlePW, KindleVoyage): return KindlePage.ID if dev is iPhone: return StanzaPage.ID return FinishPage.ID class LibraryPage(QWizardPage, LibraryUI): ID = 1 retranslate = pyqtSignal() def __init__(self): QWizardPage.__init__(self) self.made_dirs = [] self.initial_library_location = None self.setupUi(self) self.registerField('library_location', self.location) self.button_change.clicked.connect(self.change) self.init_languages() self.language.currentIndexChanged[int].connect(self.change_language) self.location.textChanged.connect(self.location_text_changed) self.set_move_lib_label_text() def makedirs(self, x): self.made_dirs.append(x) os.makedirs(x) def location_text_changed(self, newtext): self.completeChanged.emit() def set_move_lib_label_text(self): self.move_lib_label.setText(_( 'If you are moving calibre from an old computer to a new one,' ' please read <a href="{0}">the instructions</a>.').format( localize_user_manual_link( 'https://manual.calibre-ebook.com/faq.html#how-do-i-move-my-calibre-data-from-one-computer-to-another'))) def retranslateUi(self, widget): LibraryUI.retranslateUi(self, widget) self.set_move_lib_label_text() def init_languages(self): self.language.blockSignals(True) self.language.clear() from calibre.utils.localization import ( available_translations, get_lang, get_language, get_lc_messages_path ) lang = get_lang() lang = get_lc_messages_path(lang) if lang else lang if lang is None or lang not in available_translations(): lang = 'en' def get_esc_lang(l): if l == 'en': return 'English' return get_language(l) self.language.addItem(get_esc_lang(lang), (lang)) items = [(l, get_esc_lang(l)) for l in available_translations() if l != lang] if lang != 'en': items.append(('en', get_esc_lang('en'))) items.sort(key=lambda x: x[1]) for item in items: self.language.addItem(item[1], (item[0])) self.language.blockSignals(False) prefs['language'] = str(self.language.itemData(self.language.currentIndex()) or '') def change_language(self, idx): prefs['language'] = str(self.language.itemData(self.language.currentIndex()) or '') from polyglot.builtins import builtins builtins.__dict__['_'] = lambda x: x from calibre.ebooks.metadata.book.base import reset_field_metadata from calibre.gui2 import qt_app from calibre.utils.localization import set_translators set_translators() qt_app.load_translations() self.retranslate.emit() self.init_languages() reset_field_metadata() try: lang = prefs['language'].lower()[:2] metadata_plugins = { 'zh' : ('Douban Books',), 'fr' : ('Nicebooks',), 'ru' : ('OZON.ru',), }.get(lang, []) from calibre.customize.ui import enable_plugin for name in metadata_plugins: enable_plugin(name) except: pass lp = self.location.text() if lp == self.initial_library_location: self.set_initial_library_location() for x in globals().values(): if type(x) is type and hasattr(x, 'untranslated_name'): x.name = __builtins__['_'](x.untranslated_name) def is_library_dir_suitable(self, x): from calibre.db.legacy import LibraryDatabase try: return LibraryDatabase.exists_at(x) or not os.listdir(x) except: return False def validatePage(self): newloc = str(self.location.text()) if not self.is_library_dir_suitable(newloc): self.show_library_dir_error(newloc) return False return True def change(self): from calibre.db.legacy import LibraryDatabase x = choose_dir(self, 'database location dialog', _('Select location for books')) if x: if (iswindows and len(x) > LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT): return error_dialog(self, _('Too long'), _('Path to library too long. It must be less than' ' %d characters.')%(LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT), show=True) if not os.path.exists(x): try: self.makedirs(x) except: return error_dialog(self, _('Bad location'), _('Failed to create a folder at %s')%x, det_msg=traceback.format_exc(), show=True) if self.is_library_dir_suitable(x): self.location.setText(x) else: self.show_library_dir_error(x) def show_library_dir_error(self, x): if not isinstance(x, str): try: x = x.decode(filesystem_encoding) except: x = str(repr(x)) error_dialog(self, _('Bad location'), _('You must choose an empty folder for ' 'the calibre library. %s is not empty.')%x, show=True) def set_initial_library_location(self): lp = prefs['library_path'] self.default_library_name = None if not lp: fname = _('Calibre Library') try: base = os.path.expanduser('~') except ValueError: base = QDir.homePath().replace('/', os.sep) lp = os.path.join(base, fname) self.default_library_name = lp if not os.path.exists(lp): try: self.makedirs(lp) except: traceback.print_exc() try: lp = os.path.expanduser('~') except ValueError: lp = QDir.homePath().replace('/', os.sep) self.location.setText(lp) self.initial_library_location = lp def initializePage(self): self.set_initial_library_location() # Hide the library location settings if we are a portable install for x in ('location', 'button_change', 'libloc_label1', 'libloc_label2'): getattr(self, x).setVisible(not isportable) def isComplete(self): try: lp = str(self.location.text()) ans = bool(lp) and os.path.exists(lp) and os.path.isdir(lp) and os.access(lp, os.W_OK) except: ans = False return ans def commit(self): newloc = str(self.location.text()) try: dln = self.default_library_name if (dln and os.path.exists(dln) and not os.listdir(dln) and newloc != dln): os.rmdir(dln) except Exception: pass # dont leave behind any empty dirs for x in self.made_dirs: with suppress(OSError): os.rmdir(x) if not os.path.exists(newloc): os.makedirs(newloc) prefs['library_path'] = newloc def nextId(self): return DevicePage.ID class FinishPage(QWizardPage, FinishUI): ID = 4 def __init__(self): QWizardPage.__init__(self) self.setupUi(self) try: self.um_label.setText(self.um_label.text() % localize_user_manual_link('https://manual.calibre-ebook.com')) except TypeError: pass # link already localized def nextId(self): return -1 def commit(self): pass class Wizard(QWizard): BUTTON_TEXTS = { 'Next': '&Next >', 'Back': '< &Back', 'Cancel': 'Cancel', 'Finish': '&Finish', 'Commit': 'Commit' } # The latter is simply to mark the texts for translation if False: _('&Next >') _('< &Back') _('Cancel') _('&Finish') _('Commit') def __init__(self, parent): QWizard.__init__(self, parent) self.setWindowTitle(__appname__+' '+_('Welcome wizard')) self.setPixmap(QWizard.WizardPixmap.LogoPixmap, QIcon(I('library.png')).pixmap(48, 48)) self.setWizardStyle(QWizard.WizardStyle.ModernStyle) self.device_page = DevicePage() self.library_page = LibraryPage() self.library_page.retranslate.connect(self.retranslate) self.finish_page = FinishPage() self.set_finish_text() self.kindle_page = KindlePage() self.stanza_page = StanzaPage() self.setPage(self.library_page.ID, self.library_page) self.setPage(self.device_page.ID, self.device_page) self.setPage(self.finish_page.ID, self.finish_page) self.setPage(self.kindle_page.ID, self.kindle_page) self.setPage(self.stanza_page.ID, self.stanza_page) self.device_extra_page = None self.set_button_texts() self.resize(600, 520) def set_button_texts(self): for but, text in iteritems(self.BUTTON_TEXTS): self.setButtonText(getattr(self, but+'Button'), _(text)) def retranslate(self): for pid in self.pageIds(): page = self.page(pid) page.retranslateUi(page) self.set_button_texts() self.set_finish_text() def accept(self): pages = map(self.page, self.visitedPages()) for page in pages: page.commit() QWizard.accept(self) def set_finish_text(self, *args): bt = str("<em>" + self.buttonText(QWizard.WizardButton.FinishButton) + "</em>").replace('&', '') t = str(self.finish_page.finish_text.text()) if '%s' in t: self.finish_page.finish_text.setText(t%bt) def wizard(parent=None): w = Wizard(parent) return w if __name__ == '__main__': from calibre.gui2 import Application app = Application([]) wizard().exec()