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

Decent workaround to dirty a project after bad layer handling #8657

Merged
merged 1 commit into from
Dec 13, 2018

Conversation

elpaso
Copy link
Contributor

@elpaso elpaso commented Dec 12, 2018

Fixes #20743

@nyalldawson I don't know why https://github.com/qgis/QGIS/blob/master/src/app/qgisapp.cpp#L5809 but that is basically blocking a plain setDirty call from within the bad layer handlers.

If you can think of a better/cleaner solution than a timer (and that do not involve an API change in the bad layer handlers), please let me know.

@nyalldawson
Copy link
Collaborator

Here's a potential alternative approach:

  1. Add a "layersChanged" signal to QgsHandleBadLayersHandler, and emit this signal from QgsHandleBadLayersHandler::handleBadLayers if layers were changed by the QgsHandleBadLayers dialog

  2. In Qgisapp.cpp:1242, store a reference to the QgsHandleBadLayersHandler instance as a new QgisApp member, mAppBadLayersHandler.

  3. In QgisApp::addProject, tweak the constructor to setup a connection to mAppBadLayersHandler layersChanged signal, something like this:

std::unique_ptr< QgsProjectDirtyBlocker > dirtyBlocker = qgis::make_unique< QgsProjectDirtyBlocker >( QgsProject::instance() );
QObject connectionScope; // manually control scope of layersChanged lambda connection - we need the connection automatically destroyed when this function finishes
bool badLayersHandled = false;
connect( mAppBadLayersHandler, &QgsHandleBadLayersHandler::layersChanged, &connectionScope, [&badLayersHandled] { badLayersHandled = true; });

and then at the end of that function

dirtyBlocker.reset(); // allow project dirtying again
if ( badLayersHandled )
    QgsProject::instance()->setDirty(true);
return true;

This avoids the timer approach, whilst still keeping the original intention of the dirty blocking. What do you think?

@elpaso
Copy link
Contributor Author

elpaso commented Dec 13, 2018

Here's a potential alternative approach:

Looks good.

QObject connectionScope; // manually control scope of layersChanged lambda connection - we need the connection automatically destroyed when this function finishes

Do we really need this? The signal will never be emitted again after the initial bad layer handling.

@nyalldawson
Copy link
Collaborator

The signal will never be emitted again after the initial bad layer handling.

Isn't the bad layer handler tied to the life of the project instance? (I.e. forever?)

@elpaso
Copy link
Contributor Author

elpaso commented Dec 13, 2018

Yes, but what are you trying to avoid here? Multiple connections to the same lambda any time QgisApp::addProject is executed? Would a Qt::UniqueConnection work in this case (maybe it's the lambda to prevent this) ?

@nyalldawson
Copy link
Collaborator

Exactly - unique connections aren't possible with lambdas

@elpaso
Copy link
Contributor Author

elpaso commented Dec 13, 2018

std::call_once would probably also help here.

@luipir
Copy link
Contributor

luipir commented Dec 13, 2018

std::call_once would probably also help here.

I would prefer using the standard life-cycle mechanism of event connection... e.g. connect to connectionScope variable life-cycle as proposed by @nyalldawson . I'ts a kind of trick but a clean trick (btw IMHO too many lambdas respect moving and documenting in .h private or static method, but it's a question of style)

@elpaso
Copy link
Contributor Author

elpaso commented Dec 13, 2018

IMHO explicit is better than implicit: std::call_once would clearly indicate what's happening, while the connectionScope trick requires knowledge of Qt and a comment to understand what's for (at least for me).

I'm generally in favor of using std:: over Qt's black magic whenever I can, but I'll follow Nyall's advice here.

@nyalldawson
Copy link
Collaborator

I'd have to see the code, but I don't think call once will help here. If you use it to only setup the connection on the first project read, then a permanent connection is being created with the lambda capturing a reference to a local variable - which will go out of scope after the function ends the first time and subsequent reads would crash.

@elpaso
Copy link
Contributor Author

elpaso commented Dec 13, 2018

@nyalldawson you are right, I'll go for your proposed solution.

@elpaso elpaso force-pushed the bugfix-20743-badlayers-dirty branch from 1af3845 to 158cae3 Compare December 13, 2018 10:35
@elpaso elpaso force-pushed the bugfix-20743-badlayers-dirty branch from 158cae3 to 0042cc0 Compare December 13, 2018 10:40
@elpaso elpaso changed the title Ugly workaround to dirty a project after bad layer handling Decent workaround to dirty a project after bad layer handling Dec 13, 2018
@elpaso elpaso added this to the 3.6 milestone Dec 13, 2018
@elpaso elpaso merged commit 8c07c99 into qgis:master Dec 13, 2018
@elpaso elpaso deleted the bugfix-20743-badlayers-dirty branch December 13, 2018 13:58
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.

3 participants