Hi All - I'm trying to use the "Generate Offline Map" sample and am running into an error that is telling me that the mobile map directory path is not specified.
qml: error: Invalid argument Mobile map directory path is not specified.
I have tried hard coding the path in the sample to "c:\temp\out.mmpk" just in case my URL variable was not working correctly, but it still is giving me the same result. The only thing I have changed is to give it my own portal item which is a webmap that is available to the public for testing purposes.
I'm sure I'm missing something very simple as I'm new to Qt/QML. Any insights would be appreciated. Code is below, but it's almost identical to the original sample.
Thanks in advance!
// Create a button and anchor it to the attribution top
QtControls.Button {
id: downloadButton
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.verticalCenter
margins: 5 * scaleFactor
}
visible: map.loadStatus === Enums.LoadStatusLoaded
onClicked: extentRectangle.getRectangleEnvelope();
}
// Create an extent rectangle for selecting the offline area
Rectangle {
id: extentRectangle
anchors.centerIn: parent
width: parent.width - (50 * scaleFactor)height: parent.height - (125 * scaleFactor)
color: "transparent"
visible: map.loadStatus === Enums.LoadStatusLoaded
border {
color: "red"
width: 3 * scaleFactor
}
function getRectangleEnvelope() {
var corner1 = mapView.screenToLocation(extentRectangle.x, extentRectangle.y);
var corner2 = mapView.screenToLocation((extentRectangle.x + extentRectangle.width), (extentRectangle.y + extentRectangle.height));
var envBuilder = ArcGISRuntimeEnvironment.createObject("EnvelopeBuilder");
envBuilder.setCorners(corner1, corner2);
var mapExtent = GeometryEngine.project(envBuilder.geometry, SpatialReference.createWebMercator());
offlineMapTask.createDefaultGenerateOfflineMapParameters(mapExtent);
}
}
// Create Offline Map Task
OfflineMapTask {
id: offlineMapTask
portalItem: mapPortalItem
//onlineMap: map
property var generateJob
onErrorChanged: console.log("error:", error.message, error.additionalMessage);
onCreateDefaultGenerateOfflineMapParametersStatusChanged: {
if (createDefaultGenerateOfflineMapParametersStatus !== Enums.TaskStatusCompleted)
return;
// Take the map offline once the parameters are generated
takeMapOffline(offlineMapTask.createDefaultGenerateOfflineMapParametersResult);
}
function takeMapOffline(parameters) {
// create the job
generateJob = offlineMapTask.generateOfflineMap(parameters, "c:\temp\out.mmpk");
console.log(mapPortalItem.url);
console.log(mapPortalItem.itemId);
console.log(mapPortalItem.type);
// check if job is valid
if (generateJob) {
// show the export window
generateWindow.visible = true;
console.log("Path: " + generateJob.downloadDirectoryPath);
console.log("test: "+ generateJob.parameters.areaOfInterest);
// connect to the job's status changed signal to know once it is done
generateJob.jobStatusChanged.connect(updateJobStatus);
// connect to the job's progress changed signal
generateJob.progressChanged.connect(updateProgress);
generateJob.start();
} else {
generateWindow.visible = true;
generateWindow.statusText = "Task failed";
generateWindow.hideWindow(5000);
console.log("error:", generateJob.error.message, generateJob.error.additionalMessage);
}
}
function updateJobStatus() {
switch(generateJob.jobStatus) {
case Enums.JobStatusFailed:
generateWindow.statusText = "Task failed";
generateWindow.hideWindow(5000);
console.log("error:", generateJob.error.message, generateJob.error.additionalMessage);
break;
case Enums.JobStatusNotStarted:
generateWindow.statusText = "Job not started";
break;
case Enums.JobStatusPaused:
generateWindow.statusText = "Job paused";
break;
case Enums.JobStatusStarted:
generateWindow.statusText = "In progress";
break;
case Enums.JobStatusSucceeded:
// show any layer errors
if (generateJob.result.hasErrors) {
var layerErrors = generateJob.result.layerErrors;
var errorText = "";
for (var i = 0; i < layerErrors.length; i++) {
var errorPair = layerErrors[i];
errorText += errorPair.layer.name + ": " + errorPair.error.message + "\n";
}
msgDialog.detailedText = errorText;
msgDialog.open();
}
// show the map
generateWindow.statusText = "Complete";
generateWindow.hideWindow(1500);
displayOfflineMap(generateJob.result);
break;
default:
console.log("default");
break;
}
}
function updateProgress() {
generateWindow.progressText = generateJob.progress;
}
function displayOfflineMap(result) {
// Set the offline map to the MapView
mapView.map = result.offlineMap;
downloadButton.visible = false;
extentRectangle.visible = false;
}
Component.onDestruction: {
if (generateJob) {
generateJob.jobStatusChanged.disconnect(updateJobStatus);
generateJob.progressChanged.disconnect(updateProgress);
}
}
}
GenerateWindow {
id: generateWindow
anchors.fill: parent
}
MessageDialog {
id: msgDialog
title: "Layer Errors"
text: "Some layers could not be taken offline."
}
Hi Pam,
I suspect the issue may be the string "c:\temp\out.mmpk".
The backslash has a special meaning in Javascript. (And by extension, QML!) In this case if I print the above path to console I get:
c: empout.mmpk
To escape the special meaning, you would either need to write the path as:
"c:\\temp\\out.mmpk" or as "c:/temp/out.mmpk".
I would recommend using forward slashes if you can. Qt accepts forward slashes for paths on every platform!
Also as a final note - generateOfflineMap accepts a QUrl as an argument. This sometimes means you need to be explicit with the protocol you are using, such as fully qualifying your path to: "file:///C:/temp/out.mmpk"
I have seen in the past QML convert an unqualified URL to "qrc://C:/temp/out.mmpk", which is not what you want!
Hope this helps.