Ejemplo n.º 1
0
class Demo4(QDialog):
    # stackl = QStackedLayout()
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self.resize(400, 600)
        mainl = QGridLayout(self)
        self.stackl = QStackedLayout()
        self.stackl.setStackingMode(QStackedLayout.StackAll)

        for i in range(10):
            lab = QLabel(self)
            lab.setText('%d_label' % (i + 1))
            lab.setMinimumSize(100, 100)

            lab.setAutoFillBackground(True)

            pt = lab.palette()
            # pt = QPalette()
            pt.setBrush(QPalette.Background, Qt.black)
            pt.setBrush(QPalette.WindowText, Qt.white)
            lab.setPalette(pt)
            lab.setAlignment(Qt.AlignCenter)
            self.stackl.addWidget(lab)
            btn = QPushButton('item:%d' % (i + 1))
            mainl.addWidget(btn, i, 0)
            btn.clicked.connect(self.on_btnClick)

        mainl.addLayout(self.stackl, 0, 1, self.stackl.count(), 1)

    def on_btnClick(self):
        btn = QPushButton()
        i = int(self.sender().text()[len('item:'):]) - 1
        print('btn:', i)
        self.stackl.setCurrentIndex(i)
Ejemplo n.º 2
0
class ReliatyRadio(QMainWindow):
    layout = None

    back = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.init_layout()

        # Generic UI Settings
        self.resize(1024, 768)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
        self.setSizePolicy(sizePolicy)
        self.setContextMenuPolicy(QtCore.Qt.NoContextMenu)

        self.show_main_menu()

    def init_layout(self):
        self.layout = QStackedLayout()
        self.setCentralWidget(QWidget())
        self.centralWidget().setSizePolicy(self.sizePolicy())
        self.centralWidget().resize(1024, 768)
        self.centralWidget().setLayout(self.layout)

    def add_and_show_widget(self, widget):
        self.layout.addWidget(widget)
        self.layout.setCurrentWidget(widget)

    def go_back(self):
        count = self.layout.count()
        self.layout.setCurrentIndex(count - 2)
        self.layout.takeAt(count - 1)

    def show_main_menu(self):
        self.clearLayout()
        self.add_and_show_widget(MainMenu())

    def clearLayout(self):
        while self.layout.count():
            child = self.layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()
Ejemplo n.º 3
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()
Ejemplo n.º 4
0
class Tex0WidgetGroup(QWidget):
    def __init__(self,
                 parent,
                 tex0s=None,
                 max_rows=0,
                 max_columns=4,
                 brres=None):
        super().__init__(parent)
        main_layout = QVBoxLayout(self)
        self.stack = QStackedLayout(self)
        self.stack_widget = QWidget(self)
        self.map_box = QComboBox()
        self.map_box.activated.connect(self.on_map_change)
        self.__init_context_menu()
        main_layout.addWidget(self.map_box)
        self.stack_widget.setLayout(self.stack)
        main_layout.addWidget(self.stack_widget)
        self.subscriber = parent
        if tex0s is not None:
            self.set_tex0s(tex0s)
            if brres is None:
                self.brres = tex0s[0].parent
        if brres:
            self.brres = brres
        self.setLayout(main_layout)

    def __init_context_menu(self):
        self.setContextMenuPolicy(Qt.ActionsContextMenu)
        create_action = QAction('&Add Map', self)
        create_action.setToolTip('Add new map')
        create_action.triggered.connect(self.create_map)
        self.addAction(create_action)
        replace_action = QAction('&Replace', self)
        replace_action.setToolTip('Replace map')
        replace_action.triggered.connect(self.replace_map)
        self.addAction(replace_action)
        export_action = QAction('&Export', self)
        export_action.setToolTip('Export as png')
        export_action.triggered.connect(self.export)
        self.addAction(export_action)
        remove_action = QAction('&Delete', self)
        remove_action.setToolTip('Remove the map')
        remove_action.triggered.connect(self.remove)
        self.addAction(remove_action)

    def export(self):
        self.stack.currentWidget().export()

    def remove(self):
        self.remove_map_widget(self.stack.currentWidget())

    def replace_map(self):
        self.stack.currentWidget().replace_map()

    def get_tex0(self, index):
        return self.stack.itemAt(index).tex0

    def on_map_replace(self, tex):
        if self.subscriber is not None:
            self.subscriber.on_map_replace(tex, self.stack.currentIndex())

    def on_map_change(self, index):
        self.stack.setCurrentIndex(index)
        if self.subscriber is not None:
            self.subscriber.on_map_change(self.stack.currentWidget().tex0,
                                          index)

    def reset(self):
        for i in reversed(range(self.stack.count())):
            widget = self.stack.itemAt(i).widget()
            widget.del_widget()
            self.map_box.removeItem(i)

    def set_brres(self, brres):
        self.brres = brres

    def set_tex0s(self, tex0s):
        self.reset()
        for x in tex0s:
            self.add_tex0(x)

    def add_tex0(self, x):
        widget = MapWidget(self, x)
        self.add_map_widget(widget)

    def add_map_widget(self, map_widget):
        self.stack.addWidget(map_widget)
        self.map_box.addItem(map_widget.name)

    def remove_map_widget(self, map_widget):
        tex0 = map_widget.tex0
        index = self.stack.currentIndex()
        if self.subscriber is not None:
            self.subscriber.on_map_remove(tex0, index)

    def create_map(self):
        self.importer = MapImporter(self, self.brres)

    def on_import(self, tex0):
        index = self.stack.count()
        if self.subscriber:
            self.subscriber.on_map_add(tex0, index)
        self.importer = None
Ejemplo n.º 5
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()
Ejemplo n.º 6
0
class SimReader(QMainWindow):
    def __init__(self, port="\\.\COM6"):
        QMainWindow.__init__(self)
        self.sim = pySIMlib(False)
        self.backgroundWorker = Worker(self.sim)
        self.data = {}
        self._metaIdx = None
        self._contactsIdx = None
        self._smsIdx = None
        self.window = QWidget()
        self._blankIdx = 1
        self.body_layout = None
        self.stackedLayout = QStackedLayout()
        self.window.setLayout(self.stackedLayout)
        self.setCentralWidget(self.window)
        self.initUI()
        self.port = port
        self.initLib()

    def initLib(self):
        try:
            self.sim.openSession(self.port)
            self.statusBar().showMessage(
                "Successfully connected to serial port.", 2000)
        except Exception as e:
            print(e)
            self.choosePort(self.port)

    def initUI(self):
        self.setGeometry(50, 50, 600, 350)
        self.setWindowTitle('Sim Reader - Beta')

        self.createMenuBar()
        self.stackedLayout.addWidget(self.createPinEnterPanel())
        self.stackedLayout.setCurrentIndex(0)
        self.show()

    @staticmethod
    def silentlyUncheck(checkBtn):
        checkBtn.blockSignals(True)
        checkBtn.setChecked(False)
        checkBtn.blockSignals(False)

    def handleShowMetadata(self):
        self.silentlyUncheck(self.contactsBtn)
        self.silentlyUncheck(self.smsBtn)
        if "metadata" not in self.data.keys():
            self.progressSpeed = 25
            self.backgroundWorker = Worker(self.sim)
            self.loadData(self.backgroundWorker.loadMetadata,
                          self.prepareMetadataPanel)
        elif self._metaIdx is None:
            self._metaIdx = self.stackedLayout.count()
            self.prepareMetadataPanel(self.data)
        else:
            self.stackedLayout.setCurrentIndex(self._metaIdx)

    def handleShowContacts(self):
        self.silentlyUncheck(self.metaBtn)
        self.silentlyUncheck(self.smsBtn)

        if "contacts" not in self.data.keys():
            self.progressSpeed = 10
            self.backgroundWorker = Worker(self.sim)
            self.loadData(self.backgroundWorker.loadContacts,
                          self.prepareContactsPanel)
        elif self._contactsIdx is None:
            self.prepareContactsPanel(self.data)
        else:
            self.stackedLayout.setCurrentIndex(self._contactsIdx)

    def handleShowSMS(self):
        self.silentlyUncheck(self.metaBtn)
        self.silentlyUncheck(self.contactsBtn)
        if "smss" not in self.data.keys():
            self.progressSpeed = 1.5
            self.backgroundWorker = Worker(self.sim)
            self.loadData(self.backgroundWorker.loadSMSs,
                          self.prepareSMSsPanel)
        elif self._smsIdx is None:
            self.prepareSMSsPanel(self.data)
        else:
            self.stackedLayout.setCurrentIndex(self._smsIdx)

    def createMenuBar(self):
        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu('File')

        exitAction = QAction("Exit", self)
        exitAction.triggered.connect(exit)
        fileMenu.addAction(exitAction)

        toolsMenu = mainMenu.addMenu('Tools')

        self.saveToFileBtn = QAction("Save data to file", self)
        self.saveToFileBtn.triggered.connect(self.saveToFile)
        self.saveToFileBtn.setEnabled(False)
        toolsMenu.addAction(self.saveToFileBtn)

        helpMenu = mainMenu.addMenu('Help')
        about = QAction("About", self)
        about.triggered.connect(self.showAboutDialog)
        helpMenu.addAction(about)

    def showAboutDialog(self):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Information)
        msg.setWindowTitle("About sim reader")
        msg.setText(
            "Sim reader is a simple tool made by students of the Faculty for computer science in Ljubljana."
            " It allows inspecting basic data on SIM card.")
        msg.setInformativeText("@copy FRI")
        msg.setStandardButtons(QMessageBox.Ok)

        msg.exec_()

    def saveToFile(self):
        self.prevIndex = self.stackedLayout.currentIndex()
        if "contacts" not in self.data and "smss" not in self.data:
            self.progressSpeed = 1.3
            self.backgroundWorker = Worker(self.sim)
            self.loadData(self.backgroundWorker.loadContacts,
                          self._processAndLoadAnother)

        elif "contacts" not in self.data:
            self.progressSpeed = 10
            self.backgroundWorker = Worker(self.sim)
            self.loadData(self.backgroundWorker.loadContacts,
                          self._finishAndSaveToFile)
        elif "smss" not in self.data:
            self.progressSpeed = 1.5
            self.backgroundWorker = Worker(self.sim)
            self.loadData(self.backgroundWorker.loadSMSs,
                          self._finishAndSaveToFile)
        else:
            self._saveToFile()

    def _processData(self, data):
        if "error" in data:
            self.showException(data["detail"])
            return False
        else:
            for key, value in data.items():
                self.data[key] = value
            return True

    def _processAndLoadAnother(self, data):
        if self._processData(data):
            self.backgroundWorker = Worker(self.sim)
            self.loadData(self.backgroundWorker.loadSMSs,
                          self._finishAndSaveToFile,
                          resetLoader=False)

    def _finishAndSaveToFile(self, data):

        if self._processData(data):
            self.timer.stop()
            self.progress.hide()
            self._saveToFile()

    def _saveToFile(self):
        filename = 'export.json'
        with open(filename, 'w') as outfile:
            print(self.data.keys())
            json.dump(self.data, outfile, ensure_ascii=False)
            self.statusBar().showMessage("Saved data to file %s" % filename,
                                         2000)
            self.stackedLayout.setCurrentIndex(self.prevIndex)

    def createToolbar(self):
        self.formatbar = QToolBar(self)
        self.metaBtn = QToolButton(self)
        self.contactsBtn = QToolButton(self)
        self.smsBtn = QToolButton(self)

        self.metaBtn.setText('Metadata')
        self.metaBtn.toggled.connect(self.handleShowMetadata)
        self.metaBtn.setCheckable(True)
        self.formatbar.addWidget(self.metaBtn)

        self.contactsBtn.setText('Contacts')
        self.contactsBtn.toggled.connect(self.handleShowContacts)
        self.contactsBtn.setCheckable(True)
        self.formatbar.addWidget(self.contactsBtn)

        self.smsBtn.setText('Messages')
        self.smsBtn.toggled.connect(self.handleShowSMS)
        self.smsBtn.setCheckable(True)
        self.formatbar.addWidget(self.smsBtn)

        self.addToolBar(self.formatbar)

    def createPinEnterPanel(self):
        widget = QWidget()
        layout = QVBoxLayout()

        self.pinlabel = QLabel()
        self.pinlabel.setText("Enter PIN number:")

        self.pinBox = QLineEdit()
        self.pinBox.setValidator(QIntValidator())
        self.pinBox.setMaxLength(4)
        self.pinBox.setFont(QFont("Arial", 20))

        submitBtn = QPushButton("Submit", self)
        submitBtn.clicked.connect(self.verifyPin)

        layout.addWidget(self.pinlabel)
        layout.addWidget(self.pinBox)
        layout.addWidget(submitBtn)

        layout.addStretch()
        widget.setLayout(layout)

        return widget

    def choosePort(self, port):
        item, ok = QInputDialog \
            .getItem(self,
                     "Choose serial port",
                     "Serial reader not found on port %s. Please select the correct port bellow:" % port,
                     ["COM1", "COM2", "COM3", "COM4", "COM5", "COM6"], 0, False)

        if ok:
            self.initLib(item)
        else:
            exit(0)

    def verifyPin(self):
        pin = self.pinBox.text()
        ok = self.sim.verPIN(pin)
        if not ok:
            _, triesLeft = self.sim.getPINinfo()
            if triesLeft == 0:
                QMessageBox.warning(self, "Warning", "Pin card locked.")
            else:
                QMessageBox.warning(self, "Warning", "Wrong sim entered")
                self.pinlabel.setText("Enter PIN number (%s tries left):" %
                                      triesLeft)
            return False
        print("Pin OK")
        self.statusBar().showMessage("Pin OK", 2000)

        self.createToolbar()
        self.stackedLayout.addWidget(QWidget())
        self.progress = QProgressBar(self)
        self.metaBtn.setChecked(True)

    def loadData(self, loadFunction, finishCallback, resetLoader=True):
        self.stackedLayout.setCurrentIndex(self._blankIdx)
        self.progress.setAlignment(QtCore.Qt.AlignCenter)
        self.progress.setFormat(u'Loading data from SIM card: %p%')
        self.progress.setGeometry(200, 150, 250, 20)
        self.progress.show()

        self.thread = QThread()
        self.backgroundWorker.moveToThread(self.thread)
        self.backgroundWorker.finished.connect(self.thread.quit)
        self.backgroundWorker.finished.connect(finishCallback)
        self.thread.started.connect(loadFunction)
        self.thread.start()

        self.progressVal = 0 if resetLoader else self.progressVal
        self.progress.setValue(self.progressVal)
        self.timer = QtCore.QTimer()
        self.timer.setInterval(250)
        self.timer.timeout.connect(self.updateLoader)
        self.timer.start()

    def killThread(self):
        self.thread.quit()

    def updateLoader(self):
        if self.progressVal < 100:
            self.progressVal += self.progressSpeed
            self.progress.setValue(self.progressVal)

    def showException(self, e):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Information)

        msg.setText(
            "Error encountered while loading sim data. " +
            "Please restart sim reader or check if the sim card is not damaged."
        )
        msg.setInformativeText("The details are as follows:")
        msg.setWindowTitle("Error loading SIM data")
        msg.setDetailedText(e)
        msg.setStandardButtons(QMessageBox.Ok)

        if msg.exec_() == QMessageBox.Ok:
            app.quit()

    def _finishLoading(self, data):
        if "error" in data:
            self.showException(data["detail"])
            return False
        else:
            self.statusBar().showMessage("Data loaded successfully.", 1500)
            for key, value in data.items():
                self.data[key] = value
            self.timer.stop()
            self.progress.hide()
            self.saveToFileBtn.setEnabled(True)
            return True

    def prepareMetadataPanel(self, data):
        if self._finishLoading(data):
            self._metaIdx = self.stackedLayout.count()
            self.stackedLayout.addWidget(MetadataPanel(data))
            self.stackedLayout.setCurrentIndex(self._metaIdx)
        print("loaded metadata")

    def prepareContactsPanel(self, data):
        if self._finishLoading(data):
            self._contactsIdx = self.stackedLayout.count()
            self.stackedLayout.addWidget(ContactsPanel(self.sim, data))
            self.stackedLayout.setCurrentIndex(self._contactsIdx)
        print("loaded contacts")

    def prepareSMSsPanel(self, data):
        if self._finishLoading(data):
            self._smsIdx = self.stackedLayout.count()
            self.stackedLayout.addWidget(SMSPanel(data))
            self.stackedLayout.setCurrentIndex(self._smsIdx)
        print("loaded smss")
Ejemplo n.º 7
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)
Ejemplo n.º 8
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()
    """
    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)
Ejemplo n.º 9
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()
Ejemplo n.º 10
0
class HistogramDisplayControl(QWidget):
    class Layout(Enum):
        STACKED = 0
        HORIZONTAL = 1
        VERTICAL = 2

    class DisplayType(Enum):
        GREY_SCALE = 0
        RBG = 1

    __LOG: Logger = LogHelper.logger("HistogramDisplayControl")

    limit_changed = pyqtSignal(LimitChangeEvent)
    limits_reset = pyqtSignal(LimitResetEvent)
    layout_changed = pyqtSignal(Layout)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.__menu = None
        self.__plots = dict()

        # Use stacked layout as default
        self.__create_stacked_layout()

    def __create_horizontal_layout(self):
        self.__plot_layout = QHBoxLayout()
        self.__plot_layout.setSpacing(1)
        self.__plot_layout.setContentsMargins(1, 1, 1, 1)
        self.setLayout(self.__plot_layout)
        self.__current_layout = HistogramDisplayControl.Layout.HORIZONTAL

    def __create_vertical_layout(self):
        self.__plot_layout = QVBoxLayout()
        self.__plot_layout.setSpacing(1)
        self.__plot_layout.setContentsMargins(1, 1, 1, 1)
        self.setLayout(self.__plot_layout)
        self.__current_layout = HistogramDisplayControl.Layout.VERTICAL

    def __create_stacked_layout(self):
        layout = QVBoxLayout()
        layout.setSpacing(1)
        layout.setContentsMargins(1, 1, 1, 1)

        self.__plot_layout = QStackedLayout()
        self.__plot_layout.setContentsMargins(1, 1, 1, 1)
        self.__plot_layout.setSpacing(1)

        self.__tab_widget = QWidget()
        self.__tab_widget.setFixedHeight(20)
        self.__tab_widget.hide()

        self.__tab_layout = QHBoxLayout()
        self.__tab_layout.setContentsMargins(1, 1, 1, 1)
        self.__tab_layout.setAlignment(Qt.AlignLeft)
        self.__tab_layout.addSpacing(10)

        self.__red_button = QRadioButton("Red")
        self.__red_button.setStyleSheet("QRadioButton {color: red}")
        self.__red_button.toggled.connect(self.__handle_red_toggled)
        self.__tab_layout.addWidget(self.__red_button)
        self.__red_plot_index = None

        self.__green_button = QRadioButton("Green")
        self.__green_button.setStyleSheet("QRadioButton {color: green}")
        self.__green_button.toggled.connect(self.__handle_green_toggled)
        self.__tab_layout.addWidget(self.__green_button)
        self.__green_plot_index = None

        self.__blue_button = QRadioButton("Blue")
        self.__blue_button.setStyleSheet("QRadioButton {color: blue}")
        self.__blue_button.toggled.connect(self.__handle_blue_toggled)
        self.__tab_layout.addWidget(self.__blue_button)
        self.__tab_widget.setLayout(self.__tab_layout)
        self.__blue_plot_index = None

        layout.addWidget(self.__tab_widget)
        layout.addLayout(self.__plot_layout)
        self.setLayout(layout)
        self.__current_layout = HistogramDisplayControl.Layout.STACKED

    def __init_menu(self):
        self.__menu: QMenu = QMenu(self)

        stacked_action = QAction("Stacked", self)
        stacked_action.triggered.connect(self.__handle_stacked_selected)
        self.__menu.addAction(stacked_action)

        horizontal_action = QAction("Horizontal", self)
        horizontal_action.triggered.connect(self.__handle_horizontal_selected)
        self.__menu.addAction(horizontal_action)

        vertical_action = QAction("Vertical", self)
        vertical_action.triggered.connect(self.__handle_vertical_selected)
        self.__menu.addAction(vertical_action)

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(
            self.__handle_custom_context_menu)

    def __handle_custom_context_menu(self, position: QPoint):
        HistogramDisplayControl.__LOG.debug(
            "__handle_custom_context_menu called position: {0}", position)
        self.__menu.popup(self.mapToGlobal(position))

    def __handle_stacked_selected(self):
        self.__swap_layout(HistogramDisplayControl.Layout.STACKED)

    def __handle_horizontal_selected(self):
        self.__swap_layout(HistogramDisplayControl.Layout.HORIZONTAL)

    def __handle_vertical_selected(self):
        self.__swap_layout(HistogramDisplayControl.Layout.VERTICAL)

    def __swap_layout(self, new_layout: Layout):
        # The plot's will have had their parent set to the layout so first
        # we undo that so they won't get deleted when the layout does.
        for band, plot in self.__plots.items():
            plot.setParent(None)

        if self.__current_layout == HistogramDisplayControl.Layout.STACKED:
            self.__red_button.setParent(None)
            self.__green_button.setParent(None)
            self.__blue_button.setParent(None)
            self.__tab_widget.setParent(None)

        # Per Qt docs we need to delete the current layout before we can set a new one
        # And it turns out we can't delete the layout until we reassign it to another widget
        # who becomes it's parent, then we delete the parent.
        tmp = QWidget()
        tmp.setLayout(self.layout())
        del tmp

        if new_layout == HistogramDisplayControl.Layout.STACKED:
            self.__create_stacked_layout()

        if new_layout == HistogramDisplayControl.Layout.HORIZONTAL:
            self.__create_horizontal_layout()

        if new_layout == HistogramDisplayControl.Layout.VERTICAL:
            self.__create_vertical_layout()

        for band, plot in self.__plots.items():
            self.__plot_layout.addWidget(plot)
            self.__wire_band(band, plot)
            if new_layout != HistogramDisplayControl.Layout.STACKED:
                # stacked layout hides plots not displayed so set them back
                plot.show()

        self.layout_changed.emit(new_layout)

    def __wire_band(self, band: Band, plot: AdjustableHistogramControl):
        if self.__current_layout == HistogramDisplayControl.Layout.STACKED:
            set_checked: bool = False
            if self.__plot_layout.count() == 1:
                set_checked = True
                self.__tab_widget.show()

            if band == Band.RED:
                self.__red_plot_index = self.__plot_layout.indexOf(plot)
                self.__red_button.setChecked(set_checked)

            if band == Band.GREEN:
                self.__green_plot_index = self.__plot_layout.indexOf(plot)
                self.__green_button.setChecked(set_checked)

            if band == Band.BLUE:
                self.__blue_plot_index = self.__plot_layout.indexOf(plot)
                self.__blue_button.setChecked(set_checked)

    @pyqtSlot(bool)
    def __handle_red_toggled(self, checked: bool):
        if checked:
            HistogramDisplayControl.__LOG.debug("red toggle checked")
            self.__plot_layout.setCurrentIndex(self.__red_plot_index)

    @pyqtSlot(bool)
    def __handle_green_toggled(self, checked: bool):
        if checked:
            HistogramDisplayControl.__LOG.debug("green toggle checked")
            self.__plot_layout.setCurrentIndex(self.__green_plot_index)

    @pyqtSlot(bool)
    def __handle_blue_toggled(self, checked: bool):
        if checked:
            HistogramDisplayControl.__LOG.debug("blue toggle checked")
            self.__plot_layout.setCurrentIndex(self.__blue_plot_index)

    def add_plot(self, raw_data: HistogramPlotData,
                 adjusted_data: HistogramPlotData, band: Band):
        """Expects either one band with band of Band.GREY or three bands one each of
        Band.RED, Band.GREEN, Band.BLUE.  If these conditions are not met the code will attempt
        to be accommodating and won't throw and error but you might get strange results."""
        plots = AdjustableHistogramControl(band)
        plots.set_raw_data(raw_data)
        plots.set_adjusted_data(adjusted_data)
        plots.limit_changed.connect(self.limit_changed)
        plots.limits_reset.connect(self.limits_reset)

        self.__plots[band] = plots
        self.__plot_layout.addWidget(plots)

        if self.__plot_layout.count() == 2:
            self.__init_menu()

        if band == Band.RED or band == Band.GREEN or band == Band.BLUE:
            self.__wire_band(band, plots)

    def set_adjusted_data(self, data: HistogramPlotData, band: Band):
        """Update the adjusted data for a Band that has already been added using
        add_plot"""
        plots: AdjustableHistogramControl = self.__plots[band]
        if plots is not None:
            plots.set_adjusted_data(data)

    def update_limits(self, data: HistogramPlotData, band: Band):
        plots: AdjustableHistogramControl = self.__plots[band]
        if plots is not None:
            plots.update_limits(data)
Ejemplo n.º 11
0
class ArtEngine(QWidget):
    def __init__(self):
        super().__init__()

        # ...
        # Widget Creation
        # ...

        self.appNameLabel = QLabel("Art Engine v0.01", self)
        self.image = QLabel(self)

        self.tca = AlgoOne(self.imgMan)
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(self,
                                                  "Select Image",
                                                  "",
                                                  "Image Files (*.png *.jpg)",
                                                  options=options)

        img = cv2.imread(fileName)
        print("before", img.shape)
        while (img.shape[0] > 300 or img.shape[1] > 1000):
            img = cv2.resize(img,
                             None,
                             fx=9 / 10,
                             fy=9 / 10,
                             interpolation=cv2.INTER_CUBIC)
        print("after", img.shape)

        self.gimg = img

        self.image.setPixmap(self.cvToPix(img))

        layout = QVBoxLayout()

        #Creating Buttons

        filterNames = [
            "Select Filter", "Red x Negative", "Blue x Negative",
            "Green x Negative", "Erode x Morph", "Negative x Morph",
            "Dilate x Top Hat", "Morph x Top Hat", "Negative x Top Hat",
            "Blur x Top Hat", "Blur x Negative"
        ]
        buttonsLayout = QHBoxLayout()
        self.openButton = QPushButton('Open', self)
        self.saveButton = QPushButton('Save', self)
        self.shareButton = QPushButton('Share With Email', self)

        self.openButton.clicked.connect(self.openButtonClicked)
        self.saveButton.clicked.connect(self.saveButtonClicked)
        self.shareButton.clicked.connect(self.shareButtonClicked)
        self.comboBox = QComboBox()
        self.comboBox.addItems(filterNames)

        self.comboBox.currentIndexChanged.connect(self.applyFilterClicked)

        buttonsLayout.addWidget(self.openButton)
        buttonsLayout.addWidget(self.saveButton)
        buttonsLayout.addWidget(self.shareButton)
        buttonsLayout.addWidget(self.comboBox)

        layout.addLayout(buttonsLayout)
        layout.addWidget(self.appNameLabel)
        layout.addWidget(self.image)

        self.firstLabel = QLabel("Choose Your Filter")

        self.stacked_layout = QStackedLayout(
        )  # Creates stacked layout to hold the dial layouts for algos
        self.stacked_layout.addWidget(self.firstLabel)
        layout.addLayout(self.stacked_layout)

        self.setLayout(layout)
        self.setGeometry(100, 100, 300, 175)
        self.imgMan()
        self.show()

    def createAlgoLayout(self):
        self.newLayout = self.tca.getModBox()
        self.newWidget = QWidget()
        self.newWidget.setLayout(self.newLayout)
        self.stacked_layout.addWidget(self.newWidget)

    def applyFilterClicked(self, value):
        print(self.stacked_layout.count())
        if value == 1:
            self.tca = RedNeg(self.imgMan)
        elif value == 2:
            self.tca = BlueNeg(self.imgMan)
        elif value == 3:
            self.tca = GreenNeg(self.imgMan)
        elif value == 4:
            self.tca = ErodeMorph(self.imgMan)
        elif value == 5:
            self.tca = NegateMorph(self.imgMan)
        elif value == 6:
            self.tca = DilateTop(self.imgMan)
        elif value == 7:
            self.tca = MorphTop(self.imgMan)
        elif value == 8:
            self.tca = NegateTop(self.imgMan)
        elif value == 9:
            self.tca = BlurTop(self.imgMan)
        elif value == 10:
            self.tca = BlurNeg(self.imgMan)
        self.createAlgoLayout()
        self.stacked_layout.setCurrentIndex(self.stacked_layout.count() - 1)

    def openButtonClicked(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(self,
                                                  "Select Image",
                                                  "",
                                                  "Image Files (*.png *.jpg)",
                                                  options=options)

        img = cv2.imread(fileName)
        while (img.shape[0] > 300 or img.shape[1] > 1000):
            img = cv2.resize(img,
                             None,
                             fx=9 / 10,
                             fy=9 / 10,
                             interpolation=cv2.INTER_CUBIC)

        self.gimg = img

        self.image.setPixmap(self.cvToPix(img))

    def saveButtonClicked(self):

        w = len(self.final)
        h = len(self.final[0])

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getSaveFileName(self,
                                                  "Save Image",
                                                  "myImage.jpg",
                                                  "Image Files (*.png *.jpg)",
                                                  options=options)
        if fileName:
            print(fileName)

        cv2.imwrite(fileName, self.final)
        print('Save Button Clicked')

    def shareButtonClicked(self):
        self.new_win = ShareButtonWindow()

    # Converts an OpenCV image to PyQt5 image
    def cvToPix(self, img):
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        qImg = QImage(img.data, img.shape[1], img.shape[0], img.strides[0],
                      QImage.Format_RGB888)
        qpix = QPixmap()
        qpix.convertFromImage(qImg)
        return qpix

    @pyqtSlot()
    def imgMan(self):

        for op in self.tca.getOperators():
            op.updateAll()
        self.tca.updateRatios()

        self.final = self.tca.render(self.gimg)
        self.image.setPixmap(self.cvToPix(self.final))
Ejemplo n.º 12
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()
Ejemplo n.º 13
0
class ProjectTreeColumn(QDialog):

    # Signalsnproject =
    dockWidget = pyqtSignal('PyQt_PyObject')
    undockWidget = pyqtSignal()
    changeTitle = pyqtSignal('PyQt_PyObject', 'QString')
    updateLocator = pyqtSignal()
    activeProjectChanged = pyqtSignal()

    def __init__(self, parent=None):
        super(ProjectTreeColumn, self).__init__(parent)
        vbox = QVBoxLayout(self)
        vbox.setSizeConstraint(QVBoxLayout.SetDefaultConstraint)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)
        self._buttons = []
        frame = QFrame()
        frame.setObjectName("actionbar")
        box = QVBoxLayout(frame)
        box.setContentsMargins(1, 1, 1, 1)
        box.setSpacing(0)

        self._combo_project = QComboBox()
        self._combo_project.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Fixed)
        self._combo_project.setSizeAdjustPolicy(
            QComboBox.AdjustToMinimumContentsLengthWithIcon)
        self._combo_project.setObjectName("combo_projects")
        box.addWidget(self._combo_project)
        vbox.addWidget(frame)
        self._combo_project.setContextMenuPolicy(Qt.CustomContextMenu)
        self._projects_area = QStackedLayout()
        logger.debug("This is the projects area")
        vbox.addLayout(self._projects_area)

        # Empty widget
        self._empty_proj = QLabel(translations.TR_NO_PROJECTS)
        self._empty_proj.setAlignment(Qt.AlignCenter)
        self._empty_proj.setAutoFillBackground(True)
        self._empty_proj.setBackgroundRole(QPalette.Base)
        self._projects_area.addWidget(self._empty_proj)
        self._projects_area.setCurrentWidget(self._empty_proj)

        self.projects = []

        self._combo_project.activated.connect(
            self._change_current_project)
        self._combo_project.customContextMenuRequested[
            'const QPoint&'].connect(self.context_menu_for_root)

        connections = (
            {
                "target": "main_container",
                "signal_name": "addToProject",
                "slot": self._add_file_to_project
            },
            {
                "target": "main_container",
                "signal_name": "showFileInExplorer",
                "slot": self._show_file_in_explorer
            },
        )
        IDE.register_service('projects_explorer', self)
        IDE.register_signals('projects_explorer', connections)
        ExplorerContainer.register_tab(translations.TR_TAB_PROJECTS, self)

        # FIXME: Should have a ninja settings object that stores tree state
        # FIXME: Or bettter, application data object
        # TODO: check this:
        # self.connect(ide, SIGNAL("goingDown()"),
        #    self.tree_projects.shutdown)

        # def close_project_signal():
        #    self.emit(SIGNAL("updateLocator()"))

    def install_tab(self):
        ide = IDE.get_service('ide')
        ui_tools.install_shortcuts(self, actions.PROJECTS_TREE_ACTIONS, ide)
        ide.goingDown.connect(self._on_ide_going_down)

    def _on_ide_going_down(self):
        """Save some settings before close"""
        if self.current_tree is None:
            return
        ds = IDE.data_settings()
        show_filesize = not bool(self.current_tree.isColumnHidden(1))
        ds.setValue("projectsExplorer/showFileSize", show_filesize)

    def load_session_projects(self, projects):
        for project in projects:
            if os.path.exists(project):
                self._open_project_folder(project)

    def open_project_folder(self, folderName=None):
        if settings.WORKSPACE:
            directory = settings.WORKSPACE
        else:
            directory = os.path.expanduser("~")

        if folderName is None:
            folderName = QFileDialog.getExistingDirectory(
                self, translations.TR_OPEN_PROJECT_DIRECTORY, directory)
            logger.debug("Choosing Foldername")
        if folderName:
            if not file_manager.folder_exists(folderName):
                QMessageBox.information(
                    self,
                    translations.TR_PROJECT_NONEXIST_TITLE,
                    translations.TR_PROJECT_NONEXIST % folderName)
                return
            logger.debug("Opening %s" % folderName)
            for p in self.projects:
                if p.project.path == folderName:
                    QMessageBox.information(
                        self,
                        translations.TR_PROJECT_PATH_ALREADY_EXIST_TITLE,
                        translations.TR_PROJECT_PATH_ALREADY_EXIST
                        % folderName)
                    return
            self._open_project_folder(folderName)

    def _open_project_folder(self, folderName):
        ninjaide = IDE.get_service("ide")
        # TODO: handle exception when .nja file is empty
        project = NProject(folderName)
        qfsm = ninjaide.filesystem.open_project(project)
        if qfsm:
            self.add_project(project)
            self.save_recent_projects(folderName)
            # FIXME: show editor area?
            # main_container = IDE.get_service('main_container')
            # if main_container:
            #    main_container.show_editor_area()
            if len(self.projects) > 1:
                title = "%s (%s)" % (
                    translations.TR_TAB_PROJECTS, len(self.projects))
            else:
                title = translations.TR_TAB_PROJECTS
            self.changeTitle.emit(self, title)

    def _add_file_to_project(self, path):
        """Add the file for 'path' in the project the user choose here."""
        if self._projects_area.count() > 0:
            path_project = [self.current_project]
            _add_to_project = add_to_project.AddToProject(path_project, self)
            _add_to_project.exec_()
            if not _add_to_project.path_selected:
                return
            main_container = IDE.get_service('main_container')
            if not main_container:
                return
            editorWidget = main_container.get_current_editor()
            if not editorWidget.file_path:
                name = QInputDialog.getText(
                    None,
                    translations.TR_ADD_FILE_TO_PROJECT,
                    translations.TR_FILENAME + ": ")[0]
                if not name:
                    QMessageBox.information(
                        self,
                        translations.TR_INVALID_FILENAME,
                        translations.TR_INVALID_FILENAME_ENTER_A_FILENAME)
                    return
            else:
                name = file_manager.get_basename(editorWidget.file_path)
            new_path = file_manager.create_path(
                _add_to_project.path_selected, name)
            ide_srv = IDE.get_service("ide")
            old_file = ide_srv.get_or_create_nfile(path)
            new_file = old_file.save(editorWidget.text(), new_path)
            # FIXME: Make this file replace the original in the open tab
        else:
            pass
            # Message about no project

    def _show_file_in_explorer(self, path):
        '''Iterate through the list of available projects and show
        the current file in the explorer view for the first
        project that contains it (i.e. if the same file is
        included in multiple open projects, the path will be
        expanded for the first project only).
        Note: This slot is connected to the main container's
        "showFileInExplorer(QString)" signal.'''
        central = IDE.get_service('central_container')
        if central and not central.is_lateral_panel_visible():
            return
        for project in self.projects:
            index = project.model().index(path)
            if index.isValid():
                # This highlights the index in the tree for us
                project.scrollTo(index, QAbstractItemView.EnsureVisible)
                project.setCurrentIndex(index)
                break

    def add_project(self, project):
        if project not in self.projects:
            self._combo_project.addItem(project.name)
            tooltip = utils.path_with_tilde_homepath(project.path)
            self._combo_project.setToolTip(tooltip)
            index = self._combo_project.count() - 1
            self._combo_project.setItemData(index, project)
            ptree = TreeProjectsWidget(project)
            self._projects_area.addWidget(ptree)
            ptree.closeProject['PyQt_PyObject'].connect(self._close_project)
            pmodel = project.model
            ptree.setModel(pmodel)
            pindex = pmodel.index(pmodel.rootPath())
            ptree.setRootIndex(pindex)
            self.projects.append(ptree)
            self._projects_area.setCurrentWidget(ptree)  # Can be empty widget
            self._combo_project.setCurrentIndex(index)

        # FIXME: improve?
        # if len(self.projects) == 1:
        #     self._combo_project.currentIndexChanged[int].connect(
        #         self._change_current_project)

    def _close_project(self, widget):
        """Close the project related to the tree widget."""
        index = self._combo_project.currentIndex()
        self.projects.remove(widget)
        # index + 1 is necessary because the widget
        # with index 0 is the empty widget
        self._projects_area.takeAt(index + 1)
        self._combo_project.removeItem(index)
        index = self._combo_project.currentIndex()
        self._projects_area.setCurrentIndex(index + 1)
        ninjaide = IDE.get_service('ide')
        ninjaide.filesystem.close_project(widget.project.path)
        widget.deleteLater()
        if len(self.projects) > 1:
            title = "%s (%s)" % (
                translations.TR_TAB_PROJECTS, len(self.projects))
        else:
            title = translations.TR_TAB_PROJECTS
        self.changeTitle.emit(self, title)
        self.updateLocator.emit()

    def _change_current_project(self, index):
        nproject = self._combo_project.itemData(index)

        ninjaide = IDE.get_service("ide")
        projects = ninjaide.get_projects()
        for project in projects.values():
            if project == nproject:
                nproject.is_current = True
            else:
                project.is_current = False
        self._projects_area.setCurrentIndex(index + 1)
        self.activeProjectChanged.emit()

    def close_opened_projects(self):
        for project in reversed(self.projects):
            self._close_project(project)

    def save_project(self):
        """Save all the opened files that belongs to the actual project."""
        if self.current_project is not None:
            path = self.current_project.path
            main_container = IDE.get_service('main_container')
            if path and main_container:
                main_container.save_project(path)

    def create_new_project(self):
        wizard = new_project_manager.NewProjectManager(self)
        wizard.show()

    @property
    def current_project(self):
        project = None
        if self._projects_area.count() > 0 and self.current_tree is not None:
            project = self.current_tree.project
        return project

    @property
    def current_tree(self):
        tree = None
        widget = self._projects_area.currentWidget()
        if isinstance(widget, TreeProjectsWidget):
            tree = widget
        return tree

    def set_current_item(self, path):
        if self.current_project is not None:
            self.current_tree.set_current_item(path)

    def save_recent_projects(self, folder):
        settings = IDE.data_settings()
        recent_project_list = settings.value('recentProjects', {})
        # if already exist on the list update the date time
        projectProperties = json_manager.read_ninja_project(folder)
        name = projectProperties.get('name', '')
        description = projectProperties.get('description', '')

        if not name:
            name = file_manager.get_basename(folder)

        if not description:
            description = translations.TR_NO_DESCRIPTION

        if folder in recent_project_list:
            properties = recent_project_list[folder]
            properties["lastopen"] = QDateTime.currentDateTime()
            properties["name"] = name
            properties["description"] = description
            recent_project_list[folder] = properties
        else:
            recent_project_list[folder] = {
                "name": name,
                "description": description,
                "isFavorite": False, "lastopen": QDateTime.currentDateTime()}
            # if the length of the project list it's high that 10 then delete
            # the most old
            # TODO: add the length of available projects to setting
            if len(recent_project_list) > MAX_RECENT_PROJECTS:
                del recent_project_list[self.find_most_old_open(
                    recent_project_list)]
        settings.setValue('recentProjects', recent_project_list)

    def find_most_old_open(self, recent_project_list):
        listFounder = []
        for recent_project_path, content in list(recent_project_list.items()):
            listFounder.append((recent_project_path, int(
                content["lastopen"].toString("yyyyMMddHHmmzzz"))))
        listFounder = sorted(listFounder, key=lambda date: listFounder[1],
                             reverse=True)   # sort by date last used
        return listFounder[0][0]

    def reject(self):
        if self.parent() is None:
            self.dockWidget.emit(self)

    def closeEvent(self, event):
        self.dockWidget.emit(self)
        event.ignore()

    def context_menu_for_root(self):
        menu = QMenu(self)
        if self.current_tree is None:
            # No projects
            return
        path = self.current_tree.project.path
        # Reset index
        self.current_tree.setCurrentIndex(QModelIndex())

        action_add_file = menu.addAction(QIcon(":img/new"),
                                         translations.TR_ADD_NEW_FILE)
        action_add_folder = menu.addAction(QIcon(
            ":img/openProj"), translations.TR_ADD_NEW_FOLDER)
        action_create_init = menu.addAction(translations.TR_CREATE_INIT)
        menu.addSeparator()
        action_run_project = menu.addAction(translations.TR_RUN_PROJECT)
        action_properties = menu.addAction(translations.TR_PROJECT_PROPERTIES)
        action_show_file_size = menu.addAction(translations.TR_SHOW_FILESIZE)
        menu.addSeparator()
        action_close = menu.addAction(translations.TR_CLOSE_PROJECT)

        # Connections
        action_add_file.triggered.connect(
            lambda: self.current_tree._add_new_file(path))
        action_add_folder.triggered.connect(
            lambda: self.current_tree._add_new_folder(path))
        action_create_init.triggered.connect(self.current_tree._create_init)
        action_run_project.triggered.connect(
            self.current_tree._execute_project)
        action_properties.triggered.connect(
            self.current_tree.open_project_properties)
        action_close.triggered.connect(self.current_tree._close_project)
        action_show_file_size.triggered.connect(
            self.current_tree.show_filesize_info)

        # menu for the project
        for m in self.current_tree.extra_menus_by_scope['project']:
            if isinstance(m, QMenu):
                menu.addSeparator()
                menu.addMenu(m)

        # show the menu!
        menu.exec_(QCursor.pos())
class ProjectTreeColumn(QDialog):
    dockWidget = pyqtSignal("QObject*")
    undockWidget = pyqtSignal()
    changeTitle = pyqtSignal("QObject*", str)
    def __init__(self, parent=None):
        super(ProjectTreeColumn, self).__init__(parent,
                                                Qt.WindowStaysOnTopHint)
        vbox = QVBoxLayout(self)
        vbox.setSizeConstraint(QVBoxLayout.SetDefaultConstraint)
        vbox.setContentsMargins(0, 0, 0, 0)
        self._buttons = []

        self._combo_project = QComboBox()
        self._combo_project.setMinimumHeight(30)
        self._combo_project.setContextMenuPolicy(Qt.CustomContextMenu)
        vbox.addWidget(self._combo_project)

        self._projects_area = QStackedLayout()
        logger.debug("This is the projects area")
        logger.debug(self._projects_area)
        vbox.addLayout(self._projects_area)

        self.projects = []

        self._combo_project.currentIndexChanged[int].connect(self._change_current_project)
        self._combo_project.customContextMenuRequested['const QPoint &'].connect(self.context_menu_for_root)
        connections = (
            {'target': 'main_container',
             'signal_name': 'addToProject',#(QString)
             'slot': self._add_file_to_project},
            {'target': 'main_container',
             'signal_name': 'showFileInExplorer',#(QString)
             'slot': self._show_file_in_explorer},
        )
        IDE.register_service('projects_explorer', self)
        IDE.register_signals('projects_explorer', connections)
        ExplorerContainer.register_tab(translations.TR_TAB_PROJECTS, self)

        #FIXME: Should have a ninja settings object that stores tree state
        #FIXME: Or bettter, application data object
        #TODO: check this:
        #self.connect(ide, SIGNAL("goingDown()"),
            #self.tree_projects.shutdown)

        #def close_project_signal():
            #self.emit(SIGNAL("updateLocator()"))



    def install_tab(self):
        ide = IDE.getInstance()
        ui_tools.install_shortcuts(self, actions.PROJECTS_TREE_ACTIONS, ide)

        ide.goingDown.connect(self.close)

    def load_session_projects(self, projects):
        for project in projects:
            if os.path.exists(project):
                self._open_project_folder(project)

    def open_project_folder(self, folderName=None):
        print("open_project_folder", folderName)
        if settings.WORKSPACE:
            directory = settings.WORKSPACE
        else:
            directory = os.path.expanduser("~")

        if folderName is None:
            folderName = QFileDialog.getExistingDirectory(
                self, translations.TR_OPEN_PROJECT_DIRECTORY, directory)
            logger.debug("Choosing Foldername")
        if folderName:
            logger.debug("Opening %s" % folderName)
            self._open_project_folder(folderName)

    def _open_project_folder(self, folderName):
        ninjaide = IDE.get_service("ide")
        project = NProject(folderName)
        qfsm = ninjaide.filesystem.open_project(project)
        if qfsm:
            self.add_project(project)
            self.save_recent_projects(folderName)
            main_container = IDE.get_service('main_container')
            if main_container:
                main_container.show_editor_area()
            if len(self.projects) > 1:
                title = "%s (%s)" % (
                    translations.TR_TAB_PROJECTS, len(self.projects))
            else:
                title = translations.TR_TAB_PROJECTS
            self.changeTitle.emit(self, title)

    def _add_file_to_project(self, path):
        """Add the file for 'path' in the project the user choose here."""
        if self._projects_area.count() > 0:
            pathProject = [self.current_project]
            addToProject = add_to_project.AddToProject(pathProject, self)
            addToProject.exec_()
            if not addToProject.pathSelected:
                return
            main_container = IDE.get_service('main_container')
            if not main_container:
                return
            editorWidget = main_container.get_current_editor()
            if not editorWidget.file_path:
                name = QInputDialog.getText(None,
                                            translations.TR_ADD_FILE_TO_PROJECT,
                                            translations.TR_FILENAME + ": ")[0]
                if not name:
                    QMessageBox.information(
                        self,
                        translations.TR_INVALID_FILENAME,
                        translations.TR_INVALID_FILENAME_ENTER_A_FILENAME)
                    return
            else:
                name = file_manager.get_basename(editorWidget.file_path)
            new_path = file_manager.create_path(addToProject.pathSelected, name)
            ide_srv = IDE.get_service("ide")
            old_file = ide_srv.get_or_create_nfile(path)
            new_file = old_file.save(editorWidget.text(), new_path)
            #FIXME: Make this file replace the original in the open tab
        else:
            pass
            # Message about no project

    def _show_file_in_explorer(self, path):
        '''Iterate through the list of available projects and show
        the current file in the explorer view for the first
        project that contains it (i.e. if the same file is
        included in multiple open projects, the path will be
        expanded for the first project only).
        Note: This slot is connected to the main container's
        "showFileInExplorer(QString)" signal.'''
        central = IDE.get_service('central_container')
        if central and not central.is_lateral_panel_visible():
            return
        for project in self.projects:
            index = project.model().index(path)
            if index.isValid():
                # This highlights the index in the tree for us
                project.scrollTo(index, QAbstractItemView.EnsureVisible)
                project.setCurrentIndex(index)
                break

    def add_project(self, project):
        if project not in self.projects:
            self._combo_project.addItem(project.name)
            ptree = TreeProjectsWidget(project)
            self._projects_area.addWidget(ptree)
            ptree.closeProject.connect(self._close_project)
            print("project", project)#setRootPath
            pmodel = project.model
            ptree.setModel(pmodel)
            pindex = pmodel.index(pmodel.rootPath())
            ptree.setRootIndex(pindex)
            self.projects.append(ptree)
            current_index = self._projects_area.count()
            self._projects_area.setCurrentIndex(current_index - 1)
            self._combo_project.setCurrentIndex(current_index - 1)

    def _close_project(self, widget):
        """Close the project related to the tree widget."""
        index = self._projects_area.currentIndex()
        self.projects.remove(widget)
        self._projects_area.takeAt(index)
        self._combo_project.removeItem(index)
        index = self._combo_project.currentIndex()
        self._projects_area.setCurrentIndex(index)
        ninjaide = IDE.getInstance()
        ninjaide.filesystem.close_project(widget.project.path)
        widget.deleteLater()
        if len(self.projects) > 1:
            title = "%s (%s)" % (
                translations.TR_TAB_PROJECTS, len(self.projects))
        else:
            title = translations.TR_TAB_PROJECTS
        self.changeTitle.emit(self, title)

    def _change_current_project(self, index):
        self._projects_area.setCurrentIndex(index)

    def close_opened_projects(self):
        for project in reversed(self.projects):
            self._close_project(project)

    def save_project(self):
        """Save all the opened files that belongs to the actual project."""
        if self._projects_area.count() > 0:
            path = self.current_project.path
            main_container = IDE.get_service('main_container')
            if path and main_container:
                main_container.save_project(path)

    def create_new_project(self):
        wizard = new_project_manager.NewProjectManager(self)
        wizard.show()

    @property
    def current_project(self):
        if self._projects_area.count() > 0:
            return self._projects_area.currentWidget().project

    @property
    def current_tree(self):
        obj = self._projects_area.currentWidget()
        return obj

    def save_recent_projects(self, folder):
        settings = IDE.data_settings()
        recent_project_list = settings.value('recentProjects', {})
        #if already exist on the list update the date time
        projectProperties = json_manager.read_ninja_project(folder)
        name = projectProperties.get('name', '')
        description = projectProperties.get('description', '')

        if name == '':
            name = file_manager.get_basename(folder)

        if description == '':
            description = translations.TR_NO_DESCRIPTION

        if folder in recent_project_list:
            properties = recent_project_list[folder]
            properties["lastopen"] = QDateTime.currentDateTime()
            properties["name"] = name
            properties["description"] = description
            recent_project_list[folder] = properties
        else:
            recent_project_list[folder] = {
                "name": name,
                "description": description,
                "isFavorite": False, "lastopen": QDateTime.currentDateTime()}
            #if the length of the project list it's high that 10 then delete
            #the most old
            #TODO: add the length of available projects to setting
            if len(recent_project_list) > 10:
                del recent_project_list[self.find_most_old_open(
                    recent_project_list)]
        settings.setValue('recentProjects', recent_project_list)

    def find_most_old_open(self, recent_project_list):
        listFounder = []
        for recent_project_path, content in list(recent_project_list.items()):
            listFounder.append((recent_project_path, int(
                content["lastopen"].toString("yyyyMMddHHmmzzz"))))
        listFounder = sorted(listFounder, key=lambda date: listFounder[1],
                             reverse=True)   # sort by date last used
        return listFounder[0][0]

    def reject(self):
        if self.parent() is None:
            self.dockWidget.emit(self)

    def closeEvent(self, event):
        self.dockWidget.emit(self)
        event.ignore()

    def context_menu_for_root(self):
        if not self.current_tree:
            # en vez de un mensaje, colorear el area de projecto...
            # el area de projecto debería decir 'Sin Projectos'/'without Projects'
            # QMessageBox.information(self, translations.TR_INFO_TITLE_PROJECT_PROPERTIES,
            #     translations.TR_INFO_MESSAGE_PROJECT_PROPERTIES)
            return
        menu = QMenu(self)
        path = self.current_tree.project.path
        action_add_file = menu.addAction(QIcon(":img/new"),
                                         translations.TR_ADD_NEW_FILE)
        action_add_folder = menu.addAction(QIcon(
            ":img/openProj"), translations.TR_ADD_NEW_FOLDER)
        action_create_init = menu.addAction(translations.TR_CREATE_INIT)
        action_add_file.triggered['bool'].connect(lambda s,_path=path: self.current_tree._add_new_file(_path))
        action_add_folder.triggered['bool'].connect(lambda s,_path=path: self.current_tree._add_new_folder(_path))
        action_create_init.triggered['bool'].connect(lambda s,_path=path: self.current_tree._create_init(_path))
        menu.addSeparator()
        actionRunProject = menu.addAction(QIcon(
            ":img/play"), translations.TR_RUN_PROJECT)
        actionRunProject.triggered['bool'].connect(lambda s: self.current_tree._execute_project())
        if self.current_tree._added_to_console:
            actionRemoveFromConsole = menu.addAction(
                translations.TR_REMOVE_PROJECT_FROM_PYTHON_CONSOLE)
            actionRemoveFromConsole.triggered['bool'].connect(lambda s: self.current_tree._remove_project_from_console())
        else:
            actionAdd2Console = menu.addAction(
                translations.TR_ADD_PROJECT_TO_PYTHON_CONSOLE)
            actionAdd2Console.triggered['bool'].connect(lambda s: self.current_tree._add_project_to_console())
        actionShowFileSizeInfo = menu.addAction(translations.TR_SHOW_FILESIZE)
        actionShowFileSizeInfo.triggered['bool'].connect(lambda s: self.current_tree.show_filesize_info())
        actionProperties = menu.addAction(QIcon(":img/pref"),
                                          translations.TR_PROJECT_PROPERTIES)
        actionProperties.triggered['bool'].connect(lambda s: self.current_tree.open_project_properties())

        menu.addSeparator()
        action_close = menu.addAction(
            self.style().standardIcon(QStyle.SP_DialogCloseButton),
            translations.TR_CLOSE_PROJECT)
        action_close.triggered['bool'].connect(lambda s: self.current_tree._close_project())
        #menu for the project
        for m in self.current_tree.extra_menus_by_scope['project']:
            if isinstance(m, QMenu):
                menu.addSeparator()
                menu.addMenu(m)

        #show the menu!
        menu.exec_(QCursor.pos())

    def open_project_properties(self):
        print("open_project_properties-.-.-.-.-")
        _prj = self.current_project
        if _prj:
            proj = project_properties_widget.ProjectProperties(_prj, self)
            proj.show()
            return
        
        QMessageBox.information(self, translations.TR_INFO_TITLE_PROJECT_PROPERTIES,
                translations.TR_INFO_MESSAGE_PROJECT_PROPERTIES)
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()
Ejemplo n.º 16
0
class MainView(QLabel):

    DirPath = 'Images'

    def __init__(self, *args, **kwargs):
        super(MainView, self).__init__(*args, **kwargs)
        self.setScaledContents(True)
        rect = QApplication.instance().desktop().availableGeometry()
        # 桌面大小的2/3
        self.resize(int(rect.width() * 2 / 3), int(rect.height() * 2 / 3))
        # 布局
        layout = QHBoxLayout(self, spacing=0)
        layout.setContentsMargins(0, 0, 0, 0)
        Signals.setParent(self)
        NetWork.setParent(self)

        # 获取上一页图片的按钮
        layout.addWidget(
            QPushButton(self,
                        objectName='previousButton',
                        clicked=self.onPreviousPage))
        # 故事控件
        layout.addWidget(StoryView(self))
        # 层叠布局
        self.stackLayout = QStackedLayout(spacing=0)
        self.stackLayout.setContentsMargins(0, 0, 0, 0)
        layout.addLayout(self.stackLayout)

        # 获取下一页图片的按钮
        layout.addWidget(
            QPushButton(self, objectName='nextButton',
                        clicked=self.onNextPage))

        # 当前日期的图片被下载
        Signals.currentImageAdded.connect(self.loadCurrentImage)
        # 单个item鼠标悬停离开信号
        Signals.imageHovered.connect(self.onImageHovered)

    def closeEvent(self, event):
        """关闭窗口时保存窗口的截图文件"""
        os.makedirs(self.DirPath, exist_ok=True)
        self.grab().save(os.path.join(self.DirPath, 'tmp.jpg'))
        super(MainView, self).closeEvent(event)

    def onImageHovered(self, hovered, image):
        self.setPixmap(QPixmap.fromImage(image) if hovered else self.oldImage)

    def onPreviousPage(self):
        """上一页"""
        index = self.stackLayout.currentIndex()
        if index > 0:
            index -= 1
            self.stackLayout.setCurrentIndex(index)

    def onNextPage(self):
        """下一页"""
        index = self.stackLayout.currentIndex()
        count = self.stackLayout.count() - 1
        if index < count:
            index += 1
            self.stackLayout.setCurrentIndex(index)

    def splist(self, src, length):
        # 等分列表
        return (src[i:i + length] for i in range(len(src)) if i % length == 0)

    def addImages(self, _, datas):
        """解析json数据并生成层叠2x2的网格页面"""
        try:
            imagesGroup = self.splist(
                json.loads(datas.decode()).get('images', []), 4)  # 每组4个
        except Exception as e:
            print(e)
            imagesGroup = []
        for images in imagesGroup:
            pageView = PageView(self)
            pageView.addImages(images)
            self.stackLayout.addWidget(pageView)
        # 设置当前索引
        self.stackLayout.setCurrentIndex(0)

    def loadCurrentImage(self, path):
        """加载当前日期的图片作为背景"""
        self.oldImage = QPixmap(path)
        self.setPixmap(self.oldImage)
        # 延迟1秒后显示
        QTimer.singleShot(1000, self.onShow)

    def onShow(self):
        self.setCursor(Qt.ArrowCursor)
        self.setVisible(True)
        Signals.splashClosed.emit(self)  # 通知关闭启动界面

    def initData(self):
        """加载api接口数据"""
        # 获取最近几天的
        url = 'https://cn.bing.com/HPImageArchive.aspx?format=js&idx=-1&n=8'
        NetWork.get(self.createRequest(url, self.addImages))
        # 获取之前的
        url = 'https://cn.bing.com/HPImageArchive.aspx?format=js&idx=7&n=8'
        NetWork.get(self.createRequest(url, self.addImages))
        # 获取每日故事
        url = 'http://cn.bing.com/cnhp/coverstory/'
        NetWork.get(self.createRequest(url, Signals.storyAdded.emit))

    def createRequest(self, url, callback):
        """创建网络请求"""
        req = QNetworkRequest(QUrl(url))
        # 回调函数用于加载图片显示
        req.setAttribute(QNetworkRequest.User + 3, callback)
        return req
Ejemplo n.º 17
0
class mainWindow(QMainWindow):
    end_game = False

    def __init__(self):
        super().__init__()
        self.setWindowTitle('Oczko 21')
        self.setGeometry(400, 40, 700, 640)
        self.create_welcome_layout()
        self.stacked_layout = QStackedLayout()
        self.stacked_layout.addWidget(self.welcome_widget)

        self.central_widget = QWidget()
        self.central_widget.setLayout(self.stacked_layout)
        self.setCentralWidget(self.central_widget)

        #====================Create New Game Layout=====================
        self.create_new_game_layout()
        self.stacked_layout.addWidget(self.new_game_widget)

        #==========================MAIN MENU====================================
        self.statusBar()
        newGame = QAction('&New Game', self)
        newGame.setStatusTip('Starts a new game...')
        newGame.triggered.connect(self.newGame_opt)

        help = QAction('&Help', self)
        help.setStatusTip('Help...')
        help.triggered.connect(self.help_opt)

        quitGame = QAction('&Quit', self)
        quitGame.setStatusTip('Quits the game...')
        quitGame.triggered.connect(self.quit_opt)

        mainMenu = self.menuBar()

        optionsMenu = mainMenu.addMenu('&Options')
        optionsMenu.addAction(newGame)
        optionsMenu.addAction(help)
        optionsMenu.addAction(quitGame)

        #=======================END MAIN MENU===========================================

    def newGame_opt(self):  #options from menu bar

        if self.stacked_layout.currentIndex() != 0:
            choice = QMessageBox.question(self, 'Start a new game',
                                          'Do you want to start a new game?',
                                          QMessageBox.Yes | QMessageBox.No)

            if choice == QMessageBox.Yes:
                self.new_game_radio_button.check_first()
                self.stacked_layout.setCurrentIndex(1)
                self.player1_line_edit.setText('Player 1')
                self.player2_line_edit.setText('Player 2')
            else:
                pass

        else:
            self.new_game_radio_button.check_first()
            self.stacked_layout.setCurrentIndex(1)
            self.player1_line_edit.setText('Player 1')
            self.player2_line_edit.setText('Player 2')

    def quit_opt(self):  #options from menu bar

        choice = QMessageBox.question(self, 'Exit',
                                      'Do you really want to exit the game?',
                                      QMessageBox.Yes | QMessageBox.No)

        if choice == QMessageBox.Yes:
            sys.exit()
        else:
            pass

    def help_opt(self):  # options from menu bar

        self.dialog = HelpWindow()
        self.dialog.show()

    @classmethod
    def end_game_change_value(cls,
                              value):  #method used to verify if game has ended
        cls.end_game = value

    def create_welcome_layout(self):  #first layout

        self.welcome_layout = QVBoxLayout()
        self.welcome_widget = QWidget()
        self.welcome_widget.setLayout(self.welcome_layout)

    def create_new_game_layout(self):  #start new game layout (new game menu)

        self.player1_label = QLabel('First player name:')
        self.player2_label = QLabel('Second player name:')

        self.player1_line_edit = QLineEdit()
        self.player2_line_edit = QLineEdit()

        self.cancel_button = QPushButton('Cancel')
        self.cancel_button.setMaximumWidth(330)
        self.cancel_button.setMinimumWidth(330)
        self.cancel_button.setMinimumHeight(60)

        self.start_button = QPushButton('Start New Game')
        self.start_button.setMaximumWidth(330)
        self.start_button.setMinimumWidth(330)
        self.start_button.setMinimumHeight(60)

        self.start_button.clicked.connect(self.start_new_game)
        self.cancel_button.clicked.connect(self.cancel)

        self.player_grid = QGridLayout()
        self.new_game_grid = QGridLayout()

        #player grid
        self.player_grid.addWidget(self.player1_label, 0, 0)
        self.player_grid.addWidget(self.player2_label, 1, 0)
        self.player_grid.addWidget(self.player1_line_edit, 0, 1)
        self.player_grid.addWidget(self.player2_line_edit, 1, 1)

        #new game grid

        self.new_game_radio_button = RadioButton('Play with',
                                                 ('NPC', 'Friend'))
        self.new_game_grid.addWidget(self.new_game_radio_button, 0, 0)
        self.new_game_grid.addLayout(self.player_grid, 0, 1)
        self.new_game_grid.addWidget(self.cancel_button, 1, 0)
        self.new_game_grid.addWidget(self.start_button, 1, 1)

        self.new_game_widget = QWidget()
        self.new_game_widget.setLayout(self.new_game_grid)

    def create_game_layout(self, player_type):

        self.player1_points = QLabel('0')
        self.player1_points.setAlignment(Qt.AlignTop)
        self.player2_points = QLabel('0')
        self.player2_points.setAlignment(Qt.AlignTop)

        self.player1_name = QLabel(self.player1_line_edit.text())

        if player_type == 1:
            self.player2_name = QLabel(self.player2_line_edit.text() +
                                       ' (NPC)')
        else:
            self.player2_name = QLabel(self.player2_line_edit.text())

        self.points1_label = QLabel('Points:')
        self.points1_label.setAlignment(Qt.AlignBottom)
        self.points2_label = QLabel('Points:')
        self.points2_label.setAlignment(Qt.AlignBottom)

        self.player1_card = QLabel()
        self.player2_card = QLabel()

        self.stop_button_player1 = QPushButton('Stop')
        self.pull_button_player1 = QPushButton('Pull')

        self.stop_button_player2 = QPushButton('Stop')
        self.pull_button_player2 = QPushButton('Pull')

        self.new_deal_button = QPushButton('New Deal')

        self.information_field = QPlainTextEdit('Log here baby')
        self.information_field.setMaximumHeight(243)
        self.information_field.setMaximumWidth(200)

        #Buttons connection

        self.stop_button_player1.clicked.connect(
            lambda: self.stop_card_player1(player_type))
        self.stop_button_player1.setMinimumHeight(30)
        self.pull_button_player1.clicked.connect(
            lambda: self.pull_card_player1(player_type))
        self.pull_button_player1.setMinimumHeight(30)

        self.stop_button_player2.clicked.connect(self.stop_card_player2)
        self.stop_button_player2.setMinimumHeight(30)
        self.pull_button_player2.clicked.connect(self.pull_card_player2)
        self.pull_button_player2.setMinimumHeight(30)

        self.new_deal_button.clicked.connect(self.new_deal)
        self.new_deal_button.setMaximumWidth(90)
        self.new_deal_button.setMinimumHeight(80)

        #Table

        self.table = QTableWidget()
        self.table.setRowCount(11)
        self.table.setColumnCount(2)
        self.table.setHorizontalHeaderLabels(
            ("{0};{1};").format(self.player1_name.text(),
                                self.player2_name.text()).split(";"))
        self.table.setVerticalHeaderLabels(
            ("1;2;3;4;5;6;7;8;9;10;SUM").split(";"))
        self.table.setMaximumHeight(355)
        self.table.setMaximumWidth(237)

        #Grids definitions

        self.main_game_grid = QGridLayout()
        self.board_grid = QGridLayout()
        self.table_grid = QGridLayout()
        self.below_table_grid = QGridLayout()

        self.player1_grid = QGridLayout()
        self.player2_grid = QGridLayout()

        self.player1_board_grid = QGridLayout()
        self.player2_board_grid = QGridLayout()

        self.player1_buttons_grid = QGridLayout()
        self.player2_buttons_grid = QGridLayout()

        self.player1_points_grid = QGridLayout()
        self.player2_points_grid = QGridLayout()

        #player points grids

        self.player1_points_grid.addWidget(self.points1_label, 0, 0)
        self.player1_points_grid.addWidget(self.player1_points, 1, 0)

        self.player2_points_grid.addWidget(self.points2_label, 0, 0)
        self.player2_points_grid.addWidget(self.player2_points, 1, 0)

        #player buttons grids

        self.player1_buttons_grid.addWidget(self.stop_button_player1, 0, 0)
        self.player1_buttons_grid.addWidget(self.pull_button_player1, 0, 1)

        self.player2_buttons_grid.addWidget(self.stop_button_player2, 0, 0)
        self.player2_buttons_grid.addWidget(self.pull_button_player2, 0, 1)

        #player board grids

        self.player1_board_grid.addWidget(self.player1_name, 0, 0)
        self.player1_board_grid.addWidget(self.player1_card, 0, 1)
        self.player1_board_grid.addLayout(self.player1_points_grid, 0, 3)

        self.player2_board_grid.addWidget(self.player2_name, 0, 0)
        self.player2_board_grid.addWidget(self.player2_card, 0, 1)
        self.player2_board_grid.addLayout(self.player2_points_grid, 0, 3)

        #player grids

        self.player1_grid.addLayout(self.player1_buttons_grid, 0, 0)
        self.player1_grid.addLayout(self.player1_board_grid, 1, 0)

        self.player2_grid.addLayout(self.player2_buttons_grid, 1, 0)
        self.player2_grid.addLayout(self.player2_board_grid, 0, 0)

        #below table grid

        self.below_table_grid.addWidget(self.information_field, 0, 0)
        self.below_table_grid.addWidget(self.new_deal_button, 0, 1)

        #three main grids

        self.board_grid.addLayout(self.player1_grid, 0, 0)
        self.board_grid.addLayout(self.player2_grid, 1, 0)

        self.table_grid.addWidget(self.table, 0, 0)
        self.table_grid.addLayout(self.below_table_grid, 1, 0)

        self.main_game_grid.addLayout(self.board_grid, 0, 0)
        self.main_game_grid.addLayout(self.table_grid, 0, 1)

        # layout

        self.game_widget = QWidget()
        self.game_widget.setLayout(self.main_game_grid)

    def cancel(self):

        self.stacked_layout.setCurrentIndex(0)

    def start_new_game(self):

        player_type = self.new_game_radio_button.selected_button()

        if len(self.player1_line_edit.text()) > 10 or len(
                self.player2_line_edit.text()) > 10:
            QMessageBox.information(
                self, "Too long name",
                "At least one of player's name is too long. It has to be shorter than 10 characters."
            )

        elif self.player1_line_edit.text(
        ) == '' or self.player2_line_edit.text() == '':
            QMessageBox.information(
                self, "Empty name",
                "At least one of player's name is empty. Please provide correct one."
            )

        else:
            if self.stacked_layout.count() > 2:
                self.stacked_layout.removeWidget(self.game_widget)

            self.create_game_layout(player_type)
            self.stacked_layout.addWidget(self.game_widget)
            self.stacked_layout.setCurrentIndex(2)
            self.player1_score = 0
            self.player2_score = 0
            self.match = -1
            self.new_match()

    def new_match(self):
        self.end_game_change_value(False)
        self.new_deal_button.setDisabled(True)
        self.match += 1
        self.deck = Deck()
        self.turn = 0
        self.disable_player2_buttons()
        self.stop_counter = 0
        self.player1_allcards = []
        self.player2_allcards = []
        self.pixmap = QPixmap('karty\empty.png')
        self.pixmap = self.pixmap.scaledToWidth(180)
        self.player1_card.setPixmap(self.pixmap)
        self.player2_card.setPixmap(self.pixmap)
        self.information_field.setPlainText('New deal! {0} starts'.format(
            self.player1_name.text()))

    def pull_card_player1(self, player_type):
        #card pixmap
        self.pixmap1 = QPixmap(
            os.path.join('karty', '{0}.png').format(self.deck.pack[self.turn]))
        self.pixmap1 = self.pixmap1.scaledToWidth(180)
        self.player1_card.setPixmap(self.pixmap1)

        self.player1_points.setText(
            str(
                int(self.player1_points.text()) +
                self.points(self.deck.pack[self.turn][:2])))
        #log info
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} pulls and gains {1} points'.format(
                self.player1_name.text(),
                str(self.points(self.deck.pack[self.turn][:2]))))

        self.player1_allcards.append(self.deck.pack[self.turn])

        self.turn += 1
        self.stop_counter = 0
        self.disable_player1_buttons()
        if player_type == 1:
            self.game_function()
            if self.end_game == False:
                self.npc_turn()
        elif player_type == 2 and self.end_game == False:
            self.enable_player2_buttons()
            self.game_function()
        else:
            self.disable_player1_buttons()
            self.disable_player2_buttons()

    def stop_card_player1(self, player_type):

        self.stop_counter += 1
        #log info
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} stops the card'.format(self.player1_name.text()))

        self.disable_player1_buttons()

        if player_type == 1:
            self.game_function()
            if self.end_game == False:
                self.npc_turn()
        elif player_type == 2 and self.end_game == False:
            self.enable_player2_buttons()
            self.game_function()
        else:
            self.disable_player1_buttons()
            self.disable_player2_buttons()

    def pull_card_player2(self):
        #card pixmap
        self.pixmap2 = QPixmap(
            os.path.join('karty', '{0}.png').format(self.deck.pack[self.turn]))
        self.pixmap2 = self.pixmap2.scaledToWidth(180)
        self.player2_card.setPixmap(self.pixmap2)

        self.player2_points.setText(
            str(
                int(self.player2_points.text()) +
                self.points(self.deck.pack[self.turn][:2])))

        #log info
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} pulls and gains {1} points'.format(
                self.player2_name.text(),
                str(self.points(self.deck.pack[self.turn][:2]))))

        self.player2_allcards.append(self.deck.pack[self.turn])

        self.turn += 1
        self.stop_counter = 0
        self.disable_player2_buttons()

        if self.end_game == False:
            self.enable_player1_buttons()
            self.game_function()
        else:
            self.disable_player1_buttons()

    def stop_card_player2(self):

        self.disable_player2_buttons()
        self.stop_counter += 1
        #log info
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} stops the card'.format(self.player2_name.text()))

        if self.end_game == False:
            self.enable_player1_buttons()
            self.game_function()

    def game_function(self):  #check whether there is a winning result

        if int(self.player1_points.text()) == 21 and int(
                self.player2_points.text()) == 21:
            self.draw()

        if int(self.player1_points.text()) == 21 and self.stop_counter == 1:
            self.player1_wins()

        if int(self.player2_points.text()) == 21 and self.stop_counter == 1:
            self.player2_wins()

        # =====================Two Aces========================

        if int(self.player1_points.text()
               ) == 22 and 'AA' in self.player1_allcards[
                   0] and 'AA' in self.player1_allcards[1]:
            self.player1_wins()
            self.information_field.setPlainText(
                self.information_field.toPlainText() +
                '\n{0} has two Aces!'.format(self.player1_name.text()))

        if int(self.player2_points.text()
               ) == 22 and 'AA' in self.player2_allcards[
                   0] and 'AA' in self.player2_allcards[1]:
            self.player2_wins()
            self.information_field.setPlainText(
                self.information_field.toPlainText() +
                '\n{0} has two Aces!'.format(self.player1_name.text()))

        # ==================================================================

        #============================Two times Stop button in row============================

        if self.stop_counter == 2:
            if int(self.player1_points.text()) > int(
                    self.player2_points.text()):
                self.player1_wins()

            elif int(self.player1_points.text()) < int(
                    self.player2_points.text()):
                self.player2_wins()

            else:
                self.draw()

        if int(self.player1_points.text()) > 21:  # player 1 exceeds 21 points
            self.information_field.setPlainText(
                self.information_field.toPlainText() + '. 21 is exceeded!')
            self.player2_wins()

        if int(self.player2_points.text()) > 21:  # player 2 exceeds 21 points
            self.disable_player1_buttons()
            self.information_field.setPlainText(
                self.information_field.toPlainText() + '. 21 is exceeded!')
            self.player1_wins()

    def npc_turn(self):  #determines when npc pulls or stops the card
        time.sleep(0.5)
        if int(self.player1_points.text()) == 21 and int(
                self.player2_points.text()) in [18, 19]:
            self.pull_card_player2()
        elif int(self.player1_points.text()) == 21 and int(
                self.player2_points.text()) == 20:
            self.stop_card_player2()
        elif int(self.player1_points.text()) >= 21:
            self.stop_card_player2()
        elif int(self.player1_points.text()) >= int(
                self.player2_points.text()) or int(
                    self.player2_points.text()) <= 11:
            self.pull_card_player2()
        elif int(self.player2_points.text()) == 12:
            if random.randint(0, 100) < 85:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 13:
            if random.randint(0, 100) < 80:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 14:
            if random.randint(0, 100) < 70:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 15:
            if random.randint(0, 100) < 50:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 16:
            if random.randint(0, 100) < 35:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 17:
            if random.randint(0, 100) < 20:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) >= 18:
            if random.randint(0, 100) < 5:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        else:
            self.stop_card_player2()

    def player1_wins(self):  #action when player 1 wins
        self.player1_score += 1
        self.sum_rows()
        self.disable_player1_buttons()
        self.disable_player2_buttons()
        self.table.setItem(self.match, 0, QTableWidgetItem('1'))
        self.table.setItem(self.match, 1, QTableWidgetItem('0'))
        self.end_game_change_value(True)
        #log
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} wins the deal with {1} points!'.format(
                self.player1_name.text(), self.player1_points.text()))
        if self.match < 9:
            self.new_deal_button.setDisabled(False)
        else:
            self.result_message(self.player1_score, self.player2_score)

    def player2_wins(self):  #action when player 2 wins
        self.player2_score += 1
        self.sum_rows()
        self.disable_player1_buttons()
        self.disable_player2_buttons()
        self.table.setItem(self.match, 0, QTableWidgetItem('0'))
        self.table.setItem(self.match, 1, QTableWidgetItem('1'))
        self.end_game_change_value(True)
        #log
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} wins the deal with {1} points!'.format(
                self.player2_name.text(), self.player2_points.text()))
        if self.match < 9:
            self.new_deal_button.setDisabled(False)
        else:
            self.result_message(self.player1_score, self.player2_score)

    def draw(self):  #action when there is a draw
        self.disable_player1_buttons()
        self.disable_player2_buttons()
        self.table.setItem(self.match, 0, QTableWidgetItem('0'))
        self.table.setItem(self.match, 1, QTableWidgetItem('0'))
        self.end_game_change_value(True)
        #log
        self.information_field.setPlainText(
            self.information_field.toPlainText() + '\nDraw!')
        if self.match < 9:
            self.new_deal_button.setDisabled(False)
        else:
            self.result_message(self.player1_score, self.player2_score)

    def result_message(self, player1_score, player2_score):
        if player1_score > player2_score:
            QMessageBox.information(
                self, "{0} won!".format(self.player1_name.text()),
                "The score is {0}:{1}. Good luck next time {2}!".format(
                    player1_score, player2_score, self.player2_name.text()))
        elif player1_score < player2_score:
            QMessageBox.information(
                self, "{0} won!".format(self.player2_name.text()),
                "The score is {0}:{1}. Good luck next time {2}!".format(
                    player2_score, player1_score, self.player1_name.text()))
        else:
            QMessageBox.information(
                self, "Draw!",
                "Both players scored {0} points".format(player1_score))

    def disable_player1_buttons(self):
        self.pull_button_player1.setDisabled(True)
        self.stop_button_player1.setDisabled(True)

    def enable_player1_buttons(self):
        self.pull_button_player1.setDisabled(False)
        self.stop_button_player1.setDisabled(False)

    def disable_player2_buttons(self):
        self.pull_button_player2.setDisabled(True)
        self.stop_button_player2.setDisabled(True)

    def enable_player2_buttons(self):
        self.pull_button_player2.setDisabled(False)
        self.stop_button_player2.setDisabled(False)

    def points(self,
               value):  #method to match card's name with its points value
        score = {
            '11': 1,
            '22': 2,
            '33': 3,
            '44': 4,
            '55': 5,
            '66': 6,
            '77': 7,
            '88': 8,
            '99': 9,
            '10': 10,
            'WW': 2,
            'DD': 3,
            'KK': 4,
            'AA': 11
        }
        return score[value]

    def sum_rows(self):  #sums rows from the table
        self.table.setItem(10, 0, QTableWidgetItem(str(self.player1_score)))
        self.table.setItem(10, 1, QTableWidgetItem(str(self.player2_score)))

    def new_deal(self):  #start new deal

        self.enable_player1_buttons()
        self.player1_card.setText('')
        self.player2_card.setText('')
        self.player1_points.setText('0')
        self.player2_points.setText('0')
        self.new_match()
Ejemplo n.º 18
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()
Ejemplo n.º 19
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())
Ejemplo n.º 20
0
class ProjectTreeColumn(QDialog):

    # Signals
    dockWidget = pyqtSignal('PyQt_PyObject')
    undockWidget = pyqtSignal()
    changeTitle = pyqtSignal('PyQt_PyObject', 'QString')
    updateLocator = pyqtSignal()

    def __init__(self, parent=None):
        super(ProjectTreeColumn, self).__init__(parent)
        vbox = QVBoxLayout(self)
        # vbox.setSizeConstraint(QVBoxLayout.SetDefaultConstraint)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)
        self._buttons = []
        combo_container = ui_tools.StyledBar()
        combo_container.setProperty('gradient', True)
        combo_layout = QVBoxLayout(combo_container)
        combo_layout.setContentsMargins(0, 0, 0, 0)
        self._combo_project = QComboBox()
        combo_layout.addWidget(self._combo_project)
        self._combo_project.setProperty("gradient", True)
        self._combo_project.setContextMenuPolicy(Qt.CustomContextMenu)
        vbox.addWidget(combo_container)
        self._projects_area = QStackedLayout()
        logger.debug("This is the projects area")
        vbox.addLayout(self._projects_area)

        self.projects = []

        self._combo_project.currentIndexChanged[int].connect(
            self._change_current_project)
        self._combo_project.customContextMenuRequested[
            'const QPoint&'].connect(self.context_menu_for_root)

        connections = (
            {
                'target': 'main_container',
                'signal_name': 'addToProject(QString)',
                'slot': self._add_file_to_project
            },
            {
                'target': 'main_container',
                'signal_name': 'showFileInExplorer(QString)',
                'slot': self._show_file_in_explorer
            },
        )
        IDE.register_service('projects_explorer', self)
        IDE.register_signals('projects_explorer', connections)
        ExplorerContainer.register_tab(translations.TR_TAB_PROJECTS, self)

        # FIXME: Should have a ninja settings object that stores tree state
        # FIXME: Or bettter, application data object
        # TODO: check this:
        # self.connect(ide, SIGNAL("goingDown()"),
        #    self.tree_projects.shutdown)

        # def close_project_signal():
        #    self.emit(SIGNAL("updateLocator()"))

    def install_tab(self):
        ide = IDE.get_service('ide')
        ui_tools.install_shortcuts(self, actions.PROJECTS_TREE_ACTIONS, ide)

        ide.goingDown.connect(self.close)

    def load_session_projects(self, projects):
        for project in projects:
            if os.path.exists(project):
                self._open_project_folder(project)

    def open_project_folder(self, folderName=None):
        if settings.WORKSPACE:
            directory = settings.WORKSPACE
        else:
            directory = os.path.expanduser("~")

        if folderName is None:
            folderName = QFileDialog.getExistingDirectory(
                self, translations.TR_OPEN_PROJECT_DIRECTORY, directory)
            logger.debug("Choosing Foldername")
        if folderName:
            if not file_manager.folder_exists(folderName):
                QMessageBox.information(
                    self, translations.TR_PROJECT_NONEXIST_TITLE,
                    translations.TR_PROJECT_NONEXIST % folderName)
                return
            logger.debug("Opening %s" % folderName)
            for p in self.projects:
                if p.project.path == folderName:
                    QMessageBox.information(
                        self, translations.TR_PROJECT_PATH_ALREADY_EXIST_TITLE,
                        translations.TR_PROJECT_PATH_ALREADY_EXIST %
                        folderName)
                    return
            self._open_project_folder(folderName)

    def _open_project_folder(self, folderName):
        ninjaide = IDE.get_service("ide")
        # TODO: handle exception when .nja file is empty
        project = NProject(folderName)
        qfsm = ninjaide.filesystem.open_project(project)
        if qfsm:
            self.add_project(project)
            self.save_recent_projects(folderName)
            # FIXME: show editor area?
            # main_container = IDE.get_service('main_container')
            # if main_container:
            #    main_container.show_editor_area()
            if len(self.projects) > 1:
                title = "%s (%s)" % (translations.TR_TAB_PROJECTS,
                                     len(self.projects))
            else:
                title = translations.TR_TAB_PROJECTS
            self.changeTitle.emit(self, title)

    def _add_file_to_project(self, path):
        """Add the file for 'path' in the project the user choose here."""
        if self._projects_area.count() > 0:
            pathProject = [self.current_project]
            addToProject = add_to_project.AddToProject(pathProject, self)
            addToProject.exec_()
            if not addToProject.pathSelected:
                return
            main_container = IDE.get_service('main_container')
            if not main_container:
                return
            editorWidget = main_container.get_current_editor()
            if not editorWidget.file_path:
                name = QInputDialog.getText(
                    None, translations.TR_ADD_FILE_TO_PROJECT,
                    translations.TR_FILENAME + ": ")[0]
                if not name:
                    QMessageBox.information(
                        self, translations.TR_INVALID_FILENAME,
                        translations.TR_INVALID_FILENAME_ENTER_A_FILENAME)
                    return
            else:
                name = file_manager.get_basename(editorWidget.file_path)
            new_path = file_manager.create_path(addToProject.pathSelected,
                                                name)
            ide_srv = IDE.get_service("ide")
            old_file = ide_srv.get_or_create_nfile(path)
            new_file = old_file.save(editorWidget.text(), new_path)
            # FIXME: Make this file replace the original in the open tab
        else:
            pass
            # Message about no project

    def _show_file_in_explorer(self, path):
        '''Iterate through the list of available projects and show
        the current file in the explorer view for the first
        project that contains it (i.e. if the same file is
        included in multiple open projects, the path will be
        expanded for the first project only).
        Note: This slot is connected to the main container's
        "showFileInExplorer(QString)" signal.'''
        central = IDE.get_service('central_container')
        if central and not central.is_lateral_panel_visible():
            return
        for project in self.projects:
            index = project.model().index(path)
            if index.isValid():
                # This highlights the index in the tree for us
                project.scrollTo(index, QAbstractItemView.EnsureVisible)
                project.setCurrentIndex(index)
                break

    def add_project(self, project):
        if project not in self.projects:
            self._combo_project.addItem(project.name)
            ptree = TreeProjectsWidget(project)
            self._projects_area.addWidget(ptree)
            ptree.closeProject['PyQt_PyObject'].connect(self._close_project)
            pmodel = project.model
            ptree.setModel(pmodel)
            pindex = pmodel.index(pmodel.rootPath())
            ptree.setRootIndex(pindex)
            self.projects.append(ptree)
            current_index = self._projects_area.count()
            self._projects_area.setCurrentIndex(current_index - 1)
            self._combo_project.setCurrentIndex(current_index - 1)

    def _close_project(self, widget):
        """Close the project related to the tree widget."""
        index = self._projects_area.currentIndex()
        self.projects.remove(widget)
        self._projects_area.takeAt(index)
        self._combo_project.removeItem(index)
        index = self._combo_project.currentIndex()
        self._projects_area.setCurrentIndex(index)
        ninjaide = IDE.get_service('ide')
        ninjaide.filesystem.close_project(widget.project.path)
        widget.deleteLater()
        if len(self.projects) > 1:
            title = "%s (%s)" % (translations.TR_TAB_PROJECTS,
                                 len(self.projects))
        else:
            title = translations.TR_TAB_PROJECTS
        self.changeTitle.emit(self, title)
        self.updateLocator.emit()

    def _change_current_project(self, index):
        self._projects_area.setCurrentIndex(index)

    def close_opened_projects(self):
        for project in reversed(self.projects):
            self._close_project(project)

    def save_project(self):
        """Save all the opened files that belongs to the actual project."""
        if self._projects_area.count() > 0:
            path = self.current_project.path
            main_container = IDE.get_service('main_container')
            if path and main_container:
                main_container.save_project(path)

    def create_new_project(self):
        wizard = new_project_manager.NewProjectManager(self)
        wizard.show()

    @property
    def current_project(self):
        if self._projects_area.count() > 0:
            return self._projects_area.currentWidget().project

    @property
    def current_tree(self):
        return self._projects_area.currentWidget()

    def set_current_item(self, path):
        if self.current_project is not None:
            self.current_tree.set_current_item(path)

    def save_recent_projects(self, folder):
        settings = IDE.data_settings()
        recent_project_list = settings.value('recentProjects', {})
        # if already exist on the list update the date time
        projectProperties = json_manager.read_ninja_project(folder)
        name = projectProperties.get('name', '')
        description = projectProperties.get('description', '')

        if name == '':
            name = file_manager.get_basename(folder)

        if description == '':
            description = translations.TR_NO_DESCRIPTION

        if folder in recent_project_list:
            properties = recent_project_list[folder]
            properties["lastopen"] = QDateTime.currentDateTime()
            properties["name"] = name
            properties["description"] = description
            recent_project_list[folder] = properties
        else:
            recent_project_list[folder] = {
                "name": name,
                "description": description,
                "isFavorite": False,
                "lastopen": QDateTime.currentDateTime()
            }
            # if the length of the project list it's high that 10 then delete
            # the most old
            # TODO: add the length of available projects to setting
            if len(recent_project_list) > 10:
                del recent_project_list[self.find_most_old_open(
                    recent_project_list)]
        settings.setValue('recentProjects', recent_project_list)

    def find_most_old_open(self, recent_project_list):
        listFounder = []
        for recent_project_path, content in list(recent_project_list.items()):
            listFounder.append(
                (recent_project_path,
                 int(content["lastopen"].toString("yyyyMMddHHmmzzz"))))
        listFounder = sorted(listFounder,
                             key=lambda date: listFounder[1],
                             reverse=True)  # sort by date last used
        return listFounder[0][0]

    def reject(self):
        if self.parent() is None:
            self.dockWidget.emit(self)

    def closeEvent(self, event):
        self.dockWidget.emit(self)
        event.ignore()

    def context_menu_for_root(self):
        menu = QMenu(self)
        path = self.current_tree.project.path
        action_add_file = menu.addAction(QIcon(":img/new"),
                                         translations.TR_ADD_NEW_FILE)
        action_add_folder = menu.addAction(QIcon(":img/openProj"),
                                           translations.TR_ADD_NEW_FOLDER)
        action_create_init = menu.addAction(translations.TR_CREATE_INIT)

        # self.connect(action_add_file, SIGNAL("triggered()"),
        #             lambda: self.current_tree._add_new_file(path))
        # self.connect(action_add_folder, SIGNAL("triggered()"),
        #             lambda: self.current_tree._add_new_folder(path))
        # self.connect(action_create_init, SIGNAL("triggered()"),
        #             lambda: self.current_tree._create_init(path))
        # menu.addSeparator()
        # actionRunProject = menu.addAction(QIcon(
        #    ":img/play"), translations.TR_RUN_PROJECT)
        # self.connect(actionRunProject, SIGNAL("triggered()"),
        #             self.current_tree._execute_project)
        # if self.current_tree._added_to_console:
        #    actionRemoveFromConsole = menu.addAction(
        #        translations.TR_REMOVE_PROJECT_FROM_PYTHON_CONSOLE)
        #    self.connect(actionRemoveFromConsole, SIGNAL("triggered()"),
        #                 self.current_tree._remove_project_from_console)
        # else:
        #    actionAdd2Console = menu.addAction(
        #        translations.TR_ADD_PROJECT_TO_PYTHON_CONSOLE)
        #    self.connect(actionAdd2Console, SIGNAL("triggered()"),
        #                 self.current_tree._add_project_to_console)
        # actionShowFileSizeInfo = menu.addAction(
        #                          translations.TR_SHOW_FILESIZE)
        # self.connect(actionShowFileSizeInfo, SIGNAL("triggered()"),
        #             self.current_tree.show_filesize_info)
        # actionProperties = menu.addAction(QIcon(":img/pref"),
        #                                  translations.TR_PROJECT_PROPERTIES)
        # self.connect(actionProperties, SIGNAL("triggered()"),
        #             self.current_tree.open_project_properties)
        action_properties = menu.addAction(translations.TR_PROJECT_PROPERTIES)
        action_properties.triggered.connect(
            self.current_tree.open_project_properties)
        # menu.addSeparator()
        action_close = menu.addAction(translations.TR_CLOSE_PROJECT)
        action_add_file.triggered.connect(
            lambda: self.current_tree._add_new_file(path))
        action_add_folder.triggered.connect(
            lambda: self.current_tree._add_new_folder(path))
        action_close.triggered.connect(self.current_tree._close_project)
        # self.connect(action_close, SIGNAL("triggered()"),
        #             self.current_tree._close_project)
        # menu for the project
        for m in self.current_tree.extra_menus_by_scope['project']:
            if isinstance(m, QMenu):
                menu.addSeparator()
                menu.addMenu(m)

        # show the menu!
        menu.exec_(QCursor.pos())
Ejemplo n.º 21
0
class ProjectTreeColumn(QDialog):

    # Signalsnproject =
    dockWidget = pyqtSignal('PyQt_PyObject')
    undockWidget = pyqtSignal()
    changeTitle = pyqtSignal('PyQt_PyObject', 'QString')
    updateLocator = pyqtSignal()
    activeProjectChanged = pyqtSignal()

    def __init__(self, parent=None):
        super(ProjectTreeColumn, self).__init__(parent)
        vbox = QVBoxLayout(self)
        vbox.setSizeConstraint(QVBoxLayout.SetDefaultConstraint)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)
        self._buttons = []
        frame = QFrame()
        frame.setObjectName("actionbar")
        box = QVBoxLayout(frame)
        box.setContentsMargins(1, 1, 1, 1)
        box.setSpacing(0)

        self._combo_project = QComboBox()
        self._combo_project.setSizePolicy(QSizePolicy.Expanding,
                                          QSizePolicy.Fixed)
        self._combo_project.setSizeAdjustPolicy(
            QComboBox.AdjustToMinimumContentsLengthWithIcon)
        self._combo_project.setObjectName("combo_projects")
        box.addWidget(self._combo_project)
        vbox.addWidget(frame)
        self._combo_project.setContextMenuPolicy(Qt.CustomContextMenu)
        self._projects_area = QStackedLayout()
        logger.debug("This is the projects area")
        vbox.addLayout(self._projects_area)

        # Empty widget
        self._empty_proj = QLabel(translations.TR_NO_PROJECTS)
        self._empty_proj.setAlignment(Qt.AlignCenter)
        self._empty_proj.setAutoFillBackground(True)
        self._empty_proj.setBackgroundRole(QPalette.Base)
        self._projects_area.addWidget(self._empty_proj)
        self._projects_area.setCurrentWidget(self._empty_proj)

        self.projects = []

        self._combo_project.activated.connect(self._change_current_project)
        self._combo_project.customContextMenuRequested[
            'const QPoint&'].connect(self.context_menu_for_root)

        connections = (
            {
                "target": "main_container",
                "signal_name": "addToProject",
                "slot": self._add_file_to_project
            },
            {
                "target": "main_container",
                "signal_name": "showFileInExplorer",
                "slot": self._show_file_in_explorer
            },
        )
        IDE.register_service('projects_explorer', self)
        IDE.register_signals('projects_explorer', connections)
        ExplorerContainer.register_tab(translations.TR_TAB_PROJECTS, self)

        # FIXME: Should have a ninja settings object that stores tree state
        # FIXME: Or bettter, application data object
        # TODO: check this:
        # self.connect(ide, SIGNAL("goingDown()"),
        #    self.tree_projects.shutdown)

    def install_tab(self):
        ide = IDE.get_service('ide')
        ui_tools.install_shortcuts(self, actions.PROJECTS_TREE_ACTIONS, ide)
        ide.goingDown.connect(self._on_ide_going_down)

    def _on_ide_going_down(self):
        """Save some settings before close"""
        if self.current_tree is None:
            return
        ds = IDE.data_settings()
        show_filesize = not bool(self.current_tree.isColumnHidden(1))
        ds.setValue("projectsExplorer/showFileSize", show_filesize)

    def load_session_projects(self, projects):
        for project in projects:
            if os.path.exists(project):
                self._open_project_folder(project)

    def open_project_folder(self, folderName=None):
        if settings.WORKSPACE:
            directory = settings.WORKSPACE
        else:
            directory = os.path.expanduser("~")

        if folderName is None:
            folderName = QFileDialog.getExistingDirectory(
                self, translations.TR_OPEN_PROJECT_DIRECTORY, directory)
            logger.debug("Choosing Foldername")
        if folderName:
            if not file_manager.folder_exists(folderName):
                QMessageBox.information(
                    self, translations.TR_PROJECT_NONEXIST_TITLE,
                    translations.TR_PROJECT_NONEXIST % folderName)
                return
            logger.debug("Opening %s" % folderName)
            for p in self.projects:
                if p.project.path == folderName:
                    QMessageBox.information(
                        self, translations.TR_PROJECT_PATH_ALREADY_EXIST_TITLE,
                        translations.TR_PROJECT_PATH_ALREADY_EXIST %
                        folderName)
                    return
            self._open_project_folder(folderName)

    def _open_project_folder(self, folderName):
        ninjaide = IDE.get_service("ide")
        # TODO: handle exception when .nja file is empty
        project = NProject(folderName)
        qfsm = ninjaide.filesystem.open_project(project)
        if qfsm:
            self.add_project(project)
            self.save_recent_projects(folderName)
            # FIXME: show editor area?
            if len(self.projects) > 1:
                title = "%s (%s)" % (translations.TR_TAB_PROJECTS,
                                     len(self.projects))
            else:
                title = translations.TR_TAB_PROJECTS
            self.changeTitle.emit(self, title)

    def _add_file_to_project(self, path):
        """Add the file for 'path' in the project the user choose here."""
        if self._projects_area.count() > 0:
            path_project = [self.current_project]
            _add_to_project = add_to_project.AddToProject(path_project, self)
            _add_to_project.exec_()
            if not _add_to_project.path_selected:
                return
            main_container = IDE.get_service('main_container')
            if not main_container:
                return
            editorWidget = main_container.get_current_editor()
            if not editorWidget.file_path:
                name = QInputDialog.getText(
                    None, translations.TR_ADD_FILE_TO_PROJECT,
                    translations.TR_FILENAME + ": ")[0]
                if not name:
                    QMessageBox.information(
                        self, translations.TR_INVALID_FILENAME,
                        translations.TR_INVALID_FILENAME_ENTER_A_FILENAME)
                    return
            else:
                name = file_manager.get_basename(editorWidget.file_path)
            new_path = file_manager.create_path(_add_to_project.path_selected,
                                                name)
            ide_srv = IDE.get_service("ide")
            old_file = ide_srv.get_or_create_nfile(path)
            new_file = old_file.save(editorWidget.text(), new_path)
            # FIXME: Make this file replace the original in the open tab
        else:
            pass
            # Message about no project

    def _show_file_in_explorer(self, path):
        '''Iterate through the list of available projects and show
        the current file in the explorer view for the first
        project that contains it (i.e. if the same file is
        included in multiple open projects, the path will be
        expanded for the first project only).
        Note: This slot is connected to the main container's
        "showFileInExplorer(QString)" signal.'''
        central = IDE.get_service('central_container')
        if central and not central.is_lateral_panel_visible():
            return
        for project in self.projects:
            index = project.model().index(path)
            if index.isValid():
                # This highlights the index in the tree for us
                project.scrollTo(index, QAbstractItemView.EnsureVisible)
                project.setCurrentIndex(index)
                break

    def add_project(self, project):
        if project not in self.projects:
            self._combo_project.addItem(project.name)
            tooltip = utils.path_with_tilde_homepath(project.path)
            self._combo_project.setToolTip(tooltip)
            index = self._combo_project.count() - 1
            self._combo_project.setItemData(index, project)
            ptree = TreeProjectsWidget(project)
            self._projects_area.addWidget(ptree)
            ptree.closeProject['PyQt_PyObject'].connect(self._close_project)
            pmodel = project.model
            ptree.setModel(pmodel)
            pindex = pmodel.index(pmodel.rootPath())
            ptree.setRootIndex(pindex)
            self.projects.append(ptree)
            self._projects_area.setCurrentWidget(ptree)  # Can be empty widget
            self._combo_project.setCurrentIndex(index)

        # FIXME: improve?
        #     self._combo_project.currentIndexChanged[int].connect(
        #         self._change_current_project)

    def _close_project(self, widget):
        """Close the project related to the tree widget."""
        index = self._combo_project.currentIndex()
        self.projects.remove(widget)
        # index + 1 is necessary because the widget
        # with index 0 is the empty widget
        self._projects_area.takeAt(index + 1)
        self._combo_project.removeItem(index)
        index = self._combo_project.currentIndex()
        self._projects_area.setCurrentIndex(index + 1)
        ninjaide = IDE.get_service('ide')
        ninjaide.filesystem.close_project(widget.project.path)
        widget.deleteLater()
        if len(self.projects) > 1:
            title = "%s (%s)" % (translations.TR_TAB_PROJECTS,
                                 len(self.projects))
        else:
            title = translations.TR_TAB_PROJECTS
        self.changeTitle.emit(self, title)
        self.updateLocator.emit()

    def _change_current_project(self, index):
        nproject = self._combo_project.itemData(index)

        ninjaide = IDE.get_service("ide")
        projects = ninjaide.get_projects()
        for project in projects.values():
            if project == nproject:
                nproject.is_current = True
            else:
                project.is_current = False
        self._projects_area.setCurrentIndex(index + 1)
        self.activeProjectChanged.emit()

    def close_opened_projects(self):
        for project in reversed(self.projects):
            self._close_project(project)

    def save_project(self):
        """Save all the opened files that belongs to the actual project."""
        if self.current_project is not None:
            path = self.current_project.path
            main_container = IDE.get_service('main_container')
            if path and main_container:
                main_container.save_project(path)

    def create_new_project(self):
        wizard = new_project_manager.NewProjectManager(self)
        wizard.show()

    @property
    def current_project(self):
        project = None
        if self._projects_area.count() > 0 and self.current_tree is not None:
            project = self.current_tree.project
        return project

    @property
    def current_tree(self):
        tree = None
        widget = self._projects_area.currentWidget()
        if isinstance(widget, TreeProjectsWidget):
            tree = widget
        return tree

    def set_current_item(self, path):
        if self.current_project is not None:
            self.current_tree.set_current_item(path)

    def save_recent_projects(self, folder):
        settings = IDE.data_settings()
        recent_project_list = settings.value('recentProjects', {})
        # if already exist on the list update the date time
        projectProperties = json_manager.read_ninja_project(folder)
        name = projectProperties.get('name', '')
        description = projectProperties.get('description', '')

        if not name:
            name = file_manager.get_basename(folder)

        if not description:
            description = translations.TR_NO_DESCRIPTION

        if folder in recent_project_list:
            properties = recent_project_list[folder]
            properties["lastopen"] = QDateTime.currentDateTime()
            properties["name"] = name
            properties["description"] = description
            recent_project_list[folder] = properties
        else:
            recent_project_list[folder] = {
                "name": name,
                "description": description,
                "isFavorite": False,
                "lastopen": QDateTime.currentDateTime()
            }
            # if the length of the project list it's high that 10 then delete
            # the most old
            # TODO: add the length of available projects to setting
            if len(recent_project_list) > MAX_RECENT_PROJECTS:
                del recent_project_list[self.find_most_old_open(
                    recent_project_list)]
        settings.setValue('recentProjects', recent_project_list)

    def find_most_old_open(self, recent_project_list):
        listFounder = []
        for recent_project_path, content in list(recent_project_list.items()):
            listFounder.append(
                (recent_project_path,
                 int(content["lastopen"].toString("yyyyMMddHHmmzzz"))))
        listFounder = sorted(listFounder,
                             key=lambda date: listFounder[1],
                             reverse=True)  # sort by date last used
        return listFounder[0][0]

    def reject(self):
        if self.parent() is None:
            self.dockWidget.emit(self)

    def closeEvent(self, event):
        self.dockWidget.emit(self)
        event.ignore()

    def context_menu_for_root(self):
        menu = QMenu(self)
        if self.current_tree is None:
            # No projects
            return
        path = self.current_tree.project.path
        # Reset index
        self.current_tree.setCurrentIndex(QModelIndex())

        action_add_file = menu.addAction(QIcon(":img/new"),
                                         translations.TR_ADD_NEW_FILE)
        action_add_folder = menu.addAction(QIcon(":img/openProj"),
                                           translations.TR_ADD_NEW_FOLDER)
        action_create_init = menu.addAction(translations.TR_CREATE_INIT)
        menu.addSeparator()
        action_run_project = menu.addAction(translations.TR_RUN_PROJECT)
        action_properties = menu.addAction(translations.TR_PROJECT_PROPERTIES)
        action_show_file_size = menu.addAction(translations.TR_SHOW_FILESIZE)
        menu.addSeparator()
        action_close = menu.addAction(translations.TR_CLOSE_PROJECT)

        # Connections
        action_add_file.triggered.connect(
            lambda: self.current_tree._add_new_file(path))
        action_add_folder.triggered.connect(
            lambda: self.current_tree._add_new_folder(path))
        action_create_init.triggered.connect(self.current_tree._create_init)
        action_run_project.triggered.connect(
            self.current_tree._execute_project)
        action_properties.triggered.connect(
            self.current_tree.open_project_properties)
        action_close.triggered.connect(self.current_tree._close_project)
        action_show_file_size.triggered.connect(
            self.current_tree.show_filesize_info)

        # menu for the project
        for m in self.current_tree.extra_menus_by_scope['project']:
            if isinstance(m, QMenu):
                menu.addSeparator()
                menu.addMenu(m)

        # show the menu!
        menu.exec_(QCursor.pos())