Skip to content

Commit 77f500b

Browse files
sklencarwonder-sk
authored andcommittedFeb 25, 2019
[QgsQuick] - externalResource widget handler (#9232)
* [QgsQuick] - extended externalResource widget Added removeFile function and modified fileName function - former has been missing and photoPanel is using it. The latter needed modification due to a new option to choose image from a gallery. Added externalResource handler for externalResource widget which enables following features: * option to choose an image from a gallery - selected image is copied to projects folder, if it doesnt exists there. Added "ic_gallery" icon. * ability to remove value for externalResource field. Optionally removes referenced image as well ("Ok" option in dialog) * ability to interact with image preview onClick - the main idea is to have ability to enlarge preview image. Currently its possible only in edit state of the form since the whole field is disabled otherwise. Fixed resizing of icon/previewImage and component itself as well. * [QgsQuick] - extended externalResource widget Commit contains following fixes/changes/additions after review: * Added QgsQuickUtils::getRelativePath which replaced QgsQuickUtils::getFileName + related changes in photoPanel * Added test for new QgsQuickUtils functionality * fixed weird or redundant size definitions in externalResource widget * Some changes in docs. * [QgsQuick] Changed "default" case result for QgsQuickUtils::getRelativePath * [QgsQuick] Fixed test after changed functionality in QgsQuickUtils
1 parent d49dc89 commit 77f500b

File tree

8 files changed

+168
-13
lines changed

8 files changed

+168
-13
lines changed
 

‎src/quickgui/images/ic_gallery.svg

Lines changed: 1 addition & 0 deletions
Loading

‎src/quickgui/images/images.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
<file>ic_photo_notavailable_white.svg</file>
1111
<file>ic_save_white.svg</file>
1212
<file>ic_camera.svg</file>
13+
<file>ic_gallery.svg</file>
1314
</qresource>
1415
</RCC>

‎src/quickgui/plugin/editor/qgsquickexternalresource.qml

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ Item {
3131
property var notavailableImageSource: QgsQuick.Utils.getThemeIcon("ic_photo_notavailable_white")
3232

3333
id: fieldItem
34+
height: image.hasValidSource? customStyle.height * 3 : customStyle.height
3435
anchors {
3536
left: parent.left
3637
right: parent.right
3738
rightMargin: 10 * QgsQuick.Utils.dp
3839
}
3940

40-
height: Math.max(image.height, button.height)
4141
QgsQuick.PhotoCapture {
4242
id: photoCapturePanel
4343
visible: false
@@ -52,11 +52,21 @@ Item {
5252
property bool hasValidSource: false
5353

5454
id: image
55-
height: hasValidSource? customStyle.height * 3 : customStyle.height
55+
height: fieldItem.height
56+
sourceSize.height: height
5657
autoTransform: true
5758
fillMode: Image.PreserveAspectFit
5859
visible: hasValidSource
5960

61+
MouseArea {
62+
anchors.fill: parent
63+
onClicked: externalResourceHandler.previewImage(homePath + "/" + image.currentValue)
64+
}
65+
66+
onCurrentValueChanged: {
67+
image.source = image.getSource()
68+
}
69+
6070
onSourceChanged: {
6171
hasValidSource = (image.source === fieldItem.brokenImageSource ||
6272
image.source === fieldItem.notavailableImageSource) ? false : true
@@ -81,6 +91,66 @@ Item {
8191
visible: !image.hasValidSource
8292
}
8393

94+
Button {
95+
id: deleteButton
96+
visible: fieldItem.enabled && image.hasValidSource
97+
width: customStyle.height
98+
height: width
99+
padding: 0
100+
101+
anchors.right: imageBrowserButton.left
102+
anchors.bottom: parent.bottom
103+
anchors.verticalCenter: parent.verticalCenter
104+
105+
onClicked: externalResourceHandler.removeImage(fieldItem, homePath + "/" + image.currentValue)
106+
107+
background: Image {
108+
id: deleteIcon
109+
source: QgsQuick.Utils.getThemeIcon("ic_delete_forever_white")
110+
width: deleteButton.width
111+
height: deleteButton.height
112+
sourceSize.width: width
113+
sourceSize.height: height
114+
fillMode: Image.PreserveAspectFit
115+
}
116+
117+
ColorOverlay {
118+
anchors.fill: deleteIcon
119+
source: deleteIcon
120+
color: customStyle.fontColor
121+
}
122+
}
123+
124+
Button {
125+
id: imageBrowserButton
126+
visible: fieldItem.enabled
127+
width: customStyle.height
128+
height: width
129+
padding: 0
130+
131+
anchors.right: button.left
132+
anchors.bottom: parent.bottom
133+
anchors.verticalCenter: parent.verticalCenter
134+
135+
onClicked:externalResourceHandler.chooseImage(fieldItem)
136+
137+
background: Image {
138+
id: browseIcon
139+
source: QgsQuick.Utils.getThemeIcon("ic_gallery")
140+
width: imageBrowserButton.width
141+
height: imageBrowserButton.height
142+
sourceSize.width: width
143+
sourceSize.height: height
144+
fillMode: Image.PreserveAspectFit
145+
}
146+
147+
ColorOverlay {
148+
anchors.fill: browseIcon
149+
source: browseIcon
150+
color: customStyle.fontColor
151+
}
152+
}
153+
84154
Button {
85155
id: button
86156
visible: fieldItem.enabled

‎src/quickgui/plugin/qgsquickfeatureform.qml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,34 @@ Item {
3636
*/
3737
signal canceled
3838

39+
/**
40+
* A handler for extra events in externalSourceWidget.
41+
*/
42+
property var externalResourceHandler: QtObject {
43+
44+
/**
45+
* Called when clicked on the gallery icon to choose a file in a gallery.
46+
* \param itemWidget editorWidget for modified field to send valueChanged signal.
47+
*/
48+
property var chooseImage: function chooseImage(itemWidget) {
49+
}
50+
51+
/**
52+
* Called when clicked on the photo image. Suppose to be used to bring a bigger preview.
53+
* \param imagePath Absolute path to the image.
54+
*/
55+
property var previewImage: function previewImage(imagePath) {
56+
}
57+
58+
/**
59+
* Called when clicked on the trash icon. Suppose to delete the value and optionally also the image.
60+
* \param itemWidget editorWidget for modified field to send valueChanged signal.
61+
* \param imagePath Absolute path to the image.
62+
*/
63+
property var removeImage: function removeImage(itemWidget, imagePath) {
64+
}
65+
}
66+
3967
/**
4068
* AttributeFormModel binded on a feature supporting auto-generated editor layouts and "tab" layout.
4169
*/
@@ -320,6 +348,7 @@ Item {
320348
property var constraintValid: ConstraintValid
321349
property var homePath: form.project ? form.project.homePath : ""
322350
property var customStyle: form.style.fields
351+
property var externalResourceHandler: form.externalResourceHandler
323352

324353
active: widget !== 'Hidden'
325354

‎src/quickgui/plugin/qgsquickphotopanel.qml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Drawer {
7373
Component.onDestruction: {
7474
if (!captureItem && camera.imageCapture.capturedImagePath != ""){
7575
captureItem.saveImage = false
76-
QgsQuick.Utils.remove(camera.imageCapture.capturedImagePath)
76+
QgsQuick.Utils.removeFile(camera.imageCapture.capturedImagePath)
7777
}
7878
captureItem.saveImage = false
7979
}
@@ -164,7 +164,7 @@ Drawer {
164164
captureItem.saveImage = false
165165
photoPreview.visible = false
166166
if (camera.imageCapture.capturedImagePath != "") {
167-
QgsQuick.Utils.remove(camera.imageCapture.capturedImagePath)
167+
QgsQuick.Utils.removeFile(camera.imageCapture.capturedImagePath)
168168
}
169169
}
170170
}
@@ -200,7 +200,7 @@ Drawer {
200200
onClicked: {
201201
captureItem.saveImage = true
202202
photoPanel.visible = false
203-
photoPanel.lastPhotoName = QgsQuick.Utils.getFileName(camera.imageCapture.capturedImagePath)
203+
photoPanel.lastPhotoName = QgsQuick.Utils.getRelativePath(camera.imageCapture.capturedImagePath, photoPanel.targetDir)
204204
if (photoPanel.lastPhotoName !== "") {
205205
fieldItem.image.source = photoPanel.targetDir + "/" + photoPanel.lastPhotoName
206206
fieldItem.valueChanged(photoPanel.lastPhotoName, photoPanel.lastPhotoName === "" || photoPanel.lastPhotoName === null)

‎src/quickgui/qgsquickutils.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,22 @@ bool QgsQuickUtils::fileExists( const QString &path )
9595
return ( check_file.exists() && check_file.isFile() );
9696
}
9797

98-
QString QgsQuickUtils::getFileName( const QString &path )
98+
QString QgsQuickUtils::getRelativePath( const QString &path, const QString &prefixPath )
9999
{
100-
QFileInfo fileInfo( path );
101-
QString filename( fileInfo.fileName() );
102-
return filename;
100+
QString resultPath = path;
101+
QString prefixPathWithSlash;
102+
if ( !prefixPath.endsWith( "/" ) )
103+
prefixPathWithSlash = QStringLiteral( "%1/" ).arg( prefixPath );
104+
else
105+
prefixPathWithSlash = prefixPath;
106+
107+
if ( resultPath.startsWith( prefixPathWithSlash ) )
108+
return resultPath.replace( prefixPathWithSlash, QString() );
109+
QString filePrefixPath = QStringLiteral( "file://%1" ).arg( prefixPathWithSlash );
110+
if ( resultPath.startsWith( filePrefixPath ) )
111+
return resultPath.replace( filePrefixPath, QString() );
112+
113+
return QString();
103114
}
104115

105116
void QgsQuickUtils::logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level )
@@ -162,6 +173,12 @@ QString QgsQuickUtils::formatDistance( double distance,
162173
.arg( QgsUnitTypes::toAbbreviatedString( destUnits ) );
163174
}
164175

176+
bool QgsQuickUtils::removeFile( const QString &filePath )
177+
{
178+
QFile file( filePath );
179+
return file.remove( filePath );
180+
}
181+
165182

166183
void QgsQuickUtils::humanReadableDistance( double srcDistance, QgsUnitTypes::DistanceUnit srcUnits,
167184
QgsUnitTypes::SystemOfMeasurement destSystem,

‎src/quickgui/qgsquickutils.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,13 @@ class QUICK_EXPORT QgsQuickUtils: public QObject
124124
Q_INVOKABLE static bool fileExists( const QString &path );
125125

126126
/**
127-
* Extracts filename from path
128-
* \since QGIS 3.4
127+
* Returns relative path of the file to given prefixPath. If prefixPath does not match a path parameter,
128+
* returns an empty string. If a path starts with "file://", this prefix is ignored.
129+
* \param path Absolute path to file
130+
* \param prefixPath
131+
* \since QGIS 3.8
129132
*/
130-
Q_INVOKABLE static QString getFileName( const QString &path );
133+
Q_INVOKABLE static QString getRelativePath( const QString &path, const QString &prefixPath );
131134

132135
/**
133136
* Log message in QgsMessageLog
@@ -194,6 +197,16 @@ class QUICK_EXPORT QgsQuickUtils: public QObject
194197
int decimals,
195198
QgsUnitTypes::SystemOfMeasurement destSystem = QgsUnitTypes::MetricSystem );
196199

200+
/**
201+
* Deletes file from a given path.
202+
*
203+
* \param filePath Absolute path to file
204+
* \returns bool True, if removal was successful, otherwise false.
205+
*
206+
* \since QGIS 3.8
207+
*/
208+
Q_INVOKABLE static bool removeFile( const QString &filePath );
209+
197210
/**
198211
* Converts distance to human readable distance in destination system of measurement
199212
*

‎tests/src/quickgui/testqgsquickutils.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class TestQgsQuickUtils: public QObject
4343
void loadIcon();
4444
void fileExists();
4545
void loadQmlComponent();
46+
void getRelativePath();
4647

4748
private:
4849
QgsQuickUtils utils;
@@ -144,7 +145,8 @@ void TestQgsQuickUtils::loadIcon()
144145
QUrl url = utils.getThemeIcon( "ic_save_white" );
145146
Q_ASSERT( url.toString() == QStringLiteral( "qrc:/ic_save_white.svg" ) );
146147

147-
QString fileName = utils.getFileName( url.toString() );
148+
QFileInfo fileInfo( url.toString() );
149+
QString fileName( fileInfo.fileName() );
148150
Q_ASSERT( fileName == QStringLiteral( "ic_save_white.svg" ) );
149151
}
150152

@@ -164,5 +166,27 @@ void TestQgsQuickUtils::loadQmlComponent()
164166
Q_ASSERT( valuemap.path() == QString( "qgsquickvaluemap.qml" ) );
165167
}
166168

169+
void TestQgsQuickUtils::getRelativePath()
170+
{
171+
QString prefixPath = QStringLiteral( "%1/" ).arg( TEST_DATA_DIR );
172+
QString fileName = QStringLiteral( "quickapp_project.qgs" );
173+
QString path = prefixPath + fileName;
174+
QString relativePath = utils.getRelativePath( path, prefixPath );
175+
QCOMPARE( fileName, relativePath );
176+
177+
QString fileName2 = QStringLiteral( "zip/test.zip" );
178+
QString path2 = prefixPath + fileName2;
179+
QString relativePath2 = utils.getRelativePath( path2, prefixPath );
180+
QCOMPARE( fileName2, relativePath2 );
181+
182+
QString path3 = QStringLiteral( "file://" ) + path2;
183+
QString relativePath3 = utils.getRelativePath( path3, prefixPath );
184+
QCOMPARE( fileName2, relativePath3 );
185+
186+
QString relativePath4 = utils.getRelativePath( path2, QStringLiteral( "/dummy/path/" ) );
187+
QCOMPARE( QString(), relativePath4 );
188+
}
189+
190+
167191
QGSTEST_MAIN( TestQgsQuickUtils )
168192
#include "testqgsquickutils.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.