Skip to content

Commit a52c06e

Browse files
AstroChuckreilleya
authored andcommitted
Added Recent File Menu
OpenMotor now tracks recently opened files and lets you easily return to them.
1 parent 2943b45 commit a52c06e

File tree

4 files changed

+66
-4
lines changed

4 files changed

+66
-4
lines changed

uilib/fileIO.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class fileTypes(Enum):
1616
PREFERENCES = 1
1717
PROPELLANTS = 2
1818
MOTOR = 3
19+
RECENT_FILES = 4
1920

2021
def futureVersion(verA, verB): # Returns true if a is newer than b
2122
major = verA[0] > verB[0]
@@ -162,7 +163,8 @@ def migrateMotor_0_2_0_to_0_3_0(data):
162163
'to': (0, 6, 0),
163164
fileTypes.PREFERENCES: passthrough,
164165
fileTypes.PROPELLANTS: passthrough,
165-
fileTypes.MOTOR: migrateMotor_0_5_0_to_0_6_0
166+
fileTypes.MOTOR: migrateMotor_0_5_0_to_0_6_0,
167+
fileTypes.RECENT_FILES: passthrough
166168
},
167169
(0, 4, 0): {
168170
'to': (0, 5, 0),

uilib/fileManager.py

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
1-
from PyQt6.QtCore import QObject
1+
from PyQt6.QtCore import QObject, pyqtSignal
22
from PyQt6.QtWidgets import QFileDialog, QMessageBox
3-
from PyQt6.QtCore import pyqtSignal
3+
from PyQt6.QtGui import QAction
44

5+
import os
56
import motorlib
67

7-
from .fileIO import saveFile, loadFile, fileTypes
8+
from .fileIO import saveFile, loadFile, fileTypes, getConfigPath
89
from .helpers import FLAGS_NO_ICON, excludeKeys
910
from .logger import logger
1011

1112
class FileManager(QObject):
1213

14+
MAX_RECENT_FILES = 5
15+
1316
fileNameChanged = pyqtSignal(str, bool)
1417
newMotor = pyqtSignal(object)
18+
# TODO: eventually a signal like this that makes the mainWindow repopulate the propellant editor should
19+
# be emitted whenever load() is called
20+
recentFileLoaded = pyqtSignal()
1521

1622
def __init__(self, app):
1723
super().__init__()
@@ -25,6 +31,9 @@ def __init__(self, app):
2531

2632
self.newFile()
2733

34+
self.recentlyOpenedFiles = []
35+
self.recentFilesPath = os.path.join(getConfigPath(), 'recent_files.yaml')
36+
2837
# Check if current motor is unsaved and start over from default motor. Called when the menu item is triggered.
2938
def newFile(self):
3039
if not self.unsavedCheck():
@@ -67,6 +76,7 @@ def saveAs(self):
6776
if fileName is not None:
6877
self.fileName = fileName
6978
self.save()
79+
self.addRecentFile(fileName)
7080

7181
# Checks for unsaved changes, asks for a filename, and loads the file
7282
def load(self, path=None):
@@ -80,6 +90,7 @@ def load(self, path=None):
8090
motor = motorlib.motor.Motor()
8191
motor.applyDict(res)
8292
self.startFromMotor(motor, path)
93+
self.addRecentFile(path)
8394
return True
8495
except Exception as exc:
8596
self.app.outputException(exc, "An error occurred while loading the file: ")
@@ -233,3 +244,44 @@ def checkPropellant(self, motor):
233244
'New propellant added')
234245

235246
return motor
247+
248+
def createRecentlyOpenedMenu(self, recentlyOpenedMenu):
249+
self.recentlyOpenedMenu = recentlyOpenedMenu
250+
251+
try:
252+
self.recentFilesList = loadFile(self.recentFilesPath, fileTypes.RECENT_FILES)['recentFilesList']
253+
except FileNotFoundError:
254+
logger.warn('Unable to load recent files, creating new file at {}'.format(self.recentFilesPath))
255+
self.recentFilesList = []
256+
saveFile(self.recentFilesPath, {'recentFilesList': self.recentFilesList}, fileTypes.RECENT_FILES)
257+
258+
self.createRecentlyOpenedItems()
259+
260+
def createRecentlyOpenedItems(self):
261+
self.recentlyOpenedMenu.clear()
262+
263+
if len(self.recentFilesList) == 0:
264+
self.recentlyOpenedMenu.addAction(QAction('No Recent Files', self.recentlyOpenedMenu))
265+
return
266+
267+
for filepath in self.recentFilesList:
268+
_, filename = os.path.split(filepath)
269+
action = QAction(filename, self.recentlyOpenedMenu)
270+
action.triggered.connect(lambda _, path=filepath: self.loadRecentFile(path))
271+
self.recentlyOpenedMenu.addAction(action)
272+
273+
def loadRecentFile(self, path):
274+
self.load(path)
275+
self.recentFileLoaded.emit()
276+
277+
def addRecentFile(self, filepath):
278+
if filepath in self.recentFilesList:
279+
self.recentFilesList.remove(filepath)
280+
281+
self.recentFilesList = [filepath] + self.recentFilesList
282+
283+
self.recentFilesList = self.recentFilesList[:FileManager.MAX_RECENT_FILES]
284+
285+
saveFile(self.recentFilesPath, {'recentFilesList': self.recentFilesList}, fileTypes.RECENT_FILES)
286+
287+
self.createRecentlyOpenedItems()

uilib/views/forms/MainWindow.ui

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,8 +587,14 @@
587587
<string>Import</string>
588588
</property>
589589
</widget>
590+
<widget class="QMenu" name="menuOpen_Recent">
591+
<property name="title">
592+
<string>Open Recent</string>
593+
</property>
594+
</widget>
590595
<addaction name="actionNew"/>
591596
<addaction name="actionOpen"/>
597+
<addaction name="menuOpen_Recent"/>
592598
<addaction name="actionSave"/>
593599
<addaction name="actionSaveAs"/>
594600
<addaction name="separator"/>

uilib/widgets/mainWindow.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(self, app):
3434
self.app.fileManager.fileNameChanged.connect(self.updateWindowTitle)
3535
self.app.fileManager.newMotor.connect(self.resetOutput)
3636
self.app.fileManager.newMotor.connect(self.getQuickResults)
37+
self.app.fileManager.recentFileLoaded.connect(self.motorImported)
3738

3839
self.app.importExportManager.motorImported.connect(self.motorImported)
3940

@@ -88,6 +89,7 @@ def setupMenu(self):
8889
self.ui.actionOpen.triggered.connect(lambda x: self.loadMotor(None))
8990

9091
self.app.importExportManager.createMenus(self.ui.menuImport, self.ui.menuExport)
92+
self.app.fileManager.createRecentlyOpenedMenu(self.ui.menuOpen_Recent)
9193

9294
self.ui.actionQuit.triggered.connect(self.closeEvent)
9395

0 commit comments

Comments
 (0)