Replies: 5 comments 6 replies
Thanks - feedback is always welcome. I'll preface my response by saying that Toga's Document interface is an area that hasn't had as much development as some other APIs. It was built primarily to service the needs of Podium, BeeWare's slide presentation tool. I can't rule out that there are significant improvements possible or needed for Toga's Document API.
To some extent, we're hampered by operating systems here - operating systems think about documents as single files, and there's a lot of internal OS tooling that assumes a document has a document type. That said - some apps will allow you to open a folder as a "project" (or similar) - IDEs, for example, will often let you open a folder. However, even then, there is often a single "file" that can be identified as "the project".
So - a document-based app is just one way to structure an app. A Toga app can have multiple Main Windows; and the lifecycle of the app can be tied to "closing the last window". A Document-based app (i.e., adding document type registrations) is just one way to trigger that behavior. From Toga's perspective, a browser isn't a document-based app. It's an app with multiple main windows.
We're definitely option to suggestions here. As I said previously - the Document interface is an area that hasn't seen as much exercise as other parts of Toga; so if you've got concrete ideas on improvements, we're open hearing suggestions. If your specific case is the ability to open a "folder" as a document type... the fix might be as simple as providing a way to register a document as being "folder based", rather than extension based. The complication with this is that "file open" and "select folder" dialogs are very different. It may turn out that the solution for your use case isn't to think of this as a "document based" app, but an app with it's own abstraction layer around "windows as wrappers around folders of content".
This comes back to the "multi-window" use case. An app doesn't have to have a main window. If you explicitly assign So - what you're describing here is fine - and is essentially what Toga is already doing with Document-based apps. When you request a DocumentWindow opens a new document, DocumentSet has a mechanism for replacing the current window with the new content. The mechanism is slightly different to what you've described here, but fundamentally it's doing the same trick - ensuring that there's a new open window before closing the old one. The only difference is that Toga isn't relying on
If I'm following what you're trying to describe here, then yes - it's fine. You can replace the content of a window whenever you want. Whether that's because a "new document" has been loaded, or because you just don't like the way the window looks any more - window content can be replaced.
As I've indicated above, there's overlap between "document based apps" and Toga's window handling - but the two concepts are very separate. Toga's concept of window handling is independent of using Documents.
I have been able to reproduce this - it looks like it's a rendering problem. The DocumentWindow in is a Main Window, so it does have a menu... the bug appears to be that something in the rendering process is hiding that menu. I've found that if you resize the window, the menu re-appears.
I haven't seen that exception. Can you elaborate on what you did to trigger it? |
|
Many thanks for your reply. After reading your post it seems I misunderstood some of the Toga concepts. For some reason I assumed that Toga's handling of multiple windows was tied to document based apps and I had to adjust Document/DocumentWindow/ DocumentSet to my use case. I now realize that is not the case at all, and I should just implement my own similar functionality e.g. based on the snippets I shared. Thanks for clarifying that. I also misinterpreted the paragraph about assigning None to main_window. I wrote assuming it would open an application with a menu bar but no windows (macOS) while I now realize the documentation actually refers to the case where a window is openend before assigning None to main_window. About the exception, I am not doing anything specific to trigger it, it seems to occur during program startup, and the app seems to keep working. Thanks again for clarifying, Best regards, |
|
W.r.t. the documentapp sample exception: I have submitted a bug report. W.r.t. handling errors in startup(): Below is a workaround by overriding _create_initial_windows() per your suggestion. The code could be moved into startup() but you would still have to override _create_initial_windows to avoid the exception. I am not sure if it is OK to call self.exit() in startup() or _create_initial_windows() however. This is definitely an OK workaround, but it does not seem a good final solution, because of the override of the private method. I do want to point out that this issue is not limited to handling documents or parsing arguments (which was just an example and not my actual use case). In general, real world applications have various reasons to fail in the startup phase. Is there a deeper issue here, that there does not seem to be an easy way to report an error in startup() to the user? Which in the end is a common scenario. Or am I (again ;-) ) missing something? |
Thanks for your thoughts on this. W.r.t provided guarantees (if I interpret what you write you correctly): The error would be in user part of the code and not in Toga part of the code. So I think we can assume that the Toga part is still working correctly, and we can determine upfront if e.g. the application loop is running during the startup method for example. From a user perspective the solution below would already be very useful. This would require
The exit strategy probably requires some thought. This may also interact with how cleanup is handled (e.g. uncaught exception handling, atexits and return out of the main loop). I previously posted about that. In general, I think I would prefer if an exit of the app would return control to the caller of app.main_loop(), if possible of course. That would at least open up options for resource management. |
OK, I see now in #4320 the the current behavior in macOS - a program termination from the event loop - is actually not the intended behavior. That's good.
OK, I had a look at the source code and I understand what you mean. I actually assumed that startup() was called from App.main_loop() and not from App.init(). According to the documentation, startup() must create the main window for the application.
The options are not mutually exclusive. Option 1/ seems as intended / as designed? Option 2/ seems almost supported. At first sight, it seems possible to move window creation that might involve user interaction to App.on_running(), except that you need to avoid the exception involving no windows, see code below. I think this is a better workaround than in my previous post. This is something other Toga users will also be confronted with I think.
Also, I found naming a bit confusing.
You could then easily explain to users:
(But I fully realize this might be a matter of taste.) |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hi all,
I recently experimented with multiple MainWindows and Documents. I wanted to leave some feedback on how I experienced that and also ask some questions.
My use case does not map completely to the Documents case. One reason is that my files are actually (uncompressed) "bundles" (hence I open folders and not files) and also because my open/save/save as/read/write functionality does not entirely map to Toga's).
I was also not able to adapt the Document/DocumentWindow/ DocumentSet functionality to my case because it is very tightly coupled with App. For example, App creates a DocumentSet internally that insists on types/Documents having an extension attribute. So it seems difficult to adapt for the end user. Thinking about this, there are a lot of multiple document interfaces that do not work with files (e.g. browser windows, many other examples). I think that the Document functionality could be made much more broadly applicable by providing more abstract interfaces for Document/DocumentWindow/ DocumentSet and then for example a concrete implementation for files (which would also serve as an example for implementing other kinds of content). In fact, I was a bit surprised by the rigidity given that tables, trees, ... are abstracted in such a flexible way.
I also have some further questions since I must implement my own similar mechanism:
1/ Is an approach like below suitable for keeping the application open in a multiple document interface? It seems to work well, but I am not sure if it is the toga way. In essence, if a main window is about to close, and it is the main window of the app, I swap it out for another one, preventing a close. This seems to work wel for a multiple document interface.
2/ Is an approach like below suitable for swapping documents in a single document interface (single MainWindow)? In essence I group all of the content of the main window in a specific composite widget, and I swap out the entire widget, leaving the main window intact. Again, it seems to work well, but I am not sure it is the toga way and I can just swap out toga.MainWindow.content like that. Alternatives are closing the current window and opening a new one (which works when you are careful about the order of operations when setting main_window) or setting the document of MyDocumentWidget. But I found the one below particularly attractive and simple.
Additionally, I want to point out some potential issues with the documentation and example code.
1/ The page https://toga.beeware.org/en/stable/reference/api/app/ says the text below. This only seems the case when using documents, but the text is not in the section about managing documents. I was misled by that (but that might be my fault). I though that, on macOS, it would create an app with a menu bar an no windows. But this is only the case (sort of) when using document types.
2/ I suspect the document app example on windows might be broken.
In any case, I hope this is useful feedback.
Best regards,
All reactions