Beispiel #1
0
class TestWindow(QWidget):
    TMPDIR = "tmp"
    TMPHTMLFILE = os.path.join(TMPDIR,'tmptext.html')
    def __init__(self,parent = None):
        QWidget.__init__(self,parent)
        
        if os.path.isdir(TestWindow.TMPDIR) == False:
            os.mkdir(TestWindow.TMPDIR)
        
        self.textEditor = TextEditor(self)
        self.webViewer = QWebView(self)
        self.setupUI()
        self.textEditor.textChangeSignal.connect(self.reloadText)
    
    def reloadText(self,dataDict):
        if self.webViewer.isVisible() == False:
            self.webViewer.show()
        with codecs.open( ResourceManager.getResourceAbsPath('template.html'),'r','utf-8' ) as templateFileObj:
            templateStr = templateFileObj.read()
        with open( TestWindow.TMPHTMLFILE,'wb' ) as tempFileObj:
            tempFileObj.write( (templateStr % dataDict[TextEditor.KEY_ORIGINALTXET]).encode('utf-8') )
        self.webViewer.load(QUrl( "file:///%s" % os.path.abspath( TestWindow.TMPHTMLFILE ) ))


    def setupUI(self):
        self.webViewer.hide()
        
        layout = QHBoxLayout(self)
        self.splitter = QSplitter(self)
        self.splitter.addWidget(self.textEditor)
        self.splitter.addWidget(self.webViewer)
        layout.addWidget(self.splitter)

        self.textEditor.resize(400,600)
        self.webViewer.resize(400,600)
        self.resize(800,600)
        
        self.splitter.setStyleSheet("background-color:green;")
        self.textEditor.setStyleSheet("background-color:white;border:none;")
        self.webViewer.setStyleSheet("background-color:white;")
Beispiel #2
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()
Beispiel #3
0
class NodeEditor(QGroupBox):
    def __init__(self, parent=None):
        super(NodeEditor, self).__init__(parent)
        self.setTitle("editor")
        self.main_layout = QVBoxLayout(self)

        self.node = None
        self.storage = get_storage()

        self.__make_gui()

        self.storage.eon("node_selected", self.__on_node_selected)
        self.storage.eon("node_updated", self.__on_node_updated)

    def __make_gui(self):

        self.text_edit = QTextEdit()
        self.main_layout.addWidget(self.text_edit)

        #--- подсветка синтаксиса
        # self.hh = PythonHighlighter(self.text_edit.document())
        # self.hh = MarkdownHighlighter(self.text_edit)

        self.web = QWebView()
        self.main_layout.addWidget(self.web)
        # self.web.setHtml(html)

        #--- controls
        controls = QHBoxLayout()
        self.main_layout.addLayout(controls)

        self.btn_view_edit = QPushButton("edit")
        self.btn_view_edit.clicked.connect(self.__on_set_view_edit)

        self.btn_view_web = QPushButton("web")
        self.btn_view_web.clicked.connect(self.__on_set_view_web)

        self.btn_show_edit = QPushButton("show_edit")
        self.btn_show_edit.clicked.connect(self.__on_show_edit)

        self.btn_save = QPushButton("save")
        self.btn_save.clicked.connect(self.__save)

        controls.addWidget(self.btn_view_web)
        controls.addWidget(self.btn_view_edit)
        controls.addStretch()
        controls.addWidget(self.btn_show_edit)
        controls.addStretch()
        controls.addWidget(self.btn_save)

    def __on_node_selected(self):
        # self.node = node

        self.node = self.storage.get_current_node()

        self.setTitle(self.node.name)

        text = self.node.page.raw_text

        if self.node.meta.ntype == "text":
            self.__set_view_text(text)
        elif self.node.meta.ntype == "markdown":
            self.__set_view_markdown(text)
        else:
            pass
        #--- page text

        # self.web.setHtml(text)

    def __on_node_updated(self):
        self.setTitle(self.node.name)

        text = self.node.page.raw_text
        html = markdown.markdown(text)
        self.web.setHtml(html)

    def __save(self):

        #--- get data
        text = self.text_edit.toPlainText()

        #--- update node data
        self.node.update_page_text(text)

        #--- send events
        # events.update_current_node()				# update_tree - вызовет и это
        # events.update_tree()

    def __set_view_text(self, text):
        self.__on_set_view_edit()
        self.text_edit.setText(text)
        self.btn_view_web.setDisabled(True)

    def __set_view_markdown(self, text):
        self.__on_set_view_web()
        self.text_edit.setText(text)
        html = markdown.markdown(text)
        self.web.setHtml(html)

    def __on_set_view_edit(self):
        self.web.hide()
        self.text_edit.show()
        self.btn_view_edit.setDisabled(True)
        self.btn_view_web.setEnabled(True)
        self.btn_save.setEnabled(True)

    def __on_set_view_web(self):
        self.web.show()
        self.text_edit.hide()
        self.btn_view_web.setDisabled(True)
        self.btn_view_edit.setEnabled(True)
        self.btn_save.setEnabled(False)

    def __on_show_edit(self):
        modal = NodeEditorModal(self.node, self)
        modal.show()
Beispiel #4
0
class Application(QApplication):
    _active_task = None
    _exit_timer = None
    _expects = None
    _expects_active = False
    _expects_if_timeout = None
    _expects_timer = None
    _frame_data = None
    _frame_data_lock = None
    _frame_timer = None
    _handlers = None
    _queue = None
    _trigger_delay_timer = None
    _visible = True

    log_event = pyqtSignal(int, str, str)
    name = ''

    def __init__(self, name, settings):
        super(Application, self).__init__([])

        self.name = name
        self.settings = settings

        self.web_view = QWebView()

        self._exit_timer = QTimer(self)
        self._exit_timer.setSingleShot(True)
        self._exit_timer.setInterval(1000)

        self._expects = []
        self._expects_if_timeout = []
        self._expects_timer = QTimer(self)
        self._expects_timer.setSingleShot(True)
        self._expects_timer.timeout.connect(self._on_expects_timeout)
        self._frame_data = {}
        self._frame_data_lock = Lock()
        self._frame_timer = QTimer(self)
        self._frame_timer.start(3000)
        self._queue = Queue()
        self._trigger_delay_timer = QTimer(self)
        self._trigger_delay_timer.setSingleShot(True)
        self._visible = int(self.settings['application.visible'])

        self.web_page = WebPage(self.web_view)
        self.web_page.log_event.connect(self.log_event)
        self.web_page.frameCreated.connect(self._on_frame_created)
        self._on_frame_created(self.web_page.mainFrame())
        #self.web_page.networkAccessManager().finished.connect(
        #        self._on_http_response)

        self.web_view.setPage(self.web_page)

        st = self.web_page.settings()
        st.setAttribute(st.AutoLoadImages,
                        int(self.settings['application.settings.load_images']))
        st.setAttribute(
            st.JavaEnabled,
            int(self.settings['application.settings.java_enabled']))
        st.setAttribute(
            st.PluginsEnabled,
            int(self.settings['application.settings.plugins_enabled']))

        self.clear_handlers()

        # redirect qt related messages
        try:
            qInstallMessageHandler(self._pyqt5_null_message_handler)
        except NameError:
            qInstallMsgHandler(self._pyqt4_null_message_handler)

    def start(self):
        self.process_next_queue()
        if self._visible:
            self.web_view.show()
        return self.exec_()

    def add_queue(self, task, publish=False):
        self._queue.put(task)

    def process_next_queue(self):
        self._on_next_queue_trigger(self)

    def get_frame_related_data(self, frame):
        """
        There is a pool of reusable frame data, because browser's frames were
        easily created and destroyed.
        """
        with self._frame_data_lock:
            frame_data = self._frame_data.get(str(frame.objectName()))
        return frame_data

    def set_expects(self, expects):
        self._expects_active = True

        newlist = make_list(expects)
        for item in newlist:
            for key in item:
                if not key in ('path', 'hash', 'host', 'selector_exists',
                               'selector_not_exists', 'trigger',
                               'trigger_args', 'trigger_delay',
                               'trigger_wait_pageload', 'custom'):

                    self.warn('"%s" is not a valid expect field.' % key)

            item['selector_exists'] = make_list(item.get('selector_exists'))
            item['selector_not_exists'] = make_list(
                item.get('selector_not_exists'))

        self._expects = newlist

    def set_timeout_expects(self, timeout, expects):
        self._expects_timer.start(timeout * 1000)
        self._expects_if_timeout = make_list(expects)

    def set_upload_files(self, filenames):
        self.web_page.upload_files = make_list(filenames)

    def add_handler(self, name, value):
        self._handlers[name] = value

    def clear_handlers(self):
        # clear handlers registration
        self._handlers = {
            'core.next_queue': self._on_next_queue_trigger,
            'core.page_not_found': self._on_page_not_found_trigger
        }

    def load(self, url):
        self.web_view.load(QUrl(url))

    def info(self, message):
        self.log_event.emit(INFO, message, 'default')

    def debug(self, message):
        self.log_event.emit(DEBUG, message, 'default')

    def error(self, message):
        self.log_event.emit(ERROR, message, 'default')

    def warn(self, message):
        self.log_event.emit(WARNING, message, 'default')

    def exit(self, return_code):
        self.web_view.hide()
        self._expects_active = False
        self.web_view.stop()
        self._exit_timer.timeout.connect(
            partial(super(Application, self).exit, return_code))

        self._exit_timer.start(1000)

    def _url_matched_expectation(self, expect, scheme, netloc, path, query,
                                 segment):

        if 'host' in expect and not re.match(expect['host'], netloc):
            self.debug('%s location.host: "%s" "%s"' %
                       (expect['trigger'], expect['host'], netloc))
            return False

        if 'path' in expect and not re.match(expect['path'], path):
            self.debug('%s location.pathname: "%s" "%s"' %
                       (expect['trigger'], expect['path'], path))
            return False

        if 'hash' in expect and not re.match(expect['hash'], segment):
            self.debug('%s location.hash: "%s" "%s"' %
                       (expect['trigger'], expect['hash'], segment))
            return False

        return True

    def process_expectations(self, expect, frame, urlparts):
        if not self._url_matched_expectation(expect, *urlparts):
            return

        document = frame.documentElement()

        for selector in expect.get('selector_exists', []):
            if document.findFirst(selector).isNull():
                self.debug('%s selector_exists: %s' %
                           (expect['trigger'], selector))
                return

        for selector in expect.get('selector_not_exists', []):
            if not document.findFirst(selector).isNull():
                self.debug('%s selector_not_exists: %s' %
                           (expect['trigger'], selector))
                return

        if 'custom' in expect and not expect['custom'](self, frame, *urlparts):
            return

        self.debug('%s triggered.' % expect['trigger'])
        self._expects_active = False

        trigger_delay = expect.get('trigger_delay', 0)
        if trigger_delay:
            try:
                self._trigger_delay_timer.timeout.disconnect()
            except Exception as e:
                pass

            self._trigger_delay_timer.timeout.connect(
                partial(self.trigger,
                        frame=frame,
                        trigger_name=expect['trigger'],
                        trigger_args=expect.get('trigger_args', [])))

            self._trigger_delay_timer.start(trigger_delay * 1000)
        else:
            self.trigger(frame, expect['trigger'],
                         expect.get('trigger_args', []))

    def trigger(self, frame, trigger_name, trigger_args):
        if self._trigger_delay_timer.isActive():
            self._trigger_delay_timer.stop()

        trigger_args = dict((str(key), trigger_args[key]) for \
                key in trigger_args)

        if trigger_name in self._handlers:
            self._handlers[trigger_name](self, frame, **trigger_args)
        else:
            self.error('No handler for trigger %s.' % trigger_name)
            self.exit(-1)

    @staticmethod
    def _on_page_not_found_trigger(app, frame):
        app.error('PageNotFound: %s.' % frame.baseUrl().toString())
        app.exit(-1)

    @staticmethod
    def _on_next_queue_trigger(app, frame=None):
        if not app._active_task is None:
            app._queue.task_done()

        try:
            app._active_task = task = app._queue.get(timeout=15)
        except Empty:
            app.info('No more task in the queue.')
            app.web_view.close()
            app.exit(0)
            return

        expects = make_list(task['expects'])
        for expect in expects:
            expect['trigger_wait_pageload'] = True

        app.set_expects(expects)
        app.load(task['goto'])

    def _on_expects_timeout(self):
        self.debug('No expectations were fulfilled after a periode.')
        self.set_expects(self._expects_if_timeout or [])
        self.web_page.triggerAction(QWebPage.Stop)

    def _on_frame_created(self, frame):
        """ Called when QWebPage created a QWebFrame """
        frame_name = 'frame-' + uuid4().hex
        frame.setObjectName(frame_name)
        frame_data = {
            ENUM_FRAME_DATA_ACTIVE:
            False,
            ENUM_FRAME_DATA_TIMER_CALLBACK:
            partial(self._on_frame_timer, frame=frame),
            ENUM_FRAME_DATA_TIMER_COUNTER:
            0,
        }

        with self._frame_data_lock:
            self._frame_data[frame_name] = frame_data

        self._frame_timer.timeout.connect(
            frame_data[ENUM_FRAME_DATA_TIMER_CALLBACK])

        frame.destroyed.connect(self._on_frame_destroyed)
        #frame.javaScriptWindowObjectCleared.connect(partial(
        #        self._on_frame_reset, frame=frame))
        frame.loadFinished.connect(partial(self._on_frame_loaded, frame=frame))

    def _on_frame_destroyed(self, frame):
        """ Called when QWebFrame was destroyed """
        frame_name = str(frame.objectName())
        with self._frame_data_lock:
            frame_data = self._frame_data.get(frame_name)
            if frame_data is None:
                return

            del self._frame_data[frame_name]
            self._frame_timer.timeout.disconnect(
                frame_data[ENUM_FRAME_DATA_TIMER_CALLBACK])

    def _on_frame_loaded(self, success, frame=None):
        self._on_frame_reset(frame)

    def _on_frame_reset(self, frame=None):
        """
        Called when the javascript `window` object were destroyed, usually just
        before page reload.
        """
        if frame is None:
            # this happens if the frame was forced stop, probably, not sure
            self.error('Problem while loading the page.')
            self.exit(-1)
            return
        self.debug('DOMContentLoaded ' + frame.baseUrl().toString())

        frame.evaluateJavaScript("""
            window.bot = {
                click: function(el) {
                    if (el.click) {
                        el.click()
                    }
                    else if (el.fireEvent) {
                        el.fireEvent('onclick');
                    }
                    else {
                        var evt = document.createEvent('Events');
                        evt.initEvent('click', true, false);
                        el.dispatchEvent(evt);
                    }
                },
            };
        """)

        frame_data = self.get_frame_related_data(frame)
        frame_data[ENUM_FRAME_DATA_TIMER_COUNTER] = 0
        frame_data[ENUM_FRAME_DATA_ACTIVE] = True

    def _on_frame_timer(self, frame):
        if not self._expects_active:
            # we have obsolete expects
            return

        frame_data = self.get_frame_related_data(frame)
        if frame_data is None:
            return

        if not frame_data[ENUM_FRAME_DATA_ACTIVE]:
            # the frame hasn't been fully loaded
            return

        wait_pageload = False

        urlparts = urlsplit(str(frame.baseUrl().toString()))
        for expect in self._expects:
            # is it an obsolete frame
            if expect.get('trigger_wait_pageload', False) and \
                    frame_data[ENUM_FRAME_DATA_TIMER_COUNTER] > 0:

                wait_pageload = True
                continue

            self.process_expectations(expect, frame, urlparts)
            if not self._expects_active:
                # one of the triggers has been activated
                break

        if not wait_pageload:
            frame_data[ENUM_FRAME_DATA_TIMER_COUNTER] += 1

    def _pyqt4_null_message_handler(self, msgtype, msg):
        """ Nuke Qt related error messages """
        self.log_event.emit(DEBUG, str(msg), 'qt')

    def _pyqt5_null_message_handler(self, msgtype, msgctx, msg):
        """ Nuke Qt related error messages """
        self.log_event.emit(DEBUG, str(msg), 'qt')

    def _on_http_response(self, response):
        error = response.error()
        if error == QNetworkReply.NoError:
            return

        url = str(response.url().toString())
        scheme, netloc, path, query, segment = urlsplit(url)
        filename, ext = os.path.splitext(path)

        if len(ext) and ext[1:] in ('gif', 'css', 'js', 'png', 'jpg', 'jpeg',
                                    'ico'):

            return

        status_code = int(
            response.attribute(
                QNetworkRequest.HttpStatusCodeAttribute).toInt())

        for expect in self._expects:
            if self._url_matched_expectation(expect, scheme, netloc, path,
                                             query, segment):

                self.log_event.emit(WARNING, '%s: %s' % (status_code, url),
                                    'http')

                break
        else:
            self.log_event.emit(DEBUG, '%s: %s' % (status_code, url), 'http')