ENB: Adding "file not saved" dialogs in leoserver.py

52 views
Skip to first unread message

Edward K. Ream

unread,
Aug 1, 2021, 7:01:29 AM8/1/21
to leo-editor
In this Engineering Notebook post, I'll discuss how Leo handles "file not saved" dialogs and how to do roughly the same thing in leoInteg.  See leoInteg issue #142.

Background

The problem is to issue warnings about unsaved .leo files when vs-code is about to close. Alas, leoInteg can not issue "file not saved" warnings directly. vs-code does not tell leoInteg that vs-code is about to close!!

Félix tells me that a workaround is possible. leoInteg starts leoserver.py in a separate process that won't automatically die when vs-code dies. At present, leoserver.py kills itself when it detects a broken connection. The idea is to have leoserver.py issue the warnings (and save the files!) before dying.

Related code in Leo

When Leo itself quits, Leo's shutdown logic eventually calls LeoFrame.promptForSave for every unsaved (dirty) .leo file. The LeoFrame class is the base class of all frames, so promptForSave is a gui-independent method.

promptForSave calls g.app.gui.runAskYesNoCancelDialog, so the task is to make runAskYesNoCancelDialog functional in leoserver.py.

Note: It would be wrong to change runAskYesNoCancelDialog directly in Leo's NullGui class because Leo's unit tests (and maybe other code) expect the NullGui class not to wait for user input. Therefore, leoserver.py should monkey-patch runAskYesNoCancelDialog.

leoserver.py accesses Leo's code via Leo's bridge. Some experiments will show what happens if the client (of leoBridge.py) closes a dirty .leo file. I suspect that the leoBridge.py does not call promptForSave.

Implementing runAskYesNoCancelDialog

leoInteg can not assume that the leoInteg user has installed Qt. However, for prototyping I will assume that Qt is available. Even so, raising LeoQtGui.runAskYesNoCancelDialog isn't entirely trivial: it will involve instantiating (parts of) a Qt gui in leoserver.py.

When the Qt dialog works, I'll turn my attention to implementing runAskYesNoCancelDialog using python's Tk package. In general, leoInteg can assume that python contains the Tk package. Implementing runAskYesNoCancelDialog in Tk will take some work. Leo already uses Tk to implement g.EmergencyDialog. However, this class implements something like Gui.runAskOkDialog. Not exactly what we want.

Summary

leoInteg needs help to warn the user when closing unsaved .leo files.  leoserver.py knows when vs-code has closed and can issue the desired warnings with help from leoBridge.py.

leoserver.py will monkey-patch NullGui.runAskYesNoCancelDialog to raise a visible, functional warning dialog. As I write this, I see that the "Cancel" option should not be available. There is no way to tell vs-code not to quit! So the monkey-patched code will look and work like LeoQtGui.runAskYesNoDialog.

Some easy experiments will reveal how leoBridge.py can call LeoFrame.promptForSave.  NullFrame objects are subclasses of LeoFrame, so calling c.frame.promptForSave will raise the desired dialogs.

In short: leoserver.py will:

- monkey-patch LeoFrame.promptForSave so that it raises a visible, functional warning dialog. The code will use Qt if available, falling back to Tk otherwise.
- call c.frame.promptForSave for every unsaved open commander that leoBridge.py is managing.

All questions, comments, and corrections are welcome.

Edward

tbp1...@gmail.com

unread,
Aug 1, 2021, 10:02:03 AM8/1/21
to leo-editor
The save "dialog" could be console-based like in the old days.  For each open outline a line would be emitted:

Do you want to save unsaved-file.leo (Y/N)? Y

That might be considerably easier to implement than a GUI-style dialog, and TK wouldn't need to be imported if Qt weren't available.

Edward K. Ream

unread,
Aug 1, 2021, 10:40:51 AM8/1/21
to leo-editor
On Sun, Aug 1, 2021 at 9:02 AM tbp1...@gmail.com <tbp1...@gmail.com> wrote:
The save "dialog" could be console-based like in the old days.  For each open outline a line would be emitted:

Do you want to save unsaved-file.leo (Y/N)? Y

That might be considerably easier to implement than a GUI-style dialog, and TK wouldn't need to be imported if Qt weren't available.

I don't think that will work. Remember that leoInteg uses a vs-code console to show output from the server.

Edward

tbp1...@gmail.com

unread,
Aug 1, 2021, 11:21:55 AM8/1/21
to leo-editor
I was thinking that the server would put up its own console window just for this purpose.  It could do this when it discovers that vs-code has gone away (or whenever else it liked, really). 

Edward K. Ream

unread,
Aug 1, 2021, 12:15:58 PM8/1/21
to leo-editor
On Sun, Aug 1, 2021 at 10:21 AM tbp1...@gmail.com <tbp1...@gmail.com> wrote:
I was thinking that the server would put up its own console window just for this purpose.  It could do this when it discovers that vs-code has gone away (or whenever else it liked, really). 

Good idea! It should be a better fallback than using Tk.

Happily, monkey-patching a Qt dialog into the NullGui class is straightforward:

1: Copy LeoQtGui.runAskYesNoCancelDialog into the server, along with the necessary Qt-related imports.

2: The actual monkey-patch is:

# Create a minimal qt application.
g.app.use_splash_screen = False  # Suppress the splash screen.
qt_app = LeoQtGui()
g.funcToMethod(runAskYesNoCancelDialog, NullGui)

This works with zero changes to Leo's core.

Edward

Edward K. Ream

unread,
Aug 1, 2021, 12:33:32 PM8/1/21
to leo-editor
On Sunday, August 1, 2021 at 11:15:58 AM UTC-5 Edward K. Ream wrote:

> Happily, monkey-patching a Qt dialog into the NullGui class is straightforward:

The second comment in #1208 shows my test code. It's simple enough.

Edward

tbp1...@gmail.com

unread,
Aug 1, 2021, 1:35:09 PM8/1/21
to leo-editor
Just for interest, here is how I have been adding a method to an existing instance (here, c), rather than also to its parent class:

def select_card(self, gnx):
    #... body of function

c.select_card = select_card.__get__(c)

Edward K. Ream

unread,
Aug 1, 2021, 6:13:08 PM8/1/21
to leo-editor
On Sun, Aug 1, 2021 at 12:35 PM tbp1...@gmail.com <tbp1...@gmail.com> wrote:
Just for interest, here is how I have been adding a method to an existing instance (here, c), rather than also to its parent class:

Thanks. It would indeed be simpler to patch the single instance (g.app.gui) instead of the NullGui class.

Edward

Edward K. Ream

unread,
Aug 1, 2021, 6:53:55 PM8/1/21
to leo-editor
On Sunday, August 1, 2021 at 11:15:58 AM UTC-5 Edward K. Ream wrote:
On Sun, Aug 1, 2021 at 10:21 AM tbp1...@gmail.com <tbp1...@gmail.com> wrote:
I was thinking that the server would put up its own console window just for this purpose.  It could do this when it discovers that vs-code has gone away (or whenever else it liked, really). 

Good idea! It should be a better fallback than using Tk.

On second thought, raising a Tk dialog is probably better than messing with console input.

Edward

Félix

unread,
Aug 2, 2021, 3:56:29 PM8/2/21
to leo-editor
Edward saves the day again! :)

I'm just back from vacation and am feeling great about fishing the last remaining 2-3 issues ! 

So...  I'm going to modify leointeg on branch "boltex/issue142", to not force-kill the server anymore. 

Then, I'm going to work on Leo's branch "felix-server4"  to have the server detect a "user disconnect" event, to then follow up with what Edward just made in this comment : open up tk-or-qt dialog(s) to ask the user about unsaved files. 

Let's hope this works! (fingers crossed)
--
Félix

Edward K. Ream

unread,
Aug 2, 2021, 5:11:57 PM8/2/21
to leo-editor
On Mon, Aug 2, 2021 at 2:56 PM Félix <felix...@gmail.com> wrote:
Edward saves the day again! :)

I'm just back from vacation and am feeling great about fishing the last remaining 2-3 issues ! 

Excellent. I'm glad my code fits in with the plan!

Edward
Reply all
Reply to author
Forward
0 new messages