Outreachy Dec 2023 - Implement Qt/KDE Frameworks theming using native Qt widgets

Michael Weghorn m.weghorn at posteo.de
Thu Dec 7 08:20:00 UTC 2023


Hi Omkar, all,

On 2023-12-06 18:47, Omkar Acharekar wrote:
>         My Name is Omkar Acharekar. I am excited to share with you that 
> I will be working this next months on "Implement Qt/KDE Frameworks 
> theming using native Qt widgets (Weld interface)" project as part of the 
> Outreachy internship, under mentorship of Michael Weghorn and Heiko Tietze.

welcome again, it's great to have you! :-)

>       The project aim is to refine the UI of Qt/KDE Frameworks by making 
> use of native Qt widgets through the Weld interface. (...)

For reference, these are the Outreachy pages of accepted interns and 
Omkar's project:

https://www.outreachy.org/alums/2023-12/
https://www.outreachy.org/outreachy-december-2023-internship-round/communities/libreoffice/#implement-qtkde-framework-theming-using-native-qt-

The project is based on an earlier idea from Jan-Marek for a GSoC project:
https://wiki.documentfoundation.org/Development/GSoC/Ideas_without_a_mentor#Implement_qt5_/_kf5_theming_using_native_Qt_widgets_(Weld_interface)

For anyone interested, I'm copying parts of 2 emails I sent to Omkar 
earlier with some more thoughts on the project. If anyone has any 
further thoughts, please don't hesitate to add them.

Michael


On 2023-11-23 18:58, Michael Weghorn wrote:

> Some notes and code pointers in addition to what the project description mentions:
> 
> ## Qt
> 
> Did you work with Qt or any other UI toolkit before? If you didn't, I'd recommend to experiment a bit with Qt to get an impression/some experience with the toolkit outside of the LibreOffice context. (What a native Qt application looks like, how the widgets work,...)
> 
> Qt widgets doc:
> https://doc.qt.io/qt-6/qtwidgets-index.html
> Tutorial:
> https://doc.qt.io/qt-6/widgets-tutorial.html
> 
> 
> ## VCL plugins
> 
> To support good integration for different platforms/desktop environments, LibreOffice uses a concept of so-called "VCL plugins", in particular on Linux.
> 
> vcl/README.md has some more information.
> 
> In order to choose what VCL plugin to use, the SAL_USE_VCLPLUGIN environment variable can be used.
> 
> E.g. if you start LibreOffice with
> 
>     SAL_USE_VCLPLUGIN=gtk3 ./instdir/program/soffice.bin --writer
> 
> , the "gtk3" VCL plugin will be used, and likewise for the other plugins (gen/gtk3/gtk4/kf5/kf6/qt5/qt6).
> 
> For the project, the Qt-based VCL plugins are relevant (qt5, qt6, kf5/kf6).
> 
> They share most of the code. Relevant directories:
> vcl/inc/qt{5,6}
> vcl/qt{5,6}
> vcl/unx/kf{5,6}
> 
> To enable building of these VCL plugins, use the corresponding autogen.sh switch, e.g. `--enable-kf5`
> (see also `./autogen.sh --help` output)
> 
> ## Weld (API)
> 
> The weld API is an abstraction layer used in LibreOffice to support different UI toolkits.
> 
> * include/vcl/weld.hxx is the central header file with declarations for the weld API.
> * Implementing this API using native Qt widgets is basically the task of the Outreachy project.
> * weld::Widget is the basic widget and more complex widget types derive from that.
> * class weld::Builder is responsible for creating the different widgets, e.g. `weld::Builder::weld_message_dialog` creates a message dialog, `weld::Builder::weld::button` creates a button,...
> * weld::Builder and weld::Widget have purely virtual methods, the actual implementation is in different subclasses that use a specific widget toolkit/library.
> * vcl/inc/unx/gtk/gtkinst.hxx and vcl/unx/gtk3/gtkinst.cxx are a good starting point to see how this is done for the Gtk implementation that uses native Gtk widgets.
> * `SalInstanceBuilder` is the implementation using LibreOffice's own VCL toolkit, currently also used by the Qt-based VCL plugins.
> (vcl/inc/salvtables.hxx and  vcl/source/app/salvtables.cxx are good starting points.)
> * There's also a `JSInstanceBuilder` (vcl/inc/jsdialog/jsdialogbuilder.hxx) used for Collabora Online [1], which can give some more ideas on what a specific implementation can look like.
> 
> ## User interface definitions
> 
> LO's user interface is mostly defined in .ui files that can be opened and edited in Glade ( https://glade.gnome.org/ ).
> Potentially helpful:
> https://wiki.documentfoundation.org/Development/Create_new_dialog_in_Impress
> 
> The .ui file format that LO uses is the one that Gtk applications also use themselves.
> 
> Looking at the .ui files of a few sample dialogs (both, in glade and at the "plain" XML file) and experimenting with them a bit (e.g. change some properties, insert an additional widget) can be useful to get an understanding of how this works.
> 
> Basically, the .ui files (or elements therein) are processed by the weld::Builder mentioned above to create the corresponding widgets.
> 
> A simple example is the dialog that shows when you try to close LO with a document open that has unmodified changes:
> 
> UI file: sfx2/uiconfig/ui/querysavedialog.ui
> C++ code: sfx2/source/doc/QuerySaveDocument.cxx
> 
> (`git grep <UI_FILE_NAME>` is usually helpful to find the corresponding C++ source file.) 


On 2023-12-04 21:43, Michael Weghorn wrote:

> I don't have an ultimate plan of how to implement the whole project myself. Part of the project is to identify a workable approach. This likely involves identifying potential single steps and taking them, and possibly tweaking the direction a little along the way as needed.
> 
> A part of the challenge is that it's not easy to have a "quick win" in the sense of having a visual result after just taking a few small steps.
> But I think something like the following could be good start and basis for the further work:
> 
> 1) As mentioned in my previous email, `SalInstanceBuilder` is the `weld::Builder` implementation that is currently used by the Qt-based VCL plugins as well. That builder creates/uses VCL widgets. In order to use native Qt widgets instead, a new builder will have to be implemented for the Qt based VCL plugins, e.g. called `QtInstanceBuilder`.
> A first step might be to implement a `QtInstanceBuilder` that derives from `SalInstanceBuilder` and initially doesn't do anything different, but just lets the base class handle everything.
> 
> Then, make sure that the qt-based VCL plugins use that one.
> Notice how `SalInstance::CreateBuilder` is responsible for creating the corresponding builder. Since `QtInstance` currently doesn't override that method, the `SalInstance` implementation gets used.
> 
> While implementing this by itself will not change the behavior, having that skeleton should be a good basis for the upcoming steps - when it will be time to override the base class implementations (and *maybe* even get rid of the base class in the end).
> 
> 
> 2) In order to use native Qt widgets for (almost) the whole UI, basically weld::Widget and all of its subclasses and all of the weld::Builder methods will ultimately have to be implemented. That is quite a lot. One way to have something to work with and see results relatively early may be to start with less complex dialogs that just use a limited set of widgets.
> 
> Simple message dialogs look like good candidates to start with.
> `weld::MessageDialog` is the corresponding class in the weld API. Initially I wouldn't focus too much about implementing the actual functionality of every single method of the class and its base classes, but start with dummy implementations for most of the methods (i.e. implementations that do nothing or return a dummy value), and just implement the most important ones, which are likely:
> 
> * weld::Dialog::run -> runs/executes the dialog
> * weld::MessageDialog::set_primary_text
> * weld::MessageDialog::get_primary_text
> 
> For the native Qt implementation, implementing e.g. a class called `QtInstanceMessageDialog` that uses `QMessageBox` [1] as the native Qt widget might be a workable solution to start with at least.
> Note the QMessageBox hierarchy, e.g. QDialog [2] is the direct base class, wich in turn has QWidget [3] as its base class.
> 
> [1] https://doc.qt.io/qt-6/qmessagebox.html#ButtonRole-enum
> [2] https://doc.qt.io/qt-6/qdialog.html
> [3] https://doc.qt.io/qt-6/qwidget.html
> 
> Try to identify which methods in the Qt API can be used to implement the functionality from the weld API. Sample questions for the 2 examples above:
> 
> * How do I set a message in the message dialog?
> * How do I run/execute the message dialog?
> 
> This question and finding proper ways to match the weld API to Qt API is something that will likely show up for every single widget you'll implement and be a crucial part of the project.
> 
> If/When it's not (yet) easy to get visible results in LibreOffice, implementing a small sample Qt program that uses the corresponding widget and double-checking it behaves as expected may be helpful to get a better understanding/feeling that can help for implementing the LibreOffice side.
> 
> I would suggest to implement every weld interface in a single Qt class, e.g.
> 
> * weld::Widget -> QtInstanceWidget
> * weld::Container -> QtInstanceContainer
> * ...
> * weld::MessageDialog -> QtInstanceMessageDialog
> 
> As mentioned, I would start with dummy implementations for most of the methods initially. This can be completed later.
> 
> 
> 3) Once the skeleton for QtInstanceMessageDialog (or whatever the class will be called) is in place, identify a way to create/see one such dialog when running LibreOffice. Once that's done, there's a first visual result and something to test and further improve!
> 
> One example is the dialog that shows when modifying a document without saving, then pressing Alt+F4 or trying to close the application another way. (See code pointers for both, the .ui file and the C++ implementation from my previous email.)
> 
> As you can see in `ExecuteQuerySaveDocument`, this dialog is created via `weld::Builder::weld_message_dialog`.
> 
> However, there are even simpler message dialogs that don't even require that method to be implemented in the weld::Builder.
> 
> See `Application::CreateMessageDialog` and how it calls `SalInstance::CreateMessageDialog` to create a dialog. By overriding this method in the QtInstance, it might be possible to get one of these message dialogs to show without even having to implement the corresponding weld::Builder methods in QtInstanceBuilder first.
> `git grep Application::CreateMessageDialog` should help to identify some places where such message dialogs are used.
> 
> 
> Does that help for now? Please don't hesitate to ask further questions.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <https://lists.freedesktop.org/archives/libreoffice/attachments/20231207/7dfb7211/attachment.sig>


More information about the LibreOffice mailing list