Skip to content

Commit 29489e1

Browse files
authoredMay 9, 2018
Merge pull request #6865 from PeterPetrik/qgsquick_1_canvas_merge
[FEATURE] Introduction of QGIS Quick library
2 parents c1ac975 + b2188d4 commit 29489e1

37 files changed

+3295
-3
lines changed
 

‎.ci/travis/linux/docker-build-test.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ echo "${bold}Running cmake...${endbold}"
4040
cmake \
4141
-GNinja \
4242
-DUSE_CCACHE=OFF \
43+
-DWITH_QUICK=ON \
4344
-DWITH_3D=ON \
4445
-DWITH_STAGED_PLUGINS=ON \
4546
-DWITH_GRASS=OFF \

‎.docker/qgis3-build-deps.dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,17 @@ RUN apt-get update \
3333
libqca-qt5-2-dev \
3434
libqca-qt5-2-plugins \
3535
libqt53drender5 \
36+
libqt5concurrent5 \
3637
libqt5opengl5-dev \
38+
libqt5positioning5 \
39+
libqt5qml5 \
40+
libqt5quick5 \
41+
libqt5quickcontrols2-5 \
3742
libqt5scintilla2-dev \
3843
libqt5sql5-sqlite \
3944
libqt5svg5-dev \
4045
libqt5webkit5-dev \
46+
libqt5xml5 \
4147
libqt5xmlpatterns5-dev \
4248
libqwt-qt5-dev \
4349
libspatialindex-dev \
@@ -77,6 +83,8 @@ RUN apt-get update \
7783
qt3d-scene2d-plugin \
7884
qt5keychain-dev \
7985
qtbase5-dev \
86+
qtdeclarative5-dev-tools \
87+
qtdeclarative5-qtquick2-plugin \
8088
qtpositioning5-dev \
8189
qttools5-dev \
8290
qttools5-dev-tools \

‎.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ desktop.ini
3030
doc/INSTALL.tex
3131
i18n/*.qm
3232
Makefile
33+
*.pro.user
34+
*.stash
3335
ms-windows/*.exe*
3436
ms-windows/Installer-Files/postinstall.bat
3537
ms-windows/Installer-Files/preremove.bat

‎CMakeLists.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ IF(WITH_CORE)
7171

7272
SET (WITH_3D FALSE CACHE BOOL "Determines whether QGIS 3D library should be built")
7373

74+
SET (WITH_QUICK FALSE CACHE BOOL "Determines whether QGIS Quick library should be built")
75+
7476
# server disabled default because it needs FastCGI (which is optional dependency)
7577
SET (WITH_SERVER FALSE CACHE BOOL "Determines whether QGIS server should be built")
7678
IF(WITH_SERVER)
@@ -322,6 +324,18 @@ IF(WITH_CORE)
322324
ENDIF (WITH_3D)
323325
INCLUDE("cmake/modules/ECMQt4To5Porting.cmake")
324326
MESSAGE(STATUS "Found Qt version: ${Qt5Core_VERSION_STRING}")
327+
IF (WITH_QUICK)
328+
FIND_PACKAGE(Qt5Qml REQUIRED)
329+
FIND_PACKAGE(Qt5Quick REQUIRED)
330+
IF(${CMAKE_SYSTEM_NAME} MATCHES "Android")
331+
FIND_PACKAGE(Qt5AndroidExtras)
332+
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Android")
333+
FIND_PACKAGE(QtQmlTools REQUIRED)
334+
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Android")
335+
336+
# following variable is used in qgsconfig.h
337+
SET (HAVE_QUICK TRUE)
338+
ENDIF (WITH_QUICK)
325339

326340
IF(WITH_QTWEBKIT)
327341
SET(OPTIONAL_QTWEBKIT ${Qt5WebKitWidgets_LIBRARIES})
@@ -373,6 +387,9 @@ ENDIF(WITH_CORE)
373387
# build our version of astyle
374388
SET (WITH_ASTYLE FALSE CACHE BOOL "If you plan to contribute you should reindent with scripts/prepare-commit.sh (using 'our' astyle)")
375389

390+
# QML
391+
SET(QML_IMPORT_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" CACHE PATH "QML directory for QML autocomplete")
392+
376393
#############################################################
377394
# testing
378395
# whether unit tests should be build
@@ -513,6 +530,7 @@ IF (WITH_CORE)
513530
SET (DEFAULT_DATA_SUBDIR .)
514531
SET (DEFAULT_PLUGIN_SUBDIR plugins)
515532
SET (DEFAULT_INCLUDE_SUBDIR include)
533+
SET (DEFAULT_QML_SUBDIR qml)
516534

517535
SET (DEFAULT_SERVER_MODULE_SUBDIR server)
518536

@@ -583,6 +601,7 @@ IF (WITH_CORE)
583601
SET (DEFAULT_PLUGIN_SUBDIR ../PlugIns/qgis)
584602
SET (QGIS_PLUGIN_SUBDIR_REV ../../MacOS)
585603
SET (DEFAULT_INCLUDE_SUBDIR include/qgis)
604+
SET (DEFAULT_QML_SUBDIR qml)
586605

587606
# Set server moodules path to DEFAULT_LIBEXEC_SUBDIR+'/server'
588607
SET (DEFAULT_SERVER_MODULE_SUBDIR ${DEFAULT_LIBEXEC_SUBDIR}/server)
@@ -610,6 +629,7 @@ IF (WITH_CORE)
610629
SET (DEFAULT_LIBEXEC_SUBDIR lib${LIB_SUFFIX}/qgis)
611630
SET (DEFAULT_PLUGIN_SUBDIR lib${LIB_SUFFIX}/qgis/plugins)
612631
SET (DEFAULT_INCLUDE_SUBDIR include/qgis)
632+
SET (DEFAULT_QML_SUBDIR qml)
613633

614634
SET (DEFAULT_SERVER_MODULE_SUBDIR ${DEFAULT_LIBEXEC_SUBDIR}/server)
615635
ENDIF (APPLE)
@@ -658,6 +678,7 @@ SET (QGIS_LIBEXEC_SUBDIR ${DEFAULT_LIBEXEC_SUBDIR} CACHE STRING "Subdirectory wh
658678
SET (QGIS_DATA_SUBDIR ${DEFAULT_DATA_SUBDIR} CACHE STRING "Subdirectory where QGIS data will be installed")
659679
SET (QGIS_PLUGIN_SUBDIR ${DEFAULT_PLUGIN_SUBDIR} CACHE STRING "Subdirectory where plugins will be installed")
660680
SET (QGIS_INCLUDE_SUBDIR ${DEFAULT_INCLUDE_SUBDIR} CACHE STRING "Subdirectory where header files will be installed")
681+
SET (QGIS_QML_SUBDIR ${DEFAULT_QML_SUBDIR} CACHE STRING "Subdirectory where qml files/libraries will be installed")
661682

662683
SET (QGIS_SERVER_MODULE_SUBDIR ${DEFAULT_SERVER_MODULE_SUBDIR} CACHE STRING "Subdirectory where server modules will be installed")
663684

@@ -673,6 +694,7 @@ SET (QGIS_LIBEXEC_DIR ${QGIS_LIBEXEC_SUBDIR})
673694
SET (QGIS_DATA_DIR ${QGIS_DATA_SUBDIR})
674695
SET (QGIS_PLUGIN_DIR ${QGIS_PLUGIN_SUBDIR})
675696
SET (QGIS_INCLUDE_DIR ${QGIS_INCLUDE_SUBDIR})
697+
SET (QGIS_QML_DIR ${QGIS_QML_SUBDIR})
676698

677699
SET (QGIS_SERVER_MODULE_DIR ${QGIS_SERVER_MODULE_SUBDIR})
678700

‎cmake/FindQtQmlTools.cmake

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Qt QML Tools
2+
# ~~~~~~~~~~~~
3+
#
4+
# To generate qmltypes files required by Qt Creator to allow QML code inspection
5+
# (http://doc.qt.io/qtcreator/creator-qml-modules-with-plugins.html#generating-qmltypes-files)
6+
# we need to have installed qmlplugindump unity (shipped with Qt 4.8 and later)
7+
# http://doc.qt.io/qtcreator/creator-qml-modules-with-plugins.html#dumping-plugins-automatically
8+
#
9+
# Find the installed version of qmlplugindump utility.
10+
# FindQtQmlTools should be called after Qt5 has been found
11+
#
12+
# This file defines the following variables:
13+
#
14+
# QMLPLUGINDUMP_FOUND - system has qmlplugindump
15+
# QMLPLUGINDUMP_EXECUTABLE - Path to qmlplugindump executable
16+
#
17+
# Also defines MACRO to create qmltypes file, when QML directory is supplied
18+
#
19+
# Copyright (c) 2017, Peter Petrik <zilolv at gmail dot com>
20+
# Redistribution and use is allowed according to the terms of the BSD license.
21+
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
22+
23+
MACRO(FIND_QMLPLUGINDUMP)
24+
IF(NOT QMLPLUGINDUMP_EXECUTABLE)
25+
IF (MSVC)
26+
FIND_PROGRAM(QMLPLUGINDUMP_EXECUTABLE qmlplugindump.exe)
27+
ELSE (MSVC)
28+
FIND_PROGRAM(QMLPLUGINDUMP_EXECUTABLE qmlplugindump)
29+
ENDIF (MSVC)
30+
ENDIF(NOT QMLPLUGINDUMP_EXECUTABLE)
31+
32+
IF (QMLPLUGINDUMP_EXECUTABLE)
33+
SET(QMLPLUGINDUMP_FOUND TRUE)
34+
MESSAGE(STATUS "Found qmlplugindump: ${QMLPLUGINDUMP_EXECUTABLE}")
35+
ELSE()
36+
SET(QMLPLUGINDUMP_FOUND FALSE)
37+
IF (QMLPLUGINDUMP_FIND_REQUIRED)
38+
MESSAGE(FATAL_ERROR "Could not find qmlplugindump")
39+
ELSE (QMLPLUGINDUMP_FIND_REQUIRED)
40+
MESSAGE(WARNING "Could not find qmlplugindump")
41+
ENDIF (QMLPLUGINDUMP_FIND_REQUIRED)
42+
ENDIF (QMLPLUGINDUMP_EXECUTABLE)
43+
ENDMACRO(FIND_QMLPLUGINDUMP)
44+
45+
IF (NOT QMLPLUGINDUMP_FOUND)
46+
FIND_QMLPLUGINDUMP()
47+
ENDIF (NOT QMLPLUGINDUMP_FOUND)

‎cmake_templates/qgsconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#define QGIS_DATA_SUBDIR "${QGIS_DATA_SUBDIR}"
2626
#define QGIS_LIBEXEC_SUBDIR "${QGIS_LIBEXEC_SUBDIR}"
2727
#define QGIS_LIB_SUBDIR "${QGIS_LIB_SUBDIR}"
28+
#define QGIS_QML_SUBDIR "${QGIS_QML_SUBDIR}"
2829
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
2930
#define CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}"
3031

@@ -64,5 +65,7 @@
6465

6566
#cmakedefine QGISDEBUG
6667

68+
#cmakedefine HAVE_QUICK
69+
6770
#endif
6871

‎doc/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ IF(WITH_APIDOC)
100100
${CMAKE_SOURCE_DIR}/src/3d/symbols
101101
${CMAKE_SOURCE_DIR}/src/3d/terrain
102102
${CMAKE_SOURCE_DIR}/src/plugins
103+
${CMAKE_SOURCE_DIR}/src/quickgui
104+
${CMAKE_SOURCE_DIR}/src/quickgui/plugin
103105
)
104106

105107
IF(WITH_SERVER_PLUGINS)

‎doc/CONTRIBUTORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Nikos Alexandris
7171
Paolo Cavallini
7272
Paul Blottiere
7373
Paul Ramsey
74+
Peter Petrik
7475
Pierre Auckenthaler
7576
Raymond Nijssen
7677
Richard Duivenvoorde

‎doc/index.dox

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ website:
4545
<a href="https://qgis.org/api/1.7">1.7</a> and
4646
<a href="https://qgis.org/api/1.6">1.6</a>
4747

48+
\section qgsquick_docs QgsQuick library documentation
49+
50+
See \ref qgsquick for information about QGIS Quick (QML) components library
51+
4852
\section index_maillist Mailing Lists
4953

5054
For support we encourage you to join our <a

‎doc/modules.dox

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,8 @@ Contains classes related to implementation of QGIS plugins.
3737

3838
*/
3939

40+
/** @defgroup quick QgsQuick library
41+
42+
The QgsQuick library is built on top of the CORE library and Qt Quick/QML framework. It adds reusable GUI Quick Components, mainly for mobile devices.
43+
44+
*/

‎doc/qgsquick.dox

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*! \page qgsquick QGIS Quick Documentation
2+
3+
\tableofcontents
4+
5+
\section qgsquick_overview Overview
6+
7+
QGIS Quick is a QT Quick based GUI library primarily for mobile/tablet devices. Covering basic GIS components (e.g. MapCanvas, Scalebar),
8+
it simplifies creation of a mobile applications for surveys, data gathering or other on-site work. Qt Quick provides tools
9+
to create a rich application with a fluid and dynamic user interface. Additionally, Qt Quick Controls 2 provides highly
10+
optimized controls for embedded/mobile devices with limited resources.
11+
12+
QGIS Quick consists of a Qt plugin that provides the QML components and of a shared library that can be used from C++ code.
13+
14+
\subsection qgsquick_overview_widgets QML Classes
15+
\subsubsection qgsquick_overview_widgets_mapcanvas MapCanvas
16+
17+
\section qgsquick_styling Styling
18+
19+
Since the QGIS Quick library is meant to be reusable for a wide variety of applications with different styles/themes of the user
20+
interface, some effort has been done to allow developers customize the colors and layouts of the components. Individual
21+
components either have attributes for customization (e.g. ScaleBar has "barColor", "barBackgroundColor" properties) or more complex
22+
components accept a custom styling object (e.g. FeatureForm has "style" property of type FeatureFormStyling with a hierarchy of color
23+
and layout properties).
24+
25+
\section qgsquick_versioning_api Versioning and API stability
26+
27+
QML engine supports versioning of individual components with libraries - a single component may be available in multiple versions
28+
with slightly different set of features. This is allows QML libraries to keep API compatibility with older code.
29+
30+
QGIS Quick library is currently in version 0.1 and since it is still a very new library, there are no API stability guarantees:
31+
the following releases of QGIS may ship updates to components while keeping the same version or even remove some components.
32+
Over time we expect that as the library will become stable, we will deliver stable API just like with the other QGIS libraries.
33+
34+
\section qgsquick_gui Designing scalable applications
35+
36+
Qt Quick uses pixel sizes for the visual items. When building applications that may run on devices with varying screen DPI,
37+
this is a problem as the absolute pixel values make the application look different depending on the screen pixel density.
38+
We recommend to use values device independent pixels ("dp"). It is a concept used on mobile devices, where an item of width of 10dp
39+
will have always the same physical size (e.g. in millimeters) regardless of the screen density. To set width of an item to 10dp
40+
in QML, one would write: "width: 10 * QgsQuick.Utils.dp".
41+
42+
\section qgsquick_lib Building the library
43+
44+
The QGIS Quick library is not built by default because QGIS application currently does not use it. In order to build the library
45+
please make sure that WITH_QUICK variable in CMake configuration is set to ON.
46+
47+
It is recommended to build with CMake variable ENABLE_TESTS set to ON because that will also build a small example application
48+
that uses Qt Quick components. In the generated project you should see target "qgis_quickapp".
49+
50+
The built QML plugin is installed to a dedicated directory - see QgsApplication::qmlImportPath(). When using QGIS Quick components,
51+
it is necessary to either use QQmlEngine::addImportPath() to add that directory or to specify QML2_IMPORT_PATH environment variable.
52+
53+
\section qgsquick_demo_app Demo application
54+
55+
A demo application with some basic componets and functionality is available on https://github.com/lutraconsulting/qgis-quick-demo-app
56+
57+
The demo application repository contains also instructions on how to build the application, QGIS Quick and other dependencies on Android.
58+
59+
*/
60+
61+

‎python/core/qgsapplication.sip.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,14 @@ Returns the path containing qgis_core, qgis_gui, qgispython (and other) librarie
432432
static QString libexecPath();
433433
%Docstring
434434
Returns the path with utility executables (help viewer, crssync, ...)
435+
%End
436+
437+
static QString qmlImportPath();
438+
%Docstring
439+
Returns the path where QML components are installed for QGIS Quick library. Returns
440+
empty string when QGIS is built without Quick support
441+
442+
.. versionadded:: 3.2
435443
%End
436444

437445
static void setPrefixPath( const QString &prefixPath, bool useDefaultPaths = false );

‎src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ IF (WITH_CUSTOM_WIDGETS)
3535
ADD_SUBDIRECTORY(customwidgets)
3636
ENDIF (WITH_CUSTOM_WIDGETS)
3737

38+
IF (WITH_QUICK)
39+
ADD_SUBDIRECTORY(quickgui)
40+
ENDIF (WITH_QUICK)

‎src/core/qgsapplication.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ QString ABISYM( QgsApplication::mPluginPath );
9191
QString ABISYM( QgsApplication::mPkgDataPath );
9292
QString ABISYM( QgsApplication::mLibraryPath );
9393
QString ABISYM( QgsApplication::mLibexecPath );
94+
QString ABISYM( QgsApplication::mQmlImportPath );
9495
QString ABISYM( QgsApplication::mThemeName );
9596
QString ABISYM( QgsApplication::mUIThemeName );
9697
QString ABISYM( QgsApplication::mProfilePath );
@@ -205,6 +206,9 @@ void QgsApplication::init( QString profileFolder )
205206
ABISYM( mLibexecPath ) = ABISYM( mBuildOutputPath ) + '/' + QGIS_LIBEXEC_SUBDIR + '/' + ABISYM( mCfgIntDir ) + '/';
206207
#else
207208
ABISYM( mLibexecPath ) = ABISYM( mBuildOutputPath ) + '/' + QGIS_LIBEXEC_SUBDIR + '/';
209+
#endif
210+
#if defined( HAVE_QUICK )
211+
ABISYM( mQmlImportPath ) = ABISYM( mBuildOutputPath ) + '/' + QGIS_QML_SUBDIR + '/';
208212
#endif
209213
}
210214
else
@@ -397,6 +401,9 @@ void QgsApplication::setPrefixPath( const QString &prefixPath, bool useDefaultPa
397401
}
398402
ABISYM( mLibraryPath ) = ABISYM( mPrefixPath ) + '/' + QGIS_LIB_SUBDIR + '/';
399403
ABISYM( mLibexecPath ) = ABISYM( mPrefixPath ) + '/' + QGIS_LIBEXEC_SUBDIR + '/';
404+
#if defined( HAVE_QUICK )
405+
ABISYM( mQmlImportPath ) = ABISYM( mPrefixPath ) + '/' + QGIS_QML_SUBDIR + '/';
406+
#endif
400407
}
401408

402409
void QgsApplication::setPluginPath( const QString &pluginPath )
@@ -1002,6 +1009,11 @@ QString QgsApplication::libexecPath()
10021009
return ABISYM( mLibexecPath );
10031010
}
10041011

1012+
QString QgsApplication::qmlImportPath()
1013+
{
1014+
return ABISYM( mQmlImportPath );
1015+
}
1016+
10051017
QgsApplication::endian_t QgsApplication::endian()
10061018
{
10071019
return ( htonl( 1 ) == 1 ) ? XDR : NDR;

‎src/core/qgsapplication.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,14 @@ class CORE_EXPORT QgsApplication : public QApplication
406406
//! Returns the path with utility executables (help viewer, crssync, ...)
407407
static QString libexecPath();
408408

409+
/**
410+
* Returns the path where QML components are installed for QGIS Quick library. Returns
411+
* empty string when QGIS is built without Quick support
412+
*
413+
* \since QGIS 3.2
414+
*/
415+
static QString qmlImportPath();
416+
409417
//! Alters prefix path - used by 3rd party apps
410418
static void setPrefixPath( const QString &prefixPath, bool useDefaultPaths = false );
411419

@@ -759,6 +767,7 @@ class CORE_EXPORT QgsApplication : public QApplication
759767
static QString ABISYM( mPkgDataPath );
760768
static QString ABISYM( mLibraryPath );
761769
static QString ABISYM( mLibexecPath );
770+
static QString ABISYM( mQmlImportPath );
762771
static QString ABISYM( mThemeName );
763772
static QStringList ABISYM( mDefaultSvgPaths );
764773
static QMap<QString, QString> ABISYM( mSystemEnvVars );

‎src/core/qgsrelationmanager.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ QgsRelationManager::QgsRelationManager( QgsProject *project )
2525
: QObject( project )
2626
, mProject( project )
2727
{
28-
connect( project, &QgsProject::readProject, this, &QgsRelationManager::readProject );
29-
connect( project, &QgsProject::writeProject, this, &QgsRelationManager::writeProject );
30-
connect( project, &QgsProject::layersRemoved, this, &QgsRelationManager::layersRemoved );
28+
if ( mProject )
29+
{
30+
connect( project, &QgsProject::readProject, this, &QgsRelationManager::readProject );
31+
connect( project, &QgsProject::writeProject, this, &QgsRelationManager::writeProject );
32+
connect( project, &QgsProject::layersRemoved, this, &QgsRelationManager::layersRemoved );
33+
}
3134
}
3235

3336
void QgsRelationManager::setRelations( const QList<QgsRelation> &relations )

‎src/quickgui/CMakeLists.txt

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
############################################################
2+
# sources
3+
SET(QGIS_QUICK_GUI_MOC_HDRS
4+
qgsquickmapcanvasmap.h
5+
qgsquickmapsettings.h
6+
qgsquickutils.h
7+
)
8+
9+
SET(QGIS_QUICK_GUI_HDRS
10+
)
11+
12+
SET(QGIS_QUICK_GUI_SRC
13+
qgsquickmapcanvasmap.cpp
14+
qgsquickmapsettings.cpp
15+
qgsquickutils.cpp
16+
)
17+
18+
INCLUDE_DIRECTORIES(
19+
${CMAKE_CURRENT_SOURCE_DIR}
20+
${CMAKE_CURRENT_BINARY_DIR}
21+
22+
${CMAKE_SOURCE_DIR}/src/core
23+
${CMAKE_SOURCE_DIR}/src/core/annotations
24+
${CMAKE_SOURCE_DIR}/src/core/auth
25+
${CMAKE_SOURCE_DIR}/src/core/composer
26+
${CMAKE_SOURCE_DIR}/src/core/fieldformatter
27+
${CMAKE_SOURCE_DIR}/src/core/geometry
28+
${CMAKE_SOURCE_DIR}/src/core/layertree
29+
${CMAKE_SOURCE_DIR}/src/core/layout
30+
${CMAKE_SOURCE_DIR}/src/core/locator
31+
${CMAKE_SOURCE_DIR}/src/core/metadata
32+
${CMAKE_SOURCE_DIR}/src/core/providers/memory
33+
${CMAKE_SOURCE_DIR}/src/core/raster
34+
${CMAKE_SOURCE_DIR}/src/core/scalebar
35+
${CMAKE_SOURCE_DIR}/src/core/symbology
36+
${CMAKE_SOURCE_DIR}/src/core/effects
37+
${CMAKE_SOURCE_DIR}/src/core/metadata
38+
${CMAKE_SOURCE_DIR}/src/core/expression
39+
40+
${CMAKE_BINARY_DIR}/src/core
41+
)
42+
43+
INCLUDE_DIRECTORIES(SYSTEM
44+
${LIBZIP_INCLUDE_DIRS}
45+
${SPATIALINDEX_INCLUDE_DIR}
46+
${PROJ_INCLUDE_DIR}
47+
${GEOS_INCLUDE_DIR}
48+
${GDAL_INCLUDE_DIR}
49+
${EXPAT_INCLUDE_DIR}
50+
${SQLITE3_INCLUDE_DIR}
51+
${SPATIALITE_INCLUDE_DIR}
52+
${QCA_INCLUDE_DIR}
53+
${QTKEYCHAIN_INCLUDE_DIR}
54+
)
55+
56+
ADD_DEFINITIONS(-DCORE_EXPORT=)
57+
58+
############################################################
59+
# qgis_quick shared library
60+
QT5_WRAP_CPP(QGIS_QUICK_GUI_MOC_SRCS ${QGIS_QUICK_GUI_MOC_HDRS})
61+
IF(MSVC)
62+
SET_SOURCE_FILES_PROPERTIES(${QGIS_QUICK_GUI_MOC_SRCS} PROPERTIES COMPILE_FLAGS "/wd4512 /wd4996" )
63+
ELSE(MSVC)
64+
SET_SOURCE_FILES_PROPERTIES(${QGIS_QUICK_GUI_MOC_SRCS} PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations" )
65+
ENDIF(MSVC)
66+
67+
ADD_LIBRARY(qgis_quick SHARED
68+
${QGIS_QUICK_GUI_IMAGE_RCC_SRCS}
69+
${QGIS_QUICK_GUI_SRC}
70+
${QGIS_QUICK_GUI_MOC_HDRS}
71+
${QGIS_QUICK_GUI_MOC_SRCS}
72+
${QGIS_QUICK_GUI_HDRS})
73+
TARGET_LINK_LIBRARIES(qgis_quick Qt5::Quick Qt5::Qml Qt5::Xml Qt5::Concurrent Qt5::Positioning qgis_core)
74+
IF(CMAKE_SYSTEM_NAME STREQUAL "Android")
75+
TARGET_LINK_LIBRARIES(qgis_quick Qt5::AndroidExtras)
76+
ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Android")
77+
TARGET_COMPILE_DEFINITIONS(qgis_quick PRIVATE "-DQT_NO_FOREACH")
78+
79+
GENERATE_EXPORT_HEADER(
80+
qgis_quick
81+
BASE_NAME QUICK
82+
EXPORT_FILE_NAME qgis_quick.h
83+
)
84+
SET(QGIS_CORE_HDRS ${QGIS_QUICK_GUI_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/qgis_core.h)
85+
86+
# Installation
87+
INSTALL(TARGETS qgis_quick
88+
RUNTIME DESTINATION ${QGIS_BIN_DIR}
89+
LIBRARY DESTINATION ${QGIS_LIB_DIR}
90+
ARCHIVE DESTINATION ${QGIS_LIB_DIR}
91+
FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR}
92+
PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR})
93+
94+
IF(NOT APPLE)
95+
INSTALL(FILES ${QGIS_QUICK_GUI_HDRS} ${QGIS_QUICK_GUI_MOC_HDRS} DESTINATION ${QGIS_INCLUDE_DIR})
96+
ELSE(NOT APPLE)
97+
SET_TARGET_PROPERTIES(qgis_quick PROPERTIES
98+
CLEAN_DIRECT_OUTPUT 1
99+
FRAMEWORK 1
100+
FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}"
101+
MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in"
102+
MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION}
103+
MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis3_quick
104+
BUILD_WITH_INSTALL_RPATH TRUE
105+
PUBLIC_HEADER "${QGIS_QUICK_GUI_HDRS};${QGIS_QUICK_GUI_MOC_HDRS}"
106+
LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}"
107+
)
108+
# generated export header does not get copied with PUBLIC_HEADER files
109+
ADD_CUSTOM_COMMAND(TARGET qgis_quick
110+
POST_BUILD
111+
COMMAND ${CMAKE_COMMAND} -E copy qgis_quick.h
112+
"${QGIS_OUTPUT_DIRECTORY}/${QGIS_LIB_SUBDIR}/qgis_core.framework/Headers"
113+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
114+
DEPENDS qgis_quick.h
115+
)
116+
ENDIF(NOT APPLE)
117+
118+
############################################################
119+
# qgis_quick_plugin module (QML) library
120+
ADD_SUBDIRECTORY(plugin)
121+

‎src/quickgui/plugin/CMakeLists.txt

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
############################################################
2+
# sources
3+
4+
SET(QGIS_QUICK_PLUGIN_MOC_HDRS
5+
qgsquickplugin.h
6+
)
7+
8+
SET(QGIS_QUICK_PLUGIN_SRC
9+
qgsquickplugin.cpp
10+
)
11+
12+
SET(QGIS_QUICK_PLUGIN_RESOURCES
13+
qgsquickmapcanvas.qml
14+
qmldir
15+
)
16+
17+
18+
INCLUDE_DIRECTORIES(
19+
${CMAKE_CURRENT_SOURCE_DIR}
20+
${CMAKE_CURRENT_BINARY_DIR}
21+
22+
${CMAKE_SOURCE_DIR}/src/core
23+
${CMAKE_SOURCE_DIR}/src/core/annotations
24+
${CMAKE_SOURCE_DIR}/src/core/auth
25+
${CMAKE_SOURCE_DIR}/src/core/composer
26+
${CMAKE_SOURCE_DIR}/src/core/fieldformatter
27+
${CMAKE_SOURCE_DIR}/src/core/geometry
28+
${CMAKE_SOURCE_DIR}/src/core/layertree
29+
${CMAKE_SOURCE_DIR}/src/core/layout
30+
${CMAKE_SOURCE_DIR}/src/core/locator
31+
${CMAKE_SOURCE_DIR}/src/core/metadata
32+
${CMAKE_SOURCE_DIR}/src/core/providers/memory
33+
${CMAKE_SOURCE_DIR}/src/core/raster
34+
${CMAKE_SOURCE_DIR}/src/core/scalebar
35+
${CMAKE_SOURCE_DIR}/src/core/symbology
36+
${CMAKE_SOURCE_DIR}/src/core/effects
37+
${CMAKE_SOURCE_DIR}/src/core/metadata
38+
${CMAKE_SOURCE_DIR}/src/core/expression
39+
${CMAKE_SOURCE_DIR}/src/quickgui
40+
41+
${CMAKE_BINARY_DIR}/src/core
42+
${CMAKE_BINARY_DIR}/src/quickgui
43+
)
44+
45+
INCLUDE_DIRECTORIES(SYSTEM
46+
${LIBZIP_INCLUDE_DIRS}
47+
${SPATIALINDEX_INCLUDE_DIR}
48+
${PROJ_INCLUDE_DIR}
49+
${GEOS_INCLUDE_DIR}
50+
${GDAL_INCLUDE_DIR}
51+
${EXPAT_INCLUDE_DIR}
52+
${SQLITE3_INCLUDE_DIR}
53+
${SPATIALITE_INCLUDE_DIR}
54+
${QCA_INCLUDE_DIR}
55+
${QTKEYCHAIN_INCLUDE_DIR}
56+
)
57+
58+
ADD_DEFINITIONS(-DCORE_EXPORT=)
59+
60+
############################################################
61+
# qgis_quick_plugin module (QML) library
62+
63+
QT5_WRAP_CPP(QGIS_QUICK_PLUGIN_MOC_SRCS ${QGIS_QUICK_PLUGIN_MOC_HDRS})
64+
IF(MSVC)
65+
SET_SOURCE_FILES_PROPERTIES(${QGIS_QUICK_PLUGIN_MOC_SRCS} PROPERTIES COMPILE_FLAGS "/wd4512 /wd4996" )
66+
ELSE(MSVC)
67+
SET_SOURCE_FILES_PROPERTIES(${QGIS_QUICK_PLUGIN_MOC_SRCS} PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations" )
68+
ENDIF(MSVC)
69+
70+
SET(QGIS_QUICK_PLUGIN_RUNTIME_DIR ${QGIS_OUTPUT_DIRECTORY}/${QGIS_QML_SUBDIR}/QgsQuick)
71+
72+
ADD_LIBRARY(qgis_quick_plugin MODULE
73+
${QGIS_QUICK_PLUGIN_SRC}
74+
${QGIS_QUICK_PLUGIN_MOC_HDRS}
75+
${QGIS_QUICK_PLUGIN_MOC_SRCS}
76+
${QGIS_QUICK_PLUGIN_RESOURCES}
77+
)
78+
TARGET_LINK_LIBRARIES(qgis_quick_plugin qgis_quick)
79+
SET_TARGET_PROPERTIES(qgis_quick_plugin PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${QGIS_QUICK_PLUGIN_RUNTIME_DIR})
80+
TARGET_COMPILE_DEFINITIONS(qgis_quick_plugin PRIVATE "-DQUICK_EXPORT=" "-DQT_NO_FOREACH")
81+
82+
# Copy qml files to output directory, we need qml files in the same directory as the plugin shared library
83+
FOREACH(qmlfile ${QGIS_QUICK_PLUGIN_RESOURCES})
84+
ADD_CUSTOM_COMMAND(TARGET qgis_quick_plugin
85+
PRE_BUILD
86+
COMMAND ${CMAKE_COMMAND} -E copy ${qmlfile} ${QGIS_QUICK_PLUGIN_RUNTIME_DIR}
87+
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
88+
DEPENDS ${qmlfile}
89+
)
90+
ENDFOREACH(qmlfile)
91+
92+
IF(QMLPLUGINDUMP_FOUND)
93+
# To create typeinfo file, no qml files must be in the directory, otherwise
94+
# bunch of "QObject: Cannot create children for a parent that is in a different thread." errors
95+
# appear and typeinfo file is not generated
96+
SET(QGIS_QUICK_TYPEINFO_GENERATE_DIR ${CMAKE_CURRENT_BINARY_DIR}/QgsQuick)
97+
98+
# Extract QML Types Info from our QML plugin. This is useful for development with Qt Creator as it allows
99+
# Qt Creator understand also the C++ classes registered in the plugin and thus available in QML code
100+
SET(QGIS_QUICK_PLUGIN_TYPEINFO ${QGIS_QUICK_PLUGIN_RUNTIME_DIR}/qgsquick.qmltypes)
101+
ADD_CUSTOM_COMMAND(
102+
TARGET qgis_quick_plugin
103+
COMMAND ${CMAKE_COMMAND} -E make_directory ${QGIS_QUICK_TYPEINFO_GENERATE_DIR}
104+
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/qmldir ${QGIS_QUICK_TYPEINFO_GENERATE_DIR}
105+
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:qgis_quick_plugin> ${QGIS_QUICK_TYPEINFO_GENERATE_DIR}
106+
COMMAND ${QMLPLUGINDUMP_EXECUTABLE}
107+
ARGS QgsQuick 0.1 . -v --output ${QGIS_QUICK_PLUGIN_TYPEINFO}
108+
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
109+
POST_BUILD
110+
)
111+
ENDIF()
112+
113+
# Installation
114+
SET(QUICK_PLUGIN_INSTALL_DIR ${QGIS_QML_DIR}/QgsQuick)
115+
INSTALL(TARGETS qgis_quick_plugin
116+
RUNTIME DESTINATION ${QUICK_PLUGIN_INSTALL_DIR}
117+
LIBRARY DESTINATION ${QUICK_PLUGIN_INSTALL_DIR}
118+
)
119+
INSTALL(FILES ${QGIS_QUICK_PLUGIN_RESOURCES} ${QGIS_QUICK_PLUGIN_TYPEINFO}
120+
DESTINATION ${QUICK_PLUGIN_INSTALL_DIR}
121+
)
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/***************************************************************************
2+
qgsquickmapcanvas.qml
3+
--------------------------------------
4+
Date : 10.12.2014
5+
Copyright : (C) 2014 by Matthias Kuhn
6+
Email : matthias@opengis.ch
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
import QtQuick 2.3
16+
import QtQuick.Controls 2.2
17+
import QtQml 2.2
18+
import QgsQuick 0.1 as QgsQuick
19+
20+
Item {
21+
id: mapArea
22+
23+
/**
24+
* The mapSettings property contains configuration for rendering of the map.
25+
*
26+
* It should be used as a primary source of map settings (and project) for
27+
* all other components in the application.
28+
*
29+
* This is a readonly property.
30+
*
31+
* See also QgsQuickMapCanvasMap::mapSettings
32+
*/
33+
property alias mapSettings: mapCanvasWrapper.mapSettings
34+
35+
/**
36+
* The isRendering property is set to true while a rendering job is pending for this map canvas map.
37+
* It can be used to show a notification icon about an ongoing rendering job.
38+
*
39+
* This is a readonly property.
40+
*
41+
* See also QgsQuickMapCanvasMap::mapSettings
42+
*/
43+
property alias isRendering: mapCanvasWrapper.isRendering
44+
45+
/**
46+
* When the incrementalRendering property is set to true, the automatic refresh of map canvas during rendering is allowed.
47+
*/
48+
property alias incrementalRendering: mapCanvasWrapper.incrementalRendering
49+
50+
signal clicked(var mouse)
51+
52+
/**
53+
* Freezes the map canvas refreshes.
54+
*
55+
* In case of repeated geometry changes (animated resizes, pinch, pan...)
56+
* triggering refreshes all the time can cause severe performance impacts.
57+
*
58+
* If freeze is called, an internal counter is incremented and only when the
59+
* counter is 0, refreshes will happen.
60+
* It is therefore important to call freeze() and unfreeze() exactly the same
61+
* number of times.
62+
*/
63+
function freeze(id) {
64+
mapCanvasWrapper.__freezecount[id] = true
65+
mapCanvasWrapper.freeze = true
66+
}
67+
68+
function unfreeze(id) {
69+
delete mapCanvasWrapper.__freezecount[id]
70+
mapCanvasWrapper.freeze = Object.keys(
71+
mapCanvasWrapper.__freezecount).length !== 0
72+
}
73+
74+
QgsQuick.MapCanvasMap {
75+
id: mapCanvasWrapper
76+
77+
anchors.fill: parent
78+
79+
property var __freezecount: ({
80+
81+
})
82+
83+
freeze: false
84+
}
85+
86+
PinchArea {
87+
id: pinchArea
88+
89+
anchors.fill: parent
90+
91+
onPinchStarted: {
92+
freeze('pinch')
93+
}
94+
95+
onPinchUpdated: {
96+
mapCanvasWrapper.zoom(pinch.center, pinch.previousScale / pinch.scale)
97+
mapCanvasWrapper.pan(pinch.center, pinch.previousCenter)
98+
}
99+
100+
onPinchFinished: {
101+
unfreeze('pinch')
102+
mapCanvasWrapper.refresh()
103+
}
104+
105+
MouseArea {
106+
id: mouseArea
107+
108+
property point __initialPosition
109+
property point __lastPosition
110+
111+
anchors.fill: parent
112+
113+
onDoubleClicked: {
114+
var center = Qt.point(mouse.x, mouse.y)
115+
mapCanvasWrapper.zoom(center, 0.8)
116+
}
117+
118+
onClicked: {
119+
if (mouse.button === Qt.RightButton) {
120+
var center = Qt.point(mouse.x, mouse.y)
121+
mapCanvasWrapper.zoom(center, 1.2)
122+
} else {
123+
var distance = Math.abs(mouse.x - __initialPosition.x) + Math.abs(
124+
mouse.y - __initialPosition.y)
125+
126+
if (distance < 5 * QgsQuick.Utils.dp)
127+
mapArea.clicked(mouse)
128+
}
129+
}
130+
131+
onPressed: {
132+
__lastPosition = Qt.point(mouse.x, mouse.y)
133+
__initialPosition = __lastPosition
134+
freeze('pan')
135+
}
136+
137+
onReleased: {
138+
unfreeze('pan')
139+
}
140+
141+
onPositionChanged: {
142+
var currentPosition = Qt.point(mouse.x, mouse.y)
143+
mapCanvasWrapper.pan(currentPosition, __lastPosition)
144+
__lastPosition = currentPosition
145+
}
146+
147+
onCanceled: {
148+
unfreezePanTimer.start()
149+
}
150+
151+
onWheel: {
152+
mapCanvasWrapper.zoom(Qt.point(wheel.x, wheel.y),
153+
Math.pow(0.8, wheel.angleDelta.y / 60))
154+
}
155+
156+
Timer {
157+
id: unfreezePanTimer
158+
interval: 500
159+
running: false
160+
repeat: false
161+
onTriggered: unfreeze('pan')
162+
}
163+
}
164+
}
165+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/***************************************************************************
2+
qgsquickplugin.cpp
3+
--------------------------------------
4+
Date : Nov 2017
5+
Copyright : (C) 2017 by Peter Petrik
6+
Email : zilolv at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include <qqml.h>
17+
18+
#include <QObject>
19+
#include <QQmlEngine>
20+
#include <QJSEngine>
21+
22+
#include "qgsfeature.h"
23+
#include "qgslogger.h"
24+
#include "qgsmaplayer.h"
25+
#include "qgsmessagelog.h"
26+
#include "qgspointxy.h"
27+
#include "qgsproject.h"
28+
#include "qgsrelationmanager.h"
29+
#include "qgscoordinatetransformcontext.h"
30+
#include "qgsvectorlayer.h"
31+
32+
#include "qgsquickmapcanvasmap.h"
33+
#include "qgsquickmapsettings.h"
34+
#include "qgsquickplugin.h"
35+
#include "qgsquickutils.h"
36+
37+
static QObject *_utilsProvider( QQmlEngine *engine, QJSEngine *scriptEngine )
38+
{
39+
Q_UNUSED( engine )
40+
Q_UNUSED( scriptEngine )
41+
return new QgsQuickUtils(); // the object will be owned by QML engine and destroyed by the engine on exit
42+
}
43+
44+
void QgsQuickPlugin::registerTypes( const char *uri )
45+
{
46+
qRegisterMetaType< QList<QgsMapLayer *> >( "QList<QgsMapLayer*>" );
47+
qRegisterMetaType< QgsAttributes > ( "QgsAttributes" );
48+
qRegisterMetaType< QgsCoordinateReferenceSystem >( "QgsCoordinateReferenceSystem" );
49+
qRegisterMetaType< QgsCoordinateTransformContext >( "QgsCoordinateTransformContext" );
50+
qRegisterMetaType< QgsFeature > ( "QgsFeature" );
51+
qRegisterMetaType< QgsFeatureId > ( "QgsFeatureId" );
52+
qRegisterMetaType< QgsPoint >( "QgsPoint" );
53+
qRegisterMetaType< QgsPointXY >( "QgsPointXY" );
54+
55+
qmlRegisterType< QgsProject >( uri, 0, 1, "Project" );
56+
qmlRegisterType< QgsQuickMapCanvasMap >( uri, 0, 1, "MapCanvasMap" );
57+
qmlRegisterType< QgsQuickMapSettings >( uri, 0, 1, "MapSettings" );
58+
qmlRegisterType< QgsVectorLayer >( uri, 0, 1, "VectorLayer" );
59+
60+
qmlRegisterSingletonType< QgsQuickUtils >( uri, 0, 1, "Utils", _utilsProvider );
61+
62+
qmlRegisterUncreatableType< QgsRelationManager >( uri, 0, 1, "RelationManager", "The relation manager is available from the Project. Try `qgisProject.relationManager`" );
63+
qmlRegisterUncreatableType< QgsMessageLog >( uri, 0, 1, "QgsMessageLog", "Expose MessageLevel" );
64+
}
65+

‎src/quickgui/plugin/qgsquickplugin.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/***************************************************************************
2+
qgsquickplugin.h
3+
--------------------------------------
4+
Date : Nov 2017
5+
Copyright : (C) 2017 by Peter Petrik
6+
Email : zilolv at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSQUICKPLUGIN_H
17+
#define QGSQUICKPLUGIN_H
18+
19+
#include <QQmlExtensionPlugin>
20+
21+
/**
22+
* \ingroup quick
23+
*
24+
* Qgis Qml Extension Plugin responsible for exposing C++ Qgis classes to QML
25+
*
26+
* \since QGIS 3.2
27+
*/
28+
class QgsQuickPlugin : public QQmlExtensionPlugin
29+
{
30+
Q_OBJECT
31+
Q_PLUGIN_METADATA( IID "org.qt-project.Qt.QQmlExtensionInterface" )
32+
public:
33+
34+
/**
35+
* Registers the QGIS QML types in the given uri
36+
* \param uri an identifier for the plugin generated by the QML engine
37+
*/
38+
void registerTypes( const char *uri );
39+
};
40+
41+
#endif // QGSQUICKPLUGIN_H
42+

‎src/quickgui/plugin/qmldir

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# qmldir
2+
# --------------------------------------
3+
# Date : Nov 2017
4+
# Copyright : (C) 2017 by Peter Petrik
5+
# Email : zilolv at gmail dot com
6+
# *************************************************************************** *
7+
# This program is free software; you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation; either version 2 of the License, or
10+
# (at your option) any later version.
11+
12+
13+
module QgsQuick
14+
plugin qgis_quick_plugin
15+
16+
MapCanvas 0.1 qgsquickmapcanvas.qml
17+
18+
typeinfo qgsquick.qmltypes

‎src/quickgui/qgsquickmapcanvasmap.cpp

Lines changed: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
/***************************************************************************
2+
qgsquickmapcanvasmap.cpp
3+
--------------------------------------
4+
Date : 10.12.2014
5+
Copyright : (C) 2014 by Matthias Kuhn
6+
Email : matthias (at) opengis.ch
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include <QQuickWindow>
17+
#include <QScreen>
18+
#include <QSGSimpleTextureNode>
19+
#include <QtConcurrent>
20+
21+
#include "qgsmaprendererparalleljob.h"
22+
#include "qgsmessagelog.h"
23+
#include "qgspallabeling.h"
24+
#include "qgsproject.h"
25+
#include "qgsvectorlayer.h"
26+
#include "qgis.h"
27+
28+
#include "qgsquickmapcanvasmap.h"
29+
#include "qgsquickmapsettings.h"
30+
31+
32+
QgsQuickMapCanvasMap::QgsQuickMapCanvasMap( QQuickItem *parent )
33+
: QQuickItem( parent )
34+
, mMapSettings( new QgsQuickMapSettings() )
35+
{
36+
connect( this, &QQuickItem::windowChanged, this, &QgsQuickMapCanvasMap::onWindowChanged );
37+
connect( &mRefreshTimer, &QTimer::timeout, this, &QgsQuickMapCanvasMap::refreshMap );
38+
connect( &mMapUpdateTimer, &QTimer::timeout, this, &QgsQuickMapCanvasMap::renderJobUpdated );
39+
40+
connect( mMapSettings.get(), &QgsQuickMapSettings::extentChanged, this, &QgsQuickMapCanvasMap::onExtentChanged );
41+
connect( mMapSettings.get(), &QgsQuickMapSettings::layersChanged, this, &QgsQuickMapCanvasMap::onLayersChanged );
42+
43+
connect( this, &QgsQuickMapCanvasMap::renderStarting, this, &QgsQuickMapCanvasMap::isRenderingChanged );
44+
connect( this, &QgsQuickMapCanvasMap::mapCanvasRefreshed, this, &QgsQuickMapCanvasMap::isRenderingChanged );
45+
46+
mMapUpdateTimer.setSingleShot( false );
47+
mMapUpdateTimer.setInterval( 250 );
48+
mRefreshTimer.setSingleShot( true );
49+
setTransformOrigin( QQuickItem::TopLeft );
50+
setFlags( QQuickItem::ItemHasContents );
51+
}
52+
53+
QgsQuickMapSettings *QgsQuickMapCanvasMap::mapSettings() const
54+
{
55+
return mMapSettings.get();
56+
}
57+
58+
void QgsQuickMapCanvasMap::zoom( QPointF center, qreal scale )
59+
{
60+
QgsRectangle extent = mMapSettings->extent();
61+
QgsPoint oldCenter( extent.center() );
62+
QgsPoint mousePos( mMapSettings->screenToCoordinate( center ) );
63+
QgsPointXY newCenter( mousePos.x() + ( ( oldCenter.x() - mousePos.x() ) * scale ),
64+
mousePos.y() + ( ( oldCenter.y() - mousePos.y() ) * scale ) );
65+
66+
// same as zoomWithCenter (no coordinate transformations are needed)
67+
extent.scale( scale, &newCenter );
68+
mMapSettings->setExtent( extent );
69+
}
70+
71+
void QgsQuickMapCanvasMap::pan( QPointF oldPos, QPointF newPos )
72+
{
73+
QgsPoint start = mMapSettings->screenToCoordinate( oldPos.toPoint() );
74+
QgsPoint end = mMapSettings->screenToCoordinate( newPos.toPoint() );
75+
76+
double dx = end.x() - start.x();
77+
double dy = end.y() - start.y();
78+
79+
// modify the extent
80+
QgsRectangle extent = mMapSettings->extent();
81+
82+
extent.setXMinimum( extent.xMinimum() + dx );
83+
extent.setXMaximum( extent.xMaximum() + dx );
84+
extent.setYMaximum( extent.yMaximum() + dy );
85+
extent.setYMinimum( extent.yMinimum() + dy );
86+
87+
mMapSettings->setExtent( extent );
88+
}
89+
90+
void QgsQuickMapCanvasMap::refreshMap()
91+
{
92+
stopRendering(); // if any...
93+
94+
QgsMapSettings mapSettings = mMapSettings->mapSettings();
95+
96+
//build the expression context
97+
QgsExpressionContext expressionContext;
98+
expressionContext << QgsExpressionContextUtils::globalScope()
99+
<< QgsExpressionContextUtils::mapSettingsScope( mapSettings );
100+
101+
QgsProject *project = mMapSettings->project();
102+
if ( project )
103+
{
104+
expressionContext << QgsExpressionContextUtils::projectScope( project );
105+
}
106+
107+
mapSettings.setExpressionContext( expressionContext );
108+
109+
// create the renderer job
110+
Q_ASSERT( !mJob );
111+
mJob = new QgsMapRendererParallelJob( mapSettings );
112+
113+
if ( mIncrementalRendering )
114+
mMapUpdateTimer.start();
115+
116+
connect( mJob, &QgsMapRendererJob::renderingLayersFinished, this, &QgsQuickMapCanvasMap::renderJobUpdated );
117+
connect( mJob, &QgsMapRendererJob::finished, this, &QgsQuickMapCanvasMap::renderJobFinished );
118+
mJob->setCache( mCache );
119+
120+
mJob->start();
121+
122+
emit renderStarting();
123+
}
124+
125+
void QgsQuickMapCanvasMap::renderJobUpdated()
126+
{
127+
mImage = mJob->renderedImage();
128+
mImageMapSettings = mJob->mapSettings();
129+
mDirty = true;
130+
// Temporarily freeze the canvas, we only need to reset the geometry but not trigger a repaint
131+
bool freeze = mFreeze;
132+
mFreeze = true;
133+
updateTransform();
134+
mFreeze = freeze;
135+
136+
update();
137+
emit mapCanvasRefreshed();
138+
}
139+
140+
void QgsQuickMapCanvasMap::renderJobFinished()
141+
{
142+
const QgsMapRendererJob::Errors errors = mJob->errors();
143+
for ( const QgsMapRendererJob::Error &error : errors )
144+
{
145+
QgsMessageLog::logMessage( QStringLiteral( "%1 :: %2" ).arg( error.layerID, error.message ), tr( "Rendering" ) );
146+
}
147+
148+
// take labeling results before emitting renderComplete, so labeling map tools
149+
// connected to signal work with correct results
150+
delete mLabelingResults;
151+
mLabelingResults = mJob->takeLabelingResults();
152+
153+
mImage = mJob->renderedImage();
154+
mImageMapSettings = mJob->mapSettings();
155+
156+
// now we are in a slot called from mJob - do not delete it immediately
157+
// so the class is still valid when the execution returns to the class
158+
mJob->deleteLater();
159+
mJob = nullptr;
160+
mDirty = true;
161+
mMapUpdateTimer.stop();
162+
163+
// Temporarily freeze the canvas, we only need to reset the geometry but not trigger a repaint
164+
bool freeze = mFreeze;
165+
mFreeze = true;
166+
updateTransform();
167+
mFreeze = freeze;
168+
169+
update();
170+
emit mapCanvasRefreshed();
171+
}
172+
173+
void QgsQuickMapCanvasMap::onWindowChanged( QQuickWindow *window )
174+
{
175+
disconnect( window, &QQuickWindow::screenChanged, this, &QgsQuickMapCanvasMap::onScreenChanged );
176+
if ( window )
177+
{
178+
connect( window, &QQuickWindow::screenChanged, this, &QgsQuickMapCanvasMap::onScreenChanged );
179+
onScreenChanged( window->screen() );
180+
}
181+
}
182+
183+
void QgsQuickMapCanvasMap::onScreenChanged( QScreen *screen )
184+
{
185+
if ( screen )
186+
mMapSettings->setOutputDpi( screen->physicalDotsPerInch() );
187+
}
188+
189+
void QgsQuickMapCanvasMap::onExtentChanged()
190+
{
191+
updateTransform();
192+
193+
// And trigger a new rendering job
194+
refresh();
195+
}
196+
197+
void QgsQuickMapCanvasMap::updateTransform()
198+
{
199+
QgsMapSettings currentMapSettings = mMapSettings->mapSettings();
200+
QgsMapToPixel mtp = currentMapSettings.mapToPixel();
201+
202+
QgsRectangle imageExtent = mImageMapSettings.visibleExtent();
203+
QgsRectangle newExtent = currentMapSettings.visibleExtent();
204+
QgsPointXY pixelPt = mtp.transform( imageExtent.xMinimum(), imageExtent.yMaximum() );
205+
setScale( imageExtent.width() / newExtent.width() );
206+
207+
setX( pixelPt.x() );
208+
setY( pixelPt.y() );
209+
}
210+
211+
int QgsQuickMapCanvasMap::mapUpdateInterval() const
212+
{
213+
return mMapUpdateTimer.interval();
214+
}
215+
216+
void QgsQuickMapCanvasMap::setMapUpdateInterval( int mapUpdateInterval )
217+
{
218+
if ( mMapUpdateTimer.interval() == mapUpdateInterval )
219+
return;
220+
221+
mMapUpdateTimer.setInterval( mapUpdateInterval );
222+
223+
emit mapUpdateIntervalChanged();
224+
}
225+
226+
bool QgsQuickMapCanvasMap::incrementalRendering() const
227+
{
228+
return mIncrementalRendering;
229+
}
230+
231+
void QgsQuickMapCanvasMap::setIncrementalRendering( bool incrementalRendering )
232+
{
233+
if ( incrementalRendering == mIncrementalRendering )
234+
return;
235+
236+
mIncrementalRendering = incrementalRendering;
237+
emit incrementalRenderingChanged();
238+
}
239+
240+
bool QgsQuickMapCanvasMap::freeze() const
241+
{
242+
return mFreeze;
243+
}
244+
245+
void QgsQuickMapCanvasMap::setFreeze( bool freeze )
246+
{
247+
if ( freeze == mFreeze )
248+
return;
249+
250+
mFreeze = freeze;
251+
252+
if ( !mFreeze )
253+
refresh();
254+
255+
emit freezeChanged();
256+
}
257+
258+
bool QgsQuickMapCanvasMap::isRendering() const
259+
{
260+
return mJob;
261+
}
262+
263+
QSGNode *QgsQuickMapCanvasMap::updatePaintNode( QSGNode *oldNode, QQuickItem::UpdatePaintNodeData * )
264+
{
265+
if ( mDirty )
266+
{
267+
delete oldNode;
268+
oldNode = nullptr;
269+
mDirty = false;
270+
}
271+
272+
QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>( oldNode );
273+
if ( !node )
274+
{
275+
node = new QSGSimpleTextureNode();
276+
QSGTexture *texture = window()->createTextureFromImage( mImage );
277+
node->setTexture( texture );
278+
node->setOwnsTexture( true );
279+
}
280+
281+
QRectF rect( boundingRect() );
282+
283+
// Check for resizes that change the w/h ratio
284+
if ( !rect.isEmpty() &&
285+
!mImage.size().isEmpty() &&
286+
!qgsDoubleNear( rect.width() / rect.height(), mImage.width() / mImage.height() ) )
287+
{
288+
if ( qgsDoubleNear( rect.height(), mImage.height() ) )
289+
{
290+
rect.setHeight( rect.width() / mImage.width() * mImage.height() );
291+
}
292+
else
293+
{
294+
rect.setWidth( rect.height() / mImage.height() * mImage.width() );
295+
}
296+
}
297+
298+
node->setRect( rect );
299+
300+
return node;
301+
}
302+
303+
void QgsQuickMapCanvasMap::geometryChanged( const QRectF &newGeometry, const QRectF &oldGeometry )
304+
{
305+
Q_UNUSED( oldGeometry )
306+
// The Qt documentation advices to call the base method here.
307+
// However, this introduces instabilities and heavy performance impacts on Android.
308+
// It seems on desktop disabling it prevents us from downsizing the window...
309+
// Be careful when re-enabling it.
310+
// QQuickItem::geometryChanged( newGeometry, oldGeometry );
311+
312+
mMapSettings->setOutputSize( newGeometry.size().toSize() );
313+
refresh();
314+
}
315+
316+
void QgsQuickMapCanvasMap::onLayersChanged()
317+
{
318+
if ( mMapSettings->extent().isEmpty() )
319+
zoomToFullExtent();
320+
321+
for ( const QMetaObject::Connection &conn : qgis::as_const( mLayerConnections ) )
322+
{
323+
disconnect( conn );
324+
}
325+
mLayerConnections.clear();
326+
327+
const QList<QgsMapLayer *> layers = mMapSettings->layers();
328+
for ( QgsMapLayer *layer : layers )
329+
{
330+
mLayerConnections << connect( layer, &QgsMapLayer::repaintRequested, this, &QgsQuickMapCanvasMap::refresh );
331+
}
332+
333+
refresh();
334+
}
335+
336+
void QgsQuickMapCanvasMap::destroyJob( QgsMapRendererJob *job )
337+
{
338+
job->cancel();
339+
job->deleteLater();
340+
}
341+
342+
void QgsQuickMapCanvasMap::stopRendering()
343+
{
344+
if ( mJob )
345+
{
346+
disconnect( mJob, &QgsMapRendererJob::renderingLayersFinished, this, &QgsQuickMapCanvasMap::renderJobUpdated );
347+
disconnect( mJob, &QgsMapRendererJob::finished, this, &QgsQuickMapCanvasMap::renderJobFinished );
348+
349+
mJob->cancelWithoutBlocking();
350+
mJob = nullptr;
351+
}
352+
}
353+
354+
void QgsQuickMapCanvasMap::zoomToFullExtent()
355+
{
356+
QgsRectangle extent;
357+
const QList<QgsMapLayer *> layers = mMapSettings->layers();
358+
for ( QgsMapLayer *layer : layers )
359+
{
360+
if ( mMapSettings->destinationCrs() != layer->crs() )
361+
{
362+
QgsCoordinateTransform transform( layer->crs(), mMapSettings->destinationCrs(), mMapSettings->transformContext() );
363+
extent.combineExtentWith( transform.transformBoundingBox( layer->extent() ) );
364+
}
365+
else
366+
{
367+
extent.combineExtentWith( layer->extent() );
368+
}
369+
}
370+
mMapSettings->setExtent( extent );
371+
372+
refresh();
373+
}
374+
375+
void QgsQuickMapCanvasMap::refresh()
376+
{
377+
if ( mMapSettings->outputSize().isNull() )
378+
return; // the map image size has not been set yet
379+
380+
if ( !mFreeze )
381+
mRefreshTimer.start( 1 );
382+
}

‎src/quickgui/qgsquickmapcanvasmap.h

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/***************************************************************************
2+
qgsquickmapcanvasmap.h
3+
--------------------------------------
4+
Date : 10.12.2014
5+
Copyright : (C) 2014 by Matthias Kuhn
6+
Email : matthias (at) opengis.ch
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSQUICKMAPCANVASMAP_H
17+
#define QGSQUICKMAPCANVASMAP_H
18+
19+
#include <memory>
20+
21+
#include <QtQuick/QQuickItem>
22+
#include <QFutureSynchronizer>
23+
#include <QTimer>
24+
25+
#include "qgsmapsettings.h"
26+
#include "qgspoint.h"
27+
28+
#include "qgis_quick.h"
29+
#include "qgsquickmapsettings.h"
30+
31+
class QgsMapRendererParallelJob;
32+
class QgsMapRendererCache;
33+
class QgsLabelingResults;
34+
35+
/**
36+
* \ingroup quick
37+
* This class implements a visual Qt Quick Item that does map rendering
38+
* according to the current map settings. Client code is expected to use
39+
* MapCanvas item rather than using this class directly.
40+
*
41+
* QgsQuickMapCanvasMap instance internally creates QgsQuickMapSettings in
42+
* constructor. The QgsProject should be attached to the QgsQuickMapSettings.
43+
* The map settings for other QgsQuick components should be initialized from
44+
* QgsQuickMapCanvasMap's mapSettings
45+
*
46+
* \note QML Type: MapCanvasMap
47+
*
48+
* \sa QgsQuickMapCanvas
49+
*
50+
* \since QGIS 3.2
51+
*/
52+
class QUICK_EXPORT QgsQuickMapCanvasMap : public QQuickItem
53+
{
54+
Q_OBJECT
55+
56+
/**
57+
* The mapSettings property contains configuration for rendering of the map.
58+
*
59+
* It should be used as a primary source of map settings (and project) for
60+
* all other components in the application.
61+
*
62+
* This is a readonly property.
63+
*/
64+
Q_PROPERTY( QgsQuickMapSettings *mapSettings READ mapSettings )
65+
66+
/**
67+
* When freeze property is set to true, the map canvas does not refresh.
68+
* The value temporary changes during the rendering process.
69+
*/
70+
Q_PROPERTY( bool freeze READ freeze WRITE setFreeze NOTIFY freezeChanged )
71+
72+
/**
73+
* The isRendering property is set to true while a rendering job is pending for this map canvas map.
74+
* It can be used to show a notification icon about an ongoing rendering job.
75+
* This is a readonly property.
76+
*/
77+
Q_PROPERTY( bool isRendering READ isRendering NOTIFY isRenderingChanged )
78+
79+
/**
80+
* Interval in milliseconds after which the map canvas will be updated while a rendering job is ongoing.
81+
* This only has an effect if incrementalRendering is activated.
82+
* Default is 250 [ms].
83+
*/
84+
Q_PROPERTY( int mapUpdateInterval READ mapUpdateInterval WRITE setMapUpdateInterval NOTIFY mapUpdateIntervalChanged )
85+
86+
/**
87+
* When the incrementalRendering property is set to true, the automatic refresh of map canvas during rendering is allowed.
88+
*/
89+
Q_PROPERTY( bool incrementalRendering READ incrementalRendering WRITE setIncrementalRendering NOTIFY incrementalRenderingChanged )
90+
91+
public:
92+
//! Create map canvas map
93+
QgsQuickMapCanvasMap( QQuickItem *parent = nullptr );
94+
~QgsQuickMapCanvasMap() = default;
95+
96+
virtual QSGNode *updatePaintNode( QSGNode *oldNode, QQuickItem::UpdatePaintNodeData * ) override;
97+
98+
//! \copydoc QgsQuickMapCanvasMap::mapSettings
99+
QgsQuickMapSettings *mapSettings() const;
100+
101+
//! \copydoc QgsQuickMapCanvasMap::freeze
102+
bool freeze() const;
103+
104+
//! \copydoc QgsQuickMapCanvasMap::freeze
105+
void setFreeze( bool freeze );
106+
107+
//! \copydoc QgsQuickMapCanvasMap::isRendering
108+
bool isRendering() const;
109+
110+
//! \copydoc QgsQuickMapCanvasMap::mapUpdateInterval
111+
int mapUpdateInterval() const;
112+
113+
//! \copydoc QgsQuickMapCanvasMap::mapUpdateInterval
114+
void setMapUpdateInterval( int mapUpdateInterval );
115+
116+
//! \copydoc QgsQuickMapCanvasMap::incrementalRendering
117+
bool incrementalRendering() const;
118+
119+
//! \copydoc QgsQuickMapCanvasMap::incrementalRendering
120+
void setIncrementalRendering( bool incrementalRendering );
121+
122+
signals:
123+
124+
/**
125+
* Signal is emitted when a rendering is starting
126+
*/
127+
void renderStarting();
128+
129+
/**
130+
* Signal is emitted when a canvas is refreshed
131+
*/
132+
void mapCanvasRefreshed();
133+
134+
//! \copydoc QgsQuickMapCanvasMap::freeze
135+
void freezeChanged();
136+
137+
//! \copydoc QgsQuickMapCanvasMap::isRendering
138+
void isRenderingChanged();
139+
140+
//!\copydoc QgsQuickMapCanvasMap::mapUpdateInterval
141+
void mapUpdateIntervalChanged();
142+
143+
//!\copydoc QgsQuickMapCanvasMap::incrementalRendering
144+
void incrementalRenderingChanged();
145+
146+
protected:
147+
virtual void geometryChanged( const QRectF &newGeometry, const QRectF &oldGeometry ) override;
148+
149+
public slots:
150+
//! Stop map rendering
151+
void stopRendering();
152+
153+
/**
154+
* Set map setting's extent (zoom the map) on the center by given scale
155+
*/
156+
void zoom( QPointF center, qreal scale );
157+
158+
/**
159+
* Set map setting's extent (pan the map) based on the difference of positions
160+
*/
161+
void pan( QPointF oldPos, QPointF newPos );
162+
163+
/**
164+
* Refresh the map canvas.
165+
* Does nothing when output size of map settings is not set
166+
*/
167+
void refresh();
168+
169+
private slots:
170+
void refreshMap();
171+
void renderJobUpdated();
172+
void renderJobFinished();
173+
void onWindowChanged( QQuickWindow *window );
174+
void onScreenChanged( QScreen *screen );
175+
void onExtentChanged();
176+
void onLayersChanged();
177+
178+
private:
179+
180+
/**
181+
* Should only be called by stopRendering()!
182+
*/
183+
void destroyJob( QgsMapRendererJob *job );
184+
QgsMapSettings prepareMapSettings() const;
185+
void updateTransform();
186+
void zoomToFullExtent();
187+
188+
std::unique_ptr<QgsQuickMapSettings> mMapSettings;
189+
bool mPinching = false;
190+
QPoint mPinchStartPoint;
191+
QgsMapRendererParallelJob *mJob = nullptr;
192+
QgsMapRendererCache *mCache = nullptr;
193+
QgsLabelingResults *mLabelingResults = nullptr;
194+
QImage mImage;
195+
QgsMapSettings mImageMapSettings;
196+
QTimer mRefreshTimer;
197+
bool mDirty = false;
198+
bool mFreeze = false;
199+
QList<QMetaObject::Connection> mLayerConnections;
200+
QTimer mMapUpdateTimer;
201+
bool mIncrementalRendering = false;
202+
};
203+
204+
#endif // QGSQUICKMAPCANVASMAP_H

‎src/quickgui/qgsquickmapsettings.cpp

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/***************************************************************************
2+
qgsquickmapsettings.cpp
3+
--------------------------------------
4+
Date : 27.12.2014
5+
Copyright : (C) 2014 by Matthias Kuhn
6+
Email : matthias (at) opengis.ch
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
17+
#include "qgsmaplayer.h"
18+
#include "qgsmaplayerstylemanager.h"
19+
#include "qgsmessagelog.h"
20+
#include "qgsproject.h"
21+
#include "qgis.h"
22+
23+
#include "qgsquickmapsettings.h"
24+
25+
QgsQuickMapSettings::QgsQuickMapSettings( QObject *parent )
26+
: QObject( parent )
27+
{
28+
// Connect signals for derived values
29+
connect( this, &QgsQuickMapSettings::destinationCrsChanged, this, &QgsQuickMapSettings::mapUnitsPerPixelChanged );
30+
connect( this, &QgsQuickMapSettings::extentChanged, this, &QgsQuickMapSettings::mapUnitsPerPixelChanged );
31+
connect( this, &QgsQuickMapSettings::outputSizeChanged, this, &QgsQuickMapSettings::mapUnitsPerPixelChanged );
32+
connect( this, &QgsQuickMapSettings::extentChanged, this, &QgsQuickMapSettings::visibleExtentChanged );
33+
connect( this, &QgsQuickMapSettings::rotationChanged, this, &QgsQuickMapSettings::visibleExtentChanged );
34+
connect( this, &QgsQuickMapSettings::outputSizeChanged, this, &QgsQuickMapSettings::visibleExtentChanged );
35+
}
36+
37+
void QgsQuickMapSettings::setProject( QgsProject *project )
38+
{
39+
if ( project == mProject )
40+
return;
41+
42+
// If we have already something connected, disconnect it!
43+
if ( mProject )
44+
{
45+
mProject->disconnect( this );
46+
}
47+
48+
mProject = project;
49+
50+
// Connect all signals
51+
if ( mProject )
52+
{
53+
connect( mProject, &QgsProject::readProject, this, &QgsQuickMapSettings::onReadProject );
54+
setDestinationCrs( mProject->crs() );
55+
mMapSettings.setTransformContext( mProject->transformContext() );
56+
}
57+
else
58+
{
59+
mMapSettings.setTransformContext( QgsCoordinateTransformContext() );
60+
}
61+
62+
emit projectChanged();
63+
}
64+
65+
QgsProject *QgsQuickMapSettings::project() const
66+
{
67+
return mProject;
68+
}
69+
70+
QgsCoordinateTransformContext QgsQuickMapSettings::transformContext() const
71+
{
72+
return mMapSettings.transformContext();
73+
}
74+
75+
QgsRectangle QgsQuickMapSettings::extent() const
76+
{
77+
return mMapSettings.extent();
78+
}
79+
80+
void QgsQuickMapSettings::setExtent( const QgsRectangle &extent )
81+
{
82+
if ( mMapSettings.extent() == extent )
83+
return;
84+
85+
mMapSettings.setExtent( extent );
86+
emit extentChanged();
87+
}
88+
89+
void QgsQuickMapSettings::setCenter( const QgsPoint &center )
90+
{
91+
QgsVector delta = QgsPointXY( center ) - mMapSettings.extent().center();
92+
93+
QgsRectangle e = mMapSettings.extent();
94+
e.setXMinimum( e.xMinimum() + delta.x() );
95+
e.setXMaximum( e.xMaximum() + delta.x() );
96+
e.setYMinimum( e.yMinimum() + delta.y() );
97+
e.setYMaximum( e.yMaximum() + delta.y() );
98+
99+
setExtent( e );
100+
}
101+
102+
double QgsQuickMapSettings::mapUnitsPerPixel() const
103+
{
104+
return mMapSettings.mapUnitsPerPixel();
105+
}
106+
107+
QgsRectangle QgsQuickMapSettings::visibleExtent() const
108+
{
109+
return mMapSettings.visibleExtent();
110+
}
111+
112+
QPointF QgsQuickMapSettings::coordinateToScreen( const QgsPoint &point ) const
113+
{
114+
QgsPointXY pt( point.x(), point.y() );
115+
QgsPointXY pp = mMapSettings.mapToPixel().transform( pt );
116+
return pp.toQPointF();
117+
}
118+
119+
QgsPoint QgsQuickMapSettings::screenToCoordinate( const QPointF &point ) const
120+
{
121+
const QgsPointXY pp = mMapSettings.mapToPixel().toMapCoordinates( point.toPoint() );
122+
return QgsPoint( pp );
123+
}
124+
125+
QgsMapSettings QgsQuickMapSettings::mapSettings() const
126+
{
127+
return mMapSettings;
128+
}
129+
130+
QSize QgsQuickMapSettings::outputSize() const
131+
{
132+
return mMapSettings.outputSize();
133+
}
134+
135+
void QgsQuickMapSettings::setOutputSize( const QSize &outputSize )
136+
{
137+
if ( mMapSettings.outputSize() == outputSize )
138+
return;
139+
140+
mMapSettings.setOutputSize( outputSize );
141+
emit outputSizeChanged();
142+
}
143+
144+
double QgsQuickMapSettings::outputDpi() const
145+
{
146+
return mMapSettings.outputDpi();
147+
}
148+
149+
void QgsQuickMapSettings::setOutputDpi( double outputDpi )
150+
{
151+
if ( qgsDoubleNear( mMapSettings.outputDpi(), outputDpi ) )
152+
return;
153+
154+
mMapSettings.setOutputDpi( outputDpi );
155+
emit outputDpiChanged();
156+
}
157+
158+
QgsCoordinateReferenceSystem QgsQuickMapSettings::destinationCrs() const
159+
{
160+
return mMapSettings.destinationCrs();
161+
}
162+
163+
void QgsQuickMapSettings::setDestinationCrs( const QgsCoordinateReferenceSystem &destinationCrs )
164+
{
165+
if ( mMapSettings.destinationCrs() == destinationCrs )
166+
return;
167+
168+
mMapSettings.setDestinationCrs( destinationCrs );
169+
emit destinationCrsChanged();
170+
}
171+
172+
QList<QgsMapLayer *> QgsQuickMapSettings::layers() const
173+
{
174+
return mMapSettings.layers();
175+
}
176+
177+
void QgsQuickMapSettings::setLayers( const QList<QgsMapLayer *> &layers )
178+
{
179+
mMapSettings.setLayers( layers );
180+
emit layersChanged();
181+
}
182+
183+
void QgsQuickMapSettings::onReadProject( const QDomDocument &doc )
184+
{
185+
QDomNodeList nodes = doc.elementsByTagName( "mapcanvas" );
186+
if ( nodes.count() )
187+
{
188+
QDomNode node = nodes.item( 0 );
189+
190+
mMapSettings.readXml( node );
191+
192+
if ( !qgsDoubleNear( mMapSettings.rotation(), 0 ) )
193+
QgsMessageLog::logMessage( tr( "Map Canvas rotation is not supported. Resetting from %1 to 0." ).arg( mMapSettings.rotation() ) );
194+
195+
mMapSettings.setRotation( 0 );
196+
197+
emit extentChanged();
198+
emit destinationCrsChanged();
199+
emit outputSizeChanged();
200+
emit outputDpiChanged();
201+
emit layersChanged();
202+
}
203+
}
204+
205+
double QgsQuickMapSettings::rotation() const
206+
{
207+
return mMapSettings.rotation();
208+
}
209+
210+
void QgsQuickMapSettings::setRotation( double rotation )
211+
{
212+
if ( !qgsDoubleNear( rotation, 0 ) )
213+
QgsMessageLog::logMessage( tr( "Map Canvas rotation is not supported. Resetting from %1 to 0." ).arg( rotation ) );
214+
}

‎src/quickgui/qgsquickmapsettings.h

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/***************************************************************************
2+
qgsquickmapsettings.h
3+
--------------------------------------
4+
Date : 27.12.2014
5+
Copyright : (C) 2014 by Matthias Kuhn
6+
Email : matthias (at) opengis.ch
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSQUICKMAPSETTINGS_H
17+
#define QGSQUICKMAPSETTINGS_H
18+
19+
#include <QObject>
20+
21+
#include "qgscoordinatetransformcontext.h"
22+
#include "qgsmapsettings.h"
23+
#include "qgsmapthemecollection.h"
24+
#include "qgspoint.h"
25+
#include "qgsrectangle.h"
26+
27+
#include "qgis_quick.h"
28+
29+
class QgsProject;
30+
31+
/**
32+
* \ingroup quick
33+
* The QgsQuickMapSettings class encapsulates QgsMapSettings class to offer
34+
* settings of configuration of map rendering via QML properties.
35+
*
36+
* On top of QgsMapSettings functionality, when QgsProject is attached,
37+
* it automatically loads its default settings from the project.
38+
* QgsProject should be attached before it is read.
39+
*
40+
* \note QML Type: MapSettings
41+
*
42+
* \sa QgsMapCanvas
43+
*
44+
* \since QGIS 3.2
45+
*/
46+
class QUICK_EXPORT QgsQuickMapSettings : public QObject
47+
{
48+
Q_OBJECT
49+
50+
/**
51+
* A project property should be used as a primary source of project all other components
52+
* in the application. QgsProject should be attached to QgsQuickMapSettings before
53+
* it is read (QgsProject::read)
54+
*
55+
* When project is read, map settings (CRS, extent, ...) are automatically set from its DOM.
56+
*/
57+
Q_PROPERTY( QgsProject *project READ project WRITE setProject NOTIFY projectChanged )
58+
59+
/**
60+
* Geographical coordinates of the rectangle that should be rendered.
61+
* The actual visible extent used for rendering could be slightly different
62+
* since the given extent may be expanded in order to fit the aspect ratio
63+
* of output size. Use QgsQuickMapSettings::visibleExtent to get the resulting extent.
64+
*
65+
* Automatically loaded from project on QgsProject::readProject
66+
*/
67+
Q_PROPERTY( QgsRectangle extent READ extent WRITE setExtent NOTIFY extentChanged )
68+
//! \copydoc QgsMapSettings::visibleExtent()
69+
Q_PROPERTY( QgsRectangle visibleExtent READ visibleExtent NOTIFY visibleExtentChanged )
70+
//! \copydoc QgsMapSettings::mapUnitsPerPixel()
71+
Q_PROPERTY( double mapUnitsPerPixel READ mapUnitsPerPixel NOTIFY mapUnitsPerPixelChanged )
72+
73+
/**
74+
* The rotation of the resulting map image, in degrees clockwise.
75+
* Map canvas rotation support is not implemented, 0 is used
76+
*/
77+
Q_PROPERTY( double rotation READ rotation WRITE setRotation NOTIFY rotationChanged )
78+
79+
/**
80+
* The size of the resulting map image
81+
*
82+
* Automatically loaded from project on QgsProject::readProject
83+
*/
84+
Q_PROPERTY( QSize outputSize READ outputSize WRITE setOutputSize NOTIFY outputSizeChanged )
85+
86+
/**
87+
* Output DPI used for conversion between real world units (e.g. mm) and pixels
88+
*
89+
* Automatically loaded from project on QgsProject::readProject
90+
*/
91+
Q_PROPERTY( double outputDpi READ outputDpi WRITE setOutputDpi NOTIFY outputDpiChanged )
92+
93+
/**
94+
* CRS of destination coordinate reference system.
95+
*
96+
* Automatically loaded from project on QgsProject::readProject
97+
*/
98+
Q_PROPERTY( QgsCoordinateReferenceSystem destinationCrs READ destinationCrs WRITE setDestinationCrs NOTIFY destinationCrsChanged )
99+
100+
/**
101+
* Set list of layers for map rendering. The layers must be registered in QgsProject.
102+
* The layers are stored in the reverse order of how they are rendered (layer with index 0 will be on top)
103+
*
104+
* \note Any non-spatial layers will be automatically stripped from the list (since they cannot be rendered!).
105+
*
106+
* Not loaded automatically from the associated project
107+
*/
108+
Q_PROPERTY( QList<QgsMapLayer *> layers READ layers WRITE setLayers NOTIFY layersChanged )
109+
110+
public:
111+
//! Create new map settings
112+
QgsQuickMapSettings( QObject *parent = nullptr );
113+
~QgsQuickMapSettings() = default;
114+
115+
//! Clone map settings
116+
QgsMapSettings mapSettings() const;
117+
118+
//! \copydoc QgsMapSettings::extent()
119+
QgsRectangle extent() const;
120+
121+
//! \copydoc QgsMapSettings::setExtent()
122+
void setExtent( const QgsRectangle &extent );
123+
124+
//! \copydoc QgsQuickMapSettings::project
125+
void setProject( QgsProject *project );
126+
127+
//! \copydoc QgsQuickMapSettings::project
128+
QgsProject *project() const;
129+
130+
//! Move current map extent to have center point defined by \a center
131+
Q_INVOKABLE void setCenter( const QgsPoint &center );
132+
133+
//! \copydoc QgsMapSettings::mapUnitsPerPixel()
134+
double mapUnitsPerPixel() const;
135+
136+
//! \copydoc QgsMapSettings::visibleExtent()
137+
QgsRectangle visibleExtent() const;
138+
139+
//! \copydoc QgsMapSettings::transformContext()
140+
Q_INVOKABLE QgsCoordinateTransformContext transformContext() const;
141+
142+
/**
143+
* Convert a map coordinate to screen pixel coordinates
144+
*
145+
* \param point A coordinate in map coordinates
146+
*
147+
* \return A coordinate in pixel / screen space
148+
*/
149+
Q_INVOKABLE QPointF coordinateToScreen( const QgsPoint &point ) const;
150+
151+
152+
/**
153+
* Convert a screen coordinate to a map coordinate
154+
*
155+
* \param point A coordinate in pixel / screen coordinates
156+
*
157+
* \return A coordinate in map coordinates
158+
*/
159+
Q_INVOKABLE QgsPoint screenToCoordinate( const QPointF &point ) const;
160+
161+
//! \copydoc QgsMapSettings::setTransformContext()
162+
void setTransformContext( const QgsCoordinateTransformContext &context );
163+
164+
//! \copydoc QgsQuickMapSettings::rotation
165+
double rotation() const;
166+
167+
//! \copydoc QgsQuickMapSettings::rotation
168+
void setRotation( double rotation );
169+
170+
//! \copydoc QgsMapSettings::outputSize()
171+
QSize outputSize() const;
172+
173+
//! \copydoc QgsMapSettings::setOutputSize()
174+
void setOutputSize( const QSize &outputSize );
175+
176+
//! \copydoc QgsMapSettings::outputDpi()
177+
double outputDpi() const;
178+
179+
//! \copydoc QgsMapSettings::setOutputDpi()
180+
void setOutputDpi( double outputDpi );
181+
182+
//! \copydoc QgsMapSettings::destinationCrs()
183+
QgsCoordinateReferenceSystem destinationCrs() const;
184+
185+
//! \copydoc QgsMapSettings::setDestinationCrs()
186+
void setDestinationCrs( const QgsCoordinateReferenceSystem &destinationCrs );
187+
188+
//! \copydoc QgsMapSettings::layers()
189+
QList<QgsMapLayer *> layers() const;
190+
191+
//! \copydoc QgsMapSettings::setLayers()
192+
void setLayers( const QList<QgsMapLayer *> &layers );
193+
194+
signals:
195+
//! \copydoc QgsQuickMapSettings::project
196+
void projectChanged();
197+
198+
//! \copydoc QgsQuickMapSettings::extent
199+
void extentChanged();
200+
201+
//! \copydoc QgsQuickMapSettings::destinationCrs
202+
void destinationCrsChanged();
203+
204+
//! \copydoc QgsQuickMapSettings::mapUnitsPerPixel
205+
void mapUnitsPerPixelChanged();
206+
207+
//! \copydoc QgsQuickMapSettings::rotation
208+
void rotationChanged();
209+
210+
//! \copydoc QgsQuickMapSettings::visibleExtent
211+
void visibleExtentChanged();
212+
213+
//! \copydoc QgsQuickMapSettings::outputSize
214+
void outputSizeChanged();
215+
216+
//! \copydoc QgsQuickMapSettings::outputDpi
217+
void outputDpiChanged();
218+
219+
//! \copydoc QgsQuickMapSettings::layers
220+
void layersChanged();
221+
222+
private slots:
223+
224+
/**
225+
* Read map canvas settings stored in a QGIS project file
226+
*
227+
* \param doc parsed DOM of a QgsProject
228+
*/
229+
void onReadProject( const QDomDocument &doc );
230+
231+
private:
232+
QgsProject *mProject = nullptr;
233+
QgsMapSettings mMapSettings;
234+
235+
};
236+
237+
#endif // QGSQUICKMAPSETTINGS_H

‎src/quickgui/qgsquickutils.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/***************************************************************************
2+
qgsquickutils.cpp
3+
--------------------------------------
4+
Date : Nov 2017
5+
Copyright : (C) 2017 by Peter Petrik
6+
Email : zilolv at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
#include <QDesktopWidget>
16+
#include <QString>
17+
18+
#include "qgis.h"
19+
#include "qgscoordinatereferencesystem.h"
20+
#include "qgscoordinatetransform.h"
21+
#include "qgsdistancearea.h"
22+
#include "qgslogger.h"
23+
#include "qgsvectorlayer.h"
24+
25+
#include "qgsquickmapsettings.h"
26+
#include "qgsquickutils.h"
27+
#include "qgsunittypes.h"
28+
29+
30+
QgsQuickUtils::QgsQuickUtils( QObject *parent )
31+
: QObject( parent )
32+
, mScreenDensity( calculateScreenDensity() )
33+
{
34+
}
35+
36+
QString QgsQuickUtils::dumpScreenInfo() const
37+
{
38+
QRect rec = QApplication::desktop()->screenGeometry();
39+
int dpiX = QApplication::desktop()->physicalDpiX();
40+
int dpiY = QApplication::desktop()->physicalDpiY();
41+
int height = rec.height();
42+
int width = rec.width();
43+
double sizeX = static_cast<double>( width ) / dpiX * 25.4;
44+
double sizeY = static_cast<double>( height ) / dpiY * 25.4;
45+
46+
QString msg;
47+
msg += tr( "screen resolution: %1x%2 px\n" ).arg( width ).arg( height );
48+
msg += tr( "screen DPI: %1x%2\n" ).arg( dpiX ).arg( dpiY );
49+
msg += tr( "screen size: %1x%2 mm\n" ).arg( QString::number( sizeX, 'f', 0 ), QString::number( sizeY, 'f', 0 ) );
50+
msg += tr( "screen density: %1" ).arg( mScreenDensity );
51+
return msg;
52+
}
53+
54+
qreal QgsQuickUtils::screenDensity() const
55+
{
56+
return mScreenDensity;
57+
}
58+
59+
qreal QgsQuickUtils::calculateScreenDensity()
60+
{
61+
// calculate screen density for calculation of real pixel sizes from density-independent pixels
62+
int dpiX = QApplication::desktop()->physicalDpiX();
63+
int dpiY = QApplication::desktop()->physicalDpiY();
64+
int dpi = dpiX < dpiY ? dpiX : dpiY; // In case of asymmetrical DPI. Improbable
65+
return dpi / 160.; // 160 DPI is baseline for density-independent pixels in Android
66+
}

‎src/quickgui/qgsquickutils.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/***************************************************************************
2+
qgsquickutils.h
3+
--------------------------------------
4+
Date : Nov 2017
5+
Copyright : (C) 2017 by Peter Petrik
6+
Email : zilolv at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSQUICKUTILS_H
17+
#define QGSQUICKUTILS_H
18+
19+
20+
#include <QObject>
21+
#include <QString>
22+
23+
#include "qgis.h"
24+
#include "qgis_quick.h"
25+
26+
/**
27+
* \ingroup quick
28+
*
29+
* Encapsulating the common utilies for QgsQuick library.
30+
*
31+
* \note QML Type: Utils (Singleton)
32+
*
33+
* \since QGIS 3.2
34+
*/
35+
class QUICK_EXPORT QgsQuickUtils: public QObject
36+
{
37+
Q_OBJECT
38+
39+
/**
40+
* "dp" is useful for building building components that work well with different screen densities.
41+
* It stands for density-independent pixels. A width of 10dp is going to be the same physical size
42+
* on all screens regardless their density. In QML code, all values are specified in screen pixels,
43+
* so in order to set a width of 10dp, one would use the following code: "width: 10 * QgsQuick.Utils.dp"
44+
*
45+
* 1dp is approximately 0.16mm. When screen has 160 DPI (baseline), the value of "dp" is 1.
46+
* On high DPI screen the value will be greater, e.g. 1.5.
47+
*
48+
* This is a readonly property.
49+
*/
50+
Q_PROPERTY( qreal dp READ screenDensity CONSTANT )
51+
52+
public:
53+
//! Create new utilities
54+
QgsQuickUtils( QObject *parent = nullptr );
55+
//! dtor
56+
~QgsQuickUtils() = default;
57+
58+
//! \copydoc QgsQuickUtils::dp
59+
qreal screenDensity() const;
60+
61+
/**
62+
* Returns a string with information about screen size and resolution
63+
*
64+
* Useful to log for debugging of graphical problems on various display sizes
65+
*/
66+
QString dumpScreenInfo() const;
67+
68+
private:
69+
static qreal calculateScreenDensity();
70+
71+
qreal mScreenDensity;
72+
};
73+
74+
#endif // QGSQUICKUTILS_H

‎tests/src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,7 @@ IF (ENABLE_TESTS)
4646
ADD_SUBDIRECTORY(python)
4747
ENDIF (WITH_BINDINGS)
4848
ADD_SUBDIRECTORY(geometry_checker)
49+
IF (WITH_QUICK)
50+
ADD_SUBDIRECTORY(quickgui)
51+
ENDIF (WITH_QUICK)
4952
ENDIF (ENABLE_TESTS)

‎tests/src/quickgui/CMakeLists.txt

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Standard includes and utils to compile into all tests.
2+
3+
#####################################################
4+
# Don't forget to include output directory, otherwise
5+
# the UI file won't be wrapped!
6+
INCLUDE_DIRECTORIES(
7+
${CMAKE_CURRENT_SOURCE_DIR}
8+
${CMAKE_CURRENT_BINARY_DIR}
9+
10+
${CMAKE_SOURCE_DIR}/src/core
11+
${CMAKE_SOURCE_DIR}/src/core/annotations
12+
${CMAKE_SOURCE_DIR}/src/core/auth
13+
${CMAKE_SOURCE_DIR}/src/core/composer
14+
${CMAKE_SOURCE_DIR}/src/core/fieldformatter
15+
${CMAKE_SOURCE_DIR}/src/core/geometry
16+
${CMAKE_SOURCE_DIR}/src/core/layertree
17+
${CMAKE_SOURCE_DIR}/src/core/layout
18+
${CMAKE_SOURCE_DIR}/src/core/locator
19+
${CMAKE_SOURCE_DIR}/src/core/metadata
20+
${CMAKE_SOURCE_DIR}/src/core/providers/memory
21+
${CMAKE_SOURCE_DIR}/src/core/raster
22+
${CMAKE_SOURCE_DIR}/src/core/scalebar
23+
${CMAKE_SOURCE_DIR}/src/core/symbology
24+
${CMAKE_SOURCE_DIR}/src/core/effects
25+
${CMAKE_SOURCE_DIR}/src/core/metadata
26+
${CMAKE_SOURCE_DIR}/src/core/expression
27+
${CMAKE_SOURCE_DIR}/src/native
28+
${CMAKE_SOURCE_DIR}/src/quickgui
29+
${CMAKE_SOURCE_DIR}/src/test
30+
31+
${CMAKE_BINARY_DIR}/src/core
32+
${CMAKE_BINARY_DIR}/src/native
33+
${CMAKE_BINARY_DIR}/src/quickgui
34+
)
35+
36+
INCLUDE_DIRECTORIES(SYSTEM
37+
${LIBZIP_INCLUDE_DIRS}
38+
${SPATIALINDEX_INCLUDE_DIR}
39+
${PROJ_INCLUDE_DIR}
40+
${GEOS_INCLUDE_DIR}
41+
${GDAL_INCLUDE_DIR}
42+
${EXPAT_INCLUDE_DIR}
43+
${SQLITE3_INCLUDE_DIR}
44+
${SPATIALITE_INCLUDE_DIR}
45+
${QCA_INCLUDE_DIR}
46+
${QTKEYCHAIN_INCLUDE_DIR}
47+
)
48+
49+
#note for tests we should not include the moc of our
50+
#qtests in the executable file list as the moc is
51+
#directly included in the sources
52+
#and should not be compiled twice. Trying to include
53+
#them in will cause an error at build time
54+
55+
#No relinking and full RPATH for the install tree
56+
#See: http://www.cmake.org/Wiki/CMake_RPATH_handling#No_relinking_and_full_RPATH_for_the_install_tree
57+
58+
MACRO (ADD_QGIS_TEST testname testsrc)
59+
SET(qgis_${testname}_SRCS ${testsrc} ${util_SRCS})
60+
ADD_CUSTOM_TARGET(qgis_${testname}moc ALL DEPENDS ${qgis_${testname}_MOC_SRCS})
61+
ADD_EXECUTABLE(qgis_${testname} ${qgis_${testname}_SRCS})
62+
SET_TARGET_PROPERTIES(qgis_${testname} PROPERTIES AUTOMOC TRUE)
63+
TARGET_LINK_LIBRARIES(qgis_${testname}
64+
${Qt5Xml_LIBRARIES}
65+
${Qt5Core_LIBRARIES}
66+
${Qt5Svg_LIBRARIES}
67+
${Qt5Test_LIBRARIES}
68+
Qt5::Gui
69+
Qt5::Qml
70+
Qt5::Quick
71+
Qt5::Xml
72+
qgis_core
73+
qgis_quick)
74+
75+
ADD_TEST(qgis_${testname} ${CMAKE_CURRENT_BINARY_DIR}/../../../output/bin/qgis_${testname} -maxwarnings 10000)
76+
ENDMACRO (ADD_QGIS_TEST)
77+
78+
#############################################################
79+
# Tests:
80+
81+
ADD_QGIS_TEST(qgsquickutils testqgsquickutils.cpp)
82+
83+
84+
#############################################################
85+
# Add also test application
86+
ADD_SUBDIRECTORY(app)

‎tests/src/quickgui/app/CMakeLists.txt

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
SET(QGIS_QUICK_APP_MOC_HDRS
2+
)
3+
4+
SET(QGIS_QUICK_APP_SRCS
5+
main.cpp
6+
)
7+
8+
SET(QGIS_QUICK_APP_QMLS
9+
main.qml
10+
)
11+
12+
INCLUDE_DIRECTORIES(
13+
${CMAKE_CURRENT_SOURCE_DIR}
14+
${CMAKE_CURRENT_BINARY_DIR}
15+
16+
${CMAKE_SOURCE_DIR}/src/core
17+
${CMAKE_SOURCE_DIR}/src/core/annotations
18+
${CMAKE_SOURCE_DIR}/src/core/auth
19+
${CMAKE_SOURCE_DIR}/src/core/composer
20+
${CMAKE_SOURCE_DIR}/src/core/fieldformatter
21+
${CMAKE_SOURCE_DIR}/src/core/geometry
22+
${CMAKE_SOURCE_DIR}/src/core/layertree
23+
${CMAKE_SOURCE_DIR}/src/core/layout
24+
${CMAKE_SOURCE_DIR}/src/core/locator
25+
${CMAKE_SOURCE_DIR}/src/core/metadata
26+
${CMAKE_SOURCE_DIR}/src/core/providers/memory
27+
${CMAKE_SOURCE_DIR}/src/core/raster
28+
${CMAKE_SOURCE_DIR}/src/core/scalebar
29+
${CMAKE_SOURCE_DIR}/src/core/symbology
30+
${CMAKE_SOURCE_DIR}/src/core/effects
31+
${CMAKE_SOURCE_DIR}/src/core/metadata
32+
${CMAKE_SOURCE_DIR}/src/core/expression
33+
${CMAKE_SOURCE_DIR}/src/native
34+
${CMAKE_SOURCE_DIR}/src/quickgui
35+
36+
${CMAKE_BINARY_DIR}/src/core
37+
${CMAKE_BINARY_DIR}/src/native
38+
${CMAKE_BINARY_DIR}/src/quickgui
39+
)
40+
41+
INCLUDE_DIRECTORIES(SYSTEM
42+
${LIBZIP_INCLUDE_DIRS}
43+
${SPATIALINDEX_INCLUDE_DIR}
44+
${PROJ_INCLUDE_DIR}
45+
${GEOS_INCLUDE_DIR}
46+
${GDAL_INCLUDE_DIR}
47+
${EXPAT_INCLUDE_DIR}
48+
${SQLITE3_INCLUDE_DIR}
49+
${SPATIALITE_INCLUDE_DIR}
50+
${QCA_INCLUDE_DIR}
51+
${QTKEYCHAIN_INCLUDE_DIR}
52+
)
53+
54+
QT5_WRAP_CPP(QGIS_QUICK_APP_MOC_SRCS ${QGIS_QUICK_APP_MOC_HDRS})
55+
QT5_ADD_RESOURCES(QGIS_QUICK_APP_RESOURCES qml.qrc)
56+
SET(QGIS_QUICK_APP_NAME qgis_quickapp)
57+
ADD_EXECUTABLE(${QGIS_QUICK_APP_NAME}
58+
${QGIS_QUICK_APP_RESOURCES}
59+
${QGIS_QUICK_APP_QMLS}
60+
${QGIS_QUICK_APP_SRCS}
61+
${QGIS_QUICK_APP_MOC_SRCS}
62+
)
63+
64+
TARGET_LINK_LIBRARIES(${QGIS_QUICK_APP_NAME} Qt5::Gui Qt5::Qml Qt5::Quick Qt5::Xml qgis_core qgis_quick)
65+
SET_TARGET_PROPERTIES(${QGIS_QUICK_APP_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
66+
TARGET_COMPILE_DEFINITIONS(${QGIS_QUICK_APP_NAME} PRIVATE "-DQT_NO_FOREACH")
67+
ADD_DEPENDENCIES(${QGIS_QUICK_APP_NAME}
68+
qgis_quick_plugin
69+
ogrprovider
70+
gdalprovider
71+
spatialiteprovider
72+
virtuallayerprovider)
73+
74+
INSTALL(TARGETS ${QGIS_QUICK_APP_NAME}
75+
RUNTIME DESTINATION ${QGIS_BIN_DIR}
76+
LIBRARY DESTINATION ${QGIS_LIB_DIR}
77+
ARCHIVE DESTINATION ${QGIS_LIB_DIR}
78+
FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR}
79+
PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR})
80+

‎tests/src/quickgui/app/main.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/***************************************************************************
2+
main.cpp
3+
--------------------------------------
4+
Date : Nov 2017
5+
Copyright : (C) 2017 by Peter Petrik
6+
Email : zilolv at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include <QCommandLineParser>
17+
#include <QQmlApplicationEngine>
18+
#include <QQmlComponent>
19+
#include <QQmlContext>
20+
#include <QQmlError>
21+
22+
#include "qgis.h"
23+
#include "qgsapplication.h"
24+
#include "qgsproject.h"
25+
#include "qgslayertree.h"
26+
#include "qgsmessagelog.h"
27+
#include "qgsquickutils.h"
28+
#include "qgslogger.h"
29+
30+
int main( int argc, char *argv[] )
31+
{
32+
// 1) Initialize QGIS
33+
QgsApplication app( argc, argv, true );
34+
35+
// Set up the QSettings environment must be done after qapp is created
36+
QCoreApplication::setOrganizationName( "QGIS" );
37+
QCoreApplication::setOrganizationDomain( "qgis.org" );
38+
QCoreApplication::setApplicationName( "QgsQuick Test App" );
39+
QCoreApplication::setApplicationVersion( Qgis::QGIS_VERSION );
40+
41+
QCommandLineParser parser;
42+
parser.addVersionOption();
43+
parser.process( app );
44+
45+
QgsApplication::init();
46+
QgsApplication::initQgis();
47+
48+
// 2) Load QGIS Project
49+
QString dataDir( TEST_DATA_DIR ); // defined in CMakeLists.txt
50+
QString projectFile = dataDir + "/quickapp_project.qgs";
51+
QgsDebugMsg( QStringLiteral( "project file: %1" ).arg( projectFile ) );
52+
QgsProject project;
53+
bool res = project.read( projectFile );
54+
Q_ASSERT( res );
55+
56+
QQmlEngine engine;
57+
engine.addImportPath( QgsApplication::qmlImportPath() );
58+
engine.rootContext()->setContextProperty( "__project", &project );
59+
engine.rootContext()->setContextProperty( "__layers", QVariant::fromValue( project.layerTreeRoot()->layerOrder() ) );
60+
61+
QQmlComponent component( &engine, QUrl( QStringLiteral( "qrc:/main.qml" ) ) );
62+
QObject *object = component.create();
63+
64+
if ( !component.errors().isEmpty() )
65+
{
66+
QgsDebugMsg( QStringLiteral( "%s" ).arg( QgsApplication::showSettings().toLocal8Bit().data() ) );
67+
68+
QgsDebugMsg( QStringLiteral( "****************************************" ) );
69+
QgsDebugMsg( QStringLiteral( "***** QML errors: *****" ) );
70+
QgsDebugMsg( QStringLiteral( "****************************************" ) );
71+
const QList<QQmlError> errors = component.errors();
72+
for ( const QQmlError &error : errors )
73+
{
74+
QgsDebugMsg( error.toString() );
75+
}
76+
QgsDebugMsg( QStringLiteral( "****************************************" ) );
77+
QgsDebugMsg( QStringLiteral( "****************************************" ) );
78+
}
79+
80+
if ( object == nullptr )
81+
{
82+
QgsDebugMsg( QStringLiteral( "FATAL ERROR: unable to create main.qml" ) );
83+
return EXIT_FAILURE;
84+
}
85+
86+
// Add some data for debugging if needed
87+
QgsApplication::messageLog()->logMessage( QgsQuickUtils().dumpScreenInfo() );
88+
QgsDebugMsg( QStringLiteral( "data directory: %1" ).arg( dataDir ) );
89+
90+
return app.exec();
91+
}
92+

‎tests/src/quickgui/app/main.qml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/***************************************************************************
2+
main.qml
3+
--------------------------------------
4+
Date : Nov 2017
5+
Copyright : (C) 2017 by Peter Petrik
6+
Email : zilolv at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
import QtQuick 2.7
16+
import QtQuick.Controls 2.2
17+
import QgsQuick 0.1 as QgsQuick
18+
import "."
19+
20+
ApplicationWindow {
21+
id: window
22+
visible: true
23+
visibility: "Maximized"
24+
title: qsTr("QGIS Quick Test App")
25+
26+
QgsQuick.MapCanvas {
27+
id: mapCanvas
28+
29+
height: parent.height
30+
width: parent.width
31+
32+
mapSettings.project: __project
33+
mapSettings.layers: __layers
34+
35+
onClicked: {
36+
var screenPoint = Qt.point(mouse.x, mouse.y)
37+
console.log("clicked:" + screenPoint)
38+
}
39+
}
40+
}

‎tests/src/quickgui/app/qml.qrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<RCC>
2+
<qresource prefix="/">
3+
<file>main.qml</file>
4+
</qresource>
5+
</RCC>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
; This file can be edited to change the style of the application
2+
; See Styling Qt Quick Controls 2 in the documentation for details:
3+
; http://doc.qt.io/qt-5/qtquickcontrols2-styles.html
4+
5+
[Controls]
6+
Style=Default
7+
8+
[Universal]
9+
Theme=Light
10+
;Accent=Steel
11+
12+
[Material]
13+
Theme=Light
14+
;Accent=BlueGrey
15+
;Primary=BlueGray
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/***************************************************************************
2+
testqgsquickutils.cpp
3+
--------------------------------------
4+
Date : Nov 2017
5+
Copyright : (C) 2017 by Peter Petrik
6+
Email : zilolv at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
#include <QObject>
16+
#include <QApplication>
17+
#include <QDesktopWidget>
18+
19+
#include "qgsapplication.h"
20+
#include "qgstest.h"
21+
#include "qgis.h"
22+
23+
#include "qgsquickutils.h"
24+
25+
class TestQgsQuickUtils: public QObject
26+
{
27+
Q_OBJECT
28+
private slots:
29+
void init() {} // will be called before each testfunction is executed.
30+
void cleanup() {} // will be called after every testfunction.
31+
32+
void screen_density();
33+
34+
void dump_screen_info();
35+
36+
private:
37+
QgsQuickUtils utils;
38+
};
39+
40+
void TestQgsQuickUtils::screen_density()
41+
{
42+
qreal dp = utils.screenDensity();
43+
QVERIFY( ( dp > 0 ) && ( dp < 1000 ) );
44+
}
45+
46+
void TestQgsQuickUtils::dump_screen_info()
47+
{
48+
qreal dp = utils.screenDensity();
49+
QVERIFY( utils.dumpScreenInfo().contains( QStringLiteral( "%1" ).arg( dp ) ) );
50+
}
51+
52+
QGSTEST_MAIN( TestQgsQuickUtils )
53+
#include "testqgsquickutils.moc"

‎tests/testdata/quickapp_project.qgs

Lines changed: 1018 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.