Recover file work over #2176

Merged
merged 1 commit into from Jan 19, 2016

Projects

None yet

9 participants

@zonkmachine
Member

Fixes issue: #2174
Edit: I've started a feedback thread in the forum https://lmms.io/forum/viewtopic.php?f=15&t=3479

In summary: Multiple fixes for the recovery file system that introduces clear session states for LMMS.
It won't allow overwriting of recover.mmp if you run multiple instances but it will only do autosave for the first instance of LMMS launched.

recovery-final


Bugs and fixes!

  • If you start LMMS with a recovery file present and don't do anything at all the auto save will write it over with an all empty project after a minute. It's been ticking on in the background. We solve this by starting the timer the very last thing in main() after a project is loaded( if it's not a limited session or auto save is disabled altogether ).
  • When starting if you escape from the recover message the default is to delete recover.mmp This is probably not expected or wanted behaviour for everyone. Escaping from the dialogue had better be non destructive.
    I fix this by defaulting 'Escape' to button 'Exit' instead close the app.
  • If you press yes to recover and immediately shut down LMMS you will not be asked any questions and recover.mmp is deleted. This is a bit rough. Fixed in the new file save dialogue. ( MainWindow::mayChangeProject() message box )
  • If you run multiple sessions of LMMS they will simply take turns to write over recover.mmp :P
    I solve this by introducing the limited session, that will be set if the user press 'Ignore' at the recovery dialogue. This allows you to launch another session that doesn't write to recover.mmp. This way LMMS will launch a slightly limited session which simply turns off autosave for this instance. This together with running autosave() the first thing of all (described below) should minimise the risk of recover.mmp being overwritten.
  • On starting LMMS the autosave() function takes a minute to kick in. This is problematic especially since the introduction of different sessions, because this minute of no backup file is actually a logic state of it's own, and it's an ill defined one. We take care of this by executing MainWindow::autosave() in main() once as a very last step after loading a project, but only if there is no recover file present. For this to work I made MainWindow::autosave() public.
  • Clarity. Brushed up the dialogues involved and update window title to signal session.

I know it's not 100% what users have asked for but it is a solid solution for recover files which has no uncertain states and is hopefully clear enough to use. It's intended as a modification/bugfix for the upcoming 1.2 release.
Separate files for multiple sessions as has been in demand will most likely have to wait until later.
The actual action of the MainWindow::autosave() when it's running however will be one of my next areas to look at.

Last updated on 15 Dec 2015

@zonkmachine
Member

undefined reference to `MainWindow::recoverSessionCleanup()' ... ?

Yeah, I didn't think the last one would pass. I need some feedback here.
Everything was rolling along just fine until I got the mighty fine idea to put some commands in a simple function. these QFile::remove commands works fine in the MainWindow::closeEvent by themselves but not when in the function recoverSessionCleanup()

void recoverSessionCleanup()
{
    // delete recover session files
    QFile::remove( ConfigManager::inst()->recoveryFile() );
    QFile::remove( ConfigManager::inst()->recoveryFile() + ".bak" );
    QFile::remove( ConfigManager::inst()->recoverSessionFile() );
}
void MainWindow::closeEvent( QCloseEvent * _ce )
{
    if( mayChangeProject(true) )
    {
        if( isRecoverSession() )
        {
            recoverSessionCleanup();
        }
        _ce->accept();
    }
    else
    {
        _ce->ignore();
    }
}

Travis says:

Linking CXX executable tests

../src/CMakeFiles/lmmsobjs.dir/gui/MainWindow.cpp.o: In function `MainWindow::closeEvent(QCloseEvent*)':

/home/travis/build/LMMS/lmms/src/gui/MainWindow.cpp:1283: undefined reference to `MainWindow::recoverSessionCleanup()'

collect2: ld returned 1 exit status

make[3]: *** [tests/tests] Error 1

make[2]: *** [tests/CMakeFiles/tests.dir/all] Error 2

make[1]: *** [tests/CMakeFiles/tests.dir/rule] Error 2

make: *** [tests] Error 2
@zonkmachine
Member

I squashed it down to two commits and reverted to the last working state by commenting out the function above, recoverSessionCleanup() .
Changes so far are:

  • Forces question on exit with recover.mmp
    Before you could just open and close the recovery file with no question asked and the files would be deleted on exit.
  • Only one instance of LMMS can access recover.mmp
  • Separate question on close for a modified file and a recovered, for clarity.

What doesn't work?
EDIT: FIXED!
If you open a project or create a new default one during a recover session, which forces the right message box, you will now remain in a recover session and be prompted as such at the next message box. The program will also not clear up any of the files involved.

@Wallacoloo
Member

By the way, it looks like all you need to do is change

void recoverSessionCleanup()
{
[...]
}

to

void MainWindow::recoverSessionCleanup()
{
[...]
}
@zonkmachine
Member

You mean like ALL the other functions... :-P

@zonkmachine
Member

@Wallacoloo Thanks! Now I have a working patch for the recovery file. It turned out to need a little bit more than the 5 - 10 lines I was hoping for but there are many places to exit an ongoing project and you need to cover all those events.

What I've done is create a file RECOVER which lets other instances know that they don't need to care about recover.mmp. There is also a bool m_recoverSession which we set to make LMMS aware of that it is doing recover work. We can check session state whith 'MainWindow::isRecoverSession()'

  • Forces question on exit with recover.mmp Before you could just open and close the file with no question asked and the files would be deleted on exit. This works if you 'exit the recover session' <by Ctrl + N>, <Ctrl + q>, <Ctrl + o> or with equivalent menu action.
  • Only one instance of LMMS can access recover.mmp
  • Separate question on close for a modified file and a recovered, for clarity.
  • Sett window title to further distinguish session from a new default project ( next commit )

Issues:

  • { FIxed ] If a recover session crash, or is terminated from the command line, RECOVER remains and needs to be manually removed. Maybe a message box on start to check if there really is an ongoing recover session that can then remove the files. I'll work on this next.
  • Has the potential to be annoying...
@zonkmachine
Member

Like this the user can recover from a locked recover session.

recovermessagebox2

@zonkmachine zonkmachine changed the title from [WIP] Always ask upon closing when the file is recovered to Always ask upon closing when the file is recovered Jul 12, 2015
@zonkmachine
Member

This is now a working fix for #2174 and is best described here #2176 (comment)
I can't force it into any unwanted states and it takes good care of recover.mmp
If it's annoying to no ends? Don't know, works for me for now.

@tresf
Member
tresf commented Jul 13, 2015

"Open" might be misleading.... As an example, here's what VIM says:

E325: ATTENTION
Found a swap file by the name ".test.txt.swp"
          owned by: tres   dated: Sun Jul 12 20:26:57 2015
         file name: ~tres/test.txt
          modified: no
         user name: tres   host name: ubuntu-1204
        process ID: 5934 (still running)
While opening file "test.txt"
             dated: Wed May 14 23:18:12 2014

(1) Another program may be editing the same file.  If this is the case,
    be careful not to end up with two different instances of the same
    file when making changes.  Quit, or continue with caution.
(2) An edit session for this file crashed.
    If this is the case, use ":recover" or "vim -r test.txt"
    to recover the changes (see ":help recovery").
    If you did this already, delete the swap file ".test.txt.swp"
    to avoid this message.

Swap file ".test.txt.swp" already exists!
[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:

-Tres

@tresf
Member
tresf commented Jul 13, 2015

BTW, I'm not a fan of the RECOVER file. I think we should refrain from using a fixed file name and instead keep our current implementation and fix it rather than adding even more recovery temp files.

@zonkmachine
Member

"Open" might be misleading.... As an example, here's what VIM says:

I scavenged among the default buttons. I haven't looked into adding custom buttons to QMessageBox yet,
I wanted button names, Recover, Discard and... well, something else than ignore.

BTW, I'm not a fan of the RECOVER file. I think we should refrain from using a fixed file name and instead keep our current implementation and fix it rather than adding even more recovery temp files.

OK. I'm not too happy about the extra file either but it kind of work. I can just remove it and have a more general message like the one from VIM about the dire consequences of running multiple instances.

@zonkmachine
Member

There is a one line fix for this that does exactly what the title proposes.
add Engine::getSong()->setModified(); after loading recover.mmp in main().

This would mean you wouldn't be able to just open and close recover.mmp and it's gone, which was what triggered the bug report in the first place. We could do this for 1.2 and do a more complete fix later. Being in a freeze and all. I think however it's a good idea to really have separate messages.

@zonkmachine
Member

Simplified. File RECOVER is gone as is the new Messagebox.


Changes in summary:

  • Forces question on exit with recover.mmp Before you could just open and close the file with no question asked and the files would be deleted on exit. This works if you 'exit the recover session' , , or with equivalent menu action.
  • Separate question on close for a modified file and a recovered one, for clarity.
  • Set window title to further distinguish session from a new default project.
@zonkmachine zonkmachine and 1 other commented on an outdated diff Jul 16, 2015
src/gui/MainWindow.cpp
{
return( true );
}
- QMessageBox mb( tr( "Project not saved" ),
- tr( "The current project was modified since "
+ // Separate message strings for modified and recovered files
+ QString messageTitleRecovered = tr( "Recovered project not saved" );
+ QString messageRecovered = tr( "This project was recovered from the "
+ "previous session. It is currently "
+ "unsaved and will be lost if you don't "
+ "Save it. Do you want to save it now?" );
+
+ QString messageTitleUnsaved = tr( "Project not saved" );
@zonkmachine
zonkmachine Jul 16, 2015 Member

What happens with the already translated strings "Project not saved" and "The current project..." when I move it to a variable? I didn't change the text. Do I need to do anything to link it to the old string?

@midi-pascal
midi-pascal Jul 16, 2015 Contributor

Since the strings are translated at creation time by using tr() it should be Ok. You can then copy to an other variable because the content is already translated.
So this should work as expected :)

@zonkmachine
zonkmachine Jul 16, 2015 Member

Cool, thanks! 8)

@zonkmachine
Member

recoverqoriginal

Here's the messagebox in master. I've struck a somewhat odd problem. If you try and close the messagebox with the [x] recover.mmp is discarded. In a basic messagebox the closeEvent() isn't defined so you have to take care of this yourself but in the simpler version of messagebox with default buttons closeEvent() takes care of closing the window just fine but also seem to return the enum of the button with the highest value. OK is lowest...:
http://doc.qt.io/qt-4.8/qmessagebox.html#StandardButton-enum
Edit! just don't use abstractButton solves everything.

@zonkmachine
Member

[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:
What's the difference of quit and abort in this context. One closes the program and the other opens a default empty project?

messagebox2 3

Buttons renamed. I changed 'escape/close' button to a new 'close' button instead of as today, 'no' (discard).
In this sense it works pretty much as it did before but has unwanted responses fixed and a bit more text. Old message is reused however and if the translation isn't updated it should still be pretty clear.

@tresf
Member
tresf commented Jul 18, 2015

"Close" may be a but confusing, as it is often associated with the closing of a dialog...

@zonkmachine
Member

Quit or Abort then?

@tresf
Member
tresf commented Jul 18, 2015

Yeah... I think. Quit, or Quit LMMS.

Quit LMMS seems a bit overkill, but the action is clear. We could use a wildcard to replace LMMS with application name too, if desired.

@zonkmachine
Member

I prefer Quit over Quit LMMS then.

We could use a wildcard to replace LMMS with application name too, if desired.

You lost me there. What other app?

@tresf
Member
tresf commented Jul 18, 2015

Oh, I just meant the global name "LMMS" to prevent hard-coding.

@zonkmachine
Member

messagebox2 5

@zonkmachine
Member

messagebox2 6

I've reimplemented the possibility to open a limited session without autosave that was lost with the file RECOVER. I'm not happy with the name 'Open' for the button though.
There is one more thing now that's on my mind. autosave() hits in first after a minute and during this time plenty can happen. Like launching a second instance of LMMS. One way to go about this is to trigger autosave() once after setting up the session in main.cpp . I've tried this and it works just fine but I had to make autosave() public. I'm currently looking through the Qt manual to see if it's possible to run the timer much like a do-while loop. Execute immediately first run and then timer on.

@Umcaruje
Member

I'm not happy with the name 'Open' for the button though.

I think 'Ignore' would be a good name for that button.

@zonkmachine
Member

I think 'Ignore' would be a good name for that button.

That's better yes.

@zonkmachine
Member

messagebox2 7

Yeah, 'Ignore' has the right touch to it. 8)

I'm currently looking through the Qt manual to see if it's possible to run the timer much like a do-while loop.

A no go. I pushed the first version instead.

@zonkmachine
Member

Closing the messagebox ( Escape / [x] / Alt+F4 ) right now defaults to 'Quit'. With the new button perhaps Ignore should be the default response?

@zonkmachine zonkmachine changed the title from Always ask upon closing when the file is recovered to Recover file work over Jul 19, 2015
@musikBear

now this is already addressed, and i should properly keep my big trap shut, but what is wrong with a concatenated name for the recover-file
The recover of 'myProject.mmpz' becomes 'myProjectRecover.mmp'
Then overwrite and all that is not an issue at all..
(a need for temporary manual cleanup by user is, and i understand that this would be a weighted decision

But recover-autosave should definitively be in users setting: 1..20mins between autosave / disable

@zonkmachine
Member

I'm first shaping up the existing code. Then I'm going to look into what new functions to take in. Remember that we are working toward the 1.2 release and are in a freeze so what I'm basically doing is fixing everything that is a bug in the context of the original code.

@zonkmachine
Member

recovermenu3 0

I fear my home brew layout with tabs and line breaks isn't going to work well with translations so I went shopping for something better. As it turns out qmessagebox knows HTML... :P
I don't know if qlinguist can manage one chunk of HTML thrown at it like this though.

@tresf
Member
tresf commented Jul 19, 2015

I don't know if qlinguist can manage one chunk of HTML thrown at it like this though.

Perhaps just translate the cells and hard-code the layout?

@zonkmachine
Member

Looks like Qt should handle it though. From here:
http://stackoverflow.com/questions/16664915/how-to-use-html-inside-of-translatable-strings-in-qt

The ts file is XML. If you want to use HTML tags you will
need to escape them. For example: <source>&lt;b&gt;text&lt;/b&gt;</source>

Note that the recommended way of managing translations
in Qt is to run the lupdate tool on your source code and have
Qt generate the .ts file, in which case this will be done automatically.
@tresf
Member
tresf commented Jul 19, 2015

I would not recommend putting any nonessential HTML in the translation file. The HTML can be static.

@Umcaruje
Member

Closing the messagebox ( Escape / [x] / Alt+F4 ) right now defaults to 'Quit'. With the new button perhaps Ignore should be the default response?

I think that Quit is better than Ignore, since some users might expect that closing the dialog would function as either 'Discard' or 'Ignore', and there is no way to differentiate from those two without looking for 'recover.mmp' in your lmms folder. If the behaviour is 'Quit', its pretty straightforward and the user has to choose.


One minor thing: I think you should either have icons on all buttons, or have no icons at all. Right now it doesn't look very consistent.

@grejppi
Member
grejppi commented Jul 19, 2015

This is not reversible!

Compare:

This is not reversible.

Which would you prefer, a dialog that just states the facts, or one that yells at the user's face?

@tresf
Member
tresf commented Jul 19, 2015

How about

This is NOT reversible!!!!

@zonkmachine
Member

I would not recommend putting any nonessential HTML in the translation file. The HTML can be static.

Nothing fancy. Just header, bold and table tags and a star trek face palm meme as pop-up when you choose the wrong button.

One minor thing: I think you should either have icons on all buttons, or have no icons at all. Right now it doesn't look very consistent.

I will comply.

Which would you prefer, a dialog that just states the facts, or one that yells at the user's face?

They're both totally awesome! You pick!

How about

This is NOT reversible!!!!

Totally awesome!

@zonkmachine
Member

I updated the first post to sum up the work so far.

@Spekular
Contributor

There seems to be some inconsistency in what the recover file is called. We
have "recover the file", "the recover file" and "the restored files".
I think "recovered" is more accurate than "restored", and singular is
probably better than plural. That said I don't like how "the recover file"
sounds (to me), so I'd suggest "recovered file"/"recovery file".

To adress the naming of the file, I don't think anyone has suggested we do
it the way blender does, by creating fileName.blend1 (and sometimes
.blend2, maybe so if it crashes while overwriting one backup you still have
the other). I think maybe fileName.mmpz.bak or some similar added extension
would be better, but maybe that's just me.

@zonkmachine
Member

There seems to be some inconsistency in what the recover file is called. We have "recover the file", "the recover file" and "the restored files". I think "recovered" is more accurate than "restored", and singular is probably better than plural. That said I don't like how "the recover file" sounds (to me), so I'd suggest "recovered file"/"recovery file".

Thanks! I've renamed the stray 'restored', changed to singular and settled for 'recovery file'.
I'll look into naming the recover file after an existing project name.

@tresf
Member
tresf commented Jul 20, 2015

Renaming the recover file can make this task tougher. It would likely re-introduce the double-recovery file design unless we have an "untitled.mmpz" in the lmms home for unnamed files, and meanwhile each file checked for a doppelganger before opening. I too believe this to be ideal, but might be out of the scope of this PR.

P.S. @zonkmachine, tremendous work on the reception to feedback here. Top notch. 👍

@zonkmachine
Member

@tresf Thanks!

Renaming the recover file can make this task tougher.

Tried some quick hacks and backed off. It will be for another day.

I too believe this to be ideal, but might be out if the scope of this PR.

This! I see new issues pop up all the time and need to keep focus. I'd prefer to get something merged first before expanding the work. I'm also thinking of waiting with the HTML work until later. I like the look of it but there are too many question marks there right now.
Also, there are other things to fix and I'm currently locked up here.

@zonkmachine
Member

New bug. Probably my favorite so far.
In master try this:

  1. Launch LMMS with recover.mmp present ( one that you don't mind to lose... )
  2. Wait.

That's it. You don't need to do anything at all. After one minute autosave() is launched without main() having handed over a proper project so recover.mmp is overwritten with an empty project with no tracks.

Edit: Fixed in 5f83cfb

@Spekular
Contributor
@zonkmachine
Member

@Spekular Thanks!


I'm now trying to remove the limited session to simplify the code. Basically what it means anyway is to load a normal LMMS session but without the file deletion action that happens on exit. We can simply remove this from a normal session and just load a normal session on 'ignore'. You still have the option to delete files on launch by hitting 'Discard' and this should be enough.
I'll try and simplify the code as much as possible now and see what bugs there is left. There hasn't been mush compile problems on this project but on the other hand a major juggling of logic states so my brain is in a somewhat bruised state right now.

@zonkmachine zonkmachine changed the title from Recover file work over to [WIP] Recover file work over Jul 23, 2015
@zonkmachine
Member

I'm now trying to remove the limited session to simplify the code

Fail! That didn't work. I also tried to squash the commits down so they more clearly reflected the work done but so far that hasn't been successful. Furthermore I tried to produce a graf of what's been done here but libreoffice snap to grid function won after an uneven battle for some two hours and what I've got now is ascii art instead. But only for main.cpp so far.

Anyway, I think it's working now as I intended it. Basically the 'Ignore' function makes out some ~80% of whatever pain that is involved in this pull request. If we would just fix the recovery function up in the most straightest way that would mean forcing the user to deal with the recovery file straight away and that would probably be annoying. Now you can press 'Ignore if you for instance want to run another session simultaneously or whatever your heart tells you. I just ran three sessions at once, playing and editing, and only the first wrote to recover.mmp . It needs testing off course and still has code commented out left in.

Off course, all this is, strictly speaking, a matter of form as there will be no crashes in the final 1.2 release.

@zonkmachine zonkmachine commented on an outdated diff Jul 23, 2015
include/MainWindow.h
@@ -30,6 +30,7 @@
#include <QtCore/QList>
#include <QMainWindow>
+#include "ConfigManager.h"
@zonkmachine
zonkmachine Jul 23, 2015 Member

I don't remember why this moved... I think it was when I had problems compiling ( earlier in this thread ).
Moved back.

@zonkmachine zonkmachine commented on an outdated diff Jul 23, 2015
include/MainWindow.h
@@ -149,6 +187,8 @@ public slots:
void toggleWindow( QWidget *window, bool forceShow = false );
void refocus();
+ bool m_recoverSession;
+ bool m_limitedSession;
@zonkmachine
zonkmachine Jul 23, 2015 Member

I started out with recoverSession and then added 'limited' along the way. Maybe this should be done with an enum instead, something like:
enum Session { Normal, Recover, Limited }; ?

@musikBear

Sadly no one responds to your forum post. You know my feeling about 'recover', so i have not felt it necessary to post - i have made it 'sticky' though, so it should stay in focus of all visitors
Should it be moved to 'Announcements'

@tresf
Member
tresf commented Jul 24, 2015

Should it be moved to 'Announcements'

I'll let @zonkmachine decide, but he's had quite a bit of valuable feedback here, the forum post can probably be taken off of sticky.

@zonkmachine
Member

@musikBear Thanks, sticky isn't needed.

@zonkmachine
Member

I don't know if qlinguist can manage one chunk of HTML thrown at it like this though.

Perhaps just translate the cells and hard-code the layout?

It looks like that message box isn't translated anyway so right now it isn't a big thing anyway. I'd just go with either of them. The HTML version looks better but I'm pretty happy with the way it looks now. One sneaky way to do it is to pop the HTML version in there an lift out the tr() stuff since no strings are translated anyway, so we can go back and change that later when we know how it works.

@zonkmachine
Member

Edit: pngs updated

Here are the basic layout of the changes in main() .

[Before]
lmms_main cpp_before

[After]
lmms_main cpp_after

@tresf
Member
tresf commented Jul 24, 2015

It looks like that message box isn't translated anyway so right now it isn't a big thing anyway. I'd just go with either of them. The HTML version looks better but I'm pretty happy with the way it looks now.

Well, that's not a great reason to leave it as-is. Any translation of this dialog has the potential to break formatting, and it is not fair to put that on the translators, is it?

If HTML displays properly, I would propose something like this (pseudocode).

QString("
    <html><table>
        <tr><td>%1</td><td>%2</td></tr>
        <tr><td>%3</td><td>%4</td></tr>
    </table></html>
").arg(
    tr("Foo"), tr("Bar"),
    tr("Fizz"), tr("Buzz")
);

Edit: The other option is to make a new multi-option dialog class that handles this for us.

-Tres

@zonkmachine
Member

OK. I'll have another look at the HTML version.

@zonkmachine
Member

If HTML displays properly, I would propose something like this (pseudocode).

QString("
    <html><table>
        <tr><td>%1</td><td>%2</td></tr>
        <tr><td>%3</td><td>%4</td></tr>
    </table></html>
").arg(
    tr("Foo"), tr("Bar"),
    tr("Fizz"), tr("Buzz")
);

Those were clear instructions, thanks!
HTML pushed with translation strings.

@tresf
Member
tresf commented Jul 24, 2015

This looks nice. I feel like we may have a redundant MainWindow::tr( ) around the whole html text though. Am I seeing that right?

@zonkmachine
Member

a redundant MainWindow::tr( )

Ah! From the first translation efforts.

@zonkmachine
Member

Like the last commit. A bit better I think.
if it's a limited session the timer isn't started in main() and when we run occasional autoSave() to counter for a changing of project or starting a new one, etc. we do it with runAutoSave() instead which filters out when it's a limited session or when auto save isn't enabled at all.

@zonkmachine zonkmachine commented on an outdated diff Jul 26, 2015
src/core/main.cpp
+ {
+ file_to_load = recoveryFile;
+ gui->mainWindow()->setRecoverSession();
+ qDebug("Recover session...");
+ }
+ else if( answer == QMessageBox::Ignore )
+ {
+ if( autoSaveEnabled )
+ {
+ gui->mainWindow()->setLimitedSession();
+ qDebug("Limited session...");
+ }
+ }
+ else // ::Abort
+ {
+ return 0;
@zonkmachine
zonkmachine Jul 26, 2015 Member
else // ::Abort
{
    return 0;
}

Do I need to go 'delete app;' on this one before returning?

@zonkmachine
Member

I'm testing it with multiple instances now under gdb.
I don't think this backtrace is from anything I did...

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffceca1700 (LWP 13720)]
0x00000000004bd4d1 in FxMixer::masterMix(float (*) [2]) ()
(gdb) bt
#0  0x00000000004bd4d1 in FxMixer::masterMix(float (*) [2]) ()
#1  0x00000000004dc6b2 in Mixer::renderNextBuffer() ()
#2  0x00000000004dc974 in Mixer::fifoWriter::run() ()
#3  0x00007ffff685a32f in ?? () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#4  0x00007ffff7bc4182 in start_thread (arg=0x7fffceca1700) at pthread_create.c:312
#5  0x00007ffff41dd47d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
(gdb)
@midi-pascal
Contributor

@zonkmachine For sure your code is not the cause of this SIGSEGV. I think you hit issue #2192 which is a really nasty one since it happens randomly.

@zonkmachine
Member

@midi-pascal Thanks! That looks like the same case.


Unless you do something silly now like:

  • saving your files in the working directory...
  • while taking advance money for jobs you do...
  • ant trusting on the recovery function to also be your only backup system...
  • and you get to remix your favourite artist https://www.youtube.com/watch?v=MRiFMLSq13U ...!

I see how that could be a problematic case on many levels. :)

I'm running out of cases to test but I'm going to try and load defective files and other odd stuff to see what happens.

@zonkmachine
Member

Some cases that I set as goal for the project and that now works fine.

Test case 1:

1 - Open a known track in LMMS
2 - Close it from the terminal thus creating a reference recovery file
3 - Open a couple of separate sessions and choose 'Ignore'. From within these session just do whatever related to opening and saving files ( but don't open the reference project! ).
4 - Close down all instances of LMMS
5 - Start LMMS again, choose recover and confirm that the file is the same as the reference project.

Test case 2:

1 - Repeat 1 and 2 from the case above.
2 - Start LMMS and in settings, switch 'Enable auto save feature' off.
3 - Close LMMS
4 - Repeat step 3 from test case 1 above and observe that you will be presented with the same recovery menu as previously, but now when you choose ignore you are in fact working in a normal LMMS session with auto save off. No reminders to save in the title bar, just the usual message box on exiting your work.
5 - Close all instances of LMMS and confirm that you get the reference project when you re-run LMMS and choose 'Recover'.

@zonkmachine
Member

Fixed a bug when loading with a file as argument.


Session cleanup
Session cleanup

Sometimes cleanup is done twice. This keeps us from having to do unnecessary checks in a whole lot of places. Probably. I don't quite remember what the issue was here but I'll have another go at fixing it.
It won't be noticed anyway because those debug messages aren't staying for long.

Edit! This is how it works. To simplify things I made the function recoverSessionCleanup() it not only cleans out recover files that are no longer needed but also resets the recover session state in the case we want to go straight to another project after doing recovery work. recoverSessionCleanup() is called in a number of places so sometimes these multiple uses can overlap. For instance if you want to close and discard a recovery session. Then 'cleanup' is called first in canChangeProject() after which it's called again in closeEvent(). This is just one case I've found and is in any case totally a feature and a trade off to make the logic of it all manageable. I'm not totally happy about the name recoverSessionCleanup() though as it's not only called during recover sessions but also after a normal session with recovery action that is closed normally.

@zonkmachine zonkmachine changed the title from [WIP] Recover file work over to Recover file work over Jul 26, 2015
@zonkmachine
Member

Text and layout. This is what the message boxes look like now.

messagebox1

  • The messages are still largely unchanged from the first version that I just tossed in there to have something to work with. Probably the 'Recover' button explanation needs to be reworked a bit as it doesn't properly fit it's role.
  • The title text is wider than the table. Maybe some padding there?
  • Should I use normal text for the message line instead of header style?
  • Using the word 'Exit' instead of the default 'Abort' has one down side. The standard buttons are translated and overriding the name gives us one more string to translate.
  • @Umcaruje What would be good icons here? I'm thinking maybe something with an exclamation mark for ignore and then maybe the 'door with arrow' thing for exit.

closemsgrecovery

closemsgchanged

These two works as they are now I think. The original 'Project not saved' message is still used when it applies. In case the work is both recovered and changed, you get the 'Recovered project not saved' message.

The debug messages are all coming out. I was thinking of maybe leaving some of them like the ones that indicate which session it is but that would probably just be confusing. Especially the 'Limited session' one as limited isn't used anywhere else but as an internal term. The user has just pressed a button and it should be obvious what happens.

Recover session...
Limited session...
@8tab
Contributor
8tab commented Jul 27, 2015

I think you should replace sentence: "Please don't run multiple instances of LMMS when you do this" with "Please close other instances of LMMS when you do this". Moreover you can detect if there is other instance of LMMS running and disallow recovering.

@zonkmachine
Member

But it's OK to recover a file with other instances running.

@8tab
Contributor
8tab commented Jul 27, 2015

Ok, so do we really need this message then?

@zonkmachine
Member

Well. You can open a file with recover and then open other sessions with ignore and that's all fine. If you open LMMS normally in one session and then go for a coffee, comes back and forgets about your session already running, now you are presented with a recover message box if you start a new LMMS window. That could be confusing. Detecting other running instances of LMMS sounds lika a very good idea but I'd have to look it up as I've never done that. Not in a way that would be approved around here anyway ;)
I think we could cover this with a well phrased message instead.

@Umcaruje
Member

Should I use normal text for the message line instead of header style?

I think that would look nicer, it looks a bit too large and bold to me rn.

@Umcaruje What would be good icons here? I'm thinking maybe something with an exclamation mark for ignore and then maybe the 'door with arrow' thing for exit.

Maybe a crossed circle for ignore (🚫)? 'door with arrow' thing sounds good for exit.

@zonkmachine
Member

recovernoparagraph

Normal letters in message and padding on the side. I also tried to give a little padding in between the message and the table but so far no success.

@zonkmachine
Member

Here's info on the subset of HTML 4 used in Qt 4.8
http://doc.qt.io/qt-4.8/richtext-html-subset.html

@zonkmachine
Member

Maybe a crossed circle for ignore (🚫)? 'door with arrow' thing sounds good for exit.

msgboxexit

I tried the existing exit.png (from Quit in the menu) I'm a bit sceptic to the 'no entry' take on ignore but I can't think of any other icons that would fit either.

@zonkmachine
Member

@tresf
I can set custom icons with button->setIcon( embed::getIconPixmap( "icon" ); but how do I get the icons into the 'embed' function?
Right now I can't add new icons, only use the ones that are already in the system. I have added icons before but this time it doesn't seem to work to just drop them in the default themes folder.

@tresf
Member
tresf commented Aug 3, 2015

@zonkmachine I'm not sure we hard code them anywhere... Which folder are you adding them to? If you overwrite a known-good pixmap, is it reflected in the software? You might be accidentally pulling from the wrong data directory.

@zonkmachine
Member

A ghost in the machine... It eventually just turned up. :-/ -?

noentrymsgbox

There are better looking no entry signs out there, I know.

@tresf
Member
tresf commented Aug 3, 2015

👍

There are better looking no entry signs out there, I know.

Easy to replace. The critics can make a new one. :)

@zonkmachine
Member

Squash it down to one commit? ...

@tresf
Member
tresf commented Aug 3, 2015

I would say yes. 👍

@zonkmachine
Member

🚜

@zonkmachine
Member

@tresf Any more comments on this one? I suggest we merge this now.

@tresf
Member
tresf commented Aug 14, 2015

The only other feedback that I have which I've just noticed now is the amount of functions this adds to MainWindow.cpp and the amount of boolean member variables that get added. It seems like a lot of functions and variables for what appears to be a state variable storing a few mutually exclusive flags.

@zonkmachine
Member

and the amount of boolean member variables that get added.

I commented on this one third up from here:
#2176 (comment)

@tresf
Member
tresf commented Aug 14, 2015

I commented on this one third up from here [...]

Ah yes...

@tresf
Member
tresf commented Sep 15, 2015

@zonkmachine this has some merge conflicts that must be resolved prior to merging. Can we also add the state variable as well via #2176 (comment)?

Marking for 1.2 milestone.

@tresf tresf added the gui label Sep 15, 2015
@tresf tresf added this to the 1.2.0 milestone Sep 15, 2015
@zonkmachine
Member

On the case.

@zonkmachine
Member

1 - I'll try and update this but I've never fixed a merge conflict before.

2 - Can we also add the state variable as well via #2176 (comment)?

I won't have time to fix that right now. Id rather sneak back later and fix it.

@tresf
Member
tresf commented Oct 9, 2015

1 - I'll try and update this but I've never fixed a merge conflict before.

It usually is a matter of doing a rebase and finding the conflicting lines and making them what they should be.

For example, if you changed:

// Foo.cpp
QString foo = "bar";

and in the mean time someone else changed:

// Foo.cpp
QString foo = "bar1111";

Then you may have something like this in Foo.cpp

<<<<<<<
- QString foo = "bar";
=======
+ QString foo = "bar1111";
>>>>>>>

And then you have to decide which line to keep, since the commit history will have to remain. In most cases, the new value is the one you want and just remove the <<<<<<</=======/>>>>>>> stuff, although if a function or class is refactored, it can be much more complicated to merge a conflict.

Once fixed, I believe you do a git add Foo.cpp and then continue your rebase, although there are quite a few tutorials for this that go into greater detail.

@tresf
Member
tresf commented Oct 9, 2015

I won't have time to fix [the state variable] right now. Id rather sneak back later and fix it.

@Wallacoloo and @michaelgregorius can chime in, but I'd rather not expose 8 new functions to MainWindow.h for a single dialog, that seems like overkill.

@zonkmachine
Member

OK. I'll try a rebase and will have a look at the functions in the weekend.

@Wallacoloo Wallacoloo and 1 other commented on an outdated diff Oct 14, 2015
include/MainWindow.h
@@ -81,6 +81,42 @@ class MainWindow : public QMainWindow
///
bool mayChangeProject(bool stopPlayback);
+ void autoSaveTimerStart()
+ {
+ m_autoSaveTimer.start( 1000 * 60 ); // 1 minute
+ }
+
+ bool isRecoverSession()
+ {
+ return m_recoverSession;
+ }
@Wallacoloo
Wallacoloo Oct 14, 2015 Member

I believe most of these functions can be kept private.

@zonkmachine
zonkmachine Dec 10, 2015 Member

I'll look into it.

@Wallacoloo
Member

@tresf One could make an argument that these functions would be better suited for GuiApplication.h since they mostly act in the background rather than visibly affecting anything inside the main window. By this same logic, most of the autosave functionality should be moved there as well. If we were designing things from scratch, this is what I would propose, but since MainWindow seems to already be taking on the responsibility of all 'etc' tasks, it almost seems best to keep it here for consistency.

Perhaps one improvement though is that the functions like setLimitedSession(), resetLimitedSession() could be reduced to one setLimitedSession(bool isLimitedSession) function.

@zonkmachine
Member

One could make an argument that these functions would be better suited for GuiApplication.h

I'm going to do the simplest possible adaptation to get this committed so this is probably not for me right now.

@zonkmachine
Member

@zonkmachine this has some merge conflicts that must be resolved prior to merging. Can we also add the state variable as well via #2176 (comment)?

Merge conflicts fixed. I'm looking into the suggested improvements now.

@zonkmachine
Member

OK. I swapped the bools for a session state int/enum.

Edit2! The "enum SessionState" commit isn't working (crashes).

@zonkmachine
Member

Edit2! The "enum SessionState" commit isn't working (crashes).

I haven't been able to repeat the crashes I saw. It seem to work as intended. I disabled 'open last project' on limited session as the last project in this case probably was the crashed one and should be opened with recover.

@zonkmachine
Member

@tresf @Wallacoloo
I've updated the pull request and ditched the session state bools. I haven't looked into public functions that can be made/kept private. I call most of them both from main.cpp and MainWindow.cpp

@tresf
Member
tresf commented Dec 15, 2015

Thanks. Much cleaner with the enum state. I only had one comment to make. Interested in hearing from @Wallacoloo.

@zonkmachine
Member

Squashed and done. I've updated the Issue/OP.
The tests I devised in #2176 (comment) is still passed.

@zonkmachine
Member

Just a last minute tweak. I changed the name of function recoverSessionCleanup() to sessionCleanup() .

@zonkmachine
Member

@tresf I think I'm done here. I've found other things related to the auto save function to work on but I think it's probably better to get this committed and start from a fresh pull request.

@tresf
Member
tresf commented Dec 17, 2015

@zonkmachine much cleaner, thanks.

I'll give some time for final comments prior to merging.

@zonkmachine
Member

@tresf @Wallacoloo @Umcaruje
I want to move on here and I don't think there is anything else to do on this PR.
One last change though. I reverted one line as I had accidentally changed how the .bak/backup file worked. Not touching that file no more.

@tresf
Member
tresf commented Jan 19, 2016

@zonkmachine sorry for the delay. Merging, adding to 1.2 changelog. 👍

@tresf tresf merged commit d30a7df into LMMS:master Jan 19, 2016

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
@zonkmachine zonkmachine deleted the zonkmachine:recoverFileFix branch Jan 19, 2016
@zonkmachine zonkmachine restored the zonkmachine:recoverFileFix branch Jan 22, 2016
@zonkmachine zonkmachine deleted the zonkmachine:recoverFileFix branch Jan 22, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment