from __future__ import annotations from pathlib import Path from ..Qt import QtWidgets, QtCore, QtGui from ..lib.codeeditor import CodeEditor class QUsermodelEditor(QtWidgets.QMainWindow): modelsChanged = QtCore.pyqtSignal() def __init__(self, fname: str | Path = None, parent=None): super().__init__(parent=parent) self._init_gui() self.fname = None self._dir = None if fname is not None: self.read_file(fname) def _init_gui(self): self.centralwidget = QtWidgets.QWidget(self) layout = QtWidgets.QVBoxLayout(self.centralwidget) layout.setContentsMargins(3, 3, 3, 3) layout.setSpacing(3) self.edit_field = CodeEditor(self.centralwidget) font = QtGui.QFont('default') font.setStyleHint(font.Monospace) font.setPointSize(10) self.edit_field.setFont(font) layout.addWidget(self.edit_field) self.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(self) self.setStatusBar(self.statusbar) self.menubar = self.menuBar() self.menuFile = QtWidgets.QMenu('File', self.menubar) self.menubar.addMenu(self.menuFile) self.menuFile.addAction('Open...', self.open_file, QtGui.QKeySequence.Open) self.menuFile.addAction('Save', self.overwrite_file, QtGui.QKeySequence.Save) self.menuFile.addAction('Save as...', self.save_file, QtGui.QKeySequence('Ctrl+Shift+S')) self.menuFile.addSeparator() self.menuFile.addAction('Close', self.close, QtGui.QKeySequence.Quit) self.resize(800, 600) self.setGeometry(QtWidgets.QStyle.alignedRect( QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, self.size(), QtWidgets.qApp.desktop().availableGeometry() )) @property def is_modified(self): return self.edit_field.document().isModified() @is_modified.setter def is_modified(self, val: bool): self.edit_field.document().setModified(val) @QtCore.pyqtSlot() def open_file(self): overwrite = self.changes_saved if overwrite: fname, _ = QtWidgets.QFileDialog.getOpenFileName(directory=str(self._dir)) if fname: self.read_file(fname) def read_file(self, fname: str | Path): self.set_fname_opts(fname) with self.fname.open('r') as f: self.edit_field.setPlainText(f.read()) def set_fname_opts(self, fname: str | Path): self.fname = Path(fname) self._dir = self.fname.parent self.setWindowTitle('Edit ' + str(fname)) @property def changes_saved(self) -> bool: if not self.is_modified: return True ret = QtWidgets.QMessageBox.question(self, 'Time to think', '
The document was modified.
\n' 'Do you want to save changes?
', QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel) if ret == QtWidgets.QMessageBox.Yes: self.save_file() if ret == QtWidgets.QMessageBox.No: self.is_modified = False return not self.is_modified @QtCore.pyqtSlot() def save_file(self): outfile, _ = QtWidgets.QFileDialog().getSaveFileName(parent=self, caption='Save file', directory=str(self._dir)) if outfile: with open(outfile, 'w') as f: f.write(self.edit_field.toPlainText()) self.set_fname_opts(outfile) self.is_modified = False return self.is_modified @QtCore.pyqtSlot() def overwrite_file(self): if self.fname is not None: with self.fname.open('w') as f: f.write(self.edit_field.toPlainText()) self.modelsChanged.emit() self.is_modified = False def closeEvent(self, evt: QtGui.QCloseEvent): if not self.changes_saved: evt.ignore() else: super().closeEvent(evt)