示例#1
0
class SettingDialog(QDialog):
    def __init__(self, mainWindow):
        super(SettingDialog, self).__init__()
        self.setWindowFlags(Qt.WindowCloseButtonHint)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.mainWindow = mainWindow
        self.setWindowTitle('Settings')
        position = self.mainWindow.getPopUpPosition(600, 510)
        self.setGeometry(position.x(), position.y(), 600, 510)
        self.setFixedHeight(510)
        self.setFixedWidth(600)
        verticalLayout = QVBoxLayout()
        layout = QHBoxLayout()
        layout.setContentsMargins(5, 5, 5, 5)
        self.settingList = QListWidget()
        layout.addWidget(self.settingList, 1)
        settingContent = QWidget(self)
        self.layout = QStackedLayout()
        settingContent.setLayout(self.layout)
        self.setUpPages()
        self.settingList.itemSelectionChanged.connect(self.switchSettingPage)

        horizontalButtonLayout = QHBoxLayout()
        cancelButton = QPushButton("Cancel")
        cancelButton.clicked.connect(self.close)
        saveButton = QPushButton("Save")
        saveButton.clicked.connect(self.saveAll)
        horizontalButtonLayout.addWidget(saveButton)
        horizontalButtonLayout.addWidget(cancelButton)

        verticalLayout.addLayout(layout)
        verticalLayout.addLayout(horizontalButtonLayout)
        layout.addWidget(settingContent, 9)
        self.setLayout(verticalLayout)
        self.exec()

    def setUpPages(self):
        self.settingList.addItem("Main")
        self.layout.addWidget(MainWidget(self))
        self.settingList.addItem("Colors")
        self.layout.addWidget(ColorsWidget(self))
        self.settingList.addItem("Macros")
        self.layout.addWidget(MacrosWidget(self))
        self.settingList.addItem("Notification")
        self.layout.addWidget(NotificationWidget(self))

    def switchSettingPage(self):
        self.layout.setCurrentIndex(self.settingList.currentRow())

    def saveAll(self):
        for i in range(self.layout.count() - 1, -1, -1):
            self.layout.widget(i).saveSetting()
        self.accept()
示例#2
0
class Window(BaseWindow):
    def __init__(self):
        super(Window, self).__init__()

        self.last_index = 0

        self.setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT)
        # 要想使 move_center 起作用,必须设置 resize
        self.resize(WINDOW_WIDTH, WINDOW_HEIGHT)
        self.move_center()
        self.setWindowIcon(QIcon(abs_path('static/images/icon/logo.png')))
        self.setWindowTitle('江科大课表导出 v1.0')

        self.stack_layout = QStackedLayout()
        self.stack_layout.addWidget(StepHello(self.stack_layout))
        self.stack_layout.addWidget(StepAccount(self.stack_layout))
        self.stack_layout.addWidget(StepDate(self.stack_layout))
        self.stack_layout.addWidget(StepSuccess(self.stack_layout))
        self.stack_layout.addWidget(StepMistake(self.stack_layout))
        self.stack_layout.setCurrentIndex(self.last_index)
        self.stack_layout.currentChanged.connect(self.interface_changed)

        self.setLayout(self.stack_layout)
        self.show()

    def interface_changed(self):
        if self.last_index < self.stack_layout.currentIndex():
            self.last_index = self.stack_layout.currentIndex()
        elif self.last_index == 4 and self.stack_layout.currentIndex() == 0:
            for i in range(3)[::-1]:
                self.stack_layout.widget(i).step_ani(True)
            self.last_index = 0
        elif self.last_index in [3, 4
                                 ] and self.stack_layout.currentIndex() == 2:
            self.stack_layout.widget(2).step_ani(True)
            self.last_index = 2
        elif self.last_index == 2 and self.stack_layout.currentIndex() == 1:
            self.stack_layout.widget(1).step_ani(True)
            self.last_index = 1
        elif self.last_index == 1 and self.stack_layout.currentIndex() == 0:
            self.stack_layout.widget(0).step_ani(True)
            self.last_index = 0
示例#3
0
class _MainContainer(QWidget):

    ###############################################################################
    # MainContainer SIGNALS
    ###############################################################################
    """
    newFileOpened(QString)
    allTabClosed()
    runFile(QString)
    addToProject(QString)
    showFileInExplorer(QString)
    recentTabsModified()
    currentEditorChanged(QString)
    fileOpened(QString)
    ---------migrationAnalyzed()
    findOcurrences(QString)
    ---------updateFileMetadata()
    editorKeyPressEvent(QEvent)
    locateFunction(QString, QString, bool) [functionName, filePath, isVariable]
    updateLocator(QString)
    beforeFileSaved(QString)
    fileSaved(QString)
    openPreferences()
    --------openProject(QString)
    ---------dontOpenStartPage()
    """

    ###############################################################################

    fileOpened = pyqtSignal('QString')
    updateLocator = pyqtSignal('QString')
    currentEditorChanged = pyqtSignal('QString')
    beforeFileSaved = pyqtSignal('QString')
    fileSaved = pyqtSignal('QString')

    def __init__(self, parent=None):
        super(_MainContainer, self).__init__(parent)
        self.setContentsMargins(0, 0, 0, 0)
        self._parent = parent
        self._vbox = QVBoxLayout(self)
        self._vbox.setContentsMargins(0, 0, 0, 0)
        self._vbox.setSpacing(0)
        self.stack = QStackedLayout()
        self.stack.setStackingMode(QStackedLayout.StackAll)
        self._vbox.addLayout(self.stack)
        self.splitter = dynamic_splitter.DynamicSplitter()
        self.setAcceptDrops(True)
        # self._files_handler = files_handler.FilesHandler(self)
        self._add_file_folder = add_file_folder.AddFileFolderWidget(self)

        # documentation browser
        self.docPage = None
        # Code Navigation
        # self._locator = locator.GoToDefinition()
        self.__codeBack = []
        self.__codeForward = []
        self.__bookmarksFile = ''
        self.__bookmarksPos = -1
        self.__breakpointsFile = ''
        self.__breakpointsPos = -1
        self.__operations = {
            0: self._navigate_code_jumps,
            1: self._navigate_bookmarks,
            2: self._navigate_breakpoints
        }

        # self.locateFunction['QString',
        #                    'QString',
        #                    bool].connect(self.locate_function)

        IDE.register_service('main_container', self)

        # Register signals connections
        connections = ({
            'target': 'main_container',
            'signal_name': 'updateLocator',
            'slot': self._explore_file_code
        }, {
            'target': 'filesystem',
            'signal_name': 'projectOpened',
            'slot': self._explore_code
        }, {
            'target': 'projects_explorer',
            'signal_name': 'updateLocator',
            'slot': self._explore_code
        })
        """
        {'target': 'menu_file',
            'signal_name': 'openFile(QString)',
            'slot': self.open_file},
        {'target': 'explorer_container',
            'signal_name': 'goToDefinition(int)',
            'slot': self.editor_go_to_line},
        {'target': 'explorer_container',
            'signal_name': 'pep8Activated(bool)',
            'slot': self.reset_pep8_warnings},
        {'target': 'explorer_container',
            'signal_name': 'lintActivated(bool)',
            'slot': self.reset_lint_warnings},
        {'target': 'filesystem',
            'signal_name': 'projectOpened',
            'slot': self._explore_code},
        {'target': 'main_container',
            'signal_name': 'updateLocator(QString)',
            'slot': self._explore_file_code},
        )
        """

        IDE.register_signals('main_container', connections)

        self.selector = main_selector.MainSelector(self)
        self._opening_dialog = False
        self.add_widget(self.selector)

        if settings.SHOW_START_PAGE:
            self.show_start_page()

        self.selector.changeCurrent[int].connect(self._change_current_stack)
        # self.selector.removeWidget[int].connect(self._remove_item_from_stack)
        # self.selector.ready.connect(self._selector_ready)
        self.selector.animationCompleted.connect(
            self._selector_animation_completed)
        # self.closeDialog['PyQt_PyObject'].connect(self.remove_widget)

    def install(self):
        ide = IDE.get_service('ide')
        ide.place_me_on("main_container", self, "central", top=True)

        self.combo_area = combo_editor.ComboEditor(original=True)
        self.combo_area.allFilesClosed.connect(self._files_closed)
        # self.combo_area.allFilesClosed.connect(self._files_closed)
        self.splitter.add_widget(self.combo_area)
        self.add_widget(self.splitter)

        self.current_widget = self.combo_area
        # Code Locator
        self._code_locator = locator_widget.LocatorWidget(ide)

        ui_tools.install_shortcuts(self, actions.ACTIONS, ide)

    def show_locator(self):
        """Show the locator widget"""

        if not self._code_locator.isVisible():
            self._code_locator.show()

    def _explore_code(self):
        """ Update locator metadata for the current projects """

        self._code_locator.explore_code()

    def _explore_file_code(self, path):
        """ Update locator metadata for the file in path """

        self._code_locator.explore_file_code(path)

    def add_status_bar(self, status):
        self._vbox.addWidget(status)

    @property
    def combo_header_size(self):
        return self.combo_area.bar.height()

    def add_widget(self, widget):
        self.stack.addWidget(widget)

    def remove_widget(self, widget):
        self.stack.removeWidget(widget)

    def _close_dialog(self, widget):
        self.emit(SIGNAL("closeDialog(PyQt_PyObject)"), widget)
        self.disconnect(widget, SIGNAL("finished(int)"),
                        lambda: self._close_dialog(widget))

    def show_dialog(self, widget):
        self._opening_dialog = True
        # self.connect(widget, SIGNAL("finished(int)"),
        #             lambda: self._close_dialog(widget))
        self.setVisible(True)
        self.stack.addWidget(widget)
        self.show_selector()

    def show_selector(self):
        if self.selector != self.stack.currentWidget():
            temp_dir = os.path.join(QDir.tempPath(), "ninja-ide")
            if not os.path.exists(temp_dir):
                os.mkdir(temp_dir)
            collected_data = []
            current = self.stack.currentIndex()
            for index in range(self.stack.count()):
                widget = self.stack.widget(index)
                if widget == self.selector:
                    continue
                pixmap = QWidget.grab(widget, widget.rect())
                path = os.path.join(temp_dir, "screen%s.png" % index)
                pixmap.save(path)
                collected_data.append((index, path))
            self.selector.set_model(collected_data)
            self._selector_ready()
        """
        if self.selector != self.stack.currentWidget():
            temp_dir = os.path.join(QDir.tempPath(), "ninja-ide")
            if not os.path.exists(temp_dir):
                os.mkdir(temp_dir)
            collected_data = []
            current = self.stack.currentIndex()
            for index in range(self.stack.count()):
                widget = self.stack.widget(index)
                if widget == self.selector:
                    continue
                closable = True
                if widget == self.splitter:
                    closable = False
                pixmap = QWidget.grab(widget, widget.rect())
                path = os.path.join(temp_dir, "screen%s.png" % index)
                pixmap.save(path)
                if index == current:
                    self.selector.set_preview(index, path)
                    collected_data.insert(0, (index, path, closable))
                else:
                    collected_data.append((index, path, closable))
            self.selector.set_model(collected_data)
        else:
            self.selector.close_selector()
        """

    def _selector_ready(self):
        print(self.stack.currentWidget())
        self.stack.setCurrentWidget(self.selector)
        print(self.stack.currentWidget())
        self.selector.start_animation()

    def _selector_animation_completed(self):
        if self._opening_dialog:
            # We choose the last one with -2, -1 (for last one) +
            # -1 for the hidden selector widget which is in the stacked too.
            self.selector.open_item(self.stack.count() - 2)
        self._opening_dialog = False

    def _change_current_stack(self, index):
        self.stack.setCurrentIndex(index)

    def _remove_item_from_stack(self, index):
        widget = self.stack.takeAt(index)
        del widget

    def show_editor_area(self):
        self.stack.setCurrentWidget(self.splitter)

    def _files_closed(self):
        if settings.SHOW_START_PAGE:
            self.show_start_page()

    def change_visibility(self):
        """Show/Hide the Main Container area."""
        if self.isVisible():
            self.hide()
        else:
            self.show()

    def expand_symbol_combo(self):
        self.stack.setCurrentWidget(self.splitter)
        self.current_widget.show_combo_symbol()

    def expand_file_combo(self):
        self.stack.setCurrentWidget(self.splitter)
        self.current_widget.show_combo_file()

    def locate_function(self, function, filePath, isVariable):
        """Move the cursor to the proper position in the navigate stack."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            self.__codeBack.append(
                (editorWidget.file_path, editorWidget.getCursorPosition()))
            self.__codeForward = []
        self._locator.navigate_to(function, filePath, isVariable)

    def run_file(self, path):
        self.emit(SIGNAL("runFile(QString)"), path)

    def _add_to_project(self, path):
        self.emit(SIGNAL("addToProject(QString)"), path)

    def _show_file_in_explorer(self, path):
        self.emit(SIGNAL("showFileInExplorer(QString)"), path)

    def paste_history(self):
        """Paste the text from the copy/paste history."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            line, index = editorWidget.getCursorPosition()
            central = IDE.get_service('central_container')
            if central:
                editorWidget.insertAt(central.get_paste(), line, index)

    def copy_history(self):
        """Copy the selected text into the copy/paste history."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            copy = editorWidget.selectedText()
            central = IDE.get_service('central_container')
            if central:
                central.add_copy(copy)

    def import_from_everywhere(self):
        """Insert an import line from any place in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            dialog = from_import_dialog.FromImportDialog(editorWidget, self)
            dialog.show()

    def add_back_item_navigation(self):
        """Add an item to the back stack and reset the forward stack."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            self.__codeBack.append(
                (editorWidget.file_path, editorWidget.cursor_position))
            self.__codeForward = []

    def preview_in_browser(self):
        """Load the current html file in the default browser."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            if not editorWidget.file_path:
                self.save_file()
            ext = file_manager.get_file_extension(editorWidget.file_path)
            if ext in ('html', 'shpaml', 'handlebars', 'tpl'):
                webbrowser.open_new_tab(editorWidget.file_path)

    def add_bookmark_breakpoint(self):
        """Add a bookmark or breakpoint to the current file in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            if self.current_widget.bar.code_navigator.operation == 1:
                editorWidget.handle_bookmarks_breakpoints(
                    editorWidget.getCursorPosition()[0], Qt.ControlModifier)
            elif self.current_widget.bar.code_navigator.operation == 2:
                editorWidget.handle_bookmarks_breakpoints(
                    editorWidget.getCursorPosition()[0], Qt.NoModifier)

    def __navigate_with_keyboard(self, val):
        """Navigate between the positions in the jump history stack."""
        op = self.current_widget.bar.code_navigator.operation
        self.navigate_code_history(val, op)

    def navigate_code_history(self, val, op):
        """Navigate the code history."""
        self.__operations[op](val)

    def _navigate_code_jumps(self, val):
        """Navigate between the jump points."""
        node = None
        if not val and self.__codeBack:
            node = self.__codeBack.pop()
            editorWidget = self.get_current_editor()
            if editorWidget:
                self.__codeForward.append(
                    (editorWidget.file_path, editorWidget.getCursorPosition()))
        elif val and self.__codeForward:
            node = self.__codeForward.pop()
            editorWidget = self.get_current_editor()
            if editorWidget:
                self.__codeBack.append(
                    (editorWidget.file_path, editorWidget.getCursorPosition()))
        if node:
            filename = node[0]
            line, col = node[1]
            self.open_file(filename, line, col)

    def _navigate_breakpoints(self, val):
        """Navigate between the breakpoints."""
        # FIXME: put navigate breakpoints and bookmarks as one method.
        breakList = list(settings.BREAKPOINTS.keys())
        breakList.sort()
        if not breakList:
            return
        if self.__breakpointsFile not in breakList:
            self.__breakpointsFile = breakList[0]
        index = breakList.index(self.__breakpointsFile)
        breaks = settings.BREAKPOINTS.get(self.__breakpointsFile, [])
        lineNumber = 0
        # val == True: forward
        if val:
            if (len(breaks) - 1) > self.__breakpointsPos:
                self.__breakpointsPos += 1
                lineNumber = breaks[self.__breakpointsPos]
            elif len(breaks) > 0:
                if index < (len(breakList) - 1):
                    self.__breakpointsFile = breakList[index + 1]
                else:
                    self.__breakpointsFile = breakList[0]
                self.__breakpointsPos = 0
                lineNumber = settings.BREAKPOINTS[self.__breakpointsFile][0]
        else:
            if self.__breakpointsPos > 0:
                self.__breakpointsPos -= 1
                lineNumber = breaks[self.__breakpointsPos]
            elif len(breaks) > 0:
                self.__breakpointsFile = breakList[index - 1]
                breaks = settings.BREAKPOINTS[self.__breakpointsFile]
                self.__breakpointsPos = len(breaks) - 1
                lineNumber = breaks[self.__breakpointsPos]
        if file_manager.file_exists(self.__breakpointsFile):
            self.open_file(self.__breakpointsFile, lineNumber, None, True)
        else:
            settings.BREAKPOINTS.pop(self.__breakpointsFile)
            if settings.BREAKPOINTS:
                self._navigate_breakpoints(val)

    def _navigate_bookmarks(self, val):
        """Navigate between the bookmarks."""
        bookList = list(settings.BOOKMARKS.keys())
        bookList.sort()
        if not bookList:
            return
        if self.__bookmarksFile not in bookList:
            self.__bookmarksFile = bookList[0]
        index = bookList.index(self.__bookmarksFile)
        bookms = settings.BOOKMARKS.get(self.__bookmarksFile, [])
        lineNumber = 0
        # val == True: forward
        if val:
            if (len(bookms) - 1) > self.__bookmarksPos:
                self.__bookmarksPos += 1
                lineNumber = bookms[self.__bookmarksPos]
            elif len(bookms) > 0:
                if index < (len(bookList) - 1):
                    self.__bookmarksFile = bookList[index + 1]
                else:
                    self.__bookmarksFile = bookList[0]
                self.__bookmarksPos = 0
                lineNumber = settings.BOOKMARKS[self.__bookmarksFile][0]
        else:
            if self.__bookmarksPos > 0:
                self.__bookmarksPos -= 1
                lineNumber = bookms[self.__bookmarksPos]
            elif len(bookms) > 0:
                self.__bookmarksFile = bookList[index - 1]
                bookms = settings.BOOKMARKS[self.__bookmarksFile]
                self.__bookmarksPos = len(bookms) - 1
                lineNumber = bookms[self.__bookmarksPos]
        if file_manager.file_exists(self.__bookmarksFile):
            self.open_file(self.__bookmarksFile, lineNumber, None, True)
        else:
            # settings.BOOKMARKS.pop(self.__bookmarksFile)
            if settings.BOOKMARKS:
                self._navigate_bookmarks(val)

    def count_file_code_lines(self):
        """Count the lines of code in the current file."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            block_count = editorWidget.lines()
            blanks = re.findall('(^\n)|(^(\s+)?#)|(^( +)?($|\n))',
                                editorWidget.text(), re.M)
            blanks_count = len(blanks)
            resume = self.tr("Lines code: %s\n") % (block_count - blanks_count)
            resume += (self.tr("Blanks and commented lines: %s\n\n") %
                       blanks_count)
            resume += self.tr("Total lines: %s") % blockdget
            msgBox.exec_()

            msgBox = QMessageBox(QMessageBox.Information,
                                 self.tr("Summary of lines"), resume,
                                 QMessageBox.Ok, editorWidget)

    def editor_cut(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.cut()

    def editor_copy(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.copy()

    def editor_paste(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.paste()

    def editor_upper(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_upper()

    def editor_lower(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_lower()

    def editor_title(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_title()

    def editor_go_to_definition(self):
        """Search the definition of the method or variable under the cursor.

        If more than one method or variable is found with the same name,
        shows a table with the results and let the user decide where to go."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.go_to_definition()

    def editor_redo(self):
        """Execute the redo action in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.redo()

    def editor_undo(self):
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.undo()

    def editor_indent_less(self):
        """Indent 1 position to the left for the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.indent_less()

    def editor_indent_more(self):
        """Indent 1 position to the right for the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.indent_more()

    def editor_insert_debugging_prints(self):
        """Insert a print statement in each selected line."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.insert_debugging_prints(editorWidget)

    def editor_insert_pdb(self):
        """Insert a pdb.set_trace() statement in tjhe current line."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.insert_pdb(editorWidget)

    def editor_comment(self):
        """Mark the current line or selection as a comment."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.comment_or_uncomment(editorWidget)

    def editor_uncomment(self):
        """Uncomment the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.uncomment(editorWidget)

    def editor_insert_horizontal_line(self):
        """Insert an horizontal lines of comment symbols."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.insert_horizontal_line(editorWidget)

    def editor_insert_title_comment(self):
        """Insert a Title surrounded by comment symbols."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.insert_title_comment(editorWidget)

    def editor_remove_trailing_spaces(self):
        """Remove the trailing spaces in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.remove_trailing_spaces(editorWidget)

    def editor_replace_tabs_with_spaces(self):
        """Replace the Tabs with Spaces in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.replace_tabs_with_spaces(editorWidget)

    def editor_move_up(self):
        """Move the current line or selection one position up."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.move_up(editorWidget)

    def editor_move_down(self):
        """Move the current line or selection one position down."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.move_down(editorWidget)

    def editor_remove_line(self):
        """Remove the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.remove_line(editorWidget)

    def editor_duplicate(self):
        """Duplicate the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.duplicate(editorWidget)

    def editor_highlight_word(self):
        """Highlight the occurrences of the current word in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.highlight_selected_word()

    def editor_complete_declaration(self):
        """Do the opposite action that Complete Declaration expect."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.complete_declaration()

    def editor_go_to_line(self, line):
        """ Jump to the specified line in the current editor. """

        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.go_to_line(line)
            editorWidget.setFocus()

    def zoom_in_editor(self):
        """Increase the font size in the current editor."""

        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.zoom(1.0)

    def zoom_out_editor(self):
        """Decrease the font size in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.zoom(-1.0)

    def reset_zoom(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.reset_zoom()

    def recent_files_changed(self):
        self.emit(SIGNAL("recentTabsModified()"))

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        file_path = event.mimeData().urls()[0].toLocalFile()
        self.open_file(file_path)

    def setFocus(self):
        widget = self.get_current_widget()
        if widget:
            widget.setFocus()

    def current_editor_changed(self, filename):
        """Notify the new filename of the current editor."""
        if filename is None:
            filename = translations.TR_NEW_DOCUMENT
        self.currentEditorChanged.emit(filename)

    def show_split(self, orientation_vertical=False):
        # IDE.select_current(self.current_widget.currentWidget())
        self.current_widget.split_editor(orientation_vertical)

    def add_editor(self, fileName=None, ignore_checkers=False):
        ninjaide = IDE.get_service('ide')
        editable = ninjaide.get_or_create_editable(fileName)
        if editable.editor:
            self.current_widget.set_current(editable)
            return self.current_widget.currentWidget()
        else:
            editable.ignore_checkers = ignore_checkers

        editorWidget = self.create_editor_from_editable(editable)

        # add the tab
        keep_index = (self.splitter.count() > 1
                      and self.combo_area.stacked.count() > 0)
        self.combo_area.add_editor(editable, keep_index)

        # emit a signal about the file open
        self.fileOpened.emit(fileName)

        if not keep_index:
            self.current_widget.set_current(editable)

        self.stack.setCurrentWidget(self.splitter)

        editorWidget.setFocus()

        return editorWidget

    def create_editor_from_editable(self, editable):
        neditor = editor.create_editor(editable)

        # Connect signals
        neditor.zoomChanged[int].connect(self._show_zoom_indicator)
        neditor.destroyed.connect(self._editor_destroyed)
        editable.fileSaved.connect(self._editor_tab_was_saved)
        neditor.addBackItemNavigation.connect(self.add_back_item_navigation)
        # self.connect(editable, SIGNAL("fileSaved(PyQt_PyObject)"),
        #             self._editor_tab_was_saved)
        # editorWidget.font_changed.connect(self.show_zoom_indicator)
        # self.connect(editorWidget, SIGNAL("openDropFile(QString)"),
        #             self.open_file)
        # self.connect(editorWidget, SIGNAL("addBackItemNavigation()"),
        #             self.add_back_item_navigation)
        # self.connect(editorWidget,
        #             SIGNAL("locateFunction(QString, QString, bool)"),
        #             self._editor_locate_function)
        # self.connect(editorWidget, SIGNAL("findOcurrences(QString)"),
        #             self._find_occurrences)
        # keyPressEventSignal for plugins
        # self.connect(editorWidget, SIGNAL("keyPressEvent(QEvent)"),
        #             self._editor_keyPressEvent)

        return neditor

    def _editor_destroyed(self):
        ui_tools.FadingIndicator.editor_destroyed()

    def _show_zoom_indicator(self, text):
        neditor = self.get_current_editor()
        ui_tools.FadingIndicator.show_text(neditor,
                                           "Zoom: {}%".format(str(text)))

    def reset_pep8_warnings(self, value):
        pass
        # FIXME: check how we handle this
        # for i in range(self._tabMain.count()):
        # widget = self._tabMain.widget(i)
        # if type(widget) is editor.Editor:
        # if value:
        # widget.syncDocErrorsSignal = True
        # widget.pep8.check_style()
        # else:
        # widget.hide_pep8_errors()

    def reset_lint_warnings(self, value):
        pass
        #FIXME: check how we handle this
        # for i in range(self._tabMain.count()):
        #widget = self._tabMain.widget(i)
        #if type(widget) is editor.Editor:
        #if value:
        #widget.syncDocErrorsSignal = True
        #widget.errors.check_errors()
        #else:
        #widget.hide_lint_errors()

    def show_zoom_indicator(self, text):
        ui_tools.FadingIndicator.show_text(self, "Zoom: {0}%".format(text))

    def _find_occurrences(self, word):
        self.emit(SIGNAL("findOcurrences(QString)"), word)

    def _editor_keyPressEvent(self, event):
        self.emit(SIGNAL("editorKeyPressEvent(QEvent)"), event)

    def _editor_locate_function(self, function, filePath, isVariable):
        self.emit(SIGNAL("locateFunction(QString, QString, bool)"), function,
                  filePath, isVariable)

    def _editor_tab_was_saved(self, editable=None):
        self.updateLocator.emit(editable.file_path)
        # self.emit(SIGNAL("updateLocator(QString)"), editable.file_path)

    def get_current_widget(self):
        return self.current_widget.currentWidget()

    def get_current_editor(self):
        """Return the Actual Editor or None

        Return an instance of Editor if the Current Tab contains
        an Editor or None if it is not an instance of Editor"""
        widget = self.current_widget.currentWidget()
        if isinstance(widget, editor.NEditor):
            return widget
        return None

    def reload_file(self, editorWidget=None):
        if editorWidget is None:
            editorWidget = self.get_current_editor()
            editorWidget.neditable.reload_file()

    def open_image(self, fileName):
        try:
            if not self.is_open(fileName):
                viewer = image_viewer.ImageViewer(fileName)
                # self.add_tab(viewer, file_manager.get_basename(fileName))
                # viewer.ID = fileName
            else:
                self.move_to_open(fileName)
        except Exception as reason:
            logger.error('open_image: %s', reason)
            QMessageBox.information(self, self.tr("Incorrect File"),
                                    self.tr("The image couldn\'t be open"))

    def open_file(self, filename='', line=-1, col=0, ignore_checkers=False):
        logger.debug("will try to open %s" % filename)
        if not filename:
            logger.debug("has nofilename")
            if settings.WORKSPACE:
                directory = settings.WORKSPACE
            else:
                directory = os.path.expanduser("~")
                editorWidget = self.get_current_editor()
                ninjaide = IDE.get_service('ide')
                if ninjaide:
                    current_project = ninjaide.get_current_project()
                    if current_project is not None:
                        directory = current_project
                    elif editorWidget is not None and editorWidget.file_path:
                        directory = file_manager.get_folder(
                            editorWidget.file_path)
            extensions = ';;'.join([
                '{}(*{})'.format(e.upper()[1:], e)
                for e in settings.SUPPORTED_EXTENSIONS + ['.*', '']
            ])
            fileNames = QFileDialog.getOpenFileNames(self,
                                                     self.tr("Open File"),
                                                     directory, extensions)[0]
        else:
            logger.debug("has filename")
            fileNames = [filename]
        if not fileNames:
            return

        for filename in fileNames:
            image_extensions = ('bmp', 'gif', 'jpeg', 'jpg', 'png')
            if file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("will open as image")
                self.open_image(filename)
            elif file_manager.get_file_extension(filename).endswith('ui'):
                logger.debug("will load in ui editor")
                self.w = uic.loadUi(filename)
                self.w.show()
            else:
                logger.debug("will try to open: " + filename)
                self.__open_file(filename, line, col, ignore_checkers)

    def __open_file(self, fileName='', line=-1, col=0, ignore_checkers=False):
        try:
            editorWidget = self.add_editor(fileName,
                                           ignore_checkers=ignore_checkers)
            if line != -1:
                editorWidget.go_to_line(line, col)
            self.currentEditorChanged.emit(fileName)
        except file_manager.NinjaIOException as reason:
            QMessageBox.information(self, self.tr("The file couldn't be open"),
                                    str(reason))

    def is_open(self, filename):
        pass
        #return self.tabs.is_open(filename) != -1

    def move_to_open(self, filename):
        pass
        #FIXME: add in the current split?
        #if self.tabs.is_open(filename) != -1:
        #self.tabs.move_to_open(filename)
        #self.tabs.currentWidget().setFocus()
        #self.emit(SIGNAL("currentEditorChanged(QString)"), filename)

    def get_widget_for_id(self, filename):
        pass
        #widget = None
        #index = self.tabs.is_open(filename)
        #if index != -1:
        #widget = self.tabs.widget(index)
        #return widget

    def change_open_tab_id(self, idname, newId):
        """Search for the Tab with idname, and set the newId to that Tab."""
        pass
        #index = self.tabs.is_open(idname)
        #if index != -1:
        #widget = self.tabs.widget(index)
        #tabName = file_manager.get_basename(newId)
        #self.tabs.change_open_tab_name(index, tabName)
        #widget.ID = newId

    def close_deleted_file(self, idname):
        """Search for the Tab with id, and ask the user if should be closed."""
        pass
        #index = self.tabs.is_open(idname)
        #if index != -1:
        #result = QMessageBox.question(self, self.tr("Close Deleted File"),
        #self.tr("Are you sure you want to close the deleted file?\n"
        #"The content will be completely deleted."),
        #buttons=QMessageBox.Yes | QMessageBox.No)
        #if result == QMessageBox.Yes:
        #self.tabs.removeTab(index)

    def save_file(self, editorWidget=None):
        # FIXME: check how we handle this
        if not editorWidget:
            editorWidget = self.get_current_editor()
        if editorWidget is None:
            return False
        # Ok, we have an editor instance
        # Save to file only if editor really was modified
        if editorWidget.is_modified:
            try:
                if (editorWidget.nfile.is_new_file
                        or not editorWidget.nfile.has_write_permission()):
                    return self.save_file_as()

                self.beforeFileSaved.emit(editorWidget.file_path)

                if settings.REMOVE_TRAILING_SPACES:
                    helpers.remove_trailing_spaces(editorWidget)
                # New line at end
                # FIXME: from settings
                helpers.insert_block_at_end(editorWidget)
                # Save convent
                editorWidget.neditable.save_content()
                encoding = file_manager.get_file_encoding(editorWidget.text)
                editorWidget.encoding = encoding

                self.fileSaved.emit(
                    self.tr("File Saved: {}".format(editorWidget.file_path)))

                return True
            except Exception as reason:
                logger.error('save_file: %s', reason)
                QMessageBox.information(self, self.tr("Save Error"),
                                        self.tr("The file couldn't be saved!"))
            return False

    def save_file_as(self):
        editorWidget = self.get_current_editor()
        if not editorWidget:
            return False
        try:
            filters = '(*.py);;(*.*)'
            if editorWidget.file_path:  # existing file
                ext = file_manager.get_file_extension(editorWidget.file_path)
                if ext != 'py':
                    filters = '(*.%s);;(*.py);;(*.*)' % ext
            save_folder = self._get_save_folder(editorWidget.file_path)
            fileName = QFileDialog.getSaveFileName(self._parent,
                                                   self.tr("Save File"),
                                                   save_folder, filters)[0]
            if not fileName:
                return False

            if settings.REMOVE_TRAILING_SPACES:
                helpers.remove_trailing_spaces(editorWidget)

            ext = file_manager.get_file_extension(fileName)
            if not ext:
                fileName = '%s.%s' % (
                    fileName,
                    'py',
                )

            editorWidget.neditable.save_content(path=fileName)
            # editorWidget.register_syntax(
            #     file_manager.get_file_extension(fileName))

            self.fileSaved.emit(self.tr("File Saved: {}".format(fileName)))

            self.currentEditorChanged.emit(fileName)

            return True
        except file_manager.NinjaFileExistsException as ex:
            QMessageBox.information(
                self, self.tr("File Already Exists"),
                (self.tr("Invalid Path: the file '%s' "
                         " already exists.") % ex.filename))
        except Exception as reason:
            logger.error('save_file_as: %s', reason)
            QMessageBox.information(self, self.tr("Save Error"),
                                    self.tr("The file couldn't be saved!"))
        return False

    def _get_save_folder(self, fileName):
        """
        Returns the root directory of the 'Main Project' or the home folder
        """
        ninjaide = IDE.get_service('ide')
        current_project = ninjaide.get_current_project()
        if current_project:
            return current_project.path
        return os.path.expanduser("~")

    def save_project(self, projectFolder):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
        #editorWidget = self._tabMain.widget(i)
        #if type(editorWidget) is editor.Editor and \
        #file_manager.belongs_to_folder(projectFolder,
        #editorWidget.file_path):
        #reloaded = self._tabMain.check_for_external_modifications(
        #editorWidget)
        #if not reloaded:
        #self.save_file(editorWidget)
        #for i in range(self.tabsecondary.count()):
        #editorWidget = self.tabsecondary.widget(i)
        #if type(editorWidget) is editor.Editor and \
        #file_manager.belongs_to_folder(projectFolder,
        #editorWidget.file_path):
        #reloaded = self.tabsecondary.check_for_external_modifications(
        #editorWidget)
        #if not reloaded:
        #self.save_file(editorWidget)

    def save_all(self):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
        #editorWidget = self._tabMain.widget(i)
        #if type(editorWidget) is editor.Editor:
        #reloaded = self._tabMain.check_for_external_modifications(
        #editorWidget)
        #if not reloaded:
        #self.save_file(editorWidget)
        #for i in range(self.tabsecondary.count()):
        #editorWidget = self.tabsecondary.widget(i)
        #self.tabsecondary.check_for_external_modifications(editorWidget)
        #if type(editorWidget) is editor.Editor:
        #reloaded = self.tabsecondary.check_for_external_modifications(
        #editorWidget)
        #if not reloaded:
        #self.save_file(editorWidget)

    def call_editors_function(self, call_function, *arguments):
        pass
        #args = arguments[0]
        #kwargs = arguments[1]
        #for i in range(self.tabs.count()):
        #editorWidget = self.tabs.widget(i)
        #if isinstance(editorWidget, editor.Editor):
        #function = getattr(editorWidget, call_function)
        #function(*args, **kwargs)
        #TODO: add other splits

    def show_start_page(self):
        start = self.stack.widget(0)
        if isinstance(start, start_page.StartPage):
            self.stack.setCurrentIndex(0)
        else:
            startPage = start_page.StartPage(parent=self)
            # self.connect(startPage, SIGNAL("openProject(QString)"),
            #             self.open_project)
            # self.connect(startPage, SIGNAL("openPreferences()"),
            #             lambda: self.emit(SIGNAL("openPreferences()")))
            # Connections
            startPage.newFile.connect(self.add_editor)
            self.stack.insertWidget(0, startPage)
            self.stack.setCurrentIndex(0)

    def show_python_doc(self):
        if sys.platform == 'win32':
            self.docPage = browser_widget.BrowserWidget(
                'http://docs.python.org/')
        else:
            process = runner.start_pydoc()
            self.docPage = browser_widget.BrowserWidget(process[1], process[0])
        self.add_tab(self.docPage, translations.TR_PYTHON_DOC)

    def show_report_bugs(self):
        webbrowser.open(resources.BUGS_PAGE)

    def show_plugins_doc(self):
        bugsPage = browser_widget.BrowserWidget(resources.PLUGINS_DOC, self)
        self.add_tab(bugsPage, translations.TR_HOW_TO_WRITE_PLUGINS)

    def editor_jump_to_line(self, lineno=None):
        """Jump to line *lineno* if it is not None
        otherwise ask to the user the line number to jump
        """
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.jump_to_line(lineno=lineno)

    def get_opened_documents(self):
        #return self.tabs.get_documents_data()
        return []

    def check_for_unsaved_files(self):
        pass
        #return self.tabs._check_unsaved_tabs()

    def get_unsaved_files(self):
        pass
        #return self.tabs.get_unsaved_files()

    def reset_editor_flags(self):
        pass
        #for i in range(self.tabs.count()):
        #widget = self.tabs.widget(i)
        #if isinstance(widget, editor.Editor):
        #widget.set_flags()

    def _specify_syntax(self, widget, syntaxLang):
        if isinstance(widget, editor.Editor):
            widget.restyle(syntaxLang)

    def apply_editor_theme(self, family, size):
        pass
        #for i in range(self.tabs.count()):
        #widget = self.tabs.widget(i)
        #if isinstance(widget, editor.Editor):
        #widget.restyle()
        #widget.set_font(family, size)

    def update_editor_margin_line(self):
        pass
        #for i in range(self.tabs.count()):
        #widget = self.tabs.widget(i)
        #if isinstance(widget, editor.Editor):
        #widget._update_margin_line()

    def open_project(self, path):
        self.emit(SIGNAL("openProject(QString)"), path)

    def close_python_doc(self):
        pass
        # close the python document server (if running)
        # if self.docPage:
        #    index = self.tabs.indexOf(self.docPage)
        #    self.tabs.removeTab(index)
        #    assign None to the browser
        #    self.docPage = None

    def close_file(self):
        self.current_widget.close_current_file()

    def create_file(self, base_path, project_path):
        self._add_file_folder.create_file(base_path, project_path)

    def create_folder(self, base_path, project_path):
        self._add_file_folder.create_folder(base_path, project_path)

    def change_tab(self):
        """Change the tab in the current TabWidget."""
        self.stack.setCurrentWidget(self.splitter)
        # self._files_handler.next_item()

    def change_tab_reverse(self):
        """Change the tab in the current TabWidget backwards."""
        self.stack.setCurrentWidget(self.splitter)
        # self._files_handler.previous_item()

    def toggle_tabs_and_spaces(self):
        """Toggle Show/Hide Tabs and Spaces"""

        settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES
        qsettings = IDE.ninja_settings()
        qsettings.setValue('preferences/editor/show_tabs_and_spaces',
                           settings.SHOW_TABS_AND_SPACES)
        neditor = self.get_current_editor()
        if neditor is not None:
            neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES

    def show_navigation_buttons(self):
        """Show Navigation menu."""
        self.stack.setCurrentWidget(self.splitter)
        self.combo_area.show_menu_navigation()

    def change_split_focus(self):
        pass
        #FIXME: check how we handle this
        #if self.actualTab == self._tabMain and self.tabsecondary.isVisible():
        #self.actualTab = self.tabsecondary
        #else:
        #self.actualTab = self._tabMain
        #widget = self.actualTab.currentWidget()
        #if widget is not None:
        #widget.setFocus()

    def shortcut_index(self, index):
        pass
        #self.tabs.setCurrentIndex(index)

    def print_file(self):
        """Call the print of ui_tool

        Call print of ui_tool depending on the focus of the application"""
        #TODO: Add funtionality for proyect tab and methods tab
        editorWidget = self.get_current_editor()
        if editorWidget is not None:
            fileName = "newDocument.pdf"
            if editorWidget.file_path:
                fileName = file_manager.get_basename(editorWidget.file_path)
                fileName = fileName[:fileName.rfind('.')] + '.pdf'
            ui_tools.print_file(fileName, editorWidget.print_)

    def split_assistance(self):
        dialog = split_orientation.SplitOrientation(self)
        dialog.show()

    # def close_split(self):
    #    if self.current_widget != self.combo_area:
    #        self.current_widget.bar.close_split()

    # def split_vertically(self):
    #    self.show_split(False)

    # def split_horizontally(self):
    #    self.show_split(True)

    def navigate_back(self):
        self.__navigate_with_keyboard(False)

    def navigate_forward(self):
        self.__navigate_with_keyboard(True)
示例#4
0
class ComboEditor(QWidget):
    # Signals
    closeSplit = pyqtSignal('PyQt_PyObject')
    splitEditor = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject', Qt.Orientation)
    allFilesClosed = pyqtSignal()
    about_to_close_combo_editor = pyqtSignal()
    fileClosed = pyqtSignal("PyQt_PyObject")

    def __init__(self, original=False):
        super(ComboEditor, self).__init__(None)
        self.__original = original
        self.__undocked = []
        self._symbols_index = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(main_combo=original)
        vbox.addWidget(self.bar)

        # Info bar
        # self.info_bar = InfoBar(self)
        # self.info_bar.setVisible(False)
        # vbox.addWidget(self.info_bar)

        self.stacked = QStackedLayout()
        vbox.addLayout(self.stacked)

        self._main_container = IDE.get_service('main_container')

        if not self.__original:
            self._main_container.fileOpened['QString'].connect(
                self._file_opened_by_main)

        self.bar.combo_files.showComboSelector.connect(
            self._main_container.show_files_handler)
        self.bar.combo_files.hideComboSelector.connect(
            self._main_container.hide_files_handler)
        self.bar.change_current['PyQt_PyObject',
                                int].connect(self._set_current)
        self.bar.splitEditor[bool].connect(self.split_editor)
        self.bar.runFile['QString'].connect(self._run_file)
        self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject['QString'].connect(self._add_to_project)
        self.bar.showFileInExplorer['QString'].connect(
            self._show_file_in_explorer)
        self.bar.goToSymbol[int].connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.reopenTab['QString'].connect(
            lambda path: self._main_container.open_file(path))
        self.bar.closeImageViewer.connect(self._close_image)
        self.bar.code_navigator.previousPressed.connect(self._navigate_code)
        self.bar.code_navigator.nextPressed.connect(self._navigate_code)
        # self.connect(self.bar, SIGNAL("recentTabsModified()"),
        #             lambda: self._main_container.recent_files_changed())
        # self.connect(self.bar.code_navigator.btnPrevious,
        #                SIGNAL("clicked()"),
        #             lambda: self._navigate_code(False))
        # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"),
        #             lambda: self._navigate_code(True))

    def _navigate_code(self, operation, forward=True):
        self._main_container.navigate_code_history(operation, forward)

    #    op = self.bar.code_navigator.operation
    #    self._main_container.navigate_code_history(val, op)

    def current_editor(self):
        return self.stacked.currentWidget()

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        self.current_editor().setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stacked.currentIndex()
        ninjaide = IDE.get_service('ide')
        editable = ninjaide.get_or_create_editable(path)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_image_viewer(self, viewer):
        """Add Image Viewer widget to the UI area"""

        self.stacked.addWidget(viewer)
        viewer.scaleFactorChanged.connect(
            self.bar.image_viewer_controls.update_scale_label)
        viewer.imageSizeChanged.connect(
            self.bar.image_viewer_controls.update_size_label)
        self.bar.add_item(viewer.display_name(), None)
        viewer.create_scene()
        if not self.bar.isVisible():
            self.bar.setVisible(True)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original:
                editor = neditable.editor
            else:
                # editor = neditable.editor.clone()
                editor = self._main_container.create_editor_from_editable(
                    neditable)
                neditable.editor.link(editor)

            current_index = self.stacked.currentIndex()
            new_index = self.stacked.addWidget(editor)
            self.stacked.setCurrentIndex(new_index)
            self.bar.add_item(neditable.display_name, neditable)
            # Bar is not visible because all the files have been closed,
            # so if a new file is opened, show the bar
            if not self.bar.isVisible():
                self.bar.setVisible(True)
            if keep_index:
                self.bar.set_current_by_index(current_index)

            # Connections
            neditable.fileClosing.connect(self._close_file)
            neditable.fileSaved.connect(self._update_symbols)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.modificationChanged.connect(self._editor_modified)
            editor.cursor_position_changed[int, int].connect(
                self._update_cursor_position)
            editor.current_line_changed[int].connect(self._set_current_symbol)
            if neditable._swap_file.dirty:
                self._editor_modified(True, sender=editor)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            # Connect file system signals only in the original
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)
            # Load Symbols
            self._load_symbols(neditable)

    def show_combo_file(self):
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def show_combo_set_language(self):
        self.bar.set_language_combo.showPopup()

    def unlink_editors(self):
        for index in range(self.stacked.count()):
            widget = self.stacked.widget(index)
            # widget.setDocument(QsciDocument())

    def clone(self):
        combo = ComboEditor()
        for neditable in self.bar.get_editables():
            combo.add_editor(neditable)
        return combo

    def split_editor(self, orientation):
        new_combo = self.clone()
        self.splitEditor.emit(self, new_combo, orientation)

    def undock_editor(self):
        new_combo = ComboEditor()
        for neditable in self.bar.get_editables():
            new_combo.add_editor(neditable)
        self.__undocked.append(new_combo)
        new_combo.setWindowTitle("NINJA-IDE")
        editor = self.current_editor()
        new_combo.set_current(editor.neditable)
        new_combo.resize(700, 500)
        new_combo.about_to_close_combo_editor.connect(self._remove_undock)
        new_combo.show()

    def _remove_undock(self):
        widget = self.sender()
        self.__undocked.remove(widget)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_image(self, index):
        layout_item = self.stacked.takeAt(index)
        layout_item.widget().deleteLater()
        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()

    def _close_file(self, neditable):
        index = self.bar.close_file(neditable)
        layoutItem = self.stacked.takeAt(index)
        # neditable.editor.completer.cc.unload_module()
        self.fileClosed.emit(neditable.nfile)
        layoutItem.widget().deleteLater()

        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()
            tree_symbols = IDE.get_service("symbols_explorer")
            if tree_symbols is not None:
                tree_symbols.clear()

    def _editor_with_focus(self):
        self._main_container.combo_area = self
        editor = self.current_editor()
        if editor is not None:
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') % fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    @pyqtSlot("PyQt_PyObject")
    def _recovery(self, neditable):
        print("lalalal")

    def _file_has_been_modified(self, neditable):
        index = self.bar.combo_files.findData(neditable)
        self.stacked.setCurrentIndex(index)
        self.bar.combo_files.setCurrentIndex(index)

        msg_box = QMessageBox(self)
        msg_box.setIcon(QMessageBox.Information)
        msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msg_box.setDefaultButton(QMessageBox.Yes)
        msg_box.setWindowTitle(translations.TR_FILE_HAS_BEEN_MODIFIED)
        msg_box.setText(translations.TR_FILE_MODIFIED_OUTSIDE %
                        neditable.display_name)

        result = msg_box.exec_()
        if result == QMessageBox.Yes:
            neditable.reload_file()
        return

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''

        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        self.stacked.setCurrentIndex(index)
        if neditable:
            self.bar.image_viewer_controls.setVisible(False)
            self.bar.code_navigator.setVisible(True)
            self.bar.symbols_combo.setVisible(True)
            self.bar.lbl_position.setVisible(True)

            editor = self.current_editor()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(neditable.file_path)
            self._load_symbols(neditable)
            # self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()
        else:
            self.bar.combo_files.setCurrentIndex(index)
            viewer_widget = self.stacked.widget(index)
            self._main_container.current_editor_changed(
                viewer_widget.image_filename)
            self.bar.image_viewer_controls.setVisible(True)
            self.bar.code_navigator.setVisible(False)
            self.bar.symbols_combo.setVisible(False)
            self.bar.lbl_position.setVisible(False)

    def widget(self, index):
        return self.stacked.widget(index)

    def count(self):
        """Return the number of editors opened."""
        return self.stacked.count()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index)
                    or self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value, sender=None):
        if sender is None:
            sender = self.sender()
        neditable = sender.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        line = self._symbols_index[index]
        editor = self.current_editor()
        editor.go_to_line(line, center=True)
        editor.setFocus()

    def _update_symbols(self, neditable):
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if editor.neditable == neditable:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        # Get symbols handler by language
        symbols_handler = handlers.get_symbols_handler(neditable.language())
        if symbols_handler is None:
            return
        source = neditable.editor.text
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(list(symbols_simplified.items()),
                                    key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.cursor_position
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        if tree_symbols is not None:
            tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                # FIXME: sucks
                else:
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        self.about_to_close_combo_editor.emit()
        # self.emit(SIGNAL("aboutToCloseComboEditor()"))
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
示例#5
0
class _MainContainer(QWidget):

    currentEditorChanged = pyqtSignal(str)
    fileOpened = pyqtSignal(str)
    beforeFileSaved = pyqtSignal(str)
    fileSaved = pyqtSignal(str)
    runFile = pyqtSignal(str)
    showFileInExplorer = pyqtSignal(str)
    addToProject = pyqtSignal(str)
    allFilesClosed = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
        self._vbox = QVBoxLayout(self)
        self._vbox.setContentsMargins(0, 0, 0, 0)
        self._vbox.setSpacing(0)
        self.stack = QStackedLayout()
        self.stack.setStackingMode(QStackedLayout.StackAll)
        self._vbox.addLayout(self.stack)
        self.splitter = dynamic_splitter.DynamicSplitter()
        self._files_handler = files_handler.FilesHandler(self)

        # Code Navigation
        self.__code_back = []
        self.__code_forward = []
        self.__operations = {
            0: self._navigate_code_jumps,
            1: self._navigate_bookmarks
        }
        # Recent files list
        self.__last_opened_files = []
        # QML UI
        self._add_file_folder = add_file_folder.AddFileFolderWidget(self)

        if settings.SHOW_START_PAGE:
            self.show_start_page()

        IDE.register_service("main_container", self)
        # Register signals connections
        connections = (
            #     "slot": self._explore_code
            {
                "target": "filesystem",
                "signal_name": "projectOpened",
                "slot": self._explore_code
            },
            #     "slot": self._explore_code
            {
                "target": "filesystem",
                "signal_name": "projectClosed",
                "slot": self._explore_code
            })

        IDE.register_signals("main_container", connections)

        fhandler_short = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Tab), self)
        fhandler_short.activated.connect(self.show_files_handler)
        # Added for set language

    def install(self):
        ninjaide = IDE.get_service("ide")
        ninjaide.place_me_on("main_container", self, "central", top=True)

        self.combo_area = combo_editor.ComboEditor(original=True)
        self.combo_area.allFilesClosed.connect(self._files_closed)
        self.combo_area.allFilesClosed.connect(
            lambda: self.allFilesClosed.emit())
        self.combo_area.fileClosed.connect(self._add_to_last_opened)
        self.splitter.add_widget(self.combo_area)
        self.add_widget(self.splitter)
        # Code Locator
        self._code_locator = locator_widget.LocatorWidget(ninjaide)

        data_settings = IDE.data_settings()
        recent_files = data_settings.value("lastSession/recentFiles")
        if recent_files is not None:
            self.__last_opened_files = recent_files
        ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide)

    def run_file(self, filepath):
        self.runFile.emit(filepath)

    def _show_file_in_explorer(self, filepath):
        self.showFileInExplorer.emit(filepath)

    def _add_to_project(self, filepath):
        self.addToProject.emit(filepath)

    def show_files_handler(self):
        self._files_handler.next_item()

    def hide_files_handler(self):
        self._files_handler.hide()

    def import_from_everywhere(self):
        """Insert an import line from any place in the editor."""

        editorWidget = self.get_current_editor()
        if editorWidget:
            dialog = from_import_dialog.FromImportDialog(editorWidget, self)
            dialog.show()

    def navigate_code_history(self, operation, forward):
        self.__operations[operation](forward)

    def _navigate_code_jumps(self, forward=False):
        """Navigate between the jump points"""
        node = None
        if not forward and self.__code_back:
            if len(self.__code_back) == 1:
                return
            node = self.__code_back.pop()
            self.__code_forward.append(node)
            node = self.__code_back[-1]
        elif forward and self.__code_forward:
            node = self.__code_forward.pop()
            self.__code_back.append(node)
        if node is not None:
            filename = node[0]
            line, col = node[1]
            self.open_file(filename, line, col)

    def _navigate_bookmarks(self, forward=True):
        """Navigate between the bookmarks"""

        current_editor = self.get_current_editor()
        current_editor.navigate_bookmarks(forward=forward)

    def _set_focus_to_editor(self):
        status_bar = IDE.get_service("status_bar")
        tools_doock = IDE.get_service("tools_dock")
        editor_widget = self.get_current_editor()
        if status_bar.isVisible() and tools_doock.isVisible():
            status_bar.hide_status_bar()
        elif tools_doock.isVisible():
            tools_doock._hide()
        elif status_bar.isVisible():
            status_bar.hide_status_bar()
        if editor_widget is not None:
            editor_widget.extra_selections.remove("find")
            editor_widget.scrollbar().remove_marker("find")

    def split_assistance(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            split_widget = split_orientation.SplitOrientation(self)
            split_widget.show()

    def show_dialog(self, widget):
        self.add_widget(widget)
        self.stack.setCurrentWidget(widget)

    def show_split(self, orientation_vertical=False):
        orientation = Qt.Horizontal
        if orientation_vertical:
            orientation = Qt.Vertical
        self.combo_area.split_editor(orientation)

    def show_locator(self):
        """Show the Locator Widget"""

        if not self._code_locator.isVisible():
            self._code_locator.show()

    def _explore_code(self):
        """Update locator metadata for the current projects"""

        self._code_locator.explore_code()

    def _explore_file_code(self, path):
        """Update locator metadata for the file in path"""

        self._code_locator.explore_file_code(path)

    def current_editor_changed(self, filename):
        """Notify the new filename of the current editor"""

        if filename is None:
            filename = translations.TR_NEW_DOCUMENT
        self.currentEditorChanged.emit(filename)

    def get_current_editor(self):
        current_widget = self.combo_area.current_editor()
        if isinstance(current_widget, editor.NEditor):
            return current_widget
        return None

    @property
    def last_opened_files(self):
        return self.__last_opened_files

    def _add_to_last_opened(self, nfile):
        MAX_RECENT_FILES = 10  # FIXME: configuration
        if nfile.is_new_file:
            return
        file_path = nfile.file_path
        if file_path in self.__last_opened_files:
            self.__last_opened_files.remove(file_path)
        self.__last_opened_files.insert(0, file_path)
        if len(self.__last_opened_files) > MAX_RECENT_FILES:
            self.__last_opened_files.pop(-1)

    def clear_last_opened_files(self):
        self.__last_opened_files.clear()

    def open_file(self, filename='', line=-1, col=0, ignore_checkers=False):
        if not filename:
            logger.debug("Has no filename")
            if settings.WORKSPACE:
                directory = settings.WORKSPACE
            else:
                directory = os.path.expanduser("~")
                editor_widget = self.get_current_editor()
                ninjaide = IDE.get_service("ide")
                current_project = ninjaide.get_current_project()
                # TODO: handle current project in NProject
                if current_project is not None:
                    directory = current_project.full_path
                elif editor_widget is not None and editor_widget.file_path:
                    directory = file_manager.get_folder(
                        editor_widget.file_path)
            filenames = QFileDialog.getOpenFileNames(
                self,
                translations.TR_OPEN_A_FILE,
                directory,
                settings.get_supported_extensions_filter(),
                initialFilter="Python files (*.py *.pyw)")[0]
        else:
            logger.debug("Has filename")
            filenames = [filename]
        if not filenames:
            return
        for filename in filenames:
            image_extensions = ("png", "jpg", "jpeg", "bmp", "gif")
            if file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("Will open as image")
                self.open_image(filename)
            else:
                logger.debug("Will try to open: %s" % filename)
                self.__open_file(filename,
                                 line,
                                 col,
                                 ignore_checkers=ignore_checkers)

    def __open_file(self, filename, line, col, ignore_checkers=False):
        try:
            self.add_editor(filename)
            if line != -1:
                self.editor_go_to_line(line, col)
            self.currentEditorChanged.emit(filename)
        except file_manager.NinjaIOException as reason:
            QMessageBox.information(self, translations.TR_OPEN_FILE_ERROR,
                                    str(reason))
            logger.error("The file %s couldn't be open" % filename)

    def open_image(self, filename):
        for index in range(self.combo_area.stacked.count()):
            widget = self.combo_area.stacked.widget(index)
            if isinstance(widget, image_viewer.ImageViewer):
                if widget.image_filename == filename:
                    logger.debug("Image already open")
                    self.combo_area._set_current(neditable=None, index=index)
                    return
        viewer = image_viewer.ImageViewer(filename)
        self.combo_area.add_image_viewer(viewer)
        self.stack.setCurrentWidget(self.splitter)

    def autosave_file(self):
        for neditable in self.combo_area.bar.get_editables():
            neditable.autosave_file()

    def save_file(self, editor_widget=None):
        if editor_widget is None:
            # This may return None if there is not editor present
            editor_widget = self.get_current_editor()
        if editor_widget is None:
            return False
        # Ok, we have an editor instance
        # Save to file only if editor really was modified
        if editor_widget.is_modified:
            try:
                if editor_widget.nfile.is_new_file or \
                        not editor_widget.nfile.has_write_permission():
                    return self.save_file_as(editor_widget)

                file_path = editor_widget.file_path
                # Emit signal before save
                self.beforeFileSaved.emit(file_path)
                if settings.REMOVE_TRAILING_SPACES:
                    editor_widget.remove_trailing_spaces()
                if settings.ADD_NEW_LINE_AT_EOF:
                    editor_widget.insert_block_at_end()
                # Save content
                editor_widget.neditable.save_content()
                # FIXME: encoding
                message = translations.TR_FILE_SAVED.format(file_path)
                self.fileSaved.emit(message)
                return True
            except Exception as reason:
                logger.error("Save file error: %s" % reason)
                QMessageBox.information(self,
                                        translations.TR_SAVE_FILE_ERROR_TITLE,
                                        translations.TR_SAVE_FILE_ERROR_BODY)
            return False

    def save_file_as(self, editor_widget=None):
        force = False
        if editor_widget is None:
            # We invoque from menu
            editor_widget = self.get_current_editor()
            if editor_widget is None:
                # We haven't editor in main container
                return False
            force = True
        try:
            filters = "(*.py);;(*.*)"
            if editor_widget.file_path is not None:  # Existing file
                extension = file_manager.get_file_extension(
                    editor_widget.file_path)
                if extension != 'py':
                    filters = "(*.%s);;(*.py);;(*.*)" % extension
                save_folder = self._get_save_folder(editor_widget.file_path)
            else:
                save_folder = settings.WORKSPACE

            filename = QFileDialog.getSaveFileName(
                self, translations.TR_SAVE_FILE_DIALOG, save_folder,
                filters)[0]
            if not filename:
                return False
            # FIXME: remove trailing spaces
            extension = file_manager.get_file_extension(filename)
            if not extension:
                filename = "%s.%s" % (filename, "py")
            editor_widget.neditable.save_content(path=filename, force=force)
            self.fileSaved.emit(translations.TR_FILE_SAVED.format(filename))
            self.currentEditorChanged.emit(filename)
            return True
        except file_manager.NinjaFileExistsException as reason:
            QMessageBox.information(
                self, translations.TR_FILE_ALREADY_EXISTS_TITLE,
                translations.TR_FILE_ALREADY_EXISTS_BODY.format(
                    reason.filename))
        except Exception as reason:
            logger.error("Save file as: %s", reason)
            QMessageBox.information(self,
                                    translations.TR_SAVE_FILE_ERROR_TITLE,
                                    translations.TR_SAVE_FILE_ERROR_BODY)
        return False

    def save_project(self, project_path):
        """Save all files in the project path"""
        for neditable in self.combo_area.bar.get_editables():
            file_path = neditable.file_path
            if file_path is None:
                # FIXME: New edited files will not be saved, its ok?
                continue
            if file_manager.belongs_to_folder(project_path, file_path):
                neditable.save_content()

    def _get_save_folder(self, filename):
        """Returns the root directory of the 'Main Project'
        or the home folder"""

        ninjaide = IDE.get_service("ide")
        current_project = ninjaide.get_current_project()
        if current_project is not None:
            return current_project.path
        return os.path.expanduser("~")

    def close_file(self):
        self.combo_area.close_current_file()

    def add_editor(self, filename=None):
        ninjaide = IDE.get_service("ide")
        editable = ninjaide.get_or_create_editable(filename)

        if editable.editor:
            # If already open
            logger.debug("%s is already open" % filename)
            self.combo_area.set_current(editable)
            return self.combo_area.current_editor()
        else:
            pass

        editor_widget = self.create_editor_from_editable(editable)
        # Add the tab
        keep_index = (self.splitter.count() > 1
                      and self.combo_area.stacked.count() > 0)
        self.combo_area.add_editor(editable, keep_index)
        # Emit a signal about the file open
        self.fileOpened.emit(filename)

        if keep_index:
            self.combo_area.set_current(editable)

        self.stack.setCurrentWidget(self.splitter)
        editor_widget.setFocus()
        return editor_widget

    def create_editor_from_editable(self, editable):
        neditor = editor.create_editor(editable)
        neditor.zoomChanged.connect(self._on_zoom_changed)
        neditor.addBackItemNavigation.connect(self.add_back_item_navigation)
        editable.fileSaved.connect(
            lambda neditable: self._explore_file_code(neditable.file_path))
        return neditor

    def add_back_item_navigation(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            item = (editor_widget.file_path, editor_widget.cursor_position)
            if item not in self.__code_back:
                self.__code_back.append(item)

    def _on_zoom_changed(self, zoom):
        text = "Zoom: {}%".format(str(zoom))
        ide = IDE.get_service("ide")
        ide.show_message(text)

    def add_widget(self, widget):
        self.stack.addWidget(widget)

    def show_start_page(self):
        """Show Start Page widget in main container"""

        startp = self.stack.widget(0)
        if isinstance(startp, start_page.StartPage):
            self.stack.setCurrentIndex(0)
        else:
            startp = start_page.StartPage(parent=self)
            startp.newFile.connect(self.add_editor)
            self.stack.insertWidget(0, startp)
            self.stack.setCurrentIndex(0)

    def _files_closed(self):
        if settings.SHOW_START_PAGE:
            self.show_start_page()

    def add_status_bar(self, status_bar):
        self._vbox.addWidget(status_bar)

    def create_file(self, base_path, project_path):
        self._add_file_folder.create_file(base_path, project_path)

    def create_folder(self, base_path, project_path):
        self._add_file_folder.create_folder(base_path, project_path)

    def restyle_editor(self):
        neditables = self.combo_area.bar.get_editables()
        for neditable in neditables:
            neditable.editor.restyle()

    def zoom_in_editor(self):
        """Increase the font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.zoom(1.)

    def zoom_out_editor(self):
        """Decrease the font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.zoom(-1.)

    def reset_zoom_editor(self):
        """Reset the to original font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.reset_zoom()

    def editor_move_up(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.move_up_down(up=True)

    def editor_move_down(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.move_up_down()

    def editor_duplicate_line(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.duplicate_line()

    def editor_toggle_comment(self):
        """Mark the current line or selection as a comment."""
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.comment_or_uncomment()

    def editor_go_to_line(self, line, column=0, center=True):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.go_to_line(line, column, center)
            editor_widget.setFocus()

    def _editor_settings_changed(self, key, value):
        key = key.split("/")[-1]
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            callback = getattr(editor.NEditor, key, False)
            if callback:
                callback = callback
                if not hasattr(callback, "__call__"):
                    # Property!
                    callback = callback.fset
                callback(editor_widget, value)

    def toggle_tabs_and_spaces(self):
        """Toggle Show/Hide Tabs and Spaces"""

        settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES
        qsettings = IDE.ninja_settings()
        qsettings.setValue('preferences/editor/showTabsAndSpaces',
                           settings.SHOW_TABS_AND_SPACES)
        neditor = self.get_current_editor()
        if neditor is not None:
            neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES

    def __navigate_with_keyboard(self, forward):
        """Navigate between the positions in the jump history stack."""
        operation = self.combo_area.bar.code_navigator.operation
        self.navigate_code_history(operation, forward)

    def navigate_back(self):
        self.__navigate_with_keyboard(forward=False)

    def navigate_forward(self):
        self.__navigate_with_keyboard(forward=True)
class _MainContainer(QWidget):

###############################################################################
# MainContainer SIGNALS
###############################################################################
    """
    newFileOpened(QString)
    allTabClosed()
    runFile(QString)
    addToProject(QString)
    showFileInExplorer(QString)
    recentTabsModified()
    currentEditorChanged(QString)
    fileOpened(QString)
    ---------migrationAnalyzed()
    findOcurrences(QString)
    ---------updateFileMetadata()
    editorKeyPressEvent(QEvent)
    locateFunction(QString, QString, bool) [functionName, filePath, isVariable]
    updateLocator(QString)
    beforeFileSaved(QString)
    fileSaved(QString)
    openPreferences()
    --------openProject(QString)
    ---------dontOpenStartPage()
    """
    newFileOpened = pyqtSignal(str)
    allTabClosed = pyqtSignal()
    runFile = pyqtSignal(str)
    addToProject = pyqtSignal(str)
    showFileInExplorer = pyqtSignal(str)
    recentTabsModified = pyqtSignal()
    currentEditorChanged = pyqtSignal(str)
    fileOpened = pyqtSignal(str)
    migrationAnalyzed = pyqtSignal()#-----------
    findOcurrences = pyqtSignal(str)
    updateFileMetadata = pyqtSignal()#-----------
    editorKeyPressEvent = pyqtSignal('QEvent*')
    locateFunction = pyqtSignal(str, str, bool)
    updateLocator = pyqtSignal(str)
    beforeFileSaved = pyqtSignal(str)
    fileSaved = pyqtSignal(str)
    openPreferences = pyqtSignal()
    openProject = pyqtSignal(str)#-----------
    dontOpenStartPage = pyqtSignal()#-----------
    closeDialog = pyqtSignal('QObject*')
    allTabsClosed = pyqtSignal()
    splitEditor = pyqtSignal('QWidget*', 'QWidget*', bool)
    closeSplit = pyqtSignal(QWidget)
    toRemovePreview = pyqtSignal()

###############################################################################

    def __init__(self, parent=None):
        super(_MainContainer, self).__init__(parent)
        self._parent = parent
        self._vbox = QVBoxLayout(self)
        self._vbox.setContentsMargins(0, 0, 0, 0)
        self._vbox.setSpacing(0)
        self.stack = QStackedLayout()
        self.stack.setStackingMode(QStackedLayout.StackAll)
        self._vbox.addLayout(self.stack)

        self.splitter = dynamic_splitter.DynamicSplitter()
        self.setAcceptDrops(True)
        # self._files_handler = files_handler.FilesHandler(self)
        self._add_file_folder = add_file_folder.AddFileFolderWidget(self)

        self.tdir = None

        #documentation browser
        self.docPage = None
        #Code Navigation
        self._locator = locator.GoToDefinition()
        self.__codeBack = []
        self.__codeForward = []
        self.__bookmarksFile = ''
        self.__bookmarksPos = -1
        self.__breakpointsFile = ''
        self.__breakpointsPos = -1
        self.__operations = {
            0: self._navigate_code_jumps,
            1: self._navigate_bookmarks,
            2: self._navigate_breakpoints}

        self.locateFunction.connect(self.locate_function)

        IDE.register_service('main_container', self)

        #Register signals connections
        connections = (
            {'target': 'menu_file',
             'signal_name': 'openFile',#(QString)
             'slot': self.open_file},
            {'target': 'explorer_container',
             'signal_name': 'goToDefinition',#(int)
             'slot': self.editor_go_to_line},
            {'target': 'explorer_container',
             'signal_name': 'pep8Activated',#(bool)
             'slot': self.reset_pep8_warnings},
            {'target': 'explorer_container',
             'signal_name': 'lintActivated',#(bool)
             'slot': self.reset_lint_warnings},
            )

        IDE.register_signals('main_container', connections)

        self.selector = main_selector.MainSelector(self)
        self._opening_dialog = False
        self.add_widget(self.selector)

        if settings.SHOW_START_PAGE:
            self.show_start_page()

        self.selector.changeCurrent[int].connect(self._change_current_stack)
        self.selector.removeWidget[int].connect(self._remove_item_from_stack)
        self.selector.ready.connect(self._selector_ready)
        self.selector.closePreviewer.connect(self._selector_Close)
        self.selector.animationCompleted.connect(self._selector_animation_completed)

        self.closeDialog.connect(self.remove_widget)
        self.stack.widgetRemoved[int].connect(lambda i:print("widgetRemoved._-", i))

    def install(self):
        ide = IDE.getInstance()
        ide.place_me_on("main_container", self, "central", top=True)

        self.combo_area = combo_editor.ComboEditor(original=True)
        self.combo_area.allFilesClosed.connect(self._files_closed)
        self.splitter.add_widget(self.combo_area)
        self.add_widget(self.splitter)

        self.current_widget = self.combo_area

        ui_tools.install_shortcuts(self, actions.ACTIONS, ide)

    def add_status_bar(self, status):
        self._vbox.addWidget(status)

    @property
    def combo_header_size(self):
        return self.combo_area.bar.height()

    def add_widget(self, widget):
        i = self.stack.addWidget(widget)
        #if not isinstance(widget, start_page.StartPage):
        self.tryMakeImagePreview(i)

    def remove_widget(self, widget):
        #self.toRemovePreview.emit(self.stack.widget(widget))
        self.stack.removeWidget(widget)

    def _close_dialog(self, widget):
        self.closeDialog.emit(widget)
        widget.finished[int].disconnect()#lambda i: self._close_dialog(widget))

    def show_dialog(self, widget):
        print("\n\nshow_dialog", self.isVisible())
        self._opening_dialog = True
        widget.finished[int].connect(lambda i: self._close_dialog(widget))
        widget.setVisible(True)
        self.show_selector()

    def show_selector(self):
        print("\n\nshow_selector::", self.selector, self.stack.currentWidget())
        if self.selector != self.stack.currentWidget():
            _dir = self.Successful_Tmp()
            if not _dir:
                print("failed!")
                return

            # temp_dir = os.path.join(QDir.tempPath(), "ninja-ide")
            # if not os.path.exists(temp_dir):
            #     os.mkdir(temp_dir)
            collected_data = []
            current = self.stack.currentIndex()
            for index in range(self.stack.count()):
                widget = self.stack.widget(index)
                if widget == self.selector:
                    continue
                closable = True
                if widget == self.splitter:
                    closable = False
                # path = os.path.join(temp_dir, "screen%s.png" % index)
                #ff = QFile(_dir, "screen%s.png" % index)
                path = _dir.absolutePath()+"/screen%s.png" % index
                pixmap = widget.grab()#widget.rect())
                pixmap.save(path)
                #path = path.replace("\\", '/')
                #print("path::", path, QFileInfo(path).exists())
                path = "file:///"+path
                if index == current:
                    self.selector.set_preview(index, path)#QUrl(path)
                    collected_data.insert(0, (index, path, closable))
                else:
                    collected_data.append((index, path, closable))
            self.selector.set_model(collected_data)
            print("self.selector.set_model()", collected_data)
            self.stack.setCurrentWidget(self.selector)
        else:
            print("\n\n_selector_Close()")
            self._selector_Close()

    def Successful_Tmp(self):# CheckTmpDir, StateTmpDir
        failed = lambda: not self.tdir or not self.tdir.isValid()
        if failed():# not successfully
            self.tdir = QTemporaryDir()
            if failed():
                QMessageBox.critical(self, "Unexpected Failurer", "The application has detected a problem trying to\nCreate or Access a Temporary File!.")
                return None
            else:
                self.tdir.setAutoRemove(True)

        d = QDir(self.tdir.path())
        if not d.exists("ninja-ide"):
            if not d.mkdir("ninja-ide"):
                self.tdir = None
        d.cd("ninja-ide")
        return d

    def tryMakeImagePreview(self, index):
        return
        d = self.Successful_Tmp()
        if d:
            self.makeImagePreview(d, index)

    def makeImagePreview(self, _dir, index):
        return
        path = _dir.absolutePath()+"/screen%s.png" % index
        widget = self.stack.widget(index)
        pixmap = widget.grab()#widget.rect()
        pixmap.save(path)

    def _selector_ready(self):
        self.stack.setCurrentWidget(self.selector)
        self.selector.GoTo_GridPreviews()

    def _selector_Close(self):
        self.stack.setCurrentWidget(self.splitter)

    def _selector_animation_completed(self):
        if self._opening_dialog:
            # We choose the last one with -2, -1 (for last one) +
            # -1 for the hidden selector widget which is in the stacked too.
            self.selector.open_item(self.stack.count() - 2)
        self._opening_dialog = False

    def _change_current_stack(self, index):
        self.stack.setCurrentIndex(index)

    def _remove_item_from_stack(self, index):
        #self.toRemovePreview.emit(index)
        widget = self.stack.takeAt(index)
        del widget

    def show_editor_area(self):
        self.stack.setCurrentWidget(self.splitter)

    def _files_closed(self):
        if settings.SHOW_START_PAGE:
            self.show_start_page()

    def change_visibility(self):
        """Show/Hide the Main Container area."""
        print("change_visibility11")
        if self.isVisible():
            self.hide()
        else:
            self.show()

    def expand_symbol_combo(self):
        self.stack.setCurrentWidget(self.splitter)
        self.current_widget.show_combo_symbol()

    def expand_file_combo(self):
        print("expand_file_combo")
        self.stack.setCurrentWidget(self.splitter)
        self.current_widget.show_combo_file()

    def locate_function(self, function, filePath, isVariable):
        """Move the cursor to the proper position in the navigate stack."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            self.__codeBack.append((editorWidget.file_path,
                                   editorWidget.getCursorPosition()))
            self.__codeForward = []
        self._locator.navigate_to(function, filePath, isVariable)

    def run_file(self, path):
        self.runFile.emit(path)

    def _add_to_project(self, path):
        self.addToProject.emit(path)

    def _show_file_in_explorer(self, path):
        self.showFileInExplorer.emit(path)

    def paste_history(self):
        """Paste the text from the copy/paste history."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            line, index = editorWidget.getCursorPosition()
            central = IDE.get_service('central_container')
            if central:
                editorWidget.insertAt(central.get_paste(), line, index)

    def copy_history(self):
        """Copy the selected text into the copy/paste history."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            copy = editorWidget.selectedText()
            central = IDE.get_service('central_container')
            if central:
                central.add_copy(copy)

    def import_from_everywhere(self):
        """Insert an import line from any place in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            dialog = from_import_dialog.FromImportDialog(editorWidget, self)
            dialog.show()

    def add_back_item_navigation(self):
        """Add an item to the back stack and reset the forward stack."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            self.__codeBack.append((editorWidget.file_path,
                                   editorWidget.getCursorPosition()))
            self.__codeForward = []

    def preview_in_browser(self):
        """Load the current html file in the default browser."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            if not editorWidget.file_path:
                self.save_file()
            ext = file_manager.get_file_extension(editorWidget.file_path)
            if ext in ('html', 'shpaml', 'handlebars', 'tpl'):
                webbrowser.open_new_tab(editorWidget.file_path)

    def add_bookmark_breakpoint(self):
        """Add a bookmark or breakpoint to the current file in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            if self.current_widget.bar.code_navigator.operation == 1:
                editorWidget.handle_bookmarks_breakpoints(
                    editorWidget.getCursorPosition()[0], Qt.ControlModifier)
            elif self.current_widget.bar.code_navigator.operation == 2:
                editorWidget.handle_bookmarks_breakpoints(
                    editorWidget.getCursorPosition()[0], Qt.NoModifier)

    def __navigate_with_keyboard(self, val):
        """Navigate between the positions in the jump history stack."""
        op = self.current_widget.bar.code_navigator.operation
        self.navigate_code_history(val, op)

    def navigate_code_history(self, val, op):
        """Navigate the code history."""
        self.__operations[op](val)

    def _navigate_code_jumps(self, val):
        """Navigate between the jump points."""
        node = None
        if not val and self.__codeBack:
            node = self.__codeBack.pop()
            editorWidget = self.get_current_editor()
            if editorWidget:
                self.__codeForward.append((editorWidget.file_path,
                                          editorWidget.getCursorPosition()))
        elif val and self.__codeForward:
            node = self.__codeForward.pop()
            editorWidget = self.get_current_editor()
            if editorWidget:
                self.__codeBack.append((editorWidget.file_path,
                                       editorWidget.getCursorPosition()))
        if node:
            filename = node[0]
            line, col = node[1]
            self.open_file(filename, line, col)

    def _navigate_breakpoints(self, val):
        """Navigate between the breakpoints."""
        #FIXME: put navigate breakpoints and bookmarks as one method.
        breakList = list(settings.BREAKPOINTS.keys())
        breakList.sort()
        if not breakList:
            return
        if self.__breakpointsFile not in breakList:
            self.__breakpointsFile = breakList[0]
        index = breakList.index(self.__breakpointsFile)
        breaks = settings.BREAKPOINTS.get(self.__breakpointsFile, [])
        lineNumber = 0
        #val == True: forward
        if val:
            if (len(breaks) - 1) > self.__breakpointsPos:
                self.__breakpointsPos += 1
                lineNumber = breaks[self.__breakpointsPos]
            elif len(breaks) > 0:
                if index < (len(breakList) - 1):
                    self.__breakpointsFile = breakList[index + 1]
                else:
                    self.__breakpointsFile = breakList[0]
                self.__breakpointsPos = 0
                lineNumber = settings.BREAKPOINTS[self.__breakpointsFile][0]
        else:
            if self.__breakpointsPos > 0:
                self.__breakpointsPos -= 1
                lineNumber = breaks[self.__breakpointsPos]
            elif len(breaks) > 0:
                self.__breakpointsFile = breakList[index - 1]
                breaks = settings.BREAKPOINTS[self.__breakpointsFile]
                self.__breakpointsPos = len(breaks) - 1
                lineNumber = breaks[self.__breakpointsPos]
        if file_manager.file_exists(self.__breakpointsFile):
            self.open_file(self.__breakpointsFile, lineNumber, None, True)
        else:
            settings.BREAKPOINTS.pop(self.__breakpointsFile)
            if settings.BREAKPOINTS:
                self._navigate_breakpoints(val)

    def _navigate_bookmarks(self, val):
        """Navigate between the bookmarks."""
        bookList = list(settings.BOOKMARKS.keys())
        bookList.sort()
        if not bookList:
            return
        if self.__bookmarksFile not in bookList:
            self.__bookmarksFile = bookList[0]
        index = bookList.index(self.__bookmarksFile)
        bookms = settings.BOOKMARKS.get(self.__bookmarksFile, [])
        lineNumber = 0
        #val == True: forward
        if val:
            if (len(bookms) - 1) > self.__bookmarksPos:
                self.__bookmarksPos += 1
                lineNumber = bookms[self.__bookmarksPos]
            elif len(bookms) > 0:
                if index < (len(bookList) - 1):
                    self.__bookmarksFile = bookList[index + 1]
                else:
                    self.__bookmarksFile = bookList[0]
                self.__bookmarksPos = 0
                lineNumber = settings.BOOKMARKS[self.__bookmarksFile][0]
        else:
            if self.__bookmarksPos > 0:
                self.__bookmarksPos -= 1
                lineNumber = bookms[self.__bookmarksPos]
            elif len(bookms) > 0:
                self.__bookmarksFile = bookList[index - 1]
                bookms = settings.BOOKMARKS[self.__bookmarksFile]
                self.__bookmarksPos = len(bookms) - 1
                lineNumber = bookms[self.__bookmarksPos]
        if file_manager.file_exists(self.__bookmarksFile):
            self.open_file(self.__bookmarksFile,
                           lineNumber, None, True)
        else:
            settings.BOOKMARKS.pop(self.__bookmarksFile)
            if settings.BOOKMARKS:
                self._navigate_bookmarks(val)

    def count_file_code_lines(self):
        """Count the lines of code in the current file."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            block_count = editorWidget.lines()
            blanks = re.findall('(^\n)|(^(\s+)?#)|(^( +)?($|\n))',
                                editorWidget.text(), re.M)
            blanks_count = len(blanks)
            resume = self.tr("Lines code: %s\n") % (block_count - blanks_count)
            resume += (self.tr("Blanks and commented lines: %s\n\n") %
                       blanks_count)
            resume += self.tr("Total lines: %s") % block_count
            msgBox = QMessageBox(QMessageBox.Information,
                                 self.tr("Summary of lines"), resume,
                                 QMessageBox.Ok, editorWidget)
            msgBox.exec_()

    def editor_cut(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.cut()

    def editor_copy(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.copy()

    def editor_paste(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.paste()

    def editor_upper(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_upper()

    def editor_lower(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_lower()

    def editor_title(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_title()

    def editor_go_to_definition(self):
        """Search the definition of the method or variable under the cursor.

        If more than one method or variable is found with the same name,
        shows a table with the results and let the user decide where to go."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.go_to_definition()

    def editor_redo(self):
        """Execute the redo action in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.redo()

    def editor_undo(self):
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.undo()

    def editor_indent_less(self):
        """Indent 1 position to the left for the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.indent_less()

    def editor_indent_more(self):
        """Indent 1 position to the right for the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.indent_more()

    def editor_insert_debugging_prints(self):
        """Insert a print statement in each selected line."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.insert_debugging_prints(editorWidget)

    def editor_insert_pdb(self):
        """Insert a pdb.set_trace() statement in tjhe current line."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.insert_pdb(editorWidget)

    def editor_comment(self):
        """Mark the current line or selection as a comment."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.comment(editorWidget)

    def editor_uncomment(self):
        """Uncomment the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.uncomment(editorWidget)

    def editor_insert_horizontal_line(self):
        """Insert an horizontal lines of comment symbols."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.insert_horizontal_line(editorWidget)

    def editor_insert_title_comment(self):
        """Insert a Title surrounded by comment symbols."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.insert_title_comment(editorWidget)

    def editor_remove_trailing_spaces(self):
        """Remove the trailing spaces in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.remove_trailing_spaces(editorWidget)

    def editor_replace_tabs_with_spaces(self):
        """Replace the Tabs with Spaces in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.replace_tabs_with_spaces(editorWidget)

    def editor_move_up(self):
        """Move the current line or selection one position up."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.move_up(editorWidget)

    def editor_move_down(self):
        """Move the current line or selection one position down."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.move_down(editorWidget)

    def editor_remove_line(self):
        """Remove the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.remove_line(editorWidget)

    def editor_duplicate(self):
        """Duplicate the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.duplicate(editorWidget)

    def editor_highlight_word(self):
        """Highlight the occurrences of the current word in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.highlight_selected_word()

    def editor_complete_declaration(self):
        """Do the opposite action that Complete Declaration expect."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.complete_declaration()

    def editor_go_to_line(self, line, select=False):#def editor_go_to_line(self, line):
        """Jump to the specified line in the current editor."""
        editorWidget = self.get_current_editor()
        print("\nluego en segundo lugar por aca")
        if editorWidget:
            editorWidget.jump_to_line(line)#select

    def editor_go_to_symbol_line(self, line, sym= "", select=False):
        """Jump to the specified line in the current editor."""
        editorWidget = self.get_current_editor()
        print("\nluego en segundo lugar por aca")
        if editorWidget:
            editorWidget.go_to_symbol(line, sym, select)#select

    def zoom_in_editor(self):
        """Increase the font size in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.zoom_in()

    def zoom_out_editor(self):
        """Decrease the font size in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.zoom_out()

    def recent_files_changed(self):
        self.recentTabsModified.emit()

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        # file_path = event.mimeData().urls()[0].toLocalFile()
        # paths = [item.toLocalFile() for item in event.mimeData().urls()]
        self.open_files_fromUrlList(event.mimeData().urls())
        # print("\n\n dropEvent", paths)
        # self.open_file(file_path)

    def setFocus(self):
        widget = self.get_current_widget()
        if widget:
            widget.setFocus()

    def current_editor_changed(self, filename):
        """Notify the new filename of the current editor."""
        if filename is None:
            filename = translations.TR_NEW_DOCUMENT
        self.currentEditorChanged.emit(filename)

    def show_split(self, orientation_vertical=False):
        #IDE.select_current(self.current_widget.currentWidget())
        self.current_widget.split_editor(orientation_vertical)

    def add_editor(self, fileName=None, ignore_checkers=False):
        print("filename::", fileName)
        ninjaide = IDE.getInstance()
        editable = ninjaide.get_or_create_editable(fileName)
        if editable.editor:
            self.current_widget.set_current(editable)
            print("\n\nreturn")
            return self.current_widget.currentWidget()
        else:
            editable.ignore_checkers = ignore_checkers

        editorWidget = self.create_editor_from_editable(editable)

        #add the tab
        keep_index = (self.splitter.count() > 1 and
                      self.combo_area.stacked.count() > 0)
        self.combo_area.add_editor(editable, keep_index)

        #emit a signal about the file open
        self.fileOpened.emit(fileName)
        if keep_index:
            self.current_widget.set_current(editable)

        self.stack.setCurrentWidget(self.splitter)
        return editorWidget

    def create_editor_from_editable(self, editable):
        editorWidget = editor.create_editor(editable)

        #Connect signals
        editable.fileSaved.connect(self._editor_tab_was_saved)
        editorWidget.openDropFile.connect(self.open_file)
        editorWidget.addBackItemNavigation.connect(self.add_back_item_navigation)
        editorWidget.locateFunction.connect(self._editor_locate_function)
        editorWidget.findOcurrences.connect(self._find_occurrences)
        #keyPressEventSignal for plugins
        editorWidget.keyPressSignal.connect(self._editor_keyPressEvent)

        return editorWidget

    def reset_pep8_warnings(self, value):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
            #widget = self._tabMain.widget(i)
            #if type(widget) is editor.Editor:
                #if value:
                    #widget.syncDocErrorsSignal = True
                    #widget.pep8.check_style()
                #else:
                    #widget.hide_pep8_errors()

    def reset_lint_warnings(self, value):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
            #widget = self._tabMain.widget(i)
            #if type(widget) is editor.Editor:
                #if value:
                    #widget.syncDocErrorsSignal = True
                    #widget.errors.check_errors()
                #else:
                    #widget.hide_lint_errors()

    def _find_occurrences(self, word):
        self.findOcurrences.emit(word)

    def _editor_keyPressEvent(self, event):
        self.editorKeyPressEvent.emit(event)

    def _editor_locate_function(self, function, filePath, isVariable):
        self.locateFunction.emit(function, filePath, isVariable)

    def _editor_tab_was_saved(self, editable=None):
        self.updateLocator.emit(editable.file_path)

    def get_current_widget(self):
        return self.current_widget.currentWidget()

    def get_current_editor(self):
        """Return the Actual Editor or None

        Return an instance of Editor if the Current Tab contains
        an Editor or None if it is not an instance of Editor"""
        widget = self.current_widget.currentWidget()
        if isinstance(widget, editor.Editor):
            return widget
        return None

    def reload_file(self, editorWidget=None):
        if editorWidget is None:
            editorWidget = self.get_current_editor()
            if editorWidget is not None:
                editorWidget.neditable.reload_file()

    def add_tab(self, widget, tabName, tabIndex=None):
        pass
        #return self.tabs.add_tab(widget, tabName, index=tabIndex)

    def open_image(self, fileName):
        try:
            if not self.is_open(fileName):
                viewer = image_viewer.ImageViewer(fileName)
                self.add_tab(viewer, file_manager.get_basename(fileName))
                viewer.ID = fileName
            else:
                self.move_to_open(fileName)
        except Exception as reason:
            logger.error('open_image: %s', reason)
            QMessageBox.information(self, self.tr("Incorrect File"),
                                    self.tr("The image couldn\'t be open"))

    def open_files_fromList(self, lst):
        for f in lst:
            self.open_file(f)

    def open_files_fromUrlList(self, lst):
        for f in lst:
            self.open_file(f.toLocalFile())

    def open_file(self, filename='', line=-1, col=0, ignore_checkers=False):
        logger.debug("will try to open %s" % filename)
        if not filename:
            logger.debug("has nofilename")
            if settings.WORKSPACE:
                directory = settings.WORKSPACE
            else:
                directory = os.path.expanduser("~")
                editorWidget = self.get_current_editor()
                ninjaide = IDE.getInstance()
                if ninjaide:
                    current_project = ninjaide.get_current_project()
                    if current_project is not None:
                        directory = current_project
                    elif editorWidget is not None and editorWidget.file_path:
                        directory = file_manager.get_folder(
                            editorWidget.file_path)
            extensions = ';;'.join(
                ['{}(*{})'.format(e.upper()[1:], e)
                 for e in settings.SUPPORTED_EXTENSIONS + ['.*', '']])
            fileNames = QFileDialog.getOpenFileNames(self,
                             self.tr("Open File"), directory, extensions)[0]#list()
        else:
            logger.debug("has filename")
            fileNames = [filename]
        if not fileNames:
            return

        print("\n\nopen_file")
        othersFileNames = []
        image_extensions = ('bmp', 'gif', 'jpeg', 'jpg', 'png')
        for filename in fileNames:
            print("nombre", filename)
            if QFileInfo(filename).isDir():
                othersFileNames.extend( QFileDialog.getOpenFileNames(None,
                    "Select files", filename, "Files (*.*)")[0] )
            elif file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("will open as image")
                self.open_image(filename)
            elif file_manager.get_file_extension(filename).endswith('ui'):
                logger.debug("will load in ui editor")
                self.w = uic.loadUi(filename)
                self.w.show()
            else:
                logger.debug("will try to open: " + filename)
                self.__open_file(filename, line, col,
                                 ignore_checkers)

        for filename in othersFileNames:
            print("nombre", filename)
            if QFileInfo(filename).isDir():
                continue
            elif file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("will open as image")
                self.open_image(filename)
            elif file_manager.get_file_extension(filename).endswith('ui'):
                logger.debug("will load in ui editor")
                self.w = uic.loadUi(filename)
                self.w.show()
            else:
                logger.debug("will try to open: " + filename)
                self.__open_file(filename, line, col,
                                 ignore_checkers)



    def __open_file(self, fileName='', line=-1, col=0, ignore_checkers=False):
        print("unio", fileName)
        try:
            editorWidget = self.add_editor(fileName,
                                           ignore_checkers=ignore_checkers)
            if line != -1:
                editorWidget.set_cursor_position(line, col)
            self.currentEditorChanged.emit(fileName)
        except file_manager.NinjaIOException as reason:
            QMessageBox.information(self,
                                    self.tr("The file couldn't be open"),
                                    str(reason))

    def is_open(self, filename):
        pass
        #return self.tabs.is_open(filename) != -1

    def move_to_open(self, filename):
        pass
        #FIXME: add in the current split?
        #if self.tabs.is_open(filename) != -1:
            #self.tabs.move_to_open(filename)
        #self.tabs.currentWidget().setFocus()
        #self.emit(SIGNAL("currentEditorChanged(QString)"), filename)

    def get_widget_for_id(self, filename):
        pass
        #widget = None
        #index = self.tabs.is_open(filename)
        #if index != -1:
            #widget = self.tabs.widget(index)
        #return widget

    def change_open_tab_id(self, idname, newId):
        """Search for the Tab with idname, and set the newId to that Tab."""
        pass
        #index = self.tabs.is_open(idname)
        #if index != -1:
            #widget = self.tabs.widget(index)
            #tabName = file_manager.get_basename(newId)
            #self.tabs.change_open_tab_name(index, tabName)
            #widget.ID = newId

    def close_deleted_file(self, idname):
        """Search for the Tab with id, and ask the user if should be closed."""
        pass
        #index = self.tabs.is_open(idname)
        #if index != -1:
            #result = QMessageBox.question(self, self.tr("Close Deleted File"),
                #self.tr("Are you sure you want to close the deleted file?\n"
                        #"The content will be completely deleted."),
                #buttons=QMessageBox.Yes | QMessageBox.No)
            #if result == QMessageBox.Yes:
                #self.tabs.removeTab(index)

    def save_file(self, editorWidget=None):
        #FIXME: check how we handle this
        if not editorWidget:
            editorWidget = self.get_current_editor()
        if not editorWidget:
            return False
        try:
            #editorWidget.just_saved = True
            if (editorWidget.nfile.is_new_file or
                    not editorWidget.nfile.has_write_permission()):
                return self.save_file_as()

            self.beforeFileSaved.emit(editorWidget.file_path)
            if settings.REMOVE_TRAILING_SPACES:
                helpers.remove_trailing_spaces(editorWidget)
            editorWidget.neditable.save_content()
            #file_manager.store_file_content(
                #fileName, content, addExtension=False)
            encoding = file_manager.get_file_encoding(editorWidget.text())
            editorWidget.encoding = encoding
            self.fileSaved.emit((self.tr("File Saved: %s") % editorWidget.file_path))
            return True
        except Exception as reason:
            logger.error('save_file: %s', reason)
            QMessageBox.information(self, self.tr("Save Error"),
                                    self.tr("The file couldn't be saved!"))
        return False

    def save_file_as(self):
        editorWidget = self.get_current_editor()
        if not editorWidget:
            return False
        try:
            filters = '(*.py);;(*.*)'
            if editorWidget.file_path:
                ext = file_manager.get_file_extension(editorWidget.file_path)
                if ext != 'py':
                    filters = '(*.%s);;(*.py);;(*.*)' % ext
            save_folder = self._get_save_folder(editorWidget.file_path)
            fileName = QFileDialog.getSaveFileName(
                self._parent, self.tr("Save File"), save_folder, filters)
            if not fileName:
                return False

            if settings.REMOVE_TRAILING_SPACES:
                helpers.remove_trailing_spaces(editorWidget)

            editorWidget.neditable.save_content(path=fileName)
            editorWidget.register_syntax(
                file_manager.get_file_extension(fileName))

            self.fileSaved.emit((self.tr("File Saved: %s") % fileName))
            self.currentEditorChanged.emit(fileName)
            return True
        except file_manager.NinjaFileExistsException as ex:
            QMessageBox.information(self, self.tr("File Already Exists"),
                                    (self.tr("Invalid Path: the file '%s' "
                                             " already exists.") %
                                    ex.filename))
        except Exception as reason:
            logger.error('save_file_as: %s', reason)
            QMessageBox.information(self, self.tr("Save Error"),
                                    self.tr("The file couldn't be saved!"))
        return False

    def _get_save_folder(self, fileName):
        """
        Returns the root directory of the 'Main Project' or the home folder
        """
        ninjaide = IDE.getInstance()
        current_project = ninjaide.get_current_project()
        if current_project:
            return current_project.path
        return os.path.expanduser("~")

    def save_project(self, projectFolder):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
            #editorWidget = self._tabMain.widget(i)
            #if type(editorWidget) is editor.Editor and \
            #file_manager.belongs_to_folder(projectFolder,
                    #editorWidget.file_path):
                #reloaded = self._tabMain.check_for_external_modifications(
                    #editorWidget)
                #if not reloaded:
                    #self.save_file(editorWidget)
        #for i in range(self.tabsecondary.count()):
            #editorWidget = self.tabsecondary.widget(i)
            #if type(editorWidget) is editor.Editor and \
            #file_manager.belongs_to_folder(projectFolder,
                    #editorWidget.file_path):
                #reloaded = self.tabsecondary.check_for_external_modifications(
                    #editorWidget)
                #if not reloaded:
                    #self.save_file(editorWidget)

    def save_all(self):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
            #editorWidget = self._tabMain.widget(i)
            #if type(editorWidget) is editor.Editor:
                #reloaded = self._tabMain.check_for_external_modifications(
                    #editorWidget)
                #if not reloaded:
                    #self.save_file(editorWidget)
        #for i in range(self.tabsecondary.count()):
            #editorWidget = self.tabsecondary.widget(i)
            #self.tabsecondary.check_for_external_modifications(editorWidget)
            #if type(editorWidget) is editor.Editor:
                #reloaded = self.tabsecondary.check_for_external_modifications(
                    #editorWidget)
                #if not reloaded:
                    #self.save_file(editorWidget)

    def call_editors_function(self, call_function, *arguments):
        pass
        #args = arguments[0]
        #kwargs = arguments[1]
        #for i in range(self.tabs.count()):
            #editorWidget = self.tabs.widget(i)
            #if isinstance(editorWidget, editor.Editor):
                #function = getattr(editorWidget, call_function)
                #function(*args, **kwargs)
        #TODO: add other splits

    def show_start_page(self):
        start = self.stack.widget(0)
        if isinstance(start, start_page.StartPage):
            self.stack.setCurrentIndex(0)
        else:
            startPage = start_page.StartPage(parent=self)
            startPage.openProject.connect(self.open_project)
            startPage.openPreferences.connect(self.openPreferences.emit)
            startPage.newFile.connect(self.add_editor)
            startPage.openFiles.connect(self.open_files_fromList)
            self.stack.insertWidget(0, startPage)
            self.stack.setCurrentIndex(0)

            self.tryMakeImagePreview(0)
            #"screen0.png"

    def show_python_doc(self):
        if sys.platform == 'win32':
            self.docPage = browser_widget.BrowserWidget(
                'http://docs.python.org/')
        else:
            process = runner.start_pydoc()
            self.docPage = browser_widget.BrowserWidget(process[1], process[0])
        self.add_tab(self.docPage, translations.TR_PYTHON_DOC)

    def show_report_bugs(self):
        webbrowser.open(resources.BUGS_PAGE)

    def show_plugins_doc(self):
        bugsPage = browser_widget.BrowserWidget(resources.PLUGINS_DOC, self)
        self.add_tab(bugsPage, translations.TR_HOW_TO_WRITE_PLUGINS)

    def editor_jump_to_line(self, lineno=None):
        """Jump to line *lineno* if it is not None
        otherwise ask to the user the line number to jump
        """
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.jump_to_line(lineno=lineno)

    def get_opened_documents(self):
        #return self.tabs.get_documents_data()
        return []

    def check_for_unsaved_files(self):
        pass
        #return self.tabs._check_unsaved_tabs()

    def get_unsaved_files(self):
        pass
        #return self.tabs.get_unsaved_files()

    def reset_editor_flags(self):
        pass
        #for i in range(self.tabs.count()):
            #widget = self.tabs.widget(i)
            #if isinstance(widget, editor.Editor):
                #widget.set_flags()

    def _specify_syntax(self, widget, syntaxLang):
        if isinstance(widget, editor.Editor):
            widget.restyle(syntaxLang)

    def apply_editor_theme(self, family, size):
        pass
        #for i in range(self.tabs.count()):
            #widget = self.tabs.widget(i)
            #if isinstance(widget, editor.Editor):
                #widget.restyle()
                #widget.set_font(family, size)

    def update_editor_margin_line(self):
        pass
        #for i in range(self.tabs.count()):
            #widget = self.tabs.widget(i)
            #if isinstance(widget, editor.Editor):
                #widget._update_margin_line()

    def open_project(self, path):
        print("open_project")
        self.openProject.emit(path)

    def close_python_doc(self):
        pass
        #close the python document server (if running)
        #if self.docPage:
            #index = self.tabs.indexOf(self.docPage)
            #self.tabs.removeTab(index)
            ##assign None to the browser
            #self.docPage = None

    def close_file(self):
        """Close the current tab in the current TabWidget."""
        self.current_widget.close_current_file()

    def create_file(self, base_path, project_path):
        self._add_file_folder.create_file(base_path, project_path)

    def create_folder(self, base_path, project_path):
        self._add_file_folder.create_folder(base_path, project_path)

    def change_tab(self):
        """Change the tab in the current TabWidget."""
        print("\nchange_tab")
        self.stack.setCurrentWidget(self.splitter)
        # self._files_handler.next_item()
        pass

    def change_tab_reverse(self):
        """Change the tab in the current TabWidget backwards."""
        print("\nchange_tab_reverse")
        self.stack.setCurrentWidget(self.splitter)
        # self._files_handler.previous_item()

    def toggle_tabs_and_spaces(self):
        """ Toggle Show/Hide Tabs and Spaces """

        settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES
        qsettings = IDE.ninja_settings()
        qsettings.setValue('preferences/editor/showTabsAndSpaces',
                           settings.SHOW_TABS_AND_SPACES)

    def show_navigation_buttons(self):
        """Show Navigation menu."""
        self.stack.setCurrentWidget(self.splitter)
        self.combo_area.show_menu_navigation()

    def change_split_focus(self):
        pass
        #FIXME: check how we handle this
        #if self.actualTab == self._tabMain and self.tabsecondary.isVisible():
            #self.actualTab = self.tabsecondary
        #else:
            #self.actualTab = self._tabMain
        #widget = self.actualTab.currentWidget()
        #if widget is not None:
            #widget.setFocus()

    def shortcut_index(self, index):
        pass
        #self.tabs.setCurrentIndex(index)

    def print_file(self):
        """Call the print of ui_tool

        Call print of ui_tool depending on the focus of the application"""
        #TODO: Add funtionality for proyect tab and methods tab
        editorWidget = self.get_current_editor()
        if editorWidget is not None:
            fileName = "newDocument.pdf"
            if editorWidget.file_path:
                fileName = file_manager.get_basename(
                    editorWidget.file_path)
                fileName = fileName[:fileName.rfind('.')] + '.pdf'
            ui_tools.print_file(fileName, editorWidget.print_)

    def split_assistance(self):
        dialog = split_orientation.SplitOrientation(self)
        dialog.show()

    def close_split(self):
        if self.current_widget != self.combo_area:
            self.current_widget.bar.close_split()

    def split_vertically(self):
        self.show_split(False)

    def split_horizontally(self):
        self.show_split(True)

    def navigate_back(self):
        self.__navigate_with_keyboard(False)

    def navigate_forward(self):
        self.__navigate_with_keyboard(True)
class ComboEditor(QDialog):

    closeSplit = pyqtSignal(QWidget)
    aboutToCloseComboEditor = pyqtSignal()
    allFilesClosed = pyqtSignal()
    splitEditor = pyqtSignal("QWidget*", "QWidget*", bool)
    recentTabsModified = pyqtSignal()

    class NAVIGATE:
        prev = 0
        next = 1

    Q_ENUMS(NAVIGATE)

    def __init__(self, original=False, Force_Free=False):
        super(ComboEditor, self).__init__(None)  #, Qt.WindowStaysOnTopHint)
        self.__original = original
        self.Force_Free = Force_Free
        self.__undocked = []
        self._single_undocked = []
        self._symbols_index = []
        self.__OFiles = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(self, main_combo=original)
        vbox.addWidget(self.bar)

        self.stackedEditor = QStackedLayout()
        vbox.addLayout(self.stackedEditor)

        self._main_container = IDE.get_service('main_container')

        if not self.__original and not self.Force_Free:
            self._main_container.fileOpened.connect(self._file_opened_by_main)

        # QApplication.instance().focusChanged["QWidget*", "QWidget*"].connect(\
        #     lambda w1, w2: QTimer.singleShot(10, lambda w1=w1, w2=w2: print("\n\nQApplication::focusChanged::", w1, w2)))

        self.bar.combo.showComboSelector.connect(
            self._main_container.change_tab)
        self.bar.changeCurrent.connect(self._set_current)
        self.bar.editorSplited.connect(self.split_editor)
        self.bar.runFile[str].connect(self._run_file)
        self.bar.closeFile.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject[str].connect(self._add_to_project)
        self.bar.showFileInExplorer.connect(self._show_file_in_explorer)
        self.bar.goToSymbol.connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.undockThisEditor.connect(self.single_undock_editor)
        self.bar.reopenTab[str].connect(self._main_container.open_file)
        self.bar.recentTabsModified.connect(
            self._main_container.recent_files_changed)
        self.bar.code_navigator.btnPrevious.clicked['bool'].connect(
            lambda: self._navigate_code(self.NAVIGATE.prev))
        self.bar.code_navigator.btnNext.clicked['bool'].connect(
            lambda: self._navigate_code(self.NAVIGATE.prev))

        # QTimer.singleShot(39999, lambda : print("\n\ncombo:-:", self))

    # def closeEvent(self, event):
    #     for comboeditor in self._single_undocked:
    #         print("has undocked", comboeditor)
    #         comboeditor.reject()
    #         comboeditor.deleteLater()

    #     self.bar._close_all_files()
    #     super(ComboEditor, self).closeEvent(event)

    def _navigate_code(self, val):
        op = self.bar.code_navigator.operation
        self._main_container.navigate_code_history(val, op)

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        w = self.stackedEditor.currentWidget()
        if w:
            w.setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stackedEditor.currentIndex()
        ninjaide = IDE.getInstance()
        editable = ninjaide.get_or_create_editable(path)
        print("_file_opened_by_main", editable)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original or self.Force_Free:
                editor = neditable.editor
                print("\n\nadd_editor() ignora por ahora!", editor)

                # disconnect old Signals
                try:
                    editor.cursorPositionChanged[int, int].disconnect()
                except TypeError:
                    pass
                try:
                    editor.editorFocusObtained.disconnect()
                except TypeError:
                    pass
                try:
                    editor.currentLineChanged.disconnect()
                except TypeError:
                    pass
                try:
                    editor.modificationChanged['bool'].disconnect()
                except TypeError:
                    pass
                try:
                    neditable.checkersUpdated.disconnect()
                except TypeError:
                    pass
                try:
                    neditable.fileSaved.disconnect()
                except TypeError:
                    pass

                # Disonnect file system signals only in the original
                try:
                    neditable.fileClosing.disconnect()
                except TypeError:
                    pass
                if self.__original:
                    try:
                        neditable.askForSaveFileClosing.disconnect()
                    except TypeError:
                        pass
                    try:
                        neditable.fileChanged.disconnect()
                    except TypeError:
                        pass

            else:
                editor = self._main_container.create_text_editor_from_editable(
                    neditable)

            index = self.stackedEditor.currentIndex()
            self.stackedEditor.addWidget(editor)
            self.bar.add_item(neditable.display_name, neditable)
            if keep_index:
                self.bar.set_current_by_index(index)

            # Editor Signals
            editor.cursorPositionChanged[int, int].connect(
                self._update_cursor_position)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.currentLineChanged.connect(self._set_current_symbol)
            editor.modificationChanged['bool'].connect(self._editor_modified)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            neditable.fileSaved.connect(self._update_symbols)
            neditable.fileSaved.connect(self._update_combo_info)

            # Connect file system signals only in the original
            neditable.fileClosing.connect(self._close_file)
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)

            # Load Symbols
            self._load_symbols(neditable)

    def show_combo_file(self):
        print("show_combo_file")
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def getOpenedFiles(self):
        return self.__OFiles.copy()

    def addOpenedFiles(self, fil):
        self.__OFiles.append(fil)

    def unlink_editors(self):
        for index in range(self.stackedEditor.count()):
            widget = self.stackedEditor.widget(index)
            widget.setDocument(QsciDocument())

    def split_editor(self, orientationVertical):
        new_widget = ComboEditor()
        for neditable in self.bar.get_editables():
            print("\nsplit_editor", neditable, new_widget)
            new_widget.add_editor(neditable)
        self.splitEditor.emit(self, new_widget, orientationVertical)

    def undock_editor(self):
        new_combo = ComboEditor()
        new_combo.setWindowTitle("NINJA-IDE")
        self.add_Undocked(new_combo)
        for neditable in self.bar.get_editables():
            print("undock_editor", neditable)
            new_combo.add_editor(neditable)
        new_combo.resize(500, 500)
        new_combo.aboutToCloseComboEditor.connect(self._remove_undock)
        new_combo.show()

    def _remove_undock(self):
        print("_remove_undock", self.sender())
        widget = self.sender()
        self.sub_Undocked(widget)

    def add_Undocked(self, combedit):
        self.__undocked.append(combedit)

    def sub_Undocked(self, combedit):
        self.__undocked.remove(combedit)

    def add_SingleUndocked(self, combedit):
        self._single_undocked.append(combedit)

    def sub_SingleUndocked(self, combedit):
        self._single_undocked.remove(combedit)

    # aún no se ha puesto en funcionamiento!.
    def single_split_editor(self, orientationVertical):
        new_widget = ComboEditor()
        for neditable in self.bar.get_editables():
            print("\nsingle_split_editor", neditable, new_widget)
            new_widget.add_editor(neditable)
        self.splitEditor.emit(self, new_widget, orientationVertical)

    def single_undock_editor(self):
        new_combo = ComboEditor(Force_Free=True)
        new_combo.setWindowTitle("NINJA-IDE")
        self.add_SingleUndocked(new_combo)

        nEdit = self.stackedEditor.takeAt(
            self.stackedEditor.currentIndex()).widget()
        ide = IDE.getInstance()
        ide.unload_NEditable(nEdit)
        neditable = self.bar.take_editable()
        print("\n\nsingle_undock_editor:::", neditable, neditable.editor,
              nEdit, neditable.nfile)

        if self.stackedEditor.isEmpty():
            self.allFilesClosed.emit()

        new_combo.add_editor(neditable)
        new_combo.stackedEditor.setCurrentIndex(
            0)  # new_combo.stackedEditor.setCurrentWidget(nEdit)
        new_combo.resize(500, 500)
        new_combo.aboutToCloseComboEditor.connect(self.single__remove_undock)
        new_combo.show()

    def single__remove_undock(self):
        print("single__remove_undock", self.sender())
        widget = self.sender()
        self.sub_SingleUndocked(widget)
        ##widget.deleteLater()

    def bind_Editable(self, editable):
        self.bar.add_item(neditable.display_name, editable)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_file(self, neditable):
        print("\n\n_close_file", self.__original, self.Force_Free)
        index = self.bar.close_file(neditable)
        layoutItem = self.stackedEditor.takeAt(index)
        #neditable.editor.completer.cc.unload_module()
        self._add_to_last_opened(neditable.file_path)
        layoutItem.widget().deleteLater(
        )  # @@4 -> Comentando ésta linea desaparece el mensaje

        if self.stackedEditor.isEmpty():
            self.allFilesClosed.emit()

    def _add_to_last_opened(self, path):
        if path not in settings.LAST_OPENED_FILES:
            settings.LAST_OPENED_FILES.append(path)
            if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS:
                self.__lastOpened = self.__lastOpened[1:]
            self.recentTabsModified.emit()

    def _editor_with_focus(self):
        if self._main_container.current_comboEditor is not self:
            self._main_container.current_comboEditor = self
            editor = self.stackedEditor.currentWidget()
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') % fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    def _file_has_been_modified(self, neditable):
        val = QMessageBox.No
        fileName = neditable.file_path
        val = QMessageBox.question(
            self, translations.TR_FILE_HAS_BEEN_MODIFIED,
            "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE),
            QMessageBox.Yes | QMessageBox.No)
        if val == QMessageBox.Yes:
            neditable.reload_file()

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''
        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        if neditable:
            self.stackedEditor.setCurrentIndex(index)
            editor = self.stackedEditor.currentWidget()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(neditable.file_path)
            self._load_symbols(neditable)
            self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()

    def widget(self, index):
        return self.stackedEditor.widget(index)

    def countEditors(self):
        """Return the number of editors opened."""
        return self.stackedEditor.count()

    def currentEditor(self):
        """ rtn -> Editor()# local QsciScintilla"""
        return self.stackedEditor.currentWidget()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.stackedEditor.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.stackedEditor.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index)
                    or self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value):
        obj = self.sender()
        neditable = obj.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        print("_go_to_symbol in index:", index)
        line = self._symbols_index[index]
        editor = self.stackedEditor.currentWidget()
        editor.go_to_line(line)

    def _update_symbols(self, neditable):
        editor = self.stackedEditor.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if editor == neditable.editor:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        symbols_handler = handlers.get_symbols_handler('py')
        source = neditable.editor.text()
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(list(symbols_simplified.items()),
                                    key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.getCursorPosition()
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        for comboeditor in self._single_undocked:
            print("has undocked", comboeditor)
            comboeditor.reject()
            comboeditor.deleteLater()

        # print("\n\ncloseEvent", self)
        if self.__original:
            self.bar._close_all_files()
        self.aboutToCloseComboEditor.emit()
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
示例#8
0
class MainWindow(QMainWindow):
    def __init__(self):

        super(MainWindow,
              self).__init__()  # Call the inherited classes __init__ method
        self.core = Core.Core.get_core()

    def loadGui(self):

        ui_file = self.core.rsrc_dir + "mainWindow.ui"
        uic.loadUi(ui_file, self)  # Load the .ui file

        self.optionsBox = self.findChild(QHBoxLayout, 'optionsBox')
        self.installersButton = self.findChild(QPushButton, 'installersButton')
        icn = QIcon.fromTheme(
            os.path.join(settings.ICONS_THEME, "view-list-details.svg"))
        self.installersButton.setIcon(icn)
        self.installersButton.setText(_("Installers"))
        self.installersButton.clicked.connect(lambda: self.changePanel("I"))
        self.configurationButton = self.findChild(QPushButton,
                                                  "configurationButton")
        icn = QIcon.fromTheme(
            os.path.join(settings.ICONS_THEME, "configure.svg"))
        self.configurationButton.setIcon(icn)
        #self.configurationButton.setIconSize(QSize(16,16))
        self.configurationButton.setText(_("Configuration Options"))
        self.configurationButton.clicked.connect(lambda: self.changePanel("C"))
        self.mainBox = self.findChild(QVBoxLayout, 'mainBox')
        self.bannerBox = self.findChild(QLabel, 'bannerLabel')
        self.bannerBox.setStyleSheet("background-color: #7f0907")
        self.messageBox = self.findChild(QVBoxLayout, 'messageBox')
        self.messageImg = self.findChild(QLabel, 'messageImg')
        self.messageLabel = self.findChild(QLabel, 'messageLabel')
        self.progressBar = self.findChild(QProgressBar, 'progressBar')
        self.controlsBox = self.findChild(QVBoxLayout, 'controlsBox')
        self.applyButton = self.findChild(QPushButton, 'applyButton')
        icn = QIcon.fromTheme(os.path.join(settings.ICONS_THEME, "gtk-ok.svg"))
        self.applyButton.setIcon(icn)
        self.applyButton.setText(_("Install"))
        self.applyButton.clicked.connect(self.applyButtonClicked)
        self.helpButton = self.findChild(QPushButton, 'helpButton')
        icn = QIcon.fromTheme(
            os.path.join(settings.ICONS_THEME, "help-whatsthis.svg"))
        self.helpButton.setIcon(icn)
        self.helpButton.setText(_("Help"))
        self.helpButton.clicked.connect(self.helpButtonClicked)

        self.loadingBox = self.core.loadingBox
        self.installersBox = self.core.installersBox
        self.configurationBox = self.core.configurationBox

        self.QtStack = QStackedLayout()
        self.QtStack.addWidget(self.loadingBox)
        self.QtStack.addWidget(self.installersBox)
        self.QtStack.addWidget(self.configurationBox)

        self.mainBox.addLayout(self.QtStack)
        self.gatherInfo = gatherInfo()
        self.installersButton.hide()
        self.configurationButton.hide()
        #self.messageLabel.hide()
        self._manageMsgBox(True, False)
        self.applyButton.hide()
        self.helpButton.hide()

        qtRectangle = self.frameGeometry()
        centerPoint = QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())
        centerPoint = QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())
        self.exitLocked = True
        self.gatherInfo.start()
        self.gatherInfo.finished.connect(self._finishProcess)

    #def loadGui

    def _finishProcess(self):

        self.loadingBox.spinner.stop()
        if len(self.core.javaPanelManager.java_list) > 0:
            self.installersBox.drawInstallerList()
            self.fader_widget = FaderWidget(self.QtStack.currentWidget(),
                                            self.QtStack.widget(1))
            self.QtStack.setCurrentIndex(1)
            self.configurationButton.show()
            self._manageMsgBox(True, False)
            #self.messageLabel.show()
            self.applyButton.show()
            self.helpButton.show()
        else:
            #self.messageLabel.show()
            self._manageMsgBox(False, True)
            self.loadingBox.spinner.hide()
            self.messageLabel.setText(
                _("No Java version(s) availables detected"))

        self.exitLocked = False

    #def _finishProcess

    def applyButtonClicked(self):

        self.othersBox = []
        self.javasToInstall = self.installersBox.javas_selected
        self.boxSelected = self.installersBox.box_selected
        #self.installersBox.scrollArea.setEnabled(False)
        self._manageMsgBox(True, False)

        self.messageLabel.setText("")
        if len(self.javasToInstall) > 0:
            self.applyButton.setEnabled(False)
            self.configurationButton.setEnabled(False)
            self.helpButton.setEnabled(False)
            #self.messageLabel.setText(_("Installing selected Java version(s). Wait a moment..."))

            for item in self.boxSelected:
                item.itemAt(0).widget().setEnabled(False)
                item.itemAt(3).widget().hide()
                item.itemAt(4).widget().show()
                item.itemAt(4).widget().start()

            for item in self.installersBox.boxInstallers.children():
                if item.itemAt(0).widget().isEnabled():
                    item.itemAt(0).widget().setEnabled(False)
                    self.othersBox.append(item)

            self.exitLocked = True
            '''
			self.install=installProcess(self.javasToInstall)
			self.install.start()
			self.install.finished.connect(self._finishInstall)
			'''
            self.getPackages = getPackages(self.javasToInstall)
            self._manageMsgBox(True, False)
            self.messageLabel.setText(
                _("1 of 5: Obtaining information about Java(s) to install..."))
            self.progressBar.show()
            self.getPackages.start()
            self.getPackages.finished.connect(self._finishGetPackages)

        else:
            self._manageMsgBox(False, True)
            self.messageLabel.setText(
                _("You must select a Java version to install"))

    #def applyButtonClicked

    def _finishGetPackages(self):

        self.messageLabel.setText(_("2 of 5: Downloading packages..."))
        self.progressBar.setValue(100)

        self.checkProgress = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.checkProgress)
        self.checkProgress.started.connect(self.worker.run)
        self.worker._finished.connect(self.checkProgress.quit)
        self.worker._progress.connect(self._updateMessage)
        self.install = installProcess(self.javasToInstall)
        self.install.start()
        self.install.finished.connect(self._finishInstall)
        self.worker.running = True
        self.checkProgress.start()

    #def _finishGetPackages

    def _updateMessage(self, step):

        if step == "unpack":
            self.messageLabel.setText(
                _("3 of 5: Unpacking packages: %s of %s packages") %
                (str(self.core.javaPanelManager.progressUnpacked),
                 len(self.core.javaPanelManager.initialNumberPackages)))
        elif step == "install":
            self.messageLabel.setText(
                _("4 of 5: Configuring packages: %s of %s packages") %
                (str(self.core.javaPanelManager.progressInstallation),
                 len(self.core.javaPanelManager.initialNumberPackages)))
        elif step == "end":
            self.messageLabel.setText(
                _("5 of 5: Finishing the installation..."))

        self._updateProgressBar(step)

    #def _updateMessage

    def _updateProgressBar(self, step):

        if step == "unpack":
            if self.core.javaPanelManager.progressUnpackedPercentage == 0.00:
                self.progressBar.setValue(200)
            else:
                p_value = 2 + float(
                    self.core.javaPanelManager.progressUnpackedPercentage)
                self.progressBar.setValue(p_value * 100)
        elif step == "install":
            if self.core.javaPanelManager.progressInstallationPercentage == 0.00:
                self.progressBar.setValue(300)
            else:
                p_value = 3 + float(
                    self.core.javaPanelManager.progressInstallationPercentage)
                self.progressBar.setValue(p_value * 100)
        elif step == "end":
            self.progressBar.setValue(400)

    #def _updateProgressBar

    def _finishInstall(self):

        self.progressBar.hide()
        self.worker.running = False

        result = self.core.javaPanelManager.result_install
        error = False
        for item in result:
            if result[item]:
                for element in self.boxSelected:
                    if element.itemAt(4).widget().item == item:
                        element.itemAt(4).widget().stop()
                        element.itemAt(4).widget().hide()
                        pixmap = QPixmap(self.core.rsrc_dir + "check.png")
                        element.itemAt(3).widget().setPixmap(pixmap)
                        element.itemAt(0).widget().setChecked(False)
                        element.itemAt(3).widget().show()
            else:
                for element in self.boxSelected:
                    if element.itemAt(4).widget().item == item:
                        element.itemAt(4).widget().stop()
                        element.itemAt(4).widget().hide()
                        pixmap = QPixmap(self.core.rsrc_dir + "error.png")
                        element.itemAt(3).widget().setPixmap(pixmap)
                        element.itemAt(0).widget().setChecked(False)
                        element.itemAt(0).widget().setEnabled(True)
                        element.itemAt(3).widget().show()
                error = True

        self.applyButton.setEnabled(True)
        self.configurationButton.setEnabled(True)
        self.helpButton.setEnabled(True)

        for item in self.othersBox:
            item.itemAt(0).widget().setEnabled(True)

        if error:
            self._manageMsgBox(False, True)
            self.messageLabel.setText(
                _("Installing process has ending with errors"))
        else:
            self._manageMsgBox(False, False)
            self.messageLabel.setText(
                _("Installing process has ending successfully"))

        self.exitLocked = False

    #def _finishInstall

    def changePanel(self, panel):

        if panel == "C":
            self.configurationButton.hide()
            self.progressBar.hide()
            self._manageMsgBox(True, False)
            self.messageLabel.setText("")
            self.configurationBox.drawConfigurationList()
            self.fader_widget = FaderWidget(self.QtStack.currentWidget(),
                                            self.QtStack.widget(2))
            self.QtStack.setCurrentIndex(2)
            self.installersButton.show()
            self.applyButton.setEnabled(False)

        elif panel == "I":
            self.installersButton.hide()
            self._manageMsgBox(True, False)
            self.messageLabel.setText("")
            self.fader_widget = FaderWidget(self.QtStack.currentWidget(),
                                            self.QtStack.widget(2))
            self.QtStack.setCurrentIndex(1)
            self.configurationButton.show()
            self.applyButton.setEnabled(True)
            self.configurationBox.boxDelete()

    #def changePanel

    def helpButtonClicked(self):

        lang = os.environ["LANG"]
        language = os.environ["LANGUAGE"]
        run_pkexec = False

        if "PKEXEC_UID" in os.environ:
            run_pkexec = True

        exec_lang = ""
        app_lang = ""

        if language == "":
            app_lang = lang
        else:
            language = language.split(":")[0]
            app_lang = language

        if 'valencia' in app_lang:
            exec_lang = "LANG=ca_ES.UTF-8@valencia"
            cmd = exec_lang + ' xdg-open https://wiki.edu.gva.es/lliurex/tiki-index.php?page=LliureX+Java+Panel.'
        else:
            exec_lang = "LANG=es_ES.UTF-8"
            cmd = exec_lang + ' xdg-open https://wiki.edu.gva.es/lliurex/tiki-index.php?page=LliureX-Java-Panel'

        if not run_pkexec:
            self.fcmd = "su -c '%s &' $USER" % cmd
        else:
            user = pwd.getpwuid(int(os.environ["PKEXEC_UID"])).pw_name
            self.fcmd = "su -c '" + cmd + " &' " + user

        os.system(self.fcmd)

    #def helpButtonClicked

    def closeEvent(self, event):

        if self.exitLocked:
            event.ignore()
        else:
            event.accept()

    #def closeEvent

    def _manageMsgBox(self, hide, error):

        self.progressBar.hide()
        if hide:
            self.messageImg.setStyleSheet("background-color: transparent")
            self.messageLabel.setStyleSheet("background-color: transparent")
            self.messageImg.hide()
            self.messageLabel.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)

        else:
            if error:
                self.messageImg.setStyleSheet(
                    "border-bottom: 1px solid #da4453;border-left: 1px solid #da4453;border-top: 1px solid #da4453;background-color: #ebced2"
                )
                self.messageLabel.setStyleSheet(
                    "border-bottom: 1px solid #da4453;border-right: 1px solid #da4453;border-top: 1px solid #da4453;background-color: #ebced2"
                )
                pixmap = QPixmap(self.core.rsrc_dir + "dialog-error.png")
                self.messageImg.setPixmap(pixmap)
                self.messageImg.show()
                self.messageLabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
                self.messageLabel.show()
            else:
                self.messageImg.setStyleSheet(
                    "border-bottom: 1px solid #27ae60;border-left: 1px solid #27ae60;border-top: 1px solid #27ae60;background-color: #c7e3d4"
                )
                self.messageLabel.setStyleSheet(
                    "border-bottom: 1px solid #27ae60;border-right: 1px solid #27ae60;border-top: 1px solid #27ae60;background-color: #c7e3d4"
                )
                pixmap = QPixmap(self.core.rsrc_dir + "dialog-positive.png")
                self.messageImg.setPixmap(pixmap)
                self.messageImg.show()
                self.messageLabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
                self.messageLabel.show()
示例#9
0
class MainWindow(QMainWindow):
    def __init__(self):

        super(MainWindow,
              self).__init__()  # Call the inherited classes __init__ method
        self.core = Core.Core.get_core()

    def loadGui(self):

        ui_file = self.core.rsrc_dir + "mainWindow.ui"
        uic.loadUi(ui_file, self)  # Load the .ui file

        self.optionsBox = self.findChild(QHBoxLayout, 'optionsBox')
        self.installersButton = self.findChild(QPushButton, 'installersButton')
        icn = QIcon.fromTheme(
            os.path.join(settings.ICONS_THEME, "view-list-details.svg"))
        self.installersButton.setIcon(icn)
        self.installersButton.setText(_("Installers"))
        self.installersButton.clicked.connect(lambda: self.changePanel("I"))
        self.configurationButton = self.findChild(QPushButton,
                                                  "configurationButton")
        icn = QIcon.fromTheme(
            os.path.join(settings.ICONS_THEME, "configure.svg"))
        self.configurationButton.setIcon(icn)
        #self.configurationButton.setIconSize(QSize(16,16))
        self.configurationButton.setText(_("Configuration Options"))
        self.configurationButton.clicked.connect(lambda: self.changePanel("C"))
        self.mainBox = self.findChild(QVBoxLayout, 'mainBox')
        self.bannerBox = self.findChild(QLabel, 'bannerLabel')
        self.bannerBox.setStyleSheet("background-color: #7f0907")
        self.messageBox = self.findChild(QVBoxLayout, 'messageBox')
        self.messageLabel = self.findChild(QLabel, 'messageLabel')
        self.controlsBox = self.findChild(QVBoxLayout, 'controlsBox')
        self.applyButton = self.findChild(QPushButton, 'applyButton')
        icn = QIcon.fromTheme(os.path.join(settings.ICONS_THEME, "gtk-ok.svg"))
        self.applyButton.setIcon(icn)
        self.applyButton.setText(_("Install"))
        self.applyButton.clicked.connect(self.applyButtonClicked)
        self.helpButton = self.findChild(QPushButton, 'helpButton')
        icn = QIcon.fromTheme(
            os.path.join(settings.ICONS_THEME, "help-whatsthis.svg"))
        self.helpButton.setIcon(icn)
        self.helpButton.setText(_("Help"))
        self.helpButton.clicked.connect(self.helpButtonClicked)

        self.loadingBox = self.core.loadingBox
        self.installersBox = self.core.installersBox
        self.configurationBox = self.core.configurationBox

        self.QtStack = QStackedLayout()
        self.QtStack.addWidget(self.loadingBox)
        self.QtStack.addWidget(self.installersBox)
        self.QtStack.addWidget(self.configurationBox)

        self.mainBox.addLayout(self.QtStack)
        self.gatherInfo = gatherInfo()
        self.installersButton.hide()
        self.configurationButton.hide()
        self.messageLabel.hide()
        self.applyButton.hide()
        qtRectangle = self.frameGeometry()
        centerPoint = QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())
        centerPoint = QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())
        self.gatherInfo.start()
        self.gatherInfo.finished.connect(self._finishProcess)

    #def loadGui

    def _finishProcess(self):

        self.loadingBox.spinner.stop()
        if len(self.core.javaPanelManager.java_list) > 0:
            self.installersBox.drawInstallerList()
            self.fader_widget = FaderWidget(self.QtStack.currentWidget(),
                                            self.QtStack.widget(1))
            self.QtStack.setCurrentIndex(1)
            self.configurationButton.show()
            self.messageLabel.show()
            self.applyButton.show()
        else:
            self.messageLabel.show()
            self.loadingBox.spinner.hide()
            self.messageLabel.setText(
                _("No Java version(s) availables detected"))

    #def _finishProcess

    def applyButtonClicked(self):

        self.othersBox = []
        self.javasToInstall = self.installersBox.javas_selected
        self.boxSelected = self.installersBox.box_selected
        #self.installersBox.scrollArea.setEnabled(False)
        self.messageLabel.setText("")
        if len(self.javasToInstall) > 0:
            self.applyButton.setEnabled(False)
            self.messageLabel.setText(
                _("Installing selected Java version(s). Wait a moment..."))

            for item in self.boxSelected:
                item.itemAt(0).widget().setEnabled(False)
                item.itemAt(3).widget().hide()
                item.itemAt(4).widget().show()
                item.itemAt(4).widget().start()

            for item in self.installersBox.boxInstallers.children():
                if item.itemAt(0).widget().isEnabled():
                    item.itemAt(0).widget().setEnabled(False)
                    self.othersBox.append(item)

            self.install = installProcess(self.javasToInstall)
            self.install.start()
            self.install.finished.connect(self._finishInstall)
        else:
            self.messageLabel.setText(
                _("You must select a Java version to install"))

    #def applyButtonClicked

    def _finishInstall(self):

        result = self.core.javaPanelManager.result_install
        error = False
        for item in result:
            if result[item]:
                for element in self.boxSelected:
                    if element.itemAt(4).widget().item == item:
                        element.itemAt(4).widget().stop()
                        element.itemAt(4).widget().hide()
                        pixmap = QPixmap(self.core.rsrc_dir + "check.png")
                        element.itemAt(3).widget().setPixmap(pixmap)
                        element.itemAt(0).widget().setChecked(False)
                        element.itemAt(3).widget().show()
            else:
                for element in self.boxSelected:
                    if element.itemAt(4).widget().item == item:
                        element.itemAt(4).widget().stop()
                        element.itemAt(4).widget().hide()
                        pixmap = QPixmap(self.core.rsrc_dir + "error.png")
                        element.itemAt(3).widget().setPixmap(pixmap)
                        element.itemAt(0).widget().setChecked(False)
                        element.itemAt(0).widget().setEnabled(True)
                        element.itemAt(3).widget().show()
                error = True

        self.applyButton.setEnabled(True)

        for item in self.othersBox:
            item.itemAt(0).widget().setEnabled(True)

        if error:
            self.messageLabel.setText(
                _("Installing process has ending with errors"))
        else:
            self.messageLabel.setText(
                _("Installing process has ending successfully"))

    #def _finishInstall

    def changePanel(self, panel):

        if panel == "C":
            self.configurationButton.hide()
            self.messageLabel.setText("")
            self.configurationBox.drawConfigurationList()
            self.fader_widget = FaderWidget(self.QtStack.currentWidget(),
                                            self.QtStack.widget(2))
            self.QtStack.setCurrentIndex(2)
            self.installersButton.show()
            self.applyButton.setEnabled(False)

        elif panel == "I":
            self.installersButton.hide()
            self.messageLabel.setText("")
            self.fader_widget = FaderWidget(self.QtStack.currentWidget(),
                                            self.QtStack.widget(2))
            self.QtStack.setCurrentIndex(1)
            self.configurationButton.show()
            self.applyButton.setEnabled(True)
            self.configurationBox.boxDelete()

    #def changePanel

    def helpButtonClicked(self):

        lang = os.environ["LANG"]
        run_pkexec = False

        if "PKEXEC_UID" in os.environ:
            run_pkexec = True

        if 'ca_ES' in lang:
            cmd = 'xdg-open https://wiki.edu.gva.es/lliurex/tiki-index.php?page=LliureX-Java-Panel.'
        else:
            cmd = 'xdg-open https://wiki.edu.gva.es/lliurex/tiki-index.php?page=LliureX-Java-Panel'

        if not run_pkexec:
            self.fcmd = "su -c '%s' $USER" % cmd
        else:
            user = pwd.getpwuid(int(os.environ["PKEXEC_UID"])).pw_name
            self.fcmd = "su -c '" + cmd + "' " + user

        os.system(self.fcmd)
示例#10
0
class RightPanel(QFrame):
    def __init__(self, app, parent=None):
        super().__init__(parent)

        self._app = app
        self._pixmap = None

        self._layout = QVBoxLayout(self)
        self._stacked_layout = QStackedLayout()
        self.scrollarea = ScrollArea(self._app, self)
        self.table_container = self.scrollarea.t
        # TODO: collection container will be removed
        self.collection_container = CollectionContainer(self._app, self)
        self.bottom_panel = BottomPanel(app, self)

        self._setup_ui()

    def _setup_ui(self):
        self.scrollarea.setMinimumHeight(100)
        self.collection_container.hide()
        self._layout.addWidget(self.bottom_panel)
        self._layout.addLayout(self._stacked_layout)
        self._stacked_layout.addWidget(self.scrollarea)
        self._stacked_layout.addWidget(self.collection_container)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)

    def show_model(self, model):
        self.set_body(self.scrollarea)
        # TODO: use PreemptiveTask
        aio.create_task(self.table_container.show_model(model))

    def show_songs(self, songs):
        self.collection_container.hide()
        self.set_body(self.scrollarea)
        self.table_container.show_songs(songs)

    def set_body(self, widget):
        """

        .. versionadded:: 3.7.7
        """
        if widget is self.table_container:
            widget = self.scrollarea

        if widget is not self.scrollarea:
            self.show_background_image(None)

        # remove tmp widgets
        for i in range(self._stacked_layout.count()):
            w = self._stacked_layout.widget(i)
            if w not in (self.scrollarea, self.collection_container):
                self._stacked_layout.removeWidget(w)

        self._stacked_layout.addWidget(widget)
        self._stacked_layout.setCurrentWidget(widget)

    def show_collection(self, coll):
        def _show_pure_albums_coll(coll):
            self.set_body(self.scrollarea)
            reader = wrap(coll.models)
            self.table_container.show_albums_coll(reader)

        def _show_pure_songs_coll(coll):
            self.set_body(self.scrollarea)
            self.table_container.show_collection(coll)

        def _show_mixed_coll(coll):
            self.set_body(self.collection_container)
            self.collection_container.show_collection(coll)

        def _show_pure_videos_coll(coll):
            from feeluown.gui.page_containers.table import VideosRenderer

            self.set_body(self.scrollarea)
            reader = wrap(coll.models)
            renderer = VideosRenderer(reader)
            aio.create_task(self.table_container.set_renderer(renderer))

        if coll.type is CollectionType.sys_library:
            self._app.browser.goto(page='/colls/library')
            return

        types = set()
        for model in coll.models:
            types.add(model.meta.model_type)
            if len(types) >= 2:
                break

        if len(types) == 1:
            type_ = types.pop()
            if type_ == ModelType.song:
                _show_pure_songs_coll(coll)
            elif type_ == ModelType.album:
                _show_pure_albums_coll(coll)
            elif type_ == ModelType.video:
                _show_pure_videos_coll(coll)
            else:
                _show_mixed_coll(coll)
        else:
            _show_mixed_coll(coll)

    def show_background_image(self, pixmap):
        self._pixmap = pixmap
        if pixmap is None:
            self.table_container.meta_widget.setMinimumHeight(0)
        else:
            height = (self._app.height() - self.bottom_panel.height() -
                      self.table_container.toolbar.height()) // 2
            self.table_container.meta_widget.setMinimumHeight(height)
        self.update()

    def paintEvent(self, e):
        """
        draw pixmap as a the background with a dark overlay

        HELP: currently, this cost much CPU
        """
        painter = QPainter(self)
        painter.setPen(Qt.NoPen)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.SmoothPixmapTransform)

        # calculate available size
        draw_width = self.width()
        draw_height = 10  # spacing defined in table container
        draw_height += self.bottom_panel.height()
        if self.table_container.meta_widget.isVisible():
            draw_height += self.table_container.meta_widget.height()
        extra = self.table_container.current_extra
        if extra is not None and extra.isVisible():
            draw_height += extra.height()
        if self.table_container.toolbar.isVisible():
            draw_height += self.table_container.toolbar.height()

        scrolled = self.scrollarea.verticalScrollBar().value()
        max_scroll_height = draw_height - self.bottom_panel.height()

        if scrolled >= max_scroll_height:
            painter.save()
            painter.setBrush(self.palette().brush(QPalette.Window))
            painter.drawRect(self.bottom_panel.rect())
            painter.restore()
            return

        if self._pixmap is not None:
            self._draw_pixmap(painter, draw_width, draw_height, scrolled)
            self._draw_pixmap_overlay(painter, draw_width, draw_height,
                                      scrolled)
        else:
            # draw gradient for widgets(bottom panel + meta_widget + ...) above table
            self._draw_overlay(painter, draw_width, draw_height, scrolled)

            # if scrolled height > 30, draw background to seperate bottom_panel and body
            if scrolled >= 30:
                painter.save()
                painter.setBrush(self.palette().brush(QPalette.Window))
                painter.drawRect(self.bottom_panel.rect())
                painter.restore()
                return

            # since the body's background color is palette(base), we use
            # the color to draw background for remain empty area
            painter.save()
            painter.setBrush(self.palette().brush(QPalette.Base))
            painter.drawRect(0, draw_height, draw_width,
                             self.height() - draw_height)
            painter.restore()
        painter.end()

    def _draw_pixmap_overlay(self, painter, draw_width, draw_height, scrolled):
        painter.save()
        rect = QRect(0, 0, draw_width, draw_height)
        painter.translate(0, -scrolled)
        gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft())
        color = self.palette().color(QPalette.Base)
        if draw_height == self.height():
            gradient.setColorAt(0, add_alpha(color, 180))
            gradient.setColorAt(1, add_alpha(color, 230))
        else:
            if self._app.theme_mgr.theme == Light:
                gradient.setColorAt(0, add_alpha(color, 220))
                gradient.setColorAt(0.1, add_alpha(color, 180))
                gradient.setColorAt(0.2, add_alpha(color, 140))
                gradient.setColorAt(0.6, add_alpha(color, 140))
                gradient.setColorAt(0.8, add_alpha(color, 200))
                gradient.setColorAt(0.9, add_alpha(color, 240))
                gradient.setColorAt(1, color)
            else:
                gradient.setColorAt(0, add_alpha(color, 50))
                gradient.setColorAt(0.6, add_alpha(color, 100))
                gradient.setColorAt(0.8, add_alpha(color, 200))
                gradient.setColorAt(0.9, add_alpha(color, 240))
                gradient.setColorAt(1, color)
        painter.setBrush(gradient)
        painter.drawRect(rect)
        painter.restore()

    def _draw_overlay(self, painter, draw_width, draw_height, scrolled):
        painter.save()
        rect = QRect(0, 0, draw_width, draw_height)
        painter.translate(0, -scrolled)
        gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft())
        gradient.setColorAt(0, self.palette().color(QPalette.Window))
        gradient.setColorAt(1, self.palette().color(QPalette.Base))
        painter.setBrush(gradient)
        painter.drawRect(rect)
        painter.restore()

    def _draw_pixmap(self, painter, draw_width, draw_height, scrolled):
        # scale pixmap
        scaled_pixmap = self._pixmap.scaledToWidth(
            draw_width, mode=Qt.SmoothTransformation)
        pixmap_size = scaled_pixmap.size()

        # draw the center part of the pixmap on available rect
        painter.save()
        brush = QBrush(scaled_pixmap)
        painter.setBrush(brush)
        # note: in practice, most of the time, we can't show the
        # whole artist pixmap, as a result, the artist head will be cut,
        # which causes bad visual effect. So we render the top-center part
        # of the pixmap here.
        y = (pixmap_size.height() - draw_height) // 3
        painter.translate(0, -y - scrolled)
        rect = QRect(0, y, draw_width, draw_height)
        painter.drawRect(rect)
        painter.restore()

    def sizeHint(self):
        size = super().sizeHint()
        return QSize(760, size.height())
示例#11
0
class _MainContainer(QWidget):

    currentEditorChanged = pyqtSignal("QString")
    fileOpened = pyqtSignal("QString")
    fileSaved = pyqtSignal("QString")

    def __init__(self, parent=None):
        super().__init__(parent)
        self._vbox = QVBoxLayout(self)
        self._vbox.setContentsMargins(0, 0, 0, 0)
        self._vbox.setSpacing(0)
        self.stack = QStackedLayout()
        self.stack.setStackingMode(QStackedLayout.StackAll)
        self._vbox.addLayout(self.stack)
        self.splitter = dynamic_splitter.DynamicSplitter()
        self.setAcceptDrops(True)
        # QML UI
        self._add_file_folder = add_file_folder.AddFileFolderWidget(self)

        if settings.SHOW_START_PAGE:
            self.show_start_page()

        IDE.register_service("main_container", self)
        # Register signals connections
        connections = ({
            "target": "main_container",
            "signal_name": "updateLocator",
            "slot": self._explore_code
        }, {
            "target": "filesystem",
            "signal_name": "projectOpened",
            "slot": self._explore_code
        }, {
            "target": "projects_explore",
            "signal_name": "updateLocator",
            "slot": self._explore_code
        })

        IDE.register_signals("main_container", connections)

        esc_sort = QShortcut(QKeySequence(Qt.Key_Escape), self)
        esc_sort.activated.connect(self._set_focus_to_editor)

    def install(self):
        ninjaide = IDE.get_service("ide")
        ninjaide.place_me_on("main_container", self, "central", top=True)

        self.combo_area = combo_editor.ComboEditor(original=True)
        self.combo_area.allFilesClosed.connect(self._files_closed)
        self.splitter.add_widget(self.combo_area)
        self.add_widget(self.splitter)

        self.current_widget = self.combo_area
        # Code Locator
        self._code_locator = locator_widget.LocatorWidget(ninjaide)

        ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide)

    def _set_focus_to_editor(self):
        status_bar = IDE.get_service("status_bar")
        tools_doock = IDE.get_service("tools_dock")
        editor_widget = self.get_current_editor()
        if status_bar.isVisible() and tools_doock.isVisible():
            status_bar.hide_status_bar()
        elif tools_doock.isVisible():
            tools_doock._hide()
        elif status_bar.isVisible():
            status_bar.hide_status_bar()
        if editor_widget is not None:
            editor_widget.clear_extra_selections('searchs')

    def split_assistance(self):
        split_widget = split_orientation.SplitOrientation(self)
        split_widget.show()

    def show_split(self, orientation_vertical=False):
        self.current_widget.split_editor(orientation_vertical)

    def show_locator(self):
        """Show the Locator Widget"""

        if not self._code_locator.isVisible():
            self._code_locator.show()

    def _explore_code(self):
        """Update locator metadata for the current projects"""

        self._code_locator.explore_code()

    def current_editor_changed(self, filename):
        """Notify the new filename of the current editor"""

        if filename is None:
            filename = translations.TR_NEW_DOCUMENT
        self.currentEditorChanged.emit(filename)

    def get_current_editor(self):
        current_widget = self.current_widget.currentWidget()
        if isinstance(current_widget, editor.NEditor):
            return current_widget
        return None

    def open_file(self, filename='', line=-1, col=0):
        logger.debug("Will try to open %s" % filename)
        if not filename:
            logger.debug("Has no filename")
            if settings.WORKSPACE:
                directory = settings.WORKSPACE
            else:
                directory = os.path.expanduser("~")
                editor_widget = self.get_current_editor()
                ninjaide = IDE.get_service("ide")
                current_project = ninjaide.get_current_project()
                # TODO: handle current project in NProject
                if current_project is not None:
                    directory = current_project.full_path
                elif editor_widget is not None and editor_widget.file_path:
                    directory = file_manager.get_folder(
                        editor_widget.file_path)
            extensions = ";;".join([
                "{}(*{})".format(e.upper()[1:], e)
                for e in settings.SUPPORTED_EXTENSIONS + [".*", ""]
            ])
            filenames = QFileDialog.getOpenFileNames(
                self,
                "Open File",  # FIXME: translations
                directory,
                extensions)[0]
        else:
            logger.debug("Has filename")
            filenames = [filename]
        if not filenames:
            return
        for filename in filenames:
            logger.debug("Will try to open: %s" % filename)
            self.__open_file(filename, line, col)

    def __open_file(self, filename, line, col):
        try:
            editor_widget = self.add_editor(filename)
            if line != -1:
                editor_widget.go_to_line(line, col)
            self.currentEditorChanged.emit(filename)
        except file_manager.NinjaIOException as reason:
            QMessageBox.information(
                self,
                "The file couldn't be open",  # FIXME: translations
                str(reason))
            logger.error("The file %s couldn't be open" % filename)

    def save_file(self, editor_widget=None):
        if editor_widget is None:
            # This may return None if there is not editor present
            editor_widget = self.get_current_editor()
        if editor_widget is None:
            return False
        # Ok, we have an editor instance
        # Save to file only if editor really was modified
        if editor_widget.is_modified:
            try:
                if editor_widget.nfile.is_new_file or \
                        not editor_widget.nfile.has_write_permission():
                    return self.save_file_as(editor_widget)
                # FIXME: beforeFileSaved.emit
                if settings.REMOVE_TRAILING_SPACES:
                    pass
                # FIXME: new line at end
                # Save content
                editor_widget.neditable.save_content()
                # FIXME: encoding
                # FIXME: translations
                self.fileSaved.emit("File Saved: %s" % editor_widget.file_path)
                return True
            except Exception as reason:
                logger.error("Save file error: %s" % reason)
                QMessageBox.information(self, "Save Error",
                                        "The file could't be saved!")
            return False

    def save_file_as(self, editor_widget=None):
        force = False
        if editor_widget is None:
            # We invoque from menu
            editor_widget = self.get_current_editor()
            if editor_widget is None:
                # We haven't editor in main container
                return False
            force = True
        try:
            filters = "(*.py);;(*.*)"
            if editor_widget.file_path is not None:  # Existing file
                extension = file_manager.get_file_extension(
                    editor_widget.file_path)
                if extension != 'py':
                    filters = "(*.%s);;(*.py);;(*.*)" % extension
            save_folder = self._get_save_folder(editor_widget.file_path)
            filename = QFileDialog.getSaveFileName(self, "Save File",
                                                   save_folder, filters)[0]
            if not filename:
                return False
            # FIXME: remove trailing spaces
            extension = file_manager.get_file_extension(filename)
            if not extension:
                filename = "%s.%s" % (filename, "py")
            editor_widget.neditable.save_content(path=filename, force=force)

            self.fileSaved.emit("File Saved: {}".format(filename))
            self.currentEditorChanged.emit(filename)
            return True
        except file_manager.NinjaFileExistsException as reason:
            QMessageBox.information(
                self, "File Already Exists",
                "Invalid Path: the file '%s' already exists." %
                reason.filename)
        except Exception as reason:
            logger.error("save_file_as: %s", reason)
            QMessageBox.information(self, "Save Error",
                                    "The file couldn't be saved!")
        return False

    def _get_save_folder(self, filename):
        """Returns the root directory of the 'Main Project'
        or the home folder"""

        ninjaide = IDE.get_service("ide")
        current_project = ninjaide.get_current_project()
        if current_project is not None:
            return current_project.path
        return os.path.expanduser("~")

    def close_file(self):
        self.current_widget.close_current_file()

    def add_editor(self, filename=None):
        ninjaide = IDE.get_service("ide")
        editable = ninjaide.get_or_create_editable(filename)
        if editable.editor:
            # If already open
            logger.debug("%s is already open" % filename)
            self.current_widget.set_current(editable)
            return self.current_widget.currentWidget()
        else:
            pass

        editor_widget = self.create_editor_from_editable(editable)
        # editor_widget.set_language()
        # Add the tab
        keep_index = (self.splitter.count() > 1
                      and self.combo_area.stacked.count() > 0)
        self.combo_area.add_editor(editable, keep_index)
        # Emit a signal about the file open
        self.fileOpened.emit(filename)

        if not keep_index:
            self.current_widget.set_current(editable)

        self.stack.setCurrentWidget(self.splitter)
        editor_widget.setFocus()
        return editor_widget

    def create_editor_from_editable(self, editable):
        neditor = editor.create_editor(editable)
        neditor.zoomChanged.connect(self._show_zoom_indicator)
        neditor.destroyed.connect(self.__on_editor_destroyed)
        # editable.fileSaved.connect(self._editor_tab)
        return neditor

    def _show_zoom_indicator(self, zoom):
        neditor = self.get_current_editor()
        indicator.Indicator.show_text(neditor, "Zoom: {} %".format(str(zoom)))

    @pyqtSlot()
    def __on_editor_destroyed(self):
        indicator.Indicator.instance = None

    def add_widget(self, widget):
        self.stack.addWidget(widget)

    def show_start_page(self):
        """Show Start Page widget in main container"""

        startp = self.stack.widget(0)
        if isinstance(startp, start_page.StartPage):
            self.stack.setCurrentIndex(0)
        else:
            startp = start_page.StartPage(parent=self)
            startp.newFile.connect(self.add_editor)
            self.stack.insertWidget(0, startp)
            self.stack.setCurrentIndex(0)

    def _files_closed(self):
        if settings.SHOW_START_PAGE:
            self.show_start_page()

    def add_status_bar(self, status_bar):
        self._vbox.addWidget(status_bar)

    def create_file(self, base_path, project_path):
        self._add_file_folder.create_file(base_path, project_path)

    def create_folder(self, base_path, project_path):
        self._add_file_folder.create_folder(base_path, project_path)

    def zoom_in_editor(self):
        """Increase the font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.zoom(1.)

    def zoom_out_editor(self):
        """Decrease the font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.zoom(-1.)

    def reset_zoom_editor(self):
        """Reset the to original font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.reset_zoom()

    def editor_move_up(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.move_up_down(up=True)

    def editor_move_down(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.move_up_down()

    def editor_duplicate_line(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.duplicate_line()

    def editor_comment(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.comment()
示例#12
0
class ComboEditor(QWidget):
    # Signals
    closeSplit = pyqtSignal('PyQt_PyObject')
    splitEditor = pyqtSignal(
        'PyQt_PyObject', 'PyQt_PyObject', Qt.Orientation)
    allFilesClosed = pyqtSignal()
    about_to_close_combo_editor = pyqtSignal()
    fileClosed = pyqtSignal("PyQt_PyObject")

    def __init__(self, original=False):
        super(ComboEditor, self).__init__(None)
        self.__original = original
        self.__undocked = []
        self._symbols_index = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(main_combo=original)
        vbox.addWidget(self.bar)

        # Info bar
        # self.info_bar = InfoBar(self)
        # self.info_bar.setVisible(False)
        # vbox.addWidget(self.info_bar)

        self.stacked = QStackedLayout()
        vbox.addLayout(self.stacked)

        self._main_container = IDE.get_service('main_container')

        if not self.__original:
            self._main_container.fileOpened['QString'].connect(
                self._file_opened_by_main)

        self.bar.combo_files.showComboSelector.connect(
            self._main_container.show_files_handler)
        self.bar.combo_files.hideComboSelector.connect(
            self._main_container.hide_files_handler)
        self.bar.change_current['PyQt_PyObject',
                                int].connect(self._set_current)
        self.bar.splitEditor[bool].connect(self.split_editor)
        self.bar.runFile['QString'].connect(self._run_file)
        self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject['QString'].connect(self._add_to_project)
        self.bar.showFileInExplorer['QString'].connect(
            self._show_file_in_explorer)
        self.bar.goToSymbol[int].connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.reopenTab['QString'].connect(
            lambda path: self._main_container.open_file(path))
        self.bar.closeImageViewer.connect(self._close_image)
        self.bar.code_navigator.previousPressed.connect(self._navigate_code)
        self.bar.code_navigator.nextPressed.connect(self._navigate_code)
        # self.connect(self.bar, SIGNAL("recentTabsModified()"),
        #             lambda: self._main_container.recent_files_changed())
        # self.connect(self.bar.code_navigator.btnPrevious,
        #                SIGNAL("clicked()"),
        #             lambda: self._navigate_code(False))
        # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"),
        #             lambda: self._navigate_code(True))

    def _navigate_code(self, operation, forward=True):
        self._main_container.navigate_code_history(operation, forward)
    #    op = self.bar.code_navigator.operation
    #    self._main_container.navigate_code_history(val, op)

    def current_editor(self):
        return self.stacked.currentWidget()

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        self.current_editor().setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stacked.currentIndex()
        ninjaide = IDE.get_service('ide')
        editable = ninjaide.get_or_create_editable(path)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_image_viewer(self, viewer):
        """Add Image Viewer widget to the UI area"""

        self.stacked.addWidget(viewer)
        viewer.scaleFactorChanged.connect(
            self.bar.image_viewer_controls.update_scale_label)
        viewer.imageSizeChanged.connect(
            self.bar.image_viewer_controls.update_size_label)
        self.bar.add_item(viewer.display_name(), None)
        viewer.create_scene()
        if not self.bar.isVisible():
            self.bar.setVisible(True)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original:
                editor = neditable.editor
            else:
                # editor = neditable.editor.clone()
                editor = self._main_container.create_editor_from_editable(
                   neditable)
                neditable.editor.link(editor)

            current_index = self.stacked.currentIndex()
            new_index = self.stacked.addWidget(editor)
            self.stacked.setCurrentIndex(new_index)
            self.bar.add_item(neditable.display_name, neditable)
            # Bar is not visible because all the files have been closed,
            # so if a new file is opened, show the bar
            if not self.bar.isVisible():
                self.bar.setVisible(True)
            if keep_index:
                self.bar.set_current_by_index(current_index)

            # Connections
            neditable.fileClosing.connect(self._close_file)
            neditable.fileSaved.connect(self._update_symbols)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.modificationChanged.connect(self._editor_modified)
            editor.cursor_position_changed[int, int].connect(
                self._update_cursor_position)
            editor.current_line_changed[int].connect(self._set_current_symbol)
            if neditable._swap_file.dirty:
                self._editor_modified(True, sender=editor)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            # Connect file system signals only in the original
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)
            # Load Symbols
            self._load_symbols(neditable)

    def show_combo_file(self):
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def show_combo_set_language(self):
        self.bar.set_language_combo.showPopup()

    def unlink_editors(self):
        for index in range(self.stacked.count()):
            widget = self.stacked.widget(index)
            # widget.setDocument(QsciDocument())

    def clone(self):
        combo = ComboEditor()
        for neditable in self.bar.get_editables():
            combo.add_editor(neditable)
        return combo

    def split_editor(self, orientation):
        new_combo = self.clone()
        self.splitEditor.emit(self, new_combo, orientation)

    def undock_editor(self):
        new_combo = ComboEditor()
        for neditable in self.bar.get_editables():
            new_combo.add_editor(neditable)
        self.__undocked.append(new_combo)
        new_combo.setWindowTitle("NINJA-IDE")
        editor = self.current_editor()
        new_combo.set_current(editor.neditable)
        new_combo.resize(700, 500)
        new_combo.about_to_close_combo_editor.connect(self._remove_undock)
        new_combo.show()

    def _remove_undock(self):
        widget = self.sender()
        self.__undocked.remove(widget)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_image(self, index):
        layout_item = self.stacked.takeAt(index)
        layout_item.widget().deleteLater()
        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()

    def _close_file(self, neditable):
        index = self.bar.close_file(neditable)
        layoutItem = self.stacked.takeAt(index)
        # neditable.editor.completer.cc.unload_module()
        self.fileClosed.emit(neditable.nfile)
        layoutItem.widget().deleteLater()

        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()
            tree_symbols = IDE.get_service("symbols_explorer")
            if tree_symbols is not None:
                tree_symbols.clear()

    def _editor_with_focus(self):
        self._main_container.combo_area = self
        editor = self.current_editor()
        if editor is not None:
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') %
                   fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No |
            QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    @pyqtSlot("PyQt_PyObject")
    def _recovery(self, neditable):
        print("lalalal")

    def _file_has_been_modified(self, neditable):
        index = self.bar.combo_files.findData(neditable)
        self.stacked.setCurrentIndex(index)
        self.bar.combo_files.setCurrentIndex(index)

        msg_box = QMessageBox(self)
        msg_box.setIcon(QMessageBox.Information)
        msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msg_box.setDefaultButton(QMessageBox.Yes)
        msg_box.setWindowTitle(translations.TR_FILE_HAS_BEEN_MODIFIED)
        msg_box.setText(
            translations.TR_FILE_MODIFIED_OUTSIDE % neditable.display_name)

        result = msg_box.exec_()
        if result == QMessageBox.Yes:
            neditable.reload_file()
        return

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''

        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        self.stacked.setCurrentIndex(index)
        if neditable:
            self.bar.image_viewer_controls.setVisible(False)
            self.bar.code_navigator.setVisible(True)
            self.bar.symbols_combo.setVisible(True)
            self.bar.lbl_position.setVisible(True)

            editor = self.current_editor()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(
                neditable.file_path)
            self._load_symbols(neditable)
            # self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()
        else:
            self.bar.combo_files.setCurrentIndex(index)
            viewer_widget = self.stacked.widget(index)
            self._main_container.current_editor_changed(
                viewer_widget.image_filename)
            self.bar.image_viewer_controls.setVisible(True)
            self.bar.code_navigator.setVisible(False)
            self.bar.symbols_combo.setVisible(False)
            self.bar.lbl_position.setVisible(False)

    def widget(self, index):
        return self.stacked.widget(index)

    def count(self):
        """Return the number of editors opened."""
        return self.stacked.count()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index) or
                    self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value, sender=None):
        if sender is None:
            sender = self.sender()
        neditable = sender.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        line = self._symbols_index[index]
        editor = self.current_editor()
        editor.go_to_line(line, center=True)
        editor.setFocus()

    def _update_symbols(self, neditable):
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if editor.neditable == neditable:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        # Get symbols handler by language
        symbols_handler = handlers.get_symbols_handler(neditable.language())
        if symbols_handler is None:
            return
        source = neditable.editor.text
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(
            list(symbols_simplified.items()), key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.cursor_position
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        if tree_symbols is not None:
            tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                # FIXME: sucks
                else:
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        self.about_to_close_combo_editor.emit()
        # self.emit(SIGNAL("aboutToCloseComboEditor()"))
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
示例#13
0
class _MainContainer(QWidget):

    currentEditorChanged = pyqtSignal(str)
    fileOpened = pyqtSignal(str)
    beforeFileSaved = pyqtSignal(str)
    fileSaved = pyqtSignal(str)
    runFile = pyqtSignal(str)
    showFileInExplorer = pyqtSignal(str)
    addToProject = pyqtSignal(str)
    allFilesClosed = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
        self._vbox = QVBoxLayout(self)
        self._vbox.setContentsMargins(0, 0, 0, 0)
        self._vbox.setSpacing(0)
        self.stack = QStackedLayout()
        self.stack.setStackingMode(QStackedLayout.StackAll)
        self._vbox.addLayout(self.stack)
        self.splitter = dynamic_splitter.DynamicSplitter()
        self._files_handler = files_handler.FilesHandler(self)

        # Code Navigation
        self.__code_back = []
        self.__code_forward = []
        self.__operations = {
            0: self._navigate_code_jumps,
            1: self._navigate_bookmarks
        }
        # Recent files list
        self.__last_opened_files = []
        # QML UI
        self._add_file_folder = add_file_folder.AddFileFolderWidget(self)

        if settings.SHOW_START_PAGE:
            self.show_start_page()

        IDE.register_service("main_container", self)
        # Register signals connections
        connections = (
            # {
            #     "target": "main_container",
            #     "signal_name": "updateLocator",
            #     "slot": self._explore_code
            # },
            {
                "target": "filesystem",
                "signal_name": "projectOpened",
                "slot": self._explore_code
            },
            # {
            #     "target": "projects_explore",
            #     "signal_name": "updateLocator",
            #     "slot": self._explore_code
            # }
            {
                "target": "filesystem",
                "signal_name": "projectClosed",
                "slot": self._explore_code
            }
        )

        IDE.register_signals("main_container", connections)

        fhandler_short = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Tab), self)
        fhandler_short.activated.connect(self.show_files_handler)
        # Added for set language
        # self._setter_language = set_language.SetLanguageFile()

    def install(self):
        ninjaide = IDE.get_service("ide")
        ninjaide.place_me_on("main_container", self, "central", top=True)

        self.combo_area = combo_editor.ComboEditor(original=True)
        self.combo_area.allFilesClosed.connect(self._files_closed)
        self.combo_area.allFilesClosed.connect(
            lambda: self.allFilesClosed.emit())
        self.combo_area.fileClosed.connect(self._add_to_last_opened)
        self.splitter.add_widget(self.combo_area)
        self.add_widget(self.splitter)
        # self.current_widget = self.combo_area
        # Code Locator
        self._code_locator = locator_widget.LocatorWidget(ninjaide)

        data_settings = IDE.data_settings()
        recent_files = data_settings.value("lastSession/recentFiles")
        if recent_files is not None:
            self.__last_opened_files = recent_files
        ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide)
        # self.fileSaved.connect(self._show_message_about_saved)

    def run_file(self, filepath):
        self.runFile.emit(filepath)

    def _show_file_in_explorer(self, filepath):
        self.showFileInExplorer.emit(filepath)

    def _add_to_project(self, filepath):
        self.addToProject.emit(filepath)

    def show_files_handler(self):
        self._files_handler.next_item()

    def hide_files_handler(self):
        self._files_handler.hide()

    def import_from_everywhere(self):
        """Insert an import line from any place in the editor."""

        editorWidget = self.get_current_editor()
        if editorWidget:
            dialog = from_import_dialog.FromImportDialog(editorWidget, self)
            dialog.show()

    def navigate_code_history(self, operation, forward):
        self.__operations[operation](forward)

    def _navigate_code_jumps(self, forward=False):
        """Navigate between the jump points"""
        node = None
        if not forward and self.__code_back:
            if len(self.__code_back) == 1:
                return
            node = self.__code_back.pop()
            self.__code_forward.append(node)
            node = self.__code_back[-1]
        elif forward and self.__code_forward:
            node = self.__code_forward.pop()
            self.__code_back.append(node)
        if node is not None:
            filename = node[0]
            line, col = node[1]
            self.open_file(filename, line, col)

    def _navigate_bookmarks(self, forward=True):
        """Navigate between the bookmarks"""

        current_editor = self.get_current_editor()
        current_editor.navigate_bookmarks(forward=forward)

    def _set_focus_to_editor(self):
        status_bar = IDE.get_service("status_bar")
        tools_doock = IDE.get_service("tools_dock")
        editor_widget = self.get_current_editor()
        if status_bar.isVisible() and tools_doock.isVisible():
            status_bar.hide_status_bar()
        elif tools_doock.isVisible():
            tools_doock._hide()
        elif status_bar.isVisible():
            status_bar.hide_status_bar()
        if editor_widget is not None:
            editor_widget.extra_selections.remove("find")
            editor_widget.scrollbar().remove_marker("find")

    def split_assistance(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            split_widget = split_orientation.SplitOrientation(self)
            split_widget.show()

    def show_dialog(self, widget):
        self.add_widget(widget)
        self.stack.setCurrentWidget(widget)

    def show_split(self, orientation_vertical=False):
        orientation = Qt.Horizontal
        if orientation_vertical:
            orientation = Qt.Vertical
        self.combo_area.split_editor(orientation)

    def show_locator(self):
        """Show the Locator Widget"""

        if not self._code_locator.isVisible():
            self._code_locator.show()

    def _explore_code(self):
        """Update locator metadata for the current projects"""

        self._code_locator.explore_code()

    def _explore_file_code(self, path):
        """Update locator metadata for the file in path"""

        self._code_locator.explore_file_code(path)

    def current_editor_changed(self, filename):
        """Notify the new filename of the current editor"""

        if filename is None:
            filename = translations.TR_NEW_DOCUMENT
        self.currentEditorChanged.emit(filename)

    def get_current_editor(self):
        current_widget = self.combo_area.current_editor()
        if isinstance(current_widget, editor.NEditor):
            return current_widget
        return None

    @property
    def last_opened_files(self):
        return self.__last_opened_files

    def _add_to_last_opened(self, nfile):
        MAX_RECENT_FILES = 10  # FIXME: configuration
        if nfile.is_new_file:
            return
        file_path = nfile.file_path
        if file_path in self.__last_opened_files:
            self.__last_opened_files.remove(file_path)
        self.__last_opened_files.insert(0, file_path)
        if len(self.__last_opened_files) > MAX_RECENT_FILES:
            self.__last_opened_files.pop(-1)

    def clear_last_opened_files(self):
        self.__last_opened_files.clear()

    def open_file(self, filename='', line=-1, col=0, ignore_checkers=False):
        if not filename:
            logger.debug("Has no filename")
            if settings.WORKSPACE:
                directory = settings.WORKSPACE
            else:
                directory = os.path.expanduser("~")
                editor_widget = self.get_current_editor()
                ninjaide = IDE.get_service("ide")
                current_project = ninjaide.get_current_project()
                # TODO: handle current project in NProject
                if current_project is not None:
                    directory = current_project.full_path
                elif editor_widget is not None and editor_widget.file_path:
                    directory = file_manager.get_folder(
                        editor_widget.file_path)
            filenames = QFileDialog.getOpenFileNames(
                self,
                translations.TR_OPEN_A_FILE,
                directory,
                settings.get_supported_extensions_filter(),
                initialFilter="Python files (*.py *.pyw)"
            )[0]
        else:
            logger.debug("Has filename")
            filenames = [filename]
        if not filenames:
            return
        for filename in filenames:
            image_extensions = ("png", "jpg", "jpeg", "bmp", "gif")
            if file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("Will open as image")
                self.open_image(filename)
            else:
                logger.debug("Will try to open: %s" % filename)
                self.__open_file(
                    filename, line, col, ignore_checkers=ignore_checkers)

    def __open_file(self, filename, line, col, ignore_checkers=False):
        try:
            self.add_editor(filename)
            if line != -1:
                self.editor_go_to_line(line, col)
            self.currentEditorChanged.emit(filename)
        except file_manager.NinjaIOException as reason:
            QMessageBox.information(
                self,
                translations.TR_OPEN_FILE_ERROR,
                str(reason))
            logger.error("The file %s couldn't be open" % filename)

    def open_image(self, filename):
        for index in range(self.combo_area.stacked.count()):
            widget = self.combo_area.stacked.widget(index)
            if isinstance(widget, image_viewer.ImageViewer):
                if widget.image_filename == filename:
                    logger.debug("Image already open")
                    self.combo_area._set_current(neditable=None, index=index)
                    return
        viewer = image_viewer.ImageViewer(filename)
        self.combo_area.add_image_viewer(viewer)
        self.stack.setCurrentWidget(self.splitter)

    def autosave_file(self):
        for neditable in self.combo_area.bar.get_editables():
            neditable.autosave_file()

    def save_file(self, editor_widget=None):
        if editor_widget is None:
            # This may return None if there is not editor present
            editor_widget = self.get_current_editor()
        if editor_widget is None:
            return False
        # Ok, we have an editor instance
        # Save to file only if editor really was modified
        if editor_widget.is_modified:
            try:
                if editor_widget.nfile.is_new_file or \
                        not editor_widget.nfile.has_write_permission():
                    return self.save_file_as(editor_widget)

                file_path = editor_widget.file_path
                # Emit signal before save
                self.beforeFileSaved.emit(file_path)
                if settings.REMOVE_TRAILING_SPACES:
                    editor_widget.remove_trailing_spaces()
                if settings.ADD_NEW_LINE_AT_EOF:
                    editor_widget.insert_block_at_end()
                # Save content
                editor_widget.neditable.save_content()
                # FIXME: encoding
                message = translations.TR_FILE_SAVED.format(file_path)
                self.fileSaved.emit(message)
                return True
            except Exception as reason:
                logger.error("Save file error: %s" % reason)
                QMessageBox.information(
                    self,
                    translations.TR_SAVE_FILE_ERROR_TITLE,
                    translations.TR_SAVE_FILE_ERROR_BODY
                )
            return False

    def save_file_as(self, editor_widget=None):
        force = False
        if editor_widget is None:
            # We invoque from menu
            editor_widget = self.get_current_editor()
            if editor_widget is None:
                # We haven't editor in main container
                return False
            force = True
        try:
            filters = "(*.py);;(*.*)"
            if editor_widget.file_path is not None:  # Existing file
                extension = file_manager.get_file_extension(
                    editor_widget.file_path)
                if extension != 'py':
                    filters = "(*.%s);;(*.py);;(*.*)" % extension
                save_folder = self._get_save_folder(editor_widget.file_path)
            else:
                save_folder = settings.WORKSPACE

            filename = QFileDialog.getSaveFileName(
                self,
                translations.TR_SAVE_FILE_DIALOG,
                save_folder,
                filters
            )[0]
            if not filename:
                return False
            # FIXME: remove trailing spaces
            extension = file_manager.get_file_extension(filename)
            if not extension:
                filename = "%s.%s" % (filename, "py")
            editor_widget.neditable.save_content(path=filename, force=force)
            # self._setter_language.set_language_from_extension(extension)
            self.fileSaved.emit(translations.TR_FILE_SAVED.format(filename))
            self.currentEditorChanged.emit(filename)
            return True
        except file_manager.NinjaFileExistsException as reason:
            QMessageBox.information(
                self,
                translations.TR_FILE_ALREADY_EXISTS_TITLE,
                translations.TR_FILE_ALREADY_EXISTS_BODY.format(
                    reason.filename)
            )
        except Exception as reason:
            logger.error("Save file as: %s", reason)
            QMessageBox.information(
                self,
                translations.TR_SAVE_FILE_ERROR_TITLE,
                translations.TR_SAVE_FILE_ERROR_BODY
            )
        return False

    def save_project(self, project_path):
        """Save all files in the project path"""
        for neditable in self.combo_area.bar.get_editables():
            file_path = neditable.file_path
            if file_path is None:
                # FIXME: New edited files will not be saved, its ok?
                continue
            if file_manager.belongs_to_folder(project_path, file_path):
                neditable.save_content()

    def _get_save_folder(self, filename):
        """Returns the root directory of the 'Main Project'
        or the home folder"""

        ninjaide = IDE.get_service("ide")
        current_project = ninjaide.get_current_project()
        if current_project is not None:
            return current_project.path
        return os.path.expanduser("~")

    def close_file(self):
        self.combo_area.close_current_file()

    def add_editor(self, filename=None):
        ninjaide = IDE.get_service("ide")
        editable = ninjaide.get_or_create_editable(filename)

        if editable.editor:
            # If already open
            logger.debug("%s is already open" % filename)
            self.combo_area.set_current(editable)
            return self.combo_area.current_editor()
        else:
            pass

        editor_widget = self.create_editor_from_editable(editable)
        # editor_widget.set_language()
        # Add the tab
        keep_index = (self.splitter.count() > 1 and
                      self.combo_area.stacked.count() > 0)
        self.combo_area.add_editor(editable, keep_index)
        # Emit a signal about the file open
        self.fileOpened.emit(filename)

        if keep_index:
            self.combo_area.set_current(editable)

        self.stack.setCurrentWidget(self.splitter)
        editor_widget.setFocus()
        return editor_widget

    def create_editor_from_editable(self, editable):
        neditor = editor.create_editor(editable)
        neditor.zoomChanged.connect(self._on_zoom_changed)
        neditor.addBackItemNavigation.connect(self.add_back_item_navigation)
        editable.fileSaved.connect(
            lambda neditable: self._explore_file_code(neditable.file_path))
        return neditor

    def add_back_item_navigation(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            item = (editor_widget.file_path, editor_widget.cursor_position)
            if item not in self.__code_back:
                self.__code_back.append(item)
                # self.__code_forward.clear()

    def _on_zoom_changed(self, zoom):
        text = "Zoom: {}%".format(str(zoom))
        ide = IDE.get_service("ide")
        ide.show_message(text)

    def add_widget(self, widget):
        self.stack.addWidget(widget)

    def show_start_page(self):
        """Show Start Page widget in main container"""

        startp = self.stack.widget(0)
        if isinstance(startp, start_page.StartPage):
            self.stack.setCurrentIndex(0)
        else:
            startp = start_page.StartPage(parent=self)
            startp.newFile.connect(self.add_editor)
            self.stack.insertWidget(0, startp)
            self.stack.setCurrentIndex(0)

    def _files_closed(self):
        if settings.SHOW_START_PAGE:
            self.show_start_page()

    def add_status_bar(self, status_bar):
        self._vbox.addWidget(status_bar)

    def create_file(self, base_path, project_path):
        self._add_file_folder.create_file(base_path, project_path)

    def create_folder(self, base_path, project_path):
        self._add_file_folder.create_folder(base_path, project_path)

    def restyle_editor(self):
        neditables = self.combo_area.bar.get_editables()
        for neditable in neditables:
            neditable.editor.restyle()

    def zoom_in_editor(self):
        """Increase the font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.zoom(1.)

    def zoom_out_editor(self):
        """Decrease the font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.zoom(-1.)

    def reset_zoom_editor(self):
        """Reset the to original font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.reset_zoom()

    def editor_move_up(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.move_up_down(up=True)

    def editor_move_down(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.move_up_down()

    def editor_duplicate_line(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.duplicate_line()

    def editor_toggle_comment(self):
        """Mark the current line or selection as a comment."""
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.comment_or_uncomment()

    def editor_go_to_line(self, line, column=0, center=True):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.go_to_line(line, column, center)
            editor_widget.setFocus()

    def _editor_settings_changed(self, key, value):
        key = key.split("/")[-1]
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            callback = getattr(editor.NEditor, key, False)
            if callback:
                callback = callback
                if not hasattr(callback, "__call__"):
                    # Property!
                    callback = callback.fset
                callback(editor_widget, value)

    def toggle_tabs_and_spaces(self):
        """Toggle Show/Hide Tabs and Spaces"""

        settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES
        qsettings = IDE.ninja_settings()
        qsettings.setValue('preferences/editor/showTabsAndSpaces',
                           settings.SHOW_TABS_AND_SPACES)
        neditor = self.get_current_editor()
        if neditor is not None:
            neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES

    def __navigate_with_keyboard(self, forward):
        """Navigate between the positions in the jump history stack."""
        operation = self.combo_area.bar.code_navigator.operation
        self.navigate_code_history(operation, forward)

    def navigate_back(self):
        self.__navigate_with_keyboard(forward=False)

    def navigate_forward(self):
        self.__navigate_with_keyboard(forward=True)
示例#14
0
class Main(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.magneto = magnetoGauge()
        self.magneto.initialize({'mag': {'value': 0}})

        self.switch = switchPanel()

        self.light = lightPanel()

        self.warn = warnPanel()

        self.radio = radioPanel()
        self.radio.initialize({})

        self.airspeed = airspeedGauge()

        self.accelerometer = accelerometerGauge()
        self.accelerometer.initialize({'load': {'value': 0}})

        self.attitude = attitudeGauge()
        self.attitude.initialize({'pitch': {'value': 0}, 'roll': {'value': 0}})

        self.altitude = altitudeGauge()
        self.altitude.initialize({'alt': {'value': 0}, 'baro': {'value': 0}})

        self.turnslip = turnslipGauge()
        self.turnslip.initialize({'turn': {'value': 0}, 'slip': {'value': 0}})

        self.dg = dgGauge()
        self.dg.initialize({'cap': {'value': 0}})

        self.vario = varioGauge()
        self.vario.initialize({'vvi': {'value': 0}})

        self.fuel = fuelGauge()
        self.fuel.initialize({'fuel': {'value': 0}})

        self.manifold = manifoldGauge()
        self.manifold.initialize({'man': {'value': 0}, 'flow': {'value': 0}})

        self.vacuum = vacuumGauge()
        self.vacuum.initialize({'vacuum': {'value': 0}})

        self.oil = oilGauge()
        self.oil.initialize({
            'heat': {
                'value': 0,
                'max': 250
            },
            'psi': {
                'value': 0,
                'max': 25
            }
        })

        self.vor = vorGauge()
        self.vor.initialize({
            'obs': {
                'value': 0
            },
            'tofr': {
                'value': 1
            },
            'dme': {
                'value': 0
            },
            'hdef': {
                'value': 0
            },
            'vdef': {
                'value': 0
            }
        })

        self.adf = adfGauge()
        self.adf.initialize({
            'frq': {
                'value': 0
            },
            'card': {
                'value': 0
            },
            'brg': {
                'value': 0
            }
        })

        self.engine = engineGauge()
        self.engine.initialize({'rpm': {'value': 0}})

        self.trim = trimGauge()
        self.trim.initialize({'pitch': {'value': 0}})

        self.ident = identPanel()

        self.debug = fsDebug(self)
        self.debug.keyPressEvent = self.keyPressEvent
        self.debug.appendText('debug initiated', 'info')
        self.debug.appendText('error test', 'error')

        self.stack = QStackedLayout(self)
        #print (self.stack.parent.vor.param)

        for i in range(NUM_LAYOUT):
            page = QWidget()
            layout = QGridLayout()
            page.setLayout(layout)
            self.stack.addWidget(page)
        self.setFSLayout(DEFAULT_LAYOUT)

        self.b = 0

    def keyPressEvent(self, event):
        key = event.key()
        if (key == Qt.Key_1):
            self.setFSLayout(1)
        elif (key == Qt.Key_2):
            self.setFSLayout(2)
        elif (key == Qt.Key_3):
            self.setFSLayout(3)
        elif (key == Qt.Key_4):
            self.setFSLayout(4)
        elif (key == Qt.Key_5):
            self.b = (self.b + 1) % 2
            self.switch.setValue({'power': self.b})
            self.light.setValue({'power': self.b})
            #self.warn.setValue({'power':self.b,'gene':1,'oil':1,'fuel':1,'gear':1})
        elif (key == Qt.Key_D):
            self.setFSLayout(0)
        elif (key == Qt.Key_Space):
            self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
        elif (key == Qt.Key_Q):
            self.close()
        elif (key == Qt.Key_7):
            self.setPanel(-1)
        elif (key == Qt.Key_9):
            self.setPanel(1)

        elif (key == Qt.Key_B):
            self.airspeed.setup({'unit': 'kt'})
        elif (key == Qt.Key_N):
            self.airspeed.setup({'unit': 'kmh'})

        elif (key == Qt.Key_C):
            self.light.setValue({'strobe': 1})
        elif (key == Qt.Key_U):
            self.socket.send("com", "outer", -1)
        elif (key == Qt.Key_I):
            self.socket.send("com", "outer", 1)
        elif (key == Qt.Key_O):
            self.socket.send("com", "inner", -1)
        elif (key == Qt.Key_P):
            self.socket.send("com", "inner", 1)
        elif (key == Qt.Key_K):
            self.socket.send("com", "button", 1)
        elif (key == Qt.Key_L):
            self.socket.send("nav", "coder", -1)
        elif (key == Qt.Key_M):
            self.socket.send("nav", "coder", 1)

    def setBackground(self, pic):
        palette = QPalette()
        pixmap = QPixmap(pic)
        brush = QBrush(pixmap)
        palette.setBrush(QPalette.Background, brush)
        self.setPalette(palette)

    def setPanel(self, direction):
        index = (self.activeLayout + direction) % NUM_LAYOUT
        if (index == 0):
            index = (index + direction) % NUM_LAYOUT
        self.setFSLayout(index)

    def setFSLayout(self, index):
        self.activeLayout = index
        #self.stack.setCurrentIndex(index)
        layout = self.stack.widget(index).layout()
        populateLayout(self, layout, index)
        self.stack.setCurrentIndex(index)

    def setUDPSocket(self, socket):

        self.socket = socket

        socket.switch.connect(self.switch.setValue)
        socket.light.connect(self.light.setValue)
        socket.warn.connect(self.warn.setValue)
        socket.radio.connect(self.radio.setValue)
        socket.airspeed.connect(self.airspeed.setValue)
        socket.load.connect(self.accelerometer.setValue)
        socket.attitude.connect(self.attitude.setValue)
        socket.altitude.connect(self.altitude.setValue)
        socket.turnslip.connect(self.turnslip.setValue)
        socket.dg.connect(self.dg.setValue)
        socket.vario.connect(self.vario.setValue)
        socket.vacuum.connect(self.vacuum.setValue)
        socket.flow.connect(self.manifold.setValue)
        socket.fuel.connect(self.fuel.setValue)
        socket.oil.connect(self.oil.setValue)
        socket.vor.connect(self.vor.setValue)
        socket.adf.connect(self.adf.setValue)
        socket.engine.connect(self.engine.setValue)
        socket.trim.connect(self.trim.setValue)
        socket.magneto.connect(self.magneto.setValue)

        socket.panel.connect(self.setPanel)
        socket.debug.connect(self.debug.appendText)
示例#15
0
class _MainContainer(QWidget):

    currentEditorChanged = pyqtSignal("QString")
    fileOpened = pyqtSignal("QString")
    fileSaved = pyqtSignal("QString")

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
        self._vbox = QVBoxLayout(self)
        self._vbox.setContentsMargins(0, 0, 0, 0)
        self._vbox.setSpacing(0)
        self.stack = QStackedLayout()
        self.stack.setStackingMode(QStackedLayout.StackAll)
        self._vbox.addLayout(self.stack)
        self.splitter = dynamic_splitter.DynamicSplitter()
        self._files_handler = files_handler.FilesHandler(self)

        # Code Navigation
        self.__operations = {
            0: self._navigate_bookmarks
        }
        # QML UI
        self._add_file_folder = add_file_folder.AddFileFolderWidget(self)

        if settings.SHOW_START_PAGE:
            self.show_start_page()

        IDE.register_service("main_container", self)
        # Register signals connections
        connections = (
            {
                "target": "main_container",
                "signal_name": "updateLocator",
                "slot": self._explore_code
            },
            {
                "target": "filesystem",
                "signal_name": "projectOpened",
                "slot": self._explore_code
            },
            {
                "target": "projects_explore",
                "signal_name": "updateLocator",
                "slot": self._explore_code
            }
        )

        IDE.register_signals("main_container", connections)

        esc_sort = QShortcut(QKeySequence(Qt.Key_Escape), self)
        esc_sort.activated.connect(self._set_focus_to_editor)

        # Added for set language
        self._setter_language = set_language.SetLanguageFile()

    def install(self):
        ninjaide = IDE.get_service("ide")
        ninjaide.place_me_on("main_container", self, "central", top=True)

        self.combo_area = combo_editor.ComboEditor(original=True)
        self.combo_area.allFilesClosed.connect(self._files_closed)
        self.splitter.add_widget(self.combo_area)
        self.add_widget(self.splitter)
        # self.current_widget = self.combo_area
        # Code Locator
        self._code_locator = locator_widget.LocatorWidget(ninjaide)

        ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide)

    def show_files_handler(self):
        self._files_handler.next_item()

    def navigate_code_history(self, operation, forward):
        self.__operations[operation](forward)

    def _navigate_bookmarks(self, forward=True):
        current_editor = self.get_current_editor()
        current_editor.navigate_bookmarks(forward=forward)

    def _set_focus_to_editor(self):
        status_bar = IDE.get_service("status_bar")
        tools_doock = IDE.get_service("tools_dock")
        editor_widget = self.get_current_editor()
        if status_bar.isVisible() and tools_doock.isVisible():
            status_bar.hide_status_bar()
        elif tools_doock.isVisible():
            tools_doock._hide()
        elif status_bar.isVisible():
            status_bar.hide_status_bar()
        if editor_widget is not None:
            editor_widget.clear_extra_selections('searchs')

    def split_assistance(self):
        split_widget = split_orientation.SplitOrientation(self)
        split_widget.show()

    def show_dialog(self, widget):
        self.add_widget(widget)
        self.stack.setCurrentWidget(widget)

    def show_split(self, orientation_vertical=False):
        orientation = Qt.Horizontal
        if orientation_vertical:
            orientation = Qt.Vertical
        self.combo_area.split_editor(orientation)

    def show_locator(self):
        """Show the Locator Widget"""

        if not self._code_locator.isVisible():
            self._code_locator.show()

    def _explore_code(self):
        """Update locator metadata for the current projects"""

        self._code_locator.explore_code()

    def current_editor_changed(self, filename):
        """Notify the new filename of the current editor"""

        if filename is None:
            filename = translations.TR_NEW_DOCUMENT
        self.currentEditorChanged.emit(filename)

    def get_current_editor(self):
        current_widget = self.combo_area.current_editor()
        if isinstance(current_widget, editor.NEditor):
            return current_widget
        return None

    def open_file(self, filename='', line=-1, col=0, ignore_checkers=False):
        logger.debug("Will try to open %s" % filename)
        if not filename:
            logger.debug("Has no filename")
            if settings.WORKSPACE:
                directory = settings.WORKSPACE
            else:
                directory = os.path.expanduser("~")
                editor_widget = self.get_current_editor()
                ninjaide = IDE.get_service("ide")
                current_project = ninjaide.get_current_project()
                # TODO: handle current project in NProject
                if current_project is not None:
                    directory = current_project.full_path
                elif editor_widget is not None and editor_widget.file_path:
                    directory = file_manager.get_folder(
                        editor_widget.file_path)
            filenames = QFileDialog.getOpenFileNames(
                self,
                "Open File",  # FIXME: translations
                directory,
                settings.get_supported_extensions_filter()
            )[0]
        else:
            logger.debug("Has filename")
            filenames = [filename]
        if not filenames:
            return
        for filename in filenames:
            image_extensions = ("png", "jpg", "jpeg", "bmp", "gif")
            if file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("Will open as image")
                self.open_image(filename)
            else:
                logger.debug("Will try to open: %s" % filename)
                self.__open_file(
                    filename, line, col, ignore_checkers=ignore_checkers)

    def __open_file(self, filename, line, col, ignore_checkers=False):
        try:
            editor_widget = self.add_editor(filename)
            if line != -1:
                editor_widget.go_to_line(line, col)
            self.currentEditorChanged.emit(filename)
        except file_manager.NinjaIOException as reason:
            QMessageBox.information(
                self,
                "The file couldn't be open",  # FIXME: translations
                str(reason))
            logger.error("The file %s couldn't be open" % filename)

    def open_image(self, filename):
        for index in range(self.combo_area.stacked.count()):
            widget = self.combo_area.stacked.widget(index)
            if isinstance(widget, image_viewer.ImageViewer):
                if widget.image_filename == filename:
                    logger.debug("Image already open")
                    self.combo_area._set_current(neditable=None, index=index)
                    return
        viewer = image_viewer.ImageViewer(filename)
        self.combo_area.add_image_viewer(viewer)
        self.stack.setCurrentWidget(self.splitter)

    def save_file(self, editor_widget=None):
        if editor_widget is None:
            # This may return None if there is not editor present
            editor_widget = self.get_current_editor()
        if editor_widget is None:
            return False
        # Ok, we have an editor instance
        # Save to file only if editor really was modified
        if editor_widget.is_modified:
            try:
                if editor_widget.nfile.is_new_file or \
                        not editor_widget.nfile.has_write_permission():
                    return self.save_file_as(editor_widget)
                # FIXME: beforeFileSaved.emit
                if settings.REMOVE_TRAILING_SPACES:
                    helpers.remove_trailing_spaces(editor_widget)
                # FIXME: new line at end
                if settings.ADD_NEW_LINE_AT_EOF:
                    helpers.insert_block_at_end(editor_widget)
                # Save content
                editor_widget.neditable.save_content()
                # FIXME: encoding
                # FIXME: translations
                self.fileSaved.emit("File Saved: %s" % editor_widget.file_path)
                return True
            except Exception as reason:
                logger.error("Save file error: %s" % reason)
                QMessageBox.information(
                    self,
                    "Save Error",
                    "The file could't be saved!"
                )
            return False

    def save_file_as(self, editor_widget=None):
        force = False
        if editor_widget is None:
            # We invoque from menu
            editor_widget = self.get_current_editor()
            if editor_widget is None:
                # We haven't editor in main container
                return False
            force = True
        try:
            filters = "(*.py);;(*.*)"
            if editor_widget.file_path is not None:  # Existing file
                extension = file_manager.get_file_extension(
                    editor_widget.file_path)
                if extension != 'py':
                    filters = "(*.%s);;(*.py);;(*.*)" % extension
            save_folder = self._get_save_folder(editor_widget.file_path)
            filename = QFileDialog.getSaveFileName(
                self, "Save File", save_folder, filters
            )[0]
            if not filename:
                return False
            # FIXME: remove trailing spaces
            extension = file_manager.get_file_extension(filename)
            if not extension:
                filename = "%s.%s" % (filename, "py")
            editor_widget.neditable.save_content(path=filename, force=force)
            self._setter_language.set_language_from_extension(extension)
            self.fileSaved.emit("File Saved: {}".format(filename))
            self.currentEditorChanged.emit(filename)
            return True
        except file_manager.NinjaFileExistsException as reason:
            QMessageBox.information(
                self, "File Already Exists",
                "Invalid Path: the file '%s' already exists." % reason.filename
            )
        except Exception as reason:
            logger.error("save_file_as: %s", reason)
            QMessageBox.information(
                self, "Save Error",
                "The file couldn't be saved!"
            )
        return False

    def save_project(self, project_path):
        """Save all files in the project path"""
        for neditable in self.combo_area.bar.get_editables():
            file_path = neditable.file_path
            if file_manager.belongs_to_folder(project_path, file_path):
                neditable.save_content()

    def _get_save_folder(self, filename):
        """Returns the root directory of the 'Main Project'
        or the home folder"""

        ninjaide = IDE.get_service("ide")
        current_project = ninjaide.get_current_project()
        if current_project is not None:
            return current_project.path
        return os.path.expanduser("~")

    def close_file(self):
        self.combo_area.close_current_file()

    def add_editor(self, filename=None):
        ninjaide = IDE.get_service("ide")
        editable = ninjaide.get_or_create_editable(filename)
        if editable.editor:
            # If already open
            logger.debug("%s is already open" % filename)
            self.combo_area.set_current(editable)
            return self.combo_area.current_editor()
        else:
            pass

        editor_widget = self.create_editor_from_editable(editable)
        # editor_widget.set_language()
        # Add the tab
        keep_index = (self.splitter.count() > 1 and
                      self.combo_area.stacked.count() > 0)
        self.combo_area.add_editor(editable, keep_index)
        # Emit a signal about the file open
        self.fileOpened.emit(filename)

        if not keep_index:
            self.combo_area.set_current(editable)

        self.stack.setCurrentWidget(self.splitter)
        editor_widget.setFocus()
        return editor_widget

    def create_editor_from_editable(self, editable):
        neditor = editor.create_editor(editable)
        neditor.zoomChanged.connect(self._show_zoom_indicator)
        neditor.destroyed.connect(self.__on_editor_destroyed)
        # editable.fileSaved.connect(self._editor_tab)
        return neditor

    def _show_zoom_indicator(self, zoom):
        neditor = self.get_current_editor()
        indicator.Indicator.show_text(
            neditor, "Zoom: {} %".format(str(zoom)))

    @pyqtSlot()
    def __on_editor_destroyed(self):
        indicator.Indicator.instance = None

    def add_widget(self, widget):
        self.stack.addWidget(widget)

    def show_start_page(self):
        """Show Start Page widget in main container"""

        startp = self.stack.widget(0)
        if isinstance(startp, start_page.StartPage):
            self.stack.setCurrentIndex(0)
        else:
            startp = start_page.StartPage(parent=self)
            startp.newFile.connect(self.add_editor)
            self.stack.insertWidget(0, startp)
            self.stack.setCurrentIndex(0)

    def _files_closed(self):
        if settings.SHOW_START_PAGE:
            self.show_start_page()

    def add_status_bar(self, status_bar):
        self._vbox.addWidget(status_bar)

    def create_file(self, base_path, project_path):
        self._add_file_folder.create_file(base_path, project_path)

    def create_folder(self, base_path, project_path):
        self._add_file_folder.create_folder(base_path, project_path)

    def zoom_in_editor(self):
        """Increase the font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.zoom(1.)

    def zoom_out_editor(self):
        """Decrease the font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.zoom(-1.)

    def reset_zoom_editor(self):
        """Reset the to original font size in the current editor"""

        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.reset_zoom()

    def editor_move_up(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.move_up_down(up=True)

    def editor_move_down(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.move_up_down()

    def editor_duplicate_line(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.duplicate_line()

    def editor_comment(self):
        """Mark the current line or selection as a comment."""
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            helpers.comment_or_uncomment(editor_widget)

    def editor_go_to_line(self, line):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.go_to_line(line)
            editor_widget.setFocus()

    def _editor_settings_changed(self, key, value):
        key = key.split("/")[-1]
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            callback = getattr(editor.NEditor, key, False)
            if callback:
                callback = callback
                if not hasattr(callback, "__call__"):
                    # Property!
                    callback = callback.fset
                callback(editor_widget, value)

    def toggle_tabs_and_spaces(self):
        """Toggle Show/Hide Tabs and Spaces"""

        settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES
        qsettings = IDE.ninja_settings()
        qsettings.setValue('preferences/editor/showTabsAndSpaces',
                           settings.SHOW_TABS_AND_SPACES)
        neditor = self.get_current_editor()
        if neditor is not None:
            neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES
示例#16
0
class ComboEditor(ui_tools.StyledBar):
    # Signals
    closeSplit = pyqtSignal('PyQt_PyObject')
    splitEditor = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject', bool)
    allFilesClosed = pyqtSignal()
    about_to_close_combo_editor = pyqtSignal()

    def __init__(self, original=False):
        super(ComboEditor, self).__init__(None)
        self.__original = original
        self.__undocked = []
        self._symbols_index = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(main_combo=original)
        vbox.addWidget(self.bar)

        # Info bar
        self.info_bar = InfoBar(self)
        self.info_bar.setVisible(False)
        vbox.addWidget(self.info_bar)

        self.stacked = QStackedLayout()
        vbox.addLayout(self.stacked)

        self._main_container = IDE.get_service('main_container')

        if not self.__original:
            self._main_container.fileOpened['QString'].connect(
                self._file_opened_by_main)

        # self.bar.combo.showComboSelector.connect(
        #    lambda: self._main_container.change_tab())
        self.bar.change_current['PyQt_PyObject',
                                int].connect(self._set_current)
        self.bar.splitEditor[bool].connect(self.split_editor)
        self.bar.runFile['QString'].connect(self._run_file)
        self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject['QString'].connect(self._add_to_project)
        self.bar.showFileInExplorer['QString'].connect(
            self._show_file_in_explorer)
        self.bar.goToSymbol[int].connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.reopenTab['QString'].connect(
            lambda path: self._main_container.open_file(path))

        # self.connect(self.bar, SIGNAL("recentTabsModified()"),
        #             lambda: self._main_container.recent_files_changed())
        # self.connect(self.bar.code_navigator.btnPrevious, SIGNAL("clicked()"),
        #             lambda: self._navigate_code(False))
        # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"),
        #             lambda: self._navigate_code(True))

    # def _navigate_code(self, val):
    #    op = self.bar.code_navigator.operation
    #    self._main_container.navigate_code_history(val, op)

    def currentWidget(self):
        return self.stacked.currentWidget()

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        self.stacked.currentWidget().setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stacked.currentIndex()
        ninjaide = IDE.get_service('ide')
        editable = ninjaide.get_or_create_editable(path)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original:
                editor = neditable.editor
            else:
                # editor = neditable.editor.clone()
                editor = self._main_container.create_editor_from_editable(
                    neditable)
            current_index = self.stacked.currentIndex()
            new_index = self.stacked.addWidget(editor)
            self.stacked.setCurrentIndex(new_index)
            self.bar.add_item(neditable.display_name, neditable)
            # Bar is not visible because all the files have been closed,
            # so if a new file is opened, show the bar
            if not self.bar.isVisible():
                self.bar.setVisible(True)
            if keep_index:
                self.bar.set_current_by_index(current_index)
            # Connections
            neditable.fileClosing.connect(self._close_file)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.modificationChanged.connect(self._editor_modified)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            # Connect file system signals only in the original
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)
            # Editor Signals
            editor.cursor_position_changed[int, int].connect(
                self._update_cursor_position)
            editor.current_line_changed[int].connect(self._set_current_symbol)
            """
            # self.connect(editor, SIGNAL("editorFocusObtained()"),
            #             self._editor_with_focus)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            neditable.fileSaved['PyQt_PyObject'].connect(
                self._update_combo_info)
            neditable.fileSaved['PyQt_PyObject'].connect(
                self._update_symbols)
            editor.modificationChanged[bool].connect(self._editor_modified)
            neditable.checkersUpdated.connect(self._show_notification_icon)

            # Connect file system signals only in the original
            neditable.fileClosing['PyQt_PyObject'].connect(self._close_file)
            if self.__original:
                neditable.askForSaveFileClosing['PyQt_PyObject'].connect(
                    self._ask_for_save)

                neditable.fileChanged['PyQt_PyObject'].connect(
                    self._file_has_been_modified)
                self.info_bar.reloadClicked.connect(neditable.reload_file)

            # Load Symbols
            self._load_symbols(neditable)
            """

    def show_combo_file(self):
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def unlink_editors(self):
        for index in range(self.stacked.count()):
            widget = self.stacked.widget(index)
            # widget.setDocument(QsciDocument())

    def split_editor(self, orientation_vertical):
        new_widget = ComboEditor()
        for neditable in self.bar.get_editables():
            new_widget.add_editor(neditable)
        self.splitEditor.emit(self, new_widget, orientation_vertical)
        # for neditable in self.bar.get_editables():
        #    new_widget.add_editor(neditable)
        # self.splitEditor.emit(self, new_widget, orientationVertical)
        # self.emit(SIGNAL("splitEditor(PyQt_PyObject, PyQt_PyObject, bool)"),
        #          self, new_widget, orientationVertical)

    def undock_editor(self):
        new_combo = ComboEditor()
        new_combo.setWindowTitle("NINJA-IDE")
        editor = self.currentWidget()
        new_combo.add_editor(editor.neditable)
        new_combo.show()
        """
        for neditable in self.bar.get_editables():
            new_combo.add_editor(neditable)
        neditor = self.currentWidget().clone()
        new_combo.set_current(neditor.neditable)
        new_combo.resize(700, 500)
        new_combo.about_to_close_combo_editor.connect(self._remove_undock)
        new_combo.show()
        """

    def _remove_undock(self):
        widget = self.sender()
        self.__undocked.remove(widget)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_file(self, neditable):
        index = self.bar.close_file(neditable)
        print(index)
        layoutItem = self.stacked.takeAt(index)
        # neditable.editor.completer.cc.unload_module()
        self._add_to_last_opened(neditable.file_path)
        layoutItem.widget().deleteLater()

        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()

    def _add_to_last_opened(self, path):
        if path not in settings.LAST_OPENED_FILES:
            settings.LAST_OPENED_FILES.append(path)
            if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS:
                self.__lastOpened = self.__lastOpened[1:]
            print("RecentTabsModified")
            # self.emit(SIGNAL("recentTabsModified()"))

    def _editor_with_focus(self):
        if self._main_container.current_widget is not self:
            self._main_container.current_widget = self
            editor = self.stacked.currentWidget()
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') % fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    def _file_has_been_modified(self, neditable):
        self.info_bar.show_message(translations.TR_FILE_MODIFIED_OUTSIDE)
        # val = QMessageBox.No
        # fileName = neditable.file_path
        # val = QMessageBox.question(
        #    self, translations.TR_FILE_HAS_BEEN_MODIFIED,
        #    "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE),
        #    QMessageBox.Yes | QMessageBox.No)
        # if val == QMessageBox.Yes:
        #    neditable.reload_file()

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''

        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        if neditable:
            self.stacked.setCurrentIndex(index)
            editor = self.stacked.currentWidget()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(neditable.file_path)
            self._load_symbols(neditable)
            # self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()

    def widget(self, index):
        return self.stacked.widget(index)

    def count(self):
        """Return the number of editors opened."""
        return self.stacked.count()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index)
                    or self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value):
        obj = self.sender()
        neditable = obj.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        # FIXME: index 0 invalid
        line = self._symbols_index[index]
        editor = self.stacked.currentWidget()
        editor.go_to_line(line)

    def _update_symbols(self, neditable):
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if editor == neditable.editor:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        symbols_handler = handlers.get_symbols_handler('py')
        source = neditable.editor.text
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(list(symbols_simplified.items()),
                                    key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.cursor_position
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                # FIXME: sucks
                else:
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        self.about_to_close_combo_editor.emit()
        # self.emit(SIGNAL("aboutToCloseComboEditor()"))
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
示例#17
0
文件: layout.py 项目: quekky/pyktv
class SelectorWindow(CommonWindow):
    """Selector window"""

    statustext = ''
    timer = QTimer()

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Selector")

        self.globalfont = QFont()
        self.fontcolor = settings.config['font.color']
        self.fontstylesheet = 'color: ' + self.fontcolor + ';'
        self.nosingerimage = QPixmap(settings.themeDir + 'default_singer.jpg')

        self.timer.timeout.connect(self.setOldStatusText)

        self.createLayout()

        geo = list(map(int, settings.config['selector.window'].split(',')))
        if settings.config.getboolean('selector.frameless'):
            self.setWindowFlag(Qt.FramelessWindowHint)
        self.move(geo[0], geo[1])
        self.show()
        self.resize(geo[2], geo[3])
        if settings.config.getboolean('selector.fullscreen'):
            self.setWindowState(Qt.WindowFullScreen)

    def createLayout(self):
        # background image
        self.bglabel = QLabel()
        self.bglabel.setScaledContents(True)
        self.bglabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.bglabel.setPixmap(QPixmap(settings.themeDir + 'selector.jpg'))
        self.bglayout = setZeroMargins(QHBoxLayout(self))
        self.bglayout.addWidget(self.bglabel)

        # create the vertical frame
        self.vlayout = setZeroMargins(QVBoxLayout(self.bglabel))

        # create the header toolbar
        self.headerlayout = setZeroMargins(QHBoxLayout())
        self.headeroption = []

        self.homeoption = QLabelButton()
        self.homeoption.clicked.connect(screen.startHomeScreen)
        self.homeoption.setScaledContents(True)
        self.homeoption.setPixmap(
            QPixmap(settings.themeDir + 'buttons/home.png'))
        self.headeroption.append(self.homeoption)
        self.backoption = QLabelButton()
        self.backoption.setScaledContents(True)
        self.backoption.setPixmap(
            QPixmap(settings.themeDir + 'buttons/arrow-left.png'))
        self.headeroption.append(self.backoption)

        self.switchchannel = QLabelButton()
        self.switchchannel.clicked.connect(playlist.switchChannel)
        self.switchchannel.setScaledContents(True)
        self.switchchannel.setPixmap(
            QPixmap(settings.themeDir + 'buttons/music.png'))
        self.headeroption.append(self.switchchannel)
        self.playnextsong = QLabelButton()
        self.playnextsong.clicked.connect(playlist.playNextSong)
        self.playnextsong.setScaledContents(True)
        self.playnextsong.setPixmap(
            QPixmap(settings.themeDir + 'buttons/step-forward.png'))
        self.headeroption.append(self.playnextsong)
        self.pitchup = QLabelButton()
        self.pitchup.clicked.connect(playlist.setPitchUp)
        self.pitchup.setText('♭')
        self.headeroption.append(self.pitchup)
        self.pitchflat = QLabelButton()
        self.pitchflat.clicked.connect(playlist.setPitchFlat)
        self.pitchflat.setText('♮')
        self.headeroption.append(self.pitchflat)
        self.pitchdown = QLabelButton()
        self.pitchdown.clicked.connect(playlist.setPitchDown)
        self.pitchdown.setText('♯')
        self.headeroption.append(self.pitchdown)

        for opt in self.headeroption:
            opt.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
            opt.setAlignment(Qt.AlignCenter)
            opt.setStyleSheet(
                'color: white; font-weight: 800; border-radius: 3px; background-color: rgba(120, 120, 120, 40);'
            )

        self.headerlayout.addStretch(2)
        self.headerlayout.addWidget(self.homeoption, 4)
        self.headerlayout.addStretch(2)
        self.headerlayout.addWidget(self.backoption, 4)
        self.headerlayout.addStretch(100)
        self.headerlayout.addWidget(self.playnextsong, 4)
        self.headerlayout.addStretch(2)
        self.headerlayout.addWidget(self.switchchannel, 4)
        self.headerlayout.addStretch(5)
        self.headerlayout.addWidget(self.pitchup, 4)
        self.headerlayout.addStretch(2)
        self.headerlayout.addWidget(self.pitchflat, 4)
        self.headerlayout.addStretch(2)
        self.headerlayout.addWidget(self.pitchdown, 4)
        self.headerlayout.addStretch(2)

        # create the function buttons
        self.functionlayout = setZeroMargins(QHBoxLayout())
        self.functionoption = []
        self.functionlayout.addStretch(30)
        for i in range(4):
            self.functionoption.append(QLabelListButton())
            self.functionoption[i].setSizePolicy(QSizePolicy.Ignored,
                                                 QSizePolicy.Ignored)
            self.functionoption[i].setLabelText('F' + str(i + 1))
            self.functionoption[i].index = "F" + str(i + 1)
            self.functionlayout.addWidget(self.functionoption[i], 100)
            self.functionlayout.addStretch(20)
        self.functionlayout.addStretch(10)

        # create the content area, with 2 stacks
        self.contentoption = [[], []]
        self.contentlayout = []
        self.stackedlayout = QStackedLayout()
        for i in range(2):
            self.stackedlayout.addWidget(QLabel())

        # create 1st page of content (10 options vertically align)
        self.vcontentlayout1 = setZeroMargins(
            QHBoxLayout(self.stackedlayout.widget(0)))
        self.contentlayout.append(setZeroMargins(QVBoxLayout()))
        for i in range(10):
            btn = QLabelListButton()
            self.contentoption[0].append(btn)
            btn.setLabelText(str((i + 1) % 10))
            btn.index = i
            self.contentlayout[0].addWidget(btn)
        self.vcontentlayout1.addStretch(1)
        self.vcontentlayout1.addLayout(self.contentlayout[0], 10)
        self.vcontentlayout1.addStretch(1)

        # create 2nd page of content (10 image options in 5x2)
        self.vcontentlayout2 = setZeroMargins(
            QHBoxLayout(self.stackedlayout.widget(1)))
        self.contentlayout.append(
            setZeroMargins(QGridLayout(self.stackedlayout.widget(1))))
        for i in range(10):
            btn = QLabeImageButton()
            self.contentoption[1].append(btn)
            btn.setLabelText(str((i + 1) % 10))
            btn.index = i
            self.contentlayout[1].addWidget(btn, i / 5, i % 5)
        self.vcontentlayout2.addStretch(1)
        self.vcontentlayout2.addLayout(self.contentlayout[1], 15)
        self.vcontentlayout2.addStretch(1)

        self.stackedlayout.setCurrentIndex(1)

        # create footer
        self.footerlayout = setZeroMargins(QHBoxLayout())

        self.pageroption = QLabel()
        self.pageroption.setSizePolicy(QSizePolicy.Ignored,
                                       QSizePolicy.Ignored)
        self.pageroption.setStyleSheet(self.fontstylesheet)
        self.pageroption.setAlignment(Qt.AlignCenter)

        #pageup/pagedown
        self.footeroption = [QLabelButton(), QLabelButton()]
        for opt in self.footeroption:
            opt.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
            opt.setAlignment(Qt.AlignCenter)
            opt.setStyleSheet(self.fontstylesheet)

        self.footerlayout.addStretch(50)
        self.footerlayout.addWidget(self.footeroption[0], 10)
        self.footerlayout.addStretch(10)
        self.footerlayout.addWidget(self.pageroption, 20)
        self.footerlayout.addStretch(10)
        self.footerlayout.addWidget(self.footeroption[1], 10)
        self.footerlayout.addStretch(50)

        # status bar
        self.statusframe = QMarquee()
        self.statusframe.setFontColor(self.fontcolor)

        # add contents to vlayout
        self.vlayout.addStretch(3)
        self.vlayout.addLayout(self.headerlayout, 12)
        self.vlayout.addStretch(10)
        self.vlayout.addLayout(self.functionlayout, 15)
        self.vlayout.addStretch(5)
        self.vlayout.addLayout(self.stackedlayout, 200)
        self.vlayout.addStretch(5)
        self.vlayout.addLayout(self.footerlayout, 15)
        self.vlayout.addStretch(10)
        self.vlayout.addWidget(self.statusframe, 20)

        # done
        self.createSearchLayout()

    def setTextSize(self):
        """resize text size to label height"""
        self.globalfont.setPixelSize(self.headeroption[0].size().height())
        for option in self.headeroption:
            option.setFont(self.globalfont)
        self.globalfont.setPixelSize(self.functionoption[0].size().height() *
                                     0.7)
        for option in self.functionoption:
            option.setFont(self.globalfont)
        self.contentlayout[0].setSpacing(self.size().height() * 0.01)
        self.contentlayout[1].setSpacing(self.size().height() * 0.03)
        self.globalfont.setPixelSize(self.contentoption[0][0].size().height() *
                                     0.4)
        for option in self.contentoption[0]:
            option.setFont(self.globalfont)
        self.globalfont.setPixelSize(self.pageroption.size().height() * 0.7)
        self.pageroption.setFont(self.globalfont)
        for option in self.footeroption:
            option.setFont(self.globalfont)
        self.statusframe.setPixelSize(self.statusframe.size().height() * 0.7)

        if self.searchbg.isVisible():
            self.setSearchTextSize()

    """
    search functions
    """

    insearch = False
    numstylesheet = '<span style="color:#999999">'
    search_display = {
        0:
        [[
            'EN',
            ('1', 'ABC2', 'DEF3', 'GHI4', 'JKL5', 'MNO6', 'PQRS7', 'TUV8',
             'WXYZ9', '0')
        ],
         [
             'JP',
             (numstylesheet + '1:</span> あ', numstylesheet + '2:</span> か',
              numstylesheet + '3:</span> さ', numstylesheet + '4:</span> た',
              numstylesheet + '5:</span> な', numstylesheet + '6:</span> は',
              numstylesheet + '7:</span> ま', numstylesheet + '8:</span> や',
              numstylesheet + '9:</span> ら', numstylesheet + '0:</span> わ')
         ],
         [
             'KR',
             (numstylesheet + '1:</span> ㅣ', numstylesheet + '2:</span> ㆍ',
              numstylesheet + '3:</span> ㅡ', numstylesheet + '4:</span> ㄱㅋ',
              numstylesheet + '5:</span> ㄴㄹ', numstylesheet + '6:</span> ㄷㅌ',
              numstylesheet + '7:</span> ㅂㅍ', numstylesheet + '8:</span> ㅅㅎ',
              numstylesheet + '9:</span> ㅈㅊ', numstylesheet + '0:</span> ㅇㅁ')
         ]],
        1: [['NUM', ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')]]
    }
    search_keyboard = {
        0:
        [[
            'EN',
            ('1', 'ABC2', 'DEF3', 'GHI4', 'JKL5', 'MNO6', 'PQRS7', 'TUV8',
             'WXYZ9', '0')
        ],
         [
             'JP',
             ('あいうえおぁぃぅぇぉ', 'かきくけこ', 'さしすせそ', 'たちつてとっ', 'なにぬねの', 'はひふへほ',
              'まみむめも', 'やゆよゃゅょ', 'らりるれろ', 'わゐゑを')
         ],
         ['KR', ('', '', '', 'ㄱㅋㄲ', 'ㄴㄹ', 'ㄷㅌㄸ', 'ㅂㅍㅃ', 'ㅅㅎㅆ', 'ㅈㅊㅉ', 'ㅇㅁ')]],
        1: [['NUM', ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')]]
    }
    searchtype = 0
    searchindex = 0
    searchlastkey = [-1, 0]
    searchstring = ''
    searchthreshold = 2
    searchtimer = QTimer()
    searchcallback = None
    search_hangul = Hangul()

    def createSearchLayout(self):
        fontstylesheet = self.fontstylesheet
        btnstylesheet='color: white; border-radius: 5px;' + \
            'background-color: qradialgradient(spread:pad, cx:0.272, cy:0.354515, radius:0.848, fx:0.071, fy:0.199045, stop:0 rgba(130, 130, 130, 255), stop:0.2 rgba(101, 101, 101, 255), stop:1 rgba(27, 27, 27, 170));' + \
            'border: 1px solid #858585;border-right: 1px solid #414141;border-bottom: solid 3px #414141;'

        self.searchbg = QLabel(self)
        self.searchbg.setCursor(Qt.WaitCursor)

        self.searchbglayout = setZeroMargins(QGridLayout(self.searchbg))
        self.searchframe = QLabel()
        self.searchframe.setScaledContents(True)
        self.searchframe.setSizePolicy(QSizePolicy.Ignored,
                                       QSizePolicy.Ignored)
        self.searchimage = QPixmap(settings.themeDir + "search.jpg")
        self.searchframe.setCursor(Qt.ArrowCursor)
        self.searchframe.setPixmap(self.searchimage)
        self.searchbglayout.addWidget(QWidget(), 0, 1)
        self.searchbglayout.addWidget(QWidget(), 1, 0)
        self.searchbglayout.addWidget(QWidget(), 2, 1)
        self.searchbglayout.addWidget(QWidget(), 3, 0)
        self.searchbglayout.addWidget(self.searchframe, 1, 1)
        self.searchbglayout.setColumnStretch(0, 70)
        self.searchbglayout.setColumnStretch(1, 40)
        self.searchbglayout.setColumnStretch(2, 1)
        self.searchbglayout.setRowStretch(0, 3)
        self.searchbglayout.setRowStretch(1, 4)
        self.searchbglayout.setRowStretch(2, 1)

        self.searchlayout = QGridLayout(self.searchframe)
        self.searchlayout.setSpacing(10)

        # title
        self.searchtitle = QLabel()
        self.searchtitle.setSizePolicy(QSizePolicy.Ignored,
                                       QSizePolicy.Ignored)
        self.searchtitle.setStyleSheet(fontstylesheet + ';font:bold;')
        self.searchtitle.setText(_("Search character:"))
        self.searchlayout.addWidget(self.searchtitle, 0, 0, 1, 2)

        # F1 to F4
        f_text = (_('F1: Ok'), _('F2: Del'), _('F3: Cancel'), _('F4: 🌐'))
        self.searchfunctionoption = []
        #create a filler "F4"
        for i in range(4):
            self.searchfunctionoption.append(QLabelButton())
            self.searchfunctionoption[i].setSizePolicy(QSizePolicy.Ignored,
                                                       QSizePolicy.Ignored)
            self.searchfunctionoption[i].setText(f_text[i])
            self.searchfunctionoption[i].setStyleSheet(btnstylesheet)
            self.searchfunctionoption[i].setAlignment(Qt.AlignCenter)
            self.searchfunctionoption[i].index = "F" + str(i + 1)
            self.searchfunctionoption[i].clicked.connect(
                self.searchButtonPressedFunction)
        for i in range(3):
            self.searchlayout.addWidget(self.searchfunctionoption[i], 1, i)
        self.searchlayout.addWidget(self.searchfunctionoption[3], 0, 2)

        # display text
        self.searchlabel = QLabel()
        self.searchlabel.setSizePolicy(QSizePolicy.Ignored,
                                       QSizePolicy.Ignored)
        self.searchlabel.setStyleSheet(
            fontstylesheet + "; padding: 0 10%; border: 1px solid blue;")
        self.searchlabel.setStyleSheet(
            self.fontstylesheet +
            'border: 3px solid black; border-radius: 5px; background-color: qlineargradient(spread:pad, x1:0, x2:1, stop:0 rgba(0, 0, 0, 200), stop:1 rgba(120, 120, 120, 100));padding: 0px 10%;'
        )
        self.searchlayout.addWidget(self.searchlabel, 2, 0, 1, 3)

        # 0 -9
        self.searchcontentoption = []
        for i in range(10):
            self.searchcontentoption.append(QLabelButton())
            self.searchcontentoption[i].setSizePolicy(QSizePolicy.Ignored,
                                                      QSizePolicy.Ignored)
            self.searchcontentoption[i].setStyleSheet(btnstylesheet)
            self.searchcontentoption[i].setAlignment(Qt.AlignCenter)
            self.searchcontentoption[i].index = i
            self.searchcontentoption[i].clicked.connect(
                self.searchButtonPressedNumber)
        for i in range(9):
            self.searchlayout.addWidget(self.searchcontentoption[i], 3 + i / 3,
                                        i % 3)
        self.searchlayout.addWidget(self.searchcontentoption[9], 6, 1)

        # backspace
        self.searchbackspaceoption = QLabelButton()
        self.searchbackspaceoption.setSizePolicy(QSizePolicy.Ignored,
                                                 QSizePolicy.Ignored)
        self.searchbackspaceoption.setStyleSheet(btnstylesheet)
        self.searchbackspaceoption.setAlignment(Qt.AlignCenter)
        self.searchbackspaceoption.setText("🡄")
        self.searchbackspaceoption.clicked.connect(
            self.searchButtonPressedBackspace)
        # self.searchlayout.addWidget(self.searchbackspaceoption, 6, 0)

        # enter
        self.searchenteroption = QLabelButton()
        self.searchenteroption.setSizePolicy(QSizePolicy.Ignored,
                                             QSizePolicy.Ignored)
        self.searchenteroption.setStyleSheet(btnstylesheet)
        self.searchenteroption.setAlignment(Qt.AlignCenter)
        self.searchenteroption.setText("[Enter]")
        self.searchenteroption.clicked.connect(self.searchButtonPressedEnter)
        # self.searchlayout.addWidget(self.searchenteroption, 6, 2)

        self.searchbg.hide()

        self.searchtimer.setSingleShot(True)
        self.searchtimer.setInterval(self.searchthreshold * 1000)
        self.searchtimer.timeout.connect(self.searchButtonPressedTimeout)

    def setSearchTextSize(self):
        self.globalfont.setPixelSize(
            self.searchfunctionoption[0].size().height() * 0.7)
        for option in self.searchfunctionoption:
            option.setFont(self.globalfont)
        self.globalfont.setPixelSize(
            self.searchcontentoption[0].size().height() * 0.7)
        for option in self.searchcontentoption:
            option.setFont(self.globalfont)
        self.searchbackspaceoption.setFont(self.globalfont)
        self.searchenteroption.setFont(self.globalfont)
        self.globalfont.setPixelSize(self.searchtitle.size().height() * 0.9)
        self.searchtitle.setFont(self.globalfont)
        self.globalfont.setPixelSize(self.searchlabel.size().height() * 0.7)
        self.searchlabel.setFont(self.globalfont)

    def setSearchPos(self):
        if self.searchbg.isVisible():
            self.searchbg.setFixedSize(self.width(), self.height())

    def displaySearchNumbers(self):
        for i in range(10):
            self.searchcontentoption[i].setText(
                self.search_display[self.searchtype][self.searchindex][1][i])

    def startSearch(self, searchtype=0):
        """display the search bar

        searchtype:
            0=alphanumeric
            1=numbers only
        """
        self.insearch = True
        self.searchstring = ''
        self.searchtype = searchtype
        self.searchindex = 0
        self.search_hangul = Hangul()

        if len(self.search_keyboard[self.searchtype]) > 1:
            self.searchfunctionoption[3].show()
        else:
            self.searchfunctionoption[3].hide()

        self.displaySearchNumbers()
        self.searchbg.show()
        self.setSearchPos()
        self.setSearchTextSize()
        self.searchTextDisplay()
        self.callSearchCallback()

    def stopSearch(self):
        self.insearch = False
        self.searchbg.hide()

    def searchGetFinalString(self):
        searchstring = self.searchstring
        if self.searchlastkey[0] == -2:
            searchstring += self.search_hangul.getHangul()
        elif 0 <= self.searchlastkey[0] < 10:
            searchstring += self.search_keyboard[self.searchtype][
                self.searchindex][1][self.searchlastkey[0]][
                    self.searchlastkey[1]]
        return searchstring

    def setSearchCallback(self, callback):
        self.searchcallback = callback

    def callSearchCallback(self):
        if callable(self.searchcallback):
            self.searchcallback(self.searchGetFinalString())

    def searchTextDisplay(self):
        searchstring = ' '.join(self.searchGetFinalString())
        if self.searchlastkey[0] != -1:
            searchstring = searchstring[:
                                        -1] + '<font color="cyan">' + searchstring[
                                            -1] + '</font>'
        self.searchlabel.setText(searchstring)

    @pyqtSlot(object)
    def searchKeyPressedAlpha(self, char):
        #A to Z only
        if 65 <= ord(char[0]) <= 90:
            self.searchButtonPressedTimeout()
            self.searchstring += char[0]
            self.searchTextDisplay()
            self.callSearchCallback()

    def searchKoreanNumber(self, index):
        self.searchlastkey = [-2, 0]
        if 0 <= index <= 2:  # Vowels
            if self.search_hangul.step == 2:
                self.searchstring += self.search_hangul.getHangul(1)
                self.search_hangul.chosung = self.search_hangul.jongsung
                self.search_hangul.jungsung = self.search_hangul.jongsung = self.search_hangul.jongsung2 = ""
            elif self.search_hangul.step == 3:
                self.searchstring += self.search_hangul.getHangul(2)
                self.search_hangul.chosung = self.search_hangul.jongsung2
                self.search_hangul.jungsung = self.search_hangul.jongsung = self.search_hangul.jongsung2 = ""

            beforedata = self.search_hangul.jungsung
            self.search_hangul.step = 1
            self.search_hangul.searchlastkey = [-1, 0]

            if index == 0:  # ㅣ ㅓ ㅕ ㅐ ㅔ ㅖ ㅒ ㅚ ㅟ ㅙ ㅝ ㅞ ㅢ
                if beforedata == "ㆍ": nowdata = "ㅓ"
                elif beforedata == ":": nowdata = "ㅕ"
                elif beforedata == "ㅏ": nowdata = "ㅐ"
                elif beforedata == "ㅑ": nowdata = "ㅒ"
                elif beforedata == "ㅓ": nowdata = "ㅔ"
                elif beforedata == "ㅕ": nowdata = "ㅖ"
                elif beforedata == "ㅗ": nowdata = "ㅚ"
                elif beforedata == "ㅜ": nowdata = "ㅟ"
                elif beforedata == "ㅠ": nowdata = "ㅝ"
                elif beforedata == "ㅘ": nowdata = "ㅙ"
                elif beforedata == "ㅝ": nowdata = "ㅞ"
                elif beforedata == "ㅡ": nowdata = "ㅢ"
                else:
                    nowdata = "ㅣ"
            elif index == 1:  # ㆍ : ㅏ ㅑ ㅜ ㅠ ㅘ
                if beforedata == "ㆍ": nowdata = ":"
                elif beforedata == ":": nowdata = "ㆍ"
                elif beforedata == "ㅣ": nowdata = "ㅏ"
                elif beforedata == "ㅏ": nowdata = "ㅑ"
                elif beforedata == "ㅡ": nowdata = "ㅜ"
                elif beforedata == "ㅜ": nowdata = "ㅠ"
                elif beforedata == "ㅚ": nowdata = "ㅘ"
                else:
                    nowdata = "ㆍ"
            elif index == 2:  # ㅡ ㅗ ㅛ
                if beforedata == "ㆍ": nowdata = "ㅗ"
                elif beforedata == ":": nowdata = "ㅛ"
                else:
                    nowdata = "ㅡ"

            self.search_hangul.jungsung = nowdata

        elif 3 <= index <= 9:  # Consonants
            if self.search_hangul.step == 1:
                if self.search_hangul.jungsung == "ㆍ" or self.search_hangul.jungsung == ":":
                    self.search_hangul = Hangul()
                else:
                    self.search_hangul.step = 2

            if index == self.search_hangul.searchlastkey[0]:
                self.search_hangul.searchlastkey[1] = (
                    self.search_hangul.searchlastkey[1] + 1) % len(
                        self.search_keyboard[self.searchtype][
                            self.searchindex][1][index])
            else:
                self.search_hangul.searchlastkey = [index, 0]
                if self.search_hangul.step == 2 and self.search_hangul.jongsung:
                    self.search_hangul.step = 3
                elif self.search_hangul.step == 3:
                    self.searchstring += self.search_hangul.getHangul()
                    self.search_hangul = Hangul()

            nowdata = self.search_keyboard[self.searchtype][self.searchindex][
                1][index][self.search_hangul.searchlastkey[1]]
            if self.search_hangul.step == 0:
                self.search_hangul.chosung = nowdata
            elif self.search_hangul.step == 2:
                self.search_hangul.jongsung = nowdata
            elif self.search_hangul.step == 3:
                self.search_hangul.jongsung2 = nowdata

    def searchFindFromKeyboard(self, index):
        if 0 <= index < 10:
            if len(self.search_keyboard[self.searchtype][self.searchindex][1]
                   [index]) == 1:
                self.searchstring += str(self.search_keyboard[self.searchtype][
                    self.searchindex][1][index])
            else:
                if index == self.searchlastkey[0]:
                    self.searchlastkey[1] = (self.searchlastkey[1] + 1) % len(
                        self.search_keyboard[self.searchtype][
                            self.searchindex][1][index])
                else:
                    if self.searchlastkey[0] != -1:
                        self.searchstring = self.searchGetJoinString()
                    self.searchlastkey = [index, 0, '']

    @pyqtSlot(object)
    def searchButtonPressedNumber(self, index):
        try:
            self.searchtimer.stop()
            if self.search_keyboard[self.searchtype][
                    self.searchindex][0] == 'KR':
                self.searchKoreanNumber(index)
            else:
                self.searchFindFromKeyboard(index)
            self.searchtimer.start()
        except:
            settings.logger.printException()
        self.searchTextDisplay()
        self.callSearchCallback()

    @pyqtSlot()
    def searchButtonPressedTimeout(self):
        self.searchtimer.stop()
        if self.searchlastkey[0] != -1:
            self.searchstring = self.searchGetFinalString()
            self.searchlastkey = [-1, 0, '']
            self.search_hangul = Hangul()
            self.searchTextDisplay()

    @pyqtSlot(object)
    def searchButtonPressedFunction(self, index):
        if index == 'F1':
            self.searchenteroption.click()
        elif index == 'F2':
            self.searchbackspaceoption.click()
        elif index == 'F3':
            self.searchstring = ''
            self.searchlastkey = [-1, 0, '']
            self.searchenteroption.click()
        elif index == 'F4':
            self.searchButtonPressedTimeout()
            self.searchindex = (self.searchindex + 1) % len(
                self.search_keyboard[self.searchtype])
            self.displaySearchNumbers()

    @pyqtSlot(object)
    def searchButtonPressedBackspace(self, index):
        self.searchtimer.stop()
        if self.searchlastkey[0] == -2:
            if self.search_hangul.step == 0:
                self.search_hangul = Hangul()
                self.searchlastkey = [-1, 0]
            else:
                self.search_hangul.step -= 1
                self.search_hangul.searchlastkey = [-1, 0]
                if self.search_hangul.step <= 2:
                    self.search_hangul.jongsung2 = ''
                if self.search_hangul.step <= 1:
                    self.search_hangul.jongsung = ''
                if self.search_hangul.step <= 0:
                    self.search_hangul.jungsung = ''
                # if delete vowel and no leading consonant
                if self.search_hangul.step == 0 and not self.search_hangul.chosung:
                    self.searchlastkey = [-1, 0]
                self.searchtimer.start()
        elif self.searchlastkey[0] != -1:
            self.searchlastkey = [-1, 0, '']
        else:
            self.searchstring = self.searchstring[:-1]
        self.searchTextDisplay()
        self.callSearchCallback()

    @pyqtSlot(object)
    def searchButtonPressedEnter(self, index):
        self.searchButtonPressedTimeout()
        self.stopSearch()
        self.callSearchCallback()

    def resizeEvent(self, QResizeEvent):
        super().resizeEvent(QResizeEvent)
        self.setSearchPos()
        self.setTextSize()

    def gotoPage(self, u_int):
        self.stackedlayout.setCurrentIndex(u_int)
        self.setTextSize()

    def setHeaders(self, options):
        for i, option in enumerate(self.functionoption):
            try:
                option.clicked.disconnect()
            except:
                pass
            if i in options.keys():
                try:
                    option.setText(options[i]['text'])
                    if callable(options[i]['func']):
                        option.clicked.connect(options[i]['func'])
                except:
                    settings.logger.printException()
            else:
                option.setText('')

    def setFooters(self, options):
        for i, option in enumerate(self.footeroption):
            try:
                option.clicked.disconnect()
            except:
                pass
            if i in options.keys():
                try:
                    option.setText(options[i]['text'])
                    if callable(options[i]['func']):
                        option.clicked.connect(options[i]['func'])
                except:
                    settings.logger.printException()
            else:
                option.setText('')
        if 'pagertext' in options.keys():
            self.pageroption.setText(options['pagertext'])
        else:
            self.pageroption.setText('')

    def setContents(self, screenNum, options):
        if 0 <= screenNum <= 1:
            self.gotoPage(screenNum)
            for i, option in enumerate(self.contentoption[screenNum]):
                try:
                    option.clicked.disconnect()
                except:
                    pass
                if i in options.keys():
                    try:
                        option.setText(options[i]['text'])
                        if callable(options[i]['func']):
                            option.clicked.connect(options[i]['func'])
                            option.connect = options[i]['func']
                        altimage = self.nosingerimage if type(
                            option) == QLabeImageButton else None
                        try:
                            option.setImage(options[i]['image'], altimage)
                        except:
                            option.setPixmap(altimage)
                    except:
                        settings.logger.printException()
                else:
                    option.setText('')
                    if callable(option.clearPixmap):
                        option.clearPixmap()

    def setBackCallback(self, backcallback):
        try:
            self.backoption.clicked.disconnect()
        except:
            pass
        try:
            if callable(backcallback):
                self.backoption.clicked.connect(backcallback)
        except:
            settings.logger.printException()

    def setStatusText(self, p_str):
        self.statustext = p_str
        if not self.timer.isActive():
            self.statusframe.setText(p_str)

    def setStatusTempText(self, p_str, msec):
        if self.timer.isActive():
            self.timer.stop()
        self.timer.setSingleShot(True)
        self.timer.start(msec)

        self.statusframe.setText(p_str)
        self.statusframe.x = 0
        self.statusframe.paused = True
        self.statusframe.repaint()

    @pyqtSlot()
    def setOldStatusText(self):
        self.statusframe.setText(self.statustext)
        self.statusframe.paused = False
示例#18
0
class ComboEditor(QDialog):
    
    closeSplit = pyqtSignal(QWidget)#closeSplit
    allFilesClosed = pyqtSignal()
    splitEditor = pyqtSignal("QWidget*", "QWidget*", bool)
    recentTabsModified = pyqtSignal()
    aboutToCloseComboEditor = pyqtSignal()

    class NAVIGATE:
        prev = 0
        next = 1

    Q_ENUMS(NAVIGATE)

    def __init__(self, original=False):
        super(ComboEditor, self).__init__(None, Qt.WindowStaysOnTopHint)
        self.__original = original
        self.__undocked = []
        self._symbols_index = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(main_combo=original)
        vbox.addWidget(self.bar)

        self.stacked = QStackedLayout()
        vbox.addLayout(self.stacked)

        self._main_container = IDE.get_service('main_container')

        if not self.__original:
            self._main_container.fileOpened.connect(self._file_opened_by_main)

        self.bar.combo.showComboSelector.connect(self._main_container.change_tab)
        self.bar.changeCurrent.connect(self._set_current)
        self.bar.editorSplited.connect(self.split_editor)
        self.bar.runFile[str].connect(self._run_file)
        self.bar.closeFile.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject[str].connect(self._add_to_project)
        self.bar.showFileInExplorer.connect(self._show_file_in_explorer)
        self.bar.goToSymbol.connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.reopenTab[str].connect(self._main_container.open_file)
        self.bar.recentTabsModified.connect(self._main_container.recent_files_changed)
        self.bar.code_navigator.btnPrevious.clicked['bool'].connect(lambda: self._navigate_code(self.NAVIGATE.prev))
        self.bar.code_navigator.btnNext.clicked['bool'].connect(lambda: self._navigate_code(self.NAVIGATE.prev))

    def _navigate_code(self, val):
        op = self.bar.code_navigator.operation
        self._main_container.navigate_code_history(val, op)

    def currentWidget(self):
        return self.stacked.currentWidget()

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        w = self.stacked.currentWidget()
        if w:
            w.setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stacked.currentIndex()
        ninjaide = IDE.getInstance()
        editable = ninjaide.get_or_create_editable(path)
        print("_file_opened_by_main", editable)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original:
                editor = neditable.editor
            else:
                editor = self._main_container.create_editor_from_editable(
                    neditable)
            index = self.stacked.currentIndex()
            self.stacked.addWidget(editor)
            self.bar.add_item(neditable.display_name, neditable)
            if keep_index:
                self.bar.set_current_by_index(index)

            # Editor Signals
            editor.cursorPositionChanged[int, int].connect(self._update_cursor_position)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.currentLineChanged.connect(self._set_current_symbol)
            editor.modificationChanged['bool'].connect(self._editor_modified)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            neditable.fileSaved.connect(self._update_symbols)
            neditable.fileSaved.connect(self._update_combo_info)

            # Connect file system signals only in the original
            neditable.fileClosing.connect(self._close_file)
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)

            # Load Symbols
            self._load_symbols(neditable)

    def show_combo_file(self):
        print("show_combo_file")
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def unlink_editors(self):
        for index in range(self.stacked.count()):
            widget = self.stacked.widget(index)
            widget.setDocument(QsciDocument())

    def split_editor(self, orientationVertical):
        new_widget = ComboEditor()
        for neditable in self.bar.get_editables():
            print("\nsplit_editor", neditable, new_widget)
            new_widget.add_editor(neditable)
        self.splitEditor.emit(self, new_widget, orientationVertical)

    def undock_editor(self):
        new_combo = ComboEditor()
        new_combo.setWindowTitle("NINJA-IDE")
        self.__undocked.append(new_combo)
        for neditable in self.bar.get_editables():
            print("undock_editor", neditable)
            new_combo.add_editor(neditable)
        new_combo.resize(500, 500)
        new_combo.aboutToCloseComboEditor.connect(self._remove_undock)
        new_combo.show()

    def _remove_undock(self):
        widget = self.sender()
        self.__undocked.remove(widget)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_file(self, neditable):
        index = self.bar.close_file(neditable)
        layoutItem = self.stacked.takeAt(index)
        #neditable.editor.completer.cc.unload_module()
        self._add_to_last_opened(neditable.file_path)
        layoutItem.widget().deleteLater()

        if self.stacked.isEmpty():
            self.allFilesClosed.emit()

    def _add_to_last_opened(self, path):
        if path not in settings.LAST_OPENED_FILES:
            settings.LAST_OPENED_FILES.append(path)
            if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS:
                self.__lastOpened = self.__lastOpened[1:]
            self.recentTabsModified.emit()

    def _editor_with_focus(self):
        if self._main_container.current_widget is not self:
            self._main_container.current_widget = self
            editor = self.stacked.currentWidget()
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') %
                   fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No |
            QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    def _file_has_been_modified(self, neditable):
        val = QMessageBox.No
        fileName = neditable.file_path
        val = QMessageBox.question(
            self, translations.TR_FILE_HAS_BEEN_MODIFIED,
            "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE),
            QMessageBox.Yes | QMessageBox.No)
        if val == QMessageBox.Yes:
            neditable.reload_file()

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''
        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        if neditable:
            self.stacked.setCurrentIndex(index)
            editor = self.stacked.currentWidget()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(
                neditable.file_path)
            self._load_symbols(neditable)
            self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()

    def widget(self, index):
        return self.stacked.widget(index)

    def count(self):
        """Return the number of editors opened."""
        return self.stacked.count()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index) or
                    self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value):
        obj = self.sender()
        neditable = obj.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        print("_go_to_symbol in index:", index)
        line = self._symbols_index[index]
        editor = self.stacked.currentWidget()
        editor.go_to_line(line)

    def _update_symbols(self, neditable):
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if editor == neditable.editor:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        symbols_handler = handlers.get_symbols_handler('py')
        source = neditable.editor.text()
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(
            list(symbols_simplified.items()), key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.getCursorPosition()
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        self.aboutToCloseComboEditor.emit()
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()