Example #1
0
class MikiWindow(QMainWindow):
    def __init__(self, settings, parent=None):
        super(MikiWindow, self).__init__(parent)
        self.setObjectName("mikiWindow")
        self.settings = settings
        self.notePath = settings.notePath

        ################ Setup core components ################
        self.notesTree = MikiTree(self)
        self.quickNoteNav = QLineEdit()
        self.notesTab = QWidget()
        self.completer = SlashPleter()
        self.completer.setModel(self.notesTree.model())
        self.quickNoteNav.setCompleter(self.completer)
        self.notesTree.setObjectName("notesTree")
        self.initTree(self.notePath, self.notesTree)
        self.notesTree.sortItems(0, Qt.AscendingOrder)

        self.ix = None
        self.setupWhoosh()

        self.viewedList = QToolBar(self.tr('Recently Viewed'), self)
        self.viewedList.setIconSize(QSize(16, 16))
        self.viewedList.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.viewedListActions = []
        self.noteSplitter = QSplitter(Qt.Horizontal)

        self.dockIndex = QDockWidget("Index")
        self.dockSearch = QDockWidget("Search")
        self.searchEdit = QLineEdit()
        self.searchView = MikiSearch(self)
        self.searchTab = QWidget()
        self.dockToc = QDockWidget("TOC")
        self.tocTree = TocTree()
        self.dockAttachment = QDockWidget("Attachment")
        self.attachmentView = AttachmentView(self)

        self.notesEdit = MikiEdit(self)
        self.notesEdit.setObjectName("notesEdit")
        MikiHighlighter(self.notesEdit)
        self.notesView = MikiView(self)

        self.findBar = QToolBar(self.tr('Find'), self)
        self.findBar.setFixedHeight(30)
        self.findEdit = QLineEdit(self.findBar)
        self.checkBox = QCheckBox(self.tr('Match case'), self.findBar)

        self.statusBar = QStatusBar(self)
        self.statusLabel = QLabel(self)

        self.altPressed = False


        ################ Setup actions ################
        self.actions = dict()
        self.setupActions()


        ################ Setup mainwindow ################
        self.setupMainWindow()

        # show changelogs after upgrade mikidown
        if self.settings.version < __version__:
            self.changelogHelp()
            self.settings.qsettings.setValue("version", __version__)


    def setupActions(self):

        # Global Actions
        actTabIndex = self.act(self.tr('Switch to Index Tab'),
            lambda: self.raiseDock(self.dockIndex), 'Ctrl+Shift+I')
        actTabSearch = self.act(self.tr('Switch to Search Tab'),
            lambda: self.raiseDock(self.dockSearch), 'Ctrl+Shift+F')
        self.addAction(actTabIndex)
        self.addAction(actTabSearch)

        ################ Menu Actions ################
        # actions in menuFile
        actionNewPage = self.act(self.tr('&New Page...'),
            self.notesTree.newPage, QKeySequence.New)
        self.actions.update(newPage=actionNewPage)

        actionNewSubpage = self.act(self.tr('New Sub&page...'),
            self.notesTree.newSubpage, 'Ctrl+Shift+N')
        self.actions.update(newSubpage=actionNewSubpage)

        actionImportPage = self.act(self.tr('&Import Page...'), self.importPage)
        self.actions.update(importPage=actionImportPage)

        actionNBSettings = self.act(self.tr('Notebook Set&tings...'), self.notebookSettings)
        self.actions.update(NBSettings=actionNBSettings)

        actionMDSettings = self.act(self.tr('&Mikidown Settings...'), self.mikidownSettings)
        self.actions.update(MDSettings=actionMDSettings)

        actionOpenNotebook = self.act(self.tr('&Open Notebook...'),
            self.openNotebook, QKeySequence.Open)
        self.actions.update(openNotebook=actionOpenNotebook)

        actionReIndex = self.act(self.tr('Re-index'), self.reIndex)
        self.actions.update(reIndex=actionReIndex)

        actionSave = self.act(self.tr('&Save'),
            self.saveCurrentNote, QKeySequence.Save)
        actionSave.setEnabled(False)
        self.actions.update(save=actionSave)

        actionSaveAs = self.act(self.tr('Save &As...'),
            self.saveNoteAs, QKeySequence.SaveAs)
        self.actions.update(saveAs=actionSaveAs)

        actionHtml = self.act(self.tr('to &HTML'), self.notesEdit.saveAsHtml)
        self.actions.update(html=actionHtml)

        actionPrint = self.act(self.tr('&Print'),
            self.printNote, QKeySequence.Print)
        self.actions.update(print_=actionPrint)

        actionRenamePage = self.act(self.tr('&Rename Page...'),
            self.notesTree.renamePage, 'F2')
        self.actions.update(renamePage=actionRenamePage)

        actionDelPage = self.act(self.tr('&Delete Page'),
            self.notesTree.delPageWrapper, QKeySequence.Delete)
        self.actions.update(delPage=actionDelPage)

        actionQuit = self.act(self.tr('&Quit'), self.close, QKeySequence.Quit)
        actionQuit.setMenuRole(QAction.QuitRole)
        self.actions.update(quit=actionQuit)

        # actions in menuEdit
        actionUndo = self.act(self.tr('&Undo'),
            lambda: self.notesEdit.undo(), QKeySequence.Undo)
        actionUndo.setEnabled(False)
        self.notesEdit.undoAvailable.connect(actionUndo.setEnabled)
        self.actions.update(undo=actionUndo)

        actionRedo = self.act(self.tr('&Redo'),
            lambda: self.notesEdit.redo(), QKeySequence.Redo)
        actionRedo.setEnabled(False)
        self.notesEdit.redoAvailable.connect(actionRedo.setEnabled)
        self.actions.update(redo=actionRedo)

        actionFindText = self.act(self.tr('&Find Text'),
            self.findBar.setVisible, QKeySequence.Find, True)
        self.actions.update(findText=actionFindText)

        actionFind = self.act(self.tr('Next'),
            self.findText, QKeySequence.FindNext)
        self.actions.update(find=actionFind)

        actionFindPrev = self.act(self.tr('Previous'),
            lambda: self.findText(back=True), QKeySequence.FindPrevious)
        self.actions.update(findPrev=actionFindPrev)

        actionSortLines = self.act(self.tr('&Sort Lines'), self.sortLines)
        self.actions.update(sortLines=actionSortLines)

        actionQuickNav = self.act(self.tr("&Quick Open Note"),
                        self.quickNoteNav.setFocus, 'Ctrl+G')
        self.addAction(actionQuickNav)

        actionInsertImage = self.act(self.tr('&Insert Attachment'),
            self.notesEdit.insertAttachmentWrapper, 'Ctrl+I')
        actionInsertImage.setEnabled(False)
        self.actions.update(insertImage=actionInsertImage)

        # actions in menuView
        actionEdit = self.act(self.tr('Edit'), self.edit, 'Ctrl+E',
            True, QIcon(':/icons/edit.svg'), 'Edit mode (Ctrl+E)')
        self.actions.update(edit=actionEdit)

        actionSplit = self.act(self.tr('Split'), self.liveView, 'Ctrl+R',
            True, QIcon(':/icons/split.svg'), 'Split mode (Ctrl+R)')
        self.actions.update(split=actionSplit)

        actionFlipEditAndView = self.act(self.tr('Flip Edit and View'),
            self.flipEditAndView)
        actionFlipEditAndView.setEnabled(False)
        self.actions.update(flipEditAndView=actionFlipEditAndView)

        #actionLeftAndRight = self.act(
        #    self.tr('Split into Left and Right'), trig=self.leftAndRight)
        #actionUpAndDown = self.act(
        #    self.tr('Split into Up and Down'), trig=self.upAndDown)
        # self.actionLeftAndRight.setEnabled(False)
        # self.actionUpAndDown.setEnabled(False)

        # actions in menuHelp
        actionReadme = self.act(self.tr('README'), self.readmeHelp)
        self.actions.update(readme=actionReadme)

        actionChangelog = self.act(self.tr('Changelog'), self.changelogHelp)
        self.actions.update(changelog=actionChangelog)

        actionAboutQt = self.act(self.tr('About Qt'), qApp.aboutQt)
        self.actions.update(aboutQt=actionAboutQt)


    def setupMainWindow(self):
        self.resize(800, 600)
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((
            screen.width()-size.width())/2, (screen.height()-size.height())/2)
        self.setWindowTitle(
            '{} - {}'.format(self.settings.notebookName, __appname__))

        self.viewedList.setFixedHeight(25)
        self.noteSplitter.addWidget(self.notesEdit)
        self.noteSplitter.addWidget(self.notesView)
        mainSplitter = QSplitter(Qt.Vertical)
        mainSplitter.setChildrenCollapsible(False)
        mainSplitter.addWidget(self.viewedList)
        mainSplitter.addWidget(self.noteSplitter)
        mainSplitter.addWidget(self.findBar)
        self.setCentralWidget(mainSplitter)

        self.searchEdit.returnPressed.connect(self.searchNote)
        self.quickNoteNav.returnPressed.connect(self.openFuncWrapper)
        searchLayout = QVBoxLayout()
        searchLayout.addWidget(self.searchEdit)
        searchLayout.addWidget(self.searchView)
        self.searchTab.setLayout(searchLayout)
        self.tocTree.header().close()

        indexLayout = QVBoxLayout(self.notesTab)
        indexLayout.addWidget(self.quickNoteNav)
        indexLayout.addWidget(self.notesTree)

        self.dockIndex.setObjectName("Index")
        self.dockIndex.setWidget(self.notesTab)
        self.dockSearch.setObjectName("Search")
        self.dockSearch.setWidget(self.searchTab)
        self.dockToc.setObjectName("TOC")
        self.dockToc.setWidget(self.tocTree)
        self.dockAttachment.setObjectName("Attachment")
        self.dockAttachment.setWidget(self.attachmentView)

        self.setDockOptions(QMainWindow.VerticalTabs)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dockIndex)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dockSearch)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dockToc)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dockAttachment)
        self.tabifyDockWidget(self.dockIndex, self.dockSearch)
        self.tabifyDockWidget(self.dockSearch, self.dockToc)
        self.tabifyDockWidget(self.dockToc, self.dockAttachment)
        self.setTabPosition(Qt.LeftDockWidgetArea, QTabWidget.North)
        self.dockIndex.raise_()      # Put dockIndex on top of the tab stack

        menuBar = QMenuBar(self)
        self.setMenuBar(menuBar)
        menuFile = menuBar.addMenu(self.tr('&File'))
        menuEdit = menuBar.addMenu(self.tr('&Edit'))
        menuView = menuBar.addMenu(self.tr('&View'))
        menuHelp = menuBar.addMenu(self.tr('&Help'))
        # menuFile
        menuFile.addAction(self.actions['newPage'])
        menuFile.addAction(self.actions['newSubpage'])
        menuFile.addAction(self.actions['NBSettings'])
        menuFile.addAction(self.actions['MDSettings'])
        menuFile.addAction(self.actions['importPage'])
        menuFile.addAction(self.actions['openNotebook'])
        menuFile.addAction(self.actions['reIndex'])
        menuFile.addSeparator()
        menuFile.addAction(self.actions['save'])
        menuFile.addAction(self.actions['saveAs'])
        menuFile.addAction(self.actions['print_'])
        menuExport = menuFile.addMenu(self.tr('&Export'))
        menuExport.addAction(self.actions['html'])
        menuFile.addSeparator()
        menuFile.addAction(self.actions['renamePage'])
        menuFile.addAction(self.actions['delPage'])
        menuFile.addSeparator()
        menuFile.addAction(self.actions['quit'])
        # menuEdit
        menuEdit.addAction(self.actions['undo'])
        menuEdit.addAction(self.actions['redo'])
        menuEdit.addAction(self.actions['findText'])
        menuEdit.addSeparator()
        menuEdit.addAction(self.actions['sortLines'])
        menuEdit.addAction(self.actions['insertImage'])
        # menuView
        menuView.addAction(self.actions['edit'])
        menuView.addAction(self.actions['split'])
        menuView.addAction(self.actions['flipEditAndView'])
        menuShowHide = menuView.addMenu(self.tr('Show/Hide'))
        menuShowHide.addAction(self.dockIndex.toggleViewAction())
        menuShowHide.addAction(self.dockSearch.toggleViewAction())
        menuShowHide.addAction(self.dockToc.toggleViewAction())
        menuShowHide.addAction(self.dockAttachment.toggleViewAction())
        #menuMode = menuView.addMenu(self.tr('Mode'))
        #menuMode.addAction(self.actionLeftAndRight)
        #menuMode.addAction(self.actionUpAndDown)
        # menuHelp
        menuHelp.addAction(self.actions['readme'])
        menuHelp.addAction(self.actions['changelog'])
        menuHelp.addAction(self.actions['aboutQt'])

        toolBar = QToolBar(self.tr("toolbar"), self)
        toolBar.setObjectName("toolbar")       # needed in saveState()
        toolBar.setIconSize(QSize(16, 16))
        toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.addToolBar(Qt.TopToolBarArea, toolBar)
        toolBar.addAction(self.actions['edit'])
        toolBar.addAction(self.actions['split'])
        self.findEdit.returnPressed.connect(self.findText)
        self.findBar.addWidget(self.findEdit)
        self.findBar.addWidget(self.checkBox)
        self.findBar.addAction(self.actions['findPrev'])
        self.findBar.addAction(self.actions['find'])
        self.findBar.setVisible(False)
        self.findBar.visibilityChanged.connect(self.findBarVisibilityChanged)

        self.setStatusBar(self.statusBar)
        self.statusBar.addWidget(self.statusLabel, 1)

        self.notesTree.currentItemChanged.connect(
            self.currentItemChangedWrapper)
        self.tocTree.itemClicked.connect(self.tocNavigate)
        self.notesEdit.textChanged.connect(self.noteEditted)

        self.notesEdit.document(
        ).modificationChanged.connect(self.modificationChanged)

        self.updateRecentViewedNotes()
        notes = self.settings.recentViewedNotes()
        if len(notes) != 0:
            item = self.notesTree.pageToItem(notes[0])
            self.notesTree.setCurrentItem(item)

    def openFuncWrapper(self):
        self.openFunction(self.quickNoteNav.text())()

    def setupWhoosh(self):
        # Initialize whoosh index, make sure notePath/.indexdir exists
        indexdir = self.settings.indexdir
        try:
            self.ix = open_dir(indexdir)
        except:
            QDir().mkpath(indexdir)
            self.ix = create_in(indexdir, self.settings.schema)
            # Fork a process to update index, which benefit responsiveness.
            p = Thread(target=self.whoosh_index, args=())
            p.start()


    def restore(self):
        """ Restore saved geometry and state.
            Set the status of side panels in View Menu correspondently.
        """
        if self.settings.geometry:
            self.restoreGeometry(self.settings.geometry)
        if self.settings.windowstate:
            self.restoreState(self.settings.windowstate)

    def initTree(self, notePath, parent):
        ''' When there exist foo.md, foo.mkd, foo.markdown,
            only one item will be shown in notesTree.
        '''
        if not QDir(notePath).exists():
            return
        notebookDir = QDir(notePath)
        notesList = notebookDir.entryInfoList(['*.md', '*.mkd', '*.markdown'],
                                               QDir.NoFilter,
                                               QDir.Name|QDir.IgnoreCase)
        nl = [note.completeBaseName() for note in notesList]
        noduplicate = list(set(nl))
        for name in noduplicate:
            item = QTreeWidgetItem(parent, [name])
            path = notePath + '/' + name
            self.initTree(path, item)

    def updateToc(self):
        ''' TOC is updated in `updateView`
            tocTree fields: [hdrText, hdrPosition, hdrAnchor]
        '''
        root = self.notesTree.currentPage()
        self.tocTree.clear()
        item = QTreeWidgetItem(self.tocTree, [root, '0'])
        curLevel = 0
        for (level, h, p, a) in parseHeaders(self.notesEdit.toPlainText()):
            val = [h, str(p), a]
            if level == curLevel:
                item = QTreeWidgetItem(item.parent(), val)
            elif level < curLevel:
                item = QTreeWidgetItem(item.parent().parent(), val)
                curLevel = level
            else:
                item = QTreeWidgetItem(item, val)
                curLevel = level
        self.tocTree.expandAll()

    def updateAttachmentView(self):
        # Update attachmentView to show corresponding attachments.
        item = self.notesTree.currentItem()
        index = self.attachmentView.model.index(
            self.notesTree.itemToAttachmentDir(item))
        self.attachmentView.setRootIndex(index)

    def openFile(self, filename):
        fh = QFile(filename)
        try:
            if not fh.open(QIODevice.ReadOnly):
                raise IOError(fh.errorString())
        except IOError as e:
            QMessageBox.warning(self, 'Read Error',
                                'Failed to open %s: %s' % (filename, e))
        finally:
            if fh is not None:
                noteBody = QTextStream(fh).readAll()
                fh.close()
                self.notesEdit.setPlainText(noteBody)
                self.notesView.scrollPosition = QPoint(0, 0)
                # self.actionSave.setEnabled(False)
                self.notesEdit.document().setModified(False)
                self.notesView.updateView()
                self.setCurrentNote()
                self.updateRecentViewedNotes()
                #self.statusLabel.setText(noteFullName)

    def currentItemChangedWrapper(self, current, previous):
        if current is None:
            return
        #if previous != None and self.notesTree.pageExists(previous):
        prev = self.notesTree.itemToPage(previous)
        if self.notesTree.pageExists(prev):
            self.saveNote(previous)

        currentFile = self.notesTree.itemToFile(current)
        self.openFile(currentFile)

        # Update attachmentView to show corresponding attachments.
        index = self.attachmentView.model.index(
            self.notesTree.itemToAttachmentDir(current))
        self.attachmentView.setRootIndex(index)

    def tocNavigate(self, current):
        ''' works for notesEdit now '''
        if current is None:
            return
        pos = int(current.text(1))
        link = "file://" + self.notePath + "/#" + current.text(2)
        # Move cursor to END first will ensure
        # header is positioned at the top of visual area.
        self.notesEdit.moveCursor(QTextCursor.End)
        cur = self.notesEdit.textCursor()
        cur.setPosition(pos, QTextCursor.MoveAnchor)
        self.notesEdit.setTextCursor(cur)
        self.notesView.load(QUrl(link))

    def switchNote(self, num):
        if num < len(self.viewedListActions):
            self.viewedListActions[num].trigger()

    def saveCurrentNote(self):
        item = self.notesTree.currentItem()
        self.saveNote(item)

    def saveNote(self, item):
        if self.notesEdit.document().isModified():
            self.notesEdit.document().setModified(False)
        else:
            return
        self.notesEdit.save(item)

    def saveNoteAs(self):
        self.saveCurrentNote()
        fileName = QFileDialog.getSaveFileName(self, self.tr('Save as'), '',
            '(*.md *.mkd *.markdown);;'+self.tr('All files(*)'))
        if fileName == '':
            return
        if not QFileInfo(fileName).suffix():
            fileName += '.md'
        fh = QFile(fileName)
        fh.open(QIODevice.WriteOnly)
        savestream = QTextStream(fh)
        savestream << self.notesEdit.toPlainText()
        fh.close()

    def printNote(self):
        printer = QPrinter(QPrinter.HighResolution)
        printer.setCreator(__appname__ + ' ' + __version__)
        printer.setDocName(self.notesTree.currentItem().text(0))
        printdialog = QPrintDialog(printer, self)
        if printdialog.exec() == QDialog.Accepted:
            self.notesView.print_(printer)

    def noteEditted(self):
        """ Continuously get fired while editing"""
        self.updateToc()
        self.notesView.updateLiveView()

    def modificationChanged(self, changed):
        """ Fired one time: modified or not """
        self.actions['save'].setEnabled(changed)
        name = self.notesTree.currentPage()
        self.statusBar.clearMessage()
        if changed:
            self.statusLabel.setText(name + '*')
        else:
            self.statusLabel.setText(name)

    def importPage(self):
        filename = QFileDialog.getOpenFileName(
            self, self.tr('Import file'), '',
            '(*.md *.mkd *.markdown *.txt);;'+self.tr('All files(*)'))
        if filename == '':
            return
        self.importPageCore(filename)

    def importPageCore(self, filename):
        fh = QFile(filename)
        fh.open(QIODevice.ReadOnly)
        fileBody = QTextStream(fh).readAll()
        fh.close()
        page = QFileInfo(filename).completeBaseName()
        fh = QFile(self.notesTree.pageToFile(page))
        if fh.exists():
            QMessageBox.warning(self, 'Import Error',
                'Page already exists: %s' % page)
            dialog = LineEditDialog(self.notePath, self)
            if dialog.exec_():
                page = dialog.editor.text()
                fh.close()
                fh = QFile(self.notesTree.pageToFile(page))
            else:
                return
        fh.open(QIODevice.WriteOnly)
        savestream = QTextStream(fh)
        savestream << fileBody
        fh.close()
        item = QTreeWidgetItem(self.notesTree, [page])
        self.notesTree.sortItems(0, Qt.AscendingOrder)
        self.notesTree.setCurrentItem(item)

    def openNotebook(self):
        dialog = NotebookListDialog(self)
        if dialog.exec_():
            pass

    def notebookSettings(self):
        dialog = NotebookSettingsDialog(self)
        if dialog.exec_():
            pass

    def mikidownSettings(self):
        dialog = MikidownCfgDialog(self)
        if dialog.exec_():
            pass


    def reIndex(self):
        """ Whoosh index breaks for unknown reasons (sometimes) """
        shutil.rmtree(self.settings.indexdir)
        self.setupWhoosh()

    def act(self, name, trig, shortcut=None, checkable=False,
            icon=None, tooltip=None):
        """ A wrapper to several QAction methods """
        if icon:
            action = QAction(icon, name, self)
        else:
            action = QAction(name, self)
        if shortcut:
            action.setShortcut(QKeySequence(shortcut))
        action.setCheckable(checkable)
        if tooltip:
            action.setToolTip(tooltip)
        action.triggered.connect(trig)
        return action

    def edit(self, viewmode):
        """ Switch between EDIT and VIEW mode. """

        if self.actions['split'].isChecked():
            self.actions['split'].setChecked(False)
        self.notesView.setVisible(not viewmode)
        self.notesEdit.setVisible(viewmode)

        # Gives the keyboard input focus to notesEdit/notesView.
        # Without this, keyboard input may change note text even when
        # notesEdit is invisible.
        if viewmode:
            self.notesEdit.setFocus()
        else:
            self.notesView.setFocus()

        self.saveCurrentNote()
        self.actions['insertImage'].setEnabled(viewmode)
        #self.actionLeftAndRight.setEnabled(True)
        #self.actionUpAndDown.setEnabled(True)

        # Render the note text as it is.
        self.notesView.updateView()

    def liveView(self, viewmode):
        """ Switch between VIEW and LIVE VIEW mode. """

        self.actions['split'].setChecked(viewmode)
        sizes = self.noteSplitter.sizes()
        if self.actions['edit'].isChecked():
            self.actions['edit'].setChecked(False)
            self.notesView.setVisible(viewmode)
            splitSize = [sizes[0]*0.45, sizes[0]*0.55]
        else:
            self.notesEdit.setVisible(viewmode)
            splitSize = [sizes[1]*0.45, sizes[1]*0.55]

        # setFocus for the same reason as in edit(self, viewmode)
        if viewmode:
            self.notesEdit.setFocus()
        else:
            self.notesView.setFocus()

        self.actions['flipEditAndView'].setEnabled(viewmode)
        #self.actionUpAndDown.setEnabled(viewmode)
        self.actions['insertImage'].setEnabled(viewmode)
        self.noteSplitter.setSizes(splitSize)
        self.saveCurrentNote()

        # Render the note text as it is.
        self.notesView.updateView()

    def findBarVisibilityChanged(self, visible):
        self.actions['findText'].setChecked(visible)
        if visible:
            self.findEdit.setFocus(Qt.ShortcutFocusReason)

    def findText(self, back=False):
        flags = 0
        if back:
            flags = QTextDocument.FindBackward
        if self.checkBox.isChecked():
            flags = flags | QTextDocument.FindCaseSensitively
        text = self.findEdit.text()
        if not self.findMain(text, flags):
            if text in self.notesEdit.toPlainText():
                cursor = self.notesEdit.textCursor()
                if back:
                    cursor.movePosition(QTextCursor.End)
                else:
                    cursor.movePosition(QTextCursor.Start)
                self.notesEdit.setTextCursor(cursor)
                self.findMain(text, flags)
        # self.notesView.findText(text, flags)

    def findMain(self, text, flags):
        viewFlags = QWebPage.FindFlags(
            flags) | QWebPage.FindWrapsAroundDocument
        if flags:
            self.notesView.findText(text, viewFlags)
            return self.notesEdit.find(text, flags)
        else:
            self.notesView.findText(text)
            return self.notesEdit.find(text)

    def sortLines(self):
        ''' sort selected lines
            TODO: second sort reverse the order
        '''
        cursor = self.notesEdit.textCursor()
        start = cursor.selectionStart()
        end = cursor.selectionEnd()
        cursor.setPosition(start)
        cursor.movePosition(QTextCursor.StartOfLine)
        cursor.setPosition(end, mode=QTextCursor.KeepAnchor)
        cursor.movePosition(QTextCursor.EndOfLine, mode=QTextCursor.KeepAnchor)
        text = cursor.selectedText()
        lines = text.split('\u2029')      # '\u2029' is the line break
        sortedLines = sorted(lines)
        cursor.insertText('\n'.join(sortedLines))

    def notesEditInFocus(self, e):
        if e.gotFocus:
            self.actions['insertImage'].setEnabled(True)
        # if e.lostFocus:
        #    self.actionInsertImage.setEnabled(False)

        # QWidget.focusInEvent(self,f)

    def searchNote(self):
        """ Sorting criteria: "title > path > content"
            Search matches are organized into html source.
        """

        pattern = self.searchEdit.text()
        if not pattern:
            return
        results = []
        print("Searching using", pattern)
        with self.ix.searcher() as searcher:
            matches = []
            for f in ["title", "path", "content"]:
                queryp = QueryParser(f, self.ix.schema)
                queryp.add_plugin(RegexPlugin())
                # r"pattern" is the desired regex term format
                query = queryp.parse('r"' + pattern + '"')
                ms = searcher.search(query, limit=None) # default limit is 10!
                for m in ms:
                    if not m in matches:
                        matches.append(m)

            for r in matches:
                title = r['title']
                path = r['path']
                term = r.highlights("content")
                results.append([title, path, term])

            html = ""
            for title, path, hi in results:
                html += ("<p><a href='" + path + "'>" + title +
                         "</a><br/><span class='path'>" +
                         path + "</span><br/>" + hi + "</p>")
            self.searchView.setHtml(html)
            print("Finished searching", pattern)

    def whoosh_index(self):
        it = QTreeWidgetItemIterator(
            self.notesTree, QTreeWidgetItemIterator.All)
        print("Starting complete indexing.")
        writer = self.ix.writer()
        while it.value():
            treeItem = it.value()
            name = self.notesTree.itemToPage(treeItem)
            path = os.path.join(self.notesTree.pageToFile(name)).replace(os.sep, '/')
            print(path)
            fileobj = open(path, 'r')
            content = fileobj.read()
            fileobj.close()
            writer.add_document(
                path=name, title=parseTitle(content, name), content=content)
            it += 1
        writer.commit()
        print("Finished completely reindexing.")

    def listItemChanged(self, row):
        if row != -1:
            item = self.searchList.currentItem().data(Qt.UserRole)
            self.notesTree.setCurrentItem(item)
            flags = QWebPage.HighlightAllOccurrences
            self.notesView.findText(self.searchEdit.text(), flags)

    def setCurrentNote(self):
        item = self.notesTree.currentItem()
        name = self.notesTree.itemToPage(item)

        # Current note is inserted to head of list.
        notes = self.settings.recentViewedNotes()
        for f in notes:
            if f == name:
                notes.remove(f)
        notes.insert(0, name)

        recent_notes_n = Mikibook.settings.value('recentNotesNumber',type=int, defaultValue=20)
        if len(notes) > recent_notes_n:
            del notes[recent_notes_n:]
        self.settings.updateRecentViewedNotes(notes)

    def updateRecentViewedNotes(self):
        """ Switching notes will trigger this.
            When Alt pressed, show note number.
        """

        self.viewedList.clear()
        self.viewedListActions = []

        # Check notes exists.
        viewedNotes = self.settings.recentViewedNotes()
        existedNotes = []
        i = 0
        for f in viewedNotes:
            if self.notesTree.pageExists(f):
                existedNotes.append(f)
                names = f.split('/')
                if self.altPressed and i in range(1, 10):
                    action = self.act(names[-1], self.openFunction(f),
                        'Alt+'+str(i), True, ViewedNoteIcon(i), 'Alt+'+str(i))
                else:
                    action = self.act(names[-1], self.openFunction(f),
                        None, True)
                self.viewedListActions.append(action)
                i += 1

        if not self.altPressed:
            self.settings.updateRecentViewedNotes(existedNotes)
        for action in self.viewedListActions:
            self.viewedList.addAction(action)
        if len(self.viewedListActions):
            self.viewedListActions[0].setChecked(True)

    def openFunction(self, name):
        item = self.notesTree.pageToItem(name)
        return lambda: self.notesTree.setCurrentItem(item)

    def raiseDock(self, widget):
        if not widget.isVisible():
            widget.show()
        if widget == self.dockSearch:
            self.searchEdit.setFocus()
        widget.raise_()

    def flipEditAndView(self):
        index = self.noteSplitter.indexOf(self.notesEdit)
        if index == 0:
            self.noteSplitter.insertWidget(1, self.notesEdit)
        else:
            self.noteSplitter.insertWidget(0, self.notesEdit)

    def leftAndRight(self):
        self.liveView(True)
        self.noteSplitter.setOrientation(Qt.Horizontal)
        #self.actionLeftAndRight.setEnabled(False)
        #self.actionUpAndDown.setEnabled(True)

    def upAndDown(self):
        self.liveView(True)
        self.noteSplitter.setOrientation(Qt.Vertical)
        #self.actionUpAndDown.setEnabled(False)
        #self.actionLeftAndRight.setEnabled(True)

    def readmeHelp(self):
        readmeFile = '/usr/share/mikidown/README.mkd'
        if not os.path.exists(readmeFile):
            readmeFile = os.path.join(
                os.path.dirname(os.path.dirname(__file__)), 'README.mkd').replace(os.sep, '/')
        self.importPageCore(readmeFile)

    def changelogHelp(self):
        changeLog = "/usr/share/mikidown/Changelog.md"
        if not os.path.exists(changeLog):
            changeLog = os.path.join(
                os.path.dirname(os.path.dirname(__file__)), 'Changelog.md').replace(os.sep, '/')
        self.importPageCore(changeLog)

    def keyPressEvent(self, event):
        """ When Alt pressed, note number will be shown in viewedList. """
        if event.key() == Qt.Key_Alt:
            self.altPressed = True
            self.updateRecentViewedNotes()
        else:
            QMainWindow.keyPressEvent(self, event)

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Alt:
            self.altPressed = False
            self.updateRecentViewedNotes()
        else:
            QMainWindow.keyPressEvent(self, event)

    def closeEvent(self, event):
        """
            saveGeometry: Saves the current geometry and state for
                          top-level widgets
            saveState: Restores the state of this mainwindow's toolbars
                       and dockwidgets
        """
        self.saveCurrentNote()
        self.settings.saveGeometry(self.saveGeometry())
        self.settings.saveWindowState(self.saveState())
        event.accept()
Example #2
0
class MikiWindow(QMainWindow):
    def __init__(self, settings, parent=None):
        super(MikiWindow, self).__init__(parent)
        self.setObjectName("mikiWindow")
        self.settings = settings
        self.notePath = settings.notePath
        lockPath = os.path.join(settings.notebookPath, '.mikidown_lock')
        if not os.path.exists(lockPath):
            self.lockPathFH = os.open(lockPath,
                                      os.O_CREAT | os.O_EXCL | os.O_RDWR)
        ################ Setup core components ################
        self.notesTree = MikiTree(self)
        self.quickNoteNav = QLineEdit()
        self.notesTab = QWidget()
        self.completer = SlashPleter()
        self.completer.setModel(self.notesTree.model())
        self.quickNoteNav.setCompleter(self.completer)
        self.notesTree.setObjectName("notesTree")
        self.initTree(self.notePath, self.notesTree)
        self.notesTree.sortItems(0, Qt.AscendingOrder)

        self.ix = None
        self.setupWhoosh()

        self.viewedList = QToolBar(self.tr('Recently Viewed'), self)
        self.viewedList.setIconSize(QSize(16, 16))
        self.viewedList.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.viewedListActions = []
        self.noteSplitter = QSplitter(Qt.Horizontal)

        self.dockIndex = QDockWidget(self.tr("Index"))
        self.dockSearch = QDockWidget(self.tr("Search"))
        self.searchEdit = QLineEdit()
        self.searchView = MikiSearch(self)
        self.searchTab = QWidget()
        self.dockToc = QDockWidget(self.tr("TOC"))
        self.tocTree = TocTree()
        self.dockAttachment = QDockWidget(self.tr("Attachment"))
        self.attachmentView = AttachmentView(self)

        self.notesEdit = MikiEdit(self)
        self.notesEdit.setObjectName(self.tr("notesEdit"))
        self.loadHighlighter()
        self.notesView = MikiView(self)

        self.findBar = QToolBar(self.tr('Find'), self)
        self.findBar.setFixedHeight(30)
        self.findEdit = QLineEdit(self.findBar)
        self.checkBox = QCheckBox(self.tr('Match case'), self.findBar)

        self.statusBar = QStatusBar(self)
        self.statusLabel = QLabel(self)

        self.altPressed = False

        ################ Setup actions ################
        self.actions = dict()
        self.setupActions()

        ################ Setup mainwindow ################
        self.setupMainWindow()

        # show changelogs after upgrade mikidown
        if self.settings.version < __version__ or Mikibook.settings.value(
                "version", defaultValue="0") < __version__:
            self.changelogHelp()
            self.settings.qsettings.setValue("version", __version__)
            Mikibook.settings.setValue("version", __version__)

    def loadHighlighter(self):
        fnt = Mikibook.settings.value('editorFont', defaultValue=None)
        fntsize = Mikibook.settings.value('editorFontSize',
                                          type=int,
                                          defaultValue=12)
        header_scales_font = Mikibook.settings.value('headerScaleFont',
                                                     type=bool,
                                                     defaultValue=True)
        if fnt is not None:
            self.notesEdit.setFontFamily(fnt)
            self.notesEdit.setFontPointSize(fntsize)
        h = MikiHighlighter(parent=self.notesEdit,
                            scale_font_sizes=header_scales_font)
        tw = Mikibook.settings.value('tabWidth', type=int, defaultValue=4)
        qfm = QFontMetrics(h.patterns[0][1].font())
        self.notesEdit.setTabStopWidth(tw * qfm.width(' '))

    def setupActions(self):

        # Global Actions
        actTabIndex = self.act(self.tr('Switch to Index Tab'),
                               lambda: self.raiseDock(self.dockIndex),
                               self.tr('Ctrl+Shift+I'))
        actTabSearch = self.act(self.tr('Switch to Search Tab'),
                                lambda: self.raiseDock(self.dockSearch),
                                self.tr('Ctrl+Shift+F'))
        self.addAction(actTabIndex)
        self.addAction(actTabSearch)

        ################ Menu Actions ################
        # actions in menuFile
        actionNewPage = self.act(self.tr('&New Page...'),
                                 self.notesTree.newPage, QKeySequence.New)
        self.actions.update(newPage=actionNewPage)

        actionNewSubpage = self.act(self.tr('New Sub&page...'),
                                    self.notesTree.newSubpage,
                                    self.tr('Ctrl+Shift+N'))
        self.actions.update(newSubpage=actionNewSubpage)

        actionImportPage = self.act(self.tr('&Import Page...'),
                                    self.importPage)
        self.actions.update(importPage=actionImportPage)

        actionNBSettings = self.act(self.tr('Notebook Set&tings...'),
                                    self.notebookSettings)
        self.actions.update(NBSettings=actionNBSettings)

        actionMDSettings = self.act(self.tr('&Mikidown Settings...'),
                                    self.mikidownSettings)
        self.actions.update(MDSettings=actionMDSettings)

        actionOpenNotebook = self.act(self.tr('&Open Notebook...'),
                                      self.openNotebook, QKeySequence.Open)
        self.actions.update(openNotebook=actionOpenNotebook)

        actionReIndex = self.act(self.tr('Re-index'), self.reIndex)
        self.actions.update(reIndex=actionReIndex)

        actionSave = self.act(self.tr('&Save'), self.saveCurrentNote,
                              QKeySequence.Save)
        actionSave.setEnabled(False)
        self.actions.update(save=actionSave)

        actionSaveAs = self.act(self.tr('Save &As...'), self.saveNoteAs,
                                QKeySequence.SaveAs)
        self.actions.update(saveAs=actionSaveAs)

        actionHtml = self.act(self.tr('to &HTML'), self.notesEdit.saveAsHtml)
        self.actions.update(html=actionHtml)

        actionPrint = self.act(self.tr('&Print'), self.printNote,
                               QKeySequence.Print)
        self.actions.update(print_=actionPrint)

        actionRenamePage = self.act(self.tr('&Rename Page...'),
                                    self.notesTree.renamePage, 'F2')
        self.actions.update(renamePage=actionRenamePage)

        actionDelPage = self.act(self.tr('&Delete Page'),
                                 self.notesTree.delPageWrapper,
                                 QKeySequence.Delete)
        self.actions.update(delPage=actionDelPage)

        actionQuit = self.act(self.tr('&Quit'), self.close, QKeySequence.Quit)
        actionQuit.setMenuRole(QAction.QuitRole)
        self.actions.update(quit=actionQuit)

        # actions in menuEdit
        actionUndo = self.act(self.tr('&Undo'), lambda: self.notesEdit.undo(),
                              QKeySequence.Undo)
        actionUndo.setEnabled(False)
        self.notesEdit.undoAvailable.connect(actionUndo.setEnabled)
        self.actions.update(undo=actionUndo)

        actionRedo = self.act(self.tr('&Redo'), lambda: self.notesEdit.redo(),
                              QKeySequence.Redo)
        actionRedo.setEnabled(False)
        self.notesEdit.redoAvailable.connect(actionRedo.setEnabled)
        self.actions.update(redo=actionRedo)

        actionFindText = self.act(self.tr('&Find Text'),
                                  self.findBar.setVisible, QKeySequence.Find,
                                  True)
        self.actions.update(findText=actionFindText)

        actionFindRepl = self.act(self.tr('Find and Replace'),
                                  FindReplaceDialog(self.notesEdit).open,
                                  QKeySequence.Replace)
        self.actions.update(findRepl=actionFindRepl)

        actionFind = self.act(self.tr('Next'), self.findText,
                              QKeySequence.FindNext)
        self.actions.update(find=actionFind)

        actionFindPrev = self.act(self.tr('Previous'),
                                  lambda: self.findText(back=True),
                                  QKeySequence.FindPrevious)
        self.actions.update(findPrev=actionFindPrev)

        actionSortLines = self.act(self.tr('&Sort Lines'), self.sortLines)
        self.actions.update(sortLines=actionSortLines)

        actionQuickNav = self.act(self.tr("&Quick Open Note"),
                                  self.quickNoteNav.setFocus,
                                  self.tr('Ctrl+G'))
        self.addAction(actionQuickNav)

        actionInsertImage = self.act(self.tr('&Insert Attachment'),
                                     self.notesEdit.insertAttachmentWrapper,
                                     self.tr('Ctrl+I'))
        actionInsertImage.setEnabled(False)
        self.actions.update(insertImage=actionInsertImage)

        # actions in menuView
        QIcon.setThemeName(
            Mikibook.settings.value('iconTheme', QIcon.themeName()))
        #print(QIcon.themeName())
        actionEdit = self.act(self.tr('Edit'), self.edit, self.tr('Ctrl+E'),
                              True, QIcon.fromTheme('document-edit'),
                              self.tr('Edit mode (Ctrl+E)'))
        self.actions.update(edit=actionEdit)

        actionSplit = self.act(self.tr('Split'), self.liveView,
                               self.tr('Ctrl+R'), True,
                               QIcon.fromTheme('view-split-left-right'),
                               self.tr('Split mode (Ctrl+R)'))
        self.actions.update(split=actionSplit)

        actionFlipEditAndView = self.act(self.tr('Flip Edit and View'),
                                         self.flipEditAndView)
        actionFlipEditAndView.setEnabled(False)
        self.actions.update(flipEditAndView=actionFlipEditAndView)

        #actionLeftAndRight = self.act(
        #    self.tr('Split into Left and Right'), trig=self.leftAndRight)
        #actionUpAndDown = self.act(
        #    self.tr('Split into Up and Down'), trig=self.upAndDown)
        # self.actionLeftAndRight.setEnabled(False)
        # self.actionUpAndDown.setEnabled(False)

        # actions in menuHelp
        actionReadme = self.act(self.tr('README'), self.readmeHelp)
        self.actions.update(readme=actionReadme)

        actionChangelog = self.act(self.tr('Changelog'), self.changelogHelp)
        self.actions.update(changelog=actionChangelog)

        actionAboutQt = self.act(self.tr('About Qt'), qApp.aboutQt)
        self.actions.update(aboutQt=actionAboutQt)

    def setupMainWindow(self):
        self.resize(800, 600)
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2,
                  (screen.height() - size.height()) / 2)
        self.setWindowTitle('{} - {}'.format(self.settings.notebookName,
                                             __appname__))

        self.viewedList.setFixedHeight(25)
        self.noteSplitter.addWidget(self.notesEdit)
        self.noteSplitter.addWidget(self.notesView)
        mainSplitter = QSplitter(Qt.Vertical)
        mainSplitter.setChildrenCollapsible(False)
        mainSplitter.addWidget(self.viewedList)
        mainSplitter.addWidget(self.noteSplitter)
        mainSplitter.addWidget(self.findBar)
        self.setCentralWidget(mainSplitter)

        self.searchEdit.returnPressed.connect(self.searchNote)
        self.quickNoteNav.returnPressed.connect(self.openFuncWrapper)
        searchLayout = QVBoxLayout()
        searchLayout.addWidget(self.searchEdit)
        searchLayout.addWidget(self.searchView)
        self.searchTab.setLayout(searchLayout)

        indexLayout = QVBoxLayout(self.notesTab)
        indexLayout.addWidget(self.quickNoteNav)
        indexLayout.addWidget(self.notesTree)

        self.dockIndex.setObjectName("Index")
        self.dockIndex.setWidget(self.notesTab)
        self.dockSearch.setObjectName("Search")
        self.dockSearch.setWidget(self.searchTab)
        self.dockToc.setObjectName("TOC")
        self.dockToc.setWidget(self.tocTree)
        self.dockAttachment.setObjectName("Attachment")
        self.dockAttachment.setWidget(self.attachmentView)

        self.setDockOptions(QMainWindow.VerticalTabs)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dockIndex)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dockSearch)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dockToc)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dockAttachment)
        self.tabifyDockWidget(self.dockIndex, self.dockSearch)
        self.tabifyDockWidget(self.dockSearch, self.dockToc)
        self.tabifyDockWidget(self.dockToc, self.dockAttachment)
        self.setTabPosition(Qt.LeftDockWidgetArea, QTabWidget.North)
        self.dockIndex.raise_()  # Put dockIndex on top of the tab stack

        menuBar = QMenuBar(self)
        self.setMenuBar(menuBar)
        menuFile = menuBar.addMenu(self.tr('&File'))
        menuEdit = menuBar.addMenu(self.tr('&Edit'))
        menuView = menuBar.addMenu(self.tr('&View'))
        menuHelp = menuBar.addMenu(self.tr('&Help'))
        # menuFile
        menuFile.addAction(self.actions['newPage'])
        menuFile.addAction(self.actions['newSubpage'])
        menuFile.addAction(self.actions['NBSettings'])
        menuFile.addAction(self.actions['MDSettings'])
        menuFile.addAction(self.actions['importPage'])
        menuFile.addAction(self.actions['openNotebook'])
        menuFile.addAction(self.actions['reIndex'])
        menuFile.addSeparator()
        menuFile.addAction(self.actions['save'])
        menuFile.addAction(self.actions['saveAs'])
        menuFile.addAction(self.actions['print_'])
        menuExport = menuFile.addMenu(self.tr('&Export'))
        menuExport.addAction(self.actions['html'])
        menuFile.addSeparator()
        menuFile.addAction(self.actions['renamePage'])
        menuFile.addAction(self.actions['delPage'])
        menuFile.addSeparator()
        menuFile.addAction(self.actions['quit'])
        # menuEdit
        menuEdit.addAction(self.actions['undo'])
        menuEdit.addAction(self.actions['redo'])
        menuEdit.addAction(self.actions['findText'])
        menuEdit.addAction(self.actions['findRepl'])
        menuEdit.addSeparator()
        menuEdit.addAction(self.actions['sortLines'])
        menuEdit.addAction(self.actions['insertImage'])
        # menuView
        menuView.addAction(self.actions['edit'])
        menuView.addAction(self.actions['split'])
        menuView.addAction(self.actions['flipEditAndView'])
        menuShowHide = menuView.addMenu(self.tr('Show/Hide'))
        menuShowHide.addAction(self.dockIndex.toggleViewAction())
        menuShowHide.addAction(self.dockSearch.toggleViewAction())
        menuShowHide.addAction(self.dockToc.toggleViewAction())
        menuShowHide.addAction(self.dockAttachment.toggleViewAction())
        #menuMode = menuView.addMenu(self.tr('Mode'))
        #menuMode.addAction(self.actionLeftAndRight)
        #menuMode.addAction(self.actionUpAndDown)
        # menuHelp
        menuHelp.addAction(self.actions['readme'])
        menuHelp.addAction(self.actions['changelog'])
        menuHelp.addAction(self.actions['aboutQt'])

        toolBar = QToolBar(self.tr("toolbar"), self)
        toolBar.setObjectName("toolbar")  # needed in saveState()
        #toolBar.setIconSize(QSize(16, 16))
        toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.addToolBar(Qt.TopToolBarArea, toolBar)
        toolBar.addAction(self.actions['edit'])
        toolBar.addAction(self.actions['split'])
        self.findEdit.returnPressed.connect(self.findText)
        self.findBar.addWidget(self.findEdit)
        self.findBar.addWidget(self.checkBox)
        self.findBar.addAction(self.actions['findPrev'])
        self.findBar.addAction(self.actions['find'])
        self.findBar.setVisible(False)
        self.findBar.visibilityChanged.connect(self.findBarVisibilityChanged)

        self.setStatusBar(self.statusBar)
        self.statusBar.addWidget(self.statusLabel, 1)

        self.notesTree.currentItemChanged.connect(
            self.currentItemChangedWrapper)
        self.notesTree.nvwCallback = self.newNoteDisplay
        self.notesTree.nvwtCallback = self.newPlainTextNoteDisplay
        self.tocTree.itemClicked.connect(self.tocNavigate)
        self.notesEdit.textChanged.connect(self.noteEditted)

        self.notesEdit.document().modificationChanged.connect(
            self.modificationChanged)

        self.updateRecentViewedNotes()
        notes = self.settings.recentViewedNotes()
        if len(notes) != 0:
            item = self.notesTree.pageToItem(notes[0])
            self.notesTree.setCurrentItem(item)

    def newNoteDisplay(self, item, anchor=None):
        msn = MikiSepNote(self.settings,
                          item.text(0),
                          self.notesTree.itemToFile(item),
                          plain_text=False,
                          parent=self)
        if anchor:
            msn.note_view.page().mainFrame().scrollToAnchor(anchor)
        msn.show()

    def newPlainTextNoteDisplay(self, item, anchor=None):
        msn = MikiSepNote(self.settings,
                          item.text(0),
                          self.notesTree.itemToFile(item),
                          plain_text=True,
                          parent=self)
        if anchor:
            item = msn.findItemByAnchor(anchor)[0]
            msn.tocNavigate(item)
        msn.show()

    def openFuncWrapper(self):
        self.openFunction(self.quickNoteNav.text())()

    def setupWhoosh(self):
        # Initialize whoosh index, make sure notePath/.indexdir exists
        indexdir = self.settings.indexdir
        try:
            self.ix = open_dir(indexdir)
        except:
            QDir().mkpath(indexdir)
            self.ix = create_in(indexdir, self.settings.schema)
            # Fork a process to update index, which benefit responsiveness.
            p = Thread(target=self.whoosh_index, args=())
            p.start()

    def restore(self):
        """ Restore saved geometry and state.
            Set the status of side panels in View Menu correspondently.
        """
        if self.settings.geometry:
            self.restoreGeometry(self.settings.geometry)
        if self.settings.windowstate:
            self.restoreState(self.settings.windowstate)

    def initTree(self, notePath, parent):
        ''' When there exist foo.md, foo.mkd, foo.markdown,
            only one item will be shown in notesTree.
        '''
        if not QDir(notePath).exists():
            return
        notebookDir = QDir(notePath)
        notesList = notebookDir.entryInfoList(['*.md', '*.mkd', '*.markdown'],
                                              QDir.NoFilter,
                                              QDir.Name | QDir.IgnoreCase)
        nl = [note.completeBaseName() for note in notesList]
        noduplicate = list(set(nl))
        for name in noduplicate:
            item = QTreeWidgetItem(parent, [name])
            path = notePath + '/' + name
            self.initTree(path, item)

    def updateToc(self):
        ''' TOC is updated in `updateView`
            tocTree fields: [hdrText, hdrPosition, hdrAnchor]
        '''
        root = self.notesTree.currentPage()
        strip_math_for_header_parsing = False
        strip_fence_for_header_parsing = False
        if 'asciimathml' in self.settings.extensions:
            strip_math_for_header_parsing = True
        if 'fenced_code' in self.settings.extensions or 'extra' in self.settings.extensions:
            strip_fence_for_header_parsing = True
        self.tocTree.updateToc(
            root,
            parseHeaders(self.notesEdit.toPlainText(),
                         strip_fenced_block=strip_fence_for_header_parsing,
                         strip_ascii_math=strip_math_for_header_parsing))

    def updateAttachmentView(self):
        # Update attachmentView to show corresponding attachments.
        item = self.notesTree.currentItem()
        index = self.attachmentView.model.index(
            self.notesTree.itemToAttachmentDir(item))
        self.attachmentView.setRootIndex(index)

    def openFile(self, filename):
        fh = QFile(filename)
        try:
            if not fh.open(QIODevice.ReadOnly):
                raise IOError(fh.errorString())
        except IOError as e:
            QMessageBox.warning(
                self, self.tr('Read Error'),
                self.tr('Failed to open %s: %s') % (filename, e))
        finally:
            if fh is not None:
                noteBody = QTextStream(fh).readAll()
                fh.close()
                self.notesEdit.setPlainText(noteBody)
                self.notesView.scrollPosition = QPoint(0, 0)
                # self.actionSave.setEnabled(False)
                self.notesEdit.document().setModified(False)
                self.notesView.updateView()
                self.setCurrentNote()
                self.updateRecentViewedNotes()
                #self.statusLabel.setText(noteFullName)

    def currentItemChangedWrapper(self, current, previous):
        if current is None:
            return
        #if previous != None and self.notesTree.pageExists(previous):
        prev = self.notesTree.itemToPage(previous)
        if self.notesTree.pageExists(prev):
            self.saveNote(previous)

        currentFile = self.notesTree.itemToFile(current)
        self.openFile(currentFile)

        # Update attachmentView to show corresponding attachments.
        index = self.attachmentView.model.index(
            self.notesTree.itemToAttachmentDir(current))
        self.attachmentView.setRootIndex(index)

    def tocNavigate(self, current):
        ''' works for notesEdit now '''
        if current is None:
            return
        pos = int(current.text(1))
        link = "file://" + self.notePath + "/#" + current.text(2)
        # Move cursor to END first will ensure
        # header is positioned at the top of visual area.
        self.notesEdit.moveCursor(QTextCursor.End)
        cur = self.notesEdit.textCursor()
        cur.setPosition(pos, QTextCursor.MoveAnchor)
        self.notesEdit.setTextCursor(cur)
        self.notesView.load(QUrl(link))

    def switchNote(self, num):
        if num < len(self.viewedListActions):
            self.viewedListActions[num].trigger()

    def saveCurrentNote(self):
        item = self.notesTree.currentItem()
        self.saveNote(item)

    def saveNote(self, item):
        if self.notesEdit.document().isModified():
            self.notesEdit.document().setModified(False)
        else:
            return
        self.notesEdit.save(item)

    def saveNoteAs(self):
        self.saveCurrentNote()
        fileName = QFileDialog.getSaveFileName(
            self, self.tr('Save as'), '',
            '(*.md *.mkd *.markdown);;' + self.tr('All files(*)'))
        if fileName == '':
            return
        if not QFileInfo(fileName).suffix():
            fileName += '.md'
        fh = QFile(fileName)
        fh.open(QIODevice.WriteOnly)
        savestream = QTextStream(fh)
        savestream << self.notesEdit.toPlainText()
        fh.close()

    def printNote(self):
        printer = QPrinter(QPrinter.HighResolution)
        printer.setCreator(__appname__ + ' ' + __version__)
        printer.setDocName(self.notesTree.currentItem().text(0))
        printdialog = QPrintDialog(printer, self)
        if printdialog.exec() == QDialog.Accepted:
            self.notesView.print_(printer)

    def noteEditted(self):
        """ Continuously get fired while editing"""
        self.updateToc()
        self.notesView.updateLiveView()

    def modificationChanged(self, changed):
        """ Fired one time: modified or not """
        self.actions['save'].setEnabled(changed)
        name = self.notesTree.currentPage()
        self.statusBar.clearMessage()
        if changed:
            self.statusLabel.setText(name + '*')
        else:
            self.statusLabel.setText(name)

    def importPage(self):
        filename = QFileDialog.getOpenFileName(
            self, self.tr('Import file'), '',
            '(*.md *.mkd *.markdown *.txt);;' + self.tr('All files(*)'))
        if filename == '':
            return
        self.importPageCore(filename)

    def importPageCore(self, filename):
        fh = QFile(filename)
        fh.open(QIODevice.ReadOnly)
        fileBody = QTextStream(fh).readAll()
        fh.close()
        page = QFileInfo(filename).completeBaseName()
        fh = QFile(self.notesTree.pageToFile(page))
        if fh.exists():
            QMessageBox.warning(self, self.tr("Import Error"),
                                self.tr("Page already exists: %s") % page)
            dialog = LineEditDialog(self.notePath, self)
            if dialog.exec_():
                page = dialog.editor.text()
                fh.close()
                fh = QFile(self.notesTree.pageToFile(page))
            else:
                return
        fh.open(QIODevice.WriteOnly)
        savestream = QTextStream(fh)
        savestream << fileBody
        fh.close()
        item = QTreeWidgetItem(self.notesTree, [page])
        self.notesTree.sortItems(0, Qt.AscendingOrder)
        self.notesTree.setCurrentItem(item)

    def openNotebook(self):
        dialog = NotebookListDialog(self)
        if dialog.exec_():
            pass

    def notebookSettings(self):
        dialog = NotebookSettingsDialog(self)
        if dialog.exec_():
            pass

    def mikidownSettings(self):
        dialog = MikidownCfgDialog(self)
        if dialog.exec_():
            pass

    def reIndex(self):
        """ Whoosh index breaks for unknown reasons (sometimes) """
        shutil.rmtree(self.settings.indexdir)
        self.setupWhoosh()

    def act(self,
            name,
            trig,
            shortcut=None,
            checkable=False,
            icon=None,
            tooltip=None):
        """ A wrapper to several QAction methods """
        if icon:
            action = QAction(icon, name, self)
        else:
            action = QAction(name, self)
        if shortcut:
            action.setShortcut(QKeySequence(shortcut))
        action.setCheckable(checkable)
        if tooltip:
            action.setToolTip(tooltip)
        action.triggered.connect(trig)
        return action

    def edit(self, viewmode):
        """ Switch between EDIT and VIEW mode. """

        if self.actions['split'].isChecked():
            self.actions['split'].setChecked(False)
        self.notesView.setVisible(not viewmode)
        self.notesEdit.setVisible(viewmode)

        # Gives the keyboard input focus to notesEdit/notesView.
        # Without this, keyboard input may change note text even when
        # notesEdit is invisible.
        if viewmode:
            self.notesEdit.setFocus()
        else:
            self.notesView.setFocus()

        self.saveCurrentNote()
        self.actions['insertImage'].setEnabled(viewmode)
        #self.actionLeftAndRight.setEnabled(True)
        #self.actionUpAndDown.setEnabled(True)

        # Render the note text as it is.
        self.notesView.updateView()

    def liveView(self, viewmode):
        """ Switch between VIEW and LIVE VIEW mode. """

        self.actions['split'].setChecked(viewmode)
        sizes = self.noteSplitter.sizes()
        if self.actions['edit'].isChecked():
            self.actions['edit'].setChecked(False)
            self.notesView.setVisible(viewmode)
            splitSize = [sizes[0] * 0.45, sizes[0] * 0.55]
        else:
            self.notesEdit.setVisible(viewmode)
            splitSize = [sizes[1] * 0.45, sizes[1] * 0.55]

        # setFocus for the same reason as in edit(self, viewmode)
        if viewmode:
            self.notesEdit.setFocus()
        else:
            self.notesView.setFocus()

        self.actions['flipEditAndView'].setEnabled(viewmode)
        #self.actionUpAndDown.setEnabled(viewmode)
        self.actions['insertImage'].setEnabled(viewmode)
        self.noteSplitter.setSizes(splitSize)
        self.saveCurrentNote()

        # Render the note text as it is.
        self.notesView.updateView()

    def findBarVisibilityChanged(self, visible):
        self.actions['findText'].setChecked(visible)
        if visible:
            self.findEdit.setFocus(Qt.ShortcutFocusReason)

    def findText(self, back=False):
        flags = 0
        if back:
            flags = QTextDocument.FindBackward
        if self.checkBox.isChecked():
            flags = flags | QTextDocument.FindCaseSensitively
        text = self.findEdit.text()
        if not self.findMain(text, flags):
            if text in self.notesEdit.toPlainText():
                cursor = self.notesEdit.textCursor()
                if back:
                    cursor.movePosition(QTextCursor.End)
                else:
                    cursor.movePosition(QTextCursor.Start)
                self.notesEdit.setTextCursor(cursor)
                self.findMain(text, flags)
        # self.notesView.findText(text, flags)

    def findMain(self, text, flags):
        viewFlags = QWebPage.FindFlags(
            flags) | QWebPage.FindWrapsAroundDocument
        if flags:
            self.notesView.findText(text, viewFlags)
            return self.notesEdit.find(text, flags)
        else:
            self.notesView.findText(text)
            return self.notesEdit.find(text)

    def sortLines(self):
        ''' sort selected lines
            TODO: second sort reverse the order
        '''
        cursor = self.notesEdit.textCursor()
        start = cursor.selectionStart()
        end = cursor.selectionEnd()
        cursor.setPosition(start)
        cursor.movePosition(QTextCursor.StartOfLine)
        cursor.setPosition(end, mode=QTextCursor.KeepAnchor)
        cursor.movePosition(QTextCursor.EndOfLine, mode=QTextCursor.KeepAnchor)
        text = cursor.selectedText()
        lines = text.split('\u2029')  # '\u2029' is the line break
        sortedLines = sorted(lines)
        cursor.insertText('\n'.join(sortedLines))

    def notesEditInFocus(self, e):
        if e.gotFocus:
            self.actions['insertImage'].setEnabled(True)
        # if e.lostFocus:
        #    self.actionInsertImage.setEnabled(False)

        # QWidget.focusInEvent(self,f)

    def searchNote(self):
        """ Sorting criteria: "title > path > content"
            Search matches are organized into html source.
        """

        pattern = self.searchEdit.text()
        if not pattern:
            return
        results = []
        print("Searching using", pattern)
        with self.ix.searcher() as searcher:
            matches = []
            queryp = QueryParser("content", self.ix.schema)
            #allow escaped qutoes when regex searching
            queryp.add_plugin(
                RegexPlugin(expr=r'r"(?P<text>[^"\\]*(\\.[^"\\]*)*)"'))
            # ~~r"pattern" is the desired regex term format~~ Don't autoforce regexing
            query = queryp.parse(pattern)
            #print("durp durp", query)
            ms = searcher.search(query, limit=None)  # default limit is 10!
            for m in ms:
                #if not m in matches:
                matches.append(m)

            for r in matches:
                title = r['title']
                path = r['path']
                term = r.highlights("content")
                results.append([title, path, term])

            html = ""
            for title, path, hi in results:
                html += ("<p><a href='" + path + "'>" + title +
                         "</a><br/><span class='path'>" + path +
                         "</span><br/>" + hi + "</p>")
            self.searchView.setHtml(html)
            print("Finished searching", pattern)

    def whoosh_index(self):
        it = QTreeWidgetItemIterator(self.notesTree,
                                     QTreeWidgetItemIterator.All)
        print("Starting complete indexing.")
        #writer = self.ix.writer()
        writer = AsyncWriter(self.ix)
        while it.value():
            treeItem = it.value()
            name = self.notesTree.itemToPage(treeItem)
            path = os.path.join(self.notesTree.pageToFile(name)).replace(
                os.sep, '/')
            print(path)
            fileobj = open(path, 'r', encoding='utf-8')
            content = fileobj.read()
            fileobj.close()
            if METADATA_CHECKER.match(
                    content) and 'meta' in self.settings.extensions:
                no_metadata_content = METADATA_CHECKER.sub("",
                                                           content,
                                                           count=1).lstrip()
                self.settings.md.reset().convert(content)
                writer.update_document(
                    path=name,
                    title=parseTitle(content, name),
                    content=no_metadata_content,
                    tags=','.join(self.settings.md.Meta.get('tags',
                                                            [])).strip())
            else:
                writer.add_document(path=name,
                                    title=parseTitle(content, name),
                                    content=content,
                                    tags='')

            it += 1
        writer.commit()
        print("Finished completely reindexing.")

    def listItemChanged(self, row):
        if row != -1:
            item = self.searchList.currentItem().data(Qt.UserRole)
            self.notesTree.setCurrentItem(item)
            flags = QWebPage.HighlightAllOccurrences
            self.notesView.findText(self.searchEdit.text(), flags)

    def setCurrentNote(self):
        item = self.notesTree.currentItem()
        name = self.notesTree.itemToPage(item)

        # Current note is inserted to head of list.
        notes = self.settings.recentViewedNotes()
        for f in notes:
            if f == name:
                notes.remove(f)
        notes.insert(0, name)

        recent_notes_n = Mikibook.settings.value('recentNotesNumber',
                                                 type=int,
                                                 defaultValue=20)
        if len(notes) > recent_notes_n:
            del notes[recent_notes_n:]
        self.settings.updateRecentViewedNotes(notes)

    def updateRecentViewedNotes(self):
        """ Switching notes will trigger this.
            When Alt pressed, show note number.
        """

        self.viewedList.clear()
        self.viewedListActions = []

        # Check notes exists.
        viewedNotes = self.settings.recentViewedNotes()
        existedNotes = []
        i = 0
        for f in viewedNotes:
            if self.notesTree.pageExists(f):
                existedNotes.append(f)
                names = f.split('/')
                if self.altPressed and i in range(1, 10):
                    action = self.act(names[-1], self.openFunction(f),
                                      'Alt+' + str(i), True, ViewedNoteIcon(i),
                                      'Alt+' + str(i))
                else:
                    action = self.act(names[-1], self.openFunction(f), None,
                                      True)
                self.viewedListActions.append(action)
                i += 1

        if not self.altPressed:
            self.settings.updateRecentViewedNotes(existedNotes)
        for action in self.viewedListActions:
            self.viewedList.addAction(action)
        if len(self.viewedListActions):
            self.viewedListActions[0].setChecked(True)

    def openFunction(self, name):
        item = self.notesTree.pageToItem(name)
        return lambda: self.notesTree.setCurrentItem(item)

    def raiseDock(self, widget):
        if not widget.isVisible():
            widget.show()
        if widget == self.dockSearch:
            self.searchEdit.setFocus()
        widget.raise_()

    def flipEditAndView(self):
        index = self.noteSplitter.indexOf(self.notesEdit)
        if index == 0:
            self.noteSplitter.insertWidget(1, self.notesEdit)
        else:
            self.noteSplitter.insertWidget(0, self.notesEdit)

    def leftAndRight(self):
        self.liveView(True)
        self.noteSplitter.setOrientation(Qt.Horizontal)
        #self.actionLeftAndRight.setEnabled(False)
        #self.actionUpAndDown.setEnabled(True)

    def upAndDown(self):
        self.liveView(True)
        self.noteSplitter.setOrientation(Qt.Vertical)
        #self.actionUpAndDown.setEnabled(False)
        #self.actionLeftAndRight.setEnabled(True)

    def readmeHelp(self):
        readmeFile = '/usr/share/mikidown/README.mkd'
        if not os.path.exists(readmeFile):
            readmeFile = os.path.join(
                os.path.dirname(os.path.dirname(__file__)),
                'README.mkd').replace(os.sep, '/')
        self.importPageCore(readmeFile)

    def changelogHelp(self):
        changeLog = "/usr/share/mikidown/Changelog.md"
        if not os.path.exists(changeLog):
            changeLog = os.path.join(
                os.path.dirname(os.path.dirname(__file__)),
                'Changelog.md').replace(os.sep, '/')
        self.importPageCore(changeLog)

    def keyPressEvent(self, event):
        """ When Alt pressed, note number will be shown in viewedList. """
        if event.key() == Qt.Key_Alt:
            self.altPressed = True
            self.updateRecentViewedNotes()
        else:
            QMainWindow.keyPressEvent(self, event)

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Alt:
            self.altPressed = False
            self.updateRecentViewedNotes()
        else:
            QMainWindow.keyPressEvent(self, event)

    def closeEvent(self, event):
        """
            saveGeometry: Saves the current geometry and state for
                          top-level widgets
            saveState: Restores the state of this mainwindow's toolbars
                       and dockwidgets
        """
        self.saveCurrentNote()
        self.ix.close()
        self.notesEdit.ix.close()
        if hasattr(self.notesTree, 'ix'):
            self.notesTree.ix.close()
        self.settings.saveGeometry(self.saveGeometry())
        self.settings.saveWindowState(self.saveState())
        event.accept()
        os.close(self.lockPathFH)
        lockPath = os.path.join(self.settings.notebookPath, '.mikidown_lock')
        os.remove(lockPath)
Example #3
0
class mainWindow(QMainWindow):
	# ---- private begin ----
	
	## @brief initialize class function
	# @param self The object pointer.
	# @param loglevel Logging level for main window and all modules.
	# @param debug Enabled debugging. Default is false.
	# 
	# initialize:
	# - create logger thread
	# - create main window logger client
	# - create global progress bar thread
	# - add dialogs
	# - manage central widget
	def __init__(self, loglevel, debug = False, *args, **kwargs):
		QMainWindow.__init__(self, *args, **kwargs)
		
		self.__initVars()

		# load main ui before setting debug level
		uic.loadUi("./main.ui", self)

		# create logger widget
		self.__p_loggerDockWidget = QtLoggerDockWidget('Logging', self)
		self.__p_loggerDockWidget.setObjectName('Logging')
		self.__p_loggerListWidget = QtLoggerListWidget(self.__p_loggerDockWidget)
		
		# ... add list widget to dock widget
		self.__p_loggerDockWidget.setWidget(self.__p_loggerListWidget)
		
		# ... add dock widget to main window
		self.addDockWidget(Qt.BottomDockWidgetArea, self.__p_loggerDockWidget)

		
		# init QtLogger
		QtLogger.printObj = self.__p_loggerListWidget

		# init logger for main window
		self.__p_logger = logging.getLogger("mainWindow")
		
		# ... set log level
		self.__p_logger.setLevel(loglevel)
		
		# ... set debug level for modules
		abstractModuleClass.loglevel = loglevel
		

		# Hide debugging menu in none debugging mode
		if (debug):
			# add debug menu
			self.menuDebug = self.menuBar().addMenu("Debug")

			# add debug actions to menu
			self.actionPrintSettings = self.menuDebug.addAction("print settings")
			self.actionDelAllSettings = self.menuDebug.addAction("del all settings")
			
			# connect signals to actions
			self.actionPrintSettings.triggered.connect(self.__onPrintSettings)
			self.actionDelAllSettings.triggered.connect(self.__onDelAllSettings)
		# end if
		
		# add help if operating system is windows
		if (sys.platform == "win32"):
			self.menuQ.addAction("GUI help", self.__onHelp)
			#action.triggered.connect(self.__onHelp)
		# end if
		
		# progress bar
		# ... set parameters
		self.progressBarGlobal.setLabel(self.labelProgressBarGlobal)
		self.progressBarGlobal.disable()
		
		# ... create progress bar thread
		self.__p_progressBarThread = progressBarThread(self)
		self.__p_progressBarThread.sigProgressBarUpdate.connect(self.__onProgressBarUpdate)
		self.__p_progressBarThread.start()
		
		# add dialogs
		# ... about dialog
		self.__p_about = QDialog(self)
		uic.loadUi("./about.ui", self.__p_about)
		self.actionAbout.triggered.connect(self.__p_about.exec)

		# ... license dialog
		self.__p_license = QDialog(self)
		uic.loadUi("./license.ui", self.__p_license)
		self.actionLicense.triggered.connect(self.__p_license.exec)
		
		# ... select module dialog
		self.__p_selectModule = QDialog(self)
		uic.loadUi('./selectModule.ui', self.__p_selectModule)
		self.actionModules.triggered.connect(self.__p_selectModule.exec)
		
		# init GUI
		# ... set central widget to none
		#self.setCentralWidget(None)
		self.centralWidget().setFixedSize(0,0)
		
		# ... Add all dock widgets on startup into the left area. An show tabs on top.
		self.setTabPosition(Qt.LeftDockWidgetArea, QTabWidget.North)
		
		# ... create and add status bar
		self.__p_statusBar = QStatusBar()
		self.setStatusBar(self.__p_statusBar)
		
		# ... move progress bar widget into status bar
		self.__p_statusBar.addWidget(self.widgetProgressBar, 1)

		# ... set tool button style
		self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
		
		# settings
		# ... create main settings object
		self.__p_settingsHandle = QSettings('./' + self.__v_userSettingsFileName, QSettings.IniFormat)
		
		# ... set QSettings handle
		abstractGuiModuleClass.settingsHandle = self.__p_settingsHandle
	# end __init__
	

	## @brief del function
	# @param self The object pointer.
	#
	# Delete all member variables and threads.
	def __del__(self):
		# set static variables to false
		QtLogger.printObj = False
		abstractGuiModuleClass.settingsHandle = False
		abstractModuleClass.d_modules = dict()
		abstractModuleClass.p_progressBar = False
		abstractModuleClass.p_progressBarThread = False
		
		# stop and delete progressBar
		if (self.__p_progressBarThread != False):
			self.__p_progressBarThread.sigProgressBarUpdate.disconnect(self.__onProgressBarUpdate)
			self.__p_progressBarThread.stop()
			self.__p_progressBarThread.wait(500)
			self.__p_progressBarThread = False
		# end if
		
		# set all variables to false to free memory
		self.__initVars()
	# end __del__
	
	## @brief Initialize class variables.
	# @param self The object pointer.
	def __initVars(self):
		self.__p_loggerDockWidget = False
		self.__p_loggerListWidget = False
		
		## main window status bar
		self.__p_statusBar = False
		
		## global module directory
		# with "/" at the end!!!
		self.__v_modulePath = "modules/"
		
		## filename from used modules xml file
		self.__v_userSettingsFileName = 'userSettings.ini'
		
		## current tab index
		self.__v_currentTabIndex = -1
		
		## about dialog
		self.__p_about = False
		
		## license dialog
		self.__p_license = False
		
		## select module dialog
		self.__p_selectModule = False
		
		## main settings object
		self.__p_settingsHandle = False
		
		## main gui logger object
		self.__p_logger = False
		
		## list of used modules
		self.__l_usedModules = []
		
		## progress bar object thread
		self.__p_progressBarThread = False
		
		## module counter
		self.__v_moduleCounter = 0
	# end __initVars
	
	
	## @brief private slot for updating the progressbar
	# @param self The object pointer.
	# @param ret List with command and command value.
	#
	# @n ret[0]: values
	# @n ret[1]: commands
	#
	# @n valid commands:
	# - init
	# - clear
	# - disable
	# - newVal or ready
	#
	@pyqtSlot(list)
	def __onProgressBarUpdate(self, ret):
		value, command = ret
		
		if (command == 'init'):
			self.progressBarGlobal.init(self)
			
			if (value != ''):
				self.progressBarGlobal.setText(value)
			# end if
		elif (command == 'clear'):
			self.progressBarGlobal.clear()
		elif (command == 'disable'):
			self.progressBarGlobal.disable()
		elif (command == 'newVal' or command == 'ready'):
			try:
				value = int(value)
			except:
				self.__p_logger.error('Only Integers for progressBar value are allowed. But %s were set!!!', str(value))
				return
			# end if
	
			self.progressBarGlobal.setValue(value)
		# end if
	# end if
	
	## @brief get user settings like used module list and gui position
	# @param self The object pointer.
	# 
	# Load only the modules which were selected by the user.
	def __loadSettings(self):
		# main group
		self.__p_settingsHandle.beginGroup('main')
		displayName = self.__p_settingsHandle.value("displayName", "pyGUI")
		geo = self.__p_settingsHandle.value("geo")
		#state = self.__p_settingsHandle.value('state')
		self.__p_settingsHandle.endGroup()
		
		saveOnExit = self.__p_settingsHandle.value("settings/saveOnExit", True)
		
		# modules group
		self.__p_settingsHandle.beginGroup('module')
		self.__l_usedModules = self.__p_settingsHandle.value('used', [])
		self.__p_settingsHandle.endGroup()

		# restore state and geometry if information is available
		#if (state):
		#	self.restoreState(state)
		# end if
		if (geo):
			self.restoreGeometry(geo)
		# end if

		# if no used modules are available		
		if (self.__l_usedModules == None):
			self.__l_usedModules = []
		# end if

		# restore settings
		self.actionSaveSettingsOnExit.setChecked(str2bool(saveOnExit))
		
		# set display name
		self.setWindowTitle(displayName)
	# end __loadSettings

	
	## @brief save window and user settings
	# @param self The object pointer.
	#
	# saved settings are:
	# - main window position and size
	# - current active module
	def __saveSettings(self):
		# modules
		self.__l_usedModules = list()
		for i in range(self.__p_selectModule.treeWidgetModules.topLevelItemCount()):
			item = self.__p_selectModule.treeWidgetModules.topLevelItem(i)

			for c in range(item.childCount()):
				child = item.child(c)

				if (child.checkState(0) == Qt.Checked):
					self.__l_usedModules.append(child.text(0))
				# end if
			# end for
		# end for
		
		# main window settings
		self.__p_settingsHandle.setValue("main/geo", self.saveGeometry())
		if (self.__v_moduleCounter > 0):
			self.__p_settingsHandle.setValue("main/state", self.saveState())
		# end if
		self.__p_settingsHandle.setValue("main/displayName", self.windowTitle().split()[0])
		
		# used module settings
		self.__p_settingsHandle.setValue("module/used", self.__l_usedModules)
		
		# settings
		self.__p_settingsHandle.setValue("settings/saveOnExit", self.actionSaveSettingsOnExit.isChecked())
	# end __saveSettings

	
	# --- module handler begin ---
	

	## @brief search for modules
	# @param self The object pointer.
	#
	# Load all modules from self.__v_modulePath
	def __loadModules(self):
		# init variables
		loadOrder = ["hidden", "setting", "application"]

		currentDir = os.path.abspath(os.curdir)
		modulesPath = currentDir + "/" + self.__v_modulePath
		content = os.listdir(modulesPath)
		content.sort()
		modules = []
		moduleNames = []
		
		# clear gui list
		self.__p_selectModule.treeWidgetModules.reset()
		itemList = {"hidden": [], "setting": [], "application": []}

		# search for modules in module order
		index = 0
		for moduleClassType in loadOrder:
			# find modules
			for name in content:
				# only direcotries without .* and ..
				if (not os.path.isdir(modulesPath + name) or re.match("^\.", name)):
					continue
				# end if
				
				# don't load modules twice
				if (name in moduleNames):
					continue
				# end if

				m = re.match("^(\d+)(.*)$", name)
				suffix = ""
				if (m):
					suffix = m.group(1)
					name = m.group(2)
				# end if

				# change into module directory
				moduleDir = modulesPath + suffix + name
				os.chdir(moduleDir)

				# import module
				fullpath_to_py = moduleDir + "/" + name + ".py"
				if not os.path.isfile(fullpath_to_py):
					continue
				# end if
				
				modHandle = imp.load_source(name, fullpath_to_py)

				# switch back to main directory
				os.chdir(currentDir)

				# auf klasse pruefen
				if (moduleClassType + "ModuleClass" in dir(modHandle)):
					moduleNames.append(suffix+name)
					
					# search for dependencies
					dependencies = ""
					dependenciyList = list()
					if ("dependencies" in dir(modHandle)):
						dependenciyList = modHandle.dependencies
						for d in modHandle.dependencies:
							dependencies += d + ", "
						# end for
						
						dependencies = dependencies[0:len(dependencies) - 2]
					# end if
					item = QTreeWidgetItem([name, dependencies])
					item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
					
					path = modulesPath + suffix + name
					path = re.sub(r'[\\/]+', '/', path)
					module = {"name" : name, "modHandle" : modHandle, "handle" : False, "suffix" : suffix, "path" : path, "dependencies": dependenciyList}
					
					# don't load unused modules
					if (name not in self.__l_usedModules):
						item.setCheckState(0, Qt.Unchecked)
						module["modHandle"] = False
						delete(modHandle)
					else:
						item.setCheckState(0, Qt.Checked)
					# end fi
					
					modules.append(module)

					itemList[moduleClassType].append(item)

					continue
				else:
					delete(modHandle)
				# end if
			# end for
			
			# add items to tree widget
			item = self.__p_selectModule.treeWidgetModules.topLevelItem(index)
			item.addChildren(itemList[moduleClassType])
			
			index += 1
		# end for - search for modules in module order
		
		# init modules
		for module in modules:
			if (module["modHandle"] == False):
				continue
			# end if
			#module["handle"] = module["modHandle"].module(None, module["name"])
			module["handle"] = module["modHandle"].module(self, module["name"])
			
			#self.__p_logger.debug("load module " + module["name"])
		# end for - init modules


		# set static functions
		abstractModuleClass.d_modules = dict()
		abstractModuleClass.p_progressBar = self.progressBarGlobal
		abstractModuleClass.p_progressBarThread = self.__p_progressBarThread


		# open modules and load GUI
		firstDockWidget = None
		for module in modules:
			moduleName = module['name']
			moduleHand = module['handle']
			
			try:
				# Wichtig: Damit auch bei nicht geladenen Modulen die dependencies ueberprueft werden koennen.
				abstractModuleClass.d_modules[moduleName] = module
				
				# if module not used
				if (module["modHandle"] == False):
					continue
				# end if
				
				moduleDir = modulesPath + module["suffix"] + moduleName
	
				# find *.py files in the specific modules directory
				os.chdir(moduleDir)
				content = os.listdir(moduleDir)
				includes = dict()
				for filename in content:
					if (os.path.isfile(moduleDir + "/" + filename)):
						if (re.match(".*\.py$", filename) and not (moduleName + ".py") == filename ):
							name = filename[0:-3]
							includes[name] = imp.load_source(name, moduleDir + "/" + filename)
						# end if
					# end if
				# end for
				os.chdir(currentDir)

				# set module settings
				moduleHand.setModulePath(self.__v_modulePath + module["suffix"] + moduleName, os.path.abspath(os.curdir))
				moduleHand.setIncludes(includes)
	
				# check for module type
				moduleClassType = moduleHand.getClassType()

				# module type specific init
				if (moduleClassType != 'hidden'):
					# load [moduleName].ui
					self.__p_logger.setLevel(logging.WARN)
					uic.loadUi(moduleDir + "/" +moduleName + ".ui", moduleHand)
					self.__p_logger.setLevel(abstractModuleClass.loglevel)

					# load module settings
					moduleHand.initPreSettings()
					moduleHand.handleSettings()
					moduleHand.loadSettings()
				# end if

				# join in specific modules folder for initModule
				os.chdir(moduleDir)
				moduleHand.initModule()
				os.chdir(currentDir)
	
				# add module widget to GUI
				if (moduleClassType != 'hidden'):
					iconPath = False
					icon = None
					
					# get icon path
					iconPath = moduleHand.getIconPath()
					
					# try to load icon
					if (iconPath != False):
						icon = QIcon(iconPath)
					# end if
					
					displayName = moduleHand.getDisplayName()
					
					# init menu button
					button = moduleHand.getMenuButton()
					button.setText(displayName)
					
					# dock widget for current module
					# ... create
					dockWidget = mainWindowDockWidget(displayName, self)
					
					# ... set object name and title
					dockWidget.setObjectName(displayName)
					dockWidget.setWindowTitle(displayName)
					
					# ... add module as widget
					dockWidget.setWidget(moduleHand)
					
					# ... add dock widget to main window
					self.addDockWidget(Qt.LeftDockWidgetArea, dockWidget)
					
					# ... hide dock widget
					dockWidget.setVisible(False)
					
					# tabify all dock widgets
					if (firstDockWidget == None):
						firstDockWidget = dockWidget
					else:
						self.tabifyDockWidget(firstDockWidget, dockWidget)
					# end if
					
					# ... Set window icon.
					dockWidget.setWindowIcon(moduleHand.getMenuButton().icon())
					
					# ... Connect signal for checking and unchecking menu button on visibility change.
					#     If module is tabbed then set active module as current module.
					dockWidget.visibilityChanged[bool].connect(partial(self.__onModuleVisibilityChanged, dockWidget))


					# add button for application module and action for setting module					
					if (moduleClassType == 'application'):
						# get menu button
						button = moduleHand.getMenuButton()
						
						# set icon for menu button
						if (icon != None):
							button.setIcon(icon)
						# end if
						
						# add menu button to tool bar
						self.toolBar.addWidget(button)
						
						# connect signal from application menu button
						button.clicked[QObject].connect(self.__onModuleButtonClicked)
					else:
						# get action
						action = dockWidget.toggleViewAction()
						
						# set icon
						if (icon != None):
							action.setIcon(icon)
						# end if
						
						# add action to settings menu
						self.menuModuleSettings.addAction(action)
					# end if
				else:
					moduleHand.setParent(None)
				# end if
			except Exception as e:
				msg = "Error in module " + moduleName
				self.__p_logger.critical(msg)
				print(msg)
				raise e
			# end try
		# end for


		# init gui
		for module in modules:
			if (module["modHandle"] == False):
				continue
			# end if
			
			self.__v_moduleCounter += 1
			
			moduleDir = modulesPath + module["suffix"] + module["name"]
			moduleClassType = module["handle"].getClassType()
			
			if (moduleClassType != "hidden"):
				os.chdir(moduleDir)

				try:
					module["handle"].initGUI()
				except Exception as e:
					msg = "Fehler in Module " + module["name"]
					self.__p_logger.critical(msg)
					print(msg)
					raise e
				# end try

				os.chdir(currentDir)
			# end if
		# end for
		
		usedModules = self.__l_usedModules.copy()
		# remove not known used modules
		for moduleName in usedModules:
			if (moduleName not in abstractModuleClass.d_modules):
				self.__l_usedModules.remove(moduleName)
				
				continue
			# end if
	# end __loadModules
	
	
	# --- module slots begin ---
	

	## @brief Slot for dock widget visibility change.
	# @param self The object pointer.
	# @param dockWidget dockWidget form current module
	# @param v visibility as True or False
	@pyqtSlot(QDockWidget, bool)
	def __onModuleVisibilityChanged(self, dockWidget, v):
		module = dockWidget.widget()
		
		module.getMenuButton().setChecked(dockWidget.isVisible())
		
		if (v):
			mainWindowDockWidget.setAsCurrent(dockWidget)
			
			#self.__p_currentModule = module
			#self.__p_currentModule.onActive()
		else:
			module.onHide()
		# end if
	# end __onModuleVisibilityChanged
	
	## @brief if menu button was clicked
	# @param self The object pointer.
	# @param module: module pointer
	# visible this module in mdiArea
	@pyqtSlot(QObject)
	def __onModuleButtonClicked(self, module):
		modParent = module.parent()
		
		# show or hide dock widget
		modParent.setVisible(not modParent.isVisible())
		
		# set menu button checked or none checked
		module.getMenuButton().setChecked(modParent.isVisible())
		
		#self.__p_currentModule = module
	# end __onModuleButtonClicked
	
	# --- module slots end ---
	
	# --- module handler end ---
	
	
	# --- gui slots begin ---
	
	
	## @brief Qt slot to move dock widget to bottom dock widget area.
	# @param self The object pointer.
	@pyqtSlot()
	def onMoveLoggerToBottom(self):
		self.removeDockWidget(self.__p_loggerDockWidget)
		self.addDockWidget(Qt.BottomDockWidgetArea, self.__p_loggerDockWidget)
		self.__p_loggerDockWidget.show()
	# end onMoveLoggerToBottom
	
	
	## @brief show on help dialog
	# @param self The object pointer.
	@pyqtSlot()
	def __onHelp(self):
		path = os.path.abspath(os.curdir) + "/doc/index.chm"
		QProcess.startDetached("hh.exe " + path)
	# end __onHelp
	
	## @brief private slot for menu bar: settings -> load default
	# @param self The object pointer.
	@pyqtSlot()
	def __onSettingsDefault(self):
		currentDockWidget = mainWindowDockWidget.getCurrentWidget()
		if (currentDockWidget == None):
			return
		# end if
		currentModule = currentDockWidget.widget()
		
		currentModule.loadDefaultSettings()
		self.__p_logger.debug('Load default settings for %s.', currentModule.windowTitle())
	# end __onSettingsDefault
	
	## @brief private slot for main bar: settings -> load
	# @param self The object pointer.
	@pyqtSlot()
	def __onSettingsLoad(self):
		currentDockWidget = mainWindowDockWidget.getCurrentWidget()
		if (currentDockWidget == None):
			return
		# end if
		currentModule = currentDockWidget.widget()
		
		currentModule.loadSettings()
		self.__p_logger.debug('Load settings for %s.', currentModule.windowTitle())
	# end __onSettingsLoad
	
	## @brief private slot for menu bar: settings -> save
	# @param self The object pointer.
	@pyqtSlot()
	def __onSettingsSave(self):
		currentDockWidget = mainWindowDockWidget.getCurrentWidget()
		if (currentDockWidget == None):
			return
		# end if
		currentModule = currentDockWidget.widget()
		
		currentModule.saveSettings()
		self.__p_logger.debug('Save settings for %s.', currentModule.windowTitle())
	# end __onSettingsSave
	
	## @brief debug function: Print settings from current active module
	# @param self The object pointer.
	@pyqtSlot()
	def __onPrintSettings(self):
		currentDockWidget = mainWindowDockWidget.getCurrentWidget()
		if (currentDockWidget == None):
			return
		# end if
		currentModule = currentDockWidget.widget()
		
		print(currentModule.windowTitle())
		print(currentModule.getSettings())
		# end if
	# end __onPrintSettings
	
	## @brief debug function: Delete all module settings
	# @param self The object pointer.
	@pyqtSlot()
	def __onDelAllSettings(self):
		modules = abstractModuleClass.d_modules
		
		# dell all module settings
		self.__p_settingsHandle.remove('module_settings')
		#self.__p_settingsHandle.setValue()
		#self.__p_settingsHandle.endGroup()
		
		for name in modules:
			if (modules[name]["modHandle"] == False):
				continue
			# end if
			
			if (modules[name]["handle"].getClassType() != "hidden"):
				modules[name]["handle"].deleteSettings()
			# end if
			
		# end for
	# end __onDelAllSettings

	## @brief private slot for menu bar: settings -> save all
	# @param self The object pointer.
	@pyqtSlot()
	def __onSettingsSaveAll(self):
		modules = abstractModuleClass.d_modules
		
		for name in modules:
			if (modules[name]["modHandle"] == False):
				continue
			# end if
			
			if (modules[name]["handle"].getClassType() != "hidden"):
				modules[name]["handle"].saveSettings()
			# end if
		# end for
	# def __onSettingsSaveAll
	
	
	# --- gui slots end ---
	
	
	
	# --- main tab slots begin ---
	
	## @brief private slot for push button select all
	# @param self The object pointer.
	@pyqtSlot()
	def __selectAll(self):
		self.__l_usedModules = []
		for i in range(self.__p_selectModule.treeWidgetModules.topLevelItemCount()):
			item = self.__p_selectModule.treeWidgetModules.topLevelItem(i)
			for c in range(item.childCount()):
				child = item.child(c)
				child.setCheckState(0, Qt.Checked)
				self.__l_usedModules.append(child.text(0))
			# end for
		# end for
	# end __selectAll
	
	## @brief private slot for push button unselect all
	# @param self The object pointer.
	@pyqtSlot()
	def __unselectAll(self):
		self.__l_usedModules = []
		for i in range(self.__p_selectModule.treeWidgetModules.topLevelItemCount()):
			item = self.__p_selectModule.treeWidgetModules.topLevelItem(i)
			for c in range(item.childCount()):
				child = item.child(c)
				child.setCheckState(0, Qt.Unchecked)
			# end for
		# end for
	# end __unselectAll
	
	@pyqtSlot(QTreeWidgetItem, int)
	def __onTreeWidgetChanged(self, item, column):
		modules = abstractModuleClass.d_modules
		name = item.text(column)

		if (item.checkState(column) == Qt.Checked):
			if (self.__checkForDependencies(name)):
				if (name not in self.__l_usedModules):
					self.__l_usedModules.append(name)
				# end if
			else:
				item.setCheckState(column, Qt.Unchecked)
			# end if
		else:
			if (name in self.__l_usedModules):
				# if another module depend this module ?
				for modName in modules:
					if (modName in self.__l_usedModules and name in modules[modName]["dependencies"]):
						self.__l_usedModules.remove(modName)
						item = self.__treeWidgetChild(modName)
						item.setCheckState(column, Qt.Unchecked)
					# end if
				# end for
				
				self.__l_usedModules.remove(name)
			# end if
		# end if
	# end __onTreeWidgetChanged
	
	# --- main tab slots end ---
	
	
	def __treeWidgetChild(self, childName, treeWidget = False):
		if (treeWidget == False):
			treeWidget = self.__p_selectModule.treeWidgetModules
		# end if
		
		for i in range(treeWidget.topLevelItemCount()):
			item = treeWidget.topLevelItem(i)
			for c in range(item.childCount()):
				child = item.child(c)
				if (child.text(0) == childName):
					return child
				# end if
			# end for
		# end for
		
		return False
	# end __treeWidgetChild
	
	def __checkForDependencies(self, name):
		module = abstractModuleClass.d_modules[name]
		#module = self.__l_modules[name]
		for depModule in module["dependencies"]:
			if (depModule not in self.__l_usedModules):
				child = self.__treeWidgetChild(depModule)
				if (child != False):
					self.__l_usedModules.append(depModule)
					child.setCheckState(0, Qt.Checked)
				else:
					self.__p_logger.critical("module %s not found", depModule)
					return False
				# end if
			# end if
		# end for
		
		return True
	# end __checkForDependencies



	# ---- private end ----
	
	
	
	## @brief init function
	# @param self The object pointer.
	# @param availGeo available geometry as QRect
	# 
	# This init function load the modules an initialize the main gui. 
	def init(self, availGeo):
		self.__p_logger.debug("available geometry " + str(availGeo))
		self.__p_logger.debug("try load main window settings")
		
		self.setDockNestingEnabled(True)
		
		# load settings
		self.__loadSettings()

		# load modules
		self.__p_logger.debug("try load modules...")
		self.__loadModules()
		self.__p_logger.debug("load modules finished")

		# load state after modules		
		state = self.__p_settingsHandle.value('main/state')
		if (state):
			self.restoreState(state)
		# end if
		
	
		# expend all trees in module dialog
		for i in range(self.__p_selectModule.treeWidgetModules.topLevelItemCount()):
			item = self.__p_selectModule.treeWidgetModules.topLevelItem(i)
			item.setExpanded(True)
		# end for

		# connect signals from settings menue
		self.actionSettingsLoad.triggered.connect(self.__onSettingsLoad)
		self.actionSettingsDefault.triggered.connect(self.__onSettingsDefault)
		self.actionSettingsSave.triggered.connect(self.__onSettingsSave)
		self.actionSettingsSaveAll.triggered.connect(self.__onSettingsSaveAll)
		
		# connect signals from main tab
		self.__p_selectModule.pushButtonSelectAll.clicked.connect(self.__selectAll)
		self.__p_selectModule.pushButtonUnselectAll.clicked.connect(self.__unselectAll)
		self.__p_selectModule.treeWidgetModules.itemChanged[QTreeWidgetItem, int].connect(self.__onTreeWidgetChanged)
		
		# check for window height
		# if available desktop height smaler than main window height, then move the logger dock widget to the left site
		if (availGeo.height() < self.height()):
			self.__p_logger.warn('Main Window was to height.')
		# end if
		
		# scroll log window
		self.__p_loggerListWidget.scrollToBottom()
	# end init


	## @brief main windows close event
	# @param self The object pointer.
	# @param event Qt event
	# 
	# Save all settings before closing.
	def closeEvent(self, event):
		modules = abstractModuleClass.d_modules
		
		# pre close
		for name in modules:
			if (modules[name]["modHandle"] == False):
				continue
			# end if
			
			modules[name]["handle"].onPreClose()
		# end for


		if (self.actionSaveSettingsOnExit.isChecked()):
			# save user settings
			self.__saveSettings()
			
			# save module settings
			self.__onSettingsSaveAll()
		# end if
		
		# delete all plots
		abstractModuleClass.deleteAllPlots()

		# close all modules
		for name in modules:
			if (modules[name]["modHandle"] == False):
				continue
			# end if

			modules[name]["handle"].onClose()

			for inc in modules[name]["handle"].getIncludes():
				del(inc)
			# end for

			delete(modules[name]["handle"])
			delete(modules[name]["modHandle"])
		# end for
		
		del(modules)
		del(abstractModuleClass.d_modules)

		#QMainWindow.__del__(self)
	# end closeEvent

	## @brief public interface function to freeze the GUI
	# @param self The object pointer.
	# @param freeze boolean
	# 
	# true: The user can't change the current module
	def setFreeze(self, freeze = False):
		curId = self.tabWidgetModules.currentIndex()

		for i in range(int(self.tabWidgetModules.count())):
			w = self.tabWidgetModules.widget(i)

			if (i != curId):
				w.setEnabled(not freeze)
			# end if
		# end for
	# end setFreeze

	## @brief return Output Widget object
	# @param self The object pointer.
	# @retval pointer logging output widget object
	def getOutputWidget(self):
		return self.listWidgetConsole
Example #4
0
class Window(QMainWindow):
    def __init__(self,parent = None):
        QMainWindow.__init__(self,parent)
        self.resize(1024,768)
        self.setWindowTitle("Sabel")
        self.setWindowIcon(Icons.sabel)
        self.centralwidget = QWidget(self)
        self.horizontalLayout = QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setMargin(0)
        self.cmdList = config.cmds()
        self.paramList = config.params()
        
        '''A.Editor TabWidget'''
        '''This parent is for findbar and vertical layout'''
        self.editorLayoutWidget = QWidget(self)
        self.editorLayoutWidget.setMinimumWidth(800)
        self.tabWidget = EditorTab(self)
        self.editorLayout = QVBoxLayout(self.editorLayoutWidget)
        self.editorLayout.setMargin(0)
        self.editorLayout.addWidget(self.tabWidget)
        
        "0.Style Layout"
        self.styleLayoutWidget = QFrame()
        self.styleLayoutWidget.setFrameShape(QFrame.StyledPanel)
        self.styleLayout = QHBoxLayout(self.styleLayoutWidget)
        self.styleTest = QPushButton(self.styleLayoutWidget)
        self.styleTest.setText("Change Styles")
        self.styleTest.clicked.connect(self.changeStyleSheet)
        self.popWidget = Popup(self.styleLayoutWidget)
        self.styleLayout.addWidget(self.styleTest)
        self.styleLayout.addWidget(self.popWidget)
        self.styleLayout.setMargin(0)
        self.editorLayout.addWidget(self.styleLayoutWidget)
        self.styleLayoutWidget.hide()
        
        "1.Find Layout"
        self.findLayoutWidget = QFrame()
        self.findLayoutWidget.setFrameShape(QFrame.StyledPanel)
        self.findLayout = QHBoxLayout(self.findLayoutWidget)
        self.lineEdit = QLineEdit(self.findLayoutWidget)
        self.lineEdit_2 = QLineEdit(self.findLayoutWidget)
        self.findClose = QPushButton(self.findLayoutWidget)
        self.findClose.setIcon(Icons.close_view)
        self.findClose.setFlat(True)
        self.findClose.clicked.connect(self.findBarShow)
        self.find = QPushButton(self.findLayoutWidget)
        self.find.setText("Find")
        self.find.clicked.connect(self.findCurrentText)
        self.replacefind = QPushButton(self.findLayoutWidget)
        self.replacefind.setText("Replace/Find")
        self.replacefind.clicked.connect(self.replaceFindText)
        self.replace = QPushButton(self.findLayoutWidget)
        self.replace.setText("Replace")
        self.replace.clicked.connect(self.replaceCurrentText)
        self.replaceAll = QPushButton(self.findLayoutWidget)
        self.replaceAll.setText("Replace All")
        self.replaceAll.clicked.connect(self.replaceAllText)
        self.caseSensitive = QToolButton(self.findLayoutWidget)
        self.caseSensitive.setIcon(Icons.font)
        self.caseSensitive.setCheckable(True)
        self.wholeWord = QToolButton(self.findLayoutWidget)
        self.wholeWord.setText("ww")
        self.wholeWord.setCheckable(True)
        self.regex = QToolButton(self.findLayoutWidget)
        self.regex.setText("re")
        self.regex.setCheckable(True)
        self.backward = QToolButton(self.findLayoutWidget)
        self.backward.setText("bk")
        self.backward.setCheckable(True)
        self.backward.setDisabled(True)
        self.findLayout.addWidget(self.findClose)
        self.findLayout.addWidget(self.find)
        self.findLayout.addWidget(self.lineEdit)
        self.findLayout.addWidget(self.lineEdit_2)
        self.findLayout.addWidget(self.caseSensitive)
        self.findLayout.addWidget(self.wholeWord)
        self.findLayout.addWidget(self.regex)
        self.findLayout.addWidget(self.backward)
        self.findLayout.addWidget(self.replacefind)
        self.findLayout.addWidget(self.replace)
        self.findLayout.addWidget(self.replaceAll)
        self.findLayout.setMargin(0)
        self.findLayoutWidget.setMaximumHeight(25)
        self.editorLayout.addWidget(self.findLayoutWidget)
        self.findLayoutWidget.hide()
        
        
        '''B.Designer'''
        '''This parent is for widgetsbar and design layout'''
        self.designerLayoutWidget = QWidget(self)
        self.designerLayoutWidget.setMinimumWidth(800)
        self.designerWidget = Screen(self)
        self.designerLayoutWidget.hide()
        self.designerLayout = QVBoxLayout(self.designerLayoutWidget)
        self.designerLayout.setMargin(0)
        self.designerLayout.addWidget(self.designerWidget)
        
        '''C.Level Editor'''
        '''This parent is for spritesheets and level layout'''
        self.levelLayoutWidget = QWidget(self)
        self.levelLayoutWidget.setMinimumWidth(800)
        self.levelWidget = Level(self)
        self.levelLayoutWidget.hide()
        self.levelLayout = QVBoxLayout(self.levelLayoutWidget)
        self.levelLayout.setMargin(0)
        self.levelLayout.addWidget(self.levelWidget)
        
        '''D.Explorer TabWidget'''
        self.explorerTabWidget = TreeTab(self)
        #self.explorerTabWidget.setMaximumWidth(200)
        '''1.Project Tree'''
        self.tab_5 = QWidget()
        #self.tab_5.setMaximumWidth(200)
        self.VerticalLayout_2 = QVBoxLayout(self.tab_5)#QHBoxLayout(self.tab_5)
        self.VerticalLayout_2.setMargin(0)
        self.treeWidget = ProjectTree(self.tab_5)
        #self.treeWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        #self.treeWidget.horizontalScrollBar().show()
        self.VerticalLayout_2.addWidget(self.treeWidget)
        
        '''2.Outline Tree'''
        self.tab_2 = QWidget()
        #self.tab_2.setMaximumWidth(200)
        self.VerticalLayout_3 = QVBoxLayout(self.tab_2)
        self.VerticalLayout_3.setMargin(0)
        self.outlineWidget = OutlineTree(self.tab_2)
        self.outlineWidget.itemDoubleClicked.connect(self.gotoLine)
        self.VerticalLayout_3.addWidget(self.outlineWidget)
        
        '''E.Output TabWidget'''
        self.outputTabWidget = OutputTab(self)
        self.tabWidget.currentChanged.connect(self.fileChanged)
        self.explorerTabWidget.currentChanged.connect(self.closeExplorer)
        self.outputTabWidget.currentChanged.connect(self.closeConsole)
        self.tabWidget.setTabsClosable(True)
        self.tabWidget.setTabShape(0)
            
        '''1.Output layout'''
        #must check
        self.tab_6 = QWidget()
        self.horizontalLayout_2 = QVBoxLayout(self.tab_6)
        self.horizontalLayout_2.setMargin(0)
        self.textEdit = QTextEdit()
        self.inputLayout = QHBoxLayout()
        self.inputLayout.setMargin(0)
        self.fileButton = QPushButton()
        self.fileButton.setText("File")
        self.fileButton.clicked.connect(self.getFile)
        self.runButton = QPushButton()
        self.runButton.setFlat(True)
        self.runButton.setIcon(Icons.go)
        self.combo = QComboBox()
        self.combo.setFixedWidth(100)
        self.comboAdd = QPushButton()
        self.comboAdd.setIcon(Icons.add)
        self.comboAdd.setFlat(True)
        self.comboAdd.clicked.connect(self.addCmd)
        self.comboDel = QPushButton()
        self.comboDel.setIcon(Icons.close_view)
        self.comboDel.setFlat(True)
        self.comboDel.clicked.connect(self.delCmd)
        self.combo2 = QComboBox()
        self.combo2.setFixedWidth(500)
        self.combo2Add = QPushButton()
        self.combo2Add.setIcon(Icons.add)
        self.combo2Add.setFlat(True)
        self.combo2Add.clicked.connect(self.addParam)
        self.combo2Del = QPushButton()
        self.combo2Del.setIcon(Icons.close_view)
        self.combo2Del.setFlat(True)
        self.combo2Del.clicked.connect(self.delParam)
        if(self.checkHasValue(self.cmdList)):
            for cmd in self.cmdList:
                self.combo.addItem(cmd)
        else:
            self.cmdList = []
        if(self.checkHasValue(self.paramList)):
            for param in self.paramList:
                self.combo2.addItem(param)
        else:
            self.paramList = []
        
        self.horizontalLayout_2.addWidget(self.textEdit)
        self.inputLayout.addWidget(QLabel("<b>Command:</b>"))
        self.inputLayout.addWidget(self.combo)
        self.inputLayout.addWidget(self.comboAdd)
        self.inputLayout.addWidget(self.comboDel)
        self.inputLayout.addWidget(QLabel("<b>Parameters:</b>"))
        self.inputLayout.addWidget(self.combo2)
        self.inputLayout.addWidget(self.combo2Add)
        self.inputLayout.addWidget(self.combo2Del)
        self.inputLayout.addWidget(self.fileButton)
        self.inputLayout.addWidget(self.runButton)
        self.horizontalLayout_2.addLayout(self.inputLayout)
        
        '''2.Error Layout'''
        self.tab_7 = QWidget()
        self.horizontalLayout_4 = QHBoxLayout(self.tab_7)
        self.horizontalLayout_4.setMargin(0)
        self.errorTree = ErrorTree(self.tab_7)
        self.errorTree.itemDoubleClicked.connect(self.errorLine)
        self.horizontalLayout_4.addWidget(self.errorTree)
        
        '''TabWidgets tabs'''
        #self.designerWidget.addTab(QWidget(self),"")
        #self.designerWidget.setTabIcon(0,Icons.close_view)
        #self.levelWidget.addTab(QWidget(self),"")
        #self.levelWidget.setTabIcon(0,Icons.close_view)
        
        self.explorerTabWidget.addTab(self.tab_5,"Projects")
        self.explorerTabWidget.addTab(self.tab_2,"Outline")
        self.explorerTabWidget.addTab(QWidget(self),"")
        self.explorerTabWidget.setTabIcon(0,Icons.cprj)
        self.explorerTabWidget.setTabIcon(1,Icons.envvar)
        self.explorerTabWidget.setTabIcon(2,Icons.close_view)
        self.outputTabWidget.addTab(self.tab_7,"Error")
        self.outputTabWidget.addTab(self.tab_6,"Output")
        self.outputTabWidget.addTab(QWidget(self),"")
        self.outputTabWidget.setTabIcon(0,Icons.error)
        self.outputTabWidget.setTabIcon(1,Icons.console_view)
        self.outputTabWidget.setTabIcon(2,Icons.close_view)
        
        '''Splitters'''
        self.split1 = QSplitter(Qt.Horizontal)
        self.split1.addWidget(self.explorerTabWidget)
        self.split1.addWidget(self.editorLayoutWidget)
        self.split1.addWidget(self.designerLayoutWidget)
        self.split1.addWidget(self.levelLayoutWidget)
        #self.split1.addWidget(self.tab_5)
        
        self.split2 = QSplitter(Qt.Vertical)
        self.split2.addWidget(self.split1)
        self.split2.addWidget(self.outputTabWidget)
        self.horizontalLayout.addWidget(self.split2)
        
        
        '''Status Bar'''
        self.statusbar = QStatusBar(self)
        self.aboutButton = QPushButton(self)
        self.aboutButton.setFlat(True)
        self.aboutButton.setIcon(Icons.anchor)
        self.aboutButton.clicked.connect(self.about)
        self.expButton = QPushButton(self)
        self.expButton.setFlat(True)
        self.expButton.setIcon(Icons.prj)
        self.expButton.clicked.connect(self.exp)
        self.cmdButton = QPushButton(self)
        self.cmdButton.setFlat(True)
        self.cmdButton.setIcon(Icons.console_view)
        self.cmdButton.clicked.connect(self.cmd)
        self.cmdButton.setShortcut('Ctrl+D')
        self.imgButton = QPushButton(self)
        self.imgButton.setFlat(True)
        self.imgButton.setIcon(Icons.color_palette)
        self.imgButton.clicked.connect(self.design)
        self.imgButton.setShortcut('Ctrl+I')
        self.findButton = QPushButton(self)
        self.findButton.setFlat(True)
        self.findButton.setIcon(Icons.find)
        self.findButton.setShortcut("Ctrl+F")
        self.findButton.clicked.connect(self.findBarShow)
        '''
        self.zoominButton = QPushButton(self)
        self.zoominButton.setFlat(True)
        self.zoominButton.setIcon(Icons.zoomplus)
        self.zoominButton.clicked.connect(self.zoomin)
        self.zoomoutButton = QPushButton(self)
        self.zoomoutButton.setFlat(True)
        self.zoomoutButton.setIcon(Icons.zoomminus)
        self.zoomoutButton.clicked.connect(self.zoomout)
        '''

        '''Status Text,Line Text, Progress Bar and Stop Button'''
        self.statusText = QLabel("Writable")
        #self.statusText.setAlignment(Qt.AlignCenter)
        self.statusText.setFixedWidth(200)
        self.lineText = QLabel("")
        self.lineText.setFixedWidth(50)
        
        self.progressbar = QProgressBar()
        self.progressbar.setMinimum(0)
        self.progressbar.setMaximum(100)
        self.stopButton = QPushButton(self)
        self.stopButton.setFlat(True)
        self.stopButton.setIcon(Icons.stop)
        self.stopButton.clicked.connect(self.forceStop)
        self.progressbar.hide()
        self.stopButton.hide()
        self.temp = False
        self.progress = False
        self.counter = 0
        
        '''Adding all widgets to Status Bar'''
        self.statusbar.addWidget(self.aboutButton)
        self.statusbar.addWidget(self.expButton)
        self.statusbar.addWidget(self.cmdButton)
        self.statusbar.addWidget(self.imgButton)
        self.statusbar.addWidget(self.findButton)
        #self.statusbar.addWidget(QWidget(self))
        #self.statusbar.addWidget(self.zoominButton)
        #self.statusbar.addWidget(self.zoomoutButton)
        self.statusbar.addWidget(self.statusText)
        self.statusbar.addWidget(self.lineText)
        self.statusbar.addWidget(self.progressbar)
        self.statusbar.addWidget(self.stopButton)
        #self.statusbar.setFixedHeight(18)
        
        ''''Initializing Coloring Style'''
        self.initEditorStyle()
        self.initStyleSheet()
        '''Adding Cental Widget and Status Bar'''
        self.setCentralWidget(self.centralwidget)
        self.setStatusBar(self.statusbar)
        self.textEdit.setReadOnly(True)
        
        
    def initStyleSheet(self):
        import stylesheet
        self.setStyleSheet(stylesheet.mainstyl)
        self.tabWidget.tabBar().setStyleSheet(stylesheet.stletabb)
        self.explorerTabWidget.tabBar().setStyleSheet(stylesheet.stletabb)
        self.outputTabWidget.tabBar().setStyleSheet(stylesheet.stletabb)
        self.popWidget.setStyleSheet(stylesheet.popbg)
        self.popWidget.hide()
        
        
        ''' This is for changing the palette/window colors to Theme '''
    def initEditorStyle(self):
        pass
        #editStyle = config.readStyle()
        #print editStyle
        #pal = QPalette(self.explorerTabWidget.palette())
        #print pal.color(QPalette.Base).name()
        #print pal.color(QPalette.Window).name()
        #pal.setColor(QPalette.Base,self.colorStyle.paper)
        #pal.setColor(QPalette.Text,self.colorStyle.color)
        #self.explorerTabWidget.setPalette(pal)
        #self.outputTabWidget.setPalette(pal)
         
    ''' This is only for testing dont know if it works for builds '''    
    def changeStyleSheet(self):
        ''' Dynamically load the changed stylesheet.py and load the modules and change 
            the style at runtime saves countless deploys '''
        import imp
        foo = imp.load_source('stletabb', workDir+"/stylesheet.py")
        #print foo.stletabb
        #self.setStyleSheet(stylesheet.mainstyl)
        self.tabWidget.tabBar().setStyleSheet(foo.stletabb)
        self.popWidget.setStyleSheet(foo.popbg)
        if(self.popWidget.isHidden()):
            self.popWidget.showPopup()
    
    def build_project(self):
        #current_file = self.files[self.tabWidget.currentIndex()]
        prj = self.treeWidget.getProject()
        if(prj != None):
            self.treeWidget.build(prj)
            
    def run_project(self):
        #current_file = self.files[self.tabWidget.currentIndex()]
        prj = self.treeWidget.getProject()#current_file)
        if(prj != None):
            self.treeWidget.run(prj)
            
    def forceStop(self):
        self.ant.kill()
        self.progressStop()
        
    def kill(self):
        self.deleteLater()
        
#-----------------------------------------------------------------------------------#
#   Menu Actions Functions                                                          #
#-----------------------------------------------------------------------------------#
    def run(self):
        if(config.mode() == 0):
            self.sq.run()
        elif(config.mode() == 1):
            self.adb.run()
        elif(config.mode() == 2):
            self.ios.run()
        elif(config.mode() == 3):
            self.c.run()
            
    def setMode(self, action):
        if(action.text() == "Squ"):
            config.setMode(0)
            self.toolBar.action_Build.setEnabled(False)
            self.toolBar.action_Run.setEnabled(False)
        elif(action.text() == "Emo"):
            config.setMode(1)
            self.toolBar.action_Build.setEnabled(True)
            self.toolBar.action_Run.setEnabled(True)
        elif(action.text() == "Android"):
            config.setMode(2)
            self.toolBar.action_Build.setEnabled(True)
            self.toolBar.action_Run.setEnabled(True)
        elif(action.text() == "ios"):
            config.setMode(3)
            self.toolBar.action_Build.setEnabled(False)
            self.toolBar.action_Run.setEnabled(False)
            
    def openCommand(self):
        text, ok = QInputDialog.getText(self, 'Run Command', 'Command:')
        cmd = str(text)
        if ok and cmd != "":
            import subprocess
            subprocess.Popen(cmd)
     
    def about(self):
        form = DialogAbout(self)
        
    def todo(self):
        form = DialogTodo(self)
        form.show()

    def help(self):
        QMessageBox.about(self,"Help","This is about all The Help that i can Give you now")
        
    def full(self):
        if not self.isFull:
            self.setWindowState(Qt.WindowFullScreen)
            self.isFull = True
        else:
            self.setWindowState(Qt.WindowMaximized)
            self.isFull = False
            
    def android(self):
        form = DialogAndroid(self)
        form.show()
    
    def antt(self):
        form = DialogAnt(self)
        form.show()
        
    def squirrel(self):
        form = DialogSquirrel(self)
        form.show()
        
    def findBarShow(self):
        if(self.findLayoutWidget.isHidden()):
            self.findLayoutWidget.show()
        else:
            self.findLayoutWidget.hide()
            
    def exp(self):
        if(self.explorerTabWidget.isHidden()):
            self.explorerTabWidget.show()
        else:
            self.explorerTabWidget.hide()
    
    def cmd(self):
        if(self.outputTabWidget.isHidden()):
            self.outputTabWidget.show()
        else:
            self.outputTabWidget.hide()
            
    def editor(self):
        if(self.editorLayoutWidget.isHidden()):
            self.editorLayoutWidget.show()
            self.levelLayoutWidget.hide()
            self.designerLayoutWidget.hide()
            
    def design(self):
        if(self.designerLayoutWidget.isHidden()):
            self.designerLayoutWidget.show()
            self.editorLayoutWidget.hide()
            self.levelLayoutWidget.hide()
        else:
            self.designerLayoutWidget.hide()
            self.editorLayoutWidget.show()
            
    def level(self):
        if(self.levelLayoutWidget.isHidden()):
            self.levelLayoutWidget.show()
            self.editorLayoutWidget.hide()
            self.designerLayoutWidget.hide()
        else:
            self.levelLayoutWidget.hide()
            self.editorLayoutWidget.show()
            
    def closeDesigner(self,no):
        pass
        '''
        if(no == self.tiler.closeIndex()):
            if(self.tiler.isHidden()):
                self.tiler.show()
            else:
                self.tiler.setCurrentIndex(1)
                self.tiler.hide()
        '''
     
    '''The current Changed idx of outputTabWidget is passed to this a param'''   
    def closeConsole(self,no = 2):
        if(no == 2):
            if(self.outputTabWidget.isHidden()):
                self.outputTabWidget.show()
            else:
                self.outputTabWidget.setCurrentIndex(1)
                self.outputTabWidget.hide()
                
    def popOutput(self):
        if(self.outputTabWidget.isHidden()):
            self.outputTabWidget.show()
        self.outputTabWidget.setCurrentIndex(1)
    
    def popError(self):
        if(self.outputTabWidget.isHidden()):
            self.outputTabWidget.show()
        self.outputTabWidget.setCurrentIndex(0)
        
    '''The current Changed idx of explorerTabWidget is passed to this a param'''
    def closeExplorer(self,no = 2):
        if(no == 2):
            if(self.explorerTabWidget.isHidden()):
                self.explorerTabWidget.show()
            else:
                self.explorerTabWidget.setCurrentIndex(0)
                self.explorerTabWidget.hide()
        elif(no == 1):
            self.fileChanged(no)
                
    ''' This is to refresh the outline widget'''
    def fileChanged(self,no):
        if(self.explorerTabWidget.currentIndex() == 1):
            edt = self.tabWidget.widget(self.tabWidget.currentIndex())
            source = edt.text()
            self.outlineWidget.parseText(source)
           
    def statusSaving(self):
        self.statusText.setText("Saving")   
    def statusParsing(self):
        self.statusText.setText("Parsing")   
    def statusWriting(self):
        self.statusText.setText("Writable")  
    def statusRunning(self):
        self.statusText.setText("Running")   
    def statusStopping(self):
        self.statusText.setText("Stopping")
    def statusCommand(self):
        self.statusText.setText("Command")
    def statusBuilding(self):
        self.statusText.setText("Building")
    def statusInstalling(self):
        self.statusText.setText("Installing")
    def statusCleaning(self):
        self.statusText.setText("Cleaning")
    def statusCreating(self):
        self.statusText.setText("Creating")
                
    def progressStart(self):
        self.progress == True
        self.temp == True
        if(self.progressbar.isHidden()):
            self.progressbar.show()
        if(self.stopButton.isHidden()):
            self.stopButton.show()
        self.progressbar.setValue(1)
        
    def progressStop(self):
        self.progress == False
        self.temp == False
        self.progressbar.setValue(100)
        if not(self.progressbar.isHidden()):
            self.progressbar.hide()
        if not(self.stopButton.isHidden()):
            self.stopButton.hide()
              
    def progressUpdate(self):
        if(self.progress):
            if(self.temp):
                self.counter += 1
                self.progressbar.setValue(self.counter)
                if(self.counter == 100):
                    self.temp = False
            else:
                self.counter -= 1
                self.progressbar.setValue(self.counter)
                if(self.counter == 0):
                    self.temp = True
            
                
#-----------------------------------------------------------------------------------#
#   Editor Functions                                                                #
#-----------------------------------------------------------------------------------#   
    '''Search and Replace Functions'''  
    def findCurrentText(self):
        edt = self.tabWidget.widget(self.tabWidget.currentIndex())
        edt.findText(self.lineEdit.text(),self.regex.isChecked(),self.caseSensitive.isChecked(),self.wholeWord.isChecked(),self.backward.isChecked())
    def replaceCurrentText(self):
        edt = self.tabWidget.widget(self.tabWidget.currentIndex())
        edt.replaceText(self.lineEdit_2.text()) 
    def replaceFindText(self):
        edt = self.tabWidget.widget(self.tabWidget.currentIndex())
        edt.replaceText(self.lineEdit_2.text())
        self.findCurrentText()      
    def replaceAllText(self):
        edt = self.tabWidget.widget(self.tabWidget.currentIndex())
        while(edt.findText(self.lineEdit.text(),self.regex.isChecked(),self.caseSensitive.isChecked(),self.wholeWord.isChecked(),self.backward.isChecked())):
            edt.replaceText(self.lineEdit_2.text())      
    def errorLine(self,error):
        index = self.tabWidget.currentIndex()
        edt = self.tabWidget.widget(index)
        '''To prevent File item double clicking'''
        if(error.isFile() == False):
            edt.setLine(error.line)
            
    '''Font Functions'''       
    def zoomin(self):
        pass
        #for i in range(len(self.files)):
        #    self.tabWidget.widget(i).zoomin()
    def zoomout(self):
        pass
        #for i in range(len(self.files)):
        #    self.tabWidget.widget(i).zoomout()
            
    ''' Must implement Lexer '''
    def setLexer(self, action):
        pass
        #print action.text()
    
    def setApi(self, action):
        #print action.text()
        for i in range(len(self.files)): #not QString
            self.tabWidget.widget(i).setApi(str(action.text()))
    
    def setFont(self,font):
        config.setFontName(str(font.family()))
        for i in range(len(self.files)):
            self.tabWidget.widget(i).setNewFont(font)
            
    def setFontSize(self,idx):
        fontSize = idx+1
        config.setFontSize(fontSize)
        for i in range(len(self.files)):
            self.tabWidget.widget(i).setFontSize() 
            
    def gotoLine(self,item):
        edt = self.tabWidget.widget(self.tabWidget.currentIndex())
        edt.setLine(item.line)
        
    def updateLine(self,no,col):
        self.lineText.setText(str(no)+" : "+str(col))
            
    def setMargin(self):
        mar = config.margin()
        if(mar == 0): 
            config.setMargin(1)
            for i in range(len(self.files)):
                self.tabWidget.widget(i).setMargin(1)
        else:
            config.setMargin(0)
            for i in range(len(self.files)):
                self.tabWidget.widget(i).setMargin(0)
                
    ''' Toggle '''
    def setIndent(self):
        indent = config.indent()
        if(indent == 0): 
            config.setIndent(1)
            for i in range(len(self.files)):
                self.tabWidget.widget(i).setIndent(1)
        else:
            config.setIndent(0)
            for i in range(len(self.files)):
                self.tabWidget.widget(i).setIndent(0)
    ''' Toggle '''         
    def setWhiteSpace(self):
        white = config.whiteSpace()
        if(white == 0): 
            config.setWhiteSpace(1)
            for i in range(len(self.files)):
                self.tabWidget.widget(i).setWhitespaceVisibility(True)
        else:
            config.setWhiteSpace(0)
            for i in range(len(self.files)):
                self.tabWidget.widget(i).setWhitespaceVisibility(False)
    
    ''' Toggle '''         
    def setEndLine(self):
        for i in range(len(self.files)):
            edt = self.tabWidget.widget(i)
            edt.setEolVisibility(not edt.eolVisibility())
                
    def setEncoding(self, action):
        if(action.text() == "Ascii"):
            config.setAscii()
            for i in range(len(self.files)):
                self.tabWidget.widget(i).setUtf8(False)
        elif(action.text() == "Unicode"):
            config.setUnicode()
            for i in range(len(self.files)):
                self.tabWidget.widget(i).setUtf8(True)
        
    def setThreshold(self,val):
        config.setThresh(val)
        for i in range(len(self.files)):
            #print i
            self.tabWidget.widget(i).setThreshold(val)
    def setTabWidth(self,val):
        config.setTabWidth(val)
        for i in range(len(self.files)):
            #print i
            self.tabWidget.widget(i).setTabWidth(val)
    '''style Functions'''         
#-----------------------------------------------------------------------------------#
#   Command Functions                                                               #
#-----------------------------------------------------------------------------------#   
    def getFile(self):
        self.browsedialog = DialogBrowse(self)
        self.browsedialog.tree.itemDoubleClicked.connect(self.getName)
        self.browsedialog.show()
            
    def getName(self,item):
        if(item.isFile()):
                self.browsedialog.accept()
                fname = item.getPath()
                if not (fname == ""):
                    index = self.combo2.currentIndex()
                    text = str(self.combo2.itemText(index))+" "+fname
                    self.combo2.setItemText(index,text)
                    self.paramList.pop(index)
                    self.paramList.insert(index,text)
                    config.setParam(self.paramList)
                 
    def addCmd(self,index):
        text, ok = QInputDialog.getText(self, 'Add Command', 'Command:')
        if(ok):
            if(str(text) != ''):
                cmd = str(text).upper()
                self.cmdList.append(cmd)
                #print self.cmdList
                self.combo.addItem(cmd)
                config.setCmd(self.cmdList)
                config.setParam(self.paramList)
                
    def delCmd(self):
        index = self.combo.currentIndex()
        self.combo.removeItem(index)
        self.cmdList.pop(index)
        #print self.cmdList
        config.setCmd(self.cmdList)
        
    def addParam(self,index):
        text, ok = QInputDialog.getText(self, 'Add Parameters', 'Params:')
        if(ok):
            if(str(text) != ''):
                param = str(text)
                self.paramList.append(param)
                self.combo2.addItem(param)
                config.setParam(self.paramList)
                
    def delParam(self):
        index = self.combo2.currentIndex()
        self.combo2.removeItem(index)
        self.paramList.pop(index)
        config.setParam(self.paramList)
        
    def checkHasValue(self,list):
        if(list != None and len(list) != 0):
            return True
        else:
            return False
Example #5
0
class MainWindow(QMainWindow):
	def __init__(self):
		QMainWindow.__init__(self)
		
		self.setWindowTitle('%s %s' % (QApplication.applicationName(), QApplication.applicationVersion()));

		self.config = ConfigHandler(os.path.join(os.path.expanduser('~'), '.pywv/pywv.cfg'), self)

		self.setStyle(QStyleFactory.create(self.config.loadStyle()))
		if self.config.loadStyleSheet():
			self.setStyleSheet(self.config.loadStyleSheet())
		else:
			self.setStyleSheet("* {}") # without any stylesheet, windowstyles won't apply


		self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks | QMainWindow.AllowTabbedDocks | QMainWindow.VerticalTabs);

#		self.dummy = QWidget(self)
		self.setCentralWidget(QWidget(self))

		self.pBar = QProgressBar(self)
		self.pBar.setRange(0, self.config.loadReloadInterval())
		self.pBar.setFormat("%v Sekunden")
		if not self.config.loadAutoload():
			self.pBar.hide()

		self.statusBar = QStatusBar(self)
		self.setStatusBar(self.statusBar)
		self.statusBar.addWidget(self.pBar)

		self.reloadTimer = QTimer(self);
		self.reloadTimer.setInterval(self.config.loadReloadInterval() * 1000)
		self.connect(self.reloadTimer, SIGNAL('timeout()'), self.reload_)
		if self.config.loadAutoload():
			self.reloadTimer.start()

		self.autoloadStatusTimer = QTimer(self)
		self.autoloadStatusTimer.setInterval(1000) # 1 sec
		self.connect(self.autoloadStatusTimer, SIGNAL('timeout()'), self.onAutoloadStatus)
		self.autoloadStatusTimer.start()

		self.mAction = self.menuBar().addMenu(self.tr("&Action"))
		self.mAction.addAction(self.tr("&update"), self.reload_, QKeySequence('F5'))
		self.mAction.addAction(self.tr("e&xit"), self.onExit, 'Ctrl+Q')

		self.mStyle = QMenu(self.tr("&Style"), self)
		for s in list(QStyleFactory.keys()):#       // fill in all available Styles
			self.mStyle.addAction(s)
		self.connect(self.mStyle, SIGNAL('triggered(QAction*)'), self.onStyleMenu)

		self.mOption = self.menuBar().addMenu(self.tr("&Options"))
		self.mOption.addAction(self.tr("reloadinterval") , self.onReloadTime , 'F8')
		self.mOption.addAction(self.tr("manage links")   , self.onNewLink    , 'F6')
		self.mOption.addSeparator()

		self.ontopAction       = QAction(self.tr("always on &top")  , self)
		self.showTrayAction    = QAction(self.tr("show tray &icon") , self)
		self.closeToTrayAction = QAction(self.tr("close to &tray")  , self)
		self.autoloadAction    = QAction(self.tr("auto&load")       , self)

		self.ontopAction.setCheckable(True)
		self.showTrayAction.setCheckable(True)
		self.closeToTrayAction.setCheckable(True)
		self.autoloadAction.setCheckable(True)

		self.showTrayAction.setChecked   (self.config.loadShowTray()   )
		self.ontopAction.setChecked      (self.config.loadOntop()      )
		self.closeToTrayAction.setChecked(self.config.loadCloseToTray())
		self.autoloadAction.setChecked   (self.config.loadAutoload()   )

		self.connect(self.ontopAction       , SIGNAL('toggled(bool)') , self.onOntopAction)
		self.connect(self.showTrayAction    , SIGNAL('toggled(bool)') , self.onShowTrayAction)
		self.connect(self.closeToTrayAction , SIGNAL('toggled(bool)') , self.onCloseToTrayAction)
		self.connect(self.autoloadAction    , SIGNAL('toggled(bool)') , self.onAutoloadAction)

		self.mOption.addAction(self.ontopAction)
		self.mOption.addAction(self.showTrayAction)
		self.mOption.addAction(self.closeToTrayAction)
		self.mOption.addAction(self.autoloadAction)
		self.mOption.addSeparator()
		self.mOption.addMenu(self.mStyle)

		self.trayIcon = QSystemTrayIcon(QIcon(':/appicon'), self);
		self.trayMgr = TrayManager(self.config, self.trayIcon)
		self.connect(self.trayIcon, SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self.onTrayIcon)
		if self.config.loadShowTray(): self.trayIcon.show()

		self.trayIconMenu = QMenu()
		self.trayIconMenu.addAction(self.tr("e&xit"), self.onExit)
		self.trayIcon.setContextMenu(self.trayIconMenu)

		self.mAbout = self.menuBar().addMenu(self.tr("&about"))
		self.mAbout.addAction(QApplication.applicationName(), self.onAboutAppAction)
		self.mAbout.addAction("Qt", self.onAboutQtAction)

		self.createWidgets()

		self.resize(self.config.loadWindowSize())
		self.restoreState(self.config.loadWindowState())

		if self.config.loadIsVisible():
			self.show()
			self.reload_()

	def __del__(self):
		self.config.saveWindowState(self.saveState())

	def createSingleWidget(self, name):
#		print 'crt', name, type(name), '\n', self.widgets
#		print 'crt', name, type(name)
		links = self.config.loadLinks()
		if links[name]['type'] == 'generic':
			self.widgets[name] = GenericWidget(name, self.config, self)
		else:
			pluginsAvail = classdirPlugins().all_()
			for plugin in pluginsAvail:
				if links[name]['type'] == plugin['class']:
					pluginClass = plugin['class']
					break
				else:
					continue

			exec('self.widgets[name] = %s(name, self.config, self)' % pluginClass)
		#	print(('loaded plugin', self.widgets[name]))

		self.addDockWidget(0x4, self.widgets[name])
		self.widgets[name].reload_()

	def delWidget(self, name):
		#print 'del', name, type(name), '\n', self.widgets
		self.removeDockWidget(self.widgets[name])
		self.widgets[name].deleteLater()
		self.widgets[name] = None
		del self.widgets[name]

	def createWidgets(self):
		self.widgets = {}
		for name in self.config.loadLinks():
			self.createSingleWidget(name)


	@pyqtSlot()
	def onExit(self):
		self.config.saveWindowSize(self.size())
		QApplication.exit();

	def closeEvent(self, event):
		self.config.saveWindowSize(self.size())
#	       	QApplication.exit()
		# tray is visible -> close to tray
		# else close app
		if self.trayIcon.isVisible():
			event.accept()
		else:
			QApplication.exit()
			return
		# if close-to-tray is set, do so
		if self.config.loadCloseToTray():
			event.accept()
		else:
			QApplication.exit()
			return;
		# save this state
		if	self.trayIcon.isVisible():	self.config.saveIsVisible(False)
		else:					self.config.saveIsVisible(True);
	@pyqtSlot()
	def reload_(self):
		for name in self.widgets:
			self.widgets[name].reload_()
		self.pBar.setValue(self.config.loadReloadInterval())
		self.reloadTimer.start(self.config.loadReloadInterval()*1000)

	@pyqtSlot()
	def onAutoloadStatus(self):
		self.pBar.setValue(self.pBar.value()-1)
#		print([idx for idx in self.widgets])

	def onStyleMenu(self, a):
		QApplication.setStyle(QStyleFactory.create(a.text()))
		self.setStyle(QStyleFactory.create(a.text()))
		self.config.saveStyle(a.text())

	def onReloadTime(self):
		ok = False
		value, ok = QInputDialog.getInteger(self,
			self.tr("reloadinterval"), # title
			self.tr("insert time in s"), # text
			self.config.loadReloadInterval(), # default
			10, # minimum
			86400, # maximum (at least once a day)
			1, # step
			)
		if ok:
			self.config.saveReloadInterval(value)
			self.pBar.setRange(0,self.config.loadReloadInterval())
			self.reload_()

	def onAutoloadAction(self, b):
		if b:
			self.reloadTimer.start()
			self.pBar.show()
			self.reload_()
		else:
			self.reloadTimer.stop()
			self.pBar.hide()
		self.config.saveAutoload(b)

	def onNewLink(self):
		inp = LinkInput(self.config, self)
		if inp.exec_():
			# sync active widgets
			for name in inp.modifiedWidgets():
				if name in self.widgets:
					self.delWidget(name)
					self.createSingleWidget(name)
				else:
					self.createSingleWidget(name)

			# remove deleted
#			for name in self.widgets: print 'shown', name
#			for name in self.config.loadLinks(): print 'conf', name
			todel = []
			for name in self.widgets:
				if name not in self.config.loadLinks():
					todel.append(name)

			for widget in todel:
				self.delWidget(widget)

	def onOntopAction(self, b):
		if b:	self.setWindowFlags(Qt.Dialog | Qt.WindowStaysOnTopHint)
		else:	self.setWindowFlags(Qt.Dialog)
		self.setWindowIcon(QIcon(':/appicon'))
		self.show();
		self.config.saveOntop(b)

	def onShowTrayAction(self, b):
		if b:	self.trayIcon.show()
		else:	self.trayIcon.hide()
		self.config.saveShowTray(b)

	def onCloseToTrayAction(self, b):
		self.config.saveCloseToTray(b)

	def onTrayIcon(self, reason):
		if reason == QSystemTrayIcon.Trigger:
			if(self.isVisible()):
				self.config.saveWindowSize(self.size())
				self.hide()
				self.config.saveIsVisible(False)
			else:
				self.show()
				self.resize(self.config.loadWindowSize())
				self.config.saveIsVisible(True)

	def onAboutAppAction(self):
		QMessageBox.about(self, self.tr("&about"), self.tr("name %1 version %2").arg(QApplication.applicationName()).arg(QApplication.applicationVersion()))
	def onAboutQtAction(self):
		QMessageBox.aboutQt(self, self.tr("&about"))
Example #6
0
class TeigenWidget(QtGui.QWidget):
    def __init__(self,
                 ncols=2,
                 qapp=None,
                 logfile="~/teigen.log",
                 config=None,
                 use_default_config=False):
        super(TeigenWidget, self).__init__()
        self.logfile = logfile
        self.ncols = ncols
        self.gen = None
        self.figures = {}
        self.ui_stats_shown = False
        self.teigen = Teigen(logfile=self.logfile)
        if use_default_config:
            self.teigen.use_default_config()
        if config is not None:
            self.teigen.update_config(**config)
        self.version = self.teigen.version
        self.config = {}
        self.run_number = 0
        self.qapp = qapp
        self.init_ui()

    def collect_config_from_gui(self):
        id = self._ui_generators_tab_wg.currentIndex()
        config = collections.OrderedDict()
        config["generators"] = collections.OrderedDict()
        for i, wg in enumerate(self._ui_generator_widgets):
            config["generators"][
                self.teigen.generators_names[i]] = wg.config_as_dict()

        # config = self._ui_generator_widgets[id].config_as_dict()
        logger.debug(str(config))

        none, area_cfg = dictwidgetpg.from_pyqtgraph_struct(
            self.area_sampling_params.saveState())

        # config.update(area_cfg["Area Sampling"])
        config["areasampling"] = area_cfg["Area Sampling"]
        filepattern = self.ui_output_dir_widget.get_dir()
        # series_number = io3d.datawriter.get_unoccupied_series_number(filepattern=filepattern)
        config["filepattern"] = filepattern
        # config['filepattern_series_number'] = series_number
        config["generator_id"] = id

        # config["postprocessing"] = self.posprocessing_wg.config_as_dict()
        config["postprocessing"] = area_cfg["Postprocessing"]
        config["required_teigen_version"] = self.teigen.version
        config[CKEY_APPEARANCE] = area_cfg["Appearance"]
        config[CKEY_OUTPUT] = area_cfg["Output"]
        config[CKEY_MEASUREMENT] = area_cfg["Measurement"]
        self.config = config

    def _parameters_changed(self, param, changes):
        logger.debug("parameters changed")
        print("parameters changed")
        self.teigen.parameters_changed_before_save = True
        self._ui_btn_step2.setEnabled(False)
        # self.on_config_update()

    def collect_config_from_gui_and_push_to_teigen(self):
        self.collect_config_from_gui()
        self.teigen.update_config(**self.config)

    def step1(self):
        self.collect_config_from_gui_and_push_to_teigen()

        # self.config = new_cfg
        self.teigen.step1()

    def _ui_show_potential_output_path(self):
        fn = self.teigen.config["filepattern_abspath"]
        # if fn is None:
        #     fn = self.teigen.filepattern_fill_potential_series()
        self._ui_output_path.setText(fn)
        logger.debug("output path refreshed " + fn)

    def _show_stats_after_step1(self):
        logger.debug("show stats after step1 begin ")
        to_rename = {
            "length": "length [mm]",
            "volume": "volume [mm^3]",
            "surface": "surface [mm^2]",
            "radius": "radius [mm]"
        }
        to_rename_density = {
            "length": "length d. [mm^-2]",
            "volume": "volume d. []",
            "surface": "surface d. [mm^-1]"
            # "radius": "radius [mm^-2]"
        }

        # to_rename_density = {
        #     "length": "length [mm]",
        #     "volume": "volume [mm^3]",
        #     "surface": "surface [mm^2]"
        #     # "radius": "radius [mm^-2]"
        # }

        run_number_alpha = chr(ord("A") + self.run_number)
        if self.ui_stats_shown:
            #     self._wg_tab_describe.deleteLater()
            #     self._wg_tab_describe = None
            #     self._wg_tab_merne.deleteLater()
            #     self._wg_tab_merne = None
            pass
        else:

            self.stats_tab_wg = QTabWidget()
            self.mainLayout.addWidget(self.stats_tab_wg, 0, 3, 6, 2)

        self.actual_subtab_wg = QTabWidget()
        self.stats_tab_wg.addTab(self.actual_subtab_wg, '' + run_number_alpha)
        logger.debug("initiating canvas for graphs")
        if True:
            self.figure = plt.figure()
            self.canvas = FigureCanvas(self.figure)
            # self.toolbar = NavigationToolbar(self.canvas, self)
            self.actual_subtab_wg.addTab(self.canvas,
                                         'Graphs ' + run_number_alpha)

        # df = self.teigen.gen.getStats()
        df = self.teigen.dataframes["elements"]

        plt.subplot(141)
        df[["length"]].rename(columns=to_rename).boxplot(return_type='axes')
        plt.subplot(142)
        df[['radius']].rename(columns=to_rename).boxplot(return_type='axes')

        plt.subplot(143)
        df[["surface"]].rename(columns=to_rename).boxplot(return_type='axes')

        plt.subplot(144)
        df[["volume"]].rename(columns=to_rename).boxplot(return_type='axes')
        self.figure.tight_layout()

        import tablewidget

        # dfmernef.insert(0, "", dfmernef.index)
        # import ipdb; ipdb.set_trace()

        # TODO take care about redrawing
        # self.stats_tab_wg.addTab(self._wg_tab_merne, "Density table")

        logger.debug("tabs initiatization")
        dfdescribe = self.teigen.dataframes["describe"]
        dfmerne = self.teigen.dataframes["density"]
        dfoverall = self.teigen.dataframes["overall"]

        self._wg_tab_describe = tablewidget.TableWidget(self,
                                                        dataframe=dfdescribe)
        self._wg_tab_merne = tablewidget.TableWidget(self, dataframe=dfmerne)
        self._wg_tab_overall = tablewidget.TableWidget(self,
                                                       dataframe=dfoverall)
        self._wg_tab_describe.setMinimumWidth(800)
        self._wg_tab_describe.setMinimumHeight(200)
        self._wg_tab_merne.setMaximumHeight(80)
        self._wg_tab_overall.setMaximumHeight(80)

        # TODO move to main column window
        self._wg_btn_tab_save = QPushButton("Save in one row", self)
        self._wg_btn_tab_save.setToolTip("Save all data in one row")
        self._wg_btn_tab_save.clicked.connect(self.btn_save_in_one_row)

        self._wg_tables = QtGui.QWidget()
        self._wg_tables.setLayout(QGridLayout())
        self._wg_tables.layout().addWidget(self._wg_tab_describe)
        self._wg_tables.layout().addWidget(self._wg_tab_merne)
        self._wg_tables.layout().addWidget(self._wg_tab_overall)
        self._wg_tables.layout().addWidget(self._wg_btn_tab_save)

        self._wg_tab_describe.show()
        self._wg_tab_describe.raise_()
        # self.mainLayout.addWidget(self._wg_tab_describe, 0, 2, 5, 2)
        # self.stats_tab_wg.addTab(self._wg_tab_describe, "Stats table")
        self.actual_subtab_wg.addTab(self._wg_tables,
                                     "Summary " + run_number_alpha)
        # self.resize(600,700)

        logger.debug("poly data visualization init")
        if self.teigen.polydata_volume is not None and self.teigen.config[
                CKEY_APPEARANCE]["surface_3d_preview"]:
            import imtools.show_segmentation_qt
            logger.debug("segmentation widget loading")
            # test code
            fn = op.expanduser("~/lisa_data/sample_data/liver-seg001.mhd"),
            # datap = io3d.read(fn, dataplus_format=True)
            import imtools.sample_data
            datap = imtools.sample_data.donut()

            segmentation = datap['segmentation']
            voxelsize_mm = datap['voxelsize_mm']
            self._wg_show_3d = imtools.show_segmentation_qt.ShowSegmentationWidget(
                # datap["segmentation"],
                # show_load_button=True
            )
            QtGui.QApplication.processEvents()

            logger.debug("read polydata")
            # TODO use again - unstability is not here
            # this ted to be unstable
            # self._wg_show_3d.add_vtk_polydata(self.teigen.polydata_volume)
            # so we are using file way
            temp_vtk_file = op.expanduser(self.teigen.temp_vtk_file)
            self.teigen.save_surface_to_file(temp_vtk_file)
            self._wg_show_3d.add_vtk_file(temp_vtk_file)

            # test codee
            # self._wg_show_3d.add_
            logger.debug("init new tab")
            self.actual_subtab_wg.addTab(self._wg_show_3d,
                                         "Visualization " + run_number_alpha)
        else:
            self._wg_show_3d = None

        self.ui_stats_shown = True

        logger.debug("noise preview init")
        if (self.teigen.config[CKEY_APPEARANCE]["noise_preview"]
                and self.teigen.config["postprocessing"]["add_noise"]):
            self._noise_figure = plt.figure()
            self._noise_canvas = FigureCanvas(self._noise_figure)
            # self.toolbar = NavigationToolbar(self.canvas, self)
            self.actual_subtab_wg.addTab(self._noise_canvas,
                                         'Noise ' + run_number_alpha)
            noise = self.teigen.generate_noise()
            plt.imshow(noise[0, :, :], cmap="gray")
            plt.colorbar()

        logger.debug("show potential output path")
        self._ui_show_potential_output_path()

    def update_stats(self):
        """
        Function is used after volume generation and save.
        :return:
        """
        import tablewidget
        self._wg_tab_overall.deleteLater()
        self._wg_tab_overall = None
        #     self._wg_tab_describe.deleteLater()
        # self._wg_tables
        dfoverall = self.teigen.dataframes["overall"]
        self._wg_tab_overall = tablewidget.TableWidget(self,
                                                       dataframe=dfoverall)
        self._wg_tab_overall.setMaximumHeight(80)
        self._wg_tables.layout().addWidget(self._wg_tab_overall)

        output_path = QLabel()
        output_path.setText(self.teigen.filepattern_fill_series())
        self._wg_tables.layout().addWidget(output_path)
        #     self._wg_tab_describe.deleteLater()
        #     self._wg_tab_describe = None
        #     self._wg_tab_merne.deleteLater()
        #     self._wg_tab_merne = None

        # Show surface
        measurement_multiplier = self.teigen.config[CKEY_OUTPUT][
            "aposteriori_measurement_multiplier"]
        surface_measurement = self.teigen.config[CKEY_OUTPUT][
            "aposteriori_measurement"]
        show_surface = self.teigen.config[CKEY_APPEARANCE][
            "show_aposteriori_surface"]
        if surface_measurement and (measurement_multiplier >
                                    0) and show_surface:
            fig = plt.figure()
            self._surface_figure = fig
            self._surface_canvas = FigureCanvas(self._surface_figure)
            # self.toolbar = NavigationToolbar(self.canvas, self)
            run_number_alpha = chr(ord("A") + self.run_number)
            self.actual_subtab_wg.addTab(
                self._surface_canvas,
                'Aposteriori Surface ' + run_number_alpha)

            # import matplotlib.pyplot as plt
            from mpl_toolkits.mplot3d.art3d import Poly3DCollection
            faces, vertices = self.teigen.get_aposteriori_faces_and_vertices()
            # fig = plt.figure(figsize=(10, 10))
            ax = fig.add_subplot(111, projection='3d')

            # Fancy indexing: `verts[faces]` to generate a collection of triangles
            mesh = Poly3DCollection(vertices[faces])
            mesh.set_edgecolor('r')
            ax.add_collection3d(mesh)
            sh = self.teigen._numeric_surface_measurement_shape
            ax.set_xlim(0, sh[0])  # a = 6 (times two for 2nd ellipsoid)
            ax.set_ylim(0, sh[1])  # b = 10
            ax.set_zlim(0, sh[2])  # c = 16
            # plt.show()

    def complicated_to_yaml(self, cfg):
        import yaml
        # convert values to json
        isconverted = {}
        for key, value in cfg.iteritems():
            if type(value) in (str, int, float, bool):

                isconverted[key] = False
                if type(value) is str:
                    pass

            else:
                isconverted[key] = True
                cfg[key] = yaml.dump(value, default_flow_style=True)
        return cfg

    def _get_generator(self, id):
        pass

    def init_ui(self):
        wtitle = "Teigen " + self.version
        self.setWindowTitle(wtitle)
        self.mainLayout = QGridLayout(self)

        self.statusBar = QStatusBar()
        self.mainLayout.addWidget(self.statusBar, 10, 0, 1, 2)
        self.progressBar = QtGui.QProgressBar()
        self.progressBar.setRange(0, 10000)
        self.progressBar.setValue(0)

        self.ui_stop_button = QPushButton("Stop", self)
        self.ui_stop_button.clicked.connect(self.btnStop)

        self.statusBar.addWidget(self.progressBar)
        self.statusBar.addWidget(self.ui_stop_button)
        self.progressBar.show()

        self.configBarLayout = QGridLayout(self)
        self._ui_config_init()

    def _ui_init_buttons(self):

        # Toolbar
        # Use default config
        self._ui_btn_default_config = QtGui.QAction(
            self.style().standardIcon(QtGui.QStyle.SP_BrowserReload),
            "Reset parameters to default values", self)
        self._ui_btn_default_config.setToolTip(
            "Reset all parameters to default value (Ctrl+R)")
        self._ui_btn_default_config.setShortcut('Ctrl+R')
        self._ui_btn_default_config.triggered.connect(
            self.btn_use_default_config)

        # Load
        self._ui_btn_load_config = QtGui.QAction(
            self.style().standardIcon(QtGui.QStyle.SP_DialogOpenButton),
            "Load params", self)
        self._ui_btn_load_config.setToolTip(
            "Load params from file with file dialog (Ctrl+L)")
        self._ui_btn_load_config.setShortcut('Ctrl+L')
        self._ui_btn_load_config.triggered.connect(self.btn_load_config)
        # self.configBarLayout.addWidget(self._ui_btn_load_config, 1, 3, 1, 1)  # , (gd_max_i / 2), text_col)

        self._ui_btn_save = QtGui.QAction(
            self.style().standardIcon(QtGui.QStyle.SP_DialogSaveButton),
            "Save parameters", self)
        self._ui_btn_save.setToolTip("Save generator parameters (Ctrl+S)")
        self._ui_btn_save.triggered.connect(self.btn_save_parameters)
        self._ui_btn_save.setShortcut('Ctrl+S')
        # self.configBarLayout.addWidget(self._ui_btn_save, 1, 1, 1, 1)

        self._ui_btn_save_and_add_to_batch = QtGui.QAction(
            self.style().standardIcon(QtGui.QStyle.SP_FileDialogDetailedView),
            "Save parameters and add to batch", self)
        self._ui_btn_save_and_add_to_batch.setToolTip(
            "Save generator parameters and then add to batch (Ctrl+B)")
        self._ui_btn_save_and_add_to_batch.triggered.connect(
            self.btn_save_parameters_and_add_to_batch)
        self._ui_btn_save_and_add_to_batch.setShortcut('Ctrl+B')
        # self.configBarLayout.addWidget(self._ui_btn_save_and_add_to_batch, 1, 2, 1, 1)  # , (gd_max_i / 2), text_col)

        # exitAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self)
        # self.exitAction = QtGui.QAction( self.style().standardIcon(QtGui.QStyle.SP_DialogOpenButton) , 'Exit', self)
        # self.exitAction.setShortcut('Ctrl+Q')
        # self.exitAction.triggered.connect(QtGui.qApp.quit)

        # loadTubeSkeletonAction = QtGui.QAction( QtCore.QCoreApplication.translate("ahoj"), 'Exit', self)
        self.loadTubeSkeletonAction = QtGui.QAction(
            self.style().standardIcon(QtGui.QStyle.SP_MediaSkipForward),
            "Load skeleton", self)
        self.loadTubeSkeletonAction.setShortcut('Ctrl+K')
        self.loadTubeSkeletonAction.setToolTip(
            'Make Step 1 by loading skeleton (Ctrl+K)')
        self.loadTubeSkeletonAction.triggered.connect(
            self.btn_step1_by_load_tube_skeleton)

        self.toolbar = QToolBar("File")
        self.mainLayout.addWidget(self.toolbar, 3, 1, 1, 1)
        self.toolbar.addAction(self._ui_btn_save)
        self.toolbar.addAction(self._ui_btn_save_and_add_to_batch)
        self.toolbar.addAction(self._ui_btn_default_config)
        self.toolbar.addAction(self._ui_btn_load_config)
        self.toolbar.addAction(self.loadTubeSkeletonAction)
        # self.toolbar.addAction(self.exitAction)
        self._ui_output_path = QLabel(self)
        self._ui_output_path.setText("")

        self.mainLayout.addWidget(self._ui_output_path, 2, 1, 1,
                                  2)  # , (gd_max_i / 2), text_col)
        # self._ui_show_potential_output_path()

        self.mainLayout.addLayout(self.configBarLayout, 3, 1, 1,
                                  2)  # , (gd_max_i / 2), text_col)

        self._ui_btn_step1 = QPushButton(
            "Step 1 - Preview - Generate skeleton", self)
        self._ui_btn_step1.setToolTip("Generate preview and skeleton (Ctrl+P)")
        self._ui_btn_step1.clicked.connect(self.btnRunStep1)
        self._ui_btn_step1.setShortcut('Ctrl+P')
        self.mainLayout.addWidget(self._ui_btn_step1, 4, 1, 1,
                                  2)  # , (gd_max_i / 2), text_col)

        # self.posprocessing_wg = dictwidgetqt.DictWidget(postprocessing_params)
        # self.mainLayout.addWidget(self.posprocessing_wg, 3, 1)

        self._ui_btn_step2 = QPushButton(
            "Step 2 - Generate and save volumetric data", self)
        self._ui_btn_step2.setToolTip(
            "Save image slices and meta information (Ctrl+R)")
        self._ui_btn_step2.clicked.connect(self.btnRunStep2)
        self._ui_btn_step2.setShortcut('Ctrl+R')
        self.mainLayout.addWidget(self._ui_btn_step2, 5, 1, 1,
                                  2)  # , (gd_max_i / 2), text_col)

    def _ui_config_init(self):

        self._ui_init_buttons()
        self.ui_output_dir_widget = iowidgetqt.SetDirWidget(
            self.teigen.config["filepattern"], "output directory")
        self.ui_output_dir_widget.setToolTip(
            "Data are stored in defined directory.\nOutput format is based on file extension.\n\
For saving into image stack use 'filename{:06d}.jpg'")
        self.mainLayout.addWidget(self.ui_output_dir_widget, 1, 1, 1,
                                  2)  # , (gd_max_i / 2), text_col)

        postprocessing_params = self.teigen.config["postprocessing"]

        hide_keys = [
            "build", "gtree", "voxelsize_mm", "areasize_px", "resolution",
            "n_slice", "dims", "tube_shape", "radius_distribution_normal",
            "radius_distribution_uniform", "radius_distribution_fixed",
            "allow_overlap"
        ]
        self._ui_generators_tab_wg = QTabWidget()
        self._ui_generators_tab_wg.setMinimumWidth(400)
        self.mainLayout.addWidget(self._ui_generators_tab_wg, 0, 1, 1, 2)
        # l = QVBoxLayout(self)

        rename_captions_dict = {
            "voxelsize_mm": "voxel size [mm]",
        }
        dropdownoboxes = {
            "radius_distribution": ["normal", "fixed", "uniform"]
        }

        # list is pointer. It causes problems with temporary reconstruction information
        # copy fix this issue
        teigen_config = copy.deepcopy(self.teigen.config)

        self._ui_generator_widgets = []
        for generator_name in teigen_config["generators"]:
            wg = dictwidgetqt.DictWidget(
                teigen_config["generators"][generator_name],
                hide_keys=hide_keys,
                captions=rename_captions_dict,
                ncols=1,
                dropdownboxes=dropdownoboxes,
            )
            self._ui_generator_widgets.append(wg)
            self._ui_generators_tab_wg.addTab(
                wg, generator_name.replace(" ", "\n"))
            # self._ui_generators_tab_wg.

        # l.addWidget(self._ui_generators_tab_wg)
        # wgn = QtGui.QWidget()
        # layout = QtGui.QFormLayout()
        # layout.addRow("Name", QtGui.QLineEdit())
        # layout.addRow("Address",QtGui.QLineEdit())
        # wgn.setLayout(layout)
        # self._ui_generators_tab_wg.addTab(wgn, "ahoj")
        id = self.teigen.get_generator_id_by_name_or_number(
            teigen_config["generator_id"])
        self._ui_generators_tab_wg.setCurrentIndex(id)
        # self.mainLayout.setColumnMinimumWidth(text_col, 500)

        # pyqtgraph experiments
        input_params = {
            "Area Sampling":
            dictwidgetpg.AreaSamplingParameter(
                name='Area Sampling', **self.teigen.config["areasampling"]),
            "Postprocessing":
            postprocessing_params,
            "Batch processing":
            dictwidgetpg.BatchFileProcessingParameter(name="Batch processing",
                                                      children=[
                                                          {
                                                              'name':
                                                              'Run batch',
                                                              'type': 'action'
                                                          },
                                                      ]),
            "Appearance":
            self.teigen.config["appearance"],
            "Output":
            self.teigen.config["output"],
            "Measurement":
            self.teigen.config["measurement"]
            # 'name': {'type': 'action'},
            # "dur": i5,
            # TODO add more lines here
            # "Intensity Profile": dictwidgetpyqtgraph.ScalableFloatGroup(
            #     name="Intensity Profile", children=[
            #         {'name': '0.2', 'type': 'float', 'value': "100"},
            #         {'name': '0.4', 'type': 'float', 'value': "115"},
            #     ])
        }
        gr_struct = dictwidgetpg.to_pyqtgraph_struct('params',
                                                     input_params,
                                                     opts={})
        dictwidgetpg.add_tip(gr_struct, "noise_preview", "this is noise")
        dictwidgetpg.add_tips(gr_struct, teigen_keysdoc)
        gr_struct["children"][1]['tip'] = "Apperance tip"
        gr_struct["children"][2]['tip'] = "output tip"
        gr_struct["children"][3]['tip'] = "post processing tip"
        gr_struct["children"][4]['tip'] = "measurement"
        p = Parameter.create(**gr_struct)

        t = ParameterTree()
        t.setParameters(p, showTop=False)
        t.setMinimumWidth(380)
        # t.setColumnCount(3)
        t.show()

        p.sigTreeStateChanged.connect(self._parameters_changed)
        p.param('Batch processing',
                'Run batch').sigActivated.connect(self.run_batch)

        # how to add button
        # i5  = pg.TreeWidgetItem(["Item 5"])
        # b5 = QtGui.QPushButton('Button')
        # i5.setWidget(1, b5)
        # t.addTopLevelItem(i5)

        self.mainLayout.addWidget(t, 0, 0, 6, 1)
        self.config_wg = t
        # self.config_wg.setToolTip(teigendoc)
        self.area_sampling_params = p
        self.teigen.progress_callback = self._progressbar_update
        self._ui_btn_step2.setEnabled(False)

    def delete_wg(self, wg):
        self.mainLayout.removeWidget(wg)
        wg.deleteLater()
        wg = None

    def _ui_config_deinit(self):

        self.delete_wg(self.ui_output_dir_widget)
        self.delete_wg(self.config_wg)
        self.delete_wg(self._ui_generators_tab_wg)
        self.delete_wg(self._ui_btn_step1)
        self.delete_wg(self._ui_btn_step2)
        self.delete_wg(self.toolbar)
        # self.delete_wg(self._ui_btn_save_and_add_to_batch)
        # self.delete_wg(self._ui_btn_save)

    def step1_by_load_tube_skeleton(self, filename):
        self.collect_config_from_gui_and_push_to_teigen()
        self.teigen.step1_by_load_tube_skeleton(filename)
        self._show_stats_after_step1()
        self._ui_btn_step2.setEnabled(True)

    def btn_step1_by_load_tube_skeleton(self):
        fn = op.dirname(self.teigen.get_fn_base())
        filename = QFileDialog.getOpenFileName(self, 'Open config file', fn,
                                               "Config files (*.yaml)")
        if filename is not None:
            filename = str(filename)
        self.step1_by_load_tube_skeleton(filename=filename)

    def btn_load_config(self):
        self.load_config()

    def btn_use_default_config(self):
        self.teigen.use_default_config()
        self._ui_config_deinit()
        self._ui_config_init()

    def load_config(self, filename=None):
        """
        load config from file, if filename is none, file dialog is created
        :param filename:
        :return:
        """
        if filename is None:
            fn = op.dirname(self.teigen.get_fn_base())
            filename = QFileDialog.getOpenFileName(self, 'Open config file',
                                                   fn, "Config files (*.yaml)")
            if filename is not None:
                filename = str(filename)

        if filename is not None:
            params = io3d.misc.obj_from_file(filename)
            self.teigen.update_config(**params)

            self._ui_config_deinit()
            self._ui_config_init()

    def _progressbar_update(self, obj, level, *args, **kwargs):
        self.progressBar.setValue(int(10000 * level))
        if "statusbar_text" in kwargs:
            # add this in gui
            print("statusbar_text " + kwargs["statusbar_text"])
            ## end of pyqtgraph tree

    def run_batch(self):

        none, area_cfg = dictwidgetpg.from_pyqtgraph_struct(
            self.area_sampling_params.saveState())
        lst = area_cfg["Batch processing"].values()
        self.teigen.run_batch(lst)

    def btn_save_parameters(self):
        self.save_parameters()

    def save_parameters(self, filename=None):
        if filename is None:
            # fn = op.dirname(self.teigen.get_fn_base())
            fn = op.dirname(self.teigen.get_fn_base())
            fn += "_parameters.yaml"
            filename = QFileDialog.getSaveFileName(self, 'Save config file',
                                                   fn, "Config files (*.yaml)")
            if filename is not None:
                filename = str(filename)
        self.collect_config_from_gui_and_push_to_teigen()
        self.teigen.save_parameters(filename=filename)
        return filename

    def btn_save_parameters_and_add_to_batch(self):
        self.save_parameters_and_add_to_batch()

    def save_parameters_and_add_to_batch(self, filename=None):
        self.collect_config_from_gui_and_push_to_teigen()
        config_filename = self.teigen.save_parameters(filename=filename)
        self.area_sampling_params.param("Batch processing").add_filename(
            config_filename)

    def btnRunStep1(self):

        logger.debug("btnRunStage1")
        # logger.debug(str(self.config))
        self.step1()
        self._show_stats_after_step1()
        self.run_number += 1
        self._ui_btn_step2.setEnabled(True)

    def btnStop(self):
        self.teigen.stop()
        pass

    def btn_save_in_one_row(self):
        # fn = op.dirname(self.teigen.get_fn_base())
        fn_base, fn_ext = self.teigen.filepattern_split()
        fn = op.dirname(fn_base)
        superior_dir, filen = op.split(fn)
        fn = op.join(superior_dir, "output_rows.csv")
        filename = QFileDialog.getSaveFileName(
            self,
            'Save config file',
            fn,
            "(*.csv)",
            options=QtGui.QFileDialog.DontConfirmOverwrite)
        text, ok = QtGui.QInputDialog.getText(self, 'Note Dialog', 'Note:')
        if filename is not None:
            filename = str(filename)
            self.teigen.save_stats_to_row(filename, note=text)

    def btnRunStep2(self):
        # filename = "file{:05d}.jpg"
        # filename = "file%05d.jpg"
        # filename = QtGui.QFileDialog.getSaveFileName(
        #     self,
        #     "Save file",
        #     init_filename,
        #     ""
        # )
        # filename = str(filename)

        if self.teigen.need_run:
            self.step1()
            self._show_stats_after_step1()

        # filename = op.join(self.ui_output_dir_widget.get_dir(), filename)
        filename = self.config["filepattern"]

        # filename = iowidgetqt.str_format_old_to_new(filename)

        self.teigen.step2()
        fn_base, fn_ext = self.teigen.filepattern_split()
        self.figure.savefig(fn_base + "_" + "graph.pdf")
        self.figure.savefig(fn_base + "_" + "graph.png")
        self.figure.savefig(fn_base + "_" + "graph.svg")
        self.figure.savefig(fn_base + "_" + "graph.eps")

        from PyQt4.QtGui import QPixmap
        if self._wg_show_3d is not None:
            p = QPixmap.grabWidget(self._wg_show_3d.vtkWidget)
            p.save(fn_base + "_snapshot.png", 'png')

        # self.teigen.gen.saveVolumeToFile(filename)
        self.update_stats()

    def on_config_update(self):
        pass

    def config_as_dict(self):
        dictionary = self.config.as_dict()
        for key, value in dictionary.iteritems():
            from PyQt4.QtCore import pyqtRemoveInputHook
            pyqtRemoveInputHook()
            # import ipdb; ipdb.set_trace() #  noqa BREAKPOINT
            if type(value) == PyQt4.QtCore.QString:
                value = str(value)
            dictionary[key] = value

        return dictionary
Example #7
0
class Window(QMainWindow):
    def __init__(self,parent = None):
        QMainWindow.__init__(self,parent)
        self.setObjectName("self")
        self.resize(758, 673)
        self.setWindowTitle("Sabel")
        self.setWindowIcon(Icons.sabel)
        self.centralwidget = QWidget(self)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout = QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.horizontalLayout.setMargin(0)
        self.styleIndex = styleIndex
        #TabWidgets
        self.tab_1 = QWidget(self)
        self.tab_1.setObjectName("tab_1")
        self.tab_1.setMinimumWidth(800)
        self.tabWidget = Tab(self.tab_1)
        self.tabWidget.setObjectName("tabWidget")
        self.VericalLayout = QVBoxLayout(self.tab_1)
        self.VericalLayout.setMargin(0)
        self.VericalLayout.setObjectName("VericalLayout")
        self.VericalLayout.addWidget(self.tabWidget)
        
        self.tabWidget_2 = QTabWidget(self)
        #self.tabWidget_2.setMaximumWidth(200)
        self.tabWidget_2.setObjectName("tabWidget_2")
        self.tabWidget_3 = QTabWidget(self)
        self.tabWidget_3.setMaximumHeight(260)
        self.tabWidget_3.setObjectName("tabWidget_3")
        
         
        #Tree
        self.tab_5 = QWidget()
        self.tab_5.setObjectName("tab_5")
        #self.tab_5.setMaximumWidth(200)
        self.VerticalLayout_2 = QVBoxLayout(self.tab_5)#QHBoxLayout(self.tab_5)
        self.VerticalLayout_2.setMargin(0)
        self.VerticalLayout_2.setObjectName("horizontalLayout_3")
        self.treeWidget = Tree(self.tab_5)
        self.treeWidget.setObjectName("treeWidget")
        self.treeWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.treeWidget.horizontalScrollBar().show()
        self.treebar = QToolBar()
        action_Folder = QAction(Icons.newfolder,'New Folder', self)
        action_Folder.triggered.connect(self.about)
        action_Android = QAction(Icons.android,'Android', self)
        action_Android.triggered.connect(self.android)
        action_Ant = QAction(Icons.ant_view,'Ant', self)
        action_Ant.triggered.connect(self.ant)
        self.treebar.addAction(action_Folder)
        self.treebar.addAction(action_Android)
        self.treebar.addAction(action_Ant)
        self.treebar.setIconSize(QSize(16,16))
        self.VerticalLayout_2.addWidget(self.treebar)
        self.VerticalLayout_2.addWidget(self.treeWidget)
        
        #Outline
        self.tab_2 = QWidget()
        self.tab_2.setObjectName("tab_2")
        #self.tab_2.setMaximumWidth(200)
        self.VerticalLayout_3 = QVBoxLayout(self.tab_2)
        self.VerticalLayout_3.setMargin(0)
        self.VerticalLayout_3.setObjectName("VerticalLayout_3")
        self.outlineWidget = Tree(self.tab_2)
        self.outlineWidget.setObjectName("outlineWidget")
        self.VerticalLayout_3.addWidget(self.outlineWidget)
        
        #Output
        self.tab_6 = QWidget()
        self.tab_6.setObjectName("tab_6")
        #GGGGGGGGGGGGGGGGGGGG AWESOME
        self.horizontalLayout_2 = QVBoxLayout(self.tab_6)
        self.horizontalLayout_2.setMargin(0)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.textEdit = QTextEdit(self.tab_6)
        self.textEdit.setObjectName("textEdit")
        self.lineeEdit = QLineEdit(self.tab_6)
        self.lineeEdit.setObjectName("lineeEdit")
        self.label = QLabel(self.tab_6)
        self.label.setText("Input:")
        self.horizontalLayout_2.addWidget(self.textEdit)
        self.horizontalLayout_2.addWidget(self.label)
        self.horizontalLayout_2.addWidget(self.lineeEdit)
        
        #Error
        self.tab_7 = QWidget()
        self.tab_7.setObjectName("tab_7")
        self.horizontalLayout_4 = QHBoxLayout(self.tab_7)
        self.horizontalLayout_4.setMargin(0)
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.textEdit_2 = QTextEdit(self.tab_7)
        self.textEdit_2.setObjectName("textEdit_2")
        self.horizontalLayout_4.addWidget(self.textEdit_2)
        
        #Find
        self.tab_8 = QWidget()
        self.tab_8.setObjectName("tab_8")
        self.horizontalLayout_5 = QHBoxLayout(self.tab_8)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.lineEdit = QLineEdit(self.tab_8)
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QLineEdit(self.tab_8)
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.findClose = QPushButton(self.tab_8)
        self.findClose.setIcon(Icons.close_view)
        self.findClose.setFlat(True)
        self.findClose.clicked.connect(self.findBarShow)
        self.find = QPushButton(self.tab_8)
        self.find.setText("Find")
        self.find.clicked.connect(self.findCurrentText)
        self.replacefind = QPushButton(self.tab_8)
        self.replacefind.setText("Replace/Find")
        self.replace = QPushButton(self.tab_8)
        self.replace.setText("Replace")
        self.replace.clicked.connect(self.replaceCurrentText)
        self.replaceAll = QPushButton(self.tab_8)
        self.replaceAll.setText("Replace All")
        self.replaceAll.clicked.connect(self.replaceAllText)
        self.caseSensitive = QToolButton(self.tab_8)
        self.caseSensitive.setText("cs")
        self.caseSensitive.setCheckable(True)
        self.wholeWord = QToolButton(self.tab_8)
        self.wholeWord.setText("ww")
        self.wholeWord.setCheckable(True)
        self.regex = QToolButton(self.tab_8)
        self.regex.setText("re")
        self.regex.setCheckable(True)
        self.backward = QToolButton(self.tab_8)
        self.backward.setText("bk")
        self.backward.setCheckable(True)
        self.backward.setDisabled(True)
        self.horizontalLayout_5.addWidget(self.findClose)
        self.horizontalLayout_5.addWidget(self.find)
        self.horizontalLayout_5.addWidget(self.lineEdit)
        self.horizontalLayout_5.addWidget(self.lineEdit_2)
        self.horizontalLayout_5.addWidget(self.caseSensitive)
        self.horizontalLayout_5.addWidget(self.wholeWord)
        self.horizontalLayout_5.addWidget(self.regex)
        self.horizontalLayout_5.addWidget(self.backward)
        self.horizontalLayout_5.addWidget(self.replacefind)
        self.horizontalLayout_5.addWidget(self.replace)
        self.horizontalLayout_5.addWidget(self.replaceAll)
        self.horizontalLayout_5.setMargin(0)
        self.tab_8.setMaximumHeight(25)
        self.VericalLayout.addWidget(self.tab_8)
        self.tab_8.hide()
        
        
        self.tabWidget_2.addTab(self.tab_5,"Projects")
        self.tabWidget_2.addTab(self.tab_2,"Outline")
        self.tabWidget_3.addTab(self.tab_7,"Error")
        self.tabWidget_3.addTab(self.tab_6,"Output")
        self.tabWidget_3.setTabIcon(0,Icons.error)
        self.tabWidget_3.setTabIcon(1,Icons.console_view)
        self.tabWidget.setTabsClosable(True)
        self.tabWidget.setTabShape(0)
        
        
        #Splitters
        self.split1 = QSplitter(Qt.Horizontal)
        self.split1.addWidget(self.tabWidget_2)
        self.split1.addWidget(self.tab_1)
        #self.split1.addWidget(self.tab_5)
        
        self.split2 = QSplitter(Qt.Vertical)
        self.split2.addWidget(self.split1)
        self.split2.addWidget(self.tabWidget_3)
        self.tabWidget_3.hide()
        self.horizontalLayout.addWidget(self.split2)
        
        
        #Status
        self.statusbar = QStatusBar(self)
        self.statusbar.setObjectName("statusbar")
        self.aboutButton = QPushButton(self)
        self.aboutButton.setFlat(True)
        self.aboutButton.setIcon(Icons.anchor)
        self.aboutButton.clicked.connect(self.about)
        self.cmdButton = QPushButton(self)
        self.cmdButton.setFlat(True)
        self.cmdButton.setIcon(Icons.console_view)
        self.cmdButton.clicked.connect(self.cmd)
        self.cmdButton.setShortcut('Ctrl+O')
        self.findButton = QPushButton(self)
        self.findButton.setFlat(True)
        self.findButton.setIcon(Icons.find)
        self.findButton.setShortcut("Ctrl+F")
        self.findButton.clicked.connect(self.findBarShow)
        self.zoominButton = QPushButton(self)
        self.zoominButton.setFlat(True)
        self.zoominButton.setIcon(Icons.zoomplus)
        self.zoominButton.clicked.connect(self.zoomin)
        self.zoomoutButton = QPushButton(self)
        self.zoomoutButton.setFlat(True)
        self.zoomoutButton.setIcon(Icons.zoomminus)
        self.zoomoutButton.clicked.connect(self.zoomout)
        self.fontButton = QPushButton(self)
        self.fontButton.setFlat(True)
        self.fontButton.setIcon(Icons.font)
        self.fontButton.clicked.connect(self.setFont)
        self.statusbar.addWidget(self.aboutButton)
        self.statusbar.addWidget(self.cmdButton)
        self.statusbar.addWidget(self.findButton)
        self.statusbar.addWidget(self.zoominButton)
        self.statusbar.addWidget(self.zoomoutButton)
        self.statusbar.addWidget(self.fontButton)
        #self.statusbar.setFixedHeight(18)
        
        #Init colorstyling
        self.colorStyle = None
        self.initColorStyle()
        #Init
        self.setCentralWidget(self.centralwidget)
        self.setStatusBar(self.statusbar)
        self.textEdit.setReadOnly(True)
        self.fontName = fontName
        #QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Cleanlooks'))
        
    def findBarShow(self):
        if(self.tab_8.isHidden()):
            self.tab_8.show()
        else:
            self.tab_8.hide()

    def initToolBar(self):
        self.action_NewProject = QAction(Icons.newprj, 'Project', self)
        self.action_NewProject.setShortcut('Ctrl+P')
        self.action_NewProject.triggered.connect(self.newProject)
        self.action_NewProject.setToolTip("Create a New Project")
        self.action_NewProject.setStatusTip("Create a New Project")

        self.action_Open = QAction(Icons.open, 'Open', self)
        self.action_Open.setShortcut('Ctrl+O')
        self.action_Open.triggered.connect(self.fileOpen)
        self.action_Open.setToolTip("Open File")
        self.action_Open.setStatusTip("Open File")

        self.action_Save = QAction(Icons.save, 'Save', self)
        self.action_Save.setShortcut('Ctrl+S')
        self.action_Save.triggered.connect(self.fileSave)
        self.action_Save.setToolTip("Save Current File")

        self.action_SaveAll = QAction(Icons.saveall, 'SaveAll', self)
        self.action_SaveAll.setShortcut('Ctrl+A')
        self.action_SaveAll.triggered.connect(self.fileSaveAll)
        self.action_SaveAll.setToolTip("Save All Files")
        
        self.action_Help = QAction(Icons.toc_open, 'Help', self)
        self.action_Help.triggered.connect(self.help)
        self.action_Run = QAction(Icons.run, 'Run', self)
        self.action_Run.setShortcut('Ctrl+R')
        self.action_Run.triggered.connect(self.adb.run)
        self.action_RunFile = QAction(Icons.go, 'File', self)
        self.action_RunFile.triggered.connect(self.command.setCmd)
        self.lineeEdit.returnPressed.connect(self.command.setCmdLine)
        self.action_Stop = QAction(Icons.stop, 'Stop', self)
        self.action_Stop.setShortcut('Ctrl+Q')
        self.action_Stop.triggered.connect(self.adb.stop)
        self.action_Design = QAction(Icons.task_set, 'Design', self)
        self.action_Todo = QAction(Icons.task_set, 'Todo', self)
        #self.action_Todo.triggered.connect(self.stop)
        #Only variation CHeck Later
        men = QMenu()
        self.threshSlider = QSlider()
        self.threshSlider.setTickPosition(QSlider.TicksLeft)
        self.threshSlider.setOrientation(Qt.Horizontal)
        self.threshSlider.setValue(threshold)
        self.threshSlider.setMinimum(0)
        self.threshSlider.setMaximum(5)
        self.threshSlider.valueChanged.connect(self.setThreshold)
        #self.threshSlider.setInvertedAppearance(True)
        self.threshSliderAction = QWidgetAction(men)
        self.threshSliderAction.setDefaultWidget(self.threshSlider)
        
        men.addAction(QAction("Ident",self))
        men.addAction(QAction("Edit",self))
        men.addAction(QAction("Paste",self))
        men.addAction(QAction("Tabs",self))
        men.addSeparator()
        men.addAction(QAction("Threshold",self))
        men.addAction(self.threshSliderAction)
        
        self.action_Options = QAction(Icons.thread_view, 'Options', self)
        self.action_Options.setMenu(men)
        self.action_Options.triggered.connect(self.options)
        
        
        self.action_Full = QAction(Icons.fullscreen, 'Full', self)
        self.action_Full.setShortcut('Shift+Enter')
        self.action_Full.triggered.connect(self.full)

        
        self.action_Style = QAction(Icons.style, 'Style', self)
        men1 = QMenu()
        self.styleslist = []
        self.style1 = QAction("All Hallow's Eve",self)
        self.style1.triggered.connect(lambda:self.style_clicked(1))
        self.style1.setCheckable(True)
        self.style2 = QAction("Amy",self)
        self.style2.triggered.connect(lambda:self.style_clicked(2))
        self.style2.setCheckable(True)
        self.style3 = QAction("Aptana Studio",self)
        self.style3.triggered.connect(lambda:self.style_clicked(3))
        self.style3.setCheckable(True)
        self.style4 = QAction("Bespin",self)
        self.style4.triggered.connect(lambda:self.style_clicked(4))
        self.style4.setCheckable(True)
        self.style5 = QAction("Blackboard",self)
        self.style5.triggered.connect(lambda:self.style_clicked(5))
        self.style5.setCheckable(True)
        self.style6 = QAction("Choco",self)
        self.style6.triggered.connect(lambda:self.style_clicked(6))
        self.style6.setCheckable(True)
        self.style7 = QAction("Cobalt",self)
        self.style7.triggered.connect(lambda:self.style_clicked(7))
        self.style7.setCheckable(True)
        self.style8 = QAction("Dawn",self)
        self.style8.triggered.connect(lambda:self.style_clicked(8))
        self.style8.setCheckable(True)
        self.style9 = QAction("Eclipse",self)
        self.style9.triggered.connect(lambda:self.style_clicked(9))
        self.style9.setCheckable(True)
        self.styleslist.append(self.style1)
        self.styleslist.append(self.style2)
        self.styleslist.append(self.style3)
        self.styleslist.append(self.style4)
        self.styleslist.append(self.style5)
        self.styleslist.append(self.style6)
        self.styleslist.append(self.style7)
        self.styleslist.append(self.style8)
        self.styleslist.append(self.style9)
        men1.addActions(self.styleslist)
        self.action_Style.setMenu(men1)
        self.styleslist[self.styleIndex].setChecked(True)


        self.action_Stop.setDisabled(True)
        self.toolbar = self.addToolBar('ToolBar')
        self.toolbar.setIconSize(QSize(16,16))
        self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.toolbar.setAllowedAreas(Qt.AllToolBarAreas)
        #self.toolbar.setFixedHeight(40)

        self.toolbar.addAction(self.action_NewProject)
        self.toolbar.addAction(self.action_Open)
        self.toolbar.addAction(self.action_Save)
        self.toolbar.addAction(self.action_SaveAll)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.action_Run)
        self.toolbar.addAction(self.action_RunFile)
        self.toolbar.addAction(self.action_Stop)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.action_Design)
        self.toolbar.addAction(self.action_Todo)
        self.toolbar.addAction(self.action_Options)
        self.toolbar.addAction(self.action_Style)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.action_Help)
        self.toolbar.addAction(self.action_Full)
        
    def about(self):
        QMessageBox.about(self, "About Sabel IDE",
                """
                <b>Sabel</b> v%s
                <p>
                All rights reserved in accordance with
                GPL v3 or later.
                <p>This application can be used for Squirrel and EmoFramework Projects.
                <p>Squirrel Shell Copyright (c) 2006-2011, Constantin Makshin
                <p>Squirrel Copyright (c) Alberto Demichelis
                <p>zlib Copyright (c) Jean-loup Gailly and Mark Adler
                <p>Icons Copyright (c) Eclipse EPL
                <p>Emo-Framework Copyright (c) 2011 Kota Iguchi
                <p>Python %s - Qt %s - PyQt %s on %s
                <p>Created By: pyros2097
                <p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,INCLUDING, BUT NOT
                 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
                 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
                 EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
                 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
                 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
                 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                 POSSIBILITY OF SUCH DAMAGE.
                """ % (
                __version__,PY_VERSION,
                QT_VERSION_STR, PYQT_VERSION_STR,OS_NAME))

    def help(self):
        QMessageBox.about(self, "About Simple Editor","This is The Help")
        
    def full(self):
        if not self.isFull:
            self.setWindowState(Qt.WindowFullScreen)
            self.isFull = True
        else:
            self.setWindowState(Qt.WindowMaximized)
            self.isFull = False
            
    def android(self):
        form = DialogAndroid(self)
        form.show()
    
    def ant(self):
        pass
            
    def cmd(self):
        if(self.tabWidget_3.isHidden()):
            self.tabWidget_3.show()
        else:
            self.tabWidget_3.hide()
            
    def findCurrentText(self):
        edt = self.tabWidget.widget(self.tabWidget.currentIndex())
        edt.findText(self.lineEdit.text(),self.regex.isChecked(),self.caseSensitive.isChecked(),self.wholeWord.isChecked(),self.backward.isChecked())
        
    def replaceCurrentText(self):
        edt = self.tabWidget.widget(self.tabWidget.currentIndex())
        done = edt.findText(self.lineEdit.text(),self.regex.isChecked(),self.caseSensitive.isChecked(),self.wholeWord.isChecked(),self.backward.isChecked())
        if(done):
            edt.replaceText(self.lineEdit_2.text())
        else:
            QMessageBox.about(self, "About Sabel IDE","Could Not Find Text")
        return done
            
    def replaceAllText(self):
        edt = self.tabWidget.widget(self.tabWidget.currentIndex())
        while(edt.findText(self.lineEdit.text(),self.regex.isChecked(),self.caseSensitive.isChecked(),self.wholeWord.isChecked(),self.backward.isChecked())):
            edt.replaceText(self.lineEdit_2.text())
            
    def zoomin(self):
        for i in range(len(self.files)):
            self.tabWidget.widget(i).zoomin()
    def zoomout(self):
        for i in range(len(self.files)):
            self.tabWidget.widget(i).zoomout()
            
    def setFont(self):
        font = QFont()
        font.setFamily(self.fontName)
        fdialog = QFontDialog(self)
        fdialog.show()
        fdialog.setCurrentFont(font)
        fdialog.accepted.connect(lambda:self.setFontName(fdialog.currentFont()))
        
        
    def setFontName(self,font):
        #print "accepted"
        #print font.family()
        self.fontName = str(font.family())
        config.setFontName(self.fontName)
        for i in range(len(self.files)):
            self.tabWidget.widget(i).setFontName(self.fontName)
            
    def setThreshold(self,val):
        config.setThresh(val)
        for i in range(len(self.files)):
            self.tabWidget.widget(i).setThreshold(val)
            
    def initColorStyle(self):
        self.colorStyle = Styles[self.styleIndex]                
        pal = QPalette(self.tabWidget_2.palette())
        #print pal.color(QPalette.Base).name()
        #print pal.color(QPalette.Window).name()
        pal.setColor(QPalette.Base,self.colorStyle.paper)
        pal.setColor(QPalette.Text,self.colorStyle.color)
        self.tabWidget_2.setPalette(pal)
        self.tabWidget_3.setPalette(pal)
            
    def style_clicked(self,no):
        self.styleIndex = no -1
        #print self.styleIndex
        for i in self.styleslist:
            if self.styleslist.index(i) == self.styleIndex:
                i.setChecked(True)
            else:
                i.setChecked(False)
        config.setstyleIndex(self.styleIndex)
        #self.initColorStyle()
        for i in range(len(self.files)):
            pass
            #self.tabWidget.
            #self.tabWidget.widget(i).setColorStyle(self.colorStyle)