コード例 #1
0
class BrowserPage(QWebEnginePage):
    def __init__(self):
        QWebEnginePage.__init__(self)

    def execute_javascript(self, script_src):
        self.loop = QEventLoop()
        self.result = QVariant()
        QTimer.singleShot(250, self.loop.quit)

        self.runJavaScript(script_src, self.callback_js)
        self.loop.exec_()
        self.loop = None
        return self.result

    def callback_js(self, res):
        if self.loop is not None and self.loop.isRunning():
            self.result = res
            self.loop.quit()
コード例 #2
0
class BrowserPage(QWebEnginePage):
    def __init__(self):
        QWebEnginePage.__init__(self)

    def hitTestContent(self, pos):
        return WebHitTestResult(self, pos)

    def mapToViewport(self, pos):
        return QPointF(pos.x(), pos.y())

    def executeJavaScript(self, scriptSrc):
        self.loop = QEventLoop()
        self.result = QVariant()
        QTimer.singleShot(250, self.loop.quit)

        self.runJavaScript(scriptSrc, self.callbackJS)
        self.loop.exec_()
        self.loop = None
        return self.result

    def callbackJS(self, res):
        if self.loop is not None and self.loop.isRunning():
            self.result = res
            self.loop.quit()
コード例 #3
0
class TranslatorRequest(QObject):
    """
    Class implementing a synchronous network request handler for translation
    requests.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent object (QObject)
        """
        super(TranslatorRequest, self).__init__(parent)
        
        self.__contentTypes = {
            "form": b"application/x-www-form-urlencoded",
            "json": b"application/json",
        }
        
        self.__networkManager = QNetworkAccessManager(self)
        self.__networkManager.proxyAuthenticationRequired.connect(
            proxyAuthenticationRequired)
        
        self.__loop = QEventLoop()
        self.__networkManager.finished.connect(self.__loop.quit)
    
    def get(self, requestUrl, extraHeaders=None):
        """
        Public method to issue a GET request.
        
        @param requestUrl URL of the request (QUrl)
        @keyparam extraHeaders list of tuples of additional headers giving
            header name (string) and header value (string)
        @return server response (QByteArray) or error message (string)
        """
        request = QNetworkRequest(requestUrl)
        request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True)
        if extraHeaders:
            for name, value in extraHeaders:
                request.setRawHeader(name, value)
        reply = self.__networkManager.get(request)
        if not self.__loop.isRunning():
            self.__loop.exec_()
        if reply.error() != QNetworkReply.NoError:
            return reply.errorString(), False
        else:
            return reply.readAll(), True
    
    def post(self, requestUrl, requestData, dataType="form",
             extraHeaders=None):
        """
        Public method to issue a POST request.
        
        @param requestUrl URL of the request (QUrl)
        @param requestData data of the request (QByteArray)
        @keyparam dataType type of the request data (string)
        @keyparam extraHeaders list of tuples of additional headers giving
            header name (string) and header value (string)
        @return tuple of server response (string) and flag indicating
            success (boolean)
        """
        request = QNetworkRequest(requestUrl)
        request.setRawHeader(b"User-Agent",
                             b"Mozilla/5.0")
        request.setRawHeader(b"Content-Type",
                             self.__contentTypes[dataType])
        request.setRawHeader(b"Content-Length",
                             QByteArray.number(requestData.size()))
        request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True)
        if extraHeaders:
            for name, value in extraHeaders:
                request.setRawHeader(name, value)
        request.setUrl(requestUrl)
        reply = self.__networkManager.post(request, requestData)
        if not self.__loop.isRunning():
            self.__loop.exec_()
        if reply.error() != QNetworkReply.NoError:
            return reply.errorString(), False
        else:
            return str(reply.readAll(), "utf-8", "replace"), True
コード例 #4
0
class Prompt(QLabel):
    """Blocking prompt widget asking the user a question.

    The prompt is initialized with a question and displays the question, its title and
    the valid keybindings. Calling ``run`` blocks the UI until a valid keybinding to
    answer/abort the question was given.

    Class Attributes:
        BINDINGS: Valid keybindings to answer/abort the question.

    Attributes:
        question: Question object defining title, question and answer.
        loop: Event loop used to block the UI.
    """

    STYLESHEET = """
    QLabel {
        font: {prompt.font};
        color: {prompt.fg};
        background-color: {prompt.bg};
        padding: {prompt.padding};
        border-top-right-radius: {prompt.border_radius};
        border-top: {prompt.border} {prompt.border.color};
        border-right: {prompt.border} {prompt.border.color};
    }
    """

    BINDINGS = (
        ("y", "Yes"),
        ("n", "No"),
        ("<return>", "No"),
        ("<escape>", "Abort"),
    )

    def __init__(self, question: api.prompt.Question, *, parent):
        super().__init__(parent=parent)
        self.question = question
        self.loop = QEventLoop()

        styles.apply(self)
        header = f"<h3>{question.title}</h3>{question.body}"
        self.setText(header + self.bindings_table())
        _logger.debug("Initialized %s", self)

        self.setFocus()
        self.adjustSize()
        self.raise_()
        self.show()

    def __str__(self):
        return f"prompt for '{self.question.title}'"

    @classmethod
    def bindings_table(cls):
        """Return a formatted html table with the valid keybindings."""
        return utils.format_html_table(
            (f"<b>{utils.escape_html(binding)}</b>", command)
            for binding, command in cls.BINDINGS
        )

    def run(self):
        """Run the blocking event loop."""
        _logger.debug("Running blocking %s", self)
        self.loop.exec_()

    def update_geometry(self, _width: int, bottom: int):
        y = bottom - self.height()
        self.setGeometry(0, y, self.width(), self.height())

    def leave(self, *, answer=None):
        """Leave the prompt by answering the question and quitting the loop."""
        _logger.debug("Leaving %s with '%s'", self, answer)
        self.question.answer = answer
        self.loop.quit()
        self.loop.deleteLater()
        self.deleteLater()
        api.modes.current().widget.setFocus()

    def keyPressEvent(self, event):
        """Leave the prompt on a valid key binding."""
        if event.key() == Qt.Key_Y:
            self.leave(answer=True)
        elif event.key() in (Qt.Key_N, Qt.Key_Return):
            self.leave(answer=False)
        elif event.key() == Qt.Key_Escape:
            self.leave()

    def focusOutEvent(self, event):
        """Leave the prompt without answering when unfocused."""
        if self.loop.isRunning():
            self.leave()
        super().focusOutEvent(event)
コード例 #5
0
class Kiwoom(API):
    """
    Main class that can make use of Kiwoom Open API+

    This class wraps all API methods described in KOA studio and Open API+ Manual Guide.
    All methods are wrapped in dynamicCall from PyQt5. Methods and variables names are
    all converted into pythonic way convention, OnReceiveTrData -> on_receive_tr_data.

    Some of extra functions other than pure API are as follows.
    1) Kiwoom.loop() & Kiwoom.unloop()
        These methods are used to prevent from executing codes before data requested
        has not been received yet. Normally, loop can be used in signal methods to stop
        executing further and unloop can be used in slot methods to executing codes that
        are waiting in the signal methods.

    2) Kiwoom.connect(event, signal, slot)
        This method connects signals and slots to one of pre-defined events. Information
        saved in this method is used by decorator @Connector() which wraps the events.

    3) Kiwoom.set_connect_hook(event, param)
        When an event needs multiple slots to connect, depending on specific tasks, set
        a hook(key) to select which slot to map. The hook must be one of the parameters
        in the definition of the event method. Parameters can be found by help built-in
        function or Kiwoom.api_arg_spec(event).

        If hook is set to the given parameter, argument passed into the parameter when
        the event is called, is going to be a key to connect event, signal and slot.

        Convention is that the name of signal and slot that deal with the related task
        is recommended to be the same, so that 'key' is set to be the method name of
        signal and slot by default. See examples on the tutorials link below.
        https://github.com/breadum/kiwoom/blob/main/tutorials/4.%20TR%20Data.py

        Kiwoom.get_connect_hook(), Kiwoom.remove_connect_hook() are also available.

    4) Kiwoom.signal(event, key=None) & Kiwoom.slot(event, key=None)
        If signal and slot are connected to specific event, then these methods return
        the connected signal or slot method respectively. 'key' is needed when hook is
        set by Kiwoom.set_connect_hook().

        When requesting data to server is needed, specifically if more data is available,
        Kiwoom.signal() returns the exact signal method that can request more data.

        When an event is called, Kiwoom.slot() returns the exact slot method that can
        handle data received from the event. This method is used in Connector decorator
        that wraps events to execute connected slot with the event.

    5) @Connector()
        Decorator class that forwards args received from called event into connected slot.
        This class wraps all pre-defined events, and automatically calls connected slots.
    """
    # Class variable just for convenience
    map = Connector.map
    msg = True

    def __init__(self):
        super().__init__()
        self.msg = True
        self._qloop = QEventLoop()

        # To solve the issue that IDE hides error traceback
        def except_hook(cls, exception, traceback):
            sys.__excepthook__(cls, exception, traceback)

        sys.excepthook = except_hook

        # To connect signals and slots
        self._connector = Connector()

        # To set hooks for each event
        self.set_connect_hook('on_receive_tr_data', param='rq_name')
        self.set_connect_hook('on_receive_tr_condition',
                              param='condition_name')
        self.set_connect_hook('on_receive_real_condition',
                              param='condition_name')

        # To connect default slots to basic two events
        # self.connect('on_event_connect', slot=self._slot.on_event_connect)
        # self.connect('on_receive_msg', slot=self._slot.on_receive_msg)

    def loop(self):
        """
        Stop executing codes by running QEventLoop in PyQt5

        If loop is already running, then this does nothing, else freezing. This
        method can be used in signal methods to wait response from the server.
        """
        if not self._qloop.isRunning():
            self._qloop.exec()

    def unloop(self):
        """
        Keep executing codes that are blocked by Kiwoom.loop().

        If loop is not running, then this does nothing, else unfreezing. This
        method can be used in slot methods to execute awaiting codes. If the
        slot methods called, then it means client received response from server.
        There is no need to block codes that are awaiting response, anymore.
        """
        if self._qloop.isRunning():
            self._qloop.exit()

    def login(self):
        """
        Request login to the server by CommConnect API method.

        See '개발가이드 > 로그인 버전처리 > 관련함수 > CommConnect' in KOA Studio.
        """
        self.comm_connect()
        self.loop()

    @classmethod
    def message(cls, bool):
        """
        Turn on/off printing message from Kiwoom.on_receive_msg() event.

        :param bool: bool
            If True, then it prints message else does not.
        """
        cls.msg = bool

    def signal(self, event, key=None):
        """
        Returns signal methods connected to the event.

        If signal and slot are connected to specific event by Kiwoom.connect() method,
        then this method returns the connected signal method. If signal is not connected,
        or wrong key is given, this raises a KeyError.

        'key' is needed when hook is set by Kiwoom.set_connect_hook(). 'key' is set to
        be the name of signal method by default unless another string is set on purpose
        when connecting.

        When requesting data to server is needed, specifically if more data is available,
        Kiwoom.signal() returns the exact signal method that can request more data.

        :param event: str
            One of the pre-defined event names in string. See kiwoom.config.events.
        :param key: str, optional
            If hook is set by Kiwoom.set_connect_hook() method and signal is connected
            by Kiwoom.connect(), then key is needed. 'key' is set to be name of the
            signal method by default unless another 'key' is given when connecting.
        :return: method
            Signal method connected to the given event. If wrong event, returns None.
        """
        return self._connector.signal(event, key)

    def slot(self, event, key=None):
        """
        Returns slot methods connected to the event.

        If signal and slot are connected to specific event by Kiwoom.connect() method,
        then this method returns the connected slot method. If slot is not connected,
        or wrong key is given, this raises a KeyError.

        'key' is needed when hook is set by Kiwoom.set_connect_hook(). 'key' is set to
        be the name of slot method by default unless another string is set on purpose
        when connecting.

        When an event is called, Kiwoom.slot() returns the exact slot method that can
        handle data received from the event. This method is used in Connector decorator
        that wraps events to execute connected slot with the event.

        :param event: str
            One of the pre-defined event names in string. See kiwoom.config.events.
        :param key: str, optional
            If hook is set by Kiwoom.set_connect_hook() method and slot is connected
            by Kiwoom.connect(), then key is needed. 'key' is set to be name of the
            slot method by default unless another 'key' is given when connecting.
        :return: method or None
            Slot method connected to the given event. If wrong event, returns None.
        """
        return self._connector.slot(event, key)

    def connect(self, event, signal=None, slot=None, key=None):
        """
        Connects signals and slots to one of pre-defined events.

        Information saved in this method is used by decorator @Connector() which wraps
        the events and automatically calls the right slot connected to the events. In
        addition to the decorator, Kiwoom.signal(event, key) and Kiwoom.slot(event, key)
        returns the one connected to the event.

        1) If no hook is set on the event, then the connected signal/slot can be retrieved
           by Kiwoom.signal(event) and Kiwoom.slot(event). There is no need to use key.

        2) If hook is set by Kiwoom.set_connect_hook() on the event, in which case there
           needs multiple slots to connect on one event, then connection requires a key
           which is to be the name of signal/slot methods by default.

           The convention to utilizing this module recommends to define the name of related
           signal and slot to be the same. Then it becomes easier to manage and develop codes.

           Use 'key' arg only when there is a special need. The connected signal/slot can be
           retrieved by Kiwoom.signal(event, key='name') and Kiwoom.slot(event, key='name').
           Here 'name' can be a method name or special 'key' used in this method.

        This method checks whether or not given signal/slot can be called without any
        problem. If given method is not bounded to an instance, method should be static
        or lambda function. This is because normally 'self' argument is needed to call
        methods, therefore method must be bounded to an instance unless given method is
        a function.

        Please see tutorials example on the link below.
        https://github.com/breadum/kiwoom/blob/main/tutorials/4.%20TR%20Data.py

        :param event: str
            One of the pre-defined event names in string. See kiwoom.config.events.
        :param signal: method, optional
            A method that requests to the server
        :param slot: method, optional
            A method that reacts the server's response
        :param key: str, optional
            Key is needed only if hook is set by Kiwoom.set_connect_hook() method.
            Key is set to be name of the given signal and/or slot method by default.
            If key is given other than method name, the connected signal can be
            retrieved by Kiwoom.siganl(event, key) and slot by Kiwoom.slot(event, key)
        """
        self._connector.connect(event, signal=signal, slot=slot, key=key)

    def set_connect_hook(self, event, param):
        """
        Set parameter defined in event as a hook to find the right slot when event is called.

        When an event needs multiple slots to connect, depending on specific tasks, set
        a hook(key) to select which slot to map. The hook must be one of the parameters
        in the definition of the event method. Parameters can be found by help built-in
        function or Kiwoom.api_arg_spec(event). This raises a KeyError if given param is
        not defined in event method.

        If hook is set to the given parameter, argument passed into the parameter when
        the event is called, is going to be a key to connect event, signal and slot.

        The Convention is that the names of signal and slot that deal with the related task
        are recommended to be the same, so that 'key' is set to be the method name of
        signal and slot by default. See examples on the tutorials link below.
        https://github.com/breadum/kiwoom/blob/main/tutorials/4.%20TR%20Data.py

        :param event: str
            One of the pre-defined event names in string. See kiwoom.config.events.
        :param param: str
            Parameter name defined in given event. To see all parameters to event,
            use Kiwoom.api_arg_spec(event) method or help(...) built-in function.
        """
        self._connector.set_connect_hook(event, param)

    def get_connect_hook(self, event):
        """
        Returns a hook (i.e. name of parameter) set in given event.

        :param event: str
            One of the pre-defined event names in string. See kiwoom.config.events.
        :return: str or None
            If exists, returns hook in string else None. If not a valid event is given,
            this returns None.
        """
        return self._connector.get_connect_hook(event)

    def remove_connect_hook(self, event):
        """
        Remove hook which is set in given event if exists.

        This method removes all information of signals and slots connected to given
        event as well as hook. If hook of given event does not exist, this raises
        a KeyError.

        :param event: str
            One of the pre-defined event names in string. See kiwoom.config.events.
        """
        self._connector.remove_connect_hook(event)

    def get_hook_index(self, event):
        """
        Returns index of hook in method arguments.

        :param event: str
            One of the pre-defined event names in string. See kiwoom.config.events.
        :return: int
        """
        return self._connector.get_hook_index(event)

    @staticmethod
    def api_arg_spec(fn):
        """
        Returns a string list of parameters to given API function

        :param fn: str
            Name of API function to get list of parameters.
        :return: list
            Parameters of given API function in list of strings.
        """
        return signature(getattr(API, fn)).parameters

    """
    Event Handlers (8)
        on_event_connect
        on_receive_msg
        on_receive_tr_data
        on_receive_real_data
        on_receive_chejan_data
        on_receive_condition_ver
        on_receive_tr_condition
        on_receive_real_condition
    """

    @map
    def on_event_connect(self, err_code):
        pass

    @map
    def on_receive_msg(self, scr_no, rq_name, tr_code, msg):
        pass

    @map
    def on_receive_tr_data(self, scr_no, rq_name, tr_code, record_name,
                           prev_next):
        pass

    @map
    def on_receive_real_data(self, code, real_type, real_data):
        pass

    @map
    def on_receive_chejan_data(self, gubun, item_cnt, fid_list):
        pass

    @map
    def on_receive_condition_ver(self, ret, msg):
        pass

    @map
    def on_receive_tr_condition(self, scr_no, code_list, condition_name, index,
                                next):
        pass

    @map
    def on_receive_real_condition(self, code, type, condition_name,
                                  condition_index):
        pass

    """
    Methods that return error codes.
        comm_rq_data
        comm_kw_rq_data
        send_order
        send_order_credit
        set_real_reg
    """

    @catch_error
    def comm_rq_data(self, rq_name, tr_code, prev_next, scr_no):
        return super().comm_rq_data(rq_name, tr_code, prev_next, scr_no)

    @catch_error
    def comm_kw_rq_data(self, arr_code, next, code_cnt, type_flag, rq_name,
                        scr_no):
        return super().comm_kw_rq_data(arr_code, next, code_cnt, type_flag,
                                       rq_name, scr_no)

    @catch_error
    def send_order(self, rq_name, scr_no, acc_no, ord_type, code, qty, price,
                   hoga_gb, org_order_no):
        return super().send_order(rq_name, scr_no, acc_no, ord_type, code, qty,
                                  price, hoga_gb, org_order_no)

    @catch_error
    def send_order_credit(self, rq_name, scr_no, acc_no, order_type, code, qty,
                          price, hoga_gb, credit_gb, loan_date, org_order_no):
        return super().send_order_credit(rq_name, scr_no, acc_no, order_type,
                                         code, qty, price, hoga_gb, credit_gb,
                                         loan_date, org_order_no)

    @catch_error
    def set_real_reg(self, scr_no, code_list, fid_list, opt_type):
        return super().set_real_reg(scr_no, code_list, fid_list, opt_type)
コード例 #6
0
ファイル: Ace.py プロジェクト: FlorianPerrot/Mojuru
class Ace(QWebView):
    """ Embbeded Ace javascript web editor """
    
    isReady = pyqtSignal(name='isReady')
    modificationChanged = pyqtSignal(bool)
    cursorPositionChanged = pyqtSignal(int, int, name='cursorPositionChanged')
    
    def __init__(self, file_info, parent=None):
        super(Ace, self).__init__(parent)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.parent = parent
        self.file_info = file_info
        self.language = EditorHelper.lang_from_file_info(file_info)
        self.waitForReady = False
        self.loop = QEventLoop()
        
        settings = self.settings()
        settings.setAttribute(QWebSettings.JavascriptCanAccessClipboard, True)
        settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        self.inspector = QWebInspector(self)
        showInspectorAction = QAction('showInspector', self)
        showInspectorAction.triggered.connect(self.showInspector)
        self.addAction(showInspectorAction)
        
        self.modificationChanged.connect(self.modification_changed)
        self.main_frame().javaScriptWindowObjectCleared.connect(self.__self_js)
        pckg, file_name = 'ace_editor', 'ace_editor.html'
        resource = pkg_resources.resource_string(pckg, file_name)
        html_template = str(resource, 'utf-8')
        #insert file content
        with open(self.file_info.absoluteFilePath(), 'r') as f:
            text = f.read()
            text = html.escape(text)
            html_template = html_template.replace('{{ content }}', text)
        base_url = QUrl.fromLocalFile(os.path.dirname(__file__))
        
        self.setHtml(html_template, base_url)
        self.modified = False
        
        if not self.waitForReady:
            self.loop.exec()
    
    @pyqtSlot(str, name='test', result=str)
    @EditorHelper.json_dumps
    def test(self, prefix):
        print(prefix)
        return ['plop', 'cool', 42, {'plop':23}]
    
    def modification_changed(self, b):
        self.modified = b
    
    def save(self, parent, action=None):
        Alter.invoke_all('editor_presave', self)
        if self.modified:
            with open(self.file_info.absoluteFilePath(), 'w') as f:
                f.write(self.get_value())
            self.original_to_current_doc()
            self.modificationChanged.emit(False)
            parent.status_bar.showMessage(self.tr("Saved file."))
            Alter.invoke_all('editor_save', self)
        else :
            parent.status_bar.showMessage(self.tr("Nothing to save."))
    
    def toggle_hidden(self, parent, action=None):
        self.set_show_invisibles(action.isChecked())
    
    def toggle_soft_tabs(self, parent, action=None):
        self.set_use_soft_tabs(action.isChecked())
    
    def main_frame(self):
        """ Convinient function to get main QWebFrame """
        return self.page().mainFrame()
    
    def send_js(self, script):
        """ Convinient function to send javascript to ace editor """
        return self.main_frame().evaluateJavaScript(script)

    def __self_js(self):
        self.main_frame().addToJavaScriptWindowObject('AceEditor', self)
    
    @pyqtSlot(name='isReady')
    def editor_ready(self):
        if self.language != None:
            self.set_mode(self.language.lower())
        self.set_focus()
        if self.loop.isRunning():
            self.loop.quit()
        self.waitForReady = True
    
    def showInspector(self):
        self.dialogInspector = QDialog(self)
        self.dialogInspector.setLayout(QVBoxLayout())
        self.dialogInspector.layout().addWidget(self.inspector)
        self.dialogInspector.setModal(False)
        self.dialogInspector.show()
    
    def original_to_current_doc(self):
        self.send_js('editor.orignalToCurrentDoc()')
    
    def get_value(self):
        return self.send_js('editor.getValue()')
    
    def set_value(self, content):
        self.send_js('editor.setValue("{0}")'.format(content))
    
    def set_focus(self):
        self.send_js('editor.focus()')
    
    def insert(self, text):
        self.send_js('editor.insert("{0}")'.format(text))
    
    def set_mode(self, language):
        cmd = 'editor.getSession().setMode("ace/mode/{0}")'
        self.send_js(cmd.format(language))
    
    def set_theme(self, theme):
        self.send_js('editor.setTheme("ace/theme/{0}")'.format(theme))
    
    def get_selected_text(self):
        cmd = 'editor.session.getTextRange(editor.getSelectionRange())'
        return self.send_js(cmd)
    
    def get_cursor(self):
        cmd = 'editor.selection.getCursor()'
        return self.send_js(cmd)
    
    def got_to_line(self, line):
        cmd = 'editor.gotoLine({0})'
        self.send_js(cmd.format(line))
    
    def get_length(self):
        return self.send_js('editor.session.getLength()');
    
    def set_tab_size(self, tab_size):
        self.send_js('editor.getSession().setTabSize({0})'.format(tab_size))
    
    def get_tab_size(self):
        return self.send_js('editor.getSession().getTabSize()')
    
    def set_use_soft_tabs(self, b):
        b = 'true' if b else 'false'
        self.send_js('editor.getSession().setUseSoftTabs({0})'.format(b))
    
    def set_font_size(self, font_size):
        cmd = "document.getElementById('editor').style.fontSize='{0}px'"
        self.send_js(cmd.format(font_size))
    
    def set_use_wrap_mode(self, b):
        b = 'true' if b else 'false'
        cmd = "editor.getSession().setUseWrapMode({0})"
        self.send_js(cmd.format(b))
    
    def set_highlight_active_line(self, b):
        b = 'true' if b else 'false'
        cmd = "editor.setHighlightActiveLine({0})"
        self.send_js(cmd.format(b))
    
    def set_show_print_margin(self, b):
        b = 'true' if b else 'false'
        cmd = "editor.setShowPrintMargin({0})"
        self.send_js(cmd.format(b))
    
    def set_read_only(self, b):
        b = 'true' if b else 'false'
        self.send_js('editor.setReadOnly({0})'.format(b))
    
    def set_show_invisibles(self, b):
        b = 'true' if b else 'false'
        self.send_js('editor.setShowInvisibles({0})'.format(b))
コード例 #7
0
class Page(QWebEnginePage):
    def __init__(self, view):
        super(Page, self).__init__()
        self.parent = view.parent
        self.view = view
        self.result = QVariant()
        self.fullView = QWebEngineView()
        self.exitFSAction = QAction(self.fullView)
        self.loop = None

    def javaScriptConsoleMessage(self, level, msg, line, sourceID):
        """Override javaScriptConsoleMessage to use debug log."""
        if level == QWebEnginePage.InfoMessageLevel:
            print("JS - INFO - Ligne {} : {}".format(line, msg))
        elif level == QWebEnginePage.WarningMessageLevel:
            print("JS - WARNING - Ligne {} : {}".format(line, msg))
        else:
            print("JS - ERROR - Ligne {} : {}".format(line, msg))

    def hittestcontent(self, pos):
        return WebHitTestResult(self, pos)

    def maptoviewport(self, pos):
        return QPointF(pos.x(), pos.y())

    def executejavascript(self, scriptsrc):
        self.loop = QEventLoop()
        self.result = QVariant()
        QTimer.singleShot(250, self.loop.quit)

        self.runJavaScript(scriptsrc, self.callbackjs)
        self.loop.exec_()
        self.loop = None
        return self.result

    def callbackjs(self, res):
        if self.loop is not None and self.loop.isRunning():
            self.result = res
            self.loop.quit()

    def vsource(self):
        if "view-source:http" in self.url().toString():
            self.load(QUrl(self.url().toString().split("view-source:")[1]))
        else:
            self.triggerAction(self.ViewSource)

    def cutaction(self):
        self.triggerAction(self.Cut)

    def copyaction(self):
        self.triggerAction(self.Copy)

    def pasteaction(self):
        self.triggerAction(self.Paste)

    def exitfs(self):
        self.triggerAction(self.ExitFullScreen)

    def makefullscreen(self, request):
        if request.toggleOn():
            self.fullView = QWebEngineView()
            self.exitFSAction = QAction(self.fullView)
            self.exitFSAction.setShortcut(Qt.Key_Escape)
            self.exitFSAction.triggered.connect(self.exitfs)

            self.fullView.addAction(self.exitFSAction)
            self.setView(self.fullView)
            self.fullView.showFullScreen()
            self.fullView.raise_()
        else:
            del self.fullView
            self.setView(self.view)
        request.accept()
コード例 #8
0
class Ace(QWebView):
    """ Embbeded Ace javascript web editor """

    isReady = pyqtSignal(name='isReady')
    modificationChanged = pyqtSignal(bool)
    cursorPositionChanged = pyqtSignal(int, int, name='cursorPositionChanged')

    def __init__(self, file_info, parent=None):
        super(Ace, self).__init__(parent)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.parent = parent
        self.file_info = file_info
        self.language = EditorHelper.lang_from_file_info(file_info)
        self.waitForReady = False
        self.loop = QEventLoop()

        settings = self.settings()
        settings.setAttribute(QWebSettings.JavascriptCanAccessClipboard, True)
        settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        self.inspector = QWebInspector(self)
        showInspectorAction = QAction('showInspector', self)
        showInspectorAction.triggered.connect(self.showInspector)
        self.addAction(showInspectorAction)

        self.modificationChanged.connect(self.modification_changed)
        self.main_frame().javaScriptWindowObjectCleared.connect(self.__self_js)
        pckg, file_name = 'ace_editor', 'ace_editor.html'
        resource = pkg_resources.resource_string(pckg, file_name)
        html_template = str(resource, 'utf-8')
        #insert file content
        with open(self.file_info.absoluteFilePath(), 'r') as f:
            text = f.read()
            text = html.escape(text)
            html_template = html_template.replace('{{ content }}', text)
        base_url = QUrl.fromLocalFile(os.path.dirname(__file__))

        self.setHtml(html_template, base_url)
        self.modified = False

        if not self.waitForReady:
            self.loop.exec()

    @pyqtSlot(str, name='test', result=str)
    @EditorHelper.json_dumps
    def test(self, prefix):
        print(prefix)
        return ['plop', 'cool', 42, {'plop': 23}]

    def modification_changed(self, b):
        self.modified = b

    def save(self, parent, action=None):
        Alter.invoke_all('editor_presave', self)
        if self.modified:
            with open(self.file_info.absoluteFilePath(), 'w') as f:
                f.write(self.get_value())
            self.original_to_current_doc()
            self.modificationChanged.emit(False)
            parent.status_bar.showMessage(self.tr("Saved file."))
            Alter.invoke_all('editor_save', self)
        else:
            parent.status_bar.showMessage(self.tr("Nothing to save."))

    def toggle_hidden(self, parent, action=None):
        self.set_show_invisibles(action.isChecked())

    def toggle_soft_tabs(self, parent, action=None):
        self.set_use_soft_tabs(action.isChecked())

    def main_frame(self):
        """ Convinient function to get main QWebFrame """
        return self.page().mainFrame()

    def send_js(self, script):
        """ Convinient function to send javascript to ace editor """
        return self.main_frame().evaluateJavaScript(script)

    def __self_js(self):
        self.main_frame().addToJavaScriptWindowObject('AceEditor', self)

    @pyqtSlot(name='isReady')
    def editor_ready(self):
        if self.language != None:
            self.set_mode(self.language.lower())
        self.set_focus()
        if self.loop.isRunning():
            self.loop.quit()
        self.waitForReady = True

    def showInspector(self):
        self.dialogInspector = QDialog(self)
        self.dialogInspector.setLayout(QVBoxLayout())
        self.dialogInspector.layout().addWidget(self.inspector)
        self.dialogInspector.setModal(False)
        self.dialogInspector.show()

    def original_to_current_doc(self):
        self.send_js('editor.orignalToCurrentDoc()')

    def get_value(self):
        return self.send_js('editor.getValue()')

    def set_value(self, content):
        self.send_js('editor.setValue("{0}")'.format(content))

    def set_focus(self):
        self.send_js('editor.focus()')

    def insert(self, text):
        self.send_js('editor.insert("{0}")'.format(text))

    def set_mode(self, language):
        cmd = 'editor.getSession().setMode("ace/mode/{0}")'
        self.send_js(cmd.format(language))

    def set_theme(self, theme):
        self.send_js('editor.setTheme("ace/theme/{0}")'.format(theme))

    def get_selected_text(self):
        cmd = 'editor.session.getTextRange(editor.getSelectionRange())'
        return self.send_js(cmd)

    def get_cursor(self):
        cmd = 'editor.selection.getCursor()'
        return self.send_js(cmd)

    def got_to_line(self, line):
        cmd = 'editor.gotoLine({0})'
        self.send_js(cmd.format(line))

    def get_length(self):
        return self.send_js('editor.session.getLength()')

    def set_tab_size(self, tab_size):
        self.send_js('editor.getSession().setTabSize({0})'.format(tab_size))

    def get_tab_size(self):
        return self.send_js('editor.getSession().getTabSize()')

    def set_use_soft_tabs(self, b):
        b = 'true' if b else 'false'
        self.send_js('editor.getSession().setUseSoftTabs({0})'.format(b))

    def set_font_size(self, font_size):
        cmd = "document.getElementById('editor').style.fontSize='{0}px'"
        self.send_js(cmd.format(font_size))

    def set_use_wrap_mode(self, b):
        b = 'true' if b else 'false'
        cmd = "editor.getSession().setUseWrapMode({0})"
        self.send_js(cmd.format(b))

    def set_highlight_active_line(self, b):
        b = 'true' if b else 'false'
        cmd = "editor.setHighlightActiveLine({0})"
        self.send_js(cmd.format(b))

    def set_show_print_margin(self, b):
        b = 'true' if b else 'false'
        cmd = "editor.setShowPrintMargin({0})"
        self.send_js(cmd.format(b))

    def set_read_only(self, b):
        b = 'true' if b else 'false'
        self.send_js('editor.setReadOnly({0})'.format(b))

    def set_show_invisibles(self, b):
        b = 'true' if b else 'false'
        self.send_js('editor.setShowInvisibles({0})'.format(b))