mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-05 12:21:59 +02:00
[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:
parent
dcf91c244e
commit
0e434908a5
6 changed files with 101 additions and 19 deletions
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. """
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue