[ui] improve check if plugins are available and fix load/unload of tracks/sfmData

This commit is contained in:
Fabien Castan 2020-07-25 18:30:22 +02:00
parent 48e73a3772
commit 5ed9de5e4e
3 changed files with 107 additions and 40 deletions

View file

@ -0,0 +1,9 @@
import AliceVision 1.0
import QtQuick 2.7
/**
* To evaluate if the QtAliceVision plugin is available.
*/
Item {
id: root
}

View file

@ -0,0 +1,10 @@
import DepthMapEntity 2.1
import QtQuick 2.7
/**
* To evaluate if the QtOIIO plugin is available.
* DepthMapEntity is in the same plugin than the imageformats plugin, that we cannot check from qml.
*/
Item {
id: root
}

View file

@ -14,16 +14,35 @@ FocusScope {
property var viewIn3D property var viewIn3D
property Component floatViewerComp: Qt.createComponent("FloatImage.qml") property Component floatViewerComp: Qt.createComponent("FloatImage.qml")
readonly property bool floatViewerAvailable: floatViewerComp.status === Component.Ready
property alias useFloatImageViewer: displayHDR.checked property alias useFloatImageViewer: displayHDR.checked
Loader {
id: aliceVisionPluginLoader
active: true
source: "TestAliceVisionPlugin.qml"
}
Loader {
id: oiioPluginLoader
active: true
source: "TestOIIOPlugin.qml"
}
readonly property bool aliceVisionPluginAvailable: aliceVisionPluginLoader.status === Component.Ready
readonly property bool oiioPluginAvailable: oiioPluginLoader.status === Component.Ready
Component.onCompleted: {
if(!aliceVisionPluginAvailable)
console.warn("Missing plugin qtAliceVision.")
if(!oiioPluginAvailable)
console.warn("Missing plugin qtOIIO.")
}
property string loadingModules: { property string loadingModules: {
if(!imgContainer.image) if(!imgContainer.image)
return ""; return "";
var res = ""; var res = "";
if(imgContainer.image.status === Image.Loading) if(imgContainer.image.status === Image.Loading)
res += " Image"; res += " Image";
if(featuresViewerLoader.status === Loader.Ready) if(featuresViewerLoader.status === Loader.Ready && featuresViewerLoader.item)
{ {
for (var i = 0; i < featuresViewerLoader.item.count; ++i) { for (var i = 0; i < featuresViewerLoader.item.count; ++i) {
if(featuresViewerLoader.item.itemAt(i).loadingFeatures) if(featuresViewerLoader.item.itemAt(i).loadingFeatures)
@ -33,6 +52,11 @@ FocusScope {
} }
} }
} }
if(mtracksLoader.status === Loader.Ready)
{
if(mtracksLoader.item.status === MTracks.Loading)
res += " Tracks";
}
if(msfmDataLoader.status === Loader.Ready) if(msfmDataLoader.status === Loader.Ready)
{ {
if(msfmDataLoader.item.status === MSfMData.Loading) if(msfmDataLoader.item.status === MSfMData.Loading)
@ -40,11 +64,6 @@ FocusScope {
res += " SfMData"; res += " SfMData";
} }
} }
if(mtracksLoader.status === Loader.Ready)
{
if(mtracksLoader.item.status === MTracks.Loading)
res += " Tracks";
}
return res; return res;
} }
@ -179,7 +198,7 @@ FocusScope {
// qtAliceVision Image Viewer // qtAliceVision Image Viewer
Loader { Loader {
id: floatImageViewerLoader id: floatImageViewerLoader
active: root.useFloatImageViewer active: root.aliceVisionPluginAvailable && root.useFloatImageViewer
visible: (floatImageViewerLoader.status === Loader.Ready) visible: (floatImageViewerLoader.status === Loader.Ready)
anchors.centerIn: parent anchors.centerIn: parent
@ -204,7 +223,7 @@ FocusScope {
// Simple QML Image Viewer (using Qt or qtOIIO to load images) // Simple QML Image Viewer (using Qt or qtOIIO to load images)
Loader { Loader {
id: qtImageViewerLoader id: qtImageViewerLoader
active: (!root.useFloatImageViewer) || (floatImageViewerLoader.status === Loader.Error) active: !floatImageViewerLoader.active
anchors.centerIn: parent anchors.centerIn: parent
sourceComponent: Image { sourceComponent: Image {
id: qtImageViewer id: qtImageViewer
@ -354,9 +373,9 @@ FocusScope {
// show which depthmap node is active // show which depthmap node is active
Label { Label {
id: depthMapNodeName id: depthMapNodeName
property var activeNode: _reconstruction.activeNodes.get("allDepthMap").node property var activeNode: root.oiioPluginAvailable ? _reconstruction.activeNodes.get("allDepthMap").node : null
visible: (activeNode != undefined) && (imageType.type != "image") visible: (imageType.type != "image") && activeNode
text: (activeNode != undefined ? activeNode.label : "") text: activeNode ? activeNode.label : ""
font.pointSize: 8 font.pointSize: 8
horizontalAlignment: TextInput.AlignLeft horizontalAlignment: TextInput.AlignLeft
@ -387,77 +406,105 @@ FocusScope {
Loader { Loader {
id: msfmDataLoader id: msfmDataLoader
// active: _reconstruction.sfm && _reconstruction.sfm.isComputed
property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked
property var activeNode: _reconstruction.sfm property var activeNode: root.aliceVisionPluginAvailable ? _reconstruction.activeNodes.get('sfm').node : null
property bool isComputed: activeNode && activeNode.isComputed property bool isComputed: activeNode && activeNode.isComputed
property string filepath: Filepath.stringToUrl(isComputed ? activeNode.attribute("output").value : "")
active: false active: false
// It takes time to load tracks, so keep them looaded, if we may use it again. // It takes time to load tracks, so keep them looaded, if we may use it again.
// If we load another node, we can trash them (to eventually load the new node data). // If we load another node, we can trash them (to eventually load the new node data).
onIsUsedChanged: { onIsUsedChanged: {
if(!active && isUsed && isComputed) if(!active && isUsed && isComputed)
{
active = true; active = true;
}
} }
onIsComputedChanged: { onIsComputedChanged: {
if(!isComputed) if(!isComputed)
{
active = false; active = false;
if(!active && isUsed) }
else if(!active && isUsed)
{
active = true; active = true;
}
} }
onActiveNodeChanged: { onActiveNodeChanged: {
if(!isUsed) if(!isUsed)
{
active = false; active = false;
}
else if(!isComputed) else if(!isComputed)
{
active = false; active = false;
}
else else
{
active = true; active = true;
}
} }
Component.onCompleted: { onActiveChanged: {
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource if(active) {
// so it can fail safely if the c++ plugin is not available // instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
setSource("MSfMData.qml", { // so it can fail safely if the c++ plugin is not available
'sfmDataPath': Qt.binding(function() { return Filepath.stringToUrl(isComputed ? activeNode.attribute("output").value : ""); }), setSource("MSfMData.qml", {
}) 'sfmDataPath': Qt.binding(function() { return filepath; }),
})
} else {
// Force the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14
setSource("", {})
}
} }
} }
Loader { Loader {
id: mtracksLoader id: mtracksLoader
property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked
property var activeNode: _reconstruction.activeNodes.get('FeatureMatching').node property var activeNode: root.aliceVisionPluginAvailable ? _reconstruction.activeNodes.get('FeatureMatching').node : null
property bool isComputed: activeNode && activeNode.isComputed property bool isComputed: activeNode && activeNode.isComputed
active: false active: false
// It takes time to load tracks, so keep them looaded, if we may use it again. // It takes time to load tracks, so keep them looaded, if we may use it again.
// If we load another node, we can trash them (to eventually load the new node data). // If we load another node, we can trash them (to eventually load the new node data).
onIsUsedChanged: { onIsUsedChanged: {
if(!active && isUsed && isComputed) if(!active && isUsed && isComputed) {
active = true; active = true;
}
} }
onIsComputedChanged: { onIsComputedChanged: {
if(!isComputed) if(!isComputed) {
active = false; active = false;
if(!active && isUsed) }
else if(!active && isUsed) {
active = true; active = true;
}
} }
onActiveNodeChanged: { onActiveNodeChanged: {
if(!isUsed) if(!isUsed) {
active = false; active = false;
else if(!isComputed) }
else if(!isComputed) {
active = false; active = false;
else }
else {
active = true; active = true;
}
} }
Component.onCompleted: { onActiveChanged: {
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource if(active) {
// so it can fail safely if the c++ plugin is not available // instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
setSource("MTracks.qml", { // so it can fail safely if the c++ plugin is not available
'matchingFolder': Qt.binding(function() { return Filepath.stringToUrl(isComputed ? activeNode.attribute("output").value : ""); }), setSource("MTracks.qml", {
}) 'matchingFolder': Qt.binding(function() { return Filepath.stringToUrl(isComputed ? activeNode.attribute("output").value : ""); }),
})
} else {
// Force the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14
setSource("", {})
}
} }
} }
Loader { Loader {
@ -497,7 +544,7 @@ FocusScope {
left: parent.left left: parent.left
margins: 2 margins: 2
} }
active: displayFeatures.checked && featuresViewerLoader.status === Loader.Ready active: root.aliceVisionPluginAvailable && displayFeatures.checked && featuresViewerLoader.status === Loader.Ready
sourceComponent: FeaturesInfoOverlay { sourceComponent: FeaturesInfoOverlay {
featureExtractionNode: _reconstruction.activeNodes.get('FeatureExtraction').node featureExtractionNode: _reconstruction.activeNodes.get('FeatureExtraction').node
@ -555,7 +602,7 @@ FocusScope {
Layout.minimumWidth: 0 Layout.minimumWidth: 0
checkable: true checkable: true
checked: false checked: false
enabled: root.floatViewerAvailable enabled: root.aliceVisionPluginAvailable
} }
MaterialToolButton { MaterialToolButton {
id: displayFeatures id: displayFeatures
@ -565,6 +612,7 @@ FocusScope {
Layout.minimumWidth: 0 Layout.minimumWidth: 0
checkable: true checkable: true
checked: false checked: false
enabled: root.aliceVisionPluginAvailable
} }
MaterialToolButton { MaterialToolButton {
id: displayFisheyeCircleLoader id: displayFisheyeCircleLoader
@ -591,7 +639,7 @@ FocusScope {
ComboBox { ComboBox {
id: imageType id: imageType
property var activeNode: _reconstruction.activeNodes.get('allDepthMap').node property var activeNode: root.oiioPluginAvailable ? _reconstruction.activeNodes.get('allDepthMap').node : null
// set min size to 5 characters + one margin for the combobox // set min size to 5 characters + one margin for the combobox
clip: true clip: true
Layout.minimumWidth: 0 Layout.minimumWidth: 0
@ -606,7 +654,7 @@ FocusScope {
} }
MaterialToolButton { MaterialToolButton {
property var activeNode: _reconstruction.activeNodes.get('allDepthMap').node property var activeNode: root.oiioPluginAvailable ? _reconstruction.activeNodes.get('allDepthMap').node : null
enabled: activeNode enabled: activeNode
ToolTip.text: "View Depth Map in 3D (" + (activeNode ? activeNode.label : "No DepthMap Node Selected") + ")" ToolTip.text: "View Depth Map in 3D (" + (activeNode ? activeNode.label : "No DepthMap Node Selected") + ")"
text: MaterialIcons.input text: MaterialIcons.input
@ -620,7 +668,7 @@ FocusScope {
MaterialToolButton { MaterialToolButton {
id: displaySfmStatsView id: displaySfmStatsView
property var activeNode: _reconstruction.activeNodes.get('sfm').node property var activeNode: root.aliceVisionPluginAvailable ? _reconstruction.activeNodes.get('sfm').node : null
font.family: MaterialIcons.fontFamily font.family: MaterialIcons.fontFamily
text: MaterialIcons.assessment text: MaterialIcons.assessment
@ -644,7 +692,7 @@ FocusScope {
MaterialToolButton { MaterialToolButton {
id: displaySfmDataGlobalStats id: displaySfmDataGlobalStats
property var activeNode: _reconstruction.activeNodes.get('sfm').node property var activeNode: root.aliceVisionPluginAvailable ? _reconstruction.activeNodes.get('sfm').node : null
font.family: MaterialIcons.fontFamily font.family: MaterialIcons.fontFamily
text: MaterialIcons.language text: MaterialIcons.language