diff --git a/resources/function_help/json/project_bookmark b/resources/function_help/json/project_bookmark new file mode 100644 index 000000000000..d8bfd6913b12 --- /dev/null +++ b/resources/function_help/json/project_bookmark @@ -0,0 +1,15 @@ +{ + "name": "project_bookmark", + "type": "function", + "groups": ["Bookmarks"], + "description": "Returns a project bookmark by name.", + "arguments": [{ + "arg": "name", + "description": "a project bookmark name" + }], + "examples": [{ + "expression": "project_bookmark('Home')", + "returns": "A map representing the 'Home' project bookmark." + }], + "tags": ["bookmarks", "project"] +} \ No newline at end of file diff --git a/resources/function_help/json/user_bookmark b/resources/function_help/json/user_bookmark new file mode 100644 index 000000000000..8b01ec6a2750 --- /dev/null +++ b/resources/function_help/json/user_bookmark @@ -0,0 +1,15 @@ +{ + "name": "user_bookmark", + "type": "function", + "groups": ["Bookmarks"], + "description": "Returns a user (profile) bookmark by name.", + "arguments": [{ + "arg": "name", + "description": "a user bookmark name" + }], + "examples": [{ + "expression": "user_bookmark('Home')", + "returns": "A map representing the 'Home' user bookmark." + }], + "tags": ["bookmarks", "user", "profile"] +} \ No newline at end of file diff --git a/src/core/expression/qgsexpressioncontextutils.cpp b/src/core/expression/qgsexpressioncontextutils.cpp index 48546fbcb35a..c8f547eceae6 100644 --- a/src/core/expression/qgsexpressioncontextutils.cpp +++ b/src/core/expression/qgsexpressioncontextutils.cpp @@ -1002,6 +1002,8 @@ void QgsExpressionContextUtils::registerContextFunctions() { QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) ); QgsExpression::registerFunction( new GetNamedProjectColorObject( nullptr ) ); + QgsExpression::registerFunction( new GetNamedProjectBookmark( nullptr ) ); + QgsExpression::registerFunction( new GetNamedUserBookmark() ); QgsExpression::registerFunction( new GetSensorData( ) ); QgsExpression::registerFunction( new GetLayoutItemVariables( nullptr ) ); QgsExpression::registerFunction( new GetLayoutMapLayerCredits( nullptr ) ); diff --git a/src/core/project/qgsproject.cpp b/src/core/project/qgsproject.cpp index c66602f11559..f2c4568de51c 100644 --- a/src/core/project/qgsproject.cpp +++ b/src/core/project/qgsproject.cpp @@ -2979,6 +2979,9 @@ QgsExpressionContextScope *QgsProject::createExpressionContextScope() const mProjectScope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( this ) ); mProjectScope->addFunction( QStringLiteral( "project_color_object" ), new GetNamedProjectColorObject( this ) ); + mProjectScope->addFunction( QStringLiteral( "project_bookmark" ), new GetNamedProjectBookmark( this ) ); + mProjectScope->addFunction( QStringLiteral( "user_bookmark" ), new GetNamedUserBookmark( ) ); + return createExpressionContextScope(); } @@ -5566,6 +5569,125 @@ QgsScopedExpressionFunction *GetNamedProjectColorObject::clone() const return new GetNamedProjectColorObject( mColors ); } +// Helper to build the hash +static QHash loadBookmarksFromProject( const QgsProject *project ) +{ + QHash bookmarks; + const QgsBookmarkManager *bookmarkManager = project->bookmarkManager(); + if ( !bookmarkManager ) + return bookmarks; + + const QList projectBookmarks = bookmarkManager->bookmarks(); + for ( const QgsBookmark &bm : projectBookmarks ) + { + QVariantMap bmMap; + bmMap["name"] = bm.name(); + bmMap["id"] = bm.id(); + bmMap["group"] = bm.group(); + + QVariantMap extentMap; + extentMap["x_min"] = bm.extent().xMinimum(); + extentMap["y_min"] = bm.extent().yMinimum(); + extentMap["x_max"] = bm.extent().xMaximum(); + extentMap["y_max"] = bm.extent().yMaximum(); + bmMap["extent_rect"] = extentMap; + + bmMap["width"] = bm.extent().width(); + bmMap["height"] = bm.extent().height(); + bmMap["crs"] = bm.extent().crs().authid(); + bmMap["rotation"] = bm.rotation(); + + QgsGeometry geomBounds = QgsGeometry::fromRect( bm.extent() ); + QVariant result = !geomBounds.isNull() ? QVariant::fromValue( geomBounds ) : QVariant(); + bmMap["extent"] = result; + + bookmarks[bm.name()] = bmMap; + } + return bookmarks; +} + +// Constructor +GetNamedProjectBookmark::GetNamedProjectBookmark( const QgsProject * ) + : QgsScopedExpressionFunction( QStringLiteral( "project_bookmark" ), 1, QStringLiteral( "Bookmarks" ) ) +{ +} + +QVariant GetNamedProjectBookmark::func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) +{ + if ( values.isEmpty() ) + return QVariant(); + + const QgsProject *project = QgsProject::instance(); + if ( !project ) + return QVariant(); + + const QHash bookmarks = loadBookmarksFromProject( project ); + const QString bookmarkName = values.at( 0 ).toString(); + const QVariantMap bmMap = bookmarks.value( bookmarkName ); + if ( bmMap.isEmpty() ) + return QVariant(); + return bmMap; +} + +QgsScopedExpressionFunction *GetNamedProjectBookmark::clone() const +{ + return new GetNamedProjectBookmark( nullptr ); +} + + +// Helper to build the hash for user bookmarks +static QHash loadUserBookmarks() +{ + QHash bookmarks; + const auto userBookmarks = QgsApplication::bookmarkManager()->bookmarks(); + for ( const QgsBookmark &b : userBookmarks ) + { + QVariantMap map; + map["id"] = b.id(); + map["name"] = b.name(); + map["group"] = b.group(); + + QVariantMap extentMap; + extentMap["x_min"] = b.extent().xMinimum(); + extentMap["y_min"] = b.extent().yMinimum(); + extentMap["x_max"] = b.extent().xMaximum(); + extentMap["y_max"] = b.extent().yMaximum(); + map["extent_rect"] = extentMap; + + map["width"] = b.extent().width(); + map["height"] = b.extent().height(); + map["crs"] = b.extent().crs().authid(); + map["rotation"] = b.rotation(); + + QgsGeometry geomBounds = QgsGeometry::fromRect( b.extent() ); + QVariant result = !geomBounds.isNull() ? QVariant::fromValue( geomBounds ) : QVariant(); + map["extent"] = result; + + bookmarks[b.name()] = map; + } + return bookmarks; +} + +GetNamedUserBookmark::GetNamedUserBookmark() + : QgsScopedExpressionFunction( QStringLiteral( "user_bookmark" ), 1, QStringLiteral( "Bookmarks" ) ) +{} + +QVariant GetNamedUserBookmark::func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) +{ + if ( values.isEmpty() ) + return QVariant(); + + const QString name = values.at( 0 ).toString(); + const auto bookmarks = loadUserBookmarks(); + return bookmarks.value( name ); +} + +QgsScopedExpressionFunction *GetNamedUserBookmark::clone() const +{ + return new GetNamedUserBookmark(); +} + + // ---------------- GetSensorData::GetSensorData( const QMap &sensorData ) diff --git a/src/core/project/qgsproject.h b/src/core/project/qgsproject.h index 207d9cb17d03..b8d078faf2cf 100644 --- a/src/core/project/qgsproject.h +++ b/src/core/project/qgsproject.h @@ -2740,6 +2740,29 @@ class GetNamedProjectColorObject : public QgsScopedExpressionFunction }; +class GetNamedProjectBookmark : public QgsScopedExpressionFunction +{ + public: + GetNamedProjectBookmark( const QgsProject *project ); + GetNamedProjectBookmark( const QHash &bookmarks ); + + QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override; + QgsScopedExpressionFunction *clone() const override; + + private: + QHash mBookmarks; +}; + +class GetNamedUserBookmark : public QgsScopedExpressionFunction +{ + public: + GetNamedUserBookmark(); + QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override; + QgsScopedExpressionFunction *clone() const override; +}; + + + class GetSensorData : public QgsScopedExpressionFunction {