Remove KDELibs4Support from KSudoku
ClosedPublic

Authored by stikonas on Apr 27 2017, 11:11 PM.

Details

Summary

Port KNetAccess to KIO.
Change signature of Serializer::load, Serializer::loadCustomShape to use QString& instead of QString*
Change signature of Serializer::store: pass errorMsg
Remove unused function.
Port remaining Qt4 calls such as toAscii() or setAcceptsHoverEvents(),

Test Plan

Game can be played, tested loading and saving of current game.

Diff Detail

Repository
R417 KSudoku
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.
There are a very large number of changes, so older changes are hidden. Show Older Changes
ltoscano requested changes to this revision.Apr 27 2017, 11:46 PM

Non-core sudokus are not loaded ("Unable to download file.") and then the program crash:

[KCrash Handler]
#6  0x000055b4c9440908 in QVector<int>::size() const ()
#7  0x000055b4c944f6a0 in ksudoku::Puzzle::hasSolution() const ()
#8  0x000055b4c945fafb in ksudoku::WelcomeScreen::generatePuzzle() ()
#9  0x000055b4c9460ebd in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (ksudoku::WelcomeScreen::*)()>::call(void (ksudoku::WelcomeScreen::*)(), ksudoku::WelcomeScreen*, void**) ()
#10 0x000055b4c9460e4f in void QtPrivate::FunctionPointer<void (ksudoku::WelcomeScreen::*)()>::call<QtPrivate::List<>, void>(void (ksudoku::WelcomeScreen::*)(), ksudoku::WelcomeScreen*, void**) ()
#11 0x000055b4c9460d5b in QtPrivate::QSlotObject<void (ksudoku::WelcomeScreen::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) ()

There may be other issues.

This revision now requires changes to proceed.Apr 27 2017, 11:46 PM
stikonas updated this revision to Diff 13899.Apr 28 2017, 12:20 AM
stikonas edited edge metadata.

Added KIO::Overwrite to all download jobs. It seems that loading now works.

ouwerkerk edited edge metadata.Apr 28 2017, 8:53 AM

Looks basically sane, don't have enough knowledge of the real inner workings of ksudoku to offer much more feedback than this on the proposed changes.

However we should probably take the time investigate a couple of follow-up changes:

  1. Certain serialisation/deserialisation functions may be consolidated into a couple of new shared functions to reduce the amount of duplicated logic there.
  2. There is a somewhat oddly located "globals.h" which is included all over the place and smells. What to do about this?
  3. KSudoku::updateShapesList() should be cleaned up, to not do hacky things with file paths when there is perfectly good Qt API for this already.
src/gui/ksudoku.cpp
899

We should probably take the opportunity to tackle this here.
The QDir() could be used to get a proper path that is safe to pass to QUrl::fromLocalFile().
Starting with the QDir() call above at line 886:

QDir dest(destDir);
dest.mkpath(dest.path());
 // some of the following code elided...
KIO::file_copy( Url, QUrl::fromLocalFile(dest.filePath(Url.fileName())));
src/gui/serializer.cpp
402

The body of this function is basically the same as the next one which returns a Game instead. Maybe we should extract and consolidate the bulk of this to a new shared function?

465

Is this safe? The docs for QTemporaryFile say:

The file is guaranteed to have been created by this function (i.e., it has never existed before).

Therefore: is it possible that two successive calls to .open() refer to different temporary files? Wouldn't it be better to have a const bool openedOK = tmpFile.open(); before the first check and then use that, as the QTemporaryFile is never closed in between?

721

You should probably return false; here.

src/gui/symbols.cpp
41

According to the QChar docs the result of trying .toLatin1() on something that isn't 'Latin 1' will be 0.
More generally depending on how this code path is reached, quite a lot of invalid 'Latin 1' chars exist and may be returned.
As a result trusting c - 'a'; blindly may be a bit dangerous.

It's probably better to do a range check and if the character falls outside it return either VACANT or UNUSABLE.

Non-core sudokus are not loaded ("Unable to download file.") and then the program crash:

[KCrash Handler]
#6  0x000055b4c9440908 in QVector<int>::size() const ()
#7  0x000055b4c944f6a0 in ksudoku::Puzzle::hasSolution() const ()
#8  0x000055b4c945fafb in ksudoku::WelcomeScreen::generatePuzzle() ()
#9  0x000055b4c9460ebd in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (ksudoku::WelcomeScreen::*)()>::call(void (ksudoku::WelcomeScreen::*)(), ksudoku::WelcomeScreen*, void**) ()
#10 0x000055b4c9460e4f in void QtPrivate::FunctionPointer<void (ksudoku::WelcomeScreen::*)()>::call<QtPrivate::List<>, void>(void (ksudoku::WelcomeScreen::*)(), ksudoku::WelcomeScreen*, void**) ()
#11 0x000055b4c9460d5b in QtPrivate::QSlotObject<void (ksudoku::WelcomeScreen::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) ()

There may be other issues.

Looks like basically the same bug being tickled as with invalid QUrls. It seems to me there is a more fundamental memory management issue with Puzzles/Games that gets tickled if particular initialisation steps fail.
That is something we should investigate and fix more thoroughly later.

stikonas marked 2 inline comments as done.Apr 28 2017, 11:34 AM
stikonas added inline comments.Apr 28 2017, 11:37 AM
src/gui/serializer.cpp
402

Maybe do refactoring in a separate patch? This needs to fix calls to these functions too then... But yeah, that sounds good.

stikonas updated this revision to Diff 13909.Apr 28 2017, 11:38 AM

Slightly updated patch fixing most comments except for two. Maybe address them separately? As they change behaviour.

ouwerkerk requested changes to this revision.Apr 28 2017, 2:42 PM

I've added a few more comments. Before landing this change please review the one on copyright in particular, as I'm not certain the way a few copyright statements were consolidated is sound (or rather that the implications are what was intended).

src/gui/ksudoku.cpp
5

This change may not be sound:

As I understand it:

  • Copyright 2012 means copyright on the work for the year 2012
  • Copyright 2012, 2015 means copyright on the work for the years 2012 and 2015.
  • Copyright 2012-2015 means copyright on the work for the years 2012 thru 2015 (inclusive), i.e. 2012, 2013, 2014 and 2015.

Since the previous version did not claim copyright over 2013-2014, perhaps we should either leave both lines as is or maybe consolidate using Copyright 2012, 2015 instead?

src/gui/serializer.cpp
402

Agreed.

472

Maybe I'm losing track here, but I think success is no longer relevant? Because the code now short-circuits by returning early, we only get here on success. The following if() check has therefore become redundant as well.

This revision now requires changes to proceed.Apr 28 2017, 2:42 PM
stikonas marked 2 inline comments as done.Apr 28 2017, 2:46 PM
stikonas updated this revision to Diff 13934.Apr 28 2017, 2:54 PM
stikonas edited edge metadata.

Fixed copyright.

Removed bool success when it is no longer necessary.

ouwerkerk accepted this revision.Apr 28 2017, 4:16 PM

Looks good to me. Let's see what tosky thinks.

ltoscano added inline comments.Apr 28 2017, 11:34 PM
src/gui/ksudoku.cpp
866

Rechecking the code, this is part of KSudoku::loadCustomShapeFromPath(), but... is that method really used somewhere?

stikonas added inline comments.Apr 29 2017, 12:17 AM
src/gui/ksudoku.cpp
866

Indeed, it looks like it is completely unused.

➜ src git:(frameworks) ✗ grep -R loadCustomShapeFromPath
gui/ksudoku.h: void loadCustomShapeFromPath();
gui/ksudoku.cpp:void KSudoku::loadCustomShapeFromPath()

stikonas updated this revision to Diff 13955.Apr 29 2017, 12:21 AM

Remove unused function

stikonas marked an inline comment as done.Apr 29 2017, 12:21 AM

It does appear to be unused, OTOH its purpose appears to be to allow people to import new game variant types (shapes).
Logically that should have been wired up to a Get Hot New Stuff button/dialog for people to exchange custom puzzle variants.
Is that a feature we'd like to offer?

If I'm not mistaken, this is where the only call to that method was removed:
https://commits.kde.org/ksudoku/06cb470b229a49f714042f22094161a19ec26a73

It is not related to GHNS, thought, but about directly opening a local shape.

It is worth noting that the GHNS integration has been disabled at least since:
https://commits.kde.org/ksudoku/32e159a2a288fe9f991d85f36214c32917017010
(still in playground/games, so never worked in released versions by kde.org, only probably as standalone from sourceforge)

So: if you want to load a certain home-made Sudoku game, you can do it from File->Open (unless loadCustomShapeFromPath does something more). For more complex Sudoku, maybe yes, GHNS support could be useful, but wouldn't it be a different code anyway?

src/gui/serializer.cpp
408

Is some feedback required here?

446

Is some feedback required here?

ouwerkerk added a comment.EditedApr 29 2017, 1:10 PM

unless loadCustomShapeFromPath does something more

That is precisely what it does ;)

  1. It extracts data from an archive
  2. And installs this to the the writable location of XDG_DATA_DIRS underneath a "ksudoku" directory
  3. Then it calls updateShapesList();

updateShapesList(); is where we detect custom game variants by trawling through XDG_DATA_DIRS to find "ksudoku" directories with *.desktop files indicating custom game variants...
... My conclusion is that this function was meant for GHNS integration (or something similar to it) and for people to exchange custom puzzle types (game variants).

This is different from loading/saving an actual game or puzzle; this is about saving custom rules for *generating* custom puzzles.

EDIT to add:

Please note: I'm not categorically opposed to removing this functionality, but before we do so I'd like to be certain we are not removing something that we would consider the basis of a desirable feature. So to that end, perhaps the most relevant question is: is letting the user dynamically extend the repertoire of game variants by importing a package (archive) something we want to support in ksudoku? Specifically when we consider GHNS? Do we want to promote people designing custom sudoku variants or do we think so few people will bother it is better to support new variants via patches to the sudoku source (if at all)?

ltoscano accepted this revision.Apr 29 2017, 1:45 PM

Discussed on IRC:

  • GHNS manages the archives, so the code wouldn't be useful anyway;
  • if QTemporaryFile fails, even without missing feedback, probably something worse is going on. Nevertheless this could be addressed later, and also in other functions (like the serialization ones).
This revision is now accepted and ready to land.Apr 29 2017, 1:45 PM
stikonas updated this revision to Diff 13983.Apr 29 2017, 1:47 PM

Add some feedback in came QTemporaryFile::open fails.

ouwerkerk added inline comments.Apr 29 2017, 1:47 PM
src/gui/serializer.cpp
446

What happens if you set *errorMsg ? ;)

Does that yield better UX than a KMessageBox?

453

Considering tosky's earlier comment above:

What happens if you set *errorMsg ? ;) Does that yield better UX than a KMessageBox?

stikonas marked an inline comment as done.Apr 29 2017, 1:47 PM
stikonas updated this revision to Diff 13984.Apr 29 2017, 1:52 PM

Use errorMsg

stikonas marked an inline comment as done.Apr 29 2017, 1:53 PM
ltoscano added inline comments.Apr 29 2017, 2:02 PM
src/gui/serializer.cpp
402

When loadCustomShape is called, errorMsg is set to NULL, so setting it in the case of error may explode.

697

I guess that errorMsg can be used here too.

710

Same as above for errorMsg.

stikonas updated this revision to Diff 13986.Apr 29 2017, 2:07 PM

Make sure errorMsg is not empty.

stikonas marked an inline comment as done.Apr 29 2017, 2:08 PM
ouwerkerk added inline comments.Apr 29 2017, 2:13 PM
src/gui/serializer.cpp
404

This needs an if() guard:

if(errorMsg) {
    *errorMsg = i18n("Unable to download file: URL is empty.");
}
411

This needs an if() guard:

if(errorMsg) {
    *errorMsg = i18n("Unable to create temporary file.");
}
419

This needs an if() guard:

if(errorMsg) {
    *errorMsg = i18n("Unable to download file.");
}
450

This needs an if() guard:

if(errorMsg) {
    *errorMsg = i18n("Unable to create temporary file.");
}
458

This needs an if() guard:

if(errorMsg) {
    *errorMsg = i18n("Unable to download file.");
}
697

Just make sure not to forget the if() guard!

710

Just make sure not to forget the if() guard!

stikonas edited the summary of this revision. (Show Details)Apr 29 2017, 2:14 PM
stikonas edited the test plan for this revision. (Show Details)
ltoscano requested changes to this revision.Apr 29 2017, 2:15 PM

I wonder if instead of all the if (), can't we just change the signatures to pass a real QString reference instead of a pointer?

This revision now requires changes to proceed.Apr 29 2017, 2:15 PM

I wonder if instead of all the if (), can't we just change the signatures to pass a real QString reference instead of a pointer?

Yes we can. In that case the callers need to be similar to:

const QString errorMsg;
const auto ptr = doTheCall(..., errorMsg);
if(!ptr) {
  KMessageBox ....
}

Do we really need the auto pointer? (just to check if that would bump some requirement, maybe just for one usage is not needed)

Do we really need the auto pointer? (just to check if that would bump some requirement, maybe just for one usage is not needed)

Of course not: in each case the appropriate type should be used instead. ;)

For load() the specific check is a bit different:

const QString errorMsg;
const Game game = doTheCall(... errorMsg)
if(!game.puzzle()) {
  KMessageBox ...
}

Do we really need the auto pointer? (just to check if that would bump some requirement, maybe just for one usage is not needed)

Of course not: in each case the appropriate type should be used instead. ;)

For load() the specific check is a bit different:

const QString errorMsg;
const Game game = doTheCall(... errorMsg)
if(!game.puzzle()) {
  KMessageBox ...
}

I think the QString shouldn't be const. We want to modify it inside load.

This comment was removed by ouwerkerk.

I think the QString shouldn't be const. We want to modify it inside load.

You are, of course, entirely correct.

stikonas updated this revision to Diff 13991.Apr 29 2017, 2:38 PM
stikonas edited edge metadata.
stikonas edited the summary of this revision. (Show Details)
ltoscano added inline comments.Apr 29 2017, 2:41 PM
src/gui/ksudoku.cpp
648

really last bit: the KMessageBox also here when !game.isValid(), as it happens later.

stikonas updated this revision to Diff 13992.Apr 29 2017, 2:49 PM

Add one more KMessageBox.

stikonas updated this revision to Diff 13993.Apr 29 2017, 2:59 PM
stikonas updated this revision to Diff 13994.
stikonas updated this revision to Diff 13996.Apr 29 2017, 3:08 PM
stikonas updated this revision to Diff 13998.Apr 29 2017, 3:22 PM
stikonas edited the summary of this revision. (Show Details)
stikonas edited the summary of this revision. (Show Details)
ltoscano accepted this revision.Apr 29 2017, 3:25 PM

Thanks!

This revision is now accepted and ready to land.Apr 29 2017, 3:25 PM
stikonas updated this revision to Diff 14000.Apr 29 2017, 3:34 PM

whitespace

ouwerkerk accepted this revision.Apr 29 2017, 3:37 PM

Looks good to me!

This revision was automatically updated to reflect the committed changes.