def __init__(self, parent, library_path, wait_time=2): QDialog.__init__(self, parent) self.l = QVBoxLayout() self.setLayout(self.l) self.l1 = QLabel('<b>'+_('Restoring database from backups, do not' ' interrupt, this will happen in three stages')+'...') self.setWindowTitle(_('Restoring database')) self.l.addWidget(self.l1) self.pb = QProgressBar(self) self.l.addWidget(self.pb) self.pb.setMaximum(0) self.pb.setMinimum(0) self.msg = QLabel('') self.l.addWidget(self.msg) self.msg.setWordWrap(True) self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Cancel) self.l.addWidget(self.bb) self.bb.rejected.connect(self.confirm_cancel) self.resize(self.sizeHint() + QSize(100, 50)) self.error = None self.rejected = False self.library_path = library_path self.update_signal.connect(self.do_update, type=Qt.ConnectionType.QueuedConnection) from calibre.db.restore import Restore self.restorer = Restore(library_path, self) self.restorer.daemon = True # Give the metadata backup thread time to stop QTimer.singleShot(wait_time * 1000, self.start)
def do_one_apply(self): if self.apply_current_idx >= len(self.apply_id_map): return self.finalize_apply() i, mi = self.apply_id_map[self.apply_current_idx] if self.gui.current_db.has_id(i): if isinstance(mi, tuple): opf, cover = mi if opf: mi = OPF(open(opf, 'rb'), basedir=os.path.dirname(opf), populate_spine=False).to_book_metadata() self.apply_mi(i, mi) if cover: self.gui.current_db.set_cover(i, open(cover, 'rb'), notify=False, commit=False) self.applied_ids.add(i) else: self.apply_mi(i, mi) self.apply_current_idx += 1 if self.apply_pd is not None: self.apply_pd.value += 1 QTimer.singleShot(5, self.do_one_apply)
def play(self, resume=False): self.status = "Switching to Player..." import player player.app = app struct, cells_by_id, columns_by_id = save(self.scene, resume=resume) window = player.MainWindow(playtest=True) window.setWindowModality(qt.ApplicationModal) window.setWindowState(self.windowState()) window.setGeometry(self.geometry()) windowcloseevent = window.closeEvent def closeevent(e): windowcloseevent(e) for it in window.scene.all(player.Cell): cells_by_id[it.id].revealed_resume = it.kind is not Cell.unknown window.closeEvent = closeevent def delayed(): window.load(struct) window.view.setSceneRect(self.view.sceneRect()) window.view.setTransform(self.view.transform()) window.view.horizontalScrollBar().setValue(self.view.horizontalScrollBar().value()) delta = window.view.mapTo(window.central_widget, QPoint(0, 0)) window.view.verticalScrollBar().setValue(self.view.verticalScrollBar().value()+delta.y()) self.status = "Done", 1 window.show() QTimer.singleShot(0, delayed)
def __init__(self, log, parent=None): QDialog.__init__(self, parent) self.log = log self.l = l = QVBoxLayout() self.setLayout(l) self.tb = QTextBrowser(self) l.addWidget(self.tb) self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) l.addWidget(self.bb) self.copy_button = self.bb.addButton( _('Copy to clipboard'), QDialogButtonBox.ButtonRole.ActionRole) self.copy_button.clicked.connect(self.copy_to_clipboard) self.copy_button.setIcon(QIcon(I('edit-copy.png'))) self.bb.rejected.connect(self.reject) self.bb.accepted.connect(self.accept) self.setWindowTitle(_('Download log')) self.setWindowIcon(QIcon(I('debug.png'))) self.resize(QSize(800, 400)) self.keep_updating = True self.last_html = None self.finished.connect(self.stop) QTimer.singleShot(100, self.update_log) self.show()
def main(): from calibre.gui2 import Application from qt.core import QMainWindow, QStatusBar, QTimer app = Application([]) w = QMainWindow() s = QStatusBar(w) w.setStatusBar(s) s.showMessage('Testing ProceedQuestion') w.show() p = ProceedQuestion(w) def doit(): p.dummy_question() p.dummy_question( action_label='A very long button for testing relayout (indeed)') p(lambda p: None, None, 'ass2', 'ass2', 'testing2', 'testing2', det_msg= 'details shown first, with a long line to test wrapping of text and width layout', show_det=True, show_ok=True) QTimer.singleShot(10, doit) app.exec_()
def do_one_isbn_add(self): try: db = self.gui.library_view.model().db try: x = self.isbn_books.pop(0) except IndexError: self.gui.library_view.model().books_added( self.isbn_add_dialog.value) self.isbn_add_dialog.accept() self.gui.iactions['Edit Metadata'].download_metadata( ids=self.add_by_isbn_ids, ensure_fields=frozenset(['title', 'authors'])) return mi = MetaInformation(None) mi.isbn = x['isbn'] if self.isbn_add_tags: mi.tags = list(self.isbn_add_tags) fmts = [] if x['path'] is None else [x['path']] self.add_by_isbn_ids.add(db.import_book(mi, fmts)) self.isbn_add_dialog.value += 1 QTimer.singleShot(10, self.do_one_isbn_add) except: self.isbn_add_dialog.accept() raise
def check_for_completions(self): from calibre.utils.filenames import retry_on_fail for job in tuple(self.jobs): started_path = job['path'] + '.started' result_path = job['path'] + '.result' if job['started'] and os.path.exists(result_path): self.jobs.remove(job) ret = -1 def read(result_path): nonlocal ret with open(result_path) as f: ret = int(f.read().strip()) retry_on_fail(read, result_path) retry_on_fail(os.remove, result_path) if ret == 0: db = self.gui.current_db if db.new_api.library_id != job['library_id']: error_dialog(self.gui, _('Library changed'), _( 'Cannot save changes made to {0} by the ToC editor as' ' the calibre library has changed.').format(job['title']), show=True) else: db.new_api.add_format(job['book_id'], job['fmt'], job['path'], run_hooks=False) os.remove(job['path']) else: if monotonic() - job['start_time'] > 120: self.jobs.remove(job) continue if os.path.exists(started_path): job['started'] = True retry_on_fail(os.remove, started_path) if self.jobs: QTimer.singleShot(100, self.check_for_completions)
def check(self): if self.rejected: return if self.thread.is_alive(): QTimer.singleShot(100, self.check) else: self.accept()
def do_one_block(self): try: start_cursor, end_cursor = self.requests[0] except IndexError: return self.ignore_requests = True try: block = start_cursor.block() if not block.isValid(): self.requests.popleft() return formats, force_next_highlight = self.parse_single_block(block) self.apply_format_changes(block, formats) try: self.doc.markContentsDirty(block.position(), block.length()) except AttributeError: self.requests.clear() return ok = start_cursor.movePosition(QTextCursor.MoveOperation.NextBlock) if not ok: self.requests.popleft() return next_block = start_cursor.block() if next_block.position() > end_cursor.position(): if force_next_highlight: end_cursor.setPosition(next_block.position() + 1) else: self.requests.popleft() return finally: self.ignore_requests = False QTimer.singleShot(0, self.do_one_block)
def closeEvent(self, ev): if self.shutdown_done: return if self.current_book_data and self.web_view.view_is_ready and not self.close_forced: ev.ignore() if not self.shutting_down: self.shutting_down = True QTimer.singleShot(2000, self.force_close) self.web_view.prepare_for_close() return self.shutting_down = True self.search_widget.shutdown() self.web_view.shutdown() try: self.save_state() self.save_annotations() if self.annotations_saver is not None: self.annotations_saver.shutdown() self.annotations_saver = None except Exception: import traceback traceback.print_exc() clean_running_workers() self.shutdown_done = True return MainWindow.closeEvent(self, ev)
def drop_event(self, event, mime_data): mime = 'application/calibre+from_library' if mime_data.hasFormat(mime): self.dropped_ids = tuple(map(int, mime_data.data(mime).data().split())) QTimer.singleShot(1, self.do_drop) return True return False
def perform_action(self, ac, loc): if ac in ('new', 'existing'): self.callback(loc, copy_structure=self.copy_structure.isChecked()) else: # move library self.db.prefs.disable_setting = True abort_move = Event() pd = ProgressDialog(_('Moving library, please wait...'), _('Scanning...'), max=0, min=0, icon='lt.png', parent=self) pd.canceled_signal.connect(abort_move.set) self.parent().library_view.model().stop_metadata_backup() move_error = [] def do_move(): try: self.db.new_api.move_library_to(loc, abort=abort_move, progress=pd.show_new_progress) except Exception: import traceback move_error.append(traceback.format_exc()) finally: pd.finished_moving.emit() t = Thread(name='MoveLibrary', target=do_move) QTimer.singleShot(0, t.start) pd.exec_() if abort_move.is_set(): self.callback(self.db.library_path) return if move_error: error_dialog(self.parent(), _('Failed to move library'), _( 'There was an error while moving the library. The operation has been aborted. Click' ' "Show details" for details.'), det_msg=move_error[0], show=True) self.callback(self.db.library_path) return self.callback(loc, library_renamed=True)
def run_gui(app, opts, args, internal_book_data, listener=None): acc = EventAccumulator(app) app.file_event_hook = acc app.load_builtin_fonts() app.setWindowIcon(QIcon(I('viewer.png'))) migrate_previous_viewer_prefs() main = EbookViewer(open_at=opts.open_at, continue_reading=opts.continue_reading, force_reload=opts.force_reload, calibre_book_data=internal_book_data) main.set_exception_handler() if len(args) > 1: acc.events.append(os.path.abspath(args[-1])) acc.got_file.connect(main.handle_commandline_arg) main.show() if listener is not None: listener.message_received.connect( main.message_from_other_instance, type=Qt.ConnectionType.QueuedConnection) QTimer.singleShot(0, acc.flush) if opts.raise_window: main.raise_() if opts.full_screen: main.set_full_screen(True) app.exec_()
def no_changes(self): self.any_changes = False def no_changes(): self.any_changes = False QTimer.singleShot(0, no_changes)
def __init__(self, parent=None, initial=None): QDialog.__init__(self, parent) self.setWindowTitle(_('Choose a texture')) self.l = l = QVBoxLayout() self.setLayout(l) self.tdir = texture_dir() self.images = il = QListWidget(self) il.itemDoubleClicked.connect(self.accept, type=Qt.ConnectionType.QueuedConnection) il.setIconSize(QSize(256, 256)) il.setViewMode(QListView.ViewMode.IconMode) il.setFlow(QListView.Flow.LeftToRight) il.setSpacing(20) il.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) il.itemSelectionChanged.connect(self.update_remove_state) l.addWidget(il) self.ad = ad = QLabel(_('The builtin textures come from <a href="{}">subtlepatterns.com</a>.').format( 'https://www.toptal.com/designers/subtlepatterns/')) ad.setOpenExternalLinks(True) ad.setWordWrap(True) l.addWidget(ad) self.bb = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok|QDialogButtonBox.StandardButton.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) b = self.add_button = bb.addButton(_('Add texture'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('plus.png'))) b.clicked.connect(self.add_texture) b = self.remove_button = bb.addButton(_('Remove texture'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('minus.png'))) b.clicked.connect(self.remove_texture) l.addWidget(bb) images = [{ 'fname': ':'+os.path.basename(x), 'path': x, 'name': ' '.join(map(lambda s: s.capitalize(), os.path.splitext(os.path.basename(x))[0].split('_'))) } for x in glob.glob(I('textures/*.png'))] + [{ 'fname': os.path.basename(x), 'path': x, 'name': os.path.splitext(os.path.basename(x))[0], } for x in glob.glob(os.path.join(self.tdir, '*')) if x.rpartition('.')[-1].lower() in {'jpeg', 'png', 'jpg'}] images.sort(key=lambda x:sort_key(x['name'])) for i in images: self.create_item(i) self.update_remove_state() if initial: existing = {str(i.data(Qt.ItemDataRole.UserRole) or ''):i for i in (self.images.item(c) for c in range(self.images.count()))} item = existing.get(initial, None) if item is not None: item.setSelected(True) QTimer.singleShot(100, partial(il.scrollToItem, item)) self.resize(QSize(950, 650))
def check_exited(self): if getattr(self.server, 'is_running', False): QTimer.singleShot(20, self.check_exited) return self.gui.content_server = None self.main_tab.update_button_state() self.stopping_msg.accept()
def update_log(self): if not self.keep_updating: return html = self.log.html if html != self.last_html: self.last_html = html self.tb.setHtml('<pre style="font-family:monospace">%s</pre>'%html) QTimer.singleShot(1000, self.update_log)
def __init__(self, dock_action, parent=None): QWidget.__init__(self, parent=parent) self.view_to_debug = parent self.view = None self.layout = QHBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.dock_action = dock_action QTimer.singleShot(0, self.connect_to_dock)
def check(self): if self.worker.is_alive() and not self.abort.is_set(): QTimer.singleShot(50, self.check) try: self.process_result(self.worker.rq.get_nowait()) except Empty: pass else: self.process_results()
def start_download(self): self.worker.start() QTimer.singleShot(50, self.update) self.exec_() if self.worker.err is not None: error_dialog(self.parent(), _('Download failed'), _('Failed to download from %(url)r with error: %(err)s')%dict( url=self.worker.url, err=self.worker.err), det_msg=self.worker.tb, show=True)
def show_dialog(self, restrict_to_book_ids=None): if self.parent() is None: self.browse_panel.effective_query_changed() self.exec() else: self.reinitialize(restrict_to_book_ids) self.show() self.raise_() QTimer.singleShot(80, self.browse_panel.effective_query_changed)
def stop_server(self): self.server.stop() self.stopping_msg = info_dialog( self, _('Stopping'), _('Stopping server, this could take up to a minute, please wait...'), show_copy_button=False ) QTimer.singleShot(500, self.check_exited) self.stopping_msg.exec_()
def toggle_content_server(self): if self.gui.content_server is None: self.gui.start_content_server() else: self.gui.content_server.stop() self.stopping_msg = info_dialog(self.gui, _('Stopping'), _('Stopping server, this could take up to a minute, please wait...'), show_copy_button=False) QTimer.singleShot(1000, self.check_exited) self.stopping_msg.exec_()
def load_finished(self, ok): self.load_complete = True self.load_hang_check_timer.stop() if not ok: self.working = False self.work_done.emit(self, 'Load of {} failed'.format(self.url().toString())) return if self.wait_for_title and self.title() != self.wait_for_title: self.log(self.log_prefix, 'Load finished, waiting for title to change to:', self.wait_for_title) return QTimer.singleShot(int(1000 * self.settle_time), self.print_to_pdf)
def compare_books(path1, path2, revert_msg=None, revert_callback=None, parent=None, names=None): d = Diff(parent=parent, revert_button_msg=revert_msg) if revert_msg is not None: d.revert_requested.connect(revert_callback) QTimer.singleShot(0, partial(d.ebook_diff, path1, path2, names=names)) d.exec() try: d.revert_requested.disconnect() except: pass d.break_cycles()
def queue_files(self): self.tdir = PersistentTemporaryDirectory('_queue_polish') self.jobs = [] if len(self.book_id_map) <= 5: for i, (book_id, formats) in enumerate(iteritems(self.book_id_map)): self.do_book(i+1, book_id, formats) else: self.queue = [(i+1, id_) for i, id_ in enumerate(self.book_id_map)] self.pd = ProgressDialog(_('Queueing books for polishing'), max=len(self.queue), parent=self) QTimer.singleShot(0, self.do_one) self.pd.exec_()
def __init__(self, parent, book_ids, output_format, queue, db, user_recs, args, use_saved_single_settings=True): QProgressDialog.__init__(self, '', None, 0, len(book_ids), parent) self.setWindowTitle(_('Queueing books for bulk conversion')) self.book_ids, self.output_format, self.queue, self.db, self.args, self.user_recs = \ book_ids, output_format, queue, db, args, user_recs self.parent = parent self.use_saved_single_settings = use_saved_single_settings self.i, self.bad, self.jobs, self.changed = 0, [], [], False QTimer.singleShot(0, self.do_book) self.exec_()
def finalize_layout(self): self.status_bar.initialize(self.system_tray_icon) self.book_details.show_book_info.connect( self.iactions['Show Book Details'].show_book_info) self.book_details.files_dropped.connect( self.iactions['Add Books'].files_dropped_on_book) self.book_details.cover_changed.connect( self.bd_cover_changed, type=Qt.ConnectionType.QueuedConnection) self.book_details.open_cover_with.connect( self.bd_open_cover_with, type=Qt.ConnectionType.QueuedConnection) self.book_details.open_fmt_with.connect( self.bd_open_fmt_with, type=Qt.ConnectionType.QueuedConnection) self.book_details.edit_book.connect( self.bd_edit_book, type=Qt.ConnectionType.QueuedConnection) self.book_details.cover_removed.connect( self.bd_cover_removed, type=Qt.ConnectionType.QueuedConnection) self.book_details.remote_file_dropped.connect( self.iactions['Add Books'].remote_file_dropped_on_book, type=Qt.ConnectionType.QueuedConnection) self.book_details.open_containing_folder.connect( self.iactions['View'].view_folder_for_id) self.book_details.view_specific_format.connect( self.iactions['View'].view_format_by_id) self.book_details.search_requested.connect( self.set_search_string_with_append) self.book_details.remove_specific_format.connect( self.iactions['Remove Books'].remove_format_by_id) self.book_details.remove_metadata_item.connect( self.iactions['Edit Metadata'].remove_metadata_item) self.book_details.save_specific_format.connect( self.iactions['Save To Disk'].save_library_format_by_ids) self.book_details.restore_specific_format.connect( self.iactions['Remove Books'].restore_format) self.book_details.set_cover_from_format.connect( self.iactions['Edit Metadata'].set_cover_from_format) self.book_details.copy_link.connect( self.bd_copy_link, type=Qt.ConnectionType.QueuedConnection) self.book_details.view_device_book.connect( self.iactions['View'].view_device_book) self.book_details.manage_category.connect( self.manage_category_triggerred) self.book_details.find_in_tag_browser.connect( self.find_in_tag_browser_triggered) self.book_details.edit_identifiers.connect( self.edit_identifiers_triggerred) self.book_details.compare_specific_format.connect(self.compare_format) m = self.library_view.model() if m.rowCount(None) > 0: QTimer.singleShot(0, self.library_view.set_current_row) m.current_changed(self.library_view.currentIndex(), self.library_view.currentIndex()) self.library_view.setFocus(Qt.FocusReason.OtherFocusReason)
def add_isbns(self, books, add_tags=[]): self.isbn_books = list(books) self.add_by_isbn_ids = set() self.isbn_add_tags = add_tags QTimer.singleShot(10, self.do_one_isbn_add) self.isbn_add_dialog = ProgressDialog( _('Adding'), _('Creating book records from ISBNs'), max=len(books), cancelable=False, parent=self.gui) self.isbn_add_dialog.exec_()
def cover_browser_shown(self): self.cover_flow.setFocus(Qt.FocusReason.OtherFocusReason) if CoverFlow is not None: if self.db_images.ignore_image_requests: self.db_images.ignore_image_requests = False self.db_images.dataChanged.emit() self.cover_flow.setCurrentSlide(self.library_view.currentIndex().row()) self.cover_flow_syncing_enabled = True QTimer.singleShot(500, self.cover_flow_do_sync) self.library_view.setCurrentIndex( self.library_view.currentIndex()) self.library_view.scroll_to_row(self.library_view.currentIndex().row())
def main(f=None): global window window = MainWindow() window.show() if not f and len(sys.argv[1:]) == 1: f = sys.argv[1] if f: f = os.path.abspath(f) QTimer.singleShot(50, lambda: window.load_file(f)) app.exec_()
def category_click(category): open_url(category.url) QTimer.singleShot(8000, web.update)
def comment_click(comment): open_url(comment.url) comments.remove(comment) categories.comments.count -= 1 update() QTimer.singleShot(5000, web.update)