Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add null handling to value map edit widget (fixes #15215) #3274

Merged
merged 7 commits into from
Jul 9, 2016

Conversation

dgoedkoop
Copy link
Contributor

See title. :)

This makes it possible to use the NULL placeholder value in the value map widget, just like in the other editing widgets, so that NULL values can be displayed with an appropriate description, and so that values can be reset to NULL.

I hope this can also be applied to the LTR release 2.14.

@@ -24,10 +26,13 @@ QgsValueMapWidgetWrapper::QgsValueMapWidgetWrapper( QgsVectorLayer* vl, int fiel

QVariant QgsValueMapWidgetWrapper::value() const
{
QVariant v;
QString v;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to make that a QVariant and only have a single return in the end

@dgoedkoop
Copy link
Contributor Author

@m-kuhn Is this what you meant by "single return in the end"?

@m-kuhn
Copy link
Member

m-kuhn commented Jul 5, 2016

Yes, thanks.
It's mainly "good practice" because it avoids memory leaks when methods get very long.

I also wondered if the toString() is required if it's just after converted back to a QVariant?

Right now, the widget setting for NULL and the application representation setting for NULL have to match, is this correct?

@dgoedkoop
Copy link
Contributor Author

The added toString() isn't required anymore, that's true. I'll fix that.

The idea of this PR is that you should be able to do something like this:

image

(assuming that 'NULL' is the application-wide representation for null values.)

Currently, this would just try to write the literal string value 'NULL' into the attribute when selecting the first option.

@m-kuhn
Copy link
Member

m-kuhn commented Jul 5, 2016

I really like the functionality.

I'm just a bit worried about the portability of the project, mixing representation and data seems to be a bit brittle.

What would be great it to make the whole configuration for the Value Map a bit more advanced. At the moment it's just a key-value pair which is saved. This leads to ugly side-effects like leftovers from configurations from other widgets when you start configuring it. The proper way to go would be to move the configuration to a QVariantMap in a dedicated key in the configuration. (See e.g. relationreferencefactory that does a similar thing for a stringlist). Sorry, getting a bit off-topic here :)

If the above is implemented, there could also be a dedicated boolean key "AddNull" which would be semantically safe.

Would you be able to implement that for merging for QGIS 3 (I guess it's a bit late for QGIS 2 now).


To fix the current behavior, what do you think about this:

We make a hardcoded string __NULL__ which represents NULL when inserted as value (or even straight NULL)? This would be a system configuration independent option with little space for side-effects. And to make configuration easier, a button could be added "Insert NULL value" to make the configuration obvious.

@dgoedkoop
Copy link
Contributor Author

I agree that the value map widget could use some improvements. In addition to a widget-specific null configuration it should perhaps also try to actually use the data type which the attribute actually has. Currently all configuration is done with strings, so that the result after choosing is always a string, which leads to queries like SET int_field = '3', which coincidentally works but probably isn't as correct as it could be.

As for a quick fix, my thought has been that the application-wide null setting is there for a reason, namely that some people apparently really want to write the string 'NULL' into a field. So I think that the value map should also allow to enter that value, if QGis is configured accordingly.

@m-kuhn
Copy link
Member

m-kuhn commented Jul 5, 2016

But this string is nowhere to be written by the user (apart from the configuration). Normally it's written by the user into a text field and the converted to a null value which is appropriate for the backend.

If you think about it in an MVC concept way.

  • The system configured NULL should only be there on the view.
  • In this pull request it is in the model.

And the result is that if you like to write 'NULL' for NULL and your colleague likes to write empty string '' for NULL values and you give him your project it will be broken.

@dgoedkoop
Copy link
Contributor Author

That is true. And perhaps that is a more common problem than that someone really wants to enter the string 'NULL' by using a value map. Ok, I'll see if I can change it to a hard-coded value and add a button, like you suggested. :)

@dgoedkoop
Copy link
Contributor Author

So how about this?

The usage looks like this:
image

Internally the null value is represented as one particular hard-coded GUID. A bit of a hack, but I think it prevents both kinds of problem. If doing it like this, perhaps the GUID should be stored somewhere as a constant, but at the moment the widget itself and the configuration dialog don't seem to share a common header file.

@m-kuhn
Copy link
Member

m-kuhn commented Jul 6, 2016

Wow, this is exactly how I thought it should be!
But now I am afraid merging this huge changeset so close to release.

Can you convince me? ;)

{
tableWidget->setItem( row, 0, new QTableWidgetItem( mit.key() ) );
}
setRow( row, mit.key(), QString( "" ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, there's also a NULL string

@@ -48,13 +49,17 @@ QgsEditorWidgetConfig QgsValueMapConfigDlg::config()
if ( !ki )
continue;

QString ks = ki->text();
if (( ks == QString( "NULL" ) ) && !( ki->flags() & Qt::ItemIsEditable ) )
ks = "{2839923C-8B7D-419E-B84B-CA2FE9B80EC7}";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make this a #define somewhere to avoid the multiple places it's manually reused?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... i.e. just include the config in the widget

@dgoedkoop
Copy link
Contributor Author

Yes, it has turned out a bit bigger than I first expected!

I've done some more testing with a colleague just now. The functionality seems to be ok, but he complained that the value is displayed as "NULL" even if the global null representation setting is different. I think he is right, so I'll fix that.

@m-kuhn
Copy link
Member

m-kuhn commented Jul 6, 2016

Cool, if it's for displaying only it's the right thing to do I think.

Did you consider to expand the editwidget test? https://github.com/qgis/QGIS/blob/master/tests/src/python/test_qgseditwidgets.py

@dgoedkoop
Copy link
Contributor Author

@m-kuhn Thanks for the suggestion! I've added a few unit tests and they did indeed catch a minor issue with my code.

@m-kuhn
Copy link
Member

m-kuhn commented Jul 7, 2016

Thanks a lot!

@m-kuhn m-kuhn merged commit d2c9863 into qgis:master Jul 9, 2016
@dgoedkoop dgoedkoop deleted the valuemapnull branch July 9, 2016 10:36
@dgoedkoop
Copy link
Contributor Author

Great!

What would be great it to make the whole configuration for the Value Map a bit more advanced. At the moment it's just a key-value pair which is saved. This leads to ugly side-effects like leftovers from configurations from other widgets when you start configuring it. The proper way to go would be to move the configuration to a QVariantMap in a dedicated key in the configuration. (See e.g. relationreferencefactory that does a similar thing for a stringlist). Sorry, getting a bit off-topic here :)

I've been thinking about this a bit more, and I cannot think of a really suitable solution here. It is probably desired not to break things when you open a project saved by a previous QGIS version. So, then, a value map saved in the current format needs to be converted on-the-fly to the new format. But such a function would also 'upgrade' those left-overs from other widgets into a value map of the new type, right? So then, not much is solved after all.

@m-kuhn
Copy link
Member

m-kuhn commented Jul 10, 2016

There is the possibility to upgrade on project load. Then it would only affect old configurations and no left-overs. There is a "projectupgrader" class (can't remember the name right now). How does that sound?

Smooth upgrade to 3.0 is not a strict requirement - but from my side appreciated.

wonder-sk pushed a commit to wonder-sk/QGIS that referenced this pull request Mar 12, 2018
)

* Add null handling to value map edit widget (fixes qgis#15215)

* Return QVariant type

* Use hardcoded value for 'null' representation

* Detect "null" value when loading value map from csv; use null QString constructor

* Use configured "null" representation for display in value map

* Use single definition for value map null representation guid

* Added unit test for value map widget and fixed value displaying bug

(cherry picked from commit d2c9863)
wonder-sk pushed a commit to wonder-sk/QGIS that referenced this pull request Apr 12, 2018
)

* Add null handling to value map edit widget (fixes qgis#15215)

* Return QVariant type

* Use hardcoded value for 'null' representation

* Detect "null" value when loading value map from csv; use null QString constructor

* Use configured "null" representation for display in value map

* Use single definition for value map null representation guid

* Added unit test for value map widget and fixed value displaying bug

(cherry picked from commit d2c9863)
wonder-sk pushed a commit that referenced this pull request Apr 16, 2018
* Add null handling to value map edit widget (fixes #15215)

* Return QVariant type

* Use hardcoded value for 'null' representation

* Detect "null" value when loading value map from csv; use null QString constructor

* Use configured "null" representation for display in value map

* Use single definition for value map null representation guid

* Added unit test for value map widget and fixed value displaying bug

(cherry picked from commit d2c9863)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants