class SplashScreen(QSplashScreen): """ Display a Splashscreen """ signal_done = QtCore.pyqtSignal() def __init__(self): QSplashScreen.__init__(self, QtGui.QPixmap(), QtCore.Qt.WindowStaysOnTopHint) self.rootDir = Path(__file__).parent # default values self.image = None self.version = "Version: 3.x" # pixmap.height - ? self.progress_y = 68 # pixmap.width - ? self.vx = 24 # pixmap.height - ? self.vy = 32 # message font size self.msize = 12 self.cv = OpenCVLib() self.progressBar = QProgressBar(self) self.progressBar.setMinimum(0) self.progressBar.setValue(0) self.progressBar.setMaximum(100) self.progressBar.setTextVisible(False) self.setPositionProgressBar() self.message = QLabel(self) self.message.setFont(QFont("Arial", self.msize)) self.message.setStyleSheet("QLabel { color : #000000; }") self.message.setAlignment(Qt.AlignCenter) # Shadow Effekt effect = QGraphicsDropShadowEffect(self) effect.setBlurRadius(5) effect.setColor(QColor("#ffffff")) effect.setOffset(1, 1) self.message.setGraphicsEffect(effect) self.setPositionMessage() # self.message.hide() # CSS Styling self.setStyleSheet(""" QProgressBar{ border: 1px solid #eeeeee; text-align: center; padding: 0; margin-top: 10px; } QProgressBar::chunk{ background-color: #3daee9; width: 0.34em; margin: 0 1px; } """) def show(self, *args, **kwargs): if self.image == None: raise ValueError('Specify an Image via SplashScreen::setImage()') return QSplashScreen.show(self, *args, **kwargs) def setMessage(self, msg): self.message.setText("%s ..." % (msg)) self.message.show() def setPositionMessage(self): """ place Message on screen """ # where is progress? p = self.progressBar.geometry() self.message.setGeometry(0, p.y() - self.msize, self.pixmap().width(), 2 * self.msize) self.message.updateGeometry() def setPositionProgressBar(self): """ place ProgressBar on screen """ margin = 10 # x, y, w, h self.progressBar.setGeometry(margin, self.pixmap().height() - self.progress_y, self.pixmap().width() - 2 * margin, 20) self.progressBar.updateGeometry() def scale(self, pix): gold = 0.618 h = pix.size().height() w = pix.size().width() # max width 68% of screen screen = QGuiApplication.screens()[0] new_w = screen.geometry().width() * gold new_h = h * new_w / w # python resize # return pix.scaled(new_w, new_h, Qt.KeepAspectRatioByExpanding | Qt.SmoothTransformation) # resize with opencv Qimg = pix.toImage() img = self.cv.QImage2MAT(Qimg) resized = self.cv.resizeTo(img, new_w, new_h) return self.cv.MAT2QPixmap(resized) def setVersion(self, version): """ adds a Version Number and updates the image """ self.version = "Version: %s" % version def paintEvent(self, *args, **kwargs): """ override, important to work """ return QSplashScreen.paintEvent(self, *args, **kwargs) def setImage(self, img): """ sets the image and adds a Version Number """ self.image = self.rootDir.joinpath(img).as_posix() splash_pix = QtGui.QPixmap(self.image, format='jpg') if splash_pix.isNull(): raise ValueError('Error loading Image [self.image]') # Add version painter = QtGui.QPainter(splash_pix) painter.setRenderHint(QtGui.QPainter.Antialiasing) painter.setFont(QFont("Arial", 18)) painter.setPen(QColor("#666666")) painter.drawText(0, 0, splash_pix.size().width() - self.vx, splash_pix.size().height() - self.vy, QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight, self.version) painter.end() self.setPixmap(self.scale(splash_pix)) # ---------------------------------------------- # other stuff self.setPositionProgressBar() self.setPositionMessage() def step(self): """ a preloading step is done """ self.progressBar.setValue(self.progressBar.value() + 1) self.progressBar.repaint() if (self.progressBar.value() >= (self.progressBar.maximum() - 1)): self.signal_done.emit() def setProgressMax(self, maxval): self.progressBar.setMaximum(maxval)
class WebTab(QWidget): """ The tab contains chrome plus a web view; is hosted on a tab bar """ def __init__(self, parent=None): super(WebTab, self).__init__(parent) self.current = { 'title': "[EMPTY]", 'address': "" } # address bar self.address_bar = AddressBar(parent=self) # webkit (the actual "web engine") self.webkit = WebView(parent=self) # set_prefix: app defined, carries str self.webkit.set_prefix.connect(self.address_bar.set_model) # CFG02 # javascript_state: app defined, carries bool self.webkit.javascript_state.connect(self.address_bar.set_bgcolor) # small label displaying instance ID and pending tab operations info_label = QLabel(parent=self) info_label.setText('?') # CFG02 # webkit_info: app defined, carries str self.webkit.attr.webkit_info.connect(info_label.setText) def update_address(qurl): """ The 'connect' gives a QUrl and setText receives a string; can't just connect setText Required because a 3XX HTTP redirection will change the address, and without updating, the address bar will be left stale AB02 AB03 """ self.current['address'] = qurl.toString() self.address_bar.setText(self.current['address']) # urlChanged carries QUrl; loadStarted carries nothing; # loadFinished carries bool; titleChanged carries str; # loadProgress carries int self.webkit.urlChanged.connect(update_address) self.webkit.loadStarted.connect(self.load_started) self.webkit.loadFinished.connect(self.load_finished) self.webkit.titleChanged.connect(self.save_title) self.webkit.loadProgress.connect(self.load_progress) def fill_notifier(message, request): """ sends a message to be displayed by the notifier """ notify(message + " " + request.url().toString()) # downloadRequested carries QNetworkRequest self.webkit.page().downloadRequested.connect( partial(fill_notifier, "download")) # unsupportedContent carries QNetworkReply self.webkit.page().unsupportedContent.connect( partial(fill_notifier, "unsupported")) # input area for access-key navigation self.nav_bar = NavigateInput(parent=self) # editingFinished carries nothing self.nav_bar.editingFinished.connect(self.webkit.clear_labels) # textEdited carries str self.nav_bar.textEdited.connect(self.webkit.akeynav) # nonvalid_tag (app defined) carries nothing self.webkit.nonvalid_tag.connect(self.nav_bar.clear) # 'corner' message and notification label, not on timer, smaller self.message_label = MessageLabel(self.webkit) def handle_hovered(link, title, content): """ When hovered, if ALT is pressed, show message label; hide otherwise """ if ((QApplication.keyboardModifiers() & Qt.AltModifier) and (link or title or content)): # ugly hack to ensure proper resizing; find a better way? self.message_label.hide() self.message_label.setText( link + " " + title + " " + content) self.message_label.show() else: self.message_label.hide() # linkHovered carries str, str, str self.webkit.page().linkHovered.connect(handle_hovered) def handle_signaled(title): """ We received a string through a signal; display it on the message label """ # if title: self.message_label.hide() self.message_label.setText(title) self.message_label.show() # show_message (app defined) carries str self.webkit.show_message.connect(handle_signaled) # loadStarted carries nothing self.webkit.loadStarted.connect(self.message_label.hide) # At the time navigation is requested load_requested is sent, and the # requested url is set as text in grey at the address bar. Once the # urlChanged signal is received, the actual url is set in black. # load_requested (app defined) carries str self.webkit.load_requested.connect( partial(self.address_bar.set_txt_color, color=QColor(128, 128, 128))) def hide_message_label(*_): """ WARNING scrollRequested carries int, int, QRect; star swallows all """ self.message_label.hide() self.webkit.page().scrollRequested.connect(hide_message_label) # focus_webkit (app defined) carries nothing self.webkit.hide_overlay.connect(self.message_label.hide) self.webkit.focus_webkit.connect(self.address_bar.restore) # progress bar self.pbar = QProgressBar(self) self.pbar.setRange(0, 100) self.pbar.setTextVisible(False) self.pbar.setVisible(False) self.pbar.setMaximumHeight(7) # search in page self.search_frame = SearchFrame(parent=self) # NAV20 # textChanged carries str self.search_frame.search_line.textChanged.connect(self.do_search) # layout grid = QGridLayout(self) grid.setSpacing(0) grid.setVerticalSpacing(0) grid.setContentsMargins(0, 0, 0, 0) grid.setRowStretch(1, 1) grid.addWidget(info_label, 0, 0, 1, 1) grid.addWidget(self.address_bar, 0, 1, 1, 1) grid.addWidget(self.nav_bar, 0, 2, 1, 1) grid.addWidget(self.webkit, 1, 0, 1, 3) grid.addWidget(self.search_frame, 2, 0, 1, 3) grid.addWidget(self.pbar, 3, 0, 1, 3) def show_search(): """ One-time callback for QShortcut NAV20 """ self.search_frame.setVisible(True) self.search_frame.search_line.setFocus() def hide_search(): """ One-time callback for QShortcut NAV20 """ self.search_frame.setVisible(False) self.webkit.findText("") self.webkit.setFocus() def navigate_completion(key=Qt.Key_Down): """ Sends an "arrow press" to the completion popup to navigate results. Not the best way to do this. It would be better to find out what function is being called by that arrow press. AB01 """ event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier) self.address_bar.completer().popup().keyPressEvent(event) # the star swallows all arguments that aren't named 'store' def reset_addressbar(*, store=False): """ Restore the address bar to its original address and color (it could have changed because of a hover event). Optionally, store the original address in the clipboard. AB03 """ if self.current['address']: self.address_bar.set_txt_color(self.current['address'], color=QColor(0, 0, 0)) if store: clipboard(self.current['address']) # urlChanged carries QUrl (ignored) self.webkit.urlChanged.connect(reset_addressbar) def enter_address_bar(clear=True): """ do not try entering the address bar if a load is in progress; do an 'stop' first AB00 """ if 'in_page_load' not in self.webkit.attr: if clear: self.address_bar.clear_and_focus() else: self.address_bar.setFocus() def cancel(): """ if we're in the middle of loading the document, stop loading. Otherwise, hide the message label. The general concept is to reach a basic state. """ if 'in_page_load' not in self.webkit.attr: self.message_label.hide() self.webkit.update() else: self.webkit.stop() set_shortcuts([ # search NAV20 ("G", self.webkit, show_search), ("Escape", self.search_frame, hide_search), ("Return", self.search_frame, self.do_search), ("Ctrl+J", self.search_frame, self.do_search), # go to page AB00 ("Ctrl+J", self.address_bar, partial( self.webkit.navigate, self.address_bar)), ("Return", self.address_bar, partial( self.webkit.navigate, self.address_bar)), # address bar interaction ("A", self.webkit, cancel), ("Ctrl+L", self.webkit, enter_address_bar), # AB00 ("Ctrl+Shift+L", self.webkit, partial( enter_address_bar, clear=False)), ("Escape", self.address_bar, self.webkit.setFocus), # AB00 ("Ctrl+I", self.address_bar, navigate_completion), # AB01 ("Ctrl+P", self.address_bar, partial( navigate_completion, Qt.Key_Up)), # in-page element navigation ("Ñ", self, self.enter_nav), # NAV11 (";", self, self.enter_nav), # DOM01 ("Ctrl+Ñ", self, partial(self.enter_nav, target="titles")), # toggle ("Q", self.webkit, self.toggle_script), # TOG01 # clipboard ("E", self, partial(reset_addressbar, store=True)) # CB05 ]) def enter_nav(self, target="links"): """ A request for access-key navigation was received; display link labels and go to the input area NAV11 """ self.webkit.make_labels(target) if self.webkit.map_tags: self.nav_bar.show() self.nav_bar.setFocus() def toggle_script(self): """ Retrieves the current javascript state for the tab and sets the opposite Callback for shortcut action TOG01 """ self.webkit.javascript(not self.webkit.javascript()) def load_progress(self, val): """ Callback for connection """ self.pbar.setValue(val) self.set_title("{}% {}".format(val, self.current['title'])) # connect (en constructor) def load_started(self): """ Callback for connection """ self.address_bar.completer().popup().close() self.search_frame.setVisible(False) self.pbar.setValue(0) self.pbar.setVisible(True) # connect (en constructor) def load_finished(self, success): """ Callback for connection """ self.webkit.navlist = [] self.pbar.setVisible(False) self.set_title(self.current['title']) if self.address_bar.hasFocus(): self.webkit.setFocus() if not success: notify("[F]") print("loadFinished: failed", self.webkit.page().mainFrame().requestedUrl()) # connect (en constructor) def save_title(self, title): """ Store a recently changed title, and display it """ if title: self.current['title'] = title self.set_title(title) def set_title(self, title): """ Go upwards to the main window's tab widget and set this tab's title """ if title is None: title = "[NO TITLE]" mainwin().tab_widget.setTabText( mainwin().tab_widget.indexOf(self), title[:40]) # connection in constructor and action def do_search(self, search=None): """ Find text on the currently loaded web page. If no text is provided, it's extracted from the search widget. NAV20 """ if search is None: search = self.search_frame.search_line.text() self.webkit.findText(search, QWebPage.FindWrapsAroundDocument)
class ProgressDialog(QDialog): _default = ''' QProgressBar { min-width: 350px; } ''' def __init__(self, parent, title, total_progress): super().__init__(parent) self.setWindowTitle(title) self._total_progress = total_progress self._progress_bar = None self._setup_ui() self._prepare() def _setup_ui(self): self.setStyleSheet(self._default) self.setWindowFlags( Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint ) self.setStyleSheet(self._default) layout = make_layout( horizon=False, margin=24, spacing=24 ) self._progress_bar = QProgressBar() self._progress_bar.setRange(0, self._total_progress) self._progress_bar.setTextVisible(True) self._progress_bar.setFormat(r'%p% (%v/%m)') self._progress_bar.setValue(0) layout.addWidget( self._progress_bar ) self.setLayout(layout) move_center(self) def _prepare(self): return def increase(self, step=1): self._progress_bar.setValue(self._progress_bar.value() + step) if self._progress_bar.value() == self._progress_bar.maximum(): self.close() def _on_show(self): return def _on_close(self): return def showEvent(self, event): self._on_show() event.accept() def closeEvent(self, event): self._on_close() event.accept()
class WebTab(QWidget): """ The tab contains chrome plus a web view; is hosted on a tab bar """ def __init__(self, parent=None): super(WebTab, self).__init__(parent) self.current = {'title': "[EMPTY]", 'address': ""} # address bar self.address_bar = AddressBar(parent=self) # webkit (the actual "web engine") self.webkit = WebView(parent=self) # set_prefix: app defined, carries str self.webkit.set_prefix.connect(self.address_bar.set_model) # CFG02 # javascript_state: app defined, carries bool self.webkit.javascript_state.connect(self.address_bar.set_bgcolor) # small label displaying instance ID and pending tab operations info_label = QLabel(parent=self) info_label.setText('?') # CFG02 # webkit_info: app defined, carries str self.webkit.attr.webkit_info.connect(info_label.setText) def update_address(qurl): """ The 'connect' gives a QUrl and setText receives a string; can't just connect setText Required because a 3XX HTTP redirection will change the address, and without updating, the address bar will be left stale AB02 AB03 """ self.current['address'] = qurl.toString() self.address_bar.setText(self.current['address']) # urlChanged carries QUrl; loadStarted carries nothing; # loadFinished carries bool; titleChanged carries str; # loadProgress carries int self.webkit.urlChanged.connect(update_address) self.webkit.loadStarted.connect(self.load_started) self.webkit.loadFinished.connect(self.load_finished) self.webkit.titleChanged.connect(self.save_title) self.webkit.loadProgress.connect(self.load_progress) def fill_notifier(message, request): """ sends a message to be displayed by the notifier """ notify(message + " " + request.url().toString()) # downloadRequested carries QNetworkRequest self.webkit.page().downloadRequested.connect( partial(fill_notifier, "download")) # unsupportedContent carries QNetworkReply self.webkit.page().unsupportedContent.connect( partial(fill_notifier, "unsupported")) # input area for access-key navigation self.nav_bar = NavigateInput(parent=self) # editingFinished carries nothing self.nav_bar.editingFinished.connect(self.webkit.clear_labels) # textEdited carries str self.nav_bar.textEdited.connect(self.webkit.akeynav) # nonvalid_tag (app defined) carries nothing self.webkit.nonvalid_tag.connect(self.nav_bar.clear) # 'corner' message and notification label, not on timer, smaller self.message_label = MessageLabel(self.webkit) def handle_hovered(link, title, content): """ When hovered, if ALT is pressed, show message label; hide otherwise """ if ((QApplication.keyboardModifiers() & Qt.AltModifier) and (link or title or content)): # ugly hack to ensure proper resizing; find a better way? self.message_label.hide() self.message_label.setText(link + " " + title + " " + content) self.message_label.show() else: self.message_label.hide() # linkHovered carries str, str, str self.webkit.page().linkHovered.connect(handle_hovered) def handle_signaled(title): """ We received a string through a signal; display it on the message label """ # if title: self.message_label.hide() self.message_label.setText(title) self.message_label.show() # show_message (app defined) carries str self.webkit.show_message.connect(handle_signaled) # loadStarted carries nothing self.webkit.loadStarted.connect(self.message_label.hide) # At the time navigation is requested load_requested is sent, and the # requested url is set as text in grey at the address bar. Once the # urlChanged signal is received, the actual url is set in black. # load_requested (app defined) carries str self.webkit.load_requested.connect( partial(self.address_bar.set_txt_color, color=QColor(128, 128, 128))) def hide_message_label(*_): """ WARNING scrollRequested carries int, int, QRect; star swallows all """ self.message_label.hide() self.webkit.page().scrollRequested.connect(hide_message_label) # focus_webkit (app defined) carries nothing self.webkit.hide_overlay.connect(self.message_label.hide) self.webkit.focus_webkit.connect(self.address_bar.restore) # progress bar self.pbar = QProgressBar(self) self.pbar.setRange(0, 100) self.pbar.setTextVisible(False) self.pbar.setVisible(False) self.pbar.setMaximumHeight(7) # search in page self.search_frame = SearchFrame(parent=self) # NAV20 # textChanged carries str self.search_frame.search_line.textChanged.connect(self.do_search) # layout grid = QGridLayout(self) grid.setSpacing(0) grid.setVerticalSpacing(0) grid.setContentsMargins(0, 0, 0, 0) grid.setRowStretch(1, 1) grid.addWidget(info_label, 0, 0, 1, 1) grid.addWidget(self.address_bar, 0, 1, 1, 1) grid.addWidget(self.nav_bar, 0, 2, 1, 1) grid.addWidget(self.webkit, 1, 0, 1, 3) grid.addWidget(self.search_frame, 2, 0, 1, 3) grid.addWidget(self.pbar, 3, 0, 1, 3) def show_search(): """ One-time callback for QShortcut NAV20 """ self.search_frame.setVisible(True) self.search_frame.search_line.setFocus() def hide_search(): """ One-time callback for QShortcut NAV20 """ self.search_frame.setVisible(False) self.webkit.findText("") self.webkit.setFocus() def navigate_completion(key=Qt.Key_Down): """ Sends an "arrow press" to the completion popup to navigate results. Not the best way to do this. It would be better to find out what function is being called by that arrow press. AB01 """ event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier) self.address_bar.completer().popup().keyPressEvent(event) # the star swallows all arguments that aren't named 'store' def reset_addressbar(*, store=False): """ Restore the address bar to its original address and color (it could have changed because of a hover event). Optionally, store the original address in the clipboard. AB03 """ if self.current['address']: self.address_bar.set_txt_color(self.current['address'], color=QColor(0, 0, 0)) if store: clipboard(self.current['address']) # urlChanged carries QUrl (ignored) self.webkit.urlChanged.connect(reset_addressbar) def enter_address_bar(clear=True): """ do not try entering the address bar if a load is in progress; do an 'stop' first AB00 """ if 'in_page_load' not in self.webkit.attr: if clear: self.address_bar.clear_and_focus() else: self.address_bar.setFocus() def cancel(): """ if we're in the middle of loading the document, stop loading. Otherwise, hide the message label. The general concept is to reach a basic state. """ if 'in_page_load' not in self.webkit.attr: self.message_label.hide() self.webkit.update() else: self.webkit.stop() set_shortcuts([ # search NAV20 ("G", self.webkit, show_search), ("Escape", self.search_frame, hide_search), ("Return", self.search_frame, self.do_search), ("Ctrl+J", self.search_frame, self.do_search), # go to page AB00 ("Ctrl+J", self.address_bar, partial(self.webkit.navigate, self.address_bar)), ("Return", self.address_bar, partial(self.webkit.navigate, self.address_bar)), # address bar interaction ("A", self.webkit, cancel), ("Ctrl+L", self.webkit, enter_address_bar), # AB00 ("Ctrl+Shift+L", self.webkit, partial(enter_address_bar, clear=False)), ("Escape", self.address_bar, self.webkit.setFocus), # AB00 ("Ctrl+I", self.address_bar, navigate_completion), # AB01 ("Ctrl+P", self.address_bar, partial(navigate_completion, Qt.Key_Up)), # in-page element navigation ("Ñ", self, self.enter_nav), # NAV11 (";", self, self.enter_nav), # DOM01 ("Ctrl+Ñ", self, partial(self.enter_nav, target="titles")), # toggle ("Q", self.webkit, self.toggle_script), # TOG01 # clipboard ("E", self, partial(reset_addressbar, store=True)) # CB05 ]) def enter_nav(self, target="links"): """ A request for access-key navigation was received; display link labels and go to the input area NAV11 """ self.webkit.make_labels(target) if self.webkit.map_tags: self.nav_bar.show() self.nav_bar.setFocus() def toggle_script(self): """ Retrieves the current javascript state for the tab and sets the opposite Callback for shortcut action TOG01 """ self.webkit.javascript(not self.webkit.javascript()) def load_progress(self, val): """ Callback for connection """ self.pbar.setValue(val) self.set_title("{}% {}".format(val, self.current['title'])) # connect (en constructor) def load_started(self): """ Callback for connection """ self.address_bar.completer().popup().close() self.search_frame.setVisible(False) self.pbar.setValue(0) self.pbar.setVisible(True) # connect (en constructor) def load_finished(self, success): """ Callback for connection """ self.webkit.navlist = [] self.pbar.setVisible(False) self.set_title(self.current['title']) if self.address_bar.hasFocus(): self.webkit.setFocus() if not success: notify("[F]") print("loadFinished: failed", self.webkit.page().mainFrame().requestedUrl()) # connect (en constructor) def save_title(self, title): """ Store a recently changed title, and display it """ if title: self.current['title'] = title self.set_title(title) def set_title(self, title): """ Go upwards to the main window's tab widget and set this tab's title """ if title is None: title = "[NO TITLE]" mainwin().tab_widget.setTabText(mainwin().tab_widget.indexOf(self), title[:40]) # connection in constructor and action def do_search(self, search=None): """ Find text on the currently loaded web page. If no text is provided, it's extracted from the search widget. NAV20 """ if search is None: search = self.search_frame.search_line.text() self.webkit.findText(search, QWebPage.FindWrapsAroundDocument)