def __init__(self, path, panel, parent): """ Create widget. Arguments: obj (Command, Parameter): Command or Parameter being edited. parent (Optional[QWidget]): Parent widget. """ super(ParameterTableWindow, self).__init__(path, panel, parent) view = ParameterTableView(panel, item_path=path, parent_item=None, parent=self) self._actions = {} self._setView(view) self._search.setVisible(False) self._plot = None if re.match("^.*[.]VALE$", path.path()) or \ re.match("^.*[.](ABSCISSE|ORDONNEE)$", path.path()): self._plot = PlotWidget(view, self) self._plot.hide() splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(view) splitter.addWidget(self._plot) self._scroll.setWidget(splitter) else: self._scroll.setWidget(view) view.selectionChanged.connect(self._updateState) tbar = QToolBar(self) tbar.setToolButtonStyle(Qt.ToolButtonIconOnly) tbar.addAction(\ self._createAction(ParameterTableWindow.AppendRow, load_icon("as_pic_add_row.png"), translate("ParameterPanel", "Append row"), translate("ParameterPanel", "Append row to the end of table"), view.appendRow)) tbar.addAction(\ self._createAction(ParameterTableWindow.InsertRow, load_icon("as_pic_insert_row.png"), translate("ParameterPanel", "Insert row"), translate("ParameterPanel", "Insert row at current position"), view.insertRow)) tbar.addAction(\ self._createAction(ParameterTableWindow.RemoveRow, load_icon("as_pic_remove_row.png"), translate("ParameterPanel", "Remove rows"), translate("ParameterPanel", "Remove selected rows"), view.removeRows)) tbar.addSeparator() tbar.addAction(\ self._createAction(ParameterTableWindow.MoveRowUp, load_icon("as_pic_move_up.png"), translate("ParameterPanel", "Move up"), translate("ParameterPanel", "Move selected rows up"), view.moveRowsUp)) tbar.addAction(\ self._createAction(ParameterTableWindow.MoveRowDown, load_icon("as_pic_move_down.png"), translate("ParameterPanel", "Move down"), translate("ParameterPanel", "Move selected rows down"), view.moveRowsDown)) tbar.addSeparator() if self._plot is not None: tbar.addAction(\ self._createAction(ParameterTableWindow.FunctionPlot, load_icon("as_pic_show_plot.png"), translate("ParameterPanel", "Plot function"), translate("ParameterPanel", "Show/hide plot view"), self._plot.setVisible, True)) tbar.addSeparator() tbar.addAction(\ self._createAction(ParameterTableWindow.Import, load_icon("as_pic_import_table.png"), translate("ParameterPanel", "Import table"), translate("ParameterPanel", "Import function data from file"), view.importFile)) self.addControlWidget(tbar) self._updateState()
class Editor(QWidget): # {{{ toolbar_prefs_name = None data_changed = pyqtSignal() def __init__(self, parent=None, one_line_toolbar=False, toolbar_prefs_name=None): QWidget.__init__(self, parent) self.toolbar_prefs_name = toolbar_prefs_name or self.toolbar_prefs_name self.toolbar1 = QToolBar(self) self.toolbar2 = QToolBar(self) self.toolbar3 = QToolBar(self) for i in range(1, 4): t = getattr(self, 'toolbar%d' % i) t.setIconSize(QSize(18, 18)) self.editor = EditorWidget(self) self.editor.data_changed.connect(self.data_changed) self.set_base_url = self.editor.set_base_url self.set_html = self.editor.set_html self.tabs = QTabWidget(self) self.tabs.setTabPosition(self.tabs.South) self.wyswyg = QWidget(self.tabs) self.code_edit = QPlainTextEdit(self.tabs) self.source_dirty = False self.wyswyg_dirty = True self._layout = QVBoxLayout(self) self.wyswyg.layout = l = QVBoxLayout(self.wyswyg) self.setLayout(self._layout) l.setContentsMargins(0, 0, 0, 0) if one_line_toolbar: tb = QHBoxLayout() l.addLayout(tb) else: tb = l tb.addWidget(self.toolbar1) tb.addWidget(self.toolbar2) tb.addWidget(self.toolbar3) l.addWidget(self.editor) self._layout.addWidget(self.tabs) self.tabs.addTab(self.wyswyg, _('N&ormal view')) self.tabs.addTab(self.code_edit, _('&HTML source')) self.tabs.currentChanged[int].connect(self.change_tab) self.highlighter = Highlighter(self.code_edit.document()) self.layout().setContentsMargins(0, 0, 0, 0) if self.toolbar_prefs_name is not None: hidden = gprefs.get(self.toolbar_prefs_name) if hidden: self.hide_toolbars() # toolbar1 {{{ self.toolbar1.addAction(self.editor.action_undo) self.toolbar1.addAction(self.editor.action_redo) self.toolbar1.addAction(self.editor.action_select_all) self.toolbar1.addAction(self.editor.action_remove_format) self.toolbar1.addAction(self.editor.action_clear) self.toolbar1.addSeparator() for x in ('copy', 'cut', 'paste'): ac = getattr(self.editor, 'action_' + x) self.toolbar1.addAction(ac) self.toolbar1.addSeparator() self.toolbar1.addAction(self.editor.action_background) # }}} # toolbar2 {{{ for x in ('', 'un'): ac = getattr(self.editor, 'action_%sordered_list' % x) self.toolbar2.addAction(ac) self.toolbar2.addSeparator() for x in ('superscript', 'subscript', 'indent', 'outdent'): self.toolbar2.addAction(getattr(self.editor, 'action_' + x)) if x in ('subscript', 'outdent'): self.toolbar2.addSeparator() self.toolbar2.addAction(self.editor.action_block_style) w = self.toolbar2.widgetForAction(self.editor.action_block_style) if hasattr(w, 'setPopupMode'): w.setPopupMode(w.InstantPopup) self.toolbar2.addAction(self.editor.action_insert_link) self.toolbar2.addAction(self.editor.action_insert_hr) # }}} # toolbar3 {{{ for x in ('bold', 'italic', 'underline', 'strikethrough'): ac = getattr(self.editor, 'action_' + x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() for x in ('left', 'center', 'right', 'justified'): ac = getattr(self.editor, 'action_align_' + x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() self.toolbar3.addAction(self.editor.action_color) # }}} self.code_edit.textChanged.connect(self.code_dirtied) self.editor.page().contentsChanged.connect(self.wyswyg_dirtied) def set_minimum_height_for_editor(self, val): self.editor.setMinimumHeight(val) @property def html(self): self.tabs.setCurrentIndex(0) return self.editor.html @html.setter def html(self, v): self.editor.html = v def change_tab(self, index): # print 'reloading:', (index and self.wyswyg_dirty) or (not index and # self.source_dirty) if index == 1: # changing to code view if self.wyswyg_dirty: self.code_edit.setPlainText(self.editor.html) self.wyswyg_dirty = False elif index == 0: # changing to wyswyg if self.source_dirty: self.editor.html = unicode_type(self.code_edit.toPlainText()) self.source_dirty = False @property def tab(self): return 'code' if self.tabs.currentWidget( ) is self.code_edit else 'wyswyg' @tab.setter def tab(self, val): self.tabs.setCurrentWidget(self.code_edit if val == 'code' else self.wyswyg) def wyswyg_dirtied(self, *args): self.wyswyg_dirty = True def code_dirtied(self, *args): self.source_dirty = True def hide_toolbars(self): self.toolbar1.setVisible(False) self.toolbar2.setVisible(False) self.toolbar3.setVisible(False) def show_toolbars(self): self.toolbar1.setVisible(True) self.toolbar2.setVisible(True) self.toolbar3.setVisible(True) def toggle_toolbars(self): visible = self.toolbars_visible getattr(self, ('hide' if visible else 'show') + '_toolbars')() if self.toolbar_prefs_name is not None: gprefs.set(self.toolbar_prefs_name, visible) @property def toolbars_visible(self): return self.toolbar1.isVisible() or self.toolbar2.isVisible( ) or self.toolbar3.isVisible() @toolbars_visible.setter def toolbars_visible(self, val): getattr(self, ('show' if val else 'hide') + '_toolbars')() def set_readonly(self, what): self.editor.set_readonly(what) def hide_tabs(self): self.tabs.tabBar().setVisible(False)
class WebViewUI(object): def __init__(self, ui, layout): self.main_ui = ui self.layout = layout super(WebViewUI, self).__init__() self.set_ui() def set_ui(self): self._set_top_ui() self._set_down_ui() def _set_top_ui(self): up_frame = QFrame() self.up_layout = QHBoxLayout(up_frame) self.layout.addWidget(up_frame) self.toolbar = QToolBar() self.up_layout.addWidget(self.toolbar) self.action_back = QAction(QIcon(back_icon), '') self.action_forward = QAction(QIcon(forward_icon), '') self.action_reload = QAction(QIcon(reload_icon), '') self.action_stop = QAction(QIcon(stop_icon), '') self.toolbar.addAction(self.action_back) self.toolbar.addAction(self.action_forward) self.toolbar.addAction(self.action_stop) self.toolbar.addAction(self.action_reload) self.action_stop.setVisible(False) self.action_reload.setVisible(True) self.toolbar.addSeparator() self.lnt_addr = QLineEdit('http://localhost:10086') self.lnt_addr.returnPressed.connect(self.load) self.toolbar.addWidget(self.lnt_addr) def _set_down_ui(self): down_frame = QFrame() self.down_layout = QHBoxLayout(down_frame) self.layout.addWidget(down_frame) self.webview = QWebEngineView() self.webview.urlChanged.connect(self.update_url) self.webview.loadFinished.connect(self.load_finish) self.action_back.triggered.connect(self.webview.back) self.action_forward.triggered.connect(self.webview.forward) self.action_stop.triggered.connect(self.webview.stop) self.action_reload.triggered.connect(self.webview.reload) self.down_layout.addWidget(self.webview) def load_finish(self): self.action_stop.setVisible(False) self.action_reload.setVisible(True) # def reload(self, event): # try: # self.webview.reload() # except Exception as e: # print(e) def load(self): try: url = str(self.lnt_addr.text()) if '://' not in url: url = 'http://' + url url = QUrl(url) self.action_stop.setVisible(True) self.action_reload.setVisible(False) self.webview.load(url) except Exception as e: print(e) def update_url(self, q): self.lnt_addr.setText(q.toString()) self.lnt_addr.setCursorPosition(0)
class Preview(QWidget): sync_requested = pyqtSignal(object, object) split_requested = pyqtSignal(object, object, object) split_start_requested = pyqtSignal() link_clicked = pyqtSignal(object, object) refresh_starting = pyqtSignal() refreshed = pyqtSignal() live_css_data = pyqtSignal(object) render_process_restarted = pyqtSignal() open_file_with = pyqtSignal(object, object, object) edit_file = pyqtSignal(object) def __init__(self, parent=None): QWidget.__init__(self, parent) self.l = l = QVBoxLayout() self.setLayout(l) l.setContentsMargins(0, 0, 0, 0) self.view = WebView(self) self.view._page.bridge.request_sync.connect(self.request_sync) self.view._page.bridge.request_split.connect(self.request_split) self.view._page.bridge.live_css_data.connect(self.live_css_data) self.view._page.loadFinished.connect(self.load_finished) self.view.render_process_restarted.connect( self.render_process_restarted) self.pending_go_to_anchor = None self.inspector = self.view.inspector l.addWidget(self.view) self.bar = QToolBar(self) l.addWidget(self.bar) ac = actions['auto-reload-preview'] ac.setCheckable(True) ac.setChecked(True) ac.toggled.connect(self.auto_reload_toggled) self.auto_reload_toggled(ac.isChecked()) self.bar.addAction(ac) ac = actions['sync-preview-to-editor'] ac.setCheckable(True) ac.setChecked(True) ac.toggled.connect(self.sync_toggled) self.sync_toggled(ac.isChecked()) self.bar.addAction(ac) self.bar.addSeparator() ac = actions['split-in-preview'] ac.setCheckable(True) ac.setChecked(False) ac.toggled.connect(self.split_toggled) self.split_toggled(ac.isChecked()) self.bar.addAction(ac) ac = actions['reload-preview'] ac.triggered.connect(self.refresh) self.bar.addAction(ac) actions['preview-dock'].toggled.connect(self.visibility_changed) self.current_name = None self.last_sync_request = None self.refresh_timer = QTimer(self) self.refresh_timer.timeout.connect(self.refresh) parse_worker.start() self.current_sync_request = None self.search = HistoryLineEdit2(self) self.search.initialize('tweak_book_preview_search') self.search.setPlaceholderText(_('Search in preview')) self.search.returnPressed.connect(self.find_next) self.bar.addSeparator() self.bar.addWidget(self.search) for d in ('next', 'prev'): ac = actions['find-%s-preview' % d] ac.triggered.connect(getattr(self, 'find_' + d)) self.bar.addAction(ac) def find(self, direction): text = unicode_type(self.search.text()) self.view._page.findText(text, (QWebEnginePage.FindBackward if direction == 'prev' else QWebEnginePage.FindFlags(0))) def find_next(self): self.find('next') def find_prev(self): self.find('prev') def go_to_anchor(self, anchor): self.view._page.go_to_anchor(anchor) def request_sync(self, tagname, href, lnum): if self.current_name: c = current_container() if tagname == 'a' and href: if href and href.startswith('#'): name = self.current_name else: name = c.href_to_name(href, self.current_name) if href else None if name == self.current_name: return self.go_to_anchor(urlparse(href).fragment) if name and c.exists(name) and c.mime_map[name] in OEB_DOCS: return self.link_clicked.emit( name, urlparse(href).fragment or TOP) self.sync_requested.emit(self.current_name, lnum) def request_split(self, loc, totals): actions['split-in-preview'].setChecked(False) if not loc or not totals: return error_dialog(self, _('Invalid location'), _('Cannot split on the body tag'), show=True) if self.current_name: self.split_requested.emit(self.current_name, loc, totals) def sync_to_editor(self, name, sourceline_address): self.current_sync_request = (name, sourceline_address) QTimer.singleShot(100, self._sync_to_editor) def _sync_to_editor(self): if not actions['sync-preview-to-editor'].isChecked(): return try: if self.refresh_timer.isActive( ) or self.current_sync_request[0] != self.current_name: return QTimer.singleShot(100, self._sync_to_editor) except TypeError: return # Happens if current_sync_request is None sourceline_address = self.current_sync_request[1] self.current_sync_request = None self.view._page.go_to_sourceline_address(sourceline_address) def report_worker_launch_error(self): if parse_worker.launch_error is not None: tb, parse_worker.launch_error = parse_worker.launch_error, None error_dialog( self, _('Failed to launch worker'), _('Failed to launch the worker process used for rendering the preview' ), det_msg=tb, show=True) def name_to_qurl(self, name=None): name = name or self.current_name qurl = QUrl() qurl.setScheme(FAKE_PROTOCOL), qurl.setAuthority( FAKE_HOST), qurl.setPath('/' + name) return qurl def show(self, name): if name != self.current_name: self.refresh_timer.stop() self.current_name = name self.report_worker_launch_error() parse_worker.add_request(name) self.view.setUrl(self.name_to_qurl()) return True def refresh(self): if self.current_name: self.refresh_timer.stop() # This will check if the current html has changed in its editor, # and re-parse it if so self.report_worker_launch_error() parse_worker.add_request(self.current_name) # Tell webkit to reload all html and associated resources current_url = self.name_to_qurl() self.refresh_starting.emit() if current_url != self.view.url(): # The container was changed self.view.setUrl(current_url) else: self.view.refresh() self.refreshed.emit() def clear(self): self.view.clear() self.current_name = None @property def is_visible(self): return actions['preview-dock'].isChecked() @property def live_css_is_visible(self): try: return actions['live-css-dock'].isChecked() except KeyError: return False def start_refresh_timer(self): if self.live_css_is_visible or ( self.is_visible and actions['auto-reload-preview'].isChecked()): self.refresh_timer.start(tprefs['preview_refresh_time'] * 1000) def stop_refresh_timer(self): self.refresh_timer.stop() def auto_reload_toggled(self, checked): if self.live_css_is_visible and not actions[ 'auto-reload-preview'].isChecked(): actions['auto-reload-preview'].setChecked(True) error_dialog( self, _('Cannot disable'), _('Auto reloading of the preview panel cannot be disabled while the' ' Live CSS panel is open.'), show=True) actions['auto-reload-preview'].setToolTip( _('Auto reload preview when text changes in editor' ) if not checked else _('Disable auto reload of preview')) def sync_toggled(self, checked): actions['sync-preview-to-editor'].setToolTip( _('Disable syncing of preview position to editor position' ) if checked else _( 'Enable syncing of preview position to editor position')) def visibility_changed(self, is_visible): if is_visible: self.refresh() def split_toggled(self, checked): actions['split-in-preview'].setToolTip( textwrap.fill( _('Abort file split') if checked else _('Split this file at a specified location.\n\nAfter clicking this button, click' ' inside the preview panel above at the location you want the file to be split.' ))) if checked: self.split_start_requested.emit() else: self.view._page.split_mode(False) def do_start_split(self): self.view._page.split_mode(True) def stop_split(self): actions['split-in-preview'].setChecked(False) def load_finished(self, ok): if self.pending_go_to_anchor: self.view._page.go_to_anchor(self.pending_go_to_anchor) self.pending_go_to_anchor = None if actions['split-in-preview'].isChecked(): if ok: self.do_start_split() else: self.stop_split() def request_live_css_data(self, editor_name, sourceline, tags): if self.view._page.bridge.ready: self.view._page.bridge.live_css(editor_name, sourceline, tags) def apply_settings(self): s = self.view.settings() s.setFontSize(s.DefaultFontSize, tprefs['preview_base_font_size']) s.setFontSize(s.DefaultFixedFontSize, tprefs['preview_mono_font_size']) s.setFontSize(s.MinimumLogicalFontSize, tprefs['preview_minimum_font_size']) s.setFontSize(s.MinimumFontSize, tprefs['preview_minimum_font_size']) sf, ssf, mf = tprefs['engine_preview_serif_family'], tprefs[ 'engine_preview_sans_family'], tprefs['engine_preview_mono_family'] if sf: s.setFontFamily(s.SerifFont, sf) if ssf: s.setFontFamily(s.SansSerifFont, ssf) if mf: s.setFontFamily(s.FixedFont, mf) stdfnt = tprefs['preview_standard_font_family'] or 'serif' stdfnt = getattr(s, { 'serif': 'SerifFont', 'sans': 'SansSerifFont', 'mono': 'FixedFont' }[stdfnt]) s.setFontFamily(s.StandardFont, s.fontFamily(stdfnt))
class Editor(QWidget): # {{{ def __init__(self, parent=None, one_line_toolbar=False): QWidget.__init__(self, parent) self.toolbar1 = QToolBar(self) self.toolbar2 = QToolBar(self) self.toolbar3 = QToolBar(self) for i in range(1, 4): t = getattr(self, 'toolbar%d'%i) t.setIconSize(QSize(18, 18)) self.editor = EditorWidget(self) self.set_html = self.editor.set_html self.tabs = QTabWidget(self) self.tabs.setTabPosition(self.tabs.South) self.wyswyg = QWidget(self.tabs) self.code_edit = QPlainTextEdit(self.tabs) self.source_dirty = False self.wyswyg_dirty = True self._layout = QVBoxLayout(self) self.wyswyg.layout = l = QVBoxLayout(self.wyswyg) self.setLayout(self._layout) l.setContentsMargins(0, 0, 0, 0) if one_line_toolbar: tb = QHBoxLayout() l.addLayout(tb) else: tb = l tb.addWidget(self.toolbar1) tb.addWidget(self.toolbar2) tb.addWidget(self.toolbar3) l.addWidget(self.editor) self._layout.addWidget(self.tabs) self.tabs.addTab(self.wyswyg, _('N&ormal view')) self.tabs.addTab(self.code_edit, _('&HTML Source')) self.tabs.currentChanged[int].connect(self.change_tab) self.highlighter = Highlighter(self.code_edit.document()) self.layout().setContentsMargins(0, 0, 0, 0) # toolbar1 {{{ self.toolbar1.addAction(self.editor.action_undo) self.toolbar1.addAction(self.editor.action_redo) self.toolbar1.addAction(self.editor.action_select_all) self.toolbar1.addAction(self.editor.action_remove_format) self.toolbar1.addAction(self.editor.action_clear) self.toolbar1.addSeparator() for x in ('copy', 'cut', 'paste'): ac = getattr(self.editor, 'action_'+x) self.toolbar1.addAction(ac) self.toolbar1.addSeparator() self.toolbar1.addAction(self.editor.action_background) # }}} # toolbar2 {{{ for x in ('', 'un'): ac = getattr(self.editor, 'action_%sordered_list'%x) self.toolbar2.addAction(ac) self.toolbar2.addSeparator() for x in ('superscript', 'subscript', 'indent', 'outdent'): self.toolbar2.addAction(getattr(self.editor, 'action_' + x)) if x in ('subscript', 'outdent'): self.toolbar2.addSeparator() self.toolbar2.addAction(self.editor.action_block_style) w = self.toolbar2.widgetForAction(self.editor.action_block_style) w.setPopupMode(w.InstantPopup) self.toolbar2.addAction(self.editor.action_insert_link) # }}} # toolbar3 {{{ for x in ('bold', 'italic', 'underline', 'strikethrough'): ac = getattr(self.editor, 'action_'+x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() for x in ('left', 'center', 'right', 'justified'): ac = getattr(self.editor, 'action_align_'+x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() self.toolbar3.addAction(self.editor.action_color) # }}} self.code_edit.textChanged.connect(self.code_dirtied) self.editor.page().contentsChanged.connect(self.wyswyg_dirtied) def set_minimum_height_for_editor(self, val): self.editor.setMinimumHeight(val) @dynamic_property def html(self): def fset(self, v): self.editor.html = v def fget(self): self.tabs.setCurrentIndex(0) return self.editor.html return property(fget=fget, fset=fset) def change_tab(self, index): # print 'reloading:', (index and self.wyswyg_dirty) or (not index and # self.source_dirty) if index == 1: # changing to code view if self.wyswyg_dirty: self.code_edit.setPlainText(self.editor.html) self.wyswyg_dirty = False elif index == 0: # changing to wyswyg if self.source_dirty: self.editor.html = unicode(self.code_edit.toPlainText()) self.source_dirty = False @dynamic_property def tab(self): def fget(self): return 'code' if self.tabs.currentWidget() is self.code_edit else 'wyswyg' def fset(self, val): self.tabs.setCurrentWidget(self.code_edit if val == 'code' else self.wyswyg) return property(fget=fget, fset=fset) def wyswyg_dirtied(self, *args): self.wyswyg_dirty = True def code_dirtied(self, *args): self.source_dirty = True def hide_toolbars(self): self.toolbar1.setVisible(False) self.toolbar2.setVisible(False) self.toolbar3.setVisible(False) def show_toolbars(self): self.toolbar1.setVisible(True) self.toolbar2.setVisible(True) self.toolbar3.setVisible(True) @dynamic_property def toolbars_visible(self): def fget(self): return self.toolbar1.isVisible() or self.toolbar2.isVisible() or self.toolbar3.isVisible() def fset(self, val): getattr(self, ('show' if val else 'hide') + '_toolbars')() return property(fget=fget, fset=fset) def set_readonly(self, what): self.editor.set_readonly(what) def hide_tabs(self): self.tabs.tabBar().setVisible(False)
class Preview(QWidget): sync_requested = pyqtSignal(object, object) split_requested = pyqtSignal(object, object, object) split_start_requested = pyqtSignal() link_clicked = pyqtSignal(object, object) refresh_starting = pyqtSignal() refreshed = pyqtSignal() def __init__(self, parent=None): QWidget.__init__(self, parent) self.l = l = QVBoxLayout() self.setLayout(l) l.setContentsMargins(0, 0, 0, 0) self.view = WebView(self) self.view.page().sync_requested.connect(self.request_sync) self.view.page().split_requested.connect(self.request_split) self.view.page().loadFinished.connect(self.load_finished) self.inspector = self.view.inspector self.inspector.setPage(self.view.page()) l.addWidget(self.view) self.bar = QToolBar(self) l.addWidget(self.bar) ac = actions['auto-reload-preview'] ac.setCheckable(True) ac.setChecked(True) ac.toggled.connect(self.auto_reload_toggled) self.auto_reload_toggled(ac.isChecked()) self.bar.addAction(ac) ac = actions['sync-preview-to-editor'] ac.setCheckable(True) ac.setChecked(True) ac.toggled.connect(self.sync_toggled) self.sync_toggled(ac.isChecked()) self.bar.addAction(ac) self.bar.addSeparator() ac = actions['split-in-preview'] ac.setCheckable(True) ac.setChecked(False) ac.toggled.connect(self.split_toggled) self.split_toggled(ac.isChecked()) self.bar.addAction(ac) ac = actions['reload-preview'] ac.triggered.connect(self.refresh) self.bar.addAction(ac) actions['preview-dock'].toggled.connect(self.visibility_changed) self.current_name = None self.last_sync_request = None self.refresh_timer = QTimer(self) self.refresh_timer.timeout.connect(self.refresh) parse_worker.start() self.current_sync_request = None self.search = HistoryLineEdit2(self) self.search.initialize('tweak_book_preview_search') self.search.setPlaceholderText(_('Search in preview')) self.search.returnPressed.connect(partial(self.find, 'next')) self.bar.addSeparator() self.bar.addWidget(self.search) for d in ('next', 'prev'): ac = actions['find-%s-preview' % d] ac.triggered.connect(partial(self.find, d)) self.bar.addAction(ac) def find(self, direction): text = unicode(self.search.text()) self.view.findText(text, QWebPage.FindWrapsAroundDocument | ( QWebPage.FindBackward if direction == 'prev' else QWebPage.FindFlags(0))) def request_sync(self, tagname, href, lnum): if self.current_name: c = current_container() if tagname == 'a' and href: if href and href.startswith('#'): name = self.current_name else: name = c.href_to_name(href, self.current_name) if href else None if name == self.current_name: return self.view.page().go_to_anchor(urlparse(href).fragment, lnum) if name and c.exists(name) and c.mime_map[name] in OEB_DOCS: return self.link_clicked.emit(name, urlparse(href).fragment or TOP) self.sync_requested.emit(self.current_name, lnum) def request_split(self, loc, totals): if self.current_name: self.split_requested.emit(self.current_name, loc, totals) def sync_to_editor(self, name, sourceline_address): self.current_sync_request = (name, sourceline_address) QTimer.singleShot(100, self._sync_to_editor) def _sync_to_editor(self): if not actions['sync-preview-to-editor'].isChecked(): return try: if self.refresh_timer.isActive() or self.current_sync_request[0] != self.current_name: return QTimer.singleShot(100, self._sync_to_editor) except TypeError: return # Happens if current_sync_request is None sourceline_address = self.current_sync_request[1] self.current_sync_request = None self.view.page().go_to_sourceline_address(sourceline_address) def report_worker_launch_error(self): if parse_worker.launch_error is not None: tb, parse_worker.launch_error = parse_worker.launch_error, None error_dialog(self, _('Failed to launch worker'), _( 'Failed to launch the worker process used for rendering the preview'), det_msg=tb, show=True) def show(self, name): if name != self.current_name: self.refresh_timer.stop() self.current_name = name self.report_worker_launch_error() parse_worker.add_request(name) self.view.setUrl(QUrl.fromLocalFile(current_container().name_to_abspath(name))) return True def refresh(self): if self.current_name: self.refresh_timer.stop() # This will check if the current html has changed in its editor, # and re-parse it if so self.report_worker_launch_error() parse_worker.add_request(self.current_name) # Tell webkit to reload all html and associated resources current_url = QUrl.fromLocalFile(current_container().name_to_abspath(self.current_name)) self.refresh_starting.emit() if current_url != self.view.url(): # The container was changed self.view.setUrl(current_url) else: self.view.refresh() self.refreshed.emit() def clear(self): self.view.clear() self.current_name = None @property def current_root(self): return self.view.page().current_root @property def is_visible(self): return actions['preview-dock'].isChecked() @property def live_css_is_visible(self): try: return actions['live-css-dock'].isChecked() except KeyError: return False def start_refresh_timer(self): if self.live_css_is_visible or (self.is_visible and actions['auto-reload-preview'].isChecked()): self.refresh_timer.start(tprefs['preview_refresh_time'] * 1000) def stop_refresh_timer(self): self.refresh_timer.stop() def auto_reload_toggled(self, checked): if self.live_css_is_visible and not actions['auto-reload-preview'].isChecked(): actions['auto-reload-preview'].setChecked(True) error_dialog(self, _('Cannot disable'), _( 'Auto reloading of the preview panel cannot be disabled while the' ' Live CSS panel is open.'), show=True) actions['auto-reload-preview'].setToolTip(_( 'Auto reload preview when text changes in editor') if not checked else _( 'Disable auto reload of preview')) def sync_toggled(self, checked): actions['sync-preview-to-editor'].setToolTip(_( 'Disable syncing of preview position to editor position') if checked else _( 'Enable syncing of preview position to editor position')) def visibility_changed(self, is_visible): if is_visible: self.refresh() def split_toggled(self, checked): actions['split-in-preview'].setToolTip(textwrap.fill(_( 'Abort file split') if checked else _( 'Split this file at a specified location.\n\nAfter clicking this button, click' ' inside the preview panel above at the location you want the file to be split.'))) if checked: self.split_start_requested.emit() else: self.view.page().split_mode(False) def do_start_split(self): self.view.page().split_mode(True) def stop_split(self): actions['split-in-preview'].setChecked(False) def load_finished(self, ok): if actions['split-in-preview'].isChecked(): if ok: self.do_start_split() else: self.stop_split() def apply_settings(self): s = self.view.page().settings() s.setFontSize(s.DefaultFontSize, tprefs['preview_base_font_size']) s.setFontSize(s.DefaultFixedFontSize, tprefs['preview_mono_font_size']) s.setFontSize(s.MinimumLogicalFontSize, tprefs['preview_minimum_font_size']) s.setFontSize(s.MinimumFontSize, tprefs['preview_minimum_font_size']) sf, ssf, mf = tprefs['preview_serif_family'], tprefs['preview_sans_family'], tprefs['preview_mono_family'] s.setFontFamily(s.StandardFont, {'serif':sf, 'sans':ssf, 'mono':mf, None:sf}[tprefs['preview_standard_font_family']]) s.setFontFamily(s.SerifFont, sf) s.setFontFamily(s.SansSerifFont, ssf) s.setFontFamily(s.FixedFont, mf)