class TagBrowserWidget(QFrame): # {{{ def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.NoFrame if gprefs['tag_browser_old_look'] else QFrame.StyledPanel) self._parent = parent self._layout = QVBoxLayout(self) self._layout.setContentsMargins(0,0,0,0) # Set up the find box & button self.tb_bar = tbb = TagBrowserBar(self) self.alter_tb, self.item_search, self.search_button = tbb.alter_tb, tbb.item_search, tbb.search_button self.toggle_search_button = tbb.toggle_search_button self._layout.addWidget(tbb) self.current_find_position = None self.search_button.clicked.connect(self.find) self.item_search.lineEdit().textEdited.connect(self.find_text_changed) self.item_search.activated[str].connect(self.do_find) # The tags view parent.tags_view = TagsView(parent) self.tags_view = parent.tags_view self._layout.insertWidget(0, parent.tags_view) # Now the floating 'not found' box l = QLabel(self.tags_view) self.not_found_label = l l.setFrameStyle(QFrame.StyledPanel) l.setAutoFillBackground(True) l.setText('<p><b>'+_('No More Matches.</b><p> Click Find again to go to first match')) l.setAlignment(Qt.AlignVCenter) l.setWordWrap(True) l.resize(l.sizeHint()) l.move(10,20) l.setVisible(False) self.not_found_label_timer = QTimer() self.not_found_label_timer.setSingleShot(True) self.not_found_label_timer.timeout.connect(self.not_found_label_timer_event, type=Qt.QueuedConnection) # The Alter Tag Browser button l = self.alter_tb self.collapse_all_action = ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser collapse all', _('Collapse all'), default_keys=(), action=ac, group=_('Tag browser')) connect_lambda(ac.triggered, self, lambda self: self.tags_view.collapseAll()) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser alter', _('Configure Tag browser'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(l.showMenu) sb = l.m.addAction(_('Sort by')) sb.m = l.sort_menu = QMenu(l.m) sb.setMenu(sb.m) sb.bg = QActionGroup(sb) # Must be in the same order as db2.CATEGORY_SORTS for i, x in enumerate((_('Name'), _('Number of books'), _('Average rating'))): a = sb.m.addAction(x) sb.bg.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) sb.setToolTip( _('Set the sort order for entries in the Tag browser')) sb.setStatusTip(sb.toolTip()) ma = l.m.addAction(_('Search type when selecting multiple items')) ma.m = l.match_menu = QMenu(l.m) ma.setMenu(ma.m) ma.ag = QActionGroup(ma) # Must be in the same order as db2.MATCH_TYPE for i, x in enumerate((_('Match any of the items'), _('Match all of the items'))): a = ma.m.addAction(x) ma.ag.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) ma.setToolTip( _('When selecting multiple entries in the Tag browser ' 'match any or all of them')) ma.setStatusTip(ma.toolTip()) mt = l.m.addAction(_('Manage authors, tags, etc.')) mt.setToolTip(_('All of these category_managers are available by right-clicking ' 'on items in the tag browser above')) mt.m = l.manage_menu = QMenu(l.m) mt.setMenu(mt.m) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser toggle item', _("'Click' found item"), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.toggle_item) # self.leak_test_timer = QTimer(self) # self.leak_test_timer.timeout.connect(self.test_for_leak) # self.leak_test_timer.start(5000) def save_state(self): gprefs.set('tag browser search box visible', self.toggle_search_button.isChecked()) def toggle_item(self): self.tags_view.toggle_current_index() def set_pane_is_visible(self, to_what): self.tags_view.set_pane_is_visible(to_what) def find_text_changed(self, str): self.current_find_position = None def set_focus_to_find_box(self): self.tb_bar.set_focus_to_find_box() def do_find(self, str=None): self.current_find_position = None self.find() @property def find_text(self): return unicode_type(self.item_search.currentText()).strip() def find(self): model = self.tags_view.model() model.clear_boxed() txt = self.find_text if txt.startswith('*'): model.set_categories_filter(txt[1:]) self.tags_view.recount() self.current_find_position = None return if model.get_categories_filter(): model.set_categories_filter(None) self.tags_view.recount() self.current_find_position = None if not txt: return self.item_search.lineEdit().blockSignals(True) self.search_button.setFocus(True) self.item_search.lineEdit().blockSignals(False) key = None colon = txt.rfind(':') if len(txt) > 2 else 0 if colon > 0: key = self._parent.library_view.model().db.\ field_metadata.search_term_to_field_key(txt[:colon]) txt = txt[colon+1:] self.current_find_position = \ model.find_item_node(key, txt, self.current_find_position) if self.current_find_position: self.tags_view.show_item_at_path(self.current_find_position, box=True) elif self.item_search.text(): self.not_found_label.setVisible(True) if self.tags_view.verticalScrollBar().isVisible(): sbw = self.tags_view.verticalScrollBar().width() else: sbw = 0 width = self.width() - 8 - sbw height = self.not_found_label.heightForWidth(width) + 20 self.not_found_label.resize(width, height) self.not_found_label.move(4, 10) self.not_found_label_timer.start(2000) def not_found_label_timer_event(self): self.not_found_label.setVisible(False) def keyPressEvent(self, ev): if ev.key() in (Qt.Key_Enter, Qt.Key_Return) and self.find_text: self.find() ev.accept() return return QFrame.keyPressEvent(self, ev)
class TagBrowserWidget(QFrame): # {{{ def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.NoFrame if gprefs['tag_browser_old_look'] else QFrame.StyledPanel) self._parent = parent self._layout = QVBoxLayout(self) self._layout.setContentsMargins(0,0,0,0) # Set up the find box & button self.tb_bar = tbb = TagBrowserBar(self) tbb.clear_find.connect(self.reset_find) self.alter_tb, self.item_search, self.search_button = tbb.alter_tb, tbb.item_search, tbb.search_button self.toggle_search_button = tbb.toggle_search_button self._layout.addWidget(tbb) self.current_find_position = None self.search_button.clicked.connect(self.find) self.item_search.lineEdit().textEdited.connect(self.find_text_changed) self.item_search.activated[str].connect(self.do_find) # The tags view parent.tags_view = TagsView(parent) self.tags_view = parent.tags_view self._layout.insertWidget(0, parent.tags_view) # Now the floating 'not found' box l = QLabel(self.tags_view) self.not_found_label = l l.setFrameStyle(QFrame.StyledPanel) l.setAutoFillBackground(True) l.setText('<p><b>'+_('No more matches.</b><p> Click Find again to go to first match')) l.setAlignment(Qt.AlignVCenter) l.setWordWrap(True) l.resize(l.sizeHint()) l.move(10,20) l.setVisible(False) self.not_found_label_timer = QTimer() self.not_found_label_timer.setSingleShot(True) self.not_found_label_timer.timeout.connect(self.not_found_label_timer_event, type=Qt.QueuedConnection) # The Alter Tag Browser button l = self.alter_tb self.collapse_all_action = ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser collapse all', _('Collapse all'), default_keys=(), action=ac, group=_('Tag browser')) connect_lambda(ac.triggered, self, lambda self: self.tags_view.collapseAll()) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser alter', _('Configure Tag browser'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(l.showMenu) sb = l.m.addAction(_('Sort by')) sb.m = l.sort_menu = QMenu(l.m) sb.setMenu(sb.m) sb.bg = QActionGroup(sb) # Must be in the same order as db2.CATEGORY_SORTS for i, x in enumerate((_('Name'), _('Number of books'), _('Average rating'))): a = sb.m.addAction(x) sb.bg.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) sb.setToolTip( _('Set the sort order for entries in the Tag browser')) sb.setStatusTip(sb.toolTip()) ma = l.m.addAction(_('Search type when selecting multiple items')) ma.m = l.match_menu = QMenu(l.m) ma.setMenu(ma.m) ma.ag = QActionGroup(ma) # Must be in the same order as db2.MATCH_TYPE for i, x in enumerate((_('Match any of the items'), _('Match all of the items'))): a = ma.m.addAction(x) ma.ag.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) ma.setToolTip( _('When selecting multiple entries in the Tag browser ' 'match any or all of them')) ma.setStatusTip(ma.toolTip()) mt = l.m.addAction(_('Manage authors, tags, etc.')) mt.setToolTip(_('All of these category_managers are available by right-clicking ' 'on items in the Tag browser above')) mt.m = l.manage_menu = QMenu(l.m) mt.setMenu(mt.m) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser toggle item', _("'Click' found item"), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.toggle_item) # self.leak_test_timer = QTimer(self) # self.leak_test_timer.timeout.connect(self.test_for_leak) # self.leak_test_timer.start(5000) def save_state(self): gprefs.set('tag browser search box visible', self.toggle_search_button.isChecked()) def toggle_item(self): self.tags_view.toggle_current_index() def set_pane_is_visible(self, to_what): self.tags_view.set_pane_is_visible(to_what) def find_text_changed(self, str): self.current_find_position = None def set_focus_to_find_box(self): self.tb_bar.set_focus_to_find_box() def do_find(self, str=None): self.current_find_position = None self.find() @property def find_text(self): return unicode_type(self.item_search.currentText()).strip() def reset_find(self): model = self.tags_view.model() if model.get_categories_filter(): model.set_categories_filter(None) self.tags_view.recount() self.current_find_position = None def find(self): model = self.tags_view.model() model.clear_boxed() # When a key is specified don't use the auto-collapsing search. # A colon separates the lookup key from the search string. # A leading colon says not to use autocollapsing search but search all keys txt = self.find_text colon = txt.find(':') if colon >= 0: key = self._parent.library_view.model().db.\ field_metadata.search_term_to_field_key(txt[:colon]) if key in self._parent.library_view.model().db.field_metadata: txt = txt[colon+1:] else: key = '' txt = txt[1:] if colon == 0 else txt else: key = None # key is None indicates that no colon was found. # key == '' means either a leading : was found or the key is invalid # At this point the txt might have a leading =, in which case do an # exact match search if (gprefs.get('tag_browser_always_autocollapse', False) and key is None and not txt.startswith('*')): txt = '*' + txt if txt.startswith('*'): self.tags_view.collapseAll() model.set_categories_filter(txt[1:]) self.tags_view.recount() self.current_find_position = None return if model.get_categories_filter(): model.set_categories_filter(None) self.tags_view.recount() self.current_find_position = None if not txt: return self.item_search.lineEdit().blockSignals(True) self.search_button.setFocus(True) self.item_search.lineEdit().blockSignals(False) if txt.startswith('='): equals_match = True txt = txt[1:] else: equals_match = False self.current_find_position = \ model.find_item_node(key, txt, self.current_find_position, equals_match=equals_match) if self.current_find_position: self.tags_view.show_item_at_path(self.current_find_position, box=True) elif self.item_search.text(): self.not_found_label.setVisible(True) if self.tags_view.verticalScrollBar().isVisible(): sbw = self.tags_view.verticalScrollBar().width() else: sbw = 0 width = self.width() - 8 - sbw height = self.not_found_label.heightForWidth(width) + 20 self.not_found_label.resize(width, height) self.not_found_label.move(4, 10) self.not_found_label_timer.start(2000) def not_found_label_timer_event(self): self.not_found_label.setVisible(False) def keyPressEvent(self, ev): if ev.key() in (Qt.Key_Enter, Qt.Key_Return) and self.find_text: self.find() ev.accept() return return QFrame.keyPressEvent(self, ev)
class WebTab(QWidget): class SavedTab(object): def __init__(self, webTab=None): self.title = '' self.url = QUrl() self.icon = QIcon() self.history = QByteArray() self.isPinned = False self.zoomLevel = 1 self.parentTab = -1 self.childTabs = [] self.sessionData = {} if webTab: self.setWebTab(webTab) def __getstate__(self): result = dict(self.__dict__) result['url'] = result['url'].toEncoded() data = QByteArray() ds = QDataStream(data, QIODevice.WriteOnly) ds.writeQVariant(self.icon) result['icon'] = data.data() return result def __setstate__(self, state): for key, val in state.items(): if key == 'url': self.__dict__[key] = QUrl.fromEncoded(val) elif key == 'icon': ds = QDataStream(QByteArray(val)) self.__dict__[key] = ds.readQVariant() else: self.__dict__[key] = val def setWebTab(self, webTab): self.title = webTab.title() self.url = webTab.url() self.icon = webTab.icon() self.history = webTab.historyData() self.isPinned = webTab.isPinned() self.zoomLevel = webTab.zoomLevel() if webTab.parentTab(): self.parentTab = webTab.parentTab().tabIndex() else: self.parentTab = -1 self.childTabs = [ tab.tabIndex() for tab in webTab.childTabs() ] self.sessionData = webTab.sessionData() def isValid(self): return not self.url.isEmpty() or not self.history.isEmpty() def clear(self): self.title = '' self.url = QUrl() self.icon = QIcon() self.history = QByteArray() self.isPinned = False self.zoomLevel = 1 self.parentTab = -1 self.childTabs = [] self.sessionData = {} # type AddChildBehavior AppendChild = 0 PrependChild = 1 s_addChildBehavior = AppendChild def __init__(self, parent=None): super(WebTab, self).__init__(parent) self.setObjectName('webtab') self._tabBar = None self._window = None self._parentTab = None self._childTabs = [] self._sessionData = {} self._savedTab = self.SavedTab() self._isPinned = False self._isCurrentTab = False self._webView = TabbedWebView(self) self._webView.setPage(WebPage()) self._webView.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.setFocusProxy(self._webView) self._locationBar = LocationBar(self) self._locationBar.setWebView(self._webView) self._tabIcon = TabIcon(self) self._tabIcon.setWebTab(self) self._layout = QVBoxLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(0) self._layout.addWidget(self._webView) viewWidget = QWidget(self) viewWidget.setLayout(self._layout) self._splitter = QSplitter(Qt.Vertical, self) self._splitter.setChildrenCollapsible(False) self._splitter.addWidget(viewWidget) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self._splitter) self.setLayout(layout) self._notificationWidget = QWidget(self) self._notificationWidget.setAutoFillBackground(True) pal = self._notificationWidget.palette() pal.setColor(QPalette.Window, pal.window().color().darker(110)) self._notificationWidget.setPalette(pal) nlayout = QVBoxLayout(self._notificationWidget) nlayout.setSizeConstraint(QLayout.SetMinAndMaxSize) nlayout.setContentsMargins(0, 0, 0, 0) nlayout.setSpacing(1) self._webView.showNotification.connect(self.showNotification) self._webView.loadFinished.connect(self.loadFinished) self._webView.titleChanged.connect(self.titleWasChanged) self._webView.titleChanged.connect(self.titleChanged) self._webView.iconChanged.connect(self.iconChanged) self._webView.backgroundActivityChanged.connect(self.backgroundActivityChanged) self._webView.loadStarted.connect(lambda: self.loadingChanged.emit(True)) self._webView.loadFinished.connect(lambda: self.loadingChanged.emit(False)) def pageChanged(page): page.audioMutedChanged.connect(self.playingChanged) page.recentlyAudibleChanged.connect(self.mutedChanged) pageChanged(self._webView.page()) self._webView.pageChanged.connect(pageChanged) def tabIconResized(): if self._tabBar: self._tabBar.update() self._tabIcon.resized.connect(tabIconResized) def browserWindow(self): ''' @return BrowserWindow ''' return self._window def webView(self): ''' @return TabbedWebView ''' return self._webView def locationBar(self): ''' @return LocationBar ''' return self._locationBar def tabIcon(self): ''' @return TabIcon ''' return self._tabIcon def parentTab(self): ''' @return WebTab ''' return self._parentTab def setParentTab(self, tab): if self._isPinned or self._parentTab == tab: return if tab and tab.isPinned(): return if self._parentTab: index = self._parentTab._childTabs.index(self) if index >= 0: self._parentTab._childTabs.pop(index) self._parentTab.childTabRemoved.emit(self, index) self._parentTab = tab if tab: self._parentTab = None tab.addChildTab(self) else: self.parentTabChanged.emit(self._parentTab) def addChildTab(self, tab, index=-1): if self._isPinned or not tab or tab.isPinned(): return oldParent = tab._parentTab tab._parentTab = self if oldParent: index = oldParent._childTabs.index(tab) if index >= 0: oldParent._childTabs.pop(index) oldParent.childTabRemoved.emit(tab, index) if index < 0 or index > len(self._childTabs): index = 0 if self.addChildBehavior() == self.AppendChild: index = len(self._childTabs) else: # PrependChild index = 0 self._childTabs.insert(index, tab) self.childTabAdded.emit(tab, index) tab.parentTabChanged.emit(self) def childTabs(self): ''' @return QVector<WebTab*> ''' return self._childTabs def sessionData(self): ''' @return {} ''' return self._sessionData def setSessionData(self, key, value): self._sessionData[key] = value def url(self): if self.isRestored(): if self._webView.url().isEmpty() and self._webView.isLoading(): return self._webView.page().requestedUrl() return self._webView.url() else: return self._savedTab.url def title(self, allowEmpty=False): if self.isRestored(): return self._webView.title(allowEmpty) else: return self._savedTab.title def icon(self, allowNull=False): if self.isRestored(): return self._webView.icon(allowNull) if allowNull or not self._savedTab.icon.isNull(): return self._savedTab.icon return IconProvider.emptyWebIcon() def history(self): ''' @return QWebEngineHistory ''' return self._webView.history() def zoomLevel(self): return self._webView.zoomLevel() def setZoomLevel(self, level): self._webView.setZoomLevel(level) def detach(self): assert(self._window) assert(self._tabBar) # Remove from tab tree self.removeFromTabTree() # Remove icon from tab self._tabBar.setTabButton(self.tabIndex(), self._tabBar.iconButtonPosition(), None) self._tabIcon.setParent(self) # Remove the tab from tabbar self._window.tabWidget().removeTab(self.tabIndex()) self.setParent(None) # Remove the locationbar from window self._locationBar.setParent(self) # Detach TabbedWindow self._webView.setBrowserWindow(None) if self._isCurrentTab: self._isCurrentTab = False self.currentTabChanged.emit(self._isCurrentTab) self._tabBar.currentChanged.disconnect(self.onCurrentChanged) self._window = None self._tabBar = None def onCurrentChanged(self, index): wasCurrent = self._isCurrentTab self._isCurrentTab = index == self.tabIndex() if wasCurrent != self._isCurrentTab: self.currentTabChanged.emit(self._isCurrentTab) def attach(self, window): self._window = window self._tabBar = self._window.tabWidget().tabBar() self._webView.setBrowserWindow(self._window) self._locationBar.setBrowserWindow(self._window) self._tabBar.setTabText(self.tabIndex(), self.title()) self._tabBar.setTabButton(self.tabIndex(), self._tabBar.iconButtonPosition(), self._tabIcon) QTimer.singleShot(0, self._tabIcon.updateIcon) self.onCurrentChanged(self._tabBar.currentIndex()) self._tabBar.currentChanged.connect(self.onCurrentChanged) def historyData(self): ''' @return QByteArray ''' if self.isRestored(): historyArray = QByteArray() stream = QDataStream(historyArray, QIODevice.WriteOnly) history = self._webView.history() stream << history return historyArray else: return self._savedTab.history def stop(self): self._webView.stop() def reload(self): self._webView.reload() def load(self, request): ''' @param: requset LoadRequest ''' if self.isRestored(): self.tabActivated() QTimer.singleShot(0, lambda: self.load(request)) else: self._webView.load(request) def unload(self): self._savedTab = self.SavedTab(self) self.restoredChanged.emit(self.isRestored()) self._webView.setPage(WebPage()) self._webView.setFocus() def isLoading(self): return self._webView.isloading() def isPinned(self): return self._isPinned def setPinned(self, state): if self._isPinned == state: return if state: self.removeFromTabTree() self._isPinned = state self.pinnedChanged.emit(self._isPinned) def togglePinned(self): assert(self._tabBar) assert(self._window) self.setPinned(not self.isPinned()) self._window.tabWidget().pinUnPinTab(self.tabIndex(), self.title()) def isMuted(self): return self._webView.page().isAudioMuted() def isPlaying(self): return self._webView.page().recentlyAudible() def setMuted(self, muted): self._webView.page().setAudioMuted(muted) def toggleMuted(self): self.setMuted(not self.isMuted()) def backgroundActivity(self): return self._webView.backgroundActivity() def tabIndex(self): index = -1 if self._tabBar: index = self._tabBar.tabWidget().indexOf(self) return index def isCurrentTab(self): return self._isCurrentTab def makeCurrentTab(self): if self._tabBar: self._tabBar.tabWidget().setCurrentIndex(self.tabIndex()) def closeTab(self): if self._tabBar: self._tabBar.tabWidget().closeTab(self.tabIndex()) def moveTab(self, to): if self._tabBar: self._tabBar.tabWidget().moveTab(self.tabIndex(), to) def haveInspector(self): return self._splitter.count() > 1 and self._splitter.widget(1).inherits('WebInspector') def showWebInspector(self, inspectElement=False): if not WebInspector.isEnabled() or self.haveInspector(): return inspector = WebInspector(self) inspector.setView(self._webView) if inspectElement: inspector.inspectElement() height = inspector.sizeHint().height() self._splitter.addWidget(inspector) self._splitter.setSizes((self._splitter.height() - height, height)) def toggleWebInspector(self): if not self.haveInspector(): self.showWebInspector() else: self._splitter.widget(1).destroy() # TODO: del? def showSearchToolBar(self, searchText=''): index = 1 toolBar = None if self._layout.count() == 1: toolBar = SearchToolBar(self._webView, self) self._layout.insertWidget(index, toolBar) if self._layout.count() == 2: assert(isinstance(self._layout.itemAt(index).widget(), SearchToolBar)) toolBar = self._layout.itemAt(index).widget() assert(toolBar) if not searchText: toolBar.setText(searchText) toolBar.focusSearchLine() def isRestored(self): return not self._savedTab.isValid() def restoreTab(self, tab): ''' @param: tab SavedTab ''' assert(self._tabBar) self.setPinned(tab.isPinned) self._sessionData = tab.sessionData if not self.isPinned() and gVar.appSettings.loadTabsOnActivation: self._savedTab = tab self.restoredChanged.emit(self.isRestored()) index = self.tabIndex() self._tabBar.setTabText(index, tab.title) self._locationBar.showUrl(tab.url) self._tabIcon.updateIcon() else: # This is called only on restore session and restoring tabs # immediately crashes QtWebEngine, waiting after initialization is # complete fixes it QTimer.singleShot(1000, lambda: self.p_restoreTab(tab)) def p_restoreTab(self, tab): ''' @param: tab SavedTab ''' self.p_restoreTabByUrl(tab.url, tab.history, tab.zoomLevel) def p_restoreTabByUrl(self, url, history, zoomLevel): self._webView.load(url) # Restoring history of internal pages crashes QtWebEngine 5.8 blacklistedSchemes = ['view-source', 'chrome'] if (url.scheme() not in blacklistedSchemes): stream = QDataStream(history) stream >> self._webView.history() self._webView.setZoomLevel(zoomLevel) self._webView.setFocus() def tabActivated(self): if self.isRestored(): return def _onTabActivated(): if self.isRestored(): return self.p_restoreTab(self._savedTab) self._savedTab.clear() self.restoredChanged.emit(self.isRestored()) QTimer.singleShot(0, _onTabActivated) def addChildBehavior(self): ''' @return AddChildBehavior ''' return self.s_addChildBehavior def setAddChildBehavior(self, behavior): self.s_addChildBehavior = behavior # Q_SLOTS @pyqtSlot(QWidget) def showNotification(self, notif): self._notificationWidget.setParent(self) self._notificationWidget.raise_() self._notificationWidget.setFixedWidth(self.width()) self._notificationWidget.layout().addWidget(notif) self._notificationWidget.show() notif.show() @pyqtSlot() def loadFinished(self): self.titleWasChanged(self._webView.title()) # Q_SIGNALS titleChanged = pyqtSignal(str) # title iconChanged = pyqtSignal(QIcon) # icon pinnedChanged = pyqtSignal(bool) # pinned restoredChanged = pyqtSignal(bool) # restored currentTabChanged = pyqtSignal(bool) # current loadingChanged = pyqtSignal(bool) # loading mutedChanged = pyqtSignal(bool) # muted playingChanged = pyqtSignal(bool) # playing backgroundActivityChanged = pyqtSignal(bool) # activity parentTabChanged = pyqtSignal('PyQt_PyObject') # WebTab* childTabAdded = pyqtSignal('PyQt_PyObject', int) # WebTab*, index childTabRemoved = pyqtSignal('PyQt_PyObject', int) # WebTab*, index def titleWasChanged(self, title): if not self._tabBar or not self._window or not title: return if self._isCurrentTab: self._window.setWindowTitle('%s - Demo' % title) self._tabBar.setTabText(self.tabIndex(), title) # override def resizeEvent(self, event): QWidget.resizeEvent(self, event) self._notificationWidget.setFixedWidth(self.width()) def removeFromTabTree(self): parentTab = self._parentTab parentIndex = -1 if parentTab: parentIndex = parentTab._childTabs.index(self) self.setParentTab(None) idx = 0 while self._childTabs: child = self._childTabs[0] child.setParentTab(None) if parentTab: parentTab.addChildTab(child, parentIndex + idx) idx += 1