class Document(QObject): def __init__(self, app): QObject.__init__(self) self.app = app self.documentPath = None self.model = DocumentModel(app=app.model) self.model.view = self #--- Public def close(self): if self.documentPath: self.model.close() def confirmDestructiveAction(self): # Asks whether the user wants to continue before continuing with an action that will replace # the current document. Will save the document as needed. Returns True if the action can # continue. if not self.model.is_dirty(): return True title = tr("Unsaved Document") msg = tr("Do you want to save your changes before continuing?") buttons = QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard result = QMessageBox.question(self.app.mainWindow, title, msg, buttons) if result == QMessageBox.Save: self.save() if self.model.is_dirty(): # "save as" was cancelled return False else: return True elif result == QMessageBox.Cancel: return False elif result == QMessageBox.Discard: return True def importDocument(self): title = tr("Select a document to import") filters = tr("Supported files (*.moneyguru *.ofx *.qfx *.qif *.csv *.txt)") docpath = str(QFileDialog.getOpenFileName(self.app.mainWindow, title, '', filters)) # There's a strange glitch under GNOME where, right after the dialog is gone, the main # window isn't the active window, but it will become active if we give it enough time. If we # start showing the import window before that happens, we'll end up with an import window # under the main window, which is bad. Therefore, we process events until this happens. We # do this in a big forloop instead of a while to avoid a possible infinite loop. for i in range(10000): if self.app.mainWindow.isActiveWindow(): break QApplication.processEvents() if docpath: try: self.model.parse_file_for_import(docpath) except FileFormatError as e: QMessageBox.warning(self.app.mainWindow, tr("Cannot import file"), str(e)) def new(self): if not self.confirmDestructiveAction(): return self.close() self.documentPath = None self.model.clear() self.documentPathChanged.emit() def open(self, docpath): if not self.confirmDestructiveAction(): return self.close() try: self.model.load_from_xml(docpath) self.documentPath = docpath except FileFormatError as e: QMessageBox.warning(self.app.mainWindow, tr("Cannot load file"), str(e)) self.documentPathChanged.emit() self.documentOpened.emit(docpath) def openDocument(self): title = tr("Select a document to load") filters = tr("moneyGuru Documents (*.moneyguru)") docpath = str(QFileDialog.getOpenFileName(self.app.mainWindow, title, '', filters)) if docpath: self.open(docpath) def openExampleDocument(self): if not self.confirmDestructiveAction(): return self.close() dirpath = tempfile.mkdtemp() destpath = op.join(dirpath, 'example.moneyguru') QFile.copy(':/example.moneyguru', destpath) self.model.load_from_xml(destpath) self.model.adjust_example_file() self.documentPath = None # As if it was a new doc. Save As is required. self.documentPathChanged.emit() def save(self): if self.documentPath is not None: self.model.save_to_xml(self.documentPath) else: self.saveAs() def saveAs(self): title = tr("Save As") filters = tr("moneyGuru Documents (*.moneyguru)") docpath = str(QFileDialog.getSaveFileName(self.app.mainWindow, title, '', filters)) if docpath: if not docpath.endswith('.moneyguru'): docpath += '.moneyguru' self.model.save_to_xml(docpath) self.documentPath = docpath self.documentPathChanged.emit() self.documentSavedAs.emit(docpath) # model --> view def query_for_schedule_scope(self): if QApplication.keyboardModifiers() & Qt.ShiftModifier: return ScheduleScope.Global if not self.app.model.show_schedule_scope_dialog: return ScheduleScope.Local dialog = ScheduleScopeDialog(self.app.mainWindow) return dialog.queryForScope() #--- Signals documentOpened = pyqtSignal(str) documentSavedAs = pyqtSignal(str) documentPathChanged = pyqtSignal()
class Document(QObject): def __init__(self, app): QObject.__init__(self) self.app = app self.documentPath = None self.model = DocumentModel(app=app.model) self.model.view = self # --- Public def close(self): if self.documentPath: self.model.close() def confirmDestructiveAction(self): # Asks whether the user wants to continue before continuing with an action that will replace # the current document. Will save the document as needed. Returns True if the action can # continue. if not self.model.is_dirty(): return True title = tr("Unsaved Document") msg = tr("Do you want to save your changes before continuing?") buttons = QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard result = QMessageBox.question(self.app.mainWindow, title, msg, buttons) if result == QMessageBox.Save: self.save() if self.model.is_dirty(): # "save as" was cancelled return False else: return True elif result == QMessageBox.Cancel: return False elif result == QMessageBox.Discard: return True def new(self): if not self.confirmDestructiveAction(): return self.close() self.documentPath = None self.model.clear() self.documentPathChanged.emit() def open(self, docpath, initial=False): # initial flag is true when open() is called at the document's initialization. When that's # the case, we need to create a new document when we fail opening this one. if not self.confirmDestructiveAction(): return self.close() try: self.model.load_from_xml(docpath) self.documentPath = docpath except FileFormatError as e: QMessageBox.warning(self.app.mainWindow, tr("Cannot load file"), str(e)) if initial: self.new() self.documentPathChanged.emit() self.documentOpened.emit(docpath) def openDocument(self): title = tr("Select a document to load") filters = tr("moneyGuru Documents (*.moneyguru)") docpath, filetype = QFileDialog.getOpenFileName(self.app.mainWindow, title, '', filters) if docpath: self.open(docpath) def openExampleDocument(self): if not self.confirmDestructiveAction(): return self.close() dirpath = tempfile.mkdtemp() destpath = op.join(dirpath, 'example.moneyguru') QFile.copy(':/example.moneyguru', destpath) self.model.load_from_xml(destpath) self.model.adjust_example_file() self.documentPath = None # As if it was a new doc. Save As is required. self.documentPathChanged.emit() def save(self): if self.documentPath is not None: self.model.save_to_xml(self.documentPath) else: self.saveAs() def saveAs(self): title = tr("Save As") filters = tr("moneyGuru Documents (*.moneyguru)") docpath = str(QFileDialog.getSaveFileName(self.app.mainWindow, title, '', filters)) if docpath: if not docpath.endswith('.moneyguru'): docpath += '.moneyguru' self.model.save_to_xml(docpath) self.documentPath = docpath self.documentPathChanged.emit() self.documentSavedAs.emit(docpath) # model --> view def query_for_schedule_scope(self): if QApplication.keyboardModifiers() & Qt.ShiftModifier: return ScheduleScope.Global if not self.app.model.show_schedule_scope_dialog: return ScheduleScope.Local dialog = ScheduleScopeDialog(self.app.mainWindow) return dialog.queryForScope() # --- Signals documentOpened = pyqtSignal(str) documentSavedAs = pyqtSignal(str) documentPathChanged = pyqtSignal()
class Document(QObject): def __init__(self, app): QObject.__init__(self) self.app = app self.documentPath = None self.model = DocumentModel(app=app.model) self.model.view = self # --- Public def close(self): if self.documentPath: self.model.close() def confirmDestructiveAction(self): # Asks whether the user wants to continue before continuing with an action that will replace # the current document. Will save the document as needed. Returns True if the action can # continue. if not self.model.is_dirty(): return True title = tr("Unsaved Document") msg = tr("Do you want to save your changes before continuing?") buttons = QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard result = QMessageBox.question(self.app.mainWindow, title, msg, buttons) if result == QMessageBox.Save: self.save() if self.model.is_dirty(): # "save as" was cancelled return False else: return True elif result == QMessageBox.Cancel: return False elif result == QMessageBox.Discard: return True def new(self): if not self.confirmDestructiveAction(): return self.close() self.documentPath = None self.model.clear() self.documentPathChanged.emit() def open(self, docpath, initial=False): # initial flag is true when open() is called at the document's initialization. When that's # the case, we need to create a new document when we fail opening this one. if not self.confirmDestructiveAction(): return self.close() try: self.model.load_from_xml(docpath) self.documentPath = docpath except FileFormatError as e: QMessageBox.warning(self.app.mainWindow, tr("Cannot load file"), str(e)) if initial: self.new() self.documentPathChanged.emit() self.documentOpened.emit(docpath) def openDocument(self): title = tr("Select a document to load") filters = tr("moneyGuru Documents (*.moneyguru)") docpath, filetype = QFileDialog.getOpenFileName( self.app.mainWindow, title, '', filters) if docpath: self.open(docpath) def openExampleDocument(self): if not self.confirmDestructiveAction(): return self.close() dirpath = tempfile.mkdtemp() destpath = op.join(dirpath, 'example.moneyguru') QFile.copy(':/example.moneyguru', destpath) self.model.load_from_xml(destpath) self.model.adjust_example_file() self.documentPath = None # As if it was a new doc. Save As is required. self.documentPathChanged.emit() def save(self): if self.documentPath is not None: self.model.save_to_xml(self.documentPath) else: self.saveAs() def saveAs(self): title = tr("Save As") filters = tr("moneyGuru Documents (*.moneyguru)") docpath = QFileDialog.getSaveFileName(self.app.mainWindow, title, '', filters)[0] if docpath: if not docpath.endswith('.moneyguru'): docpath += '.moneyguru' self.model.save_to_xml(docpath) self.documentPath = docpath self.documentPathChanged.emit() self.documentSavedAs.emit(docpath) # model --> view def query_for_schedule_scope(self): if QApplication.keyboardModifiers() & Qt.ShiftModifier: return ScheduleScope.Global if not self.app.model.show_schedule_scope_dialog: return ScheduleScope.Local dialog = ScheduleScopeDialog(self.app.mainWindow) return dialog.queryForScope() # --- Signals documentOpened = pyqtSignal(str) documentSavedAs = pyqtSignal(str) documentPathChanged = pyqtSignal()