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()
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)
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
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
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"))
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
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)