class MainEditorWindow(QtWidgets.QMainWindow): def __init__(self): super(MainEditorWindow, self).__init__() #self.setCentralWidget(self.display) self.tabbedEditor = TabbedEditor(self.refresh, self) self.setCentralWidget(self.tabbedEditor) self.createDocks() self.createMenu() self.statusBar() self.setWindowTitle("Structured Editor") self.settings = QtCore.QSettings("TCC", "Editor Estruturado") self.restoreSettings() self.setAcceptDrops(True) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): for url in event.mimeData().urls(): self.tabbedEditor.add(HtmlEditor.from_file(url.path())) event.accept() def createDocks(self): def ask_for_name(r, old_name): old_name = old_name.replace('_', ' ') name, ok = QtWidgets.QInputDialog.getText(self, 'Rename', 'Enter a new name', text=old_name) new_name = name if ok else old_name return new_name.replace(' ', '_') actions.Rename.ask_for_name = ask_for_name def extractHotkeys(group, pairs): return {config.get(group, label): item for item, label in pairs} editing_label_pairs = [(actions.Delete, 'Delete'), (actions.Copy, 'Copy'), (actions.Cut, 'Cut'), (actions.Paste, 'Paste'), (actions.MoveUp, 'Move up'), (actions.MoveDown, 'Move down'), (actions.Rename, 'Rename')] editingWindow = CommandsWindow('Editing', self) editingWindow.addCommands( editing_label_pairs, extractHotkeys('Editing Hotkeys', editing_label_pairs), self.runCommand) movement_label_pairs = [(actions.SelectParent, 'Parent'), (actions.SelectChild, 'Child'), (actions.SelectNextSibling, 'Next'), (actions.SelectPrevSibling, 'Previous'), (actions.NextUnfilled, 'Next unfilled')] navigationWindow = CommandsWindow('Navigation', self) navigationWindow.addCommands( movement_label_pairs, extractHotkeys('Movement Hotkeys', movement_label_pairs), self.runCommand) insertionWindow = InsertionWindow(self.runCommand, config.section('Insertion Hotkeys'), self) macroWindow = MacroWindow(self) self.setDockNestingEnabled(True) self.docks = [ editingWindow, navigationWindow, insertionWindow, macroWindow ] def createMenu(self): self.menubar = self.menuBar() def makeMenuAction(label, shortcut, statusTip, menu, handler): action = QtWidgets.QAction(label, self, shortcut=shortcut, statusTip=statusTip, triggered=handler) menu.addAction(action) return action fileMenu = self.menubar.addMenu('&File') newMenu = fileMenu.addMenu("&New") makeMenuAction("&Python file", "Ctrl+N", "Creates a new empty Python document.", newMenu, lambda: self.tabbedEditor.new('py')) makeMenuAction("&Lua file", "", "Creates a new empty Lua document.", newMenu, lambda: self.tabbedEditor.new('lua')) makeMenuAction("&Lisp file", "", "Creates a new empty Lisp document.", newMenu, lambda: self.tabbedEditor.new('lisp')) makeMenuAction("&JSON file", "", "Creates a new empty JSON document.", newMenu, lambda: self.tabbedEditor.new('json')) fileMenu.addSeparator() makeMenuAction("&Open...", "Ctrl+O", "Open an existing source code file.", fileMenu, self.tabbedEditor.open) makeMenuAction( "&Parse text...", "", "Open a source code text by typing it in a temporary " "window.", fileMenu, self.tabbedEditor.parse) fileMenu.addSeparator() self.save_menu = makeMenuAction( "&Save", "Ctrl+S", "Save the current source code back to the file it came " "from.", fileMenu, lambda: self.tabbedEditor.editor().save()) makeMenuAction("&Save as...", "Ctrl+Alt+S", "Save the current source code to a different file.", fileMenu, lambda: self.tabbedEditor.editor().save_as()) fileMenu.addSeparator() makeMenuAction("&Quit", "Ctrl+Q", "Close the application.", fileMenu, self.close) editMenu = self.menubar.addMenu('&Edit') self.undo_menu = makeMenuAction( "&Undo", "Ctrl+Z", "Reverts the last change.", editMenu, lambda: self.tabbedEditor.editor().undo()) self.redo_menu = makeMenuAction( "&Redo", "Ctrl+Shift+Z", "Executes the last change undone", editMenu, lambda: self.tabbedEditor.editor().redo()) viewMenu = self.menubar.addMenu("&View") for dock in self.docks: makeMenuAction("&" + dock.title, "Alt+" + dock.title[0], "Show the floating {}.".format(dock.title.lower()), viewMenu, dock.show) viewMenu.addSeparator() makeMenuAction( "&Reset window state", "Alt+R", "Reset the window and commands bar size and state back to the original settings.", viewMenu, self.resetWindow) updatesMenu = self.menubar.addMenu("&Updates") if can_update('http://www.inf.ufsc.br/~lucasboppre/Editor.exe'): makeMenuAction( "&Download latest version", "Alt+D", "Tries to download the latest version from a remote server.", updatesMenu, self.update) else: makeMenuAction("No updates available.", "", "", updatesMenu, lambda: None).setEnabled(False) def update(self): reply = QtWidgets.QMessageBox.question( self, "Update", "Do you want to download the new version and restart the application?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.No: return class Updater(QtCore.QThread): def run(self): update_and_restart( 'http://www.inf.ufsc.br/~lucasboppre/Editor.exe') progressDialog = QtWidgets.QProgressDialog( "Downloading latest version...", "", 0, 0, self) progressDialog.setCancelButton(None) progressBar = QtWidgets.QProgressBar(progressDialog) progressBar.setMinimum(0) progressBar.setMaximum(0) progressDialog.setBar(progressBar) progressDialog.show() updater = Updater() updater.finished.connect(progressDialog.close) updater.finished.connect(QtWidgets.QApplication.quit) updater.start() # Saving reference to avoid garbage collection. self.updater = updater def resetWindow(self, event=None): for dock in self.docks: dock.reset() self.settings.clear() self.settings.sync() self.restoreSettings() def restoreSettings(self): geometry_bytes = self.settings.value("geometry") or b'' state_bytes = self.settings.value("state") or b'' # Bug: when the geometry is empty, the commands bar is not shown by default. # This is a workaround that detects if there are settings saved and, if not, # forces the display of the commands bar. if len(geometry_bytes) == 0: for dock in self.docks: dock.show() self.restoreGeometry(geometry_bytes) self.restoreState(state_bytes) def closeEvent(self, event): self.settings.setValue('geometry', self.saveGeometry()) self.settings.setValue('state', self.saveState()) while self.tabbedEditor.count(): if not self.tabbedEditor.close_tab(): event.ignore() return QtWidgets.QMainWindow.closeEvent(self, event) def runCommand(self, command): self.tabbedEditor.editor().execute(command) def refresh(self): editor = self.tabbedEditor.editor() if not editor: return for dock in self.docks: dock.refresh(editor) title_template = '{} - Structured Editor' title = title_template.format(editor.name) self.setWindowTitle(title) self.statusBar().showMessage('Currently selected: ' + class_label(type(editor.selected))) self.undo_menu.setEnabled(editor.can_undo()) self.redo_menu.setEnabled(editor.can_redo())
class MainEditorWindow(QtWidgets.QMainWindow): def __init__(self): super(MainEditorWindow, self).__init__() #self.setCentralWidget(self.display) self.tabbedEditor = TabbedEditor(self.refresh, self) self.setCentralWidget(self.tabbedEditor) self.createDocks() self.createMenu() self.statusBar() self.setWindowTitle("Structured Editor") self.settings = QtCore.QSettings("TCC", "Editor Estruturado") self.restoreSettings() self.setAcceptDrops(True) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): for url in event.mimeData().urls(): self.tabbedEditor.add(HtmlEditor.from_file(url.path())) event.accept() def createDocks(self): def ask_for_name(r, old_name): old_name = old_name.replace('_', ' ') name, ok = QtWidgets.QInputDialog.getText(self, 'Rename', 'Enter a new name', text=old_name) new_name = name if ok else old_name return new_name.replace(' ', '_') actions.Rename.ask_for_name = ask_for_name def extractHotkeys(group, pairs): return {config.get(group, label): item for item, label in pairs} editing_label_pairs = [(actions.Delete, 'Delete'), (actions.Copy, 'Copy'), (actions.Cut, 'Cut'), (actions.Paste, 'Paste'), (actions.MoveUp, 'Move up'), (actions.MoveDown, 'Move down'), (actions.Rename, 'Rename')] editingWindow = CommandsWindow('Editing', self) editingWindow.addCommands(editing_label_pairs, extractHotkeys('Editing Hotkeys', editing_label_pairs), self.runCommand) movement_label_pairs = [(actions.SelectParent, 'Parent'), (actions.SelectChild, 'Child'), (actions.SelectNextSibling, 'Next'), (actions.SelectPrevSibling, 'Previous'), (actions.NextUnfilled, 'Next unfilled')] navigationWindow = CommandsWindow('Navigation', self) navigationWindow.addCommands(movement_label_pairs, extractHotkeys('Movement Hotkeys', movement_label_pairs), self.runCommand) insertionWindow = InsertionWindow(self.runCommand, config.section('Insertion Hotkeys'), self) macroWindow = MacroWindow(self) self.setDockNestingEnabled(True) self.docks = [editingWindow, navigationWindow, insertionWindow, macroWindow] def createMenu(self): self.menubar = self.menuBar() def makeMenuAction(label, shortcut, statusTip, menu, handler): action = QtWidgets.QAction(label, self, shortcut=shortcut, statusTip=statusTip, triggered=handler) menu.addAction(action) return action fileMenu = self.menubar.addMenu('&File') newMenu = fileMenu.addMenu("&New") makeMenuAction("&Python file", "Ctrl+N", "Creates a new empty Python document.", newMenu, lambda: self.tabbedEditor.new('py')) makeMenuAction("&Lua file", "", "Creates a new empty Lua document.", newMenu, lambda: self.tabbedEditor.new('lua')) makeMenuAction("&Lisp file", "", "Creates a new empty Lisp document.", newMenu, lambda: self.tabbedEditor.new('lisp')) makeMenuAction("&JSON file", "", "Creates a new empty JSON document.", newMenu, lambda: self.tabbedEditor.new('json')) fileMenu.addSeparator() makeMenuAction("&Open...", "Ctrl+O", "Open an existing source code file.", fileMenu, self.tabbedEditor.open) makeMenuAction("&Parse text...", "", "Open a source code text by typing it in a temporary " "window.", fileMenu, self.tabbedEditor.parse) fileMenu.addSeparator() self.save_menu = makeMenuAction("&Save", "Ctrl+S", "Save the current source code back to the file it came " "from.", fileMenu, lambda: self.tabbedEditor.editor().save()) makeMenuAction("&Save as...", "Ctrl+Alt+S", "Save the current source code to a different file.", fileMenu, lambda: self.tabbedEditor.editor().save_as()) fileMenu.addSeparator() makeMenuAction("&Quit", "Ctrl+Q", "Close the application.", fileMenu, self.close) editMenu = self.menubar.addMenu('&Edit') self.undo_menu = makeMenuAction("&Undo", "Ctrl+Z", "Reverts the last change.", editMenu, lambda: self.tabbedEditor.editor().undo()) self.redo_menu = makeMenuAction("&Redo", "Ctrl+Shift+Z", "Executes the last change undone", editMenu, lambda: self.tabbedEditor.editor().redo()) viewMenu = self.menubar.addMenu("&View") for dock in self.docks: makeMenuAction("&" + dock.title, "Alt+" + dock.title[0], "Show the floating {}.".format(dock.title.lower()), viewMenu, dock.show) viewMenu.addSeparator() makeMenuAction("&Reset window state", "Alt+R", "Reset the window and commands bar size and state back to the original settings.", viewMenu, self.resetWindow) updatesMenu = self.menubar.addMenu("&Updates") if can_update('http://www.inf.ufsc.br/~lucasboppre/Editor.exe'): makeMenuAction("&Download latest version", "Alt+D", "Tries to download the latest version from a remote server.", updatesMenu, self.update) else: makeMenuAction("No updates available.", "", "", updatesMenu, lambda: None).setEnabled(False) def update(self): reply = QtWidgets.QMessageBox.question(self, "Update", "Do you want to download the new version and restart the application?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.No: return class Updater(QtCore.QThread): def run(self): update_and_restart('http://www.inf.ufsc.br/~lucasboppre/Editor.exe') progressDialog = QtWidgets.QProgressDialog("Downloading latest version...", "", 0, 0, self) progressDialog.setCancelButton(None) progressBar = QtWidgets.QProgressBar(progressDialog) progressBar.setMinimum(0) progressBar.setMaximum(0) progressDialog.setBar(progressBar) progressDialog.show() updater = Updater() updater.finished.connect(progressDialog.close) updater.finished.connect(QtWidgets.QApplication.quit) updater.start() # Saving reference to avoid garbage collection. self.updater = updater def resetWindow(self, event=None): for dock in self.docks: dock.reset() self.settings.clear() self.settings.sync() self.restoreSettings() def restoreSettings(self): geometry_bytes = self.settings.value("geometry") or b'' state_bytes = self.settings.value("state") or b'' # Bug: when the geometry is empty, the commands bar is not shown by default. # This is a workaround that detects if there are settings saved and, if not, # forces the display of the commands bar. if len(geometry_bytes) == 0: for dock in self.docks: dock.show() self.restoreGeometry(geometry_bytes) self.restoreState(state_bytes) def closeEvent(self, event): self.settings.setValue('geometry', self.saveGeometry()) self.settings.setValue('state', self.saveState()) while self.tabbedEditor.count(): if not self.tabbedEditor.close_tab(): event.ignore() return QtWidgets.QMainWindow.closeEvent(self, event) def runCommand(self, command): self.tabbedEditor.editor().execute(command) def refresh(self): editor = self.tabbedEditor.editor() if not editor: return for dock in self.docks: dock.refresh(editor) title_template = '{} - Structured Editor' title = title_template.format(editor.name) self.setWindowTitle(title) self.statusBar().showMessage('Currently selected: ' + class_label(type(editor.selected))) self.undo_menu.setEnabled(editor.can_undo()) self.redo_menu.setEnabled(editor.can_redo())