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 no_changes(self): self.any_changes = False def no_changes(): self.any_changes = False QTimer.singleShot(0, no_changes)
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 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 __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 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 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 __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 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 __init__(self, parent=None, add_clear_action=True, as_url=None): QComboBox.__init__(self, parent) self.line_edit = SearchLineEdit(self) self.line_edit.as_url = as_url self.setLineEdit(self.line_edit) self.line_edit.clear_history.connect(self.clear_history) if add_clear_action: self.lineEdit().setClearButtonEnabled(True) ac = self.findChild(QAction, QT_HIDDEN_CLEAR_ACTION) if ac is not None: ac.triggered.connect(self.clear_clicked) c = self.line_edit.completer() c.setCompletionMode(QCompleter.CompletionMode.PopupCompletion) c.highlighted[native_string_type].connect(self.completer_used) self.line_edit.key_pressed.connect(self.key_pressed, type=Qt.ConnectionType.DirectConnection) # QueuedConnection as workaround for https://bugreports.qt-project.org/browse/QTBUG-40807 self.activated[native_string_type].connect(self.history_selected, type=Qt.ConnectionType.QueuedConnection) self.setEditable(True) self.as_you_type = True self.timer = QTimer() self.timer.setSingleShot(True) self.timer.timeout.connect(self.timer_event, type=Qt.ConnectionType.QueuedConnection) self.setInsertPolicy(QComboBox.InsertPolicy.NoInsert) self.setMaxCount(self.MAX_COUNT) self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) self.setMinimumContentsLength(25) self._in_a_search = False self.tool_tip_text = self.toolTip()
def __init__(self, preview, parent=None): QWidget.__init__(self, parent) self.preview = preview preview.live_css_data.connect(self.got_live_css_data) self.preview_is_refreshing = False self.refresh_needed = False preview.refresh_starting.connect(self.preview_refresh_starting) preview.refreshed.connect(self.preview_refreshed) self.apply_theme() self.setAutoFillBackground(True) self.update_timer = QTimer(self) self.update_timer.timeout.connect(self.update_data) self.update_timer.setSingleShot(True) self.update_timer.setInterval(500) self.now_showing = (None, None, None) self.stack = s = QStackedLayout(self) self.setLayout(s) self.clear_label = la = QLabel( '<h3>' + _('No style information found') + '</h3><p>' + _('Move the cursor inside a HTML tag to see what styles' ' apply to that tag.')) la.setWordWrap(True) la.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft) s.addWidget(la) self.box = box = Box(self) box.hyperlink_activated.connect( self.goto_declaration, type=Qt.ConnectionType.QueuedConnection) self.scroll = sc = QScrollArea(self) sc.setWidget(box) sc.setWidgetResizable(True) s.addWidget(sc)
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 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 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 __init__(self, parent=None, show_open_in_editor=False): QWidget.__init__(self, parent) self.changes = [[], [], []] self.delta = 0 self.l = l = QHBoxLayout(self) self.setLayout(l) self.syncpos = 0 l.setContentsMargins(0, 0, 0, 0), l.setSpacing(0) self.view = DiffSplit(self, show_open_in_editor=show_open_in_editor) l.addWidget(self.view) self.add_diff = self.view.add_diff self.scrollbar = QScrollBar(self) l.addWidget(self.scrollbar) self.syncing = False self.bars = [] self.resize_timer = QTimer(self) self.resize_timer.setSingleShot(True) self.resize_timer.timeout.connect(self.resize_debounced) for bar in (self.scrollbar, self.view.left.verticalScrollBar(), self.view.right.verticalScrollBar()): self.bars.append(bar) bar.scroll_idx = len(self.bars) - 1 connect_lambda(bar.valueChanged[int], self, lambda self: self.scrolled(self.sender().scroll_idx)) self.view.left.resized.connect(self.resized) for v in (self.view.left, self.view.right, self.view.handle(1)): v.wheel_event.connect(self.scrollbar.wheelEvent) if v is self.view.left or v is self.view.right: v.next_change.connect(self.next_change) v.line_activated.connect(self.line_activated) connect_lambda(v.scrolled, self, lambda self: self.scrolled(1 if self.sender() is self.view.left else 2))
def __init__(self, parent=None, expected_geometry=(100, 50)): PlainTextEdit.__init__(self, parent) self.snippet_manager = SnippetManager(self) self.completion_popup = CompletionPopup(self) self.request_completion = self.completion_doc_name = None self.clear_completion_cache_timer = t = QTimer(self) t.setInterval(5000), t.timeout.connect(self.clear_completion_cache), t.setSingleShot(True) self.textChanged.connect(t.start) self.last_completion_request = -1 self.gutter_width = 0 self.tw = 2 self.expected_geometry = expected_geometry self.saved_matches = {} self.syntax = None self.smarts = NullSmarts(self) self.current_cursor_line = None self.current_search_mark = None self.smarts_highlight_timer = t = QTimer() t.setInterval(750), t.setSingleShot(True), t.timeout.connect(self.update_extra_selections) self.highlighter = SyntaxHighlighter() self.line_number_area = LineNumbers(self) self.apply_settings() self.setMouseTracking(True) self.cursorPositionChanged.connect(self.highlight_cursor_line) self.blockCountChanged[int].connect(self.update_line_number_area_width) self.updateRequest.connect(self.update_line_number_area)
def check(self): if self.rejected: return if self.thread.is_alive(): QTimer.singleShot(100, self.check) else: self.accept()
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))
class DetailView(Dialog): # {{{ def __init__(self, parent, job): self.job = job self.html_view = hasattr(job, 'html_details') and not getattr( job, 'ignore_html_details', False) Dialog.__init__(self, job.description, 'job-detail-view-dialog', parent) def sizeHint(self): return QSize(700, 500) @property def plain_text(self): if self.html_view: return self.tb.toPlainText() return self.log.toPlainText() def copy_to_clipboard(self): QApplication.instance().clipboard().setText(self.plain_text) def setup_ui(self): self.l = l = QVBoxLayout(self) if self.html_view: self.tb = w = QTextBrowser(self) else: self.log = w = QPlainTextEdit(self) w.setReadOnly(True), w.setLineWrapMode( QPlainTextEdit.LineWrapMode.NoWrap) l.addWidget(w) l.addWidget(self.bb) self.bb.clear(), self.bb.setStandardButtons( QDialogButtonBox.StandardButton.Close) self.copy_button = b = self.bb.addButton( _('&Copy to clipboard'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('edit-copy.png'))) b.clicked.connect(self.copy_to_clipboard) self.next_pos = 0 self.update() self.timer = QTimer(self) self.timer.timeout.connect(self.update) self.timer.start(1000) if not self.html_view: v = self.log.verticalScrollBar() v.setValue(v.maximum()) def update(self): if self.html_view: html = self.job.html_details if len(html) > self.next_pos: self.next_pos = len(html) self.tb.setHtml('<pre style="font-family:monospace">%s</pre>' % html) else: f = self.job.log_file f.seek(self.next_pos) more = f.read() self.next_pos = f.tell() if more: self.log.appendPlainText(more.decode('utf-8', 'replace'))
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 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 __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 __init__(self, parent=None): HTMLDisplay.__init__(self, parent) self.setAcceptDrops(False) self.wait_timer = QTimer(self) self.wait_timer.timeout.connect(self.update_wait) self.wait_timer.setInterval(800) self.dots_count = 0 self.anchor_clicked.connect(self.link_activated)
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 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 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 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 __init__(self, parent, debug=False): QObject.__init__(self, parent) self.debug = debug self.timer = QTimer(self) self.timer.timeout.connect(self.check) self.threshold = gc.get_threshold() gc.disable() self.timer.start(self.INTERVAL)
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_()
class View(common.View): def __init__(self, scene): common.View.__init__(self, scene) self.setMouseTracking(True) # fix for not updating position for simulated events self.scene.text_changed.connect(self.viewport().update) # ensure a full redraw self.progress_loaded_timer = QTimer() self.progress_loaded_timer.setInterval(1500) self.progress_loaded_timer.setSingleShot(True) self.progress_loaded_timer.timeout.connect(self.viewport().update) def resizeEvent(self, e): common.View.resizeEvent(self, e) if not self.scene.playtest: self.fit() def fit(self): rect = self.scene.itemsBoundingRect().adjusted(-0.3, -0.3, 0.3, 0.3) self.setSceneRect(rect) self.fitInView(rect, qt.KeepAspectRatio) zoom = self.transform().mapRect(QRectF(0, 0, 1, 1)).width() if zoom > 100: self.resetTransform() self.scale(100, 100) def paintEvent(self, e): common.View.paintEvent(self, e) g = QPainter(self.viewport()) g.setRenderHints(self.renderHints()) area = self.viewport().rect().adjusted(5, 2, -5, -2) if self.progress_loaded_timer.isActive(): g.setPen(QPen(Color.dark_text)) g.drawText(area, qt.AlignTop | qt.AlignLeft, "Progress loaded") try: self._info_font except AttributeError: self._info_font = g.font() multiply_font_size(self._info_font, 3) try: txt = ('{r} ({m})' if self.scene.mistakes else '{r}').format(r=self.scene.remaining, m=self.scene.mistakes) g.setFont(self._info_font) g.setPen(QPen(Color.dark_text)) g.drawText(area, qt.AlignTop | qt.AlignRight, txt) except AttributeError: pass def wheelEvent(self, e): pass
def __init__(self, scene): common.View.__init__(self, scene) self.setMouseTracking(True) # fix for not updating position for simulated events self.scene.text_changed.connect(self.viewport().update) # ensure a full redraw self.progress_loaded_timer = QTimer() self.progress_loaded_timer.setInterval(1500) self.progress_loaded_timer.setSingleShot(True) self.progress_loaded_timer.timeout.connect(self.viewport().update)
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)