Esempio n. 1
0
 def _on_show_detail(self):
     dlg = QTextEdit(self)
     dlg.setReadOnly(True)
     geo = QApplication.desktop().screenGeometry()
     dlg.setGeometry(geo.width() / 2,
                     geo.height() / 2,
                     geo.width() / 4,
                     geo.height() / 4)
     dlg.setWindowTitle('Error Detail Information')
     dlg.setText(self.property('history'))
     dlg.setWindowFlags(Qt.Dialog)
     dlg.show()
Esempio n. 2
0
class PythonCompleter(QCompleter, object):
    def __init__(self):
        super(PythonCompleter, self).__init__()

        self._info = None
        self._file_path = None
        self._model_strings = list()
        self._reset_list = True
        self._string_model = QStringListModel(self._model_strings, self)

        self._refresh_completer = True
        self._sub_activated = False
        self._last_imports = None
        self._last_lines = None
        self._last_path = None
        self._current_defined_imports = None
        self._last_path_and_part = None
        self._current_sub_functions = None
        self._last_column = 0

        self.setCompletionMode(self.PopupCompletion)
        self.setCaseSensitivity(Qt.CaseInsensitive)
        self.setModel(self._string_model)
        self.setWrapAround(False)

        self.activated.connect(self._on_insert_completion)

    def setWidget(self, widget):
        super(PythonCompleter, self).setWidget(widget)
        self.setParent(widget)

    def keyPressEvent(self):
        return

    def show_info_popup(self, info=None):
        self._info = QTextEdit()
        self._info.setEnabled(False)
        self._info.setWindowFlags(Qt.Popup)
        self._info.show()

    def get_imports(self, paths=None):
        imports = self._get_available_modules(paths=paths)
        imports.sort()

        return imports

    def get_sub_imports(self, path):
        """
        Returns namespace in a module
        :param path: str
        :return: str
        """

        defined = code.get_defined(path)
        defined.sort()

        return defined

    def clear_completer_list(self):
        self._string_model.setStringList([])

    def text_under_cursor(self):
        cursor = self.widget().textCursor()
        cursor.select(cursor.LineUnderCursor)

        return cursor.selectedText()

    def set_filepath(self, file_path):
        if not file_path:
            return

        self._file_path = file_path

    def handle_text(self, text):
        """
        Parses a single line of text
        :param text: str
        :return: bool
        """

        if not text:
            return False

        cursor = self.widget().textCursor()
        column = cursor.columnNumber() - 1
        if column < self._last_column:
            self._last_column = column
            return False
        self._last_column = column

        if column == 1:
            return False
        text = str(text)
        passed = self.handle_from_import(text, column)
        if passed:
            return True
        passed = self.handle_sub_import(text, column)
        if passed:
            return True
        passed = self.handle_import_load(text, cursor)
        if passed:
            return True

        return False

    def handle_import(self, text):
        m = re.search(r'(from|import)(?:\s+?)(\w*)', text)
        if m:
            # TODO: Find available modules in Python path
            pass

    def handle_sub_import(self, text, column):
        m = re.search(r'(from|import)(?:\s+?)(\w*.?\w*)\.(\w*)$', text)
        if m:
            if column < m.end(2):
                return False
            from_module = m.group(2)
            module_path = code.get_package_path_from_name(from_module)
            last_part = m.group(3)
            if module_path:
                defined = self.get_imports(module_path)
                self._string_model.setStringList(defined)
                self.setCompletionPrefix(last_part)
                self.popup().setCurrentIndex(self.completionModel().index(
                    0, 0))
                return True

        return False

    def handle_import_load(self, text, cursor):
        column = cursor.columnNumber() - 1
        text = text[:cursor.columnNumber()]
        m = re.search(r'\s*([a-zA-Z0-9._]+)\.([a-zA-Z0-9_]*)$', text)
        block_number = cursor.blockNumber()
        line_number = block_number + 1
        all_text = self.widget().toPlainText()
        scope_text = all_text[:(cursor.position() - 1)]

        if m and m.group(2):
            scope_text = all_text[:(cursor.position() - len(m.group(2)) + 1)]
        if not m:
            return False

        assignment = m.group(1)
        if column < m.end(1):
            return False

        sub_m = re.search(r'(from|import)\s+(%s)' % assignment, text)
        if sub_m:
            return False

        path = None
        sub_part = None
        target = None

        text = self.widget().toPlainText()
        lines = fileio.get_text_lines(text)

        # Search for assignments
        assign_map = code.get_ast_assignment(scope_text, line_number - 1,
                                             assignment)
        if assign_map:
            if assignment in assign_map:
                target = assign_map[assignment]
            else:
                split_assignment = assignment.split('.')
                inc = 1

                while assignment not in assign_map:
                    sub_assignment = string.join(split_assignment[:(inc * -1)],
                                                 '.')
                    if sub_assignment in assign_map:
                        target = assign_map[sub_assignment]
                        break
                    inc += 1
                    if inc > (len(split_assignment) - 1):
                        break
                sub_part = string.join(split_assignment[inc:], '.')

        module_name = m.group(1)
        if target and len(target) == 2:
            if target[0] == 'import':
                module_name = target[1]
            if not target[0] == 'import':
                module_name = target[0]
                sub_part = target[1]

        # import from module
        if module_name:
            imports = None
            if lines == self.last_lines:
                imports = self.last_imports
            if not imports:
                imports = code.get_line_imports(lines)

            self._last_imports = imports
            self._last_lines = lines

            if module_name in imports:
                path = imports[module_name]
            if module_name not in imports:
                split_assignment = module_name.split('.')
                last_part = split_assignment[-1]
                if last_part in imports:
                    path = imports[last_part]

            if path and not sub_part:
                test_text = ''
                defined = None
                if path == self.last_path:
                    defined = self.current_defined_imports
                if len(m.groups()) > 0:
                    test_text = m.group(2)
                if not defined:
                    defined = self.get_imports(path)
                    if defined:
                        self._current_defined_imports = defined
                    else:
                        defined = self.get_sub_imports(path)

                custom_defined = self.custom_import_load(
                    assign_map, module_name)
                if custom_defined:
                    defined = custom_defined
                if defined:
                    if test_text and test_text[0].islower():
                        defined.sort(key=str.swapcase)
                    self._string_model.setStringList(defined)
                    self.setCompletionPrefix(test_text)
                    self.setCaseSensitivity(Qt.CaseInsensitive)
                    self.popup().setCurrentIndex(self.completionModel().index(
                        0, 0))
                    return True

            # import from a class of a module
            if path and sub_part:

                sub_functions = None
                if self.last_path_and_part:
                    if path == self.last_path_and_part[
                            0] and sub_part == self.last_path_and_part[1]:
                        sub_functions = self.current_sub_functions

                if not sub_functions:
                    sub_functions = code.get_ast_class_sub_functions(
                        path, sub_part)
                    if sub_functions:
                        self._current_sub_functions = sub_functions

                self._last_path_and_part = [path, sub_part]
                if not sub_functions:
                    return False

                test_text = ''
                if len(m.groups()) > 0:
                    test_text = m.group(2)
                if test_text and test_text[0].islower():
                    sub_functions.sort(key=str.swapcase)
                self._string_model.setStringList(sub_functions)
                self.setCompletionPrefix(test_text)
                self.setCaseSensitivity(Qt.CaseInsensitive)
                self.popup().setCurrentIndex(self.completionModel().index(
                    0, 0))
                return True

        module_name = m.group(1)
        if module_name:
            custom_defined = self.custom_import_load(assign_map, module_name)

            test_text = ''
            if len(m.groups()) > 0:
                test_text = m.group(2)

            if test_text and test_text[0].islower():
                custom_defined.sort(key=str.swapcase)
            self._string_model.setStringList(custom_defined)
            self.setCompletionPrefix(test_text)
            self.setCaseSensitivity(Qt.CaseInsensitive)
            self.popup().setCurrentIndex(self.completionModel().index(0, 0))
            return True

        return False

    def handle_from_import(self, text, column):
        m = re.search(
            r'(from)(?:\s+?)(\w*.?\w*)(?:\s+?)(import)(?:\s+?)(\w+)?$', text)
        if m:
            if column < m.end(3):
                return False
            from_module = m.group(2)
            module_path = code.get_package_path_from_name(from_module)

            last_part = m.group(4)
            if not last_part:
                last_part = ''
            if module_path:
                defined = self.get_imports(module_path)
                self._string_model.setStringList(defined)
                self.setCompletionPrefix(last_part)
                self.popup().setCurrentIndex(self.completionModel().index(
                    0, 0))

                return True

        return False

    def custom_import_load(self, assign_map, moduel_name):
        return

    def _get_available_modules(self, paths=None):
        imports = list()
        if not paths:
            paths = sys.path
        if paths:
            paths = python.force_list(paths)

        for path in paths:
            fix_path = path_utils.normalize_path(path)
            stuff_in_folder = folder_utils.get_files_and_folders(fix_path)
            for file_or_folder in stuff_in_folder:
                folder_path = path_utils.join_path(fix_path, file_or_folder)
                files = folder_utils.get_files_with_extension('py',
                                                              folder_path,
                                                              full_path=False)
                if '__init__.py' in files:
                    imports.append(str(file_or_folder))

            python_files = folder_utils.get_files_with_extension(
                'py', fix_path, full_path=False)
            for python_file in python_files:
                if python_file.startswith('__'):
                    continue
                python_file_name = python_file.split('.')[0]
                imports.append(str(python_file_name))

        if imports:
            imports = list(set(imports))

        return imports

    def _on_insert_completion(self, completion_string):
        widget = self.widget()
        cursor = widget.textCursor()
        if completion_string == self.completionPrefix():
            return
        extra = len(self.completionPrefix())
        cursor.movePosition(QTextCursor.Left, cursor.KeepAnchor, extra)
        cursor.removeSelectedText()
        cursor.insertText(completion_string)
        widget.setTextCursor(cursor)
Esempio n. 3
0
class MainWindow(QMainWindow):
    def __init__(self, url):
        super().__init__()
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.progress = 0

        f = QFile()
        f.setFileName(":/jquery.min.js")
        f.open(QIODevice.ReadOnly)
        self.jQuery = f.readAll().data().decode()
        self.jQuery += "\nvar qt = { 'jQuery': jQuery.noConflict(true) };"
        f.close()

        self.view = QWebEngineView(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(self.tr("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(self.tr("&View"))
        viewSourceAction = QAction(self.tr("Page Source"), self)
        viewSourceAction.triggered.connect(self.viewSource)
        viewMenu.addAction(viewSourceAction)

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

        self.rotateAction = QAction(self)
        self.rotateAction.setIcon(self.style().standardIcon(
            QStyle.SP_FileDialogDetailedView))
        self.rotateAction.setCheckable(True)
        self.rotateAction.setText(self.tr("Turn images upside down"))
        self.rotateAction.toggled.connect(self.rotateImages)
        effectMenu.addAction(self.rotateAction)

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

        self.setCentralWidget(self.view)

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

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

    @Slot()
    def adjustTitle(self):
        if self.progress <= 0 or self.progress >= 100:
            self.setWindowTitle(self.view.title())
        else:
            self.setWindowTitle("%s (%2d)" %
                                (self.view.title(), self.progress))

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

    @Slot()
    def finishLoading(self):
        self.progress = 100
        self.adjustTitle()
        self.view.page().runJavaScript(self.jQuery)
        self.rotateImages(self.rotateAction.isChecked())

    @Slot()
    def viewSource(self):
        self.textEdit = QTextEdit()
        self.textEdit.setAttribute(Qt.WA_DeleteOnClose)
        self.textEdit.adjustSize()
        self.textEdit.move(self.geometry().center() -
                           self.textEdit.rect().center())
        self.textEdit.show()

        self.view.page().toHtml(self.textEdit.setPlainText)

    @Slot()
    def highlightAllLinks(self):
        code = "qt.jQuery('a').each( function () { qt.jQuery(this).css('background-color', 'yellow') } )"
        self.view.page().runJavaScript(code)

    @Slot(bool)
    def rotateImages(self, invert):
        code = ""
        if invert:
            code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(180deg)') } )"  # noqa: E501
        else:
            code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(0deg)') } )"  # noqa: E501
        self.view.page().runJavaScript(code)

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

    @Slot()
    def removeInlineFrames(self):
        code = "qt.jQuery('iframe').remove()"
        self.view.page().runJavaScript(code)

    @Slot()
    def removeObjectElements(self):
        code = "qt.jQuery('object').remove()"
        self.view.page().runJavaScript(code)

    @Slot()
    def removeEmbeddedElements(self):
        code = "qt.jQuery('embed').remove()"
        self.view.page().runJavaScript(code)