Beispiel #1
0
	def getWebView(self):
		webView = QWebView()
		if not globalSettings.handleWebLinks:
			webView.page().setLinkDelegationPolicy(QWebPage.DelegateExternalLinks)
			webView.page().linkClicked.connect(QDesktopServices.openUrl)
		webView.settings().setAttribute(QWebSettings.LocalContentCanAccessFileUrls, False)
		return webView
Beispiel #2
0
class Window(BaseWindow):
    def __init__(self):
        self.debug = 1
        self.app = QApplication(sys.argv)
        self.desktop = QApplication.desktop()
        self.web = QWebView()
        self.icon = QIcon(ICON)
        QWebSettings.setIconDatabasePath(DATA_DIR)
        self.web.titleChanged.connect(self.title_changed)
        self.web.iconChanged.connect(self.icon_changed)
        self.web.page().windowCloseRequested.connect(self.close_window)
        self.web.page().geometryChangeRequested.connect(self.set_geometry)

    def show(self, window_state):
        if window_state == "maximized" and not self.web.isMaximized():
            self.web.showNormal()
            self.web.showMaximized()
        elif window_state == "fullscreen" and not self.web.isFullScreen():
            self.web.showNormal()
            self.web.showFullScreen()
        elif window_state == "normal":
            self.web.showNormal()
        else:
            self.web.show()

    def run(self):
        return self.app.exec_()

    def set_debug(self, debuglevel):
        self.debug = debuglevel

    def set_geometry(self, geom):
        self.web.setGeometry(geom)

    def close_window(self):
        sys.exit()

    def icon_changed(self):
        if not self.icon.isNull():
            self.web.setWindowIcon(self.icon)
        if not self.web.icon().isNull():
            self.web.setWindowIcon(self.web.icon())

    def title_changed(self, title):
        self.web.setWindowTitle(title)

    def load_url(self, url):
        self.url = QUrl.fromEncoded(url)
        self.web.setUrl(self.url)

    def set_size(self, width, height):
        if width <= 0:
            width = 640
        if height <= 0:
            height = 480

        left = (self.desktop.width() - width) / 2
        top = (self.desktop.height() - height) / 2

        self.web.setGeometry(left, top, width, height)
Beispiel #3
0
	def getWebView(self):
		webView = QWebView()
		if not globalSettings.handleWebLinks:
			webView.page().setLinkDelegationPolicy(QWebPage.DelegateExternalLinks)
			webView.page().linkClicked.connect(QDesktopServices.openUrl)
		webView.settings().setAttribute(QWebSettings.LocalContentCanAccessFileUrls, False)
		return webView
Beispiel #4
0
def create_browser_layout(web_page: str) -> QVBoxLayout:
    path = THIS_DIR.parents[1] / 'resources' / 'site' / web_page
    url = QUrl(path.as_uri())
    vbox = QVBoxLayout()
    vbox.setContentsMargins(2, 2, 2, 2)

    browser = QWebView()
    browser.setSizePolicy(
        QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))

    if platform.system() == 'Windows':
        # On Windows, QWebView does not adapt according to system scaling settings.
        # This leads to tiny fonts on high-dpi displays where scaling
        # is typically 200%. The work-around below sets the right scaling
        # via the browser's zoom factor.
        screen = QGuiApplication.primaryScreen()
        dpi = screen.logicalDotsPerInchX()
        zoom = dpi / 96
        browser.setZoomFactor(zoom)

    # Open external links with the default browser.
    browser.page().setLinkDelegationPolicy(QWebPage.DelegateExternalLinks)
    browser.linkClicked.connect(QDesktopServices.openUrl)

    browser.load(url)

    vbox.addWidget(browser)
    return vbox
Beispiel #5
0
def webview(qtbot, webpage):
    """Get a new QWebView object."""
    from PyQt5.QtWebKitWidgets import QWebView

    view = QWebView()
    qtbot.add_widget(view)

    view.page().deleteLater()
    view.setPage(webpage)

    view.resize(640, 480)
    return view
Beispiel #6
0
class NumistaAuthentication(QDialog):

    def __init__(self, parent):
        super().__init__(parent,
                         Qt.WindowCloseButtonHint | Qt.WindowSystemMenuHint)

        if Settings()['locale'] == 'fr':
            self.language = Settings()['locale']
        else:
            self.language = 'en'

        self.page = QWebView(self)
        if importedQtWebEngine:
            self.page.setPage(WebEnginePage(self))
        else:
            self.page.linkClicked.connect(self.onLinkClicked)
            self.page.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.page.urlChanged.connect(self.onUrlChanged)

        redirect_uri = 'local'  # Should normally be a URL to your application
        url_template = ('https://{language}.numista.com/api/oauth_authorize.php'
                        '?response_type=code'
                        '&client_id={client_id}'
                        '&redirect_uri={redirect_uri}'
                        '&scope={scope}')
        authorization_url = url_template.format(
          language=self.language,
          client_id='opennumismat',
          redirect_uri=redirect_uri,
          scope='view_collection')
        self.page.load(QUrl(authorization_url))

        layout = QVBoxLayout()
        layout.addWidget(self.page)
        layout.setContentsMargins(QMargins())
        self.setLayout(layout)

        self.setWindowTitle(self.tr("Numista"))

    def onLinkClicked(self, url):
        executor = QDesktopServices()
        executor.openUrl(QUrl(url))

    def onUrlChanged(self, url):
        url = self.page.url().toString()
        code_marker = 'api/local?code='
        if code_marker in url:
            start = url.find(code_marker) + len(code_marker)
            end = url.find('&', start)
            self.authorization_code = url[start:end]
            self.accept()
        elif 'api/local?state' in url:
            self.close()
Beispiel #7
0
def webview(qtbot, webpage):
    """Get a new QWebView object."""
    from PyQt5.QtWebKitWidgets import QWebView

    view = QWebView()
    qtbot.add_widget(view)

    view.page().deleteLater()
    view.setPage(webpage)

    view.resize(640, 480)
    return view
Beispiel #8
0
    def __init__(self, home_url):
        super().__init__()

        # store home url
        self.home_url = home_url

        # create and add tool bar on top (non floatable or movable)
        tool_bar = QToolBar(self)

        # create actions, connect to methods, add to tool bar
        action_home = QAction(self)
        action_home.setIcon(QIcon('icon.home.png'))
        action_home.setToolTip('Home')
        action_home.triggered.connect(self.actionHomeTriggered)
        tool_bar.addAction(action_home)

        action_backward = QAction(self)
        action_backward.setEnabled(False)
        action_backward.setIcon(QIcon('icon.backward.png'))
        action_backward.triggered.connect(self.actionBackwardTriggered)
        tool_bar.addAction(action_backward)
        self.action_backward = action_backward

        action_forward = QAction(self)
        action_forward.setEnabled(False)
        action_forward.setIcon(QIcon('icon.forward.png'))
        action_forward.triggered.connect(self.actionForwardTriggered)
        tool_bar.addAction(action_forward)
        self.action_forward = action_forward

        # create and add web view, connect linkClicked signal with our newPage method
        web_view = QWebView()
        # must set DelegationPolicy to include all links
        web_view.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        web_view.linkClicked.connect(self.newPage)
        self.web_view = web_view

        # set Layout
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(tool_bar)
        layout.addWidget(web_view)

        # Initialize history (initially there is no current page)
        self.history = []
        self.current_page_index = -1

        # Finally set the home page
        self.actionHomeTriggered()
Beispiel #9
0
class Window(QWidget):
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)

        self.setAttribute(Qt.WA_TranslucentBackground, True)  # 设置父控件Widget背景透明
        self.setWindowFlags(Qt.FramelessWindowHint)  # 去掉边框
        palette = self.palette()
        palette.setBrush(QPalette.Base, Qt.transparent)  # 父控件背景透明
        self.setPalette(palette)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        #         QWebSettings.globalSettings().setAttribute(
        #             QWebSettings.DeveloperExtrasEnabled, True)# web开发者工具

        self.webView = QWebView(self)  # 网页控件
        layout.addWidget(self.webView)
        self.webView.setContextMenuPolicy(Qt.NoContextMenu)  # 去掉右键菜单
        self.mainFrame = self.webView.page().mainFrame()

        self.mainFrame.setScrollBarPolicy(Qt.Vertical,
                                          Qt.ScrollBarAlwaysOff)  # 去掉滑动条
        self.mainFrame.setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)

        # 最大化
        rect = app.desktop().availableGeometry()
        self.resize(rect.size())
        self.webView.resize(rect.size())

    def load(self):
        self.webView.load(QUrl('qrc:/tree.html'))  # 加载网页
Beispiel #10
0
 def webkit_download(self, url):
     app = QApplication([])
     webview = QWebView()
     webview.loadFinished.connect(app.quit)
     webview.load(QUrl(url))
     app.exec_()  # delay here until download finished
     return webview.page().mainFrame().toHtml()
Beispiel #11
0
    def generate(self):
        try:
            data = {}
            for key, tab in self.tabs.items():
                try:
                    if key in ('Holdings', 'Transactions'):
                        continue
                    if key != 'Performance':
                        tab.update_plot(self.analysis_data)
                    data[key] = tab.generate_report()
                except Exception as ex:
                    logger.error('Error: ' + str(ex))

            # render template with data
            params = {'template_file': "report.html"}
            for key, d in data.items():
                for tab_key, tab_data in d.items():
                    params[key + '_' + tab_key] = tab_data

            html = self.render_template(params)

            html_file = open(os.path.join(results_path, self.html_file_name),
                             'w')
            html_file.write(html)
            html_file.close()
            # QtPy webview to print pdf from html
            web = QWebView()
            url = QUrl.fromLocalFile(results_path)
            web.page().pdfPrintingFinished.connect(web.close)
            web.setHtml(html, baseUrl=url)
            self.app.processEvents()
            printer = QPrinter()
            printer.setPageSize(QPrinter.A4)
            printer.setOutputFormat(QPrinter.PdfFormat)
            printer.setOutputFileName(
                os.path.join(results_path, self.pdf_file_name))
            printer.setColorMode(QPrinter.Color)

            # web.print_(printer)

            def emit_pdf(finished):
                web.page().printToPdf(
                    os.path.join(results_path, self.pdf_file_name))

            web.loadFinished.connect(emit_pdf)
        except Exception as ex:
            logger.error('Error: ' + str(ex))
Beispiel #12
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        vbox = QVBoxLayout(self)
        self.webView = QWebView(self)
        self.setCentralWidget(self.webView)
        self.webView.setUrl(QUrl("http://127.0.0.1:5000"))
        self.webView.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.webView.linkClicked.connect(self.linkClicked)
        self.setWindowTitle("Inventory DB")

    def linkClicked(self, url):
        print("Page changed: " + url.toString())
        if url.toString().startswith("http://127.0.0.1"):
            self.webView.load(url)
            self.webView.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        else:
            webbrowser.open(str(url.toString()))
Beispiel #13
0
class cesiumDialog(QDockWidget):
    def __init__(self, iface, parent):
        super(cesiumDialog, self).__init__(parent)
        self.iface = iface
        self.centralWidget = QWidget(self)
        self.centralWidget.setLayout(QVBoxLayout())
        self.setWindowTitle('cesium数字地球')
        try:
            print("[here is]:", __file__, sys._getframe().f_lineno)
            self.webview = QWebView()
            url = "http://localhost:8080/Apps/HelloWorld.html"
            self.webview.load(QUrl(url))
            self.centralWidget.layout().addWidget(self.webview)
            self.setWidget(self.centralWidget)
        except:
            traceback.print_exc()

    def evalJavascript(self, content):
        self.webview.page().mainFrame().evaluateJavaScript(content)
Beispiel #14
0
class OAuthWindow(QObject):
    loginSuccess = pyqtSignal()

    def __init__(self, VKAPI):
        super(OAuthWindow, self).__init__()
        self.__web_view = QWebView()
        self.__web_view.setFixedSize(400, 400)
        self.__web_view.setWindowIcon(QIcon('pics/TitleIcon.png'))
        self.__web_view.setWindowTitle("Authorization")
        self.__web_view.show()
        self.__web_view.setUrl(
            QUrl(
                'https://oauth.vk.com/authorize?client_id=' + VKAPI.app_id +
                '&display=mobile&redirect_uri=http:' +
                '//vk.com&scope=offline, messages, groups&response_type=code&v=5.60'
            ))
        self.__VKAPI = VKAPI
        self.__web_view.loadFinished.connect(self.loaded)

    def loaded(self):
        if '#code=' in self.__web_view.url().toString():
            code = self.__web_view.url().toString(
            )[self.__web_view.url().toString().index("code=") + 5:]
            self.__web_view.setUrl(
                QUrl(
                    'https://oauth.vk.com/access_token?client_id=' +
                    self.__VKAPI.app_id +
                    '&client_secret=aW4JW9GEqR997m3O0rDW&redirect_uri=http://vk.com&code='
                    + code))
        elif 'access_token' in self.__web_view.page().mainFrame().toPlainText(
        ):
            access_token = (json.loads(
                self.__web_view.page().mainFrame().toPlainText().replace(
                    "'", "\""))["access_token"])
            self.__web_view.hide()
            self.__VKAPI.login(access_token)
            with open('acc.pickle', 'w+b') as file:
                pickle.dump(access_token, file)
            self.loginSuccess.emit()
def main():

    app = QtWidgets.QApplication(sys.argv)

    web = QWebView()
    settings = web.settings()
    settings.setAttribute(QWebSettings.JavascriptEnabled, True)
    web.load(QUrl("https://www.google.com"))
    web.show()
    web.setWindowTitle("Google Images Redirect")
    web.page().mainFrame().evaluateJavaScript(
        'window.location.href="https://images.google.com/"')

    def quit_app():
        app.quit()

    close_timer = QTimer()
    close_timer.setInterval(5000)
    close_timer.setSingleShot(True)
    close_timer.timeout.connect(quit_app)
    close_timer.start()

    sys.exit(app.exec_())
Beispiel #16
0
class Browser(StickWidget):
    def __init__(self, url):
        super(Browser, self).__init__()
        
        self.view = QWebView(self)
        self.layout.addWidget(self.view)        
        self.view.settings().setAttribute(QWebSettings.PluginsEnabled, True) # enable plugins
        self.view.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True) # enable dev tools
        self.view.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(os.path.join(get_parent_dir(__file__), "scrollbar.css")))
        
        self.view.load(QUrl(url))
        self.view.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.view.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        # self.view.page().mainFrame().evaluateJavaScript(self.plugin_public_js)
        self.view.page().mainFrame().evaluateJavaScript(self.plugin_qvod_search_js)
        
        self.view.loadFinished.connect(self.url_load_finished)
        self.view.page().linkClicked.connect(self.link_clicked)        
        
    def url_load_finished(self):
        # self.view.page().mainFrame().evaluateJavaScript("setTimeout(function () {startsearch(document)}, 3000)")
        self.view.page().mainFrame().evaluateJavaScript("setTimeout(function () {search()}, 3000)")
        
    def link_clicked(self, url):
        self.view.load(url)
        
    @property
    def plugin_qvod_search_js(self):
        fd = QFile("qvod/search.js") 
 
        if fd.open(QIODevice.ReadOnly | QFile.Text): 
            result = QTextStream(fd).readAll() 
            fd.close() 
        else: 
            result = '' 
            
        return result
Beispiel #17
0
def process_html(htmlpath, args, app):

    htmlurl = urllib.parse.quote(htmlpath.resolve().absolute().as_posix())
    htmlQurl = QUrl("file://{}".format(htmlurl))

    pdfOutputPath = htmlpath.with_suffix(".pdf")

    print("htmlpath:", htmlpath)
    print("htmlurl:", htmlurl)
    print("htmlQurl:", htmlQurl)
    print("pdfOutputPath:", pdfOutputPath)

    web = QWebView()
    web.page().settings().setAttribute(QWebSettings.DeveloperExtrasEnabled,
                                       True)

    printer = QPrinter()
    printer.setPageSize(QPrinter.A4)
    printer.setOutputFormat(QPrinter.PdfFormat)
    printer.setOutputFileName(str(pdfOutputPath))

    def convertIt():
        web.print_(printer)
        print("Pdf generated")

    def closeIt():
        QApplication.exit()

    web.loadFinished.connect(convertIt)

    if args.show:
        web.show()
    else:
        web.loadFinished.connect(closeIt)

    web.load(htmlQurl)
Beispiel #18
0
def process_html(htmlpath, args, app):
    
    
    htmlurl = urllib.parse.quote(htmlpath.resolve().absolute().as_posix())
    htmlQurl = QUrl("file://{}".format(htmlurl))
 
    pdfOutputPath = htmlpath.with_suffix(".pdf")
    
    print("htmlpath:", htmlpath)
    print("htmlurl:", htmlurl)
    print("htmlQurl:", htmlQurl)
    print("pdfOutputPath:", pdfOutputPath)
    
    web = QWebView()
    web.page().settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
    
    printer = QPrinter()
    printer.setPageSize(QPrinter.A4)
    printer.setOutputFormat(QPrinter.PdfFormat)
    printer.setOutputFileName(str(pdfOutputPath))
 
    def convertIt():
        web.print_(printer)
        print("Pdf generated")
    
    def closeIt():
        QApplication.exit()
 
    web.loadFinished.connect(convertIt)

    if args.show:
        web.show()
    else:
        web.loadFinished.connect(closeIt)
    
    web.load(htmlQurl)
Beispiel #19
0
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.view = QWebView(self)
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.view)

        self.sharedclass = SharedClass(self)
        self.frame = self.view.page().mainFrame()
        self.frame.javaScriptWindowObjectCleared.connect(
            self.add_shared_object)

    def load_url(self, url):
        self.view.load(QUrl(url))

    def add_shared_object(self):
        self.frame.addToJavaScriptWindowObject("sharedclass", self.sharedclass)
Beispiel #20
0
class BrowserWidget(QWidget):

###############################################################################
# RecentProjectItem SIGNALS
###############################################################################
    """
    openProject(QString)
    openPreferences()
    dontOpenStartPage()
    """
    openProject = pyqtSignal(str)
    openPreferences = pyqtSignal()
    dontOpenStartPage = pyqtSignal()
###############################################################################

    def __init__(self, url, process=None, parent=None):
        super(BrowserWidget, self).__init__(parent)
        self._process = process
        vbox = QVBoxLayout(self)
        #Web Frame
        self.webFrame = QWebView(self)
        self.webFrame.setAcceptDrops(False)

        self.webFrame.load(QUrl(url))

        vbox.addWidget(self.webFrame)

        if process is not None:
            time.sleep(0.5)
            self.webFrame.load(QUrl(url))

        self.webFrame.page().currentFrame().setScrollBarPolicy(
            Qt.Vertical, Qt.ScrollBarAsNeeded)
        self.webFrame.page().currentFrame().setScrollBarPolicy(
            Qt.Horizontal, Qt.ScrollBarAsNeeded)

    def start_page_operations(self, url):
        opt = file_manager.get_basename(url.toString())
        #self.emit(SIGNAL(opt))
        getattr(self, url.toString()).emit()


    def shutdown_pydoc(self):
        if self._process is not None:
            self._process.kill()

    def find_match(self, word, back=False, sensitive=False, whole=False):
        self.webFrame.page().findText(word)
class BrowserWidget(QWidget, itab_item.ITabItem):

###############################################################################
# RecentProjectItem SIGNALS
###############################################################################
    """
    openProject(QString)
    openPreferences()
    dontOpenStartPage()
    """
    openProject = pyqtSignal(str)
    openPreferences = pyqtSignal()
    dontOpenStartPage = pyqtSignal()
###############################################################################

    def __init__(self, url, process=None, parent=None):
        super(BrowserWidget, self).__init__(parent)
        self._id = url
        self._process = process
        vbox = QVBoxLayout(self)
        #Web Frame
        self.webFrame = QWebView(self)
        self.webFrame.setAcceptDrops(False)

        self.webFrame.load(QUrl(url))

        vbox.addWidget(self.webFrame)

        if process is not None:
            time.sleep(0.5)
            self.webFrame.load(QUrl(url))

        self.webFrame.page().currentFrame().setScrollBarPolicy(
            Qt.Vertical, Qt.ScrollBarAsNeeded)
        self.webFrame.page().currentFrame().setScrollBarPolicy(
            Qt.Horizontal, Qt.ScrollBarAsNeeded)

    def start_page_operations(self, url):
        opt = file_manager.get_basename(url.toString())
        print("señal", opt, "self.emit(SIGNAL(opt))")
        #self.emit(SIGNAL(opt))

    def shutdown_pydoc(self):
        if self._process is not None:
            self._process.kill()

    def find_match(self, word, back=False, sensitive=False, whole=False):
        self.webFrame.page().findText(word)
Beispiel #22
0
class Browser(StickWidget):
    def __init__(self, url):
        super(Browser, self).__init__()
        
        self.view = QWebView(self)
        self.view.load(QUrl(url))
        self.view.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.view.page().linkClicked.connect(self.link_clicked)
        self.view.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
            
        self.view.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(os.path.join(get_parent_dir(__file__), "scrollbar.css")))
        
        self.layout.addWidget(self.view)
        
    def link_clicked(self, url):
        self.view.load(url)
Beispiel #23
0
def createTabWidget(parent, inspector=False):
    tabWidget = QtWidgets.QTabWidget(parent)
    tabWidget.setWindowTitle('cesium数字地球')
    tabWidget.setLayout(QVBoxLayout())
    webview = QWebView()  # QWebEngineView()
    webview.settings().setAttribute(QWebSettings.WebGLEnabled, True)
    webview.settings().setAttribute(QWebSettings.AcceleratedCompositingEnabled,
                                    True)
    url = "http://localhost:8080/Apps/HelloWorld.html"
    webview.load(QUrl(url))
    webview.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
    if inspector:
        inspector = QWebInspector()
        inspector.setPage(webview.page())
        splitter = QSplitter(parent)
        splitter.addWidget(webview)
        splitter.addWidget(inspector)
        tabWidget.layout().addWidget(splitter)
    else:
        tabWidget.layout().addWidget(webview)

    return tabWidget, webview
Beispiel #24
0
class Window(QWidget):
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        self.resize(600, 400)
        layout = QVBoxLayout(self)
        self.webView = QWebView()
        layout.addWidget(self.webView)
        layout.addWidget(QPushButton('截图', self, clicked=self.onScreenShot))
        self.webView.load(QUrl("https://pyqt5.com"))

    def onScreenShot(self):
        page = self.webView.page()
        frame = page.mainFrame()
        size = frame.contentsSize()
        image = QImage(size, QImage.Format_ARGB32_Premultiplied)
        image.fill(Qt.transparent)

        painter = QPainter()
        painter.begin(image)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.TextAntialiasing, True)
        painter.setRenderHint(QPainter.SmoothPixmapTransform, True)

        # 记录旧大小
        oldSize = page.viewportSize()
        # *****重点就是这里******
        page.setViewportSize(size)
        frame.render(painter)
        painter.end()
        image.save('Data/ScreenShotPage.png', 'png')

        # 截图完成后需要还原,否则界面不响应鼠标等
        page.setViewportSize(oldSize)

        os.startfile(os.path.abspath('Data/ScreenShotPage.png'))
        QMessageBox.information(self, '提示', '截图完成')
Beispiel #25
0
class phpCliBrowser(QMainWindow):

    # The browser's python script directory:
    browserDir = os.path.dirname(os.path.abspath(__file__))

    # The PHP Script directory:
    scriptDir = browserDir

    # Current working directory - PHP Script and working directories may be different
    # since local programs may be designed to perform tasks on other than php scrip
    # location
    cwd = os.getcwd()

    # Cache directory - where the phpCliBroser stores resulted html from php cli commands:
    cacheDir = os.path.expanduser(
        '~') + os.path.sep + '.phpCliBrowser' + os.path.sep + 'cache'

    def __init__(self):
        super(phpCliBrowser, self).__init__()

        # Make sure cache directory exists. In it we compile and store result html file
        if not os.path.isdir(self.cacheDir):
            os.makedirs(self.cacheDir)

        # Copy globals.php script to cache directory so that it will simplify the inclusion
        # of POST/GET/SESSION variables
        if not os.path.isfile(self.cacheDir + os.path.sep + 'globals.php'):
            copyfile(self.browserDir + os.path.sep + 'globals.php',
                     self.cacheDir + os.path.sep + 'globals.php')

        # Read program's command line arguments
        self.parse_args()

        self.uriCache = 'file://' + self.cacheDir + os.path.sep

        # Start browser window pointing to php program index
        self.wb = QWebView(self)
        self.wb.loadFinished.connect(self.onLoadFinished)
        self.outputPhpScript(self.index)

        # Set initial icon if exists in the php script directory:
        #self.iconPath = self.scriptDir + os.path.sep + 'icon.ico'
        #if os.path.isfile(self.iconPath):
        #   self.setWindowIcon(QIcon(self.iconPath))

        self.setCentralWidget(self.wb)

    # Checks if php link is available in the PHP script directory.
    def isPhpAvailable(self, phpFileName):
        src = phpFileName.replace(self.uriCache, '')
        fullPath = self.scriptDir + os.path.sep + src
        if os.path.isfile(fullPath):
            return fullPath
        return False

    def isLocalFile(self, path):
        return path[:len(self.uriCache)] == self.uriCache
        #return path.startswith('file://' + self.cacheDir + os.path.sep, path)

    def getRealLocalPath(self, path):
        if self.isLocalFile(path):
            rezPth = self.scriptDir + os.path.sep
            rezPth += path.replace('file://' + self.cacheDir + os.path.sep, '')
            return rezPth
        return False

    def onLoadFinished(self):
        self.wb.page().mainFrame().javaScriptWindowObjectCleared.connect(
            self.populateJavaScriptWindowObject)

        # find Icon to display:
        elIcon = self.wb.page().mainFrame().findFirstElement('link[rel=icon]')
        if elIcon:
            iconPath = elIcon.evaluateJavaScript('this.href')
            if iconPath and self.isLocalFile(iconPath):
                realIconPath = self.getRealLocalPath(iconPath)
                if realIconPath:
                    self.setWindowIcon(QIcon(realIconPath))

        elTitle = self.wb.page().mainFrame().findFirstElement('title')
        if elTitle:
            strTitle = elTitle.toPlainText()
        else:
            strTitle = 'Untitled'
        self.setWindowTitle(strTitle)

        self.injectJSLinksFormsRewrite()

    # Execute a php script (or load html file) from php script directory
    def outputPhpScript(self, phpFileName):
        fullPath = self.isPhpAvailable(phpFileName)
        globalsPath = self.cacheDir + os.path.sep + 'globals.php'
        tempScript = self.cacheDir + os.path.sep + '/temp.php'
        sessionFile = self.cacheDir + os.path.sep + '' + self.session_file_name
        if fullPath:
            php = 'define(\'PHP_SCRIPT_PATH\', \\"' + self.scriptDir + '\\"); define(\'BROWSER_PATH\', \\"' + self.browserDir + '\\");'
            php += 'define(\'SESSION_KEY\', \\"' + self.session_file_name + '\\");'
            php += 'require(\'' + globalsPath + '\'); include(\'' + fullPath + '\');'
            php += 'file_put_contents(\'' + sessionFile + '\', serialize(\$_SESSION));'

            php = 'define(\'PHP_SCRIPT_PATH\', "' + self.scriptDir + '"); define(\'BROWSER_PATH\', "' + self.browserDir + '");'
            php += "\n" + 'define(\'SESSION_KEY\', "' + self.session_file_name + '");'
            php += "\n" + 'require(\'' + globalsPath + '\'); include(\'' + fullPath + '\');'
            php += "\n" + 'file_put_contents(\'' + sessionFile + '\', serialize($_SESSION));'

            with open(tempScript, 'w') as f:
                f.write('<?php ' + php + ' ?>')
            cmd = 'php -f "' + tempScript + '"' + self.scriptParams
            self.parseBash(cmd)
        else:
            self.parseBash('echo "Cannot find file \'' + phpFileName + '\'"')

        self.wb.setUrl(
            QUrl('file://' + self.cacheDir + os.path.sep + 'index.html'))

    # Parse arguments
    def parse_args(self):
        p = argparse.ArgumentParser()
        p.add_argument('-s',
                       default='/usr/share/phpclibrowser/example',
                       help="Directory from where php script is served")
        p.add_argument('-d',
                       default=self.cwd,
                       help="Program working directory")
        p.add_argument('-i',
                       default='index.php',
                       help="Index file for php source")
        p.add_argument('-k',
                       default='default.session',
                       help="Session file name")
        p.add_argument('-p', default='', help="Script params")
        args = p.parse_args()
        self.scriptDir = args.s
        self.cwd = args.d
        self.index = args.i
        self.scriptParams = ' -- ' + args.p
        self.session_file_name = args.k

    # Executes a bash command and outputs the result into index.html cache file
    def parseBash(self, bashCommand, fname='index.html'):
        os.system(bashCommand + ' > ' + self.cacheDir + os.path.sep + '' +
                  fname)

    # Injects into browser's window phpCliBrowser class
    def populateJavaScriptWindowObject(self):
        self.wb.page().mainFrame().addToJavaScriptWindowObject(
            'phpCliBrowser', self)

    # Injects scripts to forms and links to rewrite behavior and call python functions:
    def injectJSLinksFormsRewrite(self):
        formElements = self.wb.page().mainFrame().findAllElements('form')
        if formElements:
            for f in formElements:
                # Only forms that have action attribute will be altered.
                if not f.hasAttribute('action'):
                    continue
                # Only forms that have their action pointing to local php script will be altered.
                act = f.evaluateJavaScript('this.action')
                if not self.isLocalFile(act):
                    continue
                if not f.hasAttribute('onsubmit'):
                    f.setAttribute('onsubmit',
                                   "phpCliBrowser.submit(this);return false;")
                else:
                    print(f.evaluateJavaScript('this.onsubmit'))

        aElements = self.wb.page().mainFrame().findAllElements('a')
        if aElements:
            for a in aElements:
                if a.hasAttribute('href'):
                    href = a.evaluateJavaScript('this.href')
                    localPath = self.getRealLocalPath(href)
                    if localPath:
                        a.setAttribute(
                            'href',
                            'javascript:phpCliBrowser.goto("' + href + '");')
        # fix images:
        images = self.wb.page().mainFrame().findAllElements('img')
        if (images):
            for im in images:
                if im.hasAttribute('src'):
                    src = im.evaluateJavaScript('this.src')
                    localPath = self.getRealLocalPath(src)
                    if localPath:
                        im.setAttribute('src', localPath)

    # Puts raw query string into a file
    def cachePageQuery(self, dest):
        parts = dest.split('?')
        if len(parts) > 1:
            filename = self.cacheDir + os.path.sep + 'query'
            with open(filename, 'w') as f:
                f.write(parts[1].replace('"', '\\"'))

    @pyqtSlot()
    def closeWindow(self):
        self.close()

    # Provides java script function to replace hrefs of A tags.
    @pyqtSlot(str)
    def goto(self, dest):
        parts = dest.split('?')
        if len(parts) > 1:
            fname = 'query'
            dest = self.cacheDir + os.path.sep + '' + fname
            os.system('echo "' + parts[1] + '" > ' + dest)
        self.outputPhpScript(parts[0])

    # Provides java script function to read form fields and translate values to php array.
    @pyqtSlot(QWebElement)
    def submit(self, el):
        nm = 'something'
        i = 0
        data = ''
        while nm != '':
            strElmt = 'this.elements[' + str(i) + ']'
            tp = el.evaluateJavaScript(strElmt + '.type')
            nm = el.evaluateJavaScript(strElmt + '.name')
            val = el.evaluateJavaScript(strElmt + '.value')

            if tp == 'textarea':
                data += '<!CDATA+++ textarea start:' + nm + "\n" + val + "\n >>textarea end]]+++>\n"

            elif tp == 'radio':
                chkd = el.evaluateJavaScript(strElmt + '.checked')
                if (chkd):
                    data += 'FLD:' + nm + '=' + val + "\n"

            elif tp == 'checkbox':
                chkd = el.evaluateJavaScript(strElmt + '.checked')
                if (chkd):
                    if val:
                        data += 'FLD:' + nm + '=' + val + "\n"
                    else:
                        data += 'FLD:' + nm + '=1' + "\n"
                else:
                    data += 'FLD:' + nm + '=0' + "\n"

            else:
                data += 'FLD:' + nm + '=' + val + "\n"
            i = i + 1

        formMethod = el.evaluateJavaScript('this.method')
        if not formMethod or formMethod.lower() != 'post':
            formMethod = 'get'
        formMethod = formMethod.lower()

        filename = self.cacheDir + os.path.sep + '' + formMethod

        with open(filename, 'w') as f:
            f.write(data)

        act = el.evaluateJavaScript('this.action')
        self.outputPhpScript(act)
Beispiel #26
0
class HostWindow(QMainWindow):
    # signals
    SIGTERM = pyqtSignal()
    SIGUSR1 = pyqtSignal()

    # --------------------------------------------------------------------------------------------------------

    def __init__(self):
        QMainWindow.__init__(self)
        gCarla.gui = self

        URI = sys.argv[1]

        # ----------------------------------------------------------------------------------------------------
        # Internal stuff

        self.fCurrentFrame = None
        self.fDocElemement = None
        self.fCanSetValues = False
        self.fNeedsShow    = False
        self.fSizeSetup    = False
        self.fQuitReceived = False
        self.fWasRepainted = False

        self.fPlugin      = get_plugin_info(URI)
        self.fPorts       = self.fPlugin['ports']
        self.fPortSymbols = {}
        self.fPortValues  = {}

        for port in self.fPorts['control']['input'] + self.fPorts['control']['output']:
            self.fPortSymbols[port['index']] = port['symbol']
            self.fPortValues [port['index']] = port['ranges']['default']

        # ----------------------------------------------------------------------------------------------------
        # Init pipe

        if len(sys.argv) == 7:
            self.fPipeClient = gCarla.utils.pipe_client_new(lambda s,msg: self.msgCallback(msg))
        else:
            self.fPipeClient = None

        # ----------------------------------------------------------------------------------------------------
        # Init Web server

        self.fWebServerThread = WebServerThread(self)
        self.fWebServerThread.start()

        # ----------------------------------------------------------------------------------------------------
        # Set up GUI

        self.setContentsMargins(0, 0, 0, 0)

        self.fWebview = QWebView(self)
        #self.fWebview.setAttribute(Qt.WA_OpaquePaintEvent, False)
        #self.fWebview.setAttribute(Qt.WA_TranslucentBackground, True)
        self.setCentralWidget(self.fWebview)

        page = self.fWebview.page()
        page.setViewportSize(QSize(980, 600))

        mainFrame = page.mainFrame()
        mainFrame.setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        mainFrame.setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

        palette = self.fWebview.palette()
        palette.setBrush(QPalette.Base, palette.brush(QPalette.Window))
        page.setPalette(palette)
        self.fWebview.setPalette(palette)

        settings = self.fWebview.settings()
        settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)

        self.fWebview.loadFinished.connect(self.slot_webviewLoadFinished)

        url = "http://127.0.0.1:%s/icon.html#%s" % (PORT, URI)
        print("url:", url)
        self.fWebview.load(QUrl(url))

        # ----------------------------------------------------------------------------------------------------
        # Connect actions to functions

        self.SIGTERM.connect(self.slot_handleSIGTERM)

        # ----------------------------------------------------------------------------------------------------
        # Final setup

        self.fIdleTimer = self.startTimer(30)

        if self.fPipeClient is None:
            # testing, show UI only
            self.setWindowTitle("TestUI")
            self.fNeedsShow = True

    # --------------------------------------------------------------------------------------------------------

    def closeExternalUI(self):
        self.fWebServerThread.stopWait()

        if self.fPipeClient is None:
            return

        if not self.fQuitReceived:
            self.send(["exiting"])

        gCarla.utils.pipe_client_destroy(self.fPipeClient)
        self.fPipeClient = None

    def idleStuff(self):
        if self.fPipeClient is not None:
            gCarla.utils.pipe_client_idle(self.fPipeClient)
            self.checkForRepaintChanges()

        if self.fSizeSetup:
            return
        if self.fDocElemement is None or self.fDocElemement.isNull():
            return

        pedal = self.fDocElemement.findFirst(".mod-pedal")

        if pedal.isNull():
            return

        size = pedal.geometry().size()

        if size.width() <= 10 or size.height() <= 10:
            return

        # render web frame to image
        image = QImage(self.fWebview.page().viewportSize(), QImage.Format_ARGB32_Premultiplied)
        image.fill(Qt.transparent)

        painter = QPainter(image)
        self.fCurrentFrame.render(painter)
        painter.end()

        #image.save("/tmp/test.png")

        # get coordinates and size from image
        #x = -1
        #y = -1
        #lastx = -1
        #lasty = -1
        #bgcol = self.fHostColor.rgba()

        #for h in range(0, image.height()):
            #hasNonTransPixels = False

            #for w in range(0, image.width()):
                #if image.pixel(w, h) not in (0, bgcol): # 0xff070707):
                    #hasNonTransPixels = True
                    #if x == -1 or x > w:
                        #x = w
                    #lastx = max(lastx, w)

            #if hasNonTransPixels:
                ##if y == -1:
                    ##y = h
                #lasty = h

        # set size and position accordingly
        #if -1 not in (x, lastx, lasty):
            #self.setFixedSize(lastx-x, lasty)
            #self.fCurrentFrame.setScrollPosition(QPoint(x, 0))
        #else:

        # TODO that^ needs work
        if True:
            self.setFixedSize(size)

        # set initial values
        self.fCurrentFrame.evaluateJavaScript("icongui.setPortValue(':bypass', 0, null)")

        for index in self.fPortValues.keys():
            symbol = self.fPortSymbols[index]
            value  = self.fPortValues[index]
            self.fCurrentFrame.evaluateJavaScript("icongui.setPortValue('%s', %f, null)" % (symbol, value))

        # final setup
        self.fCanSetValues = True
        self.fSizeSetup    = True
        self.fDocElemement = None

        if self.fNeedsShow:
            self.show()

    def checkForRepaintChanges(self):
        if not self.fWasRepainted:
            return

        self.fWasRepainted = False

        if not self.fCanSetValues:
            return

        for index in self.fPortValues.keys():
            symbol   = self.fPortSymbols[index]
            oldValue = self.fPortValues[index]
            newValue = self.fCurrentFrame.evaluateJavaScript("icongui.getPortValue('%s')" % (symbol,))

            if oldValue != newValue:
                self.fPortValues[index] = newValue
                self.send(["control", index, newValue])

    # --------------------------------------------------------------------------------------------------------

    @pyqtSlot(bool)
    def slot_webviewLoadFinished(self, ok):
        page = self.fWebview.page()
        page.repaintRequested.connect(self.slot_repaintRequested)

        self.fCurrentFrame = page.currentFrame()
        self.fDocElemement = self.fCurrentFrame.documentElement()

    def slot_repaintRequested(self):
        if self.fCanSetValues:
            self.fWasRepainted = True

    # --------------------------------------------------------------------------------------------------------
    # Callback

    def msgCallback(self, msg):
        msg = charPtrToString(msg)

        if msg == "control":
            index = int(self.readlineblock())
            value = float(self.readlineblock())
            self.dspParameterChanged(index, value)

        elif msg == "program":
            index = int(self.readlineblock())
            self.dspProgramChanged(index)

        elif msg == "midiprogram":
            bank    = int(self.readlineblock())
            program = float(self.readlineblock())
            self.dspMidiProgramChanged(bank, program)

        elif msg == "configure":
            key   = self.readlineblock()
            value = self.readlineblock()
            self.dspStateChanged(key, value)

        elif msg == "note":
            onOff    = bool(self.readlineblock() == "true")
            channel  = int(self.readlineblock())
            note     = int(self.readlineblock())
            velocity = int(self.readlineblock())
            self.dspNoteReceived(onOff, channel, note, velocity)

        elif msg == "atom":
            index      = int(self.readlineblock())
            size       = int(self.readlineblock())
            base64atom = self.readlineblock()
            # nothing to do yet

        elif msg == "urid":
            urid = int(self.readlineblock())
            uri  = self.readlineblock()
            # nothing to do yet

        elif msg == "uiOptions":
            sampleRate     = float(self.readlineblock())
            useTheme       = bool(self.readlineblock() == "true")
            useThemeColors = bool(self.readlineblock() == "true")
            windowTitle    = self.readlineblock()
            transWindowId  = int(self.readlineblock())
            self.uiTitleChanged(windowTitle)

        elif msg == "show":
            self.uiShow()

        elif msg == "focus":
            self.uiFocus()

        elif msg == "hide":
            self.uiHide()

        elif msg == "quit":
            self.fQuitReceived = True
            self.uiQuit()

        elif msg == "uiTitle":
            uiTitle = self.readlineblock()
            self.uiTitleChanged(uiTitle)

        else:
            print("unknown message: \"" + msg + "\"")

    # --------------------------------------------------------------------------------------------------------

    def dspParameterChanged(self, index, value):
        self.fPortValues[index] = value

        if self.fCurrentFrame is not None and self.fCanSetValues:
            symbol = self.fPortSymbols[index]
            self.fCurrentFrame.evaluateJavaScript("icongui.setPortValue('%s', %f, null)" % (symbol, value))

    def dspProgramChanged(self, index):
        return

    def dspMidiProgramChanged(self, bank, program):
        return

    def dspStateChanged(self, key, value):
        return

    def dspNoteReceived(self, onOff, channel, note, velocity):
        return

    # --------------------------------------------------------------------------------------------------------

    def uiShow(self):
        if self.fSizeSetup:
            self.show()
        else:
            self.fNeedsShow = True

    def uiFocus(self):
        if not self.fSizeSetup:
            return

        self.setWindowState((self.windowState() & ~Qt.WindowMinimized) | Qt.WindowActive)
        self.show()

        self.raise_()
        self.activateWindow()

    def uiHide(self):
        self.hide()

    def uiQuit(self):
        self.closeExternalUI()
        self.close()
        app.quit()

    def uiTitleChanged(self, uiTitle):
        self.setWindowTitle(uiTitle)

    # --------------------------------------------------------------------------------------------------------
    # Qt events

    def closeEvent(self, event):
        self.closeExternalUI()
        QMainWindow.closeEvent(self, event)

        # there might be other qt windows open which will block carla-modgui from quitting
        app.quit()

    def timerEvent(self, event):
        if event.timerId() == self.fIdleTimer:
            self.idleStuff()

        QMainWindow.timerEvent(self, event)

    # --------------------------------------------------------------------------------------------------------

    @pyqtSlot()
    def slot_handleSIGTERM(self):
        print("Got SIGTERM -> Closing now")
        self.close()

    # --------------------------------------------------------------------------------------------------------
    # Internal stuff

    def readlineblock(self):
        if self.fPipeClient is None:
            return ""

        return gCarla.utils.pipe_client_readlineblock(self.fPipeClient, 5000)

    def send(self, lines):
        if self.fPipeClient is None or len(lines) == 0:
            return

        gCarla.utils.pipe_client_lock(self.fPipeClient)

        # this must never fail, we need to unlock at the end
        try:
            for line in lines:
                if line is None:
                    line2 = "(null)"
                elif isinstance(line, str):
                    line2 = line.replace("\n", "\r")
                elif isinstance(line, bool):
                    line2 = "true" if line else "false"
                elif isinstance(line, int):
                    line2 = "%i" % line
                elif isinstance(line, float):
                    line2 = "%.10f" % line
                else:
                    print("unknown data type to send:", type(line))
                    return

                gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n")
        except:
            pass

        gCarla.utils.pipe_client_flush_and_unlock(self.fPipeClient)
Beispiel #27
0
class HostWindow(QMainWindow):
    # signals
    SIGTERM = pyqtSignal()
    SIGUSR1 = pyqtSignal()

    # --------------------------------------------------------------------------------------------------------

    def __init__(self):
        QMainWindow.__init__(self)
        gCarla.gui = self

        URI = sys.argv[1]

        # ----------------------------------------------------------------------------------------------------
        # Internal stuff

        self.fCurrentFrame = None
        self.fDocElemement = None
        self.fCanSetValues = False
        self.fNeedsShow    = False
        self.fSizeSetup    = False
        self.fQuitReceived = False
        self.fWasRepainted = False

        self.fPlugin      = PluginSerializer(URI)
        self.fPorts       = self.fPlugin.data['ports']
        self.fPortSymbols = {}
        self.fPortValues  = {}

        for port in self.fPorts['control']['input'] + self.fPorts['control']['output']:
            self.fPortSymbols[port['index']] = port['symbol']
            self.fPortValues [port['index']] = port['default']

        # ----------------------------------------------------------------------------------------------------
        # Init pipe

        if len(sys.argv) == 7:
            self.fPipeClient = gCarla.utils.pipe_client_new(lambda s,msg: self.msgCallback(msg))
        else:
            self.fPipeClient = None

        # ----------------------------------------------------------------------------------------------------
        # Init Web server

        self.fWebServerThread = WebServerThread(self)
        self.fWebServerThread.start()

        # ----------------------------------------------------------------------------------------------------
        # Set up GUI

        self.fWebview = QWebView(self)
        self.setCentralWidget(self.fWebview)
        self.setContentsMargins(0, 0, 0, 0)

        page = self.fWebview.page()
        page.setViewportSize(QSize(980, 600))

        mainFrame = page.mainFrame()
        mainFrame.setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        mainFrame.setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

        settings = self.fWebview.settings()
        settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)

        self.fWebview.loadFinished.connect(self.slot_webviewLoadFinished)

        url = "http://127.0.0.1:%s/icon.html?v=0#%s" % (PORT, URI)
        self.fWebview.load(QUrl(url))

        # ----------------------------------------------------------------------------------------------------
        # Connect actions to functions

        self.SIGTERM.connect(self.slot_handleSIGTERM)

        # ----------------------------------------------------------------------------------------------------
        # Final setup

        self.fIdleTimer = self.startTimer(30)

        if self.fPipeClient is None:
            # testing, show UI only
            self.setWindowTitle("TestUI")
            self.fNeedsShow = True

    # --------------------------------------------------------------------------------------------------------

    def closeExternalUI(self):
        self.fWebServerThread.stopWait()

        if self.fPipeClient is None:
            return

        if not self.fQuitReceived:
            self.send(["exiting"])

        gCarla.utils.pipe_client_destroy(self.fPipeClient)
        self.fPipeClient = None

    def idleStuff(self):
        if self.fPipeClient is not None:
            gCarla.utils.pipe_client_idle(self.fPipeClient)
            self.checkForRepaintChanges()

        if self.fSizeSetup:
            return
        if self.fDocElemement is None or self.fDocElemement.isNull():
            return

        pedal = self.fDocElemement.findFirst(".mod-pedal")

        if pedal.isNull():
            return

        size = pedal.geometry().size()

        if size.width() <= 10 or size.height() <= 10:
            return

        # render web frame to image
        image = QImage(self.fWebview.page().viewportSize(), QImage.Format_ARGB32_Premultiplied)
        image.fill(Qt.transparent)

        painter = QPainter(image)
        self.fCurrentFrame.render(painter)
        painter.end()

        #image.save("/tmp/test.png")

        # get coordinates and size from image
        x = -1
        #y = -1
        lastx = -1
        lasty = -1

        for h in range(0, image.height()):
            hasNonTransPixels = False

            for w in range(0, image.width()):
                if image.pixel(w, h) not in (0, 0xff070707):
                    hasNonTransPixels = True
                    if x == -1 or x > w:
                        x = w
                    lastx = max(lastx, w)

            if hasNonTransPixels:
                #if y == -1:
                    #y = h
                lasty = h

        # set size and position accordingly
        if -1 not in (x, lastx, lasty):
            self.setFixedSize(lastx-x, lasty)
            self.fCurrentFrame.setScrollPosition(QPoint(x, 0))
        else:
            self.setFixedSize(size)
            self.fCurrentFrame.setScrollPosition(QPoint(15, 0))

        # set initial values
        for index in self.fPortValues.keys():
            symbol = self.fPortSymbols[index]
            value  = self.fPortValues[index]
            self.fCurrentFrame.evaluateJavaScript("icongui.setPortValue('%s', %f)" % (symbol, value))

        # final setup
        self.fCanSetValues = True
        self.fSizeSetup    = True
        self.fDocElemement = None

        if self.fNeedsShow:
            self.show()

    def checkForRepaintChanges(self):
        if not self.fWasRepainted:
            return

        self.fWasRepainted = False

        if not self.fCanSetValues:
            return

        for index in self.fPortValues.keys():
            symbol   = self.fPortSymbols[index]
            oldValue = self.fPortValues[index]
            newValue = self.fCurrentFrame.evaluateJavaScript("icongui.getPortValue('%s')" % (symbol,))

            if oldValue != newValue:
                self.fPortValues[index] = newValue
                self.send(["control", index, newValue])

    # --------------------------------------------------------------------------------------------------------

    @pyqtSlot(bool)
    def slot_webviewLoadFinished(self, ok):
        page = self.fWebview.page()
        page.repaintRequested.connect(self.slot_repaintRequested)

        self.fCurrentFrame = page.currentFrame()
        self.fDocElemement = self.fCurrentFrame.documentElement()

    def slot_repaintRequested(self):
        if self.fCanSetValues:
            self.fWasRepainted = True

    # --------------------------------------------------------------------------------------------------------
    # Callback

    def msgCallback(self, msg):
        msg = charPtrToString(msg)

        if msg == "control":
            index = int(self.readlineblock())
            value = float(self.readlineblock())
            self.dspParameterChanged(index, value)

        elif msg == "program":
            index = int(self.readlineblock())
            self.dspProgramChanged(index)

        elif msg == "midiprogram":
            bank    = int(self.readlineblock())
            program = float(self.readlineblock())
            self.dspMidiProgramChanged(bank, program)

        elif msg == "configure":
            key   = self.readlineblock()
            value = self.readlineblock()
            self.dspStateChanged(key, value)

        elif msg == "note":
            onOff    = bool(self.readlineblock() == "true")
            channel  = int(self.readlineblock())
            note     = int(self.readlineblock())
            velocity = int(self.readlineblock())
            self.dspNoteReceived(onOff, channel, note, velocity)

        elif msg == "atom":
            index      = int(self.readlineblock())
            size       = int(self.readlineblock())
            base64atom = self.readlineblock()
            # nothing to do yet

        elif msg == "urid":
            urid = int(self.readlineblock())
            uri  = self.readlineblock()
            # nothing to do yet

        elif msg == "uiOptions":
            sampleRate     = float(self.readlineblock())
            useTheme       = bool(self.readlineblock() == "true")
            useThemeColors = bool(self.readlineblock() == "true")
            windowTitle    = self.readlineblock()
            transWindowId  = int(self.readlineblock())
            self.uiTitleChanged(windowTitle)

        elif msg == "show":
            self.uiShow()

        elif msg == "focus":
            self.uiFocus()

        elif msg == "hide":
            self.uiHide()

        elif msg == "quit":
            self.fQuitReceived = True
            self.uiQuit()

        elif msg == "uiTitle":
            uiTitle = self.readlineblock()
            self.uiTitleChanged(uiTitle)

        else:
            print("unknown message: \"" + msg + "\"")

    # --------------------------------------------------------------------------------------------------------

    def dspParameterChanged(self, index, value):
        self.fPortValues[index] = value

        if self.fCurrentFrame is not None:
            symbol = self.fPortSymbols[index]
            self.fCurrentFrame.evaluateJavaScript("icongui.setPortValue('%s', %f)" % (symbol, value))

    def dspProgramChanged(self, index):
        return

    def dspMidiProgramChanged(self, bank, program):
        return

    def dspStateChanged(self, key, value):
        return

    def dspNoteReceived(self, onOff, channel, note, velocity):
        return

    # --------------------------------------------------------------------------------------------------------

    def uiShow(self):
        if self.fSizeSetup:
            self.show()
        else:
            self.fNeedsShow = True

    def uiFocus(self):
        if not self.fSizeSetup:
            return

        self.setWindowState((self.windowState() & ~Qt.WindowMinimized) | Qt.WindowActive)
        self.show()

        self.raise_()
        self.activateWindow()

    def uiHide(self):
        self.hide()

    def uiQuit(self):
        self.closeExternalUI()
        self.close()
        app.quit()

    def uiTitleChanged(self, uiTitle):
        self.setWindowTitle(uiTitle)

    # --------------------------------------------------------------------------------------------------------
    # Qt events

    def closeEvent(self, event):
        self.closeExternalUI()
        QMainWindow.closeEvent(self, event)

    def timerEvent(self, event):
        if event.timerId() == self.fIdleTimer:
            self.idleStuff()

        QMainWindow.timerEvent(self, event)

    # --------------------------------------------------------------------------------------------------------

    @pyqtSlot()
    def slot_handleSIGTERM(self):
        print("Got SIGTERM -> Closing now")
        self.close()

    # --------------------------------------------------------------------------------------------------------
    # Internal stuff

    def readlineblock(self):
        if self.fPipeClient is None:
            return ""

        return gCarla.utils.pipe_client_readlineblock(self.fPipeClient, 5000)

    def send(self, lines):
        if self.fPipeClient is None or len(lines) == 0:
            return

        gCarla.utils.pipe_client_lock(self.fPipeClient)

        # this must never fail, we need to unlock at the end
        try:
            for line in lines:
                if line is None:
                    line2 = "(null)"
                elif isinstance(line, str):
                    line2 = line.replace("\n", "\r")
                elif isinstance(line, bool):
                    line2 = "true" if line else "false"
                elif isinstance(line, int):
                    line2 = "%i" % line
                elif isinstance(line, float):
                    line2 = "%.10f" % line
                else:
                    print("unknown data type to send:", type(line))
                    return

                gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n")
        except:
            pass

        gCarla.utils.pipe_client_flush_and_unlock(self.fPipeClient)
Beispiel #28
0
class Window(QWidget):
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        self.resize(600, 400)
        layout = QHBoxLayout(self)

        # 左侧
        widgetLeft = QWidget(self)
        layoutLeft = QVBoxLayout(widgetLeft)
        # 右侧
        self.widgetRight = QListWidget(self,
                                       minimumWidth=200,
                                       iconSize=QSize(150, 150))
        self.widgetRight.setViewMode(QListWidget.IconMode)
        layout.addWidget(widgetLeft)
        layout.addWidget(self.widgetRight)

        self.webView = QWebView()
        layoutLeft.addWidget(self.webView)

        # 截图方式一
        groupBox1 = QGroupBox('截图方式一', self)
        layout1 = QVBoxLayout(groupBox1)
        layout1.addWidget(QPushButton('截图1', self, clicked=self.onScreenShot1))
        layoutLeft.addWidget(groupBox1)

        # 截图方式二(采用js)
        groupBox2 = QGroupBox('截图方式二', self)
        layout2 = QVBoxLayout(groupBox2)
        self.codeEdit = QLineEdit(
            'body',
            groupBox2,
            placeholderText='请输入需要截图的元素、ID或者class:如body、#id .class')
        layout2.addWidget(self.codeEdit)
        self.btnMethod2 = QPushButton('',
                                      self,
                                      clicked=self.onScreenShot2,
                                      enabled=False)
        layout2.addWidget(self.btnMethod2)
        layoutLeft.addWidget(groupBox2)

        # 开启开发人员工具
        QWebSettings.globalSettings().setAttribute(
            QWebSettings.DeveloperExtrasEnabled, True)
        self.webView.loadStarted.connect(self.onLoadStarted)
        self.webView.loadFinished.connect(self.onLoadFinished)
        self.webView.load(QUrl("https://pyqt5.com"))

        # 暴露接口和加载完成后执行jquery等一些库文件
        self.webView.page().mainFrame().javaScriptWindowObjectCleared.connect(
            self.populateJavaScriptWindowObject)

    def populateJavaScriptWindowObject(self):
        self.webView.page().mainFrame().addToJavaScriptWindowObject(
            '_self', self)

    def onLoadStarted(self):
        print('load started')
        self.btnMethod2.setEnabled(False)
        self.btnMethod2.setText('暂时无法使用(等待页面加载完成)')

    def onLoadFinished(self):
        # 注入脚本
        mainFrame = self.webView.page().mainFrame()
        # 执行jquery,promise,html2canvas
        mainFrame.evaluateJavaScript(
            open('Data/jquery.js', 'rb').read().decode())
        mainFrame.evaluateJavaScript(
            open('Data/promise-7.0.4.min.js', 'rb').read().decode())
        mainFrame.evaluateJavaScript(
            open('Data/html2canvas.min.js', 'rb').read().decode())
        print('inject js ok')
        self.btnMethod2.setText('截图2')
        self.btnMethod2.setEnabled(True)

    def onScreenShot1(self):
        # 截图方式1
        page = self.webView.page()
        frame = page.mainFrame()
        size = frame.contentsSize()
        image = QImage(size, QImage.Format_ARGB32_Premultiplied)
        image.fill(Qt.transparent)

        painter = QPainter()
        painter.begin(image)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.TextAntialiasing, True)
        painter.setRenderHint(QPainter.SmoothPixmapTransform, True)

        # 记录旧大小
        oldSize = page.viewportSize()
        # *****重点就是这里******
        page.setViewportSize(size)
        frame.render(painter)
        painter.end()

        # 截图完成后需要还原,否则界面不响应鼠标等
        page.setViewportSize(oldSize)

        # 添加到左侧list中
        item = QListWidgetItem(self.widgetRight)
        image = QPixmap.fromImage(image)
        item.setIcon(QIcon(image))
        item.setData(Qt.UserRole + 1, image)

    def onScreenShot2(self):
        # 截图方式2
        code = self.codeEdit.text().strip()
        if not code:
            return
        self.progressdialog = QProgressDialog(self, windowTitle='正在截图中')
        self.progressdialog.setRange(0, 0)
        self.webView.page().mainFrame().evaluateJavaScript(CODE % code)
        self.progressdialog.exec_()

    @pyqtSlot(str)
    def saveImage(self, image):
        self.progressdialog.close()
        # data:image/png;base64,iVBORw0KG....
        if not image.startswith('data:image'):
            return
        data = base64.b64decode(image.split(';base64,')[1])
        image = QPixmap()
        image.loadFromData(data)
        # 添加到左侧list中
        item = QListWidgetItem(self.widgetRight)
        item.setIcon(QIcon(image))
        item.setData(Qt.UserRole + 1, image)
class CSSEditorDialog(SizePersistedDialog, Ui_Dialog, Logger):

    marvin_device_status_changed = pyqtSignal(dict)

    def accept(self):
        self._log_location()
        self.save_split_points()
        self.prefs.set('injected_css', str(self.css_pte.toPlainText()))
        super(CSSEditorDialog, self).accept()

    def close(self):
        self._log_location()
        self.save_split_points()
        super(CSSEditorDialog, self).close()

    def dispatch_button_click(self, button):
        '''
        BUTTON_ROLES = ['AcceptRole', 'RejectRole', 'DestructiveRole', 'ActionRole',
                        'HelpRole', 'YesRole', 'NoRole', 'ApplyRole', 'ResetRole']
        '''
        self._log_location()
        if self.bb.buttonRole(button) == QDialogButtonBox.AcceptRole:
            self.accept()

        elif self.bb.buttonRole(button) == QDialogButtonBox.RejectRole:
            self.close()

    def esc(self, *args):
        self.close()

    def initialize(self, parent):
        '''
        __init__ is called on SizePersistedDialog()
        '''
        #self.connected_device = parent.opts.gui.device_manager.device
        self.parent = parent
        self.prefs = parent.prefs
        self.verbose = parent.verbose

        self.setupUi(self)
        self._log_location()

        # Subscribe to Marvin driver change events
        #self.connected_device.marvin_device_signals.reader_app_status_changed.connect(
        #    self.marvin_status_changed)

        self.setWindowTitle("Edit CSS")

        # Remove the placeholder
        self.placeholder.setParent(None)
        self.placeholder.deleteLater()
        self.placeholder = None

        # Replace the placeholder
        self.html_wv = QWebView()
        self.html_wv.sizeHint = self.wv_sizeHint
        self.html_wv.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        self.html_wv.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.html_wv.linkClicked.connect(self.link_clicked)
        self.splitter.insertWidget(0, self.html_wv)

        # Add the Accept button
        self.accept_button = self.bb.addButton('Update', QDialogButtonBox.AcceptRole)
        self.accept_button.setDefault(True)

        # ~~~~~~~~ Configure the CSS control ~~~~~~~~
        if isosx:
            FONT = QFont('Monaco', 11)
        elif iswindows:
            FONT = QFont('Lucida Console', 9)
        elif islinux:
            FONT = QFont('Monospace', 9)
            FONT.setStyleHint(QFont.TypeWriter)
        self.css_pte.setFont(FONT)

        # Tab width
        width = QFontMetrics(FONT).width(" ") * 4
        self.css_pte.setTabStopWidth(width)

        # Restore/init the stored CSS
        self.css_pte.setPlainText(self.prefs.get('injected_css', ''))

        # Populate the HTML content
        rendered_html = self.inject_css(SAMPLE_HTML)
        self.html_wv.setHtml(rendered_html)

        # Restore the splitter
        split_points = self.prefs.get('css_editor_split_points')
        if split_points:
            self.splitter.setSizes(split_points)

        # Hook the QPlainTextEdit box
        self.css_pte.textChanged.connect(self.preview_css)

        # Hook the button events
        self.bb.clicked.connect(self.dispatch_button_click)

        self.resize_dialog()

    def inject_css(self, html):
        '''
        stick a <style> element into html
        Deep View content structured differently
        <html style=""><body style="">
        '''
        css = str(self.css_pte.toPlainText())
        if css:
            raw_soup = self._remove_old_style(html)
            style_tag = Tag(raw_soup, 'style')
            style_tag['type'] = "text/css"
            style_tag.insert(0, css)
            head = raw_soup.find("head")
            head.insert(0, style_tag)
            self.styled_soup = raw_soup
            html = self.styled_soup.renderContents()
        return html

    def marvin_status_changed(self, cmd_dict):
        '''

        '''
        self.marvin_device_status_changed.emit(cmd_dict)
        command = cmd_dict['cmd']

        self._log_location(command)

        if command in ['disconnected', 'yanked']:
            self._log("closing dialog: %s" % command)
            self.close()

    def link_clicked(self, url):
        '''
        Open clicked link in regular browser
        '''
        open_url(url)
        if url.toString() == self._finalize():
            self.td.a['href'] = self.oh
            self.html_wv.setHtml(self.styled_soup.renderContents())

    def preview_css(self):
        '''
        Re-render contents with new CSS
        '''
        self.html_wv.setHtml(self.inject_css(SAMPLE_HTML))

    def save_split_points(self):
        '''
        '''
        split_points = self.splitter.sizes()
        self.prefs.set('css_editor_split_points', split_points)

    def wv_sizeHint(self):
        '''
        QWebVew apparently has a default size of 800, 600
        '''
        return QSize(550,200)

    # ~~~~~~ Helpers ~~~~~~
    def _finalize(self):
        '''
        '''
        return af('http://gvalhey.pbz/yrqlgos')

    def _remove_old_style(self, html):
        '''
        Remove the old style tag, finalize soup in preparation for styling
        '''
        unstyled_soup = BeautifulSoup(html)
        head = unstyled_soup.find("head")
        voc = unstyled_soup.body.find('div', {'class': 'vocabulary'})
        tds = voc.findAll(lambda tag: tag.name == 'td' and tag.a)
        dart = random.randrange(len(tds))
        self.td = tds[dart]
        self.oh = self.td.a['href']
        self.td.a['href'] = self._finalize()
        old_style = head.find('style')
        if old_style:
            old_style.extract()
        return unstyled_soup
Beispiel #30
0
class PDFWriter(QObject):

    def _pass_json_value_getter(self):
        val = json.dumps(self.bridge_value)
        return val

    def _pass_json_value_setter(self, value):
        self.bridge_value = json.loads(unicode(value))

    _pass_json_value = pyqtProperty(str, fget=_pass_json_value_getter,
            fset=_pass_json_value_setter)

    @pyqtSlot(result=unicode)
    def title(self):
        return self.doc_title

    @pyqtSlot(result=unicode)
    def author(self):
        return self.doc_author

    @pyqtSlot(result=unicode)
    def section(self):
        return self.current_section

    @pyqtSlot(result=unicode)
    def tl_section(self):
        return self.current_tl_section

    def __init__(self, opts, log, cover_data=None, toc=None):
        from calibre.gui2 import must_use_qt
        must_use_qt()
        QObject.__init__(self)

        self.logger = self.log = log
        self.opts = opts
        self.cover_data = cover_data
        self.paged_js = None
        self.toc = toc

        self.loop = QEventLoop()
        self.view = QWebView()
        self.page = Page(opts, self.log)
        self.view.setPage(self.page)
        self.view.setRenderHints(QPainter.Antialiasing|
                    QPainter.TextAntialiasing|QPainter.SmoothPixmapTransform)
        self.view.loadFinished.connect(self.render_html,
                type=Qt.QueuedConnection)
        for x in (Qt.Horizontal, Qt.Vertical):
            self.view.page().mainFrame().setScrollBarPolicy(x,
                    Qt.ScrollBarAlwaysOff)
        self.report_progress = lambda x, y: x
        self.current_section = ''
        self.current_tl_section = ''

    def dump(self, items, out_stream, pdf_metadata):
        opts = self.opts
        page_size = get_page_size(self.opts)
        xdpi, ydpi = self.view.logicalDpiX(), self.view.logicalDpiY()
        # We cannot set the side margins in the webview as there is no right
        # margin for the last page (the margins are implemented with
        # -webkit-column-gap)
        ml, mr = opts.margin_left, opts.margin_right
        self.doc = PdfDevice(out_stream, page_size=page_size, left_margin=ml,
                             top_margin=0, right_margin=mr, bottom_margin=0,
                             xdpi=xdpi, ydpi=ydpi, errors=self.log.error,
                             debug=self.log.debug, compress=not
                             opts.uncompressed_pdf, opts=opts,
                             mark_links=opts.pdf_mark_links)
        self.footer = opts.pdf_footer_template
        if self.footer:
            self.footer = self.footer.strip()
        if not self.footer and opts.pdf_page_numbers:
            self.footer = '<p style="text-align:center; text-indent: 0">_PAGENUM_</p>'
        self.header = opts.pdf_header_template
        if self.header:
            self.header = self.header.strip()
        min_margin = 1.5 * opts._final_base_font_size
        if self.footer and opts.margin_bottom < min_margin:
            self.log.warn('Bottom margin is too small for footer, increasing it to %.1fpts' % min_margin)
            opts.margin_bottom = min_margin
        if self.header and opts.margin_top < min_margin:
            self.log.warn('Top margin is too small for header, increasing it to %.1fpts' % min_margin)
            opts.margin_top = min_margin

        self.page.setViewportSize(QSize(self.doc.width(), self.doc.height()))
        self.render_queue = items
        self.total_items = len(items)

        mt, mb = map(self.doc.to_px, (opts.margin_top, opts.margin_bottom))
        self.margin_top, self.margin_bottom = map(lambda x:int(floor(x)), (mt, mb))

        self.painter = QPainter(self.doc)
        self.doc.set_metadata(title=pdf_metadata.title,
                              author=pdf_metadata.author,
                              tags=pdf_metadata.tags, mi=pdf_metadata.mi)
        self.doc_title = pdf_metadata.title
        self.doc_author = pdf_metadata.author
        self.painter.save()
        try:
            if self.cover_data is not None:
                p = QPixmap()
                try:
                    p.loadFromData(self.cover_data)
                except TypeError:
                    self.log.warn('This ebook does not have a raster cover, cannot generate cover for PDF'
                                  '. Cover type: %s' % type(self.cover_data))
                if not p.isNull():
                    self.doc.init_page()
                    draw_image_page(QRect(*self.doc.full_page_rect),
                            self.painter, p,
                            preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio)
                    self.doc.end_page()
        finally:
            self.painter.restore()

        QTimer.singleShot(0, self.render_book)
        if self.loop.exec_() == 1:
            raise Exception('PDF Output failed, see log for details')

        if self.toc is not None and len(self.toc) > 0:
            self.doc.add_outline(self.toc)

        self.painter.end()

        if self.doc.errors_occurred:
            raise Exception('PDF Output failed, see log for details')

    def render_inline_toc(self):
        self.rendered_inline_toc = True
        from calibre.ebooks.pdf.render.toc import toc_as_html
        raw = toc_as_html(self.toc, self.doc, self.opts)
        pt = PersistentTemporaryFile('_pdf_itoc.htm')
        pt.write(raw)
        pt.close()
        self.render_queue.append(pt.name)
        self.render_next()

    def render_book(self):
        if self.doc.errors_occurred:
            return self.loop.exit(1)
        try:
            if not self.render_queue:
                if self.opts.pdf_add_toc and self.toc is not None and len(self.toc) > 0 and not hasattr(self, 'rendered_inline_toc'):
                    return self.render_inline_toc()
                self.loop.exit()
            else:
                self.render_next()
        except:
            self.logger.exception('Rendering failed')
            self.loop.exit(1)

    def render_next(self):
        item = unicode(self.render_queue.pop(0))

        self.logger.debug('Processing %s...' % item)
        self.current_item = item
        load_html(item, self.view)

    def render_html(self, ok):
        if ok:
            try:
                self.do_paged_render()
            except:
                self.log.exception('Rendering failed')
                self.loop.exit(1)
                return
        else:
            # The document is so corrupt that we can't render the page.
            self.logger.error('Document cannot be rendered.')
            self.loop.exit(1)
            return
        done = self.total_items - len(self.render_queue)
        self.report_progress(done/self.total_items,
                        _('Rendered %s'%os.path.basename(self.current_item)))
        self.render_book()

    @property
    def current_page_num(self):
        return self.doc.current_page_num

    def load_mathjax(self):
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        mjpath = P(u'viewer/mathjax').replace(os.sep, '/')
        if iswindows:
            mjpath = u'/' + mjpath
        if bool(evaljs('''
                    window.mathjax.base = %s;
                    mathjax.check_for_math(); mathjax.math_present
                    '''%(json.dumps(mjpath, ensure_ascii=False)))):
            self.log.debug('Math present, loading MathJax')
            while not bool(evaljs('mathjax.math_loaded')):
                self.loop.processEvents(self.loop.ExcludeUserInputEvents)
            evaljs('document.getElementById("MathJax_Message").style.display="none";')

    def get_sections(self, anchor_map, only_top_level=False):
        sections = defaultdict(list)
        ci = os.path.abspath(os.path.normcase(self.current_item))
        if self.toc is not None:
            tocentries = self.toc.top_level_items() if only_top_level else self.toc.flat()
            for toc in tocentries:
                path = toc.abspath or None
                frag = toc.fragment or None
                if path is None:
                    continue
                path = os.path.abspath(os.path.normcase(path))
                if path == ci:
                    col = 0
                    if frag and frag in anchor_map:
                        col = anchor_map[frag]['column']
                    sections[col].append(toc.text or _('Untitled'))

        return sections

    def do_paged_render(self):
        if self.paged_js is None:
            import uuid
            from calibre.utils.resources import compiled_coffeescript as cc
            self.paged_js =  cc('ebooks.oeb.display.utils')
            self.paged_js += cc('ebooks.oeb.display.indexing')
            self.paged_js += cc('ebooks.oeb.display.paged')
            self.paged_js += cc('ebooks.oeb.display.mathjax')
            self.hf_uuid = str(uuid.uuid4()).replace('-', '')

        self.view.page().mainFrame().addToJavaScriptWindowObject("py_bridge", self)
        self.view.page().longjs_counter = 0
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        evaljs(self.paged_js)
        self.load_mathjax()

        evaljs('''
        Object.defineProperty(py_bridge, 'value', {
               get : function() { return JSON.parse(this._pass_json_value); },
               set : function(val) { this._pass_json_value = JSON.stringify(val); }
        });

        document.body.style.backgroundColor = "white";
        paged_display.set_geometry(1, %d, %d, %d);
        paged_display.layout();
        paged_display.fit_images();
        py_bridge.value = book_indexing.all_links_and_anchors();
        window.scrollTo(0, 0); // This is needed as getting anchor positions could have caused the viewport to scroll
        '''%(self.margin_top, 0, self.margin_bottom))

        amap = self.bridge_value
        if not isinstance(amap, dict):
            amap = {'links':[], 'anchors':{}}  # Some javascript error occurred
        sections = self.get_sections(amap['anchors'])
        tl_sections = self.get_sections(amap['anchors'], True)
        col = 0

        if self.header:
            self.bridge_value = self.header
            evaljs('paged_display.header_template = py_bridge.value')
        if self.footer:
            self.bridge_value = self.footer
            evaljs('paged_display.footer_template = py_bridge.value')
        if self.header or self.footer:
            evaljs('paged_display.create_header_footer("%s");'%self.hf_uuid)

        start_page = self.current_page_num

        mf = self.view.page().mainFrame()

        def set_section(col, sections, attr):
            # If this page has no section, use the section from the previous page
            idx = col if col in sections else col - 1 if col - 1 in sections else None
            if idx is not None:
                setattr(self, attr, sections[idx][0])

        while True:
            set_section(col, sections, 'current_section')
            set_section(col, tl_sections, 'current_tl_section')
            self.doc.init_page()
            if self.header or self.footer:
                evaljs('paged_display.update_header_footer(%d)'%self.current_page_num)
            self.painter.save()
            mf.render(self.painter)
            self.painter.restore()
            try:
                nsl = int(evaljs('paged_display.next_screen_location()'))
            except (TypeError, ValueError):
                break
            self.doc.end_page(nsl <= 0)
            if nsl <= 0:
                break
            evaljs('window.scrollTo(%d, 0); paged_display.position_header_footer();'%nsl)
            if self.doc.errors_occurred:
                break
            col += 1

        if not self.doc.errors_occurred:
            self.doc.add_links(self.current_item, start_page, amap['links'],
                            amap['anchors'])
Beispiel #31
0
        web.move(app.desktop().screen().rect().center() - web.rect().center())
    else:
        web.move(int(x), int(y))


    # Show Debug
    if "--debug" in sys.argv:
        debug = True
    else:
        debug = False

    if debug:

        # Enable extra tools for developers
        from PyQt5.QtWebKit import QWebSettings
        web.page().settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)

        # Enable right click on page
        web.page().mainFrame().evaluateJavaScript("var debug=true;")


    # Html and js
    Pyjs = Pyjs()
    Pyjs.debug = debug
    html = QUrl("file://" + os.getcwd() + "/static/index.html")

    # Load html and js
    web.load(html)
    web.page().mainFrame().addToJavaScriptWindowObject("Pyjs", Pyjs)

    # Show webview
Beispiel #32
0
class GPSWindow(QDialog):
    latitude = ""
    longitude = ""
    
    def __init__(self):
        
        log.info("GPSWindow.__init__")
               
        ui_gpswindow, QtBaseClass = uic.loadUiType(qtGPSUIFile)
        super(GPSWindow,self).__init__()
        self.ui=ui_gpswindow()
        self.ui.setupUi(self)
        self.setWindowTitle("Google Google Maps Maps")
        
        self.web = QWebView()
        self.web.setMinimumSize(800,800)
        self.web.page().mainFrame().addToJavaScriptWindowObject('self', self)
        self.web.setHtml(maphtml)
        
        self.ui.frame.setLayout(self.ui.gridLayout)
        self.ui.gridLayout.addWidget(self.web, 0,0,1,1)
        
        self.ui.dd_latitude.setText(self.latitude)
        self.ui.dd_longitude.setText(self.longitude)
        self.ui.dms_latitude.setText(self.latitude)
        self.ui.dms_longitude.setText(self.longitude)
        
        self.setStyleSheet(open("styles.css", "r").read())		






    @pyqtSlot(float, float)
    def click(self, lat, lng):
        log.debug("click")
        self.latitude = str("%.4f" % lat)
        self.longitude = str("%.4f" % lng)
        self.ui.dd_latitude.setText(self.latitude)
        self.ui.dd_longitude.setText(self.longitude)
        
        degrees     = math.floor(lat)
        minutes     = math.floor(60*(lat-degrees))
        seconds     = 3600*(lat-degrees) - 60*minutes
        log.debug("lat=%f, minutes=%f, seconds=%f" % (lat,minutes,seconds))
        self.ui.dms_latitude.setText("N %.0f %.0f' %.2f\"" % (degrees, minutes, seconds))
        
        degrees     = math.floor(lng)
        minutes     = math.floor(60*(lng-degrees))
        seconds     = 3600*(lng-degrees) - 60*minutes
        self.ui.dms_longitude.setText("E %.0f %.0f' %.2f\"" % (degrees, minutes, seconds))        


    def save(self):
            
        log.info("GPSWindow SAVE")
        
        
        self.close()
        return self.latitude, self.longitude
    
        
        
    def cancel(self):
        log.info("GPSWindow Cancel")
        self.close()
        return self.Rejected
Beispiel #33
0
class TestProtocolView(QFrame):
    
    def __init__(self, parent):
        super(TestProtocolView, self).__init__()
        self.parent = parent
        self.setFrameStyle(QFrame.StyledPanel)
        self.protocolView = QWebView()
        
        self.protocolView.setStyle(QStyleFactory.create("windows"))
        
        layout = QVBoxLayout()
        layout.addWidget(self.protocolView)
        self.setLayout(layout)
        
        self.protocolView.page().mainFrame().javaScriptWindowObjectCleared.connect(self.populateJavaScriptWindowObject)
        self.protocolView.page().settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        # view->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
        

    @Slot()
    def populateJavaScriptWindowObject(self):
        self.protocolView.page().mainFrame().addToJavaScriptWindowObject("formExtractor", self);

    def setHtml(testhtml, testqurl):
        self.protocolView.setHtml(testhtml, testqurl)
        
    @Slot()
    def submit(self):
        
        try:

            frame = self.protocolView.page().mainFrame()
            updatedHtml = frame.toHtml()
            
            with self.protocolTestSampleUrl.open('w', encoding='utf-8') as protocolHtml:
                print("Saving updated protocol: ", str(self.protocolTestSampleUrl))
                protocolHtml.write(updatedHtml)
        
        finally:
            return False

        
    @Slot(object)
    def update(self, obj):
        
        print("TestProtocolView", obj)
        test = self.parent.tester.getitem()
        
        if not test["folder",]:
            self.protocolView.setHtml("<html></html>", QUrl())
            
        else:
            protocolUrl = test.folder.main / ".." / ".." / 'protocol.html'
            protocolTestSampleUrl = test.folder.main / 'protocol (test={}).html'.format(test["info"].short)
            
            self.protocolTestSampleUrl = protocolTestSampleUrl
            
            if not protocolUrl.exists() and not protocolTestSampleUrl.exists():
                logging.warn("Protocol doesn't exist for test: "+str(protocolUrl))
                return 
            
            if not protocolTestSampleUrl.exists():
                shutil.copy(str(protocolUrl), str(protocolTestSampleUrl))
                
            with protocolTestSampleUrl.open('rb') as protocolFile:            
                protocolHtmlStr = protocolFile.read().decode(encoding='UTF-8')
                self.protocolView.setHtml(protocolHtmlStr, QUrl("."))            
Beispiel #34
0
class Browser(QWidget):
    """LilyPond documentation browser widget."""
    def __init__(self, dockwidget):
        super(Browser, self).__init__(dockwidget)
        
        layout = QVBoxLayout(spacing=0)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)
        
        self.toolbar = tb = QToolBar()
        self.webview = QWebView(contextMenuPolicy=Qt.CustomContextMenu)
        self.chooser = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents)
        self.search = SearchEntry(maximumWidth=200)
        
        layout.addWidget(self.toolbar)
        layout.addWidget(self.webview)
        
        ac = dockwidget.actionCollection
        ac.help_back.triggered.connect(self.webview.back)
        ac.help_forward.triggered.connect(self.webview.forward)
        ac.help_home.triggered.connect(self.showHomePage)
        ac.help_print.triggered.connect(self.slotPrint)
        
        self.webview.page().setNetworkAccessManager(lilydoc.network.accessmanager())
        self.webview.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.webview.page().linkClicked.connect(self.openUrl)
        self.webview.page().setForwardUnsupportedContent(True)
        self.webview.page().unsupportedContent.connect(self.slotUnsupported)
        self.webview.urlChanged.connect(self.slotUrlChanged)
        self.webview.customContextMenuRequested.connect(self.slotShowContextMenu)
        
        tb.addAction(ac.help_back)
        tb.addAction(ac.help_forward)
        tb.addSeparator()
        tb.addAction(ac.help_home)
        tb.addAction(ac.help_print)
        tb.addSeparator()
        tb.addWidget(self.chooser)
        tb.addWidget(self.search)
        
        self.chooser.activated[int].connect(self.showHomePage)
        self.search.textEdited.connect(self.slotSearchChanged)
        self.search.returnPressed.connect(self.slotSearchReturnPressed)
        dockwidget.mainwindow().iconSizeChanged.connect(self.updateToolBarSettings)
        dockwidget.mainwindow().toolButtonStyleChanged.connect(self.updateToolBarSettings)
        
        app.settingsChanged.connect(self.readSettings)
        self.readSettings()
        self.loadDocumentation()
        self.showInitialPage()
        app.settingsChanged.connect(self.loadDocumentation)
        app.translateUI(self)
    
    def readSettings(self):
        s = QSettings()
        s.beginGroup("documentation")
        ws = self.webview.page().settings()
        family = s.value("fontfamily", self.font().family(), str)
        size = s.value("fontsize", 16, int)
        ws.setFontFamily(QWebSettings.StandardFont, family)
        ws.setFontSize(QWebSettings.DefaultFontSize, size)
        fixed = textformats.formatData('editor').font
        ws.setFontFamily(QWebSettings.FixedFont, fixed.family())
        ws.setFontSize(QWebSettings.DefaultFixedFontSize, fixed.pointSizeF() * 96 / 72)
        
    def keyPressEvent(self, ev):
        if ev.text() == "/":
            self.search.setFocus()
        else:
            super(Browser, self).keyPressEvent(ev)
        
    def translateUI(self):
        try:
            self.search.setPlaceholderText(_("Search..."))
        except AttributeError:
            pass # not in Qt 4.6
    
    def showInitialPage(self):
        """Shows the preferred start page.
        
        If a local documentation instance already has a suitable version,
        just loads it. Otherwise connects to the allLoaded signal, that is
        emitted when all the documentation instances have loaded their version
        information and then shows the start page (if another page wasn't yet
        loaded).
        
        """
        if self.webview.url().isEmpty():
            docs = lilydoc.manager.docs()
            version = lilypondinfo.preferred().version()
            index = -1
            if version:
                for num, doc in enumerate(docs):
                    if doc.version() is not None and doc.version() >= version:
                        index = num # a suitable documentation is found
                        break
            if index == -1:
                # nothing found (or LilyPond version not available),
                # wait for loading or show the most recent version
                if not lilydoc.manager.loaded():
                    lilydoc.manager.allLoaded.connect(self.showInitialPage)
                    return
                index = len(docs) - 1
            self.chooser.setCurrentIndex(index)
            self.showHomePage()
    
    def loadDocumentation(self):
        """Puts the available documentation instances in the combobox."""
        i = self.chooser.currentIndex()
        self.chooser.clear()
        for doc in lilydoc.manager.docs():
            v = doc.versionString()
            if doc.isLocal():
                t = _("(local)")
            else:
                t = _("({hostname})").format(hostname=doc.url().host())
            self.chooser.addItem("{0} {1}".format(v or _("<unknown>"), t))
        self.chooser.setCurrentIndex(i)
        if not lilydoc.manager.loaded():
            lilydoc.manager.allLoaded.connect(self.loadDocumentation, -1)
            return
        
    def updateToolBarSettings(self):
        mainwin = self.parentWidget().mainwindow()
        self.toolbar.setIconSize(mainwin.iconSize())
        self.toolbar.setToolButtonStyle(mainwin.toolButtonStyle())
        
    def showManual(self):
        """Invoked when the user presses F1."""
        self.slotHomeFrescobaldi() # TEMP
        
    def slotUrlChanged(self):
        ac = self.parentWidget().actionCollection
        ac.help_back.setEnabled(self.webview.history().canGoBack())
        ac.help_forward.setEnabled(self.webview.history().canGoForward())
    
    def openUrl(self, url):
        if url.path().endswith(('.ily', '.lyi', '.ly')):
            self.sourceViewer().showReply(lilydoc.network.get(url))
        else:
            self.webview.load(url)
    
    def slotUnsupported(self, reply):
        helpers.openUrl(reply.url())
    
    def slotSearchChanged(self):
        text = self.search.text()
        if not text.startswith(':'):
            self.webview.page().findText(text, QWebPage.FindWrapsAroundDocument)
    
    def slotSearchReturnPressed(self):
        text = self.search.text()
        if not text.startswith(':'):
            self.slotSearchChanged()
        else:
            pass # TODO: implement full doc search
    
    def sourceViewer(self):
        try:
            return self._sourceviewer
        except AttributeError:
            from . import sourceviewer
            self._sourceviewer = sourceviewer.SourceViewer(self)
            return self._sourceviewer
    
    def showHomePage(self):
        """Shows the homepage of the LilyPond documentation."""
        i = self.chooser.currentIndex()
        if i < 0:
            i = 0
        doc = lilydoc.manager.docs()[i]
        
        url = doc.home()
        if doc.isLocal():
            path = url.toLocalFile()
            langs = lilydoc.network.langs()
            if langs:
                for lang in langs:
                    if os.path.exists(path + '.' + lang + '.html'):
                        path += '.' + lang
                        break
            url = QUrl.fromLocalFile(path + '.html')
        self.webview.load(url)
    
    def slotPrint(self):
        printer = QPrinter()
        dlg = QPrintDialog(printer, self)
        dlg.setWindowTitle(app.caption(_("Print")))
        if dlg.exec_():
            self.webview.print_(printer)
    
    def slotShowContextMenu(self, pos):
        hit = self.webview.page().currentFrame().hitTestContent(pos)
        menu = QMenu()
        if hit.linkUrl().isValid():
            a = self.webview.pageAction(QWebPage.CopyLinkToClipboard)
            a.setIcon(icons.get("edit-copy"))
            a.setText(_("Copy &Link"))
            menu.addAction(a)
            menu.addSeparator()
            a = menu.addAction(icons.get("window-new"), _("Open Link in &New Window"))
            a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl()))
        else:
            if hit.isContentSelected():
                a = self.webview.pageAction(QWebPage.Copy)
                a.setIcon(icons.get("edit-copy"))
                a.setText(_("&Copy"))
                menu.addAction(a)
                menu.addSeparator()
            a = menu.addAction(icons.get("window-new"), _("Open Document in &New Window"))
            a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(self.webview.url()))
        if menu.actions():
            menu.exec_(self.webview.mapToGlobal(pos))
    
    def slotNewWindow(self, url):
        helpers.openUrl(url)
Beispiel #35
0
class PDFWriter(QObject):

    @pyqtSlot(result=unicode)
    def title(self):
        return self.doc_title

    @pyqtSlot(result=unicode)
    def author(self):
        return self.doc_author

    @pyqtSlot(result=unicode)
    def section(self):
        return self.current_section

    @pyqtSlot(result=unicode)
    def tl_section(self):
        return self.current_tl_section

    def __init__(self, opts, log, cover_data=None, toc=None):
        from calibre.gui2 import must_use_qt
        must_use_qt()
        QObject.__init__(self)

        self.logger = self.log = log
        current_log(log)
        self.opts = opts
        self.cover_data = cover_data
        self.paged_js = None
        self.toc = toc

        self.loop = QEventLoop()
        self.view = QWebView()
        self.page = Page(opts, self.log)
        self.view.setPage(self.page)
        self.view.setRenderHints(QPainter.Antialiasing|QPainter.TextAntialiasing|QPainter.SmoothPixmapTransform)
        self.view.loadFinished.connect(self.render_html,
                type=Qt.QueuedConnection)
        for x in (Qt.Horizontal, Qt.Vertical):
            self.view.page().mainFrame().setScrollBarPolicy(x,
                    Qt.ScrollBarAlwaysOff)
        self.report_progress = lambda x, y: x
        self.current_section = ''
        self.current_tl_section = ''

    def dump(self, items, out_stream, pdf_metadata):
        opts = self.opts
        page_size = get_page_size(self.opts)
        xdpi, ydpi = self.view.logicalDpiX(), self.view.logicalDpiY()

        def margin(which):
            val = getattr(opts, 'pdf_page_margin_' + which)
            if val == 0.0:
                val = getattr(opts, 'margin_' + which)
            return val
        ml, mr, mt, mb = map(margin, 'left right top bottom'.split())
        # We cannot set the side margins in the webview as there is no right
        # margin for the last page (the margins are implemented with
        # -webkit-column-gap)
        self.doc = PdfDevice(out_stream, page_size=page_size, left_margin=ml,
                             top_margin=0, right_margin=mr, bottom_margin=0,
                             xdpi=xdpi, ydpi=ydpi, errors=self.log.error,
                             debug=self.log.debug, compress=not
                             opts.uncompressed_pdf, opts=opts,
                             mark_links=opts.pdf_mark_links, page_margins=(ml, mr, mt, mb))
        self.footer = opts.pdf_footer_template
        if self.footer:
            self.footer = self.footer.strip()
        if not self.footer and opts.pdf_page_numbers:
            self.footer = '<p style="text-align:center; text-indent: 0">_PAGENUM_</p>'
        self.header = opts.pdf_header_template
        if self.header:
            self.header = self.header.strip()
        min_margin = 1.5 * opts._final_base_font_size
        if self.footer and mb < min_margin:
            self.log.warn('Bottom margin is too small for footer, increasing it to %.1fpts' % min_margin)
            mb = min_margin
        if self.header and mt < min_margin:
            self.log.warn('Top margin is too small for header, increasing it to %.1fpts' % min_margin)
            mt = min_margin

        self.page.setViewportSize(QSize(self.doc.width(), self.doc.height()))
        self.render_queue = items
        self.total_items = len(items)

        mt, mb = map(self.doc.to_px, (mt, mb))
        self.margin_top, self.margin_bottom = map(lambda x:int(floor(x)), (mt, mb))

        self.painter = QPainter(self.doc)
        try:
            self.book_language = pdf_metadata.mi.languages[0]
        except Exception:
            self.book_language = 'eng'
        self.doc.set_metadata(title=pdf_metadata.title,
                              author=pdf_metadata.author,
                              tags=pdf_metadata.tags, mi=pdf_metadata.mi)
        self.doc_title = pdf_metadata.title
        self.doc_author = pdf_metadata.author
        self.painter.save()
        try:
            if self.cover_data is not None:
                p = QPixmap()
                try:
                    p.loadFromData(self.cover_data)
                except TypeError:
                    self.log.warn('This ebook does not have a raster cover, cannot generate cover for PDF'
                                  '. Cover type: %s' % type(self.cover_data))
                if not p.isNull():
                    self.doc.init_page()
                    draw_image_page(QRect(*self.doc.full_page_rect),
                            self.painter, p,
                            preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio)
                    self.doc.end_page()
        finally:
            self.painter.restore()

        QTimer.singleShot(0, self.render_book)
        if self.loop.exec_() == 1:
            raise Exception('PDF Output failed, see log for details')

        if self.toc is not None and len(self.toc) > 0:
            self.doc.add_outline(self.toc)

        self.painter.end()

        if self.doc.errors_occurred:
            raise Exception('PDF Output failed, see log for details')

    def render_inline_toc(self):
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        self.rendered_inline_toc = True
        from calibre.ebooks.pdf.render.toc import toc_as_html
        raw = toc_as_html(self.toc, self.doc, self.opts, evaljs)
        pt = PersistentTemporaryFile('_pdf_itoc.htm')
        pt.write(raw)
        pt.close()
        self.render_queue.append(pt.name)
        self.render_next()

    def render_book(self):
        if self.doc.errors_occurred:
            return self.loop.exit(1)
        try:
            if not self.render_queue:
                if self.opts.pdf_add_toc and self.toc is not None and len(self.toc) > 0 and not hasattr(self, 'rendered_inline_toc'):
                    return self.render_inline_toc()
                self.loop.exit()
            else:
                self.render_next()
        except:
            self.logger.exception('Rendering failed')
            self.loop.exit(1)

    def render_next(self):
        item = unicode(self.render_queue.pop(0))

        self.logger.debug('Processing %s...' % item)
        self.current_item = item
        load_html(item, self.view)

    def render_html(self, ok):
        if ok:
            try:
                self.do_paged_render()
            except:
                self.log.exception('Rendering failed')
                self.loop.exit(1)
                return
        else:
            # The document is so corrupt that we can't render the page.
            self.logger.error('Document cannot be rendered.')
            self.loop.exit(1)
            return
        done = self.total_items - len(self.render_queue)
        self.report_progress(done/self.total_items,
                        _('Rendered %s'%os.path.basename(self.current_item)))
        self.render_book()

    @property
    def current_page_num(self):
        return self.doc.current_page_num

    def load_mathjax(self):
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        mjpath = P(u'viewer/mathjax').replace(os.sep, '/')
        if iswindows:
            mjpath = u'/' + mjpath
        if bool(evaljs('''
                    window.mathjax.base = %s;
                    mathjax.check_for_math(); mathjax.math_present
                    '''%(json.dumps(mjpath, ensure_ascii=False)))):
            self.log.debug('Math present, loading MathJax')
            while not bool(evaljs('mathjax.math_loaded')):
                self.loop.processEvents(self.loop.ExcludeUserInputEvents)
            evaljs('document.getElementById("MathJax_Message").style.display="none";')

    def load_header_footer_images(self):
        from calibre.utils.monotonic import monotonic
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        st = monotonic()
        while not evaljs('paged_display.header_footer_images_loaded()'):
            self.loop.processEvents(self.loop.ExcludeUserInputEvents)
            if monotonic() - st > 5:
                self.log.warn('Header and footer images have not loaded in 5 seconds, ignoring')
                break

    def get_sections(self, anchor_map, only_top_level=False):
        sections = defaultdict(list)
        ci = os.path.abspath(os.path.normcase(self.current_item))
        if self.toc is not None:
            tocentries = self.toc.top_level_items() if only_top_level else self.toc.flat()
            for toc in tocentries:
                path = toc.abspath or None
                frag = toc.fragment or None
                if path is None:
                    continue
                path = os.path.abspath(os.path.normcase(path))
                if path == ci:
                    col = 0
                    if frag and frag in anchor_map:
                        col = anchor_map[frag]['column']
                    sections[col].append(toc.text or _('Untitled'))

        return sections

    def hyphenate(self, evaljs):
        evaljs(u'''\
        Hyphenator.config(
            {
            'minwordlength'    : 6,
            // 'hyphenchar'     : '|',
            'displaytogglebox' : false,
            'remoteloading'    : false,
            'doframes'         : true,
            'defaultlanguage'  : 'en',
            'storagetype'      : 'session',
            'onerrorhandler'   : function (e) {
                                    console.log(e);
                                }
            });
        Hyphenator.hyphenate(document.body, "%s");
        ''' % self.hyphenate_lang
        )

    def convert_page_margins(self, doc_margins):
        ans = [0, 0, 0, 0]

        def convert(name, idx, vertical=True):
            m = doc_margins.get(name)
            if m is None:
                ans[idx] = getattr(self.doc.engine, '{}_margin'.format(name))
            else:
                ans[idx] = m

        convert('left', 0, False), convert('top', 1), convert('right', 2, False), convert('bottom', 3)
        return ans

    def do_paged_render(self):
        if self.paged_js is None:
            import uuid
            from calibre.utils.resources import compiled_coffeescript as cc
            self.paged_js =  cc('ebooks.oeb.display.utils')
            self.paged_js += cc('ebooks.oeb.display.indexing')
            self.paged_js += cc('ebooks.oeb.display.paged')
            self.paged_js += cc('ebooks.oeb.display.mathjax')
            if self.opts.pdf_hyphenate:
                self.paged_js += P('viewer/hyphenate/Hyphenator.js', data=True).decode('utf-8')
                hjs, self.hyphenate_lang = load_hyphenator_dicts({}, self.book_language)
                self.paged_js += hjs
            self.hf_uuid = str(uuid.uuid4()).replace('-', '')

        self.view.page().mainFrame().addToJavaScriptWindowObject("py_bridge", self)
        self.view.page().longjs_counter = 0
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        evaljs(self.paged_js)
        self.load_mathjax()
        if self.opts.pdf_hyphenate:
            self.hyphenate(evaljs)

        margin_top, margin_bottom = self.margin_top, self.margin_bottom
        page_margins = None
        if self.opts.pdf_use_document_margins:
            doc_margins = evaljs('document.documentElement.getAttribute("data-calibre-pdf-output-page-margins")')
            try:
                doc_margins = json.loads(doc_margins)
            except Exception:
                doc_margins = None
            if doc_margins and isinstance(doc_margins, dict):
                doc_margins = {k:float(v) for k, v in doc_margins.iteritems() if isinstance(v, (float, int)) and k in {'right', 'top', 'left', 'bottom'}}
                if doc_margins:
                    margin_top = margin_bottom = 0
                    page_margins = self.convert_page_margins(doc_margins)

        amap = json.loads(evaljs('''
        document.body.style.backgroundColor = "white";
        // Qt WebKit cannot handle opacity with the Pdf backend
        s = document.createElement('style');
        s.textContent = '* {opacity: 1 !important}';
        document.documentElement.appendChild(s);
        paged_display.set_geometry(1, %d, %d, %d);
        paged_display.layout();
        paged_display.fit_images();
        ret = book_indexing.all_links_and_anchors();
        window.scrollTo(0, 0); // This is needed as getting anchor positions could have caused the viewport to scroll
        JSON.stringify(ret);
        '''%(margin_top, 0, margin_bottom)))

        if not isinstance(amap, dict):
            amap = {'links':[], 'anchors':{}}  # Some javascript error occurred
        for val in amap['anchors'].itervalues():
            if isinstance(val, dict) and 'column' in val:
                val['column'] = int(val['column'])
        for href, val in amap['links']:
            if isinstance(val, dict) and 'column' in val:
                val['column'] = int(val['column'])
        sections = self.get_sections(amap['anchors'])
        tl_sections = self.get_sections(amap['anchors'], True)
        col = 0

        if self.header:
            evaljs('paged_display.header_template = ' + json.dumps(self.header))
        if self.footer:
            evaljs('paged_display.footer_template = ' + json.dumps(self.footer))
        if self.header or self.footer:
            evaljs('paged_display.create_header_footer("%s");'%self.hf_uuid)

        start_page = self.current_page_num

        mf = self.view.page().mainFrame()

        def set_section(col, sections, attr):
            # If this page has no section, use the section from the previous page
            idx = col if col in sections else col - 1 if col - 1 in sections else None
            if idx is not None:
                setattr(self, attr, sections[idx][0])

        from calibre.ebooks.pdf.render.toc import calculate_page_number

        while True:
            set_section(col, sections, 'current_section')
            set_section(col, tl_sections, 'current_tl_section')
            self.doc.init_page(page_margins)
            num = calculate_page_number(self.current_page_num, self.opts.pdf_page_number_map, evaljs)
            if self.header or self.footer:
                if evaljs('paged_display.update_header_footer(%d)'%num) is True:
                    self.load_header_footer_images()

            self.painter.save()
            mf.render(self.painter, mf.ContentsLayer)
            self.painter.restore()
            try:
                nsl = int(evaljs('paged_display.next_screen_location()'))
            except (TypeError, ValueError):
                break
            self.doc.end_page(nsl <= 0)
            if nsl <= 0:
                break
            evaljs('window.scrollTo(%d, 0); paged_display.position_header_footer();'%nsl)
            if self.doc.errors_occurred:
                break
            col += 1

        if not self.doc.errors_occurred and self.doc.current_page_num > 1:
            self.doc.add_links(self.current_item, start_page, amap['links'],
                            amap['anchors'])
class MapTip(QDockWidget):

    closed = pyqtSignal()

    def __init__(self, iface: QgisInterface, html: str, point: QgsPointXY):
        super().__init__()
        self.map_canvas = iface.mapCanvas()
        self.point = point
        self.web_view = QWebView(self)

        self.dbg_info('map position: {}'.format(point.asWkt()))

        self.web_view.page().setLinkDelegationPolicy(
            QWebPage.DelegateAllLinks)  # Handle link clicks by yourself
        self.web_view.setContextMenuPolicy(
            Qt.NoContextMenu
        )  # No context menu is allowed if you don't need it
        self.web_view.linkClicked.connect(self.on_link_clicked)

        self.web_view.page().settings().setAttribute(
            QWebSettings.DeveloperExtrasEnabled, True)
        self.web_view.page().settings().setAttribute(
            QWebSettings.JavascriptEnabled, True)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setWidget(self.web_view)

        # assure the map tip is never larger than half the map canvas
        max_width = int(self.map_canvas.geometry().width() / 1.8)
        max_height = int(self.map_canvas.geometry().height() / 1.8)
        self.dbg_info('max size {} {}'.format(max_height, max_width))
        self.setMaximumSize(max_width, max_height)

        # start with 0 size,
        # the content will automatically make it grow up to MaximumSize
        self.resize(300, 200)

        background_color = self.palette().base().color()
        background_color.setAlpha(235)
        stroke_color = self.palette().shadow().color()
        #self.setStyleSheet(".QDocWidget{{ border: 1px solid {stroke}; background-color: {bg} }}"
        #                          .format(stroke=stroke_color.name(QColor.HexArgb),
        #                                  bg=background_color.name(QColor.HexArgb)))

        palette = self.web_view.palette()
        palette.setBrush(QPalette.Base, Qt.transparent)
        palette.setBrush(QPalette.Base, background_color)
        self.web_view.page().setPalette(palette)
        self.web_view.setAttribute(Qt.WA_OpaquePaintEvent, False)

        body_style = "background-color: {bg}; margin: 0".format(
            bg=background_color)
        container_style = "display: inline-block; margin: 0px"

        body_html = "<html><body style='{body_style}'>" \
                    "<div id='QgsWebViewContainer' style='{container_style}'>{html}</div><" \
                    "/body></html>".format(body_style=body_style,
                                           container_style=container_style,
                                           html=html)

        self.web_view.setHtml(body_html)

        scrollbar_width = self.web_view.page().mainFrame().scrollBarGeometry(
            Qt.Vertical).width()
        scrollbar_height = self.web_view.page().mainFrame().scrollBarGeometry(
            Qt.Horizontal).height()
        if scrollbar_width > 0 or scrollbar_height > 0:
            # Get the content size
            container = self.web_view.page().mainFrame().findFirstElement(
                "#QgsWebViewContainer")
            width = container.geometry().width() + 25 + scrollbar_width
            height = container.geometry().height() + 25 + scrollbar_height

            #self.resize(width, height)

        iface.addDockWidget(Qt.RightDockWidgetArea, self)
        self.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.setFloating(True)
        self.setWindowOpacity(0.9)
        self.move_to_point()

    def move_to_point(self):
        pixel_position = self.map_canvas.mapSettings().mapToPixel().transform(
            self.point)
        pixel_position = self.map_canvas.mapToGlobal(
            QPoint(pixel_position.x(), pixel_position.y()))
        self.move(pixel_position.x() + 10, pixel_position.y() + 10)

    def on_link_clicked(self, url):
        QDesktopServices.openUrl(url)

    def closeEvent(self, event: QCloseEvent):
        self.closed.emit()

    def info(self, msg="", level=Qgis.Info):
        QgsMessageLog.logMessage('{} {}'.format(self.__class__.__name__, msg),
                                 'Locator bar', level)

    def dbg_info(self, msg=""):
        if DEBUG:
            self.info(msg)
Beispiel #37
0
class PDFWriter(QObject):
    @pyqtSlot(result=unicode_type)
    def title(self):
        return self.doc_title

    @pyqtSlot(result=unicode_type)
    def author(self):
        return self.doc_author

    @pyqtSlot(result=unicode_type)
    def section(self):
        return self.current_section

    @pyqtSlot(result=unicode_type)
    def tl_section(self):
        return self.current_tl_section

    def __init__(self, opts, log, cover_data=None, toc=None):
        from calibre.gui2 import must_use_qt
        must_use_qt()
        QObject.__init__(self)

        self.logger = self.log = log
        self.mathjax_dir = P('mathjax', allow_user_override=False)
        current_log(log)
        self.opts = opts
        self.cover_data = cover_data
        self.paged_js = None
        self.toc = toc

        self.loop = QEventLoop()
        self.view = QWebView()
        self.page = Page(opts, self.log)
        self.view.setPage(self.page)
        self.view.setRenderHints(QPainter.Antialiasing
                                 | QPainter.TextAntialiasing
                                 | QPainter.SmoothPixmapTransform)
        self.view.loadFinished.connect(self.render_html,
                                       type=Qt.QueuedConnection)
        self.view.loadProgress.connect(self.load_progress)
        self.ignore_failure = None
        self.hang_check_timer = t = QTimer(self)
        t.timeout.connect(self.hang_check)
        t.setInterval(1000)

        for x in (Qt.Horizontal, Qt.Vertical):
            self.view.page().mainFrame().setScrollBarPolicy(
                x, Qt.ScrollBarAlwaysOff)
        self.report_progress = lambda x, y: x
        self.current_section = ''
        self.current_tl_section = ''

    def dump(self, items, out_stream, pdf_metadata):
        opts = self.opts
        page_size = get_page_size(self.opts)
        xdpi, ydpi = self.view.logicalDpiX(), self.view.logicalDpiY()

        def margin(which):
            val = getattr(opts, 'pdf_page_margin_' + which)
            if val == 0.0:
                val = getattr(opts, 'margin_' + which)
            return val

        ml, mr, mt, mb = map(margin, 'left right top bottom'.split())
        # We cannot set the side margins in the webview as there is no right
        # margin for the last page (the margins are implemented with
        # -webkit-column-gap)
        self.doc = PdfDevice(out_stream,
                             page_size=page_size,
                             left_margin=ml,
                             top_margin=0,
                             right_margin=mr,
                             bottom_margin=0,
                             xdpi=xdpi,
                             ydpi=ydpi,
                             errors=self.log.error,
                             debug=self.log.debug,
                             compress=not opts.uncompressed_pdf,
                             opts=opts,
                             mark_links=opts.pdf_mark_links,
                             page_margins=(ml, mr, mt, mb))
        self.footer = opts.pdf_footer_template
        if self.footer:
            self.footer = self.footer.strip()
        if not self.footer and opts.pdf_page_numbers:
            self.footer = '<p style="text-align:center; text-indent: 0">_PAGENUM_</p>'
        self.header = opts.pdf_header_template
        if self.header:
            self.header = self.header.strip()
        min_margin = 1.5 * opts._final_base_font_size
        if self.footer and mb < min_margin:
            self.log.warn(
                'Bottom margin is too small for footer, increasing it to %.1fpts'
                % min_margin)
            mb = min_margin
        if self.header and mt < min_margin:
            self.log.warn(
                'Top margin is too small for header, increasing it to %.1fpts'
                % min_margin)
            mt = min_margin

        self.page.setViewportSize(QSize(self.doc.width(), self.doc.height()))
        self.render_queue = items
        self.total_items = len(items)

        mt, mb = map(self.doc.to_px, (mt, mb))
        self.margin_top, self.margin_bottom = map(lambda x: int(floor(x)),
                                                  (mt, mb))

        self.painter = QPainter(self.doc)
        try:
            self.book_language = pdf_metadata.mi.languages[0]
        except Exception:
            self.book_language = 'eng'
        self.doc.set_metadata(title=pdf_metadata.title,
                              author=pdf_metadata.author,
                              tags=pdf_metadata.tags,
                              mi=pdf_metadata.mi)
        self.doc_title = pdf_metadata.title
        self.doc_author = pdf_metadata.author
        self.painter.save()
        try:
            if self.cover_data is not None:
                p = QPixmap()
                try:
                    p.loadFromData(self.cover_data)
                except TypeError:
                    self.log.warn(
                        'This ebook does not have a raster cover, cannot generate cover for PDF'
                        '. Cover type: %s' % type(self.cover_data))
                if not p.isNull():
                    self.doc.init_page()
                    draw_image_page(QRect(*self.doc.full_page_rect),
                                    self.painter,
                                    p,
                                    preserve_aspect_ratio=self.opts.
                                    preserve_cover_aspect_ratio)
                    self.doc.end_page()
        finally:
            self.painter.restore()

        QTimer.singleShot(0, self.render_book)
        if self.loop.exec_() == 1:
            raise Exception('PDF Output failed, see log for details')

        if self.toc is not None and len(self.toc) > 0:
            self.doc.add_outline(self.toc)

        self.painter.end()

        if self.doc.errors_occurred:
            raise Exception('PDF Output failed, see log for details')

    def render_inline_toc(self):
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        self.rendered_inline_toc = True
        from calibre.ebooks.pdf.render.toc import toc_as_html
        raw = toc_as_html(self.toc, self.doc, self.opts, evaljs)
        pt = PersistentTemporaryFile('_pdf_itoc.htm')
        pt.write(raw)
        pt.close()
        self.render_queue.append(pt.name)
        self.render_next()

    def render_book(self):
        if self.doc.errors_occurred:
            return self.loop.exit(1)
        try:
            if not self.render_queue:
                if self.opts.pdf_add_toc and self.toc is not None and len(
                        self.toc) > 0 and not hasattr(self,
                                                      'rendered_inline_toc'):
                    return self.render_inline_toc()
                self.loop.exit()
            else:
                self.render_next()
        except:
            self.logger.exception('Rendering failed')
            self.loop.exit(1)

    def render_next(self):
        item = unicode_type(self.render_queue.pop(0))

        self.logger.debug('Processing %s...' % item)
        self.current_item = item
        load_html(item, self.view)
        self.last_load_progress_at = monotonic()
        self.hang_check_timer.start()

    def load_progress(self, progress):
        self.last_load_progress_at = monotonic()

    def hang_check(self):
        if monotonic() - self.last_load_progress_at > 60:
            self.log.warn('Timed out waiting for %s to render' %
                          self.current_item)
            self.ignore_failure = self.current_item
            self.view.stop()

    def render_html(self, ok):
        self.hang_check_timer.stop()
        if self.ignore_failure == self.current_item:
            ok = True
        self.ignore_failure = None
        if ok:
            try:
                self.do_paged_render()
            except:
                self.log.exception('Rendering failed')
                self.loop.exit(1)
                return
        else:
            # The document is so corrupt that we can't render the page.
            self.logger.error('Document %s cannot be rendered.' %
                              self.current_item)
            self.loop.exit(1)
            return
        done = self.total_items - len(self.render_queue)
        self.report_progress(
            done / self.total_items,
            _('Rendered %s' % os.path.basename(self.current_item)))
        self.render_book()

    @property
    def current_page_num(self):
        return self.doc.current_page_num

    def load_mathjax(self):
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        mjpath = self.mathjax_dir.replace(os.sep, '/')
        if iswindows:
            mjpath = u'/' + mjpath
        if bool(
                evaljs('''
                    window.mathjax.base = %s;
                    mathjax.check_for_math(); mathjax.math_present
                    ''' % (json.dumps(mjpath, ensure_ascii=False)))):
            self.log.debug('Math present, loading MathJax')
            while not bool(evaljs('mathjax.math_loaded')):
                self.loop.processEvents(self.loop.ExcludeUserInputEvents)
            # give the MathJax fonts time to load
            for i in range(5):
                self.loop.processEvents(self.loop.ExcludeUserInputEvents)
            evaljs(
                'document.getElementById("MathJax_Message").style.display="none";'
            )

    def load_header_footer_images(self):
        from calibre.utils.monotonic import monotonic
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        st = monotonic()
        while not evaljs('paged_display.header_footer_images_loaded()'):
            self.loop.processEvents(self.loop.ExcludeUserInputEvents)
            if monotonic() - st > 5:
                self.log.warn(
                    'Header and footer images have not loaded in 5 seconds, ignoring'
                )
                break

    def get_sections(self, anchor_map, only_top_level=False):
        sections = defaultdict(list)
        ci = os.path.abspath(os.path.normcase(self.current_item))
        if self.toc is not None:
            tocentries = self.toc.top_level_items(
            ) if only_top_level else self.toc.flat()
            for toc in tocentries:
                path = toc.abspath or None
                frag = toc.fragment or None
                if path is None:
                    continue
                path = os.path.abspath(os.path.normcase(path))
                if path == ci:
                    col = 0
                    if frag and frag in anchor_map:
                        col = anchor_map[frag]['column']
                    sections[col].append(toc.text or _('Untitled'))

        return sections

    def hyphenate(self, evaljs):
        evaljs(u'''\
        Hyphenator.config(
            {
            'minwordlength'    : 6,
            // 'hyphenchar'     : '|',
            'displaytogglebox' : false,
            'remoteloading'    : false,
            'doframes'         : true,
            'defaultlanguage'  : 'en',
            'storagetype'      : 'session',
            'onerrorhandler'   : function (e) {
                                    console.log(e);
                                }
            });
        Hyphenator.hyphenate(document.body, "%s");
        ''' % self.hyphenate_lang)

    def convert_page_margins(self, doc_margins):
        ans = [0, 0, 0, 0]

        def convert(name, idx, vertical=True):
            m = doc_margins.get(name)
            if m is None:
                ans[idx] = getattr(self.doc.engine, '{}_margin'.format(name))
            else:
                ans[idx] = m

        convert('left', 0,
                False), convert('top',
                                1), convert('right', 2,
                                            False), convert('bottom', 3)
        return ans

    def do_paged_render(self):
        if self.paged_js is None:
            import uuid
            from calibre.utils.resources import compiled_coffeescript as cc
            self.paged_js = cc('ebooks.oeb.display.utils').decode('utf-8')
            self.paged_js += cc('ebooks.oeb.display.indexing').decode('utf-8')
            self.paged_js += cc('ebooks.oeb.display.paged').decode('utf-8')
            self.paged_js += cc('ebooks.oeb.display.mathjax').decode('utf-8')
            if self.opts.pdf_hyphenate:
                self.paged_js += P('viewer/hyphenate/Hyphenator.js',
                                   data=True).decode('utf-8')
                hjs, self.hyphenate_lang = load_hyphenator_dicts(
                    {}, self.book_language)
                self.paged_js += hjs
            self.hf_uuid = str(uuid.uuid4()).replace('-', '')

        self.view.page().mainFrame().addToJavaScriptWindowObject(
            "py_bridge", self)
        self.view.page().longjs_counter = 0
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        evaljs(self.paged_js)
        self.load_mathjax()
        if self.opts.pdf_hyphenate:
            self.hyphenate(evaljs)

        margin_top, margin_bottom = self.margin_top, self.margin_bottom
        page_margins = None
        if self.opts.pdf_use_document_margins:
            doc_margins = evaljs(
                'document.documentElement.getAttribute("data-calibre-pdf-output-page-margins")'
            )
            try:
                doc_margins = json.loads(doc_margins)
            except Exception:
                doc_margins = None
            if doc_margins and isinstance(doc_margins, dict):
                doc_margins = {
                    k: float(v)
                    for k, v in iteritems(doc_margins)
                    if isinstance(v, numbers.Number)
                    and k in {'right', 'top', 'left', 'bottom'}
                }
                if doc_margins:
                    margin_top = margin_bottom = 0
                    page_margins = self.convert_page_margins(doc_margins)

        amap = json.loads(
            evaljs('''
        document.body.style.backgroundColor = "white";
        // Qt WebKit cannot handle opacity with the Pdf backend
        s = document.createElement('style');
        s.textContent = '* {opacity: 1 !important}';
        document.documentElement.appendChild(s);
        paged_display.set_geometry(1, %d, %d, %d);
        paged_display.layout();
        paged_display.fit_images();
        ret = book_indexing.all_links_and_anchors();
        window.scrollTo(0, 0); // This is needed as getting anchor positions could have caused the viewport to scroll
        JSON.stringify(ret);
        ''' % (margin_top, 0, margin_bottom)))

        if not isinstance(amap, dict):
            amap = {
                'links': [],
                'anchors': {}
            }  # Some javascript error occurred
        for val in itervalues(amap['anchors']):
            if isinstance(val, dict) and 'column' in val:
                val['column'] = int(val['column'])
        for href, val in amap['links']:
            if isinstance(val, dict) and 'column' in val:
                val['column'] = int(val['column'])
        sections = self.get_sections(amap['anchors'])
        tl_sections = self.get_sections(amap['anchors'], True)
        col = 0

        if self.header:
            evaljs('paged_display.header_template = ' +
                   json.dumps(self.header))
        if self.footer:
            evaljs('paged_display.footer_template = ' +
                   json.dumps(self.footer))
        if self.header or self.footer:
            evaljs('paged_display.create_header_footer("%s");' % self.hf_uuid)

        start_page = self.current_page_num

        mf = self.view.page().mainFrame()

        def set_section(col, sections, attr):
            # If this page has no section, use the section from the previous page
            idx = col if col in sections else col - 1 if col - 1 in sections else None
            if idx is not None:
                setattr(self, attr, sections[idx][0])

        from calibre.ebooks.pdf.render.toc import calculate_page_number

        while True:
            set_section(col, sections, 'current_section')
            set_section(col, tl_sections, 'current_tl_section')
            self.doc.init_page(page_margins)
            num = calculate_page_number(self.current_page_num,
                                        self.opts.pdf_page_number_map, evaljs)
            if self.header or self.footer:
                if evaljs('paged_display.update_header_footer(%d)' %
                          num) is True:
                    self.load_header_footer_images()

            self.painter.save()
            mf.render(self.painter, mf.ContentsLayer)
            self.painter.restore()
            try:
                nsl = int(evaljs('paged_display.next_screen_location()'))
            except (TypeError, ValueError):
                break
            self.doc.end_page(nsl <= 0)
            if nsl <= 0:
                break
            evaljs(
                'window.scrollTo(%d, 0); paged_display.position_header_footer();'
                % nsl)
            if self.doc.errors_occurred:
                break
            col += 1

        if not self.doc.errors_occurred and self.doc.current_page_num > 1:
            self.doc.add_links(self.current_item, start_page, amap['links'],
                               amap['anchors'])
Beispiel #38
0
class DrawLotteryView(QObject):
    def __init__(self, parent):
        super(DrawLotteryView, self).__init__()
        self.pwindow = parent   #获取父窗口指针

        self.states = QStateMachine()

        sinitinfo = QState()
        sltypeinfo = QState()
        sprizeinfo = QState()
        svnumberwindow = QState()
        sdrawlottery = QState()
        sfinal = QState()

        sinitinfo.addTransition(self.on_nextstep_event, sltypeinfo)
        sltypeinfo.addTransition(self.on_nextstep_event, sprizeinfo)
        sprizeinfo.addTransition(self.on_nextstep_event, svnumberwindow)
        svnumberwindow.addTransition(self.on_nextstep_event, sdrawlottery)
        sdrawlottery.addTransition(self.on_nextstep_event, sfinal)
        sfinal.addTransition(self.on_final_event, sinitinfo)

        sinitinfo.entered.connect(self.initinfo)
        sltypeinfo.entered.connect(self.viewltypeinfo)
        sprizeinfo.entered.connect(self.viewprizeinfo)
        svnumberwindow.entered.connect(self.viewnumberwindow)
        sdrawlottery.entered.connect(self.drawlottery)
        sfinal.entered.connect(self.final)

        self.states.addState(sinitinfo)
        self.states.addState(sltypeinfo)
        self.states.addState(sprizeinfo)
        self.states.addState(svnumberwindow)
        self.states.addState(sdrawlottery)
        self.states.addState(sfinal)
        self.states.setInitialState(sinitinfo)

        self.states.start()

    def show(self):
        #It is IMPERATIVE that all forward slashes are scrubbed out, otherwise QTWebKit seems to be
        # easily confused
        # kickOffHTML = 'file:///' + join(dirname(__file__).replace('\\', '/'), "www/test02.html").replace('\\', '/')
        # kickOffHTML = 'file:///' + join(dirname(__file__).replace('\\', '/'), "www/test02.html").replace('\\', '/')
        kickOffHTML = 'file:///' + QDir().absolutePath() + SysConfig().getlotterywindowspath() + 'index.html'
        # kickOffHTML = 'http://get.webgl.org/'
        # kickOffHTML = 'http://www.airtightinteractive.com/demos/js/nebula/'

        #This is basically a browser instance
        # self.gweb = QGraphicsWebView()
        self.web = QWebView()
        self.web.setMinimumSize(1024,680)
        self.web.setWindowFlags(Qt.FramelessWindowHint) #无边框
        self.web.setContextMenuPolicy(0)    #关闭右键

        #Unlikely to matter but prefer to be waiting for callback then try to catch
        # it in time.
        self.web.loadFinished.connect(self.onLoad)
        self.web.load(QUrl(kickOffHTML))
        self.web.show()
        # self.scene = QGraphicsScene()
        # self.scene.addItem(self.gweb)
        # self.view = QGraphicsView()
        # self.view.setScene(self.scene)
        # self.view.show()

    def onLoad(self):
        #如果mywebinterface未初始化,则初始化mywebinterface
        # if getattr(self, "mywebinterface", False) == False:
        #     self.mywebinterface = WebInterface()

        #This is the body of a web browser tab
        self.myPage = self.web.page()
        self.myPage.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        self.myPage.settings().setAttribute(QWebSettings.JavascriptEnabled, True)
        self.myPage.settings().setAttribute(QWebSettings.WebGLEnabled, True)
        self.myPage.settings().setAttribute(QWebSettings.AcceleratedCompositingEnabled, True)

        #This is the actual context/frame a webpage is running in.
        # Other frames could include iframes or such.
        self.myFrame = self.myPage.mainFrame()
        # ATTENTION here's the magic that sets a bridge between Python to HTML
        self.myFrame.addToJavaScriptWindowObject("mywebinterface", self)
        #Tell the HTML side, we are open for business
        self.myFrame.evaluateJavaScript("ApplicationIsReady()")

    def initinfo(self):
        # print('initinfo')
        cltypes = self.pwindow.getcurrentqueue()
        if cltypes == None:
            self.isfinished = True
        else:
            self.isfinished = False
            self.currentltype = cltypes['ltype']
            self.currentnumber = cltypes['number'] #当前奖项需要抽取的数量
            self.drawcount = int(self.currentnumber)  #当前抽奖序列的人数,需要重复抽奖的次数
            self.isdrawing = False    #当前是否为抽奖状态

    @pyqtSlot()
    def nextstep(self):
        if self.isfinished:
            # print('close this window')
            self.on_message_event.emit('当前抽奖序列已抽取完毕!<br>按退出按钮退出!')
        else:
            if self.isdrawing and self.drawcount > 0:
                self.drawlottery()
            else:
                # print('nextstep')
                self.on_nextstep_event.emit()

    @pyqtSlot()
    def exitwindow(self):
        # print('exit window')
        self.web.close()

    def viewltypeinfo(self):
        # print('viewltypeinfo')
        self.on_viewltypeinfo_event.emit(self.currentltype, int(self.currentnumber))

    def viewprizeinfo(self):
        # print('return prizeinfo')
        ls = SysConfig().getprizeitempicandnote(self.currentltype)
        icon = ls[0]
        notes = ls[1]
        self.on_viewprizeinfo_event.emit(icon, notes)

    def viewnumberwindow(self):
        # print('return viewnumberwindow')
        self.on_viewnumberwindow_event.emit()

    def drawlottery(self):
        # print('return drawlottery')
        progress = str(int(self.currentnumber)-self.drawcount+1) + '/' + self.currentnumber
        self.on_viewprogress_event.emit(progress)
        try:
            dl = DAllList().getwininfo()
            sid = dl[0][2] + dl[0][5] + dl[0][6] + dl[0][7]
            name = dl[1]
            DAllList().setwininfo(self.currentltype,dl[0])
        except:
            sid = '0000'
            name = 'error, retry'
            self.drawcount = 0
            self.isdrawing = False
            self.on_drawlottery_event.emit(sid, name)
            pass
        self.on_drawlottery_event.emit(sid, name)
        self.drawcount -= 1
        if self.drawcount == 0:
            self.isdrawing = False
        else:
            self.isdrawing = True

    def final(self):
        print('final')
        self.on_final_event.emit()

    @pyqtSlot()
    def changesize(self):
        # print('changesize')
        if self.web.isFullScreen():
            self.web.showNormal()
        else:
            self.web.showFullScreen()

    on_nextstep_event = pyqtSignal()
    on_viewltypeinfo_event = pyqtSignal(str, int)
    on_viewprizeinfo_event = pyqtSignal(str, str)
    on_viewluckguyinfo_event = pyqtSignal(str, str)
    on_viewnumberwindow_event = pyqtSignal()
    on_drawlottery_event = pyqtSignal(str, str)
    on_final_event = pyqtSignal()
    on_message_event = pyqtSignal(str)
    on_viewprogress_event = pyqtSignal(str)


# app = QApplication(sys.argv)
#
# myWebApp = DrawLotteryView()
# myWebApp.show()
#
# exit(app.exec_())
Beispiel #39
0
class BookInfo(QDialog):

    closed = pyqtSignal(object)

    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self)
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = QWebView(self)
        self.details.sizeHint = self.details_size_hint
        self.details.page().setLinkDelegationPolicy(self.details.page().DelegateAllLinks)
        self.details.linkClicked.connect(self.link_clicked)
        s = self.details.page().settings()
        s.setAttribute(s.JavascriptEnabled, False)
        self.css = css()
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.page().setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(gprefs.get('book_info_dialog_fit_cover', True))
        l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, -1)
        self.previous_button = QPushButton(QIcon(I('previous.png')), _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(_('Next [%s]')%
                unicode(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(_('Previous [%s]')%
                unicode(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width/2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass

    def link_clicked(self, qurl):
        link = unicode(qurl.toString(QUrl.None))
        self.link_delegate(link)

    def done(self, r):
        saved_layout = (bytearray(self.saveGeometry()), bytearray(self.splitter.saveState()))
        gprefs.set('book_info_dialog_layout', saved_layout)
        ret = QDialog.done(self, r)
        self.view.model().new_bookdisplay_data.disconnect(self.slave)
        self.view = self.link_delegate = self.gui = None
        self.closed.emit(self)
        return ret

    def cover_changed(self, data):
        if self.current_row is not None:
            id_ = self.view.model().id(self.current_row)
            self.view.model().db.set_cover(id_, data)
        if self.gui.cover_flow:
            self.gui.cover_flow.dataChanged()
        ci = self.view.currentIndex()
        if ci.isValid():
            self.view.model().current_changed(ci, ci)

    def details_size_hint(self):
        return QSize(350, 550)

    def toggle_cover_fit(self, state):
        gprefs.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
        self.resize_cover()

    def cover_view_resized(self, event):
        QTimer.singleShot(1, self.resize_cover)

    def slave(self, mi):
        self.refresh(mi.row_number, mi)

    def move(self, delta=1):
        idx = self.view.currentIndex()
        if idx.isValid():
            m = self.view.model()
            ni = m.index(idx.row() + delta, idx.column())
            if ni.isValid():
                if self.view.isVisible():
                    self.view.scrollTo(ni)
                self.view.setCurrentIndex(ni)

    def next(self):
        self.move()

    def previous(self):
        self.move(-1)

    def resize_cover(self):
        if self.cover_pixmap is None:
            return
        pixmap = self.cover_pixmap
        if self.fit_cover.isChecked():
            scaled, new_width, new_height = fit_image(pixmap.width(),
                    pixmap.height(), self.cover.size().width()-10,
                    self.cover.size().height()-10)
            if scaled:
                pixmap = pixmap.scaled(new_width, new_height,
                        Qt.KeepAspectRatio, Qt.SmoothTransformation)
        self.cover.set_pixmap(pixmap)
        self.update_cover_tooltip()

    def update_cover_tooltip(self):
        tt = ''
        if self.marked:
            tt = _('This book is marked') if self.marked in {True, 'true'} else _(
                'This book is marked as: %s') % self.marked
            tt += '\n\n'
        if self.cover_pixmap is not None:
            sz = self.cover_pixmap.size()
            tt += _('Cover size: %(width)d x %(height)d')%dict(width=sz.width(), height=sz.height())
        self.cover.setToolTip(tt)

    def refresh(self, row, mi=None):
        if isinstance(row, QModelIndex):
            row = row.row()
        if row == self.current_row and mi is None:
            return
        mi = self.view.model().get_book_display_info(row) if mi is None else mi
        if mi is None:
            # Indicates books was deleted from library, or row numbers have
            # changed
            return

        self.previous_button.setEnabled(False if row == 0 else True)
        self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True)
        self.current_row = row
        self.setWindowTitle(mi.title)
        self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1])
        self.resize_cover()
        html = render_html(mi, self.css, True, self, all_fields=True)
        self.details.setHtml(html)
        self.marked = mi.marked
        self.cover.setBackgroundBrush(self.marked_brush if mi.marked else self.normal_brush)
        self.update_cover_tooltip()
Beispiel #40
0
class PreviewerHTML(QWidget):
    """
    Class implementing a previewer widget for HTML, Markdown and ReST files.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(PreviewerHTML, self).__init__(parent)
        
        self.__layout = QVBoxLayout(self)
        
        self.titleLabel = QLabel(self)
        self.titleLabel.setWordWrap(True)
        self.titleLabel.setTextInteractionFlags(Qt.NoTextInteraction)
        self.__layout.addWidget(self.titleLabel)
        
        try:
            from PyQt5.QtWebEngineWidgets import QWebEngineView
            self.previewView = QWebEngineView(self)
            self.__usesWebKit = False
        except ImportError:
            from PyQt5.QtWebKitWidgets import QWebPage, QWebView
            self.previewView = QWebView(self)
            self.previewView.page().setLinkDelegationPolicy(
                QWebPage.DelegateAllLinks)
            self.__usesWebKit = True
        
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.previewView.sizePolicy().hasHeightForWidth())
        self.previewView.setSizePolicy(sizePolicy)
        self.previewView.setContextMenuPolicy(Qt.NoContextMenu)
        self.previewView.setUrl(QUrl("about:blank"))
        self.__layout.addWidget(self.previewView)
        
        self.jsCheckBox = QCheckBox(self.tr("Enable JavaScript"), self)
        self.jsCheckBox.setToolTip(self.tr(
            "Select to enable JavaScript for HTML previews"))
        self.__layout.addWidget(self.jsCheckBox)
        
        self.ssiCheckBox = QCheckBox(self.tr("Enable Server Side Includes"),
                                     self)
        self.ssiCheckBox.setToolTip(self.tr(
            "Select to enable support for Server Side Includes"))
        self.__layout.addWidget(self.ssiCheckBox)
        
        self.jsCheckBox.clicked[bool].connect(self.on_jsCheckBox_clicked)
        self.ssiCheckBox.clicked[bool].connect(self.on_ssiCheckBox_clicked)
        self.previewView.titleChanged.connect(self.on_previewView_titleChanged)
        if self.__usesWebKit:
            self.previewView.linkClicked.connect(
                self.on_previewView_linkClicked)
        
        self.jsCheckBox.setChecked(
            Preferences.getUI("ShowFilePreviewJS"))
        self.ssiCheckBox.setChecked(
            Preferences.getUI("ShowFilePreviewSSI"))
        
        self.__scrollBarPositions = {}
        self.__vScrollBarAtEnd = {}
        self.__hScrollBarAtEnd = {}
        
        self.__processingThread = PreviewProcessingThread()
        self.__processingThread.htmlReady.connect(self.__setHtml)

        self.__previewedPath = None
        self.__previewedEditor = None
    
    def shutdown(self):
        """
        Public method to perform shutdown actions.
        """
        self.__processingThread.wait()
    
    @pyqtSlot(bool)
    def on_jsCheckBox_clicked(self, checked):
        """
        Private slot to enable/disable JavaScript.
        
        @param checked state of the checkbox (boolean)
        """
        Preferences.setUI("ShowFilePreviewJS", checked)
        self.__setJavaScriptEnabled(checked)
    
    def __setJavaScriptEnabled(self, enable):
        """
        Private method to enable/disable JavaScript.
        
        @param enable flag indicating the enable state (boolean)
        """
        self.jsCheckBox.setChecked(enable)
        
        settings = self.previewView.settings()
        settings.setAttribute(settings.JavascriptEnabled, enable)
        
        self.processEditor()
    
    @pyqtSlot(bool)
    def on_ssiCheckBox_clicked(self, checked):
        """
        Private slot to enable/disable SSI.
        
        @param checked state of the checkbox (boolean)
        """
        Preferences.setUI("ShowFilePreviewSSI", checked)
        self.processEditor()
    
    def processEditor(self, editor=None):
        """
        Public slot to process an editor's text.
        
        @param editor editor to be processed (Editor)
        """
        if editor is None:
            editor = self.__previewedEditor
        else:
            self.__previewedEditor = editor
        
        if editor is not None:
            fn = editor.getFileName()
            
            if fn:
                extension = os.path.normcase(os.path.splitext(fn)[1][1:])
            else:
                extension = ""
            if extension in \
                Preferences.getEditor("PreviewHtmlFileNameExtensions") or \
               editor.getLanguage() == "HTML":
                language = "HTML"
            elif extension in \
                    Preferences.getEditor("PreviewMarkdownFileNameExtensions"):
                language = "Markdown"
            elif extension in \
                    Preferences.getEditor("PreviewRestFileNameExtensions"):
                language = "ReST"
            else:
                self.__setHtml(fn, self.tr(
                    "<p>No preview available for this type of file.</p>"))
                return
            
            if fn:
                project = e5App().getObject("Project")
                if project.isProjectFile(fn):
                    rootPath = project.getProjectPath()
                else:
                    rootPath = os.path.dirname(os.path.abspath(fn))
            else:
                rootPath = ""
            
            self.__processingThread.process(
                fn, language, editor.text(),
                self.ssiCheckBox.isChecked(), rootPath,
                Preferences.getEditor("PreviewRestUseSphinx"))

    def __setHtml(self, filePath, html):
        """
        Private method to set the HTML to the view and restore the scroll bars
        positions.
        
        @param filePath file path of the previewed editor (string)
        @param html processed HTML text ready to be shown (string)
        """
        self.__previewedPath = Utilities.normcasepath(
            Utilities.fromNativeSeparators(filePath))
        self.__saveScrollBarPositions()
        if self.__usesWebKit:
            self.previewView.page().mainFrame().contentsSizeChanged.connect(
                self.__restoreScrollBarPositions)
        else:
            self.previewView.page().loadFinished.connect(
                self.__restoreScrollBarPositions)
        self.previewView.setHtml(html, baseUrl=QUrl.fromLocalFile(filePath))
    
    @pyqtSlot(str)
    def on_previewView_titleChanged(self, title):
        """
        Private slot to handle a change of the title.
        
        @param title new title (string)
        """
        if title:
            self.titleLabel.setText(self.tr("Preview - {0}").format(title))
        else:
            self.titleLabel.setText(self.tr("Preview"))
    
    def __saveScrollBarPositions(self):
        """
        Private method to save scroll bar positions for a previewed editor.
        """
        if self.__usesWebKit:
            frame = self.previewView.page().mainFrame()
            if frame.contentsSize() == QSize(0, 0):
                return  # no valid data, nothing to save
            
            pos = frame.scrollPosition()
            self.__scrollBarPositions[self.__previewedPath] = pos
            self.__hScrollBarAtEnd[self.__previewedPath] = \
                frame.scrollBarMaximum(Qt.Horizontal) == pos.x()
            self.__vScrollBarAtEnd[self.__previewedPath] = \
                frame.scrollBarMaximum(Qt.Vertical) == pos.y()
        else:
            from PyQt5.QtCore import QPoint
            pos = self.__execJavaScript(
                "(function() {"
                "var res = {"
                "    x: 0,"
                "    y: 0,"
                "};"
                "res.x = window.scrollX;"
                "res.y = window.scrollY;"
                "return res;"
                "})()"
            )
            pos = QPoint(pos["x"], pos["y"])
            self.__scrollBarPositions[self.__previewedPath] = pos
            self.__hScrollBarAtEnd[self.__previewedPath] = False
            self.__vScrollBarAtEnd[self.__previewedPath] = False

    def __restoreScrollBarPositions(self):
        """
        Private method to restore scroll bar positions for a previewed editor.
        """
        if self.__usesWebKit:
            try:
                self.previewView.page().mainFrame().contentsSizeChanged.\
                    disconnect(self.__restoreScrollBarPositions)
            except TypeError:
                # not connected, simply ignore it
                pass
            
            if self.__previewedPath not in self.__scrollBarPositions:
                return
            
            frame = self.previewView.page().mainFrame()
            frame.setScrollPosition(
                self.__scrollBarPositions[self.__previewedPath])
            
            if self.__hScrollBarAtEnd[self.__previewedPath]:
                frame.setScrollBarValue(
                    Qt.Horizontal, frame.scrollBarMaximum(Qt.Horizontal))
            
            if self.__vScrollBarAtEnd[self.__previewedPath]:
                frame.setScrollBarValue(
                    Qt.Vertical, frame.scrollBarMaximum(Qt.Vertical))
        else:
            if self.__previewedPath not in self.__scrollBarPositions:
                return
            
            pos = self.__scrollBarPositions[self.__previewedPath]
            self.previewView.page().runJavaScript(
                "window.scrollTo({0}, {1});".format(pos.x(), pos.y()))
    
    @pyqtSlot(QUrl)
    def on_previewView_linkClicked(self, url):
        """
        Private slot handling the clicking of a link.
        
        @param url url of the clicked link (QUrl)
        """
        e5App().getObject("UserInterface").launchHelpViewer(url.toString())
    
    def __execJavaScript(self, script):
        """
        Private function to execute a JavaScript function Synchroneously.
        
        @param script JavaScript script source to be executed
        @type str
        @return result of the script
        @rtype depending upon script result
        """
        from PyQt5.QtCore import QEventLoop
        loop = QEventLoop()
        resultDict = {"res": None}
        
        def resultCallback(res, resDict=resultDict):
            if loop and loop.isRunning():
                resDict["res"] = res
                loop.quit()
        
        self.previewView.page().runJavaScript(
            script, resultCallback)
        
        loop.exec_()
        return resultDict["res"]
Beispiel #41
0
class Printing(QObject):
    def __init__(self, iterator, parent):
        QObject.__init__(self, parent)
        self.current_index = 0
        self.iterator = iterator
        self.view = QWebView(self.parent())
        self.mf = mf = self.view.page().mainFrame()
        for x in (Qt.Horizontal, Qt.Vertical):
            mf.setScrollBarPolicy(x, Qt.ScrollBarAlwaysOff)
        self.view.loadFinished.connect(self.load_finished)
        self.paged_js = compiled_coffeescript('ebooks.oeb.display.utils')
        self.paged_js += compiled_coffeescript('ebooks.oeb.display.paged')

    def load_finished(self, ok):
        self.loaded_ok = ok

    def start_print(self):
        self.pd = QPrintDialog(self.parent())
        self.pd.open(self._start_print)

    def _start_print(self):
        self.do_print(self.pd.printer())

    def start_preview(self):
        self.pd = QPrintPreviewDialog(self.parent())
        self.pd.paintRequested.connect(self.do_print)
        self.pd.exec_()

    def do_print(self, printer):
        painter = QPainter(printer)
        zoomx = printer.logicalDpiX() / self.view.logicalDpiX()
        zoomy = printer.logicalDpiY() / self.view.logicalDpiY()
        painter.scale(zoomx, zoomy)
        pr = printer.pageRect()
        self.view.page().setViewportSize(
            QSize(pr.width() / zoomx,
                  pr.height() / zoomy))
        evaljs = self.mf.evaluateJavaScript
        loop = QEventLoop(self)
        pagenum = 0
        from_, to = printer.fromPage(), printer.toPage()
        first = True

        for path in self.iterator.spine:
            self.loaded_ok = None
            load_html(path,
                      self.view,
                      codec=getattr(path, 'encoding', 'utf-8'),
                      mime_type=getattr(path, 'mime_type', None))
            while self.loaded_ok is None:
                loop.processEvents(loop.ExcludeUserInputEvents)
            if not self.loaded_ok:
                return error_dialog(self.parent(),
                                    _('Failed to render'),
                                    _('Failed to render document %s') % path,
                                    show=True)
            evaljs(self.paged_js)
            evaljs('''
                document.body.style.backgroundColor = "white";
                paged_display.set_geometry(1, 0, 0, 0);
                paged_display.layout();
                paged_display.fit_images();
            ''')

            while True:
                pagenum += 1
                if (pagenum >= from_ and (to == 0 or pagenum <= to)):
                    if not first:
                        printer.newPage()
                    first = False
                    self.mf.render(painter)
                try:
                    nsl = int(evaljs('paged_display.next_screen_location()'))
                except (TypeError, ValueError):
                    break
                if nsl <= 0:
                    break
                evaljs('window.scrollTo(%d, 0)' % nsl)

        painter.end()
Beispiel #42
0
class MainWindow(QMainWindow):
    def __init__(self, url):
        super(MainWindow, self).__init__()

        self.progress = 0

        fd = QFile(":/jquery.min.js")

        if fd.open(QIODevice.ReadOnly | QFile.Text):
            self.jQuery = QTextStream(fd).readAll()
            fd.close()
        else:
            self.jQuery = ''

        QNetworkProxyFactory.setUseSystemConfiguration(True)

        self.view = QWebView(self)
        self.view.load(url)
        self.view.loadFinished.connect(self.adjustLocation)
        self.view.titleChanged.connect(self.adjustTitle)
        self.view.loadProgress.connect(self.setProgress)
        self.view.loadFinished.connect(self.finishLoading)

        self.locationEdit = QLineEdit(self)
        self.locationEdit.setSizePolicy(QSizePolicy.Expanding,
                self.locationEdit.sizePolicy().verticalPolicy())
        self.locationEdit.returnPressed.connect(self.changeLocation)

        toolBar = self.addToolBar("Navigation")
        toolBar.addAction(self.view.pageAction(QWebPage.Back))
        toolBar.addAction(self.view.pageAction(QWebPage.Forward))
        toolBar.addAction(self.view.pageAction(QWebPage.Reload))
        toolBar.addAction(self.view.pageAction(QWebPage.Stop))
        toolBar.addWidget(self.locationEdit)

        viewMenu = self.menuBar().addMenu("&View")
        viewSourceAction = QAction("Page Source", self)
        viewSourceAction.triggered.connect(self.viewSource)
        viewMenu.addAction(viewSourceAction)

        effectMenu = self.menuBar().addMenu("&Effect")
        effectMenu.addAction("Highlight all links", self.highlightAllLinks)

        self.rotateAction = QAction(
                self.style().standardIcon(QStyle.SP_FileDialogDetailedView),
                "Turn images upside down", self, checkable=True,
                toggled=self.rotateImages)
        effectMenu.addAction(self.rotateAction)

        toolsMenu = self.menuBar().addMenu("&Tools")
        toolsMenu.addAction("Remove GIF images", self.removeGifImages)
        toolsMenu.addAction("Remove all inline frames",
                self.removeInlineFrames)
        toolsMenu.addAction("Remove all object elements",
                self.removeObjectElements)
        toolsMenu.addAction("Remove all embedded elements",
                self.removeEmbeddedElements)
        self.setCentralWidget(self.view)

    def viewSource(self):
        accessManager = self.view.page().networkAccessManager()
        request = QNetworkRequest(self.view.url())
        reply = accessManager.get(request)
        reply.finished.connect(self.slotSourceDownloaded)

    def slotSourceDownloaded(self):
        reply = self.sender()
        self.textEdit = QTextEdit()
        self.textEdit.setAttribute(Qt.WA_DeleteOnClose)
        self.textEdit.show()
        self.textEdit.setPlainText(QTextStream(reply).readAll())
        self.textEdit.resize(600, 400)
        reply.deleteLater()

    def adjustLocation(self):
        self.locationEdit.setText(self.view.url().toString())

    def changeLocation(self):
        url = QUrl.fromUserInput(self.locationEdit.text())
        self.view.load(url)
        self.view.setFocus()

    def adjustTitle(self):
        if 0 < self.progress < 100:
            self.setWindowTitle("%s (%s%%)" % (self.view.title(), self.progress))
        else:
            self.setWindowTitle(self.view.title())

    def setProgress(self, p):
        self.progress = p
        self.adjustTitle()

    def finishLoading(self):
        self.progress = 100
        self.adjustTitle()
        self.view.page().mainFrame().evaluateJavaScript(self.jQuery)
        self.rotateImages(self.rotateAction.isChecked())

    def highlightAllLinks(self):
        code = """$('a').each(
                    function () {
                        $(this).css('background-color', 'yellow') 
                    } 
                  )"""
        self.view.page().mainFrame().evaluateJavaScript(code)

    def rotateImages(self, invert):
        if invert:
            code = """
                $('img').each(
                    function () {
                        $(this).css('-webkit-transition', '-webkit-transform 2s'); 
                        $(this).css('-webkit-transform', 'rotate(180deg)') 
                    } 
                )"""
        else:
            code = """
                $('img').each(
                    function () { 
                        $(this).css('-webkit-transition', '-webkit-transform 2s'); 
                        $(this).css('-webkit-transform', 'rotate(0deg)') 
                    } 
                )"""

        self.view.page().mainFrame().evaluateJavaScript(code)

    def removeGifImages(self):
        code = "$('[src*=gif]').remove()"
        self.view.page().mainFrame().evaluateJavaScript(code)

    def removeInlineFrames(self):
        code = "$('iframe').remove()"
        self.view.page().mainFrame().evaluateJavaScript(code)

    def removeObjectElements(self):
        code = "$('object').remove()"
        self.view.page().mainFrame().evaluateJavaScript(code)

    def removeEmbeddedElements(self):
        code = "$('embed').remove()"
        self.view.page().mainFrame().evaluateJavaScript(code)
Beispiel #43
0
class GPSWindow(QDialog):
    latitude = ""
    longitude = ""

    def __init__(self):

        log.info("GPSWindow.__init__")

        ui_gpswindow, QtBaseClass = uic.loadUiType(qtGPSUIFile)
        super(GPSWindow, self).__init__()
        self.ui = ui_gpswindow()
        self.ui.setupUi(self)
        self.setWindowTitle("Google Google Maps Maps")

        self.web = QWebView()
        self.web.setMinimumSize(800, 800)
        self.web.page().mainFrame().addToJavaScriptWindowObject('self', self)
        self.web.setHtml(maphtml)

        self.ui.frame.setLayout(self.ui.gridLayout)
        self.ui.gridLayout.addWidget(self.web, 0, 0, 1, 1)

        self.ui.dd_latitude.setText(self.latitude)
        self.ui.dd_longitude.setText(self.longitude)
        self.ui.dms_latitude.setText(self.latitude)
        self.ui.dms_longitude.setText(self.longitude)

        self.setStyleSheet(open("styles.css", "r").read())

    @pyqtSlot(float, float)
    def click(self, lat, lng):
        log.debug("click")
        self.latitude = str("%.4f" % lat)
        self.longitude = str("%.4f" % lng)
        self.ui.dd_latitude.setText(self.latitude)
        self.ui.dd_longitude.setText(self.longitude)

        degrees = math.floor(lat)
        minutes = math.floor(60 * (lat - degrees))
        seconds = 3600 * (lat - degrees) - 60 * minutes
        log.debug("lat=%f, minutes=%f, seconds=%f" % (lat, minutes, seconds))
        self.ui.dms_latitude.setText("N %.0f %.0f' %.2f\"" %
                                     (degrees, minutes, seconds))

        degrees = math.floor(lng)
        minutes = math.floor(60 * (lng - degrees))
        seconds = 3600 * (lng - degrees) - 60 * minutes
        self.ui.dms_longitude.setText("E %.0f %.0f' %.2f\"" %
                                      (degrees, minutes, seconds))

    def save(self):

        log.info("GPSWindow SAVE")

        self.close()
        return self.latitude, self.longitude

    def cancel(self):
        log.info("GPSWindow Cancel")
        self.close()
        return self.Rejected
Beispiel #44
0
class Browser(QWidget):
    """LilyPond documentation browser widget."""
    def __init__(self, dockwidget):
        super(Browser, self).__init__(dockwidget)

        layout = QVBoxLayout(spacing=0)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.toolbar = tb = QToolBar()
        self.webview = QWebView(contextMenuPolicy=Qt.CustomContextMenu)
        self.chooser = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents)
        self.search = SearchEntry(maximumWidth=200)

        layout.addWidget(self.toolbar)
        layout.addWidget(self.webview)

        ac = dockwidget.actionCollection
        ac.help_back.triggered.connect(self.webview.back)
        ac.help_forward.triggered.connect(self.webview.forward)
        ac.help_home.triggered.connect(self.showHomePage)
        ac.help_print.triggered.connect(self.slotPrint)

        self.webview.page().setNetworkAccessManager(
            lilydoc.network.accessmanager())
        self.webview.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.webview.page().linkClicked.connect(self.openUrl)
        self.webview.page().setForwardUnsupportedContent(True)
        self.webview.page().unsupportedContent.connect(self.slotUnsupported)
        self.webview.urlChanged.connect(self.slotUrlChanged)
        self.webview.customContextMenuRequested.connect(
            self.slotShowContextMenu)

        tb.addAction(ac.help_back)
        tb.addAction(ac.help_forward)
        tb.addSeparator()
        tb.addAction(ac.help_home)
        tb.addAction(ac.help_print)
        tb.addSeparator()
        tb.addWidget(self.chooser)
        tb.addWidget(self.search)

        self.chooser.activated[int].connect(self.showHomePage)
        self.search.textEdited.connect(self.slotSearchChanged)
        self.search.returnPressed.connect(self.slotSearchReturnPressed)
        dockwidget.mainwindow().iconSizeChanged.connect(
            self.updateToolBarSettings)
        dockwidget.mainwindow().toolButtonStyleChanged.connect(
            self.updateToolBarSettings)

        app.settingsChanged.connect(self.readSettings)
        self.readSettings()
        self.loadDocumentation()
        self.showInitialPage()
        app.settingsChanged.connect(self.loadDocumentation)
        app.translateUI(self)

    def readSettings(self):
        s = QSettings()
        s.beginGroup("documentation")
        ws = self.webview.page().settings()
        family = s.value("fontfamily", self.font().family(), str)
        size = s.value("fontsize", 16, int)
        ws.setFontFamily(QWebSettings.StandardFont, family)
        ws.setFontSize(QWebSettings.DefaultFontSize, size)
        fixed = textformats.formatData('editor').font
        ws.setFontFamily(QWebSettings.FixedFont, fixed.family())
        ws.setFontSize(QWebSettings.DefaultFixedFontSize,
                       fixed.pointSizeF() * 96 / 72)

    def keyPressEvent(self, ev):
        if ev.text() == "/":
            self.search.setFocus()
        else:
            super(Browser, self).keyPressEvent(ev)

    def translateUI(self):
        try:
            self.search.setPlaceholderText(_("Search..."))
        except AttributeError:
            pass  # not in Qt 4.6

    def showInitialPage(self):
        """Shows the preferred start page.
        
        If a local documentation instance already has a suitable version,
        just loads it. Otherwise connects to the allLoaded signal, that is
        emitted when all the documentation instances have loaded their version
        information and then shows the start page (if another page wasn't yet
        loaded).
        
        """
        if self.webview.url().isEmpty():
            docs = lilydoc.manager.docs()
            version = lilypondinfo.preferred().version()
            index = -1
            if version:
                for num, doc in enumerate(docs):
                    if doc.version() is not None and doc.version() >= version:
                        index = num  # a suitable documentation is found
                        break
            if index == -1:
                # nothing found (or LilyPond version not available),
                # wait for loading or show the most recent version
                if not lilydoc.manager.loaded():
                    lilydoc.manager.allLoaded.connect(self.showInitialPage)
                    return
                index = len(docs) - 1
            self.chooser.setCurrentIndex(index)
            self.showHomePage()

    def loadDocumentation(self):
        """Puts the available documentation instances in the combobox."""
        i = self.chooser.currentIndex()
        self.chooser.clear()
        for doc in lilydoc.manager.docs():
            v = doc.versionString()
            if doc.isLocal():
                t = _("(local)")
            else:
                t = _("({hostname})").format(hostname=doc.url().host())
            self.chooser.addItem("{0} {1}".format(v or _("<unknown>"), t))
        self.chooser.setCurrentIndex(i)
        if not lilydoc.manager.loaded():
            lilydoc.manager.allLoaded.connect(self.loadDocumentation, -1)
            return

    def updateToolBarSettings(self):
        mainwin = self.parentWidget().mainwindow()
        self.toolbar.setIconSize(mainwin.iconSize())
        self.toolbar.setToolButtonStyle(mainwin.toolButtonStyle())

    def showManual(self):
        """Invoked when the user presses F1."""
        self.slotHomeFrescobaldi()  # TEMP

    def slotUrlChanged(self):
        ac = self.parentWidget().actionCollection
        ac.help_back.setEnabled(self.webview.history().canGoBack())
        ac.help_forward.setEnabled(self.webview.history().canGoForward())

    def openUrl(self, url):
        if url.path().endswith(('.ily', '.lyi', '.ly')):
            self.sourceViewer().showReply(lilydoc.network.get(url))
        else:
            self.webview.load(url)

    def slotUnsupported(self, reply):
        helpers.openUrl(reply.url())

    def slotSearchChanged(self):
        text = self.search.text()
        if not text.startswith(':'):
            self.webview.page().findText(text,
                                         QWebPage.FindWrapsAroundDocument)

    def slotSearchReturnPressed(self):
        text = self.search.text()
        if not text.startswith(':'):
            self.slotSearchChanged()
        else:
            pass  # TODO: implement full doc search

    def sourceViewer(self):
        try:
            return self._sourceviewer
        except AttributeError:
            from . import sourceviewer
            self._sourceviewer = sourceviewer.SourceViewer(self)
            return self._sourceviewer

    def showHomePage(self):
        """Shows the homepage of the LilyPond documentation."""
        i = self.chooser.currentIndex()
        if i < 0:
            i = 0
        doc = lilydoc.manager.docs()[i]

        url = doc.home()
        if doc.isLocal():
            path = url.toLocalFile()
            langs = lilydoc.network.langs()
            if langs:
                for lang in langs:
                    if os.path.exists(path + '.' + lang + '.html'):
                        path += '.' + lang
                        break
            url = QUrl.fromLocalFile(path + '.html')
        self.webview.load(url)

    def slotPrint(self):
        printer = QPrinter()
        dlg = QPrintDialog(printer, self)
        dlg.setWindowTitle(app.caption(_("Print")))
        if dlg.exec_():
            self.webview.print_(printer)

    def slotShowContextMenu(self, pos):
        hit = self.webview.page().currentFrame().hitTestContent(pos)
        menu = QMenu()
        if hit.linkUrl().isValid():
            a = self.webview.pageAction(QWebPage.CopyLinkToClipboard)
            a.setIcon(icons.get("edit-copy"))
            a.setText(_("Copy &Link"))
            menu.addAction(a)
            menu.addSeparator()
            a = menu.addAction(icons.get("window-new"),
                               _("Open Link in &New Window"))
            a.triggered.connect(
                (lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl()))
        else:
            if hit.isContentSelected():
                a = self.webview.pageAction(QWebPage.Copy)
                a.setIcon(icons.get("edit-copy"))
                a.setText(_("&Copy"))
                menu.addAction(a)
                menu.addSeparator()
            a = menu.addAction(icons.get("window-new"),
                               _("Open Document in &New Window"))
            a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(
                self.webview.url()))
        if menu.actions():
            menu.exec_(self.webview.mapToGlobal(pos))

    def slotNewWindow(self, url):
        helpers.openUrl(url)
Beispiel #45
0
    def readData(self, size):
        if self.bytes_read >= len(self.content):
            return None
        data = self.content[self.bytes_read:self.bytes_read + size]
        self.bytes_read += len(data)
        return data

    def manager(self):
        return self.parent()


if __name__ == '__main__':
    app = QApplication(sys.argv)

    gs = QtWebKit.QWebSettings.globalSettings()
    gs.setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True)
    gs.setAttribute(QtWebKit.QWebSettings.JavascriptEnabled, True)
    gs.setAttribute(QtWebKit.QWebSettings.AutoLoadImages, True)
    gs.setAttribute(QtWebKit.QWebSettings.JavascriptCanOpenWindows, True)
    gs.setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)
    gs.setAttribute(QtWebKit.QWebSettings.LocalContentCanAccessRemoteUrls,
                    True)

    wv = QWebView()
    enam = NetworkAccessManager()
    wv.page().setNetworkAccessManager(enam)
    wv.show()
    wv.setUrl(QUrl("http://localhost/"))
    app.exec()
Beispiel #46
0
class PDFWriter(QObject):  # {{{

    def __init__(self, opts, log, cover_data=None, toc=None):
        from calibre.gui2 import must_use_qt
        from calibre.utils.podofo import get_podofo
        must_use_qt()
        QObject.__init__(self)

        self.logger = self.log = log
        self.podofo = get_podofo()
        self.doc = self.podofo.PDFDoc()

        self.loop = QEventLoop()
        self.view = QWebView()
        self.page = Page(opts, self.log)
        self.view.setPage(self.page)
        self.view.setRenderHints(QPainter.Antialiasing|QPainter.TextAntialiasing|QPainter.SmoothPixmapTransform)
        self.view.loadFinished.connect(self._render_html,
                type=Qt.QueuedConnection)
        for x in (Qt.Horizontal, Qt.Vertical):
            self.view.page().mainFrame().setScrollBarPolicy(x,
                    Qt.ScrollBarAlwaysOff)
        self.render_queue = []
        self.combine_queue = []
        self.tmp_path = PersistentTemporaryDirectory(u'_pdf_output_parts')

        self.opts = opts
        self.cover_data = cover_data
        self.paged_js = None
        self.toc = toc

    def dump(self, items, out_stream, pdf_metadata):
        self.metadata = pdf_metadata
        self._delete_tmpdir()
        self.outline = Outline(self.toc, items)

        self.render_queue = items
        self.combine_queue = []
        self.out_stream = out_stream
        self.insert_cover()

        self.render_succeeded = False
        self.current_page_num = self.doc.page_count()
        self.combine_queue.append(os.path.join(self.tmp_path,
            'qprinter_out.pdf'))
        self.first_page = True
        self.setup_printer(self.combine_queue[-1])
        QTimer.singleShot(0, self._render_book)
        self.loop.exec_()
        if self.painter is not None:
            self.painter.end()
        if self.printer is not None:
            self.printer.abort()

        if not self.render_succeeded:
            raise Exception('Rendering HTML to PDF failed')

    def _render_book(self):
        try:
            if len(self.render_queue) == 0:
                self._write()
            else:
                self._render_next()
        except:
            self.logger.exception('Rendering failed')
            self.loop.exit(1)

    def _render_next(self):
        item = unicode(self.render_queue.pop(0))

        self.logger.debug('Processing %s...' % item)
        self.current_item = item
        load_html(item, self.view)

    def _render_html(self, ok):
        if ok:
            self.do_paged_render()
        else:
            # The document is so corrupt that we can't render the page.
            self.logger.error('Document cannot be rendered.')
            self.loop.exit(0)
            return
        self._render_book()

    def _pass_json_value_getter(self):
        val = json.dumps(self.bridge_value)
        return val

    def _pass_json_value_setter(self, value):
        self.bridge_value = json.loads(unicode(value))

    _pass_json_value = pyqtProperty(str, fget=_pass_json_value_getter,
            fset=_pass_json_value_setter)

    def setup_printer(self, outpath):
        self.printer = self.painter = None
        printer = get_pdf_printer(self.opts, output_file_name=outpath)
        painter = QPainter(printer)
        zoomx = printer.logicalDpiX()/self.view.logicalDpiX()
        zoomy = printer.logicalDpiY()/self.view.logicalDpiY()
        painter.scale(zoomx, zoomy)
        pr = printer.pageRect()
        self.printer, self.painter = printer, painter
        self.viewport_size = QSize(pr.width()/zoomx, pr.height()/zoomy)
        self.page.setViewportSize(self.viewport_size)

    def do_paged_render(self):
        if self.paged_js is None:
            from calibre.utils.resources import compiled_coffeescript
            self.paged_js = compiled_coffeescript('ebooks.oeb.display.utils')
            self.paged_js += compiled_coffeescript('ebooks.oeb.display.indexing')
            self.paged_js += compiled_coffeescript('ebooks.oeb.display.paged')

        self.view.page().mainFrame().addToJavaScriptWindowObject("py_bridge", self)
        evaljs = self.view.page().mainFrame().evaluateJavaScript
        evaljs(self.paged_js)
        evaljs('''
        py_bridge.__defineGetter__('value', function() {
            return JSON.parse(this._pass_json_value);
        });
        py_bridge.__defineSetter__('value', function(val) {
            this._pass_json_value = JSON.stringify(val);
        });

        document.body.style.backgroundColor = "white";
        paged_display.set_geometry(1, 0, 0, 0);
        paged_display.layout();
        paged_display.fit_images();
        ''')
        mf = self.view.page().mainFrame()
        start_page = self.current_page_num
        if not self.first_page:
            start_page += 1
        while True:
            if not self.first_page:
                if self.printer.newPage():
                    self.current_page_num += 1
            self.first_page = False
            mf.render(self.painter)
            try:
                nsl = int(evaljs('paged_display.next_screen_location()'))
            except (TypeError, ValueError):
                break
            if nsl <= 0:
                break
            evaljs('window.scrollTo(%d, 0)'%nsl)

        self.bridge_value = tuple(self.outline.anchor_map[self.current_item])
        evaljs('py_bridge.value = book_indexing.anchor_positions(py_bridge.value)')
        amap = self.bridge_value
        if not isinstance(amap, dict):
            amap = {}  # Some javascript error occurred
        self.outline.set_pos(self.current_item, None, start_page, 0)
        for anchor, x in amap.iteritems():
            pagenum, ypos = x
            self.outline.set_pos(self.current_item, anchor, start_page + pagenum, ypos)

    def append_doc(self, outpath):
        doc = self.podofo.PDFDoc()
        with open(outpath, 'rb') as f:
            raw = f.read()
        doc.load(raw)
        self.doc.append(doc)

    def _delete_tmpdir(self):
        if os.path.exists(self.tmp_path):
            shutil.rmtree(self.tmp_path, True)
            self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')

    def insert_cover(self):
        if not isinstance(self.cover_data, bytes):
            return
        item_path = os.path.join(self.tmp_path, 'cover.pdf')
        printer = get_pdf_printer(self.opts, output_file_name=item_path,
                for_comic=True)
        self.combine_queue.insert(0, item_path)
        p = QPixmap()
        p.loadFromData(self.cover_data)
        if not p.isNull():
            painter = QPainter(printer)
            draw_image_page(printer, painter, p,
                    preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio)
            painter.end()
            self.append_doc(item_path)
        printer.abort()

    def _write(self):
        self.painter.end()
        self.printer.abort()
        self.painter = self.printer = None
        self.append_doc(self.combine_queue[-1])

        try:
            self.doc.creator = u'%s %s [http://calibre-ebook.com]'%(
                    __appname__, __version__)
            self.doc.title = self.metadata.title
            self.doc.author = self.metadata.author
            if self.metadata.tags:
                self.doc.keywords = self.metadata.tags
            self.outline(self.doc)
            self.doc.save_to_fileobj(self.out_stream)
            self.render_succeeded = True
        finally:
            self._delete_tmpdir()
            self.loop.exit(0)
Beispiel #47
0
class Window(QWidget):

    session = dict()

    def __init__(self, config):
        super(Window, self).__init__()

        self.config = config

        self.base_uri = QUrl.fromLocalFile(os.path.dirname(__file__)).toString()

        # initial web view add handle all link and form submitted
        self.web_view = QWebView(self)
        self.web_view.setPage(WebPage())
        self.web_view.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.web_view.page().linkClicked.connect(self.link_clicked)
        # self.web_view.page().urlChanged.connect(self.url_changed)
        self.web_view.page().loadFinished.connect(self.load_finished)
        self.web_view.page().loadStarted.connect(self.load_started)

        self.web_view.page().form_submitted.connect(self.handle_form_submitted)
        self.web_view.page().request_reload.connect(self.handle_reload)

        # initial template lookup
        self.tempalte_lookup = TemplateLookup(
            directories=[self.config.settings.get("mako.directories")],
            module_directory=self.config.settings.get("mako.module_directory"),
            input_encoding="utf-8",
        )

        # layout attribute
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        # add debug inspector
        if self.config.settings.get("debug", False):
            self.setup_inspector()
            self.splitter = QSplitter(self)
            self.splitter.setOrientation(Qt.Vertical)
            layout.addWidget(self.splitter)
            self.splitter.addWidget(self.web_view)
            self.splitter.addWidget(self.web_inspector)

        else:
            layout.addWidget(self.web_view)

    def setup_inspector(self):
        """
            This code from http://agateau.com/2012/02/03/pyqtwebkit-experiments-part-2-debugging/
        """
        page = self.web_view.page()
        page.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        self.web_inspector = QWebInspector(self)
        self.web_inspector.setPage(page)

        shortcut = QShortcut(self)
        shortcut.setKey(Qt.Key_F12)
        shortcut.activated.connect(self.toggle_inspector)
        self.web_inspector.setVisible(False)

    def toggle_inspector(self):
        self.web_inspector.setVisible(not self.web_inspector.isVisible())

    def handle_form_submitted(self, qurl, elements=dict()):

        #       print("\n\ngot url: ", qurl)
        qqurl = QUrlQuery(qurl)
        for key, value in qqurl.queryItems():
            elements[key] = value

        self.render(qurl.path(), elements)
        # do stuff with elements...

    #        for item in elements.items():
    #            print ("got: ", item)

    def handle_reload(self, qurl):
        self.render(qurl.path())

    def load_started(self):
        """"""
        # print("load_started ->: ", self.web_view.url())

    def load_finished(self, finished):
        """"""
        # print("load_finished ->: ", finished)

    #        if finished:
    #            self.web_view.setUrl(QUrl('/login'))

    #     def url_changed(self, qurl):
    #         ''''''
    # print("url_changed ->: ", qurl)

    def link_clicked(self, qurl):
        # print("link_clicked ->: ", qurl)
        qqurl = QUrlQuery(qurl)
        elements = {}
        # print("got link_clicked url: ", qurl)
        for key, value in qqurl.queryItems():
            elements[key] = value

        self.render(qurl.path(), elements)
        # self.render(qurl.path())

    def render(self, url, args=None):
        self.config.current_route_path = url
        print("current_route_path: ", self.config.current_route_path)
        logger.debug("url: %s" % url)
        route = self.config.get_route(url)
        logger.debug("view: %s" % route)

        if route is not None:
            view = route.get("view")
            context_obj = context.ResourceContext(self.config, self.session)
            context_obj.add_args(args)
            try:
                response = view(context_obj)
            except Exception as e:
                if e.args[0] == "Request Exit":
                    self.close()
                    return

                logger.exception(e)
                # need error page
                return self.link_clicked("/home")

            if not isinstance(response, dict):
                if isinstance(response, QUrl):
                    return self.link_clicked(response)
            #                    url = response.path()
            #                    print('window url', url)
            #                    return self.render(url)
            #                else:
            #                    # need error page
            #                    return self.render('/login')

            logger.debug("response: %s" % response)

            template = self.tempalte_lookup.get_template(self.config.get_route(url).get("renderer"))

            response["request"] = context_obj
            response["base_uri"] = self.base_uri
            html = template.render(**response)

            self.web_view.setHtml(html, QUrl("file://" + url))
            # self.web_view.setHtml(html)
            # self.web_view.load(a)

    def welcome(self):
        context_obj = context.ResourceContext(self.config, self.session)
        return self.link_clicked(context_obj.redirect_url("login"))
Beispiel #48
0
class Spdom(WizardWidget):
    drag_label = "Spatial Domain <spdom>"
    acceptable_tags = ["spdom", "bounding"]
    ui_class = UI_spdom.Ui_fgdc_spdom

    def __init__(self, root_widget=None):

        self.east = 180
        self.west = -180
        self.north = 90
        self.south = -90
        self.valid = True

        super(self.__class__, self).__init__()
        self.schema = "bdp"
        self.root_widget = root_widget

        self.after_load = False
        self.in_xml_load = False
        self.has_rect = True

        self.completer = QCompleter()
        self.ui.fgdc_descgeog.setCompleter(self.completer)

        self.model = QStringListModel()
        self.completer.setModel(self.model)
        self.completer.setCaseSensitivity(0)

        fname = utils.get_resource_path("spatial/BNDCoords.csv")
        self.bnds_df = pd.read_csv(fname)
        self.model.setStringList(self.bnds_df["Name"])

        self.completer.popup().clicked.connect(self.on_completer_activated)
        self.completer.popup().selectionModel().selectionChanged.connect(
            self.on_completer_activated)
        # self.completer.popup().activated.connect(self.on_completer_activated)

    def build_ui(self):
        """
        Build and modify this widget's GUI

        Returns
        -------
        None
        """
        self.ui = self.ui_class()
        self.ui.setupUi(self)

        if platform.system() == "Darwin":
            map_fname = utils.get_resource_path("leaflet/map_mac.html")
        else:
            map_fname = utils.get_resource_path("leaflet/map.html")

        try:
            self.view = QWebView()
            self.view.page().mainFrame().addToJavaScriptWindowObject(
                "Spdom", self)
            self.view.setUrl(QUrl.fromLocalFile(map_fname))
            self.frame = self.view.page().mainFrame()
            self.view.load(
                QUrl.fromLocalFile(QtCore.QDir.current().filePath(map_fname)))
        except AttributeError:
            self.view = QWebView()
            self.view.load(
                QUrl.fromLocalFile(QtCore.QDir.current().filePath(map_fname)))
            channel = QWebChannel(self.view.page())

            jstr = """
            var spdom;

            new QWebChannel(qt.webChannelTransport, function (channel) {
                spdom = channel.objects.spdom;
            });"""

            self.view.page().setWebChannel(channel)
            self.evaluate_js(jstr)
            channel.registerObject("spdom", self)

        self.ui.verticalLayout_3.addWidget(self.view)

        # setup drag-drop functionality for this widget and all it's children.
        self.setup_dragdrop(self)
        self.add_rect()
        self.raise_()

    def connect_events(self):
        self.ui.fgdc_eastbc.editingFinished.connect(self.coord_updated)
        self.ui.fgdc_westbc.editingFinished.connect(self.coord_updated)
        self.ui.fgdc_northbc.editingFinished.connect(self.coord_updated)
        self.ui.fgdc_southbc.editingFinished.connect(self.coord_updated)

    def on_completer_activated(self, model_index):

        try:
            cur_descgeog = model_index.data()
        except AttributeError:
            try:
                cur_descgeog = model_index.indexes()[0].data()
            except:
                return

        try:
            if self.bnds_df["Name"].str.contains(cur_descgeog).any():
                self.ui.fgdc_eastbc.setText(
                    str(
                        float(self.bnds_df[self.bnds_df["Name"] ==
                                           cur_descgeog]["east"])))
                self.ui.fgdc_westbc.setText(
                    str(
                        float(self.bnds_df[self.bnds_df["Name"] ==
                                           cur_descgeog]["west"])))
                self.ui.fgdc_northbc.setText(
                    str(
                        float(self.bnds_df[self.bnds_df["Name"] ==
                                           cur_descgeog]["north"])))
                self.ui.fgdc_southbc.setText(
                    str(
                        float(self.bnds_df[self.bnds_df["Name"] ==
                                           cur_descgeog]["south"])))
                self.add_rect()
                self.update_map()
        except:
            pass
            # this is a convenience function.
            # If anything at all happens pass silently

    def complete_name(self):
        self.view.page().runJavaScript("addRect();", js_callback)

    def coord_updated(self):

        good_coords = self.all_good_coords()

        try:
            cur_name = self.sender().objectName()
            if "fgdc" not in cur_name:
                return
            cur_value = self.sender().text()
        except AttributeError:
            cur_name = ""
            cur_value = ""

        try:
            cur_value = float(cur_value)
        except ValueError:
            pass

        msg = ""
        if type(cur_value) != float and cur_value != "":
            msg = "number entered must be numeric only"
        elif cur_value == "":
            msg = ""
        elif cur_name in ["fgdc_westbc", "fgdc_eastbc"
                          ] and -180 >= cur_value >= 180:
            msg = "East or West coordinate must be within -180 and 180"
        elif cur_name in ["fgdc_southbc", "fgdc_northbc"
                          ] and -90 >= cur_value >= 90:
            msg = "North and South coordinates must be within -90 and 90"
        elif cur_name == "fgdc_southbc":
            try:
                north = float(self.ui.fgdc_northbc.text())
                if north <= cur_value:
                    msg = "North coordinate must be greater than South coordinate"
            except ValueError:
                pass
        elif cur_name == "fgdc_northbc":
            try:
                south = float(self.ui.fgdc_southbc.text())
                if south >= cur_value:
                    msg = "North coordinate must be greater than South coordinate"
            except ValueError:
                pass

        if msg:
            QMessageBox.warning(self, "Problem bounding coordinates", msg)

        if good_coords:
            self.add_rect()
        else:
            self.remove_rect()
            return

        self.update_map()

    def update_map(self):
        jstr = """east = {eastbc};
        west = {westbc};
        south = {southbc};
        north = {northbc};
        updateMap();
        fitMap();
        """.format(
            **{
                "eastbc": self.ui.fgdc_eastbc.text(),
                "westbc": self.ui.fgdc_westbc.text(),
                "northbc": self.ui.fgdc_northbc.text(),
                "southbc": self.ui.fgdc_southbc.text(),
            })
        self.evaluate_js(jstr)

    def add_rect(self):
        jstr = """addRect();"""
        self.evaluate_js(jstr)

    def remove_rect(self):
        if self.has_rect:
            self.has_rect = False
            jstr = """removeRect()"""
            self.evaluate_js(jstr)

    def evaluate_js(self, jstr):
        """

        :param jstr:
        :return:
        """
        try:
            self.frame.evaluateJavaScript(jstr)
        except:
            self.view.page().runJavaScript(jstr, js_callback)

    @pyqtSlot(float, float)
    def on_ne_move(self, lat, lng):
        if self.in_xml_load:
            n, e = lat, lng
            try:
                s = float(self.ui.fgdc_southbc.text())
                w = float(self.ui.fgdc_westbc.text())
                bounds = spatial_utils.format_bounding((w, e, n, s))

                self.ui.fgdc_eastbc.setText(bounds[1])
                self.ui.fgdc_northbc.setText(bounds[2])
            except:
                pass

    @pyqtSlot(float, float)
    def on_nw_move(self, lat, lng):
        if self.in_xml_load:
            n, w = lat, lng
            try:
                s = float(self.ui.fgdc_southbc.text())
                e = float(self.ui.fgdc_eastbc.text())
                bounds = spatial_utils.format_bounding((w, e, n, s))

                self.ui.fgdc_westbc.setText(bounds[0])
                self.ui.fgdc_northbc.setText(bounds[2])
            except:
                pass

    @pyqtSlot(float, float)
    def on_se_move(self, lat, lng):
        if self.in_xml_load:
            s, e = lat, lng
            try:
                n = float(self.ui.fgdc_northbc.text())
                w = float(self.ui.fgdc_westbc.text())
                bounds = spatial_utils.format_bounding((w, e, n, s))

                self.ui.fgdc_eastbc.setText(bounds[1])
                self.ui.fgdc_southbc.setText(bounds[3])
            except:
                pass

    @pyqtSlot(float, float)
    def on_sw_move(self, lat, lng):
        if self.in_xml_load:
            s, w = lat, lng
            try:
                n = float(self.ui.fgdc_northbc.text())
                e = float(self.ui.fgdc_eastbc.text())
                bounds = spatial_utils.format_bounding((w, e, n, s))

                self.ui.fgdc_westbc.setText(bounds[0])
                self.ui.fgdc_southbc.setText(bounds[3])
            except:
                pass

    def switch_schema(self, schema):
        self.schema = schema
        if schema == "bdp":
            self.ui.fgdc_descgeog.show()
            self.ui.descgeog_label.show()
            self.ui.descgeog_star.show()
        else:
            self.ui.fgdc_descgeog.hide()
            self.ui.descgeog_label.hide()
            self.ui.descgeog_star.hide()

    def all_good_coords(self):
        try:
            if -180 > float(self.ui.fgdc_westbc.text()) > 180:
                return False
            if -180 > float(self.ui.fgdc_eastbc.text()) > 180:
                return False
            if -90 > float(self.ui.fgdc_southbc.text()) > 90:
                return False
            if -90 > float(self.ui.fgdc_northbc.text()) > 90:
                return False
            if float(self.ui.fgdc_northbc.text()) <= float(
                    self.ui.fgdc_southbc.text()):
                return False
            return True
        except:
            return False

    def clear_widget(self):
        super(self.__class__, self).clear_widget()

        # self.view.page().mainFrame().addToJavaScriptWindowObject("Spdom", self)
        # map_fname = utils.get_resource_path('leaflet/map.html')
        # self.view.setUrl(QUrl.fromLocalFile(map_fname))

    def showEvent(self, e):
        if not self.after_load:
            self.add_rect()
            self.update_map()
            jstr = "sw_marker.openPopup();"
            self.evaluate_js(jstr)
            self.after_load = True

    def to_xml(self):
        spdom = xml_node("spdom")

        if self.schema == "bdp":
            descgeog = xml_node("descgeog",
                                text=self.ui.fgdc_descgeog.text(),
                                parent_node=spdom)

        bounding = xml_node("bounding", parent_node=spdom)
        westbc = xml_node("westbc",
                          text=self.ui.fgdc_westbc.text(),
                          parent_node=bounding)
        eastbc = xml_node("eastbc",
                          text=self.ui.fgdc_eastbc.text(),
                          parent_node=bounding)
        northbc = xml_node("northbc",
                           text=self.ui.fgdc_northbc.text(),
                           parent_node=bounding)
        southbc = xml_node("southbc",
                           text=self.ui.fgdc_southbc.text(),
                           parent_node=bounding)

        if self.original_xml is not None:
            boundalt = xml_utils.search_xpath(self.original_xml,
                                              "bounding/boundalt")
            if boundalt is not None:
                spdom.append(deepcopy(boundalt))

            dsgpoly_list = xml_utils.search_xpath(self.original_xml,
                                                  "dsgpoly",
                                                  only_first=False)
            for dsgpoly in dsgpoly_list:
                spdom.append(deepcopy(dsgpoly))

        return spdom

    def from_xml(self, spdom):
        self.in_xml_load = False
        self.original_xml = spdom
        self.clear_widget()
        utils.populate_widget(self, spdom)

        contents = xml_utils.node_to_dict(spdom, add_fgdc=False)
        if "bounding" in contents:
            contents = contents["bounding"]

        try:
            if self.all_good_coords():
                self.add_rect()
                self.update_map()
            else:
                self.remove_rect()
        except KeyError:
            self.remove_rect()
        self.in_xml_load = True
Beispiel #49
0
class Application(object):

    settings = None
    html_template = None
    geometry = None

    loaded_plugins = None
    command_handlers = None

    metadata = None

    def _on_navigation(self, url):
        url = str(url.toString())
        handler, cmd = url.split('::')
        if handler and handler in self.command_handlers:
            return self.command_handlers[handler].handle(cmd)
        else:
            self.web_view.load(QUrl(url))
            return False

    def render_template(self):
        metadata = self.metadata
        output = self.html_template
        # @TODO: create shell::{some command} parser
        # MSG = MSG.replace('%UNAME%', shell_cmd('uname -a').decode('UTF-8'))
        if metadata:
            output = output.replace('%ARTIST%', metadata['artist'])
            output = output.replace('%ALBUM%', metadata['album'])
            output = output.replace('%TITLE%', metadata['title'])
            output = output.replace('%ARTURL%', metadata['arturl'])
        self.web_view.setHtml(output)

    def _read_config(self):
        # @TODO: here it will be config parsing, now it's a placeholder

        self.settings = SETTINGS

        try:
            self.html_template = open('index.html', 'r').read()
        except Exception:
            print('Error in template')
            self.html_template = DEFAULT_MSG

        left = self.settings.get(
            "left",
            self.app.desktop().screenGeometry().width() -
            self.settings["right"] - self.settings["width"]
        )
        self.settings['geometry'] = (
            left, self.settings["top"],
            self.settings["width"], self.settings["height"]
        )
        self.html_template = self.html_template.replace(
            '%WIDTH%', str(self.settings["width"]))
        self.html_template = self.html_template.replace('%PATH%', APP_PATH)

    def __init__(self):

        self.app = QApplication(sys.argv)
        self.window = QMainWindow()

        self.metadata = {}
        self.command_handlers = {}
        self._read_config()

        if get_desktop_name() in ['openbox', 'pekwm']:
            # windowAttribute for openbox/pekwm WM
            self.window.setAttribute(Qt.WA_X11NetWmWindowTypeDesktop)
        else:
            # windowAttribute for any other DE like xfce, gnome, unity, kde etc
            self.window.setAttribute(Qt.WA_X11NetWmWindowTypeDock)
            self.window.setWindowFlags(Qt.WindowStaysOnBottomHint)
        self.window.setAttribute(Qt.WA_TranslucentBackground)

        self.web_view = QWebView()

        # trasparent webview
        palette = self.web_view.palette()
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.web_view.page().setPalette(palette)

        self.web_view.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.web_view.linkClicked.connect(self._on_navigation)
        self.web_view.setHtml(self.html_template)

        self.window.setGeometry(*self.settings['geometry'])
        self.window.setCentralWidget(self.web_view)
        self.window.show()

        self.loaded_plugins = [
            CmdHandler(self),
            ClementineDBusInterface(self),
        ]

        sys.exit(self.app.exec_())
Beispiel #50
0
class HelpWidget(QWidget) :

    def __init__( self ) :
        super().__init__() # no parent; we are a standalone window
        # Set window title to translated value
        self.setWindowTitle(
            _TR( "title of help viewer window", "PPQT Help Viewer" ) )
        # Initialize saved geometry, see showEvent()
        self.last_shape = None
        # Initialize find string, see find_action().
        self.find_text = None
        self.view = QWebView()
        hb = QHBoxLayout()
        hb.addWidget(self.view)
        self.setLayout(hb)
        # Look for the help text file and load it if found.
        paths.notify_me( self.path_change )
        self.help_url = None
        self.path_change( ) # force a load now

    # Slot to receive the pathChanged signal from the paths module. That
    # signal is given when any of the standard paths are changed. Use the
    # extras path to (re)load the help file.
    #
    # This is also called from __init__ to do the initial load, and from
    # keyEvent processing to implement Back when the history stack is empty.
    #
    # The file we need to load is not actually ppqt2help.html but the
    # file sphinx/index.html. QWebView only shows the nice trimmings if we
    # open that.

    def path_change( self, code='extras' ) :
        if code == 'extras' :
            extras_path = paths.get_extras_path()
            help_path = os.path.join( extras_path , 'ppqt2help.html' )
            sphinx_path = os.path.join( extras_path, 'sphinx', 'index.html' )
            if os.access( help_path, os.R_OK ) and os.access( sphinx_path, os.R_OK ) :
                # the help file exists. Save a QUrl describing it, and load it.
                self.help_url = QUrl.fromLocalFile( sphinx_path )
                self.view.load( self.help_url )
            else :
                self.help_url = None
                self.view.setHtml( DEFAULT_HTML )

    def closeEvent( self, event ) :
        self.last_shape = self.saveGeometry()
        event.ignore()
        self.hide()
        return super().closeEvent(event)

    def showEvent( self, event ) :
        if self.last_shape : # is not None
            self.restoreGeometry( self.last_shape )

    def keyPressEvent( self, event ) :
        kkey = int( int(event.modifiers()) & C.KEYPAD_MOD_CLEAR) | int(event.key() )
        if kkey == C.CTL_F :
            event.accept()
            self.find_action()
        elif kkey == C.CTL_G :
            event.accept()
            self.find_next_action()
        elif kkey == C.CTL_SHFT_G :
            event.accept()
            self.find_prior_action()
        elif kkey in C.KEYS_WEB_BACK :
            event.accept()
            if self.view.history().canGoBack() :
                self.view.history().back()
            elif self.help_url is not None:
                self.view.load( self.help_url )
            else: # try to reload the default text
                self.path_change()
        elif kkey in C.KEYS_WEB_FORWARD :
            if self.view.history().canGoForward() :
                self.view.history().forward()
            else:
                utilities.beep()
        else :
            super().keyPressEvent(event)

    # Methods for a basic Find operation. Other modules e.g. noteview have a
    # custom Edit menu with Find/Next as menu actions. Here we do not support
    # any editing actions, so support Find/Next/Prior only via keystrokes.
    #
    # Use the simple find dialog in utilities to get a string to look for.
    # Initialize the dialog with up to 40 chars of the current selection. If
    # the user clicks Cancel in the Find dialog, self.find_text is None; if
    # the user just clears the input area and clicks OK the find_text is an
    # empty string. In either case do nothing.
    #
    # Following a successful find, the found text is selected in the view, so
    # if you do ^f again without disturbing that selection, that text is back
    # in the dialog to be used or replaced. So ^f+Enter is the same as ^g.

    FIND_NORMAL = QWebPage.FindWrapsAroundDocument
    FIND_PRIOR = QWebPage.FindWrapsAroundDocument | QWebPage.FindBackward


    def find_action(self):
        prep_text = self.view.selectedText()[:40]
        self.find_text = utilities.get_find_string(
            _TR('Help viewer find dialog','Text to find'),
            self, prep_text)
        if self.find_text : # is not None nor an empty string
            self._do_find( self.FIND_NORMAL )

    # For ^g Find Next, if there is no active find-text pretend that ^f was
    # hit. If there was a prior search, repeat the search.
    def find_next_action(self):
        if self.find_text : # is not None nor an empty string
            self._do_find( self.FIND_NORMAL )
        else :
            self.find_action()

    # for ^G Find Prior, same as for ^g but backward.
    def find_prior_action(self):
        if self.find_text :
            self._do_find( self.FIND_PRIOR )
        else :
            self.find_action()

    # The actual search, factored out of the above actions. Because the
    # search wraps around, if it fails, it fails, and that's that.

    def _do_find( self, find_flags ) :
        if not self.view.page().findText( self.find_text, find_flags ):
            utilities.beep()
class BrowserController(QObject):

    def __init__(self, parent, fullscreen, sizes):
        """
        This constructor function initializes a layout of the Arius output
        module but doesn`t displays it on the screen.

        Firstly, it creates a new app and detects screens configuration.
        Then, QGridLayout is created and its appearance is configured: margins
        and spaces between elements is set to 0.

        After that, we create three QWebViews: one for our main content view
        and two others for header and footer views.

        Immideately after creating these instances we assign them their heights
        according to percentages given by user and dimensions of the screen.

        Next, we remove scroll bars from top and bottom views and load predefined
        pages into them.

        Then we allow QWebKit to run all extensions it needs to render the page.

        After that, wee set the layout design as a grid of three rows.

        Finally, we create an updater object which will run in another stream and
        a timer instance which checks that stream for new commands
        from the server, and in case if there`s some update handles it.
        """
        super(BrowserController, self).__init__()
        if not fullscreen and not sizes:
            print 'You must initialize windows size'
            raise Exception
        self._fullscreen = fullscreen
        if sizes:
            self._screen_width = sizes[0]
            self._screen_height = sizes[1]
        self._app = QtWidgets.QApplication(sys.argv)
        self._app.setStyle("Fusion")
        if self._fullscreen:
            self._get_screen_height()

        self._layout = QGridLayout()
        self._layout.setSpacing(0)
        self._layout.setContentsMargins(0, 0, 0, 0)

        self._main_browser = QWebView()
        main_page = FakePage(self)
        self._main_browser.setPage(main_page)

        self._top_browser = QWebView()
        self._bottom_browser = QWebView()

        self._top_browser_height = config['output_header_height'] * self._screen_height
        self._bottom_browser_height = config['output_footer_height'] * self._screen_height

        self._top_browser.setMaximumHeight(self._top_browser_height)
        self._top_browser.setMinimumHeight(self._top_browser_height)

        self._bottom_browser.setMaximumHeight(self._bottom_browser_height)
        self._bottom_browser.setMinimumHeight(self._bottom_browser_height)

        self._top_browser.page().mainFrame().setScrollBarPolicy(
            QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)
        self._main_browser.page().mainFrame().setScrollBarPolicy(
            QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)
        self._main_browser.page().mainFrame().setScrollBarPolicy(
            QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
        self._bottom_browser.page().mainFrame().setScrollBarPolicy(
            QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)

        self._top_browser_load_url(
            config['flask_server_home'] + config['output_browser_top_page'])
        self._bottom_browser_load_url(
            config['flask_server_home'] + config['output_browser_bottom_page'])

        self._main_browser.settings().setAttribute(
            QWebSettings.DeveloperExtrasEnabled, True)
        self._main_browser.settings().setAttribute(QWebSettings.PluginsEnabled, True)
        QWebSettings.setObjectCacheCapacities(0, 0, 0)
        self._main_browser.settings().setAttribute(
            QWebSettings.AcceleratedCompositingEnabled, True)
        self._main_browser.settings().setAttribute(QWebSettings.WebGLEnabled, True)

        self._layout.addWidget(self._top_browser, 1, 0)
        self._layout.addWidget(self._main_browser, 2, 0)
        self._layout.addWidget(self._bottom_browser, 3, 0)
        self._parent = parent
        self._parent.load_url.connect(self._load_url)
        self._parent.js_execution.connect(self._execute_js)
        self._parent.zooming.connect(self._zoom)

    def run(self):
        self._main_window = QWidget()  # create a window as a QWidget
        self._main_window.setLayout(self._layout)  # assign a layout to it
        if self._fullscreen:
            self._main_window.showFullScreen()  # set full screen enabled
        else:
            self._main_window.resize(self._screen_width, self._screen_height)
        self._main_window.show()  # and finally, show the window
        # and set a trigger to exit the app, as window is closed
        sys.exit(self._app.exec_())

    def _get_screen_height(self):
        if self._fullscreen:
            output = subprocess.Popen('xrandr | grep "\*" | cut -d" " -f4',
                                      shell=True, stdout=subprocess.PIPE).communicate()[0]
            output = [int(val) for val in output.split('x')]
            self._screen_height = output[1]
            self._screen_width = output[0]
        else:
            output = [self._width, self._height]
        return output[0], output[1]

    def _zoom(self, factor):
        self._main_browser.page().mainFrame().setZoomFactor(factor)

    def _top_browser_load_url(self, url):
        self._top_browser.load(QUrl(url))

    def _bottom_browser_load_url(self, url):
        self._bottom_browser.load(QUrl(url))

    def _load_url(self, url):
        logger.debug('OPENING URL %s', url)
        self._main_browser.load(QUrl(url))

    def _execute_js(self, string_js):
        logger.debug(string_js)
        self._main_browser.page().mainFrame().evaluateJavaScript(string_js)
Beispiel #52
0
class WebBrowser(QMainWindow):

    adjTitle = pyqtSignal(str)
    setProg = pyqtSignal(int)
    finishLoad = pyqtSignal(str)

    def __init__(self, url, parent=None):
        super(WebBrowser, self).__init__(parent)

        self.progress = 0

        fd = QFile(":/jquery.min.js")

        if fd.open(QIODevice.ReadOnly | QFile.Text):
            self.jQuery = QTextStream(fd).readAll()
            fd.close()
        else:
            self.jQuery = ''

        QNetworkProxyFactory.setUseSystemConfiguration(True)

        self.view = QWebEngineView(self)
        self.view.load(QUrl(url))
        self.view.loadFinished.connect(self.adjustLocation)
        self.view.titleChanged.connect(self.adjustTitle)
        self.view.loadProgress.connect(self.setProgress)
        self.view.loadFinished.connect(self.finishLoading)

        self.locationEdit = QLineEdit(self)
        self.locationEdit.setSizePolicy(
            QSizePolicy.Expanding,
            self.locationEdit.sizePolicy().verticalPolicy())
        self.locationEdit.returnPressed.connect(self.changeLocation)

        toolBar = self.addToolBar("Navigation")
        toolBar.addAction(self.view.pageAction(QWebEnginePage.Back))
        toolBar.addAction(self.view.pageAction(QWebEnginePage.Forward))
        toolBar.addAction(self.view.pageAction(QWebEnginePage.Reload))
        toolBar.addAction(self.view.pageAction(QWebEnginePage.Stop))
        toolBar.addWidget(self.locationEdit)

        viewMenu = self.menuBar().addMenu("&View")
        viewSourceAction = QAction("Page Source", self)
        viewSourceAction.triggered.connect(self.viewSource)
        viewMenu.addAction(viewSourceAction)

        effectMenu = self.menuBar().addMenu("&Effect")
        effectMenu.addAction("Highlight all links", self.highlightAllLinks)

        self.rotateAction = QAction(self.style().standardIcon(
            QStyle.SP_FileDialogDetailedView),
                                    "Turn images upside down",
                                    self,
                                    checkable=True,
                                    toggled=self.rotateImages)
        effectMenu.addAction(self.rotateAction)

        toolsMenu = self.menuBar().addMenu("&Tools")
        toolsMenu.addAction("Remove GIF images", self.removeGifImages)
        toolsMenu.addAction("Remove all inline frames",
                            self.removeInlineFrames)
        toolsMenu.addAction("Remove all object elements",
                            self.removeObjectElements)
        toolsMenu.addAction("Remove all embedded elements",
                            self.removeEmbeddedElements)
        self.setCentralWidget(self.view)

    def viewSource(self):
        accessManager = self.view.page().networkAccessManager()
        request = QNetworkRequest(self.view.url())
        reply = accessManager.get(request)
        reply.finished.connect(self.slotSourceDownloaded)

    def slotSourceDownloaded(self):
        reply = self.sender()
        self.textEdit = QTextEdit()
        self.textEdit.setAttribute(Qt.WA_DeleteOnClose)
        self.textEdit.show()
        self.textEdit.setPlainText(QTextStream(reply).readAll())
        self.textEdit.resize(600, 400)
        reply.deleteLater()

    def adjustLocation(self):
        self.locationEdit.setText(self.view.url().toString())

    def changeLocation(self):
        url = QUrl.fromUserInput(self.locationEdit.text())
        self.view.load(url)
        self.view.setFocus()

    def adjustTitle(self):
        if 0 < self.progress < 100:
            self.setWindowTitle("{0} ({1}%%)".format(self.view.title(),
                                                     self.progress))
        else:
            self.setWindowTitle(self.view.title())

    def setProgress(self, p):
        self.progress = p
        self.setProg.emit(self.progress)
        self.adjustTitle()

    def finishLoading(self):
        self.progress = 100
        self.adjustTitle()
        # self.view.page().mainFrame().evaluateJavaScript(self.jQuery)
        self.rotateImages(self.rotateAction.isChecked())

    def highlightAllLinks(self):
        code = """$('a').each(
                    function () {
                        $(this).css('background-color', 'yellow') 
                    } 
                  )"""
        self.view.page().javaScriptPrompt(code)

    def rotateImages(self, invert):
        if invert:
            code = """
                $('img').each(
                    function () {
                        $(this).css('-webkit-transition', '-webkit-transform 2s'); 
                        $(this).css('-webkit-transform', 'rotate(180deg)') 
                    } 
                )"""
        else:
            code = """
                $('img').each(
                    function () { 
                        $(this).css('-webkit-transition', '-webkit-transform 2s'); 
                        $(this).css('-webkit-transform', 'rotate(0deg)') 
                    } 
                )"""

        # self.view.page().mainFrame().evaluateJavaScript(code)

    def removeGifImages(self):
        code = "$('[src*=gif]').remove()"
        self.view.page().runJavaScript(code)

    def removeInlineFrames(self):
        code = "$('iframe').remove()"
        self.view.page().runJavaScript(code)

    def removeObjectElements(self):
        code = "$('object').remove()"
        self.view.page().runJavaScript(code)

    def removeEmbeddedElements(self):
        code = "$('embed').remove()"
        self.view.page().runJavaScript(code)
Beispiel #53
0
        ba = len(self.content) - self.bytes_read + super().bytesAvailable()
        return ba

    def readData(self, size):
        if self.bytes_read >= len(self.content):
            return None
        data = self.content[self.bytes_read:self.bytes_read + size]
        self.bytes_read += len(data)
        return data

    def manager(self):
        return self.parent()

if __name__ == '__main__':
    app = QApplication(sys.argv)

    gs = QtWebKit.QWebSettings.globalSettings()
    gs.setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True)
    gs.setAttribute(QtWebKit.QWebSettings.JavascriptEnabled, True)
    gs.setAttribute(QtWebKit.QWebSettings.AutoLoadImages, True)
    gs.setAttribute(QtWebKit.QWebSettings.JavascriptCanOpenWindows, True)
    gs.setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)
    gs.setAttribute(QtWebKit.QWebSettings.LocalContentCanAccessRemoteUrls, True)

    wv = QWebView()
    enam = NetworkAccessManager()
    wv.page().setNetworkAccessManager(enam)
    wv.show()
    wv.setUrl(QUrl("http://localhost/"))
    app.exec()
Beispiel #54
0
class OutputInterface:

    def __init__(self, fullscreen=False, sizes=None):
        """
        This constructor function initializes a layout of the Arius output
        module but doesn`t displays it on the screen.

        Firstly, it creates a new app and detects screens configuration.
        Then, QGridLayout is created and its appearance is configured: margins
        and spaces between elements is set to 0.

        After that, we create three QWebViews: one for our main content view
        and two others for header and footer views.

        Immideately after creating these instances we assign them their heights
        according to percentages given by user and dimensions of the screen.

        Next, we remove scroll bars from top and bottom views and load predefined
        pages into them.

        Then we allow QWebKit to run all extensions it needs to render the page.

        After that, wee set the layout design as a grid of three rows.

        Finally, we create an updater object which will run in another stream and
        a timer instance which checks that stream for new commands
        from the server, and in case if there`s some update handles it.
        """
        if not fullscreen and not sizes:
            print 'You must initialize windows size'
            raise Exception
        self._fullscreen = fullscreen
        if sizes:
            self._screen_width = sizes[0]
            self._screen_height = sizes[1]
        self._app = QtWidgets.QApplication(sys.argv)
        self._app.setStyle("Fusion")
        if self._fullscreen:
            self._get_screen_height()

        self._layout = QGridLayout()  # create a main view of an app
        self._layout.setSpacing(0)  # and do some design settings
        self._layout.setContentsMargins(0, 0, 0, 0)

        self._main_browser = QWebView()  # create a main content view
        # and initialize zoom factor variable which will be used to control
        # zoom
        main_page = FakeBrowser(self)
        self._main_browser.setPage(main_page)
        self._zoom_factor = 1

        self._top_browser = QWebView()  # and create top and bottom views
        self._bottom_browser = QWebView()

        self._top_browser_height = config[
            'output_header_height'] * self._screen_height  # calculate views sizes
        self._bottom_browser_height = config[
            'output_footer_height'] * self._screen_height

        self._top_browser.setMaximumHeight(
            self._top_browser_height)  # and assign them to the views
        self._top_browser.setMinimumHeight(self._top_browser_height)

        self._bottom_browser.setMaximumHeight(self._bottom_browser_height)
        self._bottom_browser.setMinimumHeight(self._bottom_browser_height)

        self._top_browser.page().mainFrame().setScrollBarPolicy(
            QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)  # remove the scroll bars
        self._main_browser.page().mainFrame().setScrollBarPolicy(QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)
        self._main_browser.page().mainFrame().setScrollBarPolicy(QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
        self._bottom_browser.page().mainFrame().setScrollBarPolicy(
            QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)

        self._top_browser_load_url(
            config['flask_server_home'] + config['output_browser_top_page'])  # load default design
        self._bottom_browser_load_url(
            config['flask_server_home'] + config['output_browser_bottom_page'])

        self._main_browser.settings().setAttribute(
            QWebSettings.DeveloperExtrasEnabled, True)  # enable console
        self._main_browser.settings().setAttribute(
            QWebSettings.PluginsEnabled, True)  # enable plugins
        QWebSettings.setObjectCacheCapacities(0, 0, 0)  # disable caching
        self._main_browser.settings().setAttribute(
            QWebSettings.AcceleratedCompositingEnabled, True)
        self._main_browser.settings().setAttribute(
            QWebSettings.WebGLEnabled, True)

        self._layout.addWidget(self._top_browser, 1, 0)  # set views positions
        self._layout.addWidget(self._main_browser, 2, 0)
        self._layout.addWidget(self._bottom_browser, 3, 0)

        # create a RLock object to syncronyze threads.
        self._lock = threading.RLock()
        # and create an updater object
        self._updater = OutputUpdater(self._lock)

        self._updater.start()  # which is ran in another non-blocking stream

        self.timeoutTimer = QTimer()  # create a timer to check for commands
        tCallback = functools.partial(
            self._handle_command)  # set a timer`s function
        self.timeoutTimer.timeout.connect(tCallback)
        self.timeoutTimer.start(
            config['output_update_frequency'])  # and start it

        # as no data is displayed on the main view - curent content type is
        # None
        self._cur_filetype = None

        # text to speech speaker
        self._speaker = None
        # audioplayer
        self._player = Player()

    def run(self):
        """
        This method is called to show the output module window
        after initializing all views in __init__.
        """
        self._main_window = QWidget()  # create a window as a QWidget
        self._main_window.setLayout(self._layout)  # assign a layout to it
        if self._fullscreen:
            self._main_window.showFullScreen()  # set full screen enabled
        else:
            self._main_window.resize(self._screen_width, self._screen_height)
        self._main_window.show()  # and finally, show the window
        # and set a trigger to exit the app, as window is closed
        sys.exit(self._app.exec_())
        logger.info('Finished')

    def _get_screen_height(self):
        """
        This method is used to get dimensions of user`s screen.
        To do this is uses system utilite 'xrandr' via subprocess module,
        which is not very nice way, however we didn`t find
        anything better.
        """
        if self._fullscreen:
            output = subprocess.Popen('xrandr | grep "\*" | cut -d" " -f4',
                                      shell=True, stdout=subprocess.PIPE).communicate()[0]
            output = [int(val) for val in output.split('x')]
            # logger.debug('Screen dimensions are: {} x {}'.format(output[0], output[1]))
            self._screen_height = output[1]
            self._screen_width = output[0]
        else:
            output = [self._width, self._height]
        return output[0], output[1]

    def _handle_command(self):
        """
        This is a method called by an updater timer each given interval of time.
        It checks updater object and in case if there`s some new command it proceeds it.
        """
        command = self._updater.get_state()  # get a new command
        if command[0] != 'none' and command[0] != None:  # if there`s a command, handle it
            logger.info('Handling command {}'.format(command))

            # self._updater.reset()  # clear the updater object command buffer

            # Commands for opening all types of content are handled by
            # calling of _load_content method with specified content type.

            # start music play if it was stopped

            if command[0] == 'OPEN_PDF':
                self._player.play()
                self._load_content('local_pdf', command[1])
            elif command[0] == 'OPEN_URL':
                self._player.play()
                self._load_content('external_url', command[1])
            elif command[0] == 'OPEN_LOCAL_PAGE':
                self._player.play()
                self._load_content('local_url', command[1])
            elif command[0] == 'OPEN_VIDEO':
                self._player.stop()
                self._load_content('local_video', command[1])

            # Command to open a system scren (e.g. {'type': 'OPEN_SCREEN', 'command':'OPEN_IDLE'})
            # will be proceeded by sending a 'command' to a _load_screen method, which does futher
            # work.

            elif command[0] == 'OPEN_SCREEN':
                self._player.play()
                self._load_screen(command[1])

            # Zoom commands are handled each with its own method.

            elif command[0] == 'ZOOM_IN':
                self._main_browser_zoom_in()
            elif command[0] == 'ZOOM_OUT':
                self._main_browser_zoom_out()
            elif command[0] == 'NO_ZOOM':
                self._main_browser_reset_zoom()

            # as well as scroll.

            elif command[0] == 'SCROLL_DOWN':
                self._main_browser_scroll_down()
            elif command[0] == 'SCROLL_UP':
                self._main_browser_scroll_up()

            elif command[0] == 'SCROLL_LEFT':
                self._main_browser_scroll_left()
            elif command[0] == 'SCROLL_RIGHT':
                self._main_browser_scroll_right()
            elif command[0] == 'CONTINIOUS_SCROLL_UP':
                pass
            elif command[0] == 'CONTINIOUS_SCROLL_DOWN':
                pass
            elif command[0] == 'STOP_SCROLL':
                pass
            # Following two commands are responsible for playing
            # video and pausing it. As a second part of the command
            # name of the video file should be given.

            elif command[0] == 'PLAY':
                self._player.stop()
                self._video_play()
            elif command[0] == 'PAUSE':
                self._video_pause()

            # These two commands are used for increasing or
            # decreasing video volume.

            elif command[0] == 'VOLUME_UP':
                self._volume_up()
            elif command[0] == 'VOLUME_DOWN':
                self._volume_down()

            # and these two are for text-to-speech
            # The 'command' body should be a text you
            # you want to hear.

            elif command[0] == "SPEAK":
                print 'SPEAK'
                self._player.play()
                self._speak_text(command[1])
            elif command[0] == "STOP_SPEAK":
                self._player.play()
                self._speak_stop()
            elif command[0] == 'NEXT_PAGE':
                self._main_browser_next_page()
            elif command[0] == 'PREV_PAGE':
                self._main_browser_prev_page()

            elif command[0] == 'MUTE':
                self._mute()
            elif command[0] == 'UNMUTE':
                self._unmute()
            else:
                logger.info('command not recognized {}'.format(command))
        else:
            pass

    def _load_screen(self, screen_type):
        """
        This method is responsible for opening system
        Arius screens. It receives a type of screen,
        server wants to open and then displays it on
        the main content view.
        """
        self._main_browser_reset_zoom()  # set zoom level to 1 in case if previous page was zoomed
        # this a default path to the arius server
        url = 'http://' + config['flask_server_address'] + \
            ':' + config['flask_server_port']
        if screen_type == 'IDLE':  # and here in depend of type of the required screen
            # we set the last path of the URL to the exact screen
            url = url + config['flask_server_idle_address']
        elif screen_type == 'ERROR':
            url = url + config['flask_server_error_address']
        elif screen_type == 'SEARCH':
            url = url + config['flask_server_search_address']
        elif screen_type == 'SPEAKING':
            url = url + config['flask_server_speaking_address']
        else:  # and if the target screen wasn`t recognized we can also handle it
            logger.info('WRONG SCREEN TYPE: {}'.format(screen_type))
        logger.debug(
            'Opening {} screen on following address {}'.format(screen_type, url))
        self._main_browser.load(QUrl(url))

    def _custom_ua(self, url):
        """
        This function returns a custom user agent data
        which is stored in config.py file as 'output_user_agent'
        """
        return config['output_user_agent']

    def _load_content(self, content_type, content):
        """
        This method is for displaying some content of
        such types: local web pages, remote web pages,
        local pdf`s, local videos.

        It should be called like in the following example
        to work correctly:
        self._load_content('local_video', 'some_video.mp4')
        """
        self._main_browser_reset_zoom()  # reset zoom
        if content_type == 'local_url':
            source = config['flask_server_home'] + \
                config['flask_server_local_page_client'] + \
                content  # simply get the file from flask-server by its relative path-id
            # specify type of currently opened file for zoom and scroll methods
            self._cur_filetype = "webpage"
        elif content_type == 'external_url':
            self._cur_filetype = "webpage"
            # no needs required as, link should be given in
            # 'http://yoursite.com/yourpage'
            source = content
        elif content_type == 'local_pdf':
            # to render PDF`s we use PDF.js, so we open its page and send it a
            # path for the target file.
            source = config['flask_server_home'] + \
                config['flask_server_local_page_client'] + \
                content
            self._cur_filetype = "pdf"
        elif content_type == 'local_video':
            # in case of opening local videos we need to modify the path to the video in the source code of
            # the videoplayer, so don`t die after reading this code. It works just in the same style as other
            # filetypes, but in a very weird way.
            source = config['flask_server_home'] + \
                config['flask_server_video_addr_client'] + content
            logger.info('Opening video at {}'.format(source))
            self._cur_filetype = "video"
        # Set a custom user agent to avoid message about deprecated version of
        # browser

        self._main_browser.page().userAgentForUrl = self._custom_ua

        logger.info('Loading data on address: {}'.format(source))

        # Create a request to be able to set user-agent data. Without
        # it, it`s impossible to customize request data.
        request = QNetworkRequest()
        request.setUrl(QUrl(source))
        request.setRawHeader("USER-AGENT", config['output_user_agent'])

        # and finally load the result
        self._main_browser.load(request)

    def _top_browser_load_url(self, url):
        """
        This method just loads a given URL in the top content view.
        URL must contain protocol and the address.
        e.g. http://placehold.it/400x200
        or
        file://data/somepage.html
        """
        logger.info('Loading {} to the top content view.'.format(url))
        self._top_browser.load(QUrl(url))

    def _bottom_browser_load_url(self, url):
        """
        This method just loads a given URL in the bottom content view.
        URL must contain protocol and the address.
        e.g. http://placehold.it/400x200
        or
        file:
        """
        logger.info('Loading {} to the bottom content view.'.format(url))
        self._bottom_browser.load(QUrl(url))

    def _main_browser_scroll_down(self):
        """
        This method is called to smoothly scroll the page down. In
        dependence of the current content type if provides different
        implementations of scroll, but generally it gives the same result.
        """
        logger.debug('Scrolling main content view down')
        scroll_js = open("scroll.js", "r").read()
        self._main_browser.page().mainFrame().evaluateJavaScript(scroll_js)
        if self._cur_filetype == "pdf":
            self._main_browser.page().mainFrame().evaluateJavaScript("smooth_vscroll_by(PDFViewerApplication.pdfViewer.container, 300, 1000);")
        elif self._cur_filetype == "webpage":
            self._main_browser.page().mainFrame().evaluateJavaScript("smooth_vscroll_by(document.body, 300, 1000);")

    def _main_browser_scroll_up(self):
        """
        This method is called to smoothly scroll the page up. In
        dependence of the current content type if provides different
        implementations of scroll, but generally it gives the same result.
        """
        logger.debug('Scrolling main content view down')
        scroll_js = open("scroll.js", "r").read()
        self._main_browser.page().mainFrame().evaluateJavaScript(scroll_js)
        if self._cur_filetype == "pdf":
            self._main_browser.page().mainFrame().evaluateJavaScript("smooth_vscroll_by(PDFViewerApplication.pdfViewer.container, -300, 1000);")
        elif self._cur_filetype == "webpage":
            self._main_browser.page().mainFrame().evaluateJavaScript("smooth_vscroll_by(document.body, -300, 1000);")

    def _main_browser_scroll_left(self):
        """
        This method is called to smoothly scroll the page left. In
        dependence of the current content type if provides different
        implementations of scroll, but generally it gives the same result.
        """
        logger.debug('Scrolling main content view left')
        scroll_js = open("scroll.js", "r").read()
        self._main_browser.page().mainFrame().evaluateJavaScript(scroll_js)
        if self._cur_filetype == "pdf":
            self._main_browser.page().mainFrame().evaluateJavaScript("smooth_hscroll_by(PDFViewerApplication.pdfViewer.container, -100, 1000);")
        elif self._cur_filetype == "webpage":
            self._main_browser.page().mainFrame().evaluateJavaScript("smooth_hscroll_by(document.body, -100, 1000);")

    def _main_browser_scroll_right(self):
        """
        This method is called to smoothly scroll the page right. In
        dependence of the current content type if provides different
        implementations of scroll, but generally it gives the same result.
        """
        logger.debug('Scrolling main content view right')
        scroll_js = open("scroll.js", "r").read()
        self._main_browser.page().mainFrame().evaluateJavaScript(scroll_js)
        if self._cur_filetype == "pdf":
            self._main_browser.page().mainFrame().evaluateJavaScript("smooth_hscroll_by(PDFViewerApplication.pdfViewer.container, 100, 1000);")
        elif self._cur_filetype == "webpage":
            self._main_browser.page().mainFrame().evaluateJavaScript("smooth_hscroll_by(document.body, 100, 1000);")

    def _main_browser_zoom_in(self):
        """
        This methoud simply zooms main content view in. It works
        well with all content types.
        """
        logger.debug('Zooming main content view in')
        if self._cur_filetype == "pdf":
            string_js = """PDFViewerApplication.zoomIn();"""
            self._main_browser.page().mainFrame().evaluateJavaScript(string_js)
        elif self._cur_filetype == "webpage":

            self._zoom_factor += .1
            self._main_browser.page().mainFrame().setZoomFactor(self._zoom_factor)

    def _main_browser_reset_zoom(self):
        """
        This method sets zoom level of the main content view to the default level.
        It should be called before loading a new page or in order to cancel any zoom
        changes.
        """
        logger.debug('Resetting zoom in the main content view')
        if self._cur_filetype == "pdf":
            string_js = 'PDFViewerApplication.pdfViewer.currentScaleValue = "page-width"'
            self._main_browser.page().mainFrame().evaluateJavaScript(string_js)
        elif self._cur_filetype == "webpage":
            self._zoom_factor = 1
            self._main_browser.page().mainFrame().setZoomFactor(self._zoom_factor)

    def _main_browser_zoom_out(self):
        """
        This methoud simply zooms main content view out. It works
        well with all content types.
        """
        logger.debug('Zooming main content view out')
        if self._cur_filetype == "pdf":
            string_js = """PDFViewerApplication.zoomOut();"""
            self._main_browser.page().mainFrame().evaluateJavaScript(string_js)
        elif self._cur_filetype == "webpage":
            self._zoom_factor -= .1
            self._main_browser.page().mainFrame().setZoomFactor(self._zoom_factor)

    def _main_browser_next_page(self):
        logger.debug('Next page')
        script_js = """PDFViewerApplication.page++;"""
        self._main_browser.page().mainFrame().evaluateJavaScript(script_js)

    def _main_browser_prev_page(self):
        logger.debug('Previous page')
        script_js = """PDFViewerApplication.page--;"""
        self._main_browser.page().mainFrame().evaluateJavaScript(script_js)

    def _speak_text(self, input_text):
        """
        This method is used to provide text-to-speech syntesizer for voice output.
        As a back-end of this method Mary TTS is used.
        Voices can be configured through config.py quit easy.
        """
        logger.info('Speaking following text {}'.format(input_text))
        if self._speaker is None:  # if there wasn`t no tts requests before, create a TTS client
            self._speaker = Speaker(config['default_voice'], config[
                                    "marytts_host"], config["marytts_port"])
        # otherwise just stop previous speaking session (if Arius isn`t
        # speaking at the moment, nothing will crash)
        else:
            self._speaker.stop()
        # and send given text as a tts request.
        self._speaker.speak(input_text)

    def _speak_stop(self):
        """
        This method simply stops current voice output.
        """
        logger.info('Stop speaking')
        self._speaker.stop()

    def _video_play(self):
        """
        This method is used to begin playing video on the current page.
        It should be run only if current content type is 'video'.
        """
        logger.debug('Playing video')
        if self._cur_filetype == 'video':
            script_js = """video=document.getElementById("arius_videoplayer"); video.play()"""
            self._main_browser.page().mainFrame().evaluateJavaScript(script_js)

    def _video_pause(self):
        """
        This method is used to pause currently playing video on the page.
        It should be run only if current content type is 'video'.
        """
        logger.debug('Video paused')
        if self._cur_filetype == 'video':
            script_js = """video=document.getElementById("arius_videoplayer"); video.pause()"""
            self._main_browser.page().mainFrame().evaluateJavaScript(script_js)

    def _volume_up(self):
        """
        This method is used to increase volume.
        It should be run only if current content type is 'video'.
        """
        logger.debug('Increasing volume')
        if self._cur_filetype == 'video':
            script_js = """video=document.getElementById("arius_videoplayer"); video.volume+=0.2;"""
            self._main_browser.page().mainFrame().evaluateJavaScript(script_js)

    def _volume_down(self):
        """
        This method is used to decrease volume.
        It should be run only if current content type is 'video'.
        """
        logger.debug('Decreasing volume')
        if self._cur_filetype == 'video':
            script_js = """video=document.getElementById("arius_videoplayer"); video.volume-=0.2;"""
            self._main_browser.page().mainFrame().evaluateJavaScript(script_js)

    def _mute(self):
        if self._player:
            self._player.mute()
        if self._speaker:
            self._speaker.mute()

    def _unmute(self):
        if self._player:
            self._player.unmute()
        if self._speaker:
            self._speaker.unmute()
Beispiel #55
0
class Printing(QObject):

    def __init__(self, iterator, parent):
        QObject.__init__(self, parent)
        self.current_index = 0
        self.iterator = iterator
        self.view = QWebView(self.parent())
        self.mf = mf = self.view.page().mainFrame()
        for x in (Qt.Horizontal, Qt.Vertical):
            mf.setScrollBarPolicy(x, Qt.ScrollBarAlwaysOff)
        self.view.loadFinished.connect(self.load_finished)
        self.paged_js = compiled_coffeescript('ebooks.oeb.display.utils')
        self.paged_js += compiled_coffeescript('ebooks.oeb.display.paged')

    def load_finished(self, ok):
        self.loaded_ok = ok

    def start_print(self):
        self.pd = QPrintDialog(self.parent())
        self.pd.open(self._start_print)

    def _start_print(self):
        self.do_print(self.pd.printer())

    def start_preview(self):
        self.pd = QPrintPreviewDialog(self.parent())
        self.pd.paintRequested.connect(self.do_print)
        self.pd.exec_()

    def do_print(self, printer):
        painter = QPainter(printer)
        zoomx = printer.logicalDpiX()/self.view.logicalDpiX()
        zoomy = printer.logicalDpiY()/self.view.logicalDpiY()
        painter.scale(zoomx, zoomy)
        pr = printer.pageRect()
        self.view.page().setViewportSize(QSize(pr.width()/zoomx,
            pr.height()/zoomy))
        evaljs = self.mf.evaluateJavaScript
        loop = QEventLoop(self)
        pagenum = 0
        from_, to = printer.fromPage(), printer.toPage()
        first = True

        for path in self.iterator.spine:
            self.loaded_ok = None
            load_html(path, self.view, codec=getattr(path, 'encoding', 'utf-8'),
                    mime_type=getattr(path, 'mime_type', None))
            while self.loaded_ok is None:
                loop.processEvents(loop.ExcludeUserInputEvents)
            if not self.loaded_ok:
                return error_dialog(self.parent(), _('Failed to render'),
                        _('Failed to render document %s')%path, show=True)
            evaljs(self.paged_js)
            evaljs('''
                document.body.style.backgroundColor = "white";
                paged_display.set_geometry(1, 0, 0, 0);
                paged_display.layout();
                paged_display.fit_images();
            ''')

            while True:
                pagenum += 1
                if (pagenum >= from_ and (to == 0 or pagenum <= to)):
                    if not first:
                        printer.newPage()
                    first = False
                    self.mf.render(painter)
                try:
                    nsl = int(evaljs('paged_display.next_screen_location()'))
                except (TypeError, ValueError):
                    break
                if nsl <= 0:
                    break
                evaljs('window.scrollTo(%d, 0)'%nsl)

        painter.end()
Beispiel #56
0
class Window(BaseWindow):
    def __init__(self):
        self.debug=1
        self.app = QApplication(sys.argv)
        self.desktop= QApplication.desktop()
        self.web = QWebView()
        self.icon = QIcon(ICON)
        QWebSettings.setIconDatabasePath(DATA_DIR)
        self.web.setWindowIcon(self.icon)
        self.web.titleChanged.connect(self.title_changed)
        self.web.iconChanged.connect(self.icon_changed)
        self.web.page().windowCloseRequested.connect(self.close_window)
        self.web.page().geometryChangeRequested.connect(self.set_geometry)

    def show(self,window_state):
        if window_state == "maximized" and not self.web.isMaximized():
            self.web.showNormal()
            self.web.showMaximized()
        elif window_state == "fullscreen" and not self.web.isFullScreen():
            self.web.showNormal()
            self.web.showFullScreen()
        elif window_state == "normal":
            self.web.showNormal()
        else:
            self.web.show()

    def run(self):
        return self.app.exec_()

    def set_debug(self, debuglevel):
        self.debug=debuglevel

    def set_geometry(self,geom ):
        self.web.setGeometry(geom)

    def close_window(self):
        sys.exit()

    def icon_changed(self):
        if not self.icon.isNull():
            self.web.setWindowIcon(self.icon)
        if not self.web.icon().isNull():
            self.web.setWindowIcon(self.web.icon())

    def title_changed(self, title):
        if title:
            self.web.setWindowTitle(title)

    def load_url(self,url):
        self.url=QUrl.fromEncoded(url)
        self.web.setUrl(self.url)

    def set_size(self,width, height):
        if width<=0:
            width=640
        if height<=0:
            height=480

        left=(self.desktop.width()-width)/2
        top=(self.desktop.height()-height)/2

        self.web.setGeometry(left,top,width,height)
Beispiel #57
0
class CentralWidget(QWidget):

    l = logging.getLogger('CentralWidget')

    updateWindowTitle = pyqtSignal(str)

    def __init__(self, parentWidget, settings):
        QWidget.__init__(self, parentWidget)

        self.settings = settings
        self.theLayout = QHBoxLayout()
        self.splitter = QSplitter(self)
        self.theLayout.addWidget(self.splitter)

        self.browserWidget = BrowserWidget(self, self.settings)
        self.browserWidget.itemSelected.connect(self.itemSelected)

        self.tabWidget = QTabWidget(self)

        tab = QWidget()

        tabLayout = QVBoxLayout(tab)
        tab.setLayout(tabLayout)

        self.editorWidget = EditorWidget(tab)

        self.editorWidget.setObjectName("EditorWidget1")
        self.editorWidget.message.connect(self.showMessage)
        self.editorWidget.titleChanged.connect(self.updateWindowTitle)
        self.editorWidget.navigate.connect(self.navigate)

        tabLayout.addWidget(self.editorWidget)
        self.editTabIdx = self.tabWidget.addTab(tab, "Edit")
#############################

        self.browser = QWebView(self.tabWidget)
        self.browser.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        self.browser.linkClicked.connect(self.navigateWeb)
        self.webTabIdx = self.tabWidget.addTab(self.browser, "View web")

        self.pdfTabIdx = self.tabWidget.addTab(QWidget(self.tabWidget), "View pdf")

        self.textView = QTextEdit(self.tabWidget)
        self.textView.setReadOnly(True)
        self.textView.setFontFamily('Courier')
        self.textView.setFontPointSize(8)
        self.structureTabIdx = self.tabWidget.addTab(self.textView, "View document structure")

        self.customView = QTextEdit(self.tabWidget)
        self.customView.setReadOnly(True)
        self.customView.setFontFamily('Courier')
        self.customView.setFontPointSize(10)
        self.xmlTabIdx = self.tabWidget.addTab(self.customView, "View XML")

        self.htmlView = QTextEdit(self.tabWidget)
        self.htmlView.setReadOnly(True)
        self.htmlView.setFontFamily('Courier')
        self.htmlView.setFontPointSize(10)
        self.htmlTabIdx = self.tabWidget.addTab(self.htmlView, "View Html")

        self.tabWidget.currentChanged.connect(self.tabSelected)

# Search/Links widget in lower left corner ####################################
        self.searchWidget = SearchWidget(self)
        self.searchWidget.resultSelected.connect(self.navigateDirect)

        self.toLinksWidget = LinklistWidget(self)
        self.toLinksWidget.resultSelected.connect(self.navigateDirect)

        self.fromLinksWidget = LinklistWidget(self)
        self.fromLinksWidget.resultSelected.connect(self.navigateDirect)

        self.listsWidget = QTabWidget(self)
        self.listsWidget.addTab(self.searchWidget, 'Search')
        self.listsWidget.addTab(self.toLinksWidget, 'Links to')
        self.listsWidget.addTab(self.fromLinksWidget, 'Links from')
###############################################################################

        leftWidget = QSplitter(Qt.Vertical, self)
        leftWidget.addWidget(self.browserWidget)
        leftWidget.addWidget(self.listsWidget)

        self.splitter.addWidget(leftWidget)
        self.splitter.addWidget(self.tabWidget)
        leftWidget.setSizes([400, 100])             # TODO

        self.setLayout(self.theLayout)
        self.splitter.setSizes([100, 400])          # TODO
        # self.splitter.setChildrenCollapsible(False)
        self.editorWidget.setEnabled(False)


    def navigateWeb(self, url):
        if url.scheme() == 'file':
            pageId = url.fileName()
            self.navigate(pageId)
            self.tabSelected(1)
        elif url.scheme() == 'http' or url.scheme() == 'https':
            self.browser.setUrl(url)


    def showMessage(self, message):
        self.parent().statusBar.showMessage(message, 3000)


    def navigate(self, pageId):
        """Assumption: pageId is sub page of current page"""
        self.l.debug('Navigating to sub page "{}"'.format(pageId))

        self.editorWidget.save()
        self.browserWidget.navigate(pageId)        # Will implicitly load the page


    def navigateDirect(self, pageId):
        """Assumption: pageId is NOT sub page of current page. 
        Hence we need to let the browser point to the first occurrence of the page."""
        self.l.debug('Navigating directly to "{}"'.format(pageId))

        self.editorWidget.save()
        self.browserWidget.navigateDirect(pageId)   # Will implicitly load the page


    def itemSelected(self):
        treeNode = self.browserWidget.currentItem
        self.l.debug('Selected tree node: {}'.format(treeNode))

        pageId = treeNode.getPageId()
        notepad = treeNode.getNotepad()

        self.editorWidget.setEnabled(True)
        self.editorWidget.save()
        self.editorWidget.load(notepad, pageId)

        self.updateLinkLists(notepad, pageId)


    def updateLinkLists(self, notepad, pageId):
        
        linksTo = notepad.getChildPages(pageId)
        linksFrom = notepad.getParentPages(pageId)

        self.toLinksWidget.setContents(linksTo)
        self.fromLinksWidget.setContents(linksFrom)


    def tabSelected(self, index):
        if index == self.editTabIdx:
            pass
        elif index == self.webTabIdx:
            self.activateWebView()
        elif index == self.pdfTabIdx:
            pass
        elif index == self.structureTabIdx:
            self.activateStructureView()
        elif index == self.xmlTabIdx:
            self.activateXMLView()
        elif index == self.htmlTabIdx:
            self.activateHTMLView()


    def activateWebView(self):
        exporter = HTMLExporter(self.editorWidget.page.getPageDir())
        self.htmlView.setPlainText(exporter.getHtmlString(self.editorWidget.editView.document()))

        ########### get URL for the stylesheet and for the base URL

        webpageCSS = pkg_resources.resource_string(data.__name__, 'webpage.css')
        print("webpage.css file: {} - {}".format(webpageCSS, type(webpageCSS)))

        mypath = os.getcwd()
        mypath = mypath.replace('\\', '/')
        baseURL = QUrl('file:///{}/'.format(mypath))

        # The location must be either a path on the local filesystem, or a 
        # data URL with UTF-8 and Base64 encoded data, such as:
        # "data:text/css;charset=utf-8;base64,cCB7IGJhY2tncm91bmQtY29sb3I6IHJlZCB9Ow=="
        # BASE64 works on bytes!!
        import base64
        cssData = base64.b64encode(webpageCSS)
        cssData = cssData.decode('utf-8')
        cssDataUrl = 'data:text/css;charset=utf-8;base64,{}'.format(cssData)
        print("webpage.css base64: {}".format(cssDataUrl ))
        # cssDataUrl = QUrl('data:text/css;charset=utf-8;base64,{}'.format(cssData)) # 'file:///{}/webpage.css'.format(mypath))

        ###########

        self.browser.settings().setUserStyleSheetUrl(QUrl(cssDataUrl))

        self.browser.setHtml(self.htmlView.toPlainText(), baseURL)


    def activateStructureView(self):
        self.textView.clear()

        doc = self.editorWidget.editView.document()
        traversal = TextDocumentTraversal()
        tree = traversal.traverse(doc)
        
        sp = StructurePrinter(tree, self.textView.insertPlainText)
        sp.traverse()


    def activateXMLView(self):
        exporter = XMLExporter(self.editorWidget.page.getPageDir(), None)
        self.customView.setPlainText(exporter.getXmlString(self.editorWidget.editView.document()))


    def activateHTMLView(self):
        exporter = HTMLExporter(self.editorWidget.page.getPageDir())
        self.htmlView.setPlainText(exporter.getHtmlString(self.editorWidget.editView.document()))