Пример #1
0
class mainWindow(QMainWindow):
    disableProjectMenu = pyqtSignal()
    enableProjectMenu = pyqtSignal()

    def __init__(self, parent=None):
        super(mainWindow, self).__init__(parent)
        self.ui = loadUi('UI/mainFrame.ui', self)
        self.mainWidget = QWidget(self)
        self.mainWidgetLayout = QVBoxLayout(self.mainWidget)
        self.setCentralWidget(self.mainWidget)
        self.setWindowIcon(QIcon('res/pluto.ico'))
        ###############################
        # local variables
        self.defaultDir = '.'
        self.curOpenProjectHandle = None
        self.curProjectTabManager = None
        self.openedProject = ProjectQueue()
        self.handleToTabWidget = dict()
        self.plutoVariables = plutoVariables()
        # flags

        ###############################
        # menu
        newProjectMenu = self.ui.actionNew_Project
        newProjectMenu.triggered.connect(self.newProjectDialog)
        openProjectMenu = self.ui.actionOpen_Project
        openProjectMenu.triggered.connect(self.openProjectDialog)
        saveProjectMenu = self.ui.actionSave_Project
        saveProjectMenu.triggered.connect(self.saveProject)

        self.newProjectDataSetMenu = self.ui.actionNew_DataSet
        self.newProjectDataSetMenu.triggered.connect(
            self.onNewProjectDataSetMenu)
        self.newProjectModel = self.ui.actionNew_Model
        self.newProjectModel.triggered.connect(self.onNewProjectModel)
        self.newProjectScript = self.ui.actionNew_Script
        self.newProjectScript.triggered.connect(self.onNewProjectScript)

        self.newProjectDataSetMenu.setEnabled(False)
        self.newProjectModel.setEnabled(False)
        self.newProjectScript.setEnabled(False)
        ###############################
        # init toolbar status bar
        self.toolBar = QToolBar(self)
        self.statusBar = QStatusBar(self)
        self.openAction = QAction(QIcon('res/Open.ico'), 'Open Project', self)
        self.homePageAction = QAction(QIcon('res/homepage.png'), 'HOME', self)
        self.projectAction = QAction(QIcon('res/ProjectManager.ico'),
                                     'Project Manager', self)
        ###############################
        # init widgets
        self.leftStage = QTabWidget(self)
        self.mainStage = QWidget(self)
        self.bottomStage = QWidget(self)
        self.bottomLayout = QHBoxLayout(self.bottomStage)
        self.bottomTabWidget = CollapsibleTabWidget(0, self)
        self.mainLayout = QStackedLayout(self.mainStage)
        ###############################
        # splitter
        self.vertical_splitter = QSplitter(Qt.Horizontal)
        self.horizontal_splitter = QSplitter(Qt.Vertical)
        self.downSize = 0.22 * self.height()
        ###############################
        # left stage
        self.leftTreeView = QTreeView(self)
        ###############################
        # bottom stage
        self.bottomOutputView = QTextEdit(self)
        ###############################
        # main stage
        self.scrollarea = QScrollArea(self)
        self.scrollbar = QScrollBar(self)
        self.projectList = QWidget(self.scrollarea)
        self.projectListLayout = FlowLayout()

        self.initUI()
        self.initToolBar()
        self.setContextMenuPolicy(
            Qt.NoContextMenu)  # close right click of mainWindow

    def initUI(self):
        self.mainStage.setLayout(self.mainLayout)
        # setup splitter
        self.vertical_splitter.addWidget(self.leftStage)
        self.vertical_splitter.addWidget(self.mainStage)
        self.vertical_splitter.setStretchFactor(1, 1)
        self.vertical_splitter.setCollapsible(0, False)
        self.vertical_splitter.setCollapsible(1, False)

        self.horizontal_splitter.addWidget(self.vertical_splitter)
        self.horizontal_splitter.addWidget(self.bottomStage)
        self.horizontal_splitter.setStretchFactor(1, 1)
        self.horizontal_splitter.setCollapsible(0, False)
        self.horizontal_splitter.setCollapsible(1, False)

        self.vertical_splitter.setSizes(
            [self.width() * 0.22, self.width() * 0.78])
        # self.horizontal_splitter.setSizes([self.height() * 0.78, self.height() * 0.22])
        self.horizontal_splitter.setSizes(
            [self.height() - self.downSize, self.downSize])

        self.horizontal_splitter.splitterMoved.connect(self.onHSplitterMoved)

        self.mainWidgetLayout.addWidget(self.horizontal_splitter)
        self.bottomStage.setLayout(self.bottomLayout)
        self.bottomTabWidget.setSplitter(self.horizontal_splitter)
        self.bottomLayout.addWidget(self.bottomTabWidget)
        # setup left stage
        self.leftStage.setTabPosition(QTabWidget.West)
        self.leftStage.addTab(self.leftTreeView, 'File')

        # setup bottom stage
        # self.bottomStage.setTabPosition(QTabWidget.South)
        self.bottomTabWidget.addTab(self.bottomOutputView, 'Output')
        self.bottomLayout.setContentsMargins(20, 0, 0, 0)
        # init main stage
        self.initProjectList()

        # connect
        self.disableProjectMenu.connect(self.onDisableProjectMenu)
        self.enableProjectMenu.connect(self.onEnableProjectMenu)

    def initToolBar(self):
        self.statusBar.setContentsMargins(10, 0, 0, 10)
        self.addToolBar(self.toolBar)
        self.setStatusBar(self.statusBar)

        # open
        self.openAction.setStatusTip('Open Project')
        self.openAction.triggered.connect(self.openProjectDialog)
        self.toolBar.addAction(self.openAction)

        self.homePageAction.setStatusTip('Home Page')
        self.homePageAction.triggered.connect(self.jumpToHomePage)
        self.toolBar.addAction(self.homePageAction)

        self.projectAction.setStatusTip('Project Manager')
        self.projectAction.triggered.connect(self.showOpenProject)
        self.toolBar.addAction(self.projectAction)

    def initProjectList(self):
        self.scrollarea.setWidgetResizable(True)
        self.projectList.setLayout(self.projectListLayout)
        self.scrollarea.setWidget(self.projectList)
        self.scrollarea.setVerticalScrollBar(self.scrollbar)
        self.scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        self.mainLayout.addWidget(self.scrollarea)

        # init projects from plutoVariables projectFiles
        projectHandleList = []
        # projectItemList = []
        for projectPath in self.plutoVariables.projectFiles:
            projectHandle = ProjectReader(projectPath)
            projectHandleList.append(projectHandle)

            # projectName, projectLocation, lastOpenTime, projectFiles
            projectItem = ProjectWidget(projectHandle.projectName,
                                        projectHandle.projectPath,
                                        projectHandle.lastAccessTime,
                                        projectHandle)
            projectItem.triggered.connect(self.openProject)
            self.projectListLayout.addWidget(projectItem)

    def newProjectDialog(self):
        dialog = newProjectDialog(self)
        dialog.projectInited.connect(self.onProjectInited)
        dialog.show()

    def openProject(self, handle: ProjectReader):
        if self.openedProject.isExist(handle):
            QMessageBox.information(
                self, 'open project',
                "project \"" + handle.projectName + "\" has been opened")
        else:
            print('open project:', handle.projectName)
            tabWidget = ColorTabWidget(self)
            tabManager = self.initTabWidget(tabWidget, handle)
            self.openedProject.add(handle, tabManager)
            self.mainLayout.addWidget(tabWidget)
            self.mainLayout.setCurrentIndex(self.openedProject.currentIndex)
            self.curOpenProjectHandle = handle  # self.openedProject.getHandle(self.openedProject.currentIndex)
            self.curProjectTabManager = tabManager
            self.updateProjectLastAccessTime()
            self.enableProjectMenu.emit()

    def closeProject(self):
        if self.curOpenProjectHandle:
            self.saveProject()
            self.curOpenProjectHandle = None
            gc.collect()

    def saveProject(self):  # TODO
        print('save project')
        if not self.curOpenProjectHandle:
            QMessageBox.information(self, 'Save Project', 'No open project',
                                    QMessageBox.Ok)
        else:
            self.curOpenProjectHandle.saveToYaml()
            QMessageBox.information(
                self, 'Save Project',
                'Project Saved to ' + self.curOpenProjectHandle.yamlFile,
                QMessageBox.Ok)

    def changeProjectName(self, name):
        self.curOpenProjectHandle.setProjectName(name)
        self.curOpenProjectHandle.updateToYamlDict()

    def updateProjectLastAccessTime(self):
        currentTime = datetime.utcnow()
        self.curOpenProjectHandle.setLastAccessTime(currentTime)
        self.curOpenProjectHandle.updateToYamlDict()

    def addFileToProject(self):  # TODO
        pass

    def delFileFromProject(self):  # TODO
        pass

    def openProjectDialog(self):
        dialog = QFileDialog(self)
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        dialog.setDirectory(self.defaultDir)
        projectFile, _ = dialog.getOpenFileName(
            self,
            "Open Project",
            "",
            "Project File (*.pluto);;All Files (*.*)",
            options=options)
        if projectFile:
            handle = ProjectReader(projectFile)
            self.openProject(handle)
        else:
            raise Exception('Open project failed')

    def jumpToHomePage(self):
        self.mainLayout.setCurrentIndex(0)
        self.disableProjectMenu.emit()

    def showOpenProject(self):
        # display a pop menu of current open project
        if not len(self.openedProject):
            print('no opened project')
            return
        allOpenedProjectID = self.openedProject.getAllID()
        openedProjectMenu = QMenu()
        for index, ID in enumerate(allOpenedProjectID):
            if not ID:
                continue
            handle = self.openedProject.getHandle(index)
            oneProject = QAction(handle.projectName, self)
            oneProject.triggered.connect(partial(self.showProjectPage, index))
            openedProjectMenu.addAction(oneProject)

        self.projectAction.setMenu(openedProjectMenu)
        openedProjectMenu.exec(QCursor.pos())

    def showProjectPage(self, index):
        # show opened project page using index
        self.mainLayout.setCurrentIndex(index)
        self.curOpenProjectHandle, self.curProjectTabManager = self.openedProject.getHandle(
            index)
        self.enableProjectMenu.emit()

    def initTabWidget(self, tabWidget: ColorTabWidget, handle: ProjectReader):
        tabManager = TabManager(tabWidget, handle)
        # init qml main page list
        projectMainPage = QQuickWidget(tabWidget)
        projectMainPage.setResizeMode(QQuickWidget.SizeRootObjectToView)
        projectMainPage.setSource(
            QUrl.fromLocalFile('QML/ProjectMainPage.qml'))
        projectMainPage.setMinimumWidth(550)
        projectMainPage.setMinimumHeight(250)
        projectMainPage.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)
        obj_projectMainPage = projectMainPage.rootObject()
        # send main page init dict
        obj_projectMainPage.onInitMainPageItems(
            self.getProjectDetail(tabManager))
        obj_projectMainPage.sendData.connect(self.getData_ProjectMainPage)
        tabManager.qmlHandle = obj_projectMainPage
        tabManager.qmlWidget = projectMainPage
        tabWidget.addTab(projectMainPage, 'MainPage:MainPage')
        return tabManager

    @staticmethod
    def getProjectDetail(tabManager: TabManager):
        info = dict()
        handle = tabManager.handle
        info['ID'] = handle.yamlFile
        info['projectName'] = handle.projectName
        info['lastAccessTime'] = handle.lastAccessTime.replace(
            tzinfo=timezone.utc).astimezone(
                tz=None).strftime('%y/%m/%d %H:%M:%S')
        info['model'] = handle.modelSourceHandle.getAllPath()
        info['data'] = handle.dataSourceHandle.getAllPath()
        info['script'] = handle.scriptSourceHandle.getAllPath()
        info['result'] = []
        return info

    def onProjectInited(self, projectFile: str):
        handle = ProjectReader(projectFile)
        self.openProject(handle)

    def getData_ProjectMainPage(self, data):
        dataType, itemIndex, itemName = data.toVariant()
        # print(dataType, itemIndex, itemName)
        if dataType == 'data':
            handle = dataLoader(itemName)
            self.openDSEditor(handle)

    def changeEvent(self, e: QEvent) -> None:
        if e.type() == QEvent.WindowStateChange and self.windowState(
        ) == Qt.WindowMaximized:
            self.horizontal_splitter.setSizes(
                [self.height() - self.downSize, self.downSize])
        elif e.type() == QEvent.WindowStateChange and self.windowState(
        ) == Qt.WindowNoState:
            self.horizontal_splitter.setSizes(
                [self.height() - self.downSize, self.downSize])

    def onHSplitterMoved(self, pos: int, index: int):
        self.downSize = self.height() - pos

    def onDisableProjectMenu(self):
        self.newProjectDataSetMenu.setEnabled(False)
        self.newProjectModel.setEnabled(False)
        self.newProjectScript.setEnabled(False)

    def onEnableProjectMenu(self):
        self.newProjectDataSetMenu.setEnabled(True)
        self.newProjectModel.setEnabled(True)
        self.newProjectScript.setEnabled(True)

    def onNewProjectDataSetMenu(self):
        dialog = newPlutoDSDialog(self.curOpenProjectHandle, self)
        r = dialog.exec()
        if r == QDialog.Accepted:
            obj_projectMainPage = self.curProjectTabManager.qmlWidget.rootObject(
            )
            obj_projectMainPage.addData(dialog.target)
            handle = dataLoader(dialog.target)
            self.openDSEditor(handle)

    def onNewProjectModel(self):
        pass

    def onNewProjectScript(self):
        pass

    def openDSEditor(self, DSHandle):
        tabManager = self.curProjectTabManager
        tabWidget = tabManager.tabWidget
        if DSHandle.yamlFile in tabManager.dataTabs:
            print(tabManager.dataTabs[DSHandle.yamlFile])
            tabWidget.setCurrentIndex(
                tabManager.dataTabs[DSHandle.yamlFile][0])
        else:
            widget, title = self.DSEditor(DSHandle, tabWidget)
            tabWidget.addTab(widget, title)
            tabManager.dataTabs[
                DSHandle.yamlFile] = tabWidget.count() - 1, widget
            tabWidget.setCurrentIndex(tabWidget.count() - 1)

    def DSEditor(self, DSHandle: dataLoader, parent=None):
        handle = DSHandle
        widget = QWidget(parent)
        title = 'Data:' + QDir(handle.yamlFile).dirName()

        return widget, title