[ui] improve open recent files

* fix path conversion on windows
* remove invalid paths from the list on error
* explicit error message for "No Such File"
This commit is contained in:
Fabien Castan 2020-03-16 19:58:37 +01:00
parent dcf91c244e
commit 0e434908a5
6 changed files with 101 additions and 19 deletions

View file

@ -280,6 +280,8 @@ class Graph(BaseObject):
# Create graph edges by resolving attributes expressions
self._applyExpr()
return True
@property
def updateEnabled(self):
return self._updateEnabled

View file

@ -8,6 +8,8 @@ from PySide2.QtWidgets import QApplication
import meshroom
from meshroom.core import nodesDesc
from meshroom.core import pyCompatibility
from meshroom.ui import components
from meshroom.ui.components.clipboard import ClipboardHelper
from meshroom.ui.components.filepath import FilepathHelper
@ -183,8 +185,19 @@ class MeshroomApp(QApplication):
return projects
@Slot(str)
@Slot(QUrl)
def addRecentProjectFile(self, projectFile):
projectFile = QUrl(projectFile).path()
if not isinstance(projectFile, (QUrl, pyCompatibility.basestring)):
raise TypeError("Unexpected data type: {}".format(projectFile.__class__))
if isinstance(projectFile, QUrl):
projectFileNorm = projectFile.toLocalFile()
if not projectFileNorm:
projectFileNorm = projectFile.toString()
else:
projectFileNorm = QUrl(projectFile).toLocalFile()
if not projectFileNorm:
projectFileNorm = QUrl.fromLocalFile(projectFile).toLocalFile()
projects = self._recentProjectFiles()
# remove duplicates while preserving order
@ -192,10 +205,10 @@ class MeshroomApp(QApplication):
uniqueProjects = OrderedDict.fromkeys(projects)
projects = list(uniqueProjects)
# remove previous usage of the value
if projectFile in uniqueProjects:
projects.remove(projectFile)
if projectFileNorm in uniqueProjects:
projects.remove(projectFileNorm)
# add the new value in the first place
projects.insert(0, projectFile)
projects.insert(0, projectFileNorm)
# keep only the 10 first elements
projects = projects[0:20]
@ -211,6 +224,43 @@ class MeshroomApp(QApplication):
self.recentProjectFilesChanged.emit()
@Slot(str)
@Slot(QUrl)
def removeRecentProjectFile(self, projectFile):
if not isinstance(projectFile, (QUrl, pyCompatibility.basestring)):
raise TypeError("Unexpected data type: {}".format(projectFile.__class__))
if isinstance(projectFile, QUrl):
projectFileNorm = projectFile.toLocalFile()
if not projectFileNorm:
projectFileNorm = projectFile.toString()
else:
projectFileNorm = QUrl(projectFile).toLocalFile()
if not projectFileNorm:
projectFileNorm = QUrl.fromLocalFile(projectFile).toLocalFile()
projects = self._recentProjectFiles()
# remove duplicates while preserving order
from collections import OrderedDict
uniqueProjects = OrderedDict.fromkeys(projects)
projects = list(uniqueProjects)
# remove previous usage of the value
if projectFileNorm not in uniqueProjects:
return
projects.remove(projectFileNorm)
settings = QSettings()
settings.beginGroup("RecentFiles")
size = settings.beginWriteArray("Projects")
for i, p in enumerate(projects):
settings.setArrayIndex(i)
settings.setValue("filepath", p)
settings.endArray()
settings.sync()
self.recentProjectFilesChanged.emit()
@Slot(str, result=str)
def markdownToHtml(self, md):
"""

View file

@ -309,16 +309,14 @@ class UIGraph(QObject):
self.stopExecution()
self._chunksMonitor.stop()
def load(self, filepath, setupProjectFile=True):
@Slot(str, result=bool)
def loadGraph(self, filepath, setupProjectFile=True):
g = Graph('')
g.load(filepath, setupProjectFile)
status = g.load(filepath, setupProjectFile)
if not os.path.exists(g.cacheDir):
os.mkdir(g.cacheDir)
self.setGraph(g)
@Slot(QUrl)
def loadUrl(self, url):
self.load(url.toLocalFile())
return status
@Slot(QUrl)
def saveAs(self, url):

View file

@ -75,7 +75,7 @@ FloatingPane {
property var viewer: root.featuresViewer.itemAt(index)
spacing: 4
// Visibility toogle
// Visibility toggle
MaterialToolButton {
text: featureType.viewer.visible ? MaterialIcons.visibility : MaterialIcons.visibility_off
onClicked: featureType.viewer.visible = !featureType.viewer.visible

View file

@ -207,8 +207,10 @@ ApplicationWindow {
title: "Open File"
nameFilters: ["Meshroom Graphs (*.mg)"]
onAccepted: {
_reconstruction.loadUrl(file.toString())
MeshroomApp.addRecentProjectFile(file.toString())
if(_reconstruction.loadUrl(file))
{
MeshroomApp.addRecentProjectFile(file.toString())
}
}
}
@ -353,8 +355,14 @@ ApplicationWindow {
MenuItem {
onTriggered: ensureSaved(function() {
openRecentMenu.dismiss();
_reconstruction.load(modelData);
MeshroomApp.addRecentProjectFile(modelData);
if(_reconstruction.loadUrl(modelData))
{
MeshroomApp.addRecentProjectFile(modelData);
}
else
{
MeshroomApp.removeRecentProjectFile(modelData);
}
})
text: fileTextMetrics.elidedText

View file

@ -430,10 +430,10 @@ class Reconstruction(UIGraph):
# use the user-provided default photogrammetry project file
self.load(p, setupProjectFile=False)
@Slot(str)
@Slot(str, result=bool)
def load(self, filepath, setupProjectFile=True):
try:
super(Reconstruction, self).load(filepath, setupProjectFile)
status = super(Reconstruction, self).loadGraph(filepath, setupProjectFile)
# warn about pre-release projects being automatically upgraded
if Version(self._graph.fileReleaseVersion).major == "0":
self.warning.emit(Message(
@ -442,17 +442,41 @@ class Reconstruction(UIGraph):
"Data might have been lost in the process.",
"Open it with the corresponding version of Meshroom to recover your data."
))
return status
except FileNotFoundError as e:
self.error.emit(
Message(
"No Such File",
"Error While Loading '{}': No Such File.".format(os.path.basename(filepath)),
""
)
)
logging.error("Error while loading '{}': No Such File.".format(os.path.basename(filepath)))
return False
except Exception as e:
import traceback
trace = traceback.format_exc()
self.error.emit(
Message(
"Error while loading {}".format(os.path.basename(filepath)),
"An unexpected error has occurred",
"Error While Loading Project File",
"An unexpected error has occurred while loading file: '{}'".format(os.path.basename(filepath)),
trace
)
)
logging.error(trace)
return False
@Slot(QUrl, result=bool)
def loadUrl(self, url):
if isinstance(url, (QUrl)):
# depending how the QUrl has been initialized,
# toLocalFile() may return the local path or an empty string
localFile = url.toLocalFile()
if not localFile:
localFile = url.toString()
else:
localFile = url
return self.load(localFile)
def onGraphChanged(self):
""" React to the change of the internal graph. """