Use transactions to manage how changes are committed to a geodatabase.

Use case
Transactions allow you to control how changes are added to a database. This is useful to ensure that when multiple changes are made to a database, they all succeed or fail at once. For example, you could have a business rule that both parent/guardian and student must be added to a database used for calculating school bus routes. You can use transactions to avoid breaking the business rule if you lose power while between the steps of adding the student and parent/guardian.
How to use the sample
Tap on the map to add multiple types of features. To apply edits directly, uncheck the “Requires Transaction”. When using transactions, use the buttons to start editing and stop editing. When you stop editing, you can choose to commit the changes or roll them back.
How it works
- Create a
Geodatabaseusing the mobile geodatabase file location. - Display the
GeodatabaseFeatureTablein feature layers. - If a transaction is required, begin one using
Geodatabase::beginTransaction(). - To check if a Geodatabase is in transaction use
Geodatabase::isInTransaction(). - Add one or more features to the feature table(s).
- When ready, either commit the transaction to the geodatabase with
Geodatabase::commitTransaction()or roll back the transaction withGeodatabase::rollbackTransaction().
Relevant API
- Geodatabase
- Geodatabase::beginTransaction
- Geodatabase::commitTransaction
- Geodatabase::isInTransaction
- Geodatabase::rollbackTransaction
- GeometryEditor
Offline data
This sample downloads the Save The Bay Geodatabase item from ArcGIS Online.
About the data
The mobile geodatabase contains a collection schema for wildlife sightings around Christmas Bay, TX, USA. It was created using data from the Save The Bay Feature Service.
Tags
commit, database, geodatabase, geometry editor, transact, transactions
Sample Code
// [WriteFile Name=EditGeodatabaseWithTransactions, Category=EditData]// [Legal]// Copyright 2025 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifdef PCH_BUILD#include "pch.hpp"#endif // PCH_BUILD
// sample headers#include "EditGeodatabaseWithTransactions.h"
// ArcGIS Maps SDK headers#include "ErrorException.h"#include "Feature.h"#include "FeatureLayer.h"#include "FeatureTemplate.h"#include "FeatureType.h"#include "Geodatabase.h"#include "GeodatabaseFeatureTable.h"#include "Geometry.h"#include "GeometryEngine.h"#include "Graphic.h"#include "GraphicListModel.h"#include "GraphicsOverlay.h"#include "GraphicsOverlayListModel.h"#include "LayerListModel.h"#include "Map.h"#include "MapQuickView.h"#include "MapTypes.h"#include "Point.h"#include "SimpleLineSymbol.h"#include "SpatialReference.h"#include "SymbolTypes.h"#include "Viewpoint.h"
// Qt headers#include <QException>#include <QFuture>#include <QFutureWatcher>#include <QStandardPaths>#include <QTimer>
using namespace Esri::ArcGISRuntime;
// helper method to get cross platform data pathnamespace{ QString defaultDataPath() {#ifdef Q_OS_IOS return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);#else return QStandardPaths::writableLocation(QStandardPaths::HomeLocation);#endif }} // namespace
EditGeodatabaseWithTransactions::EditGeodatabaseWithTransactions(QObject* parent /* = nullptr */) : QObject(parent), m_map(new Map(BasemapStyle::ArcGISTopographic, this)){ m_extent = Envelope(-95.3035, 29.0100, -95.1053, 29.1298, SpatialReference::wgs84()); m_map->setInitialViewpoint(Viewpoint(m_extent));
const QString dataPath = defaultDataPath() + "/ArcGIS/Runtime/Data/geodatabase/SaveTheBay.geodatabase";
m_geodatabase = new Geodatabase(dataPath, this); connect(m_geodatabase, &Geodatabase::doneLoading, this, &EditGeodatabaseWithTransactions::onGeodatabaseDoneLoading_);
m_geodatabase->load();}
EditGeodatabaseWithTransactions::~EditGeodatabaseWithTransactions() = default;
void EditGeodatabaseWithTransactions::init(){ // Register the map view for QML qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView"); qmlRegisterType<EditGeodatabaseWithTransactions>("Esri.Samples", 1, 0, "EditGeodatabaseWithTransactionsSample");}
MapQuickView* EditGeodatabaseWithTransactions::mapView() const{ return m_mapView;}
bool EditGeodatabaseWithTransactions::stopEditingEnabled() const{ return m_stopEditingEnabled;}
bool EditGeodatabaseWithTransactions::requireTransaction() const{ return m_requireTransaction;}
bool EditGeodatabaseWithTransactions::loadingVisible() const{ return m_loadingVisible;}
QStringList EditGeodatabaseWithTransactions::currentFeatureTypes() const{ return m_currentFeatureTypes;}
QStringList EditGeodatabaseWithTransactions::availableTableNames() const{ return m_availableTableNames;}
QString EditGeodatabaseWithTransactions::messageText() const{ return m_messageText;}
QString EditGeodatabaseWithTransactions::selectedTableName() const{ return m_selectedTableName;}
// Set the view (created in QML)void EditGeodatabaseWithTransactions::setMapView(MapQuickView* mapView){ if (!mapView || mapView == m_mapView) { return; }
m_mapView = mapView; m_mapView->setMap(m_map);
emit mapViewChanged();
connectSignals_();}
void EditGeodatabaseWithTransactions::connectSignals_(){ connect(m_mapView, &MapQuickView::mouseClicked, this, [this](QMouseEvent& mouseEvent) { if (!m_geodatabase) { return; }
// Only allow adding features if transaction conditions are met if (m_requireTransaction && !m_geodatabase->isInTransaction()) { setMessageText("Start a transaction first."); return; }
// Get screen coordinates and emit signal to show feature type dialog const double screenX = mouseEvent.position().x(); const double screenY = mouseEvent.position().y();
emit featureTypeSelectionRequested(screenX, screenY); });}
void EditGeodatabaseWithTransactions::onGeodatabaseDoneLoading_(const Error& error){ if (!error.isEmpty()) { setMessageText(error.message()); setLoadingVisible_(false); return; }
setLoadingVisible_(false); setMessageText("Using local geodatabase.");
m_allFeatureTables.clear(); m_tablesByName.clear(); m_availableTableNames.clear();
const int totalTablesToLoad = m_geodatabase->geodatabaseFeatureTables().size();
// Use a shared pointer to track the count across lambda captures auto tablesLoadedCount = std::make_shared<int>(0);
for (GeodatabaseFeatureTable* table : m_geodatabase->geodatabaseFeatureTables()) { connect(table, &GeodatabaseFeatureTable::doneLoading, this, [this, table, totalTablesToLoad, tablesLoadedCount](const Error& error) { if (!error.isEmpty()) { setMessageText(error.message()); return; }
// Store reference to the table with proper name mapping m_allFeatureTables.append(table);
// Set specific display names as per the Geodatabase QString displayName; if (table->tableName() == "Save_The_Bay_Marine_Sync") { table->setDisplayName("Marine"); displayName = "Marine"; } else if (table->tableName() == "Save_The_Bay_Birds_Sync") { table->setDisplayName("Bird"); displayName = "Bird"; } else { displayName = table->displayName().isEmpty() ? table->tableName() : table->displayName(); }
m_tablesByName[displayName] = table; m_availableTableNames.append(displayName);
// Create feature layer for the map if (m_mapView && m_mapView->map()) { FeatureLayer* layer = new FeatureLayer(table, this); layer->setMinScale(0); layer->setMaxScale(0); layer->setVisible(true); m_mapView->map()->operationalLayers()->append(layer); }
(*tablesLoadedCount)++;
// When all tables are loaded if (*tablesLoadedCount == totalTablesToLoad) { onAllTablesLoaded_(); } });
table->load(); }}
void EditGeodatabaseWithTransactions::onAllTablesLoaded_(){ // Initialize with first table as default selection if (!m_availableTableNames.isEmpty()) { m_selectedTableName = m_availableTableNames.first(); updateFeatureTypesForTable_(m_tablesByName[m_selectedTableName]); emit selectedTableNameChanged(); }
emit availableTableNamesChanged();
// Connect transaction status monitoring connect(m_geodatabase, &Geodatabase::transactionStatusChanged, this, &EditGeodatabaseWithTransactions::gdbTransactionStatusChanged_);
// Show the extent graphic drawExtent_();
// Set the map viewpoint to show the geodatabase extent if (m_mapView) { m_mapView->setViewpointAsync(Viewpoint(m_extent)); }
setMessageText("Tap Start to begin a transaction.");}
void EditGeodatabaseWithTransactions::gdbTransactionStatusChanged_(){ if (!m_geodatabase) { return; } // Update UI controls based on whether the geodatabase has a current transaction const bool isInTransaction = m_geodatabase->isInTransaction();
m_stopEditingEnabled = isInTransaction;
// Update status message based on current state if (isInTransaction) { setMessageText("Transaction started."); } else if (m_requireTransaction) { setMessageText("Tap Start to begin a transaction."); } else { setMessageText("Tap on the map to add a feature."); }
emit stopEditingEnabledChanged();}
void EditGeodatabaseWithTransactions::setRequireTransaction(bool require){ if (!m_geodatabase) { return; }
if (!require && m_geodatabase->isInTransaction()) { setMessageText("Stop editing to end the current transaction."); return; }
m_requireTransaction = require; emit requireTransactionChanged();
// Update status message based on requirement if (require) { setMessageText("Tap Start to begin a transaction."); } else { setMessageText("Tap on the map to add a feature."); }
// Update control states const bool isInTransaction = m_geodatabase->isInTransaction(); m_stopEditingEnabled = require && isInTransaction;
emit stopEditingEnabledChanged();}
void EditGeodatabaseWithTransactions::beginTransaction(){ if (!m_geodatabase) { return; }
// Begin transaction for the geodatabase if it's not in transaction if (!m_geodatabase->isInTransaction()) { m_geodatabase->beginTransaction(); }}
void EditGeodatabaseWithTransactions::stopTransaction(){ if (!m_geodatabase || !m_mapView) { return; }
// Ask the user if they want to commit or rollback the transaction emit commitDialogRequested();}
void EditGeodatabaseWithTransactions::commitTransaction(){ if (!m_geodatabase) { return; }
// Commit the transaction to store the edits (this will also end the transaction) m_geodatabase->commitTransaction(); setMessageText("Edits committed to geodatabase.");}
void EditGeodatabaseWithTransactions::rollbackTransaction(){ if (!m_geodatabase) { return; }
// Rollback the transaction to discard the edits (this will also end the transaction) m_geodatabase->rollbackTransaction(); setMessageText("Edits discarded.");}
void EditGeodatabaseWithTransactions::cancelTransactionCommit(){ // User canceled - indicate that the transaction is active setMessageText("Transaction started.");}
void EditGeodatabaseWithTransactions::updateFeatureTypesForTable_(GeodatabaseFeatureTable* table){ if (!table) { return; }
m_currentFeatureTypes.clear();
QStringList featureTypeNames; featureTypeNames.reserve(table->featureTypes().size());
for (const FeatureType& featureType : table->featureTypes()) { featureTypeNames.append(featureType.name()); }
featureTypeNames.sort(Qt::CaseInsensitive); m_currentFeatureTypes = featureTypeNames;
emit currentFeatureTypesChanged();}
void EditGeodatabaseWithTransactions::setSelectedTableName(const QString& tableName){ if (m_selectedTableName != tableName) { m_selectedTableName = tableName; emit selectedTableNameChanged();
// Update feature types for the newly selected table GeodatabaseFeatureTable* table = m_tablesByName.value(tableName, nullptr); if (table) { updateFeatureTypesForTable_(table); } }}
void EditGeodatabaseWithTransactions::addFeatureAtLocation(const QString& tableName, const QString& featureTypeName, const QPoint& location){ if (!m_mapView || !m_geodatabase) { return; }
GeodatabaseFeatureTable* targetTable = m_tablesByName.value(tableName, nullptr); if (!targetTable) { setMessageText(QString("Table '%1' not found.").arg(tableName)); return; }
// Find the feature type FeatureType selectedFeatureType; bool foundType = false; for (const FeatureType& featureType : targetTable->featureTypes()) { if (featureType.name() == featureTypeName) { selectedFeatureType = featureType; foundType = true; break; } }
if (!foundType) { setMessageText(QString("Feature type '%1' not found in table '%2'.").arg(featureTypeName, tableName)); return; }
// Convert screen point to map point const Point mapPoint = m_mapView->screenToLocation(location.x(), location.y()); if (mapPoint.isEmpty()) { setMessageText("Invalid location clicked."); return; }
// Convert point to WGS84 and check if point is in the extent (extent is in WGS84) const Geometry projectedGeometry = GeometryEngine::project(mapPoint, SpatialReference::wgs84()); if (GeometryEngine::contains(m_extent, projectedGeometry) == false) { setMessageText("Error: Feature geometry is outside the generate geodatabase geometry."); return; }
// Create feature using the selected type's template attributes QVariantMap attributes; if (!selectedFeatureType.templates().isEmpty()) { // Use the first template's attributes if available attributes = selectedFeatureType.templates().at(0).prototypeAttributes(); }
Feature* newFeature = targetTable->createFeature(attributes, mapPoint, this); if (!newFeature) { setMessageText("Failed to create new feature."); return; }
// Add the new feature to the table targetTable->addFeatureAsync(newFeature) .then(this, [this]() { setMessageText("Added feature."); }) .onFailed(this, [this](const ErrorException& exception) { QString errorMsg = QString("Error adding feature: %1").arg(exception.error().message()); setMessageText(errorMsg); }) .onCanceled(this, [this]() { setMessageText("Add feature operation was canceled."); });}
void EditGeodatabaseWithTransactions::updateFeatureTypesForSelectedTable(const QString& tableName){ GeodatabaseFeatureTable* table = m_tablesByName.value(tableName, nullptr); updateFeatureTypesForTable_(table);}
void EditGeodatabaseWithTransactions::setMessageText(const QString& message){ if (m_messageText != message) { m_messageText = message; emit messageTextChanged(); }}
void EditGeodatabaseWithTransactions::setLoadingVisible_(bool visible){ if (m_loadingVisible != visible) { m_loadingVisible = visible; emit loadingVisibleChanged(); }}
void EditGeodatabaseWithTransactions::drawExtent_(){ if (!m_mapView) { return; }
// Create a graphic for the geodatabase extent SimpleLineSymbol* lineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor(Qt::red), 2, this); Graphic* extentGraphic = new Graphic(m_extent, lineSymbol, this);
// Create a graphics overlay for the extent graphic GraphicsOverlay* extentOverlay = new GraphicsOverlay(this); extentOverlay->graphics()->append(extentGraphic);
// Add graphics overlay to the map view m_mapView->graphicsOverlays()->append(extentOverlay);}// [WriteFile Name=EditGeodatabaseWithTransactions, Category=EditData]// [Legal]// Copyright 2025 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifndef EDITGEODATABASETRANSACTIONS_H#define EDITGEODATABASETRANSACTIONS_H
// ArcGIS Maps SDK headers#include "Envelope.h"
// Qt headers#include <QList>#include <QMap>#include <QObject>
namespace Esri::ArcGISRuntime{ class Error; class Geodatabase; class GeodatabaseFeatureTable; class Map; class MapQuickView;} // namespace Esri::ArcGISRuntime
Q_MOC_INCLUDE("MapQuickView.h");
class EditGeodatabaseWithTransactions : public QObject{ Q_OBJECT
Q_PROPERTY(Esri::ArcGISRuntime::MapQuickView* mapView READ mapView WRITE setMapView NOTIFY mapViewChanged) Q_PROPERTY(bool stopEditingEnabled READ stopEditingEnabled NOTIFY stopEditingEnabledChanged) Q_PROPERTY(bool requireTransaction READ requireTransaction WRITE setRequireTransaction NOTIFY requireTransactionChanged) Q_PROPERTY(bool loadingVisible READ loadingVisible NOTIFY loadingVisibleChanged) Q_PROPERTY(QStringList currentFeatureTypes READ currentFeatureTypes NOTIFY currentFeatureTypesChanged) Q_PROPERTY(QStringList availableTableNames READ availableTableNames NOTIFY availableTableNamesChanged) Q_PROPERTY(QString messageText READ messageText NOTIFY messageTextChanged) Q_PROPERTY(QString selectedTableName READ selectedTableName WRITE setSelectedTableName NOTIFY selectedTableNameChanged)
public: explicit EditGeodatabaseWithTransactions(QObject* parent = nullptr); ~EditGeodatabaseWithTransactions() override;
static void init();
// Property getters bool stopEditingEnabled() const; bool requireTransaction() const; bool loadingVisible() const; QStringList currentFeatureTypes() const; QStringList availableTableNames() const; QString messageText() const; QString selectedTableName() const;
public slots: void beginTransaction(); void stopTransaction(); void commitTransaction(); void rollbackTransaction(); void cancelTransactionCommit(); void setRequireTransaction(bool require); void setSelectedTableName(const QString& tableName); void addFeatureAtLocation(const QString& tableName, const QString& featureTypeName, const QPoint& location); void updateFeatureTypesForSelectedTable(const QString& tableName);
signals: void mapViewChanged(); void stopEditingEnabledChanged(); void requireTransactionChanged(); void messageTextChanged(); void loadingVisibleChanged(); void availableTableNamesChanged(); void selectedTableNameChanged(); void currentFeatureTypesChanged(); void featureTypeSelectionRequested(int x, int y); void commitDialogRequested();
private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); void setMessageText(const QString& message);
void onGeodatabaseDoneLoading_(const Esri::ArcGISRuntime::Error& error); void gdbTransactionStatusChanged_(); void onAllTablesLoaded_(); void connectSignals_(); void setLoadingVisible_(bool visible); void updateFeatureTypesForTable_(Esri::ArcGISRuntime::GeodatabaseFeatureTable* table); void drawExtent_();
Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr;
Esri::ArcGISRuntime::Envelope m_extent; Esri::ArcGISRuntime::Geodatabase* m_geodatabase = nullptr;
// Store references to all available feature tables QList<Esri::ArcGISRuntime::GeodatabaseFeatureTable*> m_allFeatureTables; QMap<QString, Esri::ArcGISRuntime::GeodatabaseFeatureTable*> m_tablesByName;
// UI state properties bool m_loadingVisible = true; bool m_requireTransaction = true; bool m_stopEditingEnabled = false; QStringList m_availableTableNames; QStringList m_currentFeatureTypes; QString m_messageText; QString m_selectedTableName;};
#endif// [WriteFile Name=EditGeodatabaseWithTransactions, Category=EditData]// [Legal]// Copyright 2025 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
import QtQuickimport QtQuick.Controlsimport QtQuick.Layoutsimport Esri.Samples
Item {
// add a mapView component MapView { id: view anchors.fill: parent
Component.onCompleted: { // Set and keep the focus on MapView to enable keyboard navigation forceActiveFocus(); } }
// Status text overlay Rectangle { anchors { top: parent.top left: parent.left right: parent.right } height: statusText.implicitHeight + (parent.height * 0.02) opacity: 0.9 color: palette.base
MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: mouse => mouse.accepted = true onDoubleClicked: mouse => mouse.accepted = true onWheel: wheel => wheel.accepted = true }
Label { id: statusText anchors.centerIn: parent text: gdbModel.messageText font.pointSize: Math.max(10, parent.height * 0.025) wrapMode: Text.WordWrap width: parent.width - (parent.width * 0.05) horizontalAlignment: Label.AlignHCenter } }
// Loading progress bar ProgressBar { anchors { bottom: bottomToolbar.top left: parent.left right: parent.right leftMargin: parent.width * 0.05 rightMargin: parent.width * 0.05 bottomMargin: parent.height * 0.01 } visible: gdbModel.loadingVisible indeterminate: true }
// Bottom toolbar Rectangle { id: bottomToolbar anchors { bottom: parent.bottom left: parent.left right: parent.right } height: Math.max(parent.height * 0.08, 50) border.color: "gray" border.width: 1 color: palette.base
MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: mouse => mouse.accepted = true onDoubleClicked: mouse => mouse.accepted = true onWheel: wheel => wheel.accepted = true }
RowLayout { anchors { left: parent.left right: parent.right verticalCenter: parent.verticalCenter margins: 10 } spacing: 20
// Start/Stop Transaction button Button { text: gdbModel.stopEditingEnabled ? qsTr("End Transaction") : qsTr("Start Transaction") enabled: gdbModel.requireTransaction onClicked: { if (gdbModel.stopEditingEnabled) { gdbModel.stopTransaction(); } else { gdbModel.beginTransaction(); } } }
Item { Layout.fillWidth: true }
// Require Transaction toggle CheckBox { text: qsTr("Requires Transaction") checked: true enabled: !gdbModel.stopEditingEnabled onCheckedChanged: { gdbModel.requireTransaction = checked; } } } }
// Feature type selection dialog Dialog { id: featureTypeDialog title: qsTr("New Feature") anchors.centerIn: parent width: Math.min(500, parent.width * 0.9) height: Math.min(600, parent.height * 0.8)
property point tapLocation: Qt.point(0, 0)
ColumnLayout { anchors.fill: parent anchors.margins: 15 spacing: 12
Label { text: qsTr("Feature Table") font.bold: true }
ListView { id: tableSelectionList Layout.fillWidth: true Layout.preferredHeight: Math.min(contentHeight, 96) clip: true boundsBehavior: Flickable.StopAtBounds
model: gdbModel.availableTableNames
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
delegate: ItemDelegate { id: featureTableItem width: tableSelectionList.width implicitHeight: 32
Rectangle { anchors.fill: parent color: gdbModel.selectedTableName === modelData ? palette.highlight : "transparent" border.color: "gray" border.width: 1
Label { anchors.centerIn: parent text: modelData color: (gdbModel.selectedTableName === modelData || featureTableItem.hovered) ? "#F8F8F8" : palette.text } }
onClicked: { gdbModel.selectedTableName = modelData; } }
Connections { target: gdbModel function onSelectedTableNameChanged() { if (gdbModel.selectedTableName && tableSelectionList.model) { for (let i = 0; i < tableSelectionList.model.length; i++) { if (tableSelectionList.model[i] === gdbModel.selectedTableName) { tableSelectionList.currentIndex = i; break; } } } } } }
Label { text: qsTr("Feature Type") font.bold: true }
// Feature type list - populated from geodatabase ListView { id: featureTypeList Layout.fillWidth: true
Layout.fillHeight: true Layout.preferredHeight: 128
clip: true boundsBehavior: Flickable.StopAtBounds
property string selectedFeatureType: ""
model: gdbModel.currentFeatureTypes
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
delegate: ItemDelegate { id: featureTypeItem width: featureTypeList.width implicitHeight: 32
Rectangle { anchors.fill: parent color: featureTypeList.currentIndex === index ? palette.highlight : "transparent" border.color: "gray" border.width: 1
Label { anchors.centerIn: parent text: modelData color: (featureTypeList.currentIndex === index || featureTypeItem.hovered)? "#F8F8F8" : palette.text } }
onClicked: { featureTypeList.selectedFeatureType = modelData; featureTypeList.currentIndex = index; } }
onModelChanged: { if (model && model.length > 0) { currentIndex = 0; selectedFeatureType = model[0]; } }
Component.onCompleted: { if (model && model.length > 0) { currentIndex = 0; selectedFeatureType = model[0]; } } } }
footer: DialogButtonBox { Button { text: qsTr("Done") enabled: featureTypeList.selectedFeatureType !== "" DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole onClicked: { var tableName = gdbModel.selectedTableName; gdbModel.addFeatureAtLocation(tableName, featureTypeList.selectedFeatureType, featureTypeDialog.tapLocation); featureTypeDialog.accept(); } } Button { text: qsTr("Cancel") DialogButtonBox.buttonRole: DialogButtonBox.RejectRole onClicked: featureTypeDialog.reject(); } } }
Dialog { id: commitDialog title: qsTr("Commit Edits") anchors.centerIn: parent width: Math.min(400, parent.width * 0.9) modal: true
contentItem: Column { spacing: 10
Label { text: qsTr("Commit the edits in the transaction to the geodatabase or rollback to discard them.") width: parent.width - 40 wrapMode: Label.WordWrap } }
footer: DialogButtonBox { Button { text: qsTr("Commit") DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole onClicked: { commitDialog.close(); gdbModel.commitTransaction(); } }
Button { text: qsTr("Rollback") DialogButtonBox.buttonRole: DialogButtonBox.DestructiveRole onClicked: { commitDialog.close(); gdbModel.rollbackTransaction(); } }
Button { text: qsTr("Cancel") DialogButtonBox.buttonRole: DialogButtonBox.RejectRole onClicked: { commitDialog.close(); gdbModel.cancelTransactionCommit(); } } } }
// Declare the C++ instance which creates the map etc. and supply the view EditGeodatabaseWithTransactionsSample { id: gdbModel mapView: view
onCommitDialogRequested: { commitDialog.open(); }
onFeatureTypeSelectionRequested: function(x, y) { featureTypeDialog.tapLocation = Qt.point(x, y); if (gdbModel.selectedTableName){ gdbModel.updateFeatureTypesForSelectedTable(gdbModel.selectedTableName); }
featureTypeDialog.open(); } }}// [WriteFile Name=EditGeodatabaseWithTransactions, Category=EditData]// [Legal]// Copyright 2025 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
// sample headers#include "EditGeodatabaseWithTransactions.h"
// ArcGIS Maps SDK headers#include "ArcGISRuntimeEnvironment.h"
// Qt headers#include <QCommandLineParser>#include <QDir>#include <QGuiApplication>#include <QQmlApplicationEngine>
// Platform specific headers#ifdef Q_OS_WIN#include <Windows.h>#endif
int main(int argc, char* argv[]){ QGuiApplication app(argc, argv); app.setApplicationName(QString("EditGeodatabaseWithTransactions"));
// Use of ArcGIS location services, such as basemap styles, geocoding, and routing services, // requires an access token. For more information see // https://links.esri.com/arcgis-runtime-security-auth.
// The following methods grant an access token:
// 1. User authentication: Grants a temporary access token associated with a user's ArcGIS account. // To generate a token, a user logs in to the app with an ArcGIS account that is part of an // organization in ArcGIS Online or ArcGIS Enterprise.
// 2. API key authentication: Get a long-lived access token that gives your application access to // ArcGIS location services. Go to the tutorial at https://links.esri.com/create-an-api-key. // Copy the API Key access token.
const QString accessToken = QString("");
if (accessToken.isEmpty()) { qWarning() << "Use of ArcGIS location services, such as the basemap styles service, requires" << "you to authenticate with an ArcGIS account or set the API Key property."; } else { Esri::ArcGISRuntime::ArcGISRuntimeEnvironment::setApiKey(accessToken); }
// Initialize the sample EditGeodatabaseWithTransactions::init();
// Initialize application view QQmlApplicationEngine engine; // Add the import Path engine.addImportPath(QDir(QCoreApplication::applicationDirPath()).filePath("qml"));
#ifdef ARCGIS_RUNTIME_IMPORT_PATH_2 engine.addImportPath(ARCGIS_RUNTIME_IMPORT_PATH_2);#endif
// Set the source engine.load(QUrl("qrc:/Samples/EditData/EditGeodatabaseWithTransactions/main.qml"));
return app.exec();}// Copyright 2025 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.
import QtQuick.Controlsimport Esri.Samples
ApplicationWindow { visible: true width: 800 height: 600
EditGeodatabaseWithTransactions { anchors.fill: parent }}