class BlockingBusy(QDialog): def __init__(self, msg, parent=None, window_title=_('Working')): QDialog.__init__(self, parent) self._layout = QVBoxLayout() self.setLayout(self._layout) self.msg = QLabel(msg) # self.msg.setWordWrap(True) self.font = QFont() self.font.setPointSize(self.font.pointSize() + 8) self.msg.setFont(self.font) self.pi = ProgressIndicator(self) self.pi.setDisplaySize(100) self._layout.addWidget(self.pi, 0, Qt.AlignHCenter) self._layout.addSpacing(15) self._layout.addWidget(self.msg, 0, Qt.AlignHCenter) self.start() self.setWindowTitle(window_title) self.resize(self.sizeHint()) def start(self): self.pi.startAnimation() def stop(self): self.pi.stopAnimation() def accept(self): self.stop() return QDialog.accept(self) def reject(self): pass # Cannot cancel this dialog
def __init__(self, args, force_calibre_style=False, override_program_name=None, headless=False, color_prefs=gprefs): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] if headless: if not args: args = sys.argv[:1] args.extend(['-platformpluginpath', sys.extensions_location, '-platform', 'headless']) qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args] self.pi = plugins['progress_indicator'][0] QApplication.__init__(self, qargs) self.setup_styles(force_calibre_style) f = QFont(QApplication.font()) if (f.family(), f.pointSize()) == ('Sans Serif', 9): # Hard coded Qt settings, no user preference detected f.setPointSize(10) QApplication.setFont(f) f = QFontInfo(f) self.original_font = (f.family(), f.pointSize(), f.weight(), f.italic(), 100) if not self.using_calibre_style and self.style().objectName() == 'fusion': # Since Qt is using the fusion style anyway, specialize it self.load_calibre_style() fi = gprefs['font'] if fi is not None: font = QFont(*(fi[:4])) s = gprefs.get('font_stretch', None) if s is not None: font.setStretch(s) QApplication.setFont(font) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock() if not isosx: # OS X uses a native color dialog that does not support custom # colors self.color_prefs = color_prefs self.read_custom_colors() self.lastWindowClosed.connect(self.save_custom_colors) if isxp: error_dialog(None, _('Windows XP not supported'), '<p>' + _( 'calibre versions newer than 2.0 do not run on Windows XP. This is' ' because the graphics toolkit calibre uses (Qt 5) crashes a lot' ' on Windows XP. We suggest you stay with <a href="%s">calibre 1.48</a>' ' which works well on Windows XP.') % 'http://download.calibre-ebook.com/1.48.0/', show=True) raise SystemExit(1)
def __init__(self, args, force_calibre_style=False, override_program_name=None, headless=False): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] if headless: if not args: args = sys.argv[:1] args.extend([ '-platformpluginpath', sys.extensions_location, '-platform', 'headless' ]) qargs = [ i.encode('utf-8') if isinstance(i, unicode) else i for i in args ] self.pi = plugins['progress_indicator'][0] self.setup_styles(force_calibre_style) QApplication.__init__(self, qargs) f = QFont(QApplication.font()) if (f.family(), f.pointSize()) == ( 'Sans Serif', 9): # Hard coded Qt settings, no user preference detected f.setPointSize(10) QApplication.setFont(f) f = QFontInfo(f) self.original_font = (f.family(), f.pointSize(), f.weight(), f.italic(), 100) if not self.using_calibre_style and self.style().objectName( ) == 'fusion': # Since Qt is using the fusion style anyway, specialize it self.load_calibre_style() fi = gprefs['font'] if fi is not None: font = QFont(*(fi[:4])) s = gprefs.get('font_stretch', None) if s is not None: font.setStretch(s) QApplication.setFont(font) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock()
def setup_ui_font(self): f = QFont(QApplication.font()) q = (f.family(), f.pointSize()) if iswindows: if q == ('MS Shell Dlg 2', 8): # Qt default setting # Microsoft recommends the default font be Segoe UI at 9 pt # https://msdn.microsoft.com/en-us/library/windows/desktop/dn742483(v=vs.85).aspx f.setFamily('Segoe UI') f.setPointSize(9) QApplication.setFont(f) else: if q == ('Sans Serif', 9): # Hard coded Qt settings, no user preference detected f.setPointSize(10) QApplication.setFont(f) f = QFontInfo(f) self.original_font = (f.family(), f.pointSize(), f.weight(), f.italic(), 100)
def __init__(self, args, force_calibre_style=False, override_program_name=None, headless=False): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] if headless: if not args: args = sys.argv[:1] args.extend(['-platformpluginpath', sys.extensions_location, '-platform', 'headless']) qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args] self.pi = plugins['progress_indicator'][0] self.setup_styles(force_calibre_style) QApplication.__init__(self, qargs) f = QFont(QApplication.font()) if (f.family(), f.pointSize()) == ('Sans Serif', 9): # Hard coded Qt settings, no user preference detected f.setPointSize(10) QApplication.setFont(f) f = QFontInfo(f) self.original_font = (f.family(), f.pointSize(), f.weight(), f.italic(), 100) if not self.using_calibre_style and self.style().objectName() == 'fusion': # Since Qt is using the fusion style anyway, specialize it self.load_calibre_style() fi = gprefs['font'] if fi is not None: font = QFont(*(fi[:4])) s = gprefs.get('font_stretch', None) if s is not None: font.setStretch(s) QApplication.setFont(font) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock()
def __init__(self, args, force_calibre_style=False, override_program_name=None, headless=False, color_prefs=gprefs): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] if headless: if not args: args = sys.argv[:1] args.extend(['-platformpluginpath', sys.extensions_location, '-platform', 'headless']) self.headless = headless qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args] self.pi = plugins['progress_indicator'][0] QApplication.__init__(self, qargs) if islinux or isbsd: self.setAttribute(Qt.AA_DontUseNativeMenuBar, 'CALIBRE_NO_NATIVE_MENUBAR' in os.environ) self.setup_styles(force_calibre_style) f = QFont(QApplication.font()) if (f.family(), f.pointSize()) == ('Sans Serif', 9): # Hard coded Qt settings, no user preference detected f.setPointSize(10) QApplication.setFont(f) f = QFontInfo(f) self.original_font = (f.family(), f.pointSize(), f.weight(), f.italic(), 100) if not self.using_calibre_style and self.style().objectName() == 'fusion': # Since Qt is using the fusion style anyway, specialize it self.load_calibre_style() fi = gprefs['font'] if fi is not None: font = QFont(*(fi[:4])) s = gprefs.get('font_stretch', None) if s is not None: font.setStretch(s) QApplication.setFont(font) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock() if not isosx: # OS X uses a native color dialog that does not support custom # colors self.color_prefs = color_prefs self.read_custom_colors() self.lastWindowClosed.connect(self.save_custom_colors) if isxp: error_dialog(None, _('Windows XP not supported'), '<p>' + _( 'calibre versions newer than 2.0 do not run on Windows XP. This is' ' because the graphics toolkit calibre uses (Qt 5) crashes a lot' ' on Windows XP. We suggest you stay with <a href="%s">calibre 1.48</a>' ' which works well on Windows XP.') % 'http://download.calibre-ebook.com/1.48.0/', show=True) raise SystemExit(1) if iswindows: # On windows the highlighted colors for inactive widgets are the # same as non highlighted colors. This is a regression from Qt 4. # https://bugreports.qt-project.org/browse/QTBUG-41060 p = self.palette() for role in (p.Highlight, p.HighlightedText, p.Base, p.AlternateBase): p.setColor(p.Inactive, role, p.color(p.Active, role)) self.setPalette(p) # Prevent text copied to the clipboard from being lost on quit due to # Qt 5 bug: https://bugreports.qt-project.org/browse/QTBUG-41125 self.aboutToQuit.connect(self.flush_clipboard)
class MyBlockingBusy(QDialog): # {{{ all_done = pyqtSignal() def __init__(self, args, ids, db, refresh_books, cc_widgets, s_r_func, do_sr, sr_calls, parent=None, window_title=_('Working')): QDialog.__init__(self, parent) self._layout = l = QVBoxLayout() self.setLayout(l) self.msg = QLabel(_('Processing %d books, please wait...') % len(ids)) self.font = QFont() self.font.setPointSize(self.font.pointSize() + 8) self.msg.setFont(self.font) self.pi = ProgressIndicator(self) self.pi.setDisplaySize(100) self._layout.addWidget(self.pi, 0, Qt.AlignHCenter) self._layout.addSpacing(15) self._layout.addWidget(self.msg, 0, Qt.AlignHCenter) self.setWindowTitle(window_title + '...') self.setMinimumWidth(200) self.resize(self.sizeHint()) self.error = None self.all_done.connect(self.on_all_done, type=Qt.QueuedConnection) self.args, self.ids = args, ids self.db, self.cc_widgets = db, cc_widgets self.s_r_func = FunctionDispatcher(s_r_func) self.do_sr = do_sr self.sr_calls = sr_calls self.refresh_books = refresh_books def accept(self): pass def reject(self): pass def on_all_done(self): if not self.error: # The cc widgets can only be accessed in the GUI thread try: for w in self.cc_widgets: w.commit(self.ids) except Exception as err: import traceback self.error = (err, traceback.format_exc()) self.pi.stopAnimation() QDialog.accept(self) def exec_(self): self.thread = Thread(target=self.do_it) self.thread.start() self.pi.startAnimation() return QDialog.exec_(self) def do_it(self): try: self.do_all() except Exception as err: import traceback try: err = unicode(err) except: err = repr(err) self.error = (err, traceback.format_exc()) self.all_done.emit() def do_all(self): cache = self.db.new_api args = self.args # Title and authors if args.do_swap_ta: title_map = cache.all_field_for('title', self.ids) authors_map = cache.all_field_for('authors', self.ids) def new_title(authors): ans = authors_to_string(authors) return titlecase(ans) if args.do_title_case else ans new_title_map = {bid:new_title(authors) for bid, authors in authors_map.iteritems()} new_authors_map = {bid:string_to_authors(title) for bid, title in title_map.iteritems()} cache.set_field('authors', new_authors_map) cache.set_field('title', new_title_map) if args.do_title_case and not args.do_swap_ta: title_map = cache.all_field_for('title', self.ids) cache.set_field('title', {bid:titlecase(title) for bid, title in title_map.iteritems()}) if args.do_title_sort: lang_map = cache.all_field_for('languages', self.ids) title_map = cache.all_field_for('title', self.ids) def get_sort(book_id): if args.languages: lang = args.languages[0] else: try: lang = lang_map[book_id][0] except (KeyError, IndexError, TypeError, AttributeError): lang = 'eng' return title_sort(title_map[book_id], lang=lang) cache.set_field('sort', {bid:get_sort(bid) for bid in self.ids}) if args.au: authors = string_to_authors(args.au) cache.set_field('authors', {bid:authors for bid in self.ids}) if args.do_auto_author: aus_map = cache.author_sort_strings_for_books(self.ids) cache.set_field('author_sort', {book_id:' & '.join(aus_map[book_id]) for book_id in aus_map}) if args.aus and args.do_aus: cache.set_field('author_sort', {bid:args.aus for bid in self.ids}) # Covers if args.cover_action == 'remove': cache.set_cover({bid:None for bid in self.ids}) elif args.cover_action == 'generate': from calibre.ebooks import calibre_cover from calibre.ebooks.metadata import fmt_sidx from calibre.gui2 import config for book_id in self.ids: mi = self.db.get_metadata(book_id, index_is_id=True) series_string = None if mi.series: series_string = _('Book %(sidx)s of %(series)s')%dict( sidx=fmt_sidx(mi.series_index, use_roman=config['use_roman_numerals_for_series_number']), series=mi.series) cdata = calibre_cover(mi.title, mi.format_field('authors')[-1], series_string=series_string) cache.set_cover({book_id:cdata}) elif args.cover_action == 'fromfmt': for book_id in self.ids: fmts = cache.formats(book_id, verify_formats=False) if fmts: covers = [] for fmt in fmts: fmtf = cache.format(book_id, fmt, as_file=True) if fmtf is None: continue cdata, area = get_cover_data(fmtf, fmt) if cdata: covers.append((cdata, area)) covers.sort(key=lambda x: x[1]) if covers: cache.set_cover({book_id:covers[-1][0]}) elif args.cover_action == 'trim': from calibre.utils.magick import Image for book_id in self.ids: cdata = cache.cover(book_id) if cdata: im = Image() im.load(cdata) im.trim(tweaks['cover_trim_fuzz_value']) cdata = im.export('jpg') cache.set_cover({book_id:cdata}) elif args.cover_action == 'clone': cdata = None for book_id in self.ids: cdata = cache.cover(book_id) if cdata: break if cdata: cache.set_cover({bid:cdata for bid in self.ids if bid != book_id}) # Formats if args.do_remove_format: cache.remove_formats({bid:(args.remove_format,) for bid in self.ids}) if args.restore_original: for book_id in self.ids: formats = cache.formats(book_id) originals = tuple(x.upper() for x in formats if x.upper().startswith('ORIGINAL_')) for ofmt in originals: cache.restore_original_format(book_id, ofmt) # Various fields if args.rating != -1: cache.set_field('rating', {bid:args.rating*2 for bid in self.ids}) if args.clear_pub: cache.set_field('publisher', {bid:'' for bid in self.ids}) if args.pub: cache.set_field('publisher', {bid:args.pub for bid in self.ids}) if args.clear_series: cache.set_field('series', {bid:'' for bid in self.ids}) if args.pubdate is not None: cache.set_field('pubdate', {bid:args.pubdate for bid in self.ids}) if args.adddate is not None: cache.set_field('timestamp', {bid:args.adddate for bid in self.ids}) if args.do_series: sval = args.series_start_value if args.do_series_restart else cache.get_next_series_num_for(args.series, current_indices=True) cache.set_field('series', {bid:args.series for bid in self.ids}) if not args.series: cache.set_field('series_index', {bid:1.0 for bid in self.ids}) else: def next_series_num(bid, i): if args.do_series_restart: return sval + i next_num = _get_next_series_num_for_list(sorted(sval.itervalues()), unwrap=False) sval[bid] = next_num return next_num smap = {bid:next_series_num(bid, i) for i, bid in enumerate(self.ids)} if args.do_autonumber: cache.set_field('series_index', smap) elif tweaks['series_index_auto_increment'] != 'no_change': cache.set_field('series_index', {bid:1.0 for bid in self.ids}) if args.comments is not null: cache.set_field('comments', {bid:args.comments for bid in self.ids}) if args.do_remove_conv: cache.delete_conversion_options(self.ids) if args.clear_languages: cache.set_field('languages', {bid:() for bid in self.ids}) elif args.languages: cache.set_field('languages', {bid:args.languages for bid in self.ids}) if args.remove_all: cache.set_field('tags', {bid:() for bid in self.ids}) if args.add or args.remove: self.db.bulk_modify_tags(self.ids, add=args.add, remove=args.remove) if self.do_sr: for book_id in self.ids: self.s_r_func(book_id) if self.sr_calls: for field, book_id_val_map in self.sr_calls.iteritems(): self.refresh_books.update(self.db.new_api.set_field(field, book_id_val_map))