Difference between revisions of "Defining menus and toolbars (KDE3 Architecture)"

From Trinity Desktop Project Wiki
Jump to navigation Jump to search
imported>Eliddell
m (-Applicable to TDE (redundant), float TOC on the right to save space)
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
  +
<div style="float: right;">__TOC__</div>
== Introduction ==
 
   
While the [[../Action_Pattern|action pattern]] allows to encapsulate
+
While the [[Action Pattern (KDE3 Architecture)|Action Pattern]] allows to encapsulate
 
actions triggered by the user in an object which can be "plugged" somewhere in
 
actions triggered by the user in an object which can be "plugged" somewhere in
 
the menu bars or toolbars, it does not by itself solve the problem of
 
the menu bars or toolbars, it does not by itself solve the problem of
Line 14: Line 14:
 
and tool bars (coded in XML). Without modifying any source code, menus
 
and tool bars (coded in XML). Without modifying any source code, menus
 
can be simply customized by adjusting an XML file. Furthermore, it helps
 
can be simply customized by adjusting an XML file. Furthermore, it helps
to make sure that standard actions (such as <tt>File-&gt;Open</tt> or
+
to make sure that standard actions (such as <code>FileOpen</code> or
<tt>Help-&gt;About</tt>) appear in the locations suggested by the style guide.
+
<code>HelpAbout</code>) appear in the locations suggested by the style guide.
 
XMLGUI is especially important for modular programs, where the items
 
XMLGUI is especially important for modular programs, where the items
 
appearing in the menu bar may come from many different plugins or parts.
 
appearing in the menu bar may come from many different plugins or parts.
   
KDE's class for toplevel windows,
+
Trinity's class for toplevel windows,
[http://api.kde.org/3.5-api/kdelibs-apidocs/kdeui/html/classKMainWindow.html KMainWindow],
+
[http://trinitydesktop.org/docs/trinity/tdelibs/tdeui/html/classTDEMainWindow.html TDEMainWindow],
 
inherits
 
inherits
[http://api.kde.org/3.5-api/kdelibs-apidocs/kdeui/html/classKMainWindow.html KXMLGUIClient]
+
[http://trinitydesktop.org/docs/trinity/tdelibs/tdeui/html/classTDEMainWindow.html KXMLGUIClient]
 
and therefore supports XMLGUI out of the box. All actions created within it must
 
and therefore supports XMLGUI out of the box. All actions created within it must
have the client's actionCollection() as parent. A call to createGUI() will then
+
have the client's <code>actionCollection()</code> as parent. A call to <code>createGUI()</code> will then
 
build the whole set of menu and tool bars defined the applications XML file
 
build the whole set of menu and tool bars defined the applications XML file
 
(conventionally with the suffix ui.rc).
 
(conventionally with the suffix ui.rc).
   
== An example: Menu in KView ==
+
= An example: Menu in KView =
   
In the following, we take KDE's image view KView as example. It has a ui.rc
+
In the following, we take TDE's image viewer KView as example. It has a ui.rc
file kviewui.rc, which is installed with the Makefile.am snippet
+
file kviewui.rc, which is installed with the following CMakeLists.txt snippet:
  +
  +
<syntaxhighlight lang="cmake">
  +
install( FILES kviewui.rc DESTINATION ${DATA_INSTALL_DIR}/kview )
  +
</syntaxhighlight>
  +
  +
<!-- with the following Makefile.am snippet
   
 
rcdir = $(kde_datadir)/kview
 
rcdir = $(kde_datadir)/kview
rc_DATA = kviewui.rc
+
rc_DATA = kviewui.rc -->
   
 
Here is an excerpt from the kviewui.rc file. For simplicity, we show
 
Here is an excerpt from the kviewui.rc file. For simplicity, we show
only the definition of the View menu.
+
only the definition of the <code>View</code> menu.
  +
 
<syntaxhighlight lang="xml">
 
<syntaxhighlight lang="xml">
 
<!DOCTYPE kpartgui>
 
<!DOCTYPE kpartgui>
Line 60: Line 67:
 
KStdAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection());
 
KStdAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection());
 
KStdAction::zoom (this, SLOT(slotZoom()), actionCollection());
 
KStdAction::zoom (this, SLOT(slotZoom()), actionCollection());
new KAction (i18n("&Half size"), ALT+Key_0,
+
new TDEAction (i18n("&Half size"), ALT+Key_0,
 
this, SLOT(slotHalfSize()),
 
this, SLOT(slotHalfSize()),
 
actionCollection(), "zoom50");
 
actionCollection(), "zoom50");
new KAction (i18n("&Normal size"), ALT+Key_1,
+
new TDEAction (i18n("&Normal size"), ALT+Key_1,
 
this, SLOT(slotDoubleSize()),
 
this, SLOT(slotDoubleSize()),
 
actionCollection(), "zoom100");
 
actionCollection(), "zoom100");
new KAction (i18n("&Double size"), ALT+Key_2,
+
new TDEAction (i18n("&Double size"), ALT+Key_2,
 
this, SLOT(slotDoubleSize()),
 
this, SLOT(slotDoubleSize()),
 
actionCollection(), "zoom200");
 
actionCollection(), "zoom200");
new KAction (i18n("&Fill Screen"), ALT+Key_3,
+
new TDEAction (i18n("&Fill Screen"), ALT+Key_3,
 
this, SLOT(slotFillScreen()),
 
this, SLOT(slotFillScreen()),
 
actionCollection(), "zoomMaxpect");
 
actionCollection(), "zoomMaxpect");
new KAction (i18n("Fullscreen &Mode"), CTRL+SHIFT+Key_F,
+
new TDEAction (i18n("Fullscreen &Mode"), CTRL+SHIFT+Key_F,
 
this, SLOT(slotFullScreen()),
 
this, SLOT(slotFullScreen()),
 
actionCollection(), "fullscreen");
 
actionCollection(), "fullscreen");
Line 83: Line 90:
   
 
The XML file begins with a document type declaration. The DTD for kpartgui can
 
The XML file begins with a document type declaration. The DTD for kpartgui can
be found in the kdelibs sources in kdeui/kpartgui.dtd. The outermost
+
be found in the tdelibs sources in tdeui/kpartgui.dtd. The outermost
 
element of the file contains the instance name of the application as attribute.
 
element of the file contains the instance name of the application as attribute.
 
It can also contain a version number in the form "version=2". This is useful
 
It can also contain a version number in the form "version=2". This is useful
 
when you release new versions of an application with a changed menu structure,
 
when you release new versions of an application with a changed menu structure,
 
e.g. with more features. If you bump up the version number of the ui.rc file,
 
e.g. with more features. If you bump up the version number of the ui.rc file,
KDE makes sure that any customized version of the file is discarded and the new
+
TDE makes sure that any customized version of the file is discarded and the new
 
file is used instead.
 
file is used instead.
   
Line 106: Line 113:
 
</syntaxhighlight>
 
</syntaxhighlight>
   
In KDE's automake framework, such titles are automatically extracted and put
+
In TDE's framework, such titles are automatically extracted and put
 
into the application's [kde-i18n-howto.html <tt>.po</tt>] file, so
 
into the application's [kde-i18n-howto.html <tt>.po</tt>] file, so
 
it is considered by translators. Note that you have to write the accelerator
 
it is considered by translators. Note that you have to write the accelerator
Line 112: Line 119:
   
 
Let us come back to the example. KView's View menu contains a couple of custom
 
Let us come back to the example. KView's View menu contains a couple of custom
actions: zoom50, zoom100, zoom200, zoomMaxpect and fullscreen, declared with a
+
actions: <code>zoom50</code>, <code>zoom100</code>, <code>zoom200</code>,
  +
<code>zoomMaxpect</code> and <code>fullscreen</code>, declared with a
 
&lt;Action&gt; element. The separator in the screenshots corresponds with the
 
&lt;Action&gt; element. The separator in the screenshots corresponds with the
 
&lt;Separator&gt; element.
 
&lt;Separator&gt; element.
Line 119: Line 127:
 
the XML file. These are ''standard actions''. Standard actions are created by
 
the XML file. These are ''standard actions''. Standard actions are created by
 
the class
 
the class
[http://api.kde.org/3.5-api/kdelibs-apidocs/kdeui/html/kstdaction_8h-source.html KStdAction].
+
[http://trinitydesktop.org/docs/trinity/tdelibs/tdeui/html/kstdaction_8h_source.html KStdAction].
 
When you create such actions in your application (such as in the C++ example
 
When you create such actions in your application (such as in the C++ example
 
above), they will automatically be inserted in a prescribed position, and
 
above), they will automatically be inserted in a prescribed position, and
 
possibly with an icon and a shortcut key. You can look up these locations in
 
possibly with an icon and a shortcut key. You can look up these locations in
the file <tt>kdeui/ui_standards.rc</tt> in the kdelibs sources.
+
the file <tt>tdeui/ui_standards.rc</tt> in the tdelibs sources.
   
== An example: Toolbars in Konqueror ==
+
= An example: Toolbars in Konqueror =
   
 
For the discussion of toolbars, we switch to Konqueror's GUI
 
For the discussion of toolbars, we switch to Konqueror's GUI
Line 151: Line 159:
 
*'''<tt>position</tt>''': The default for this attribute is "top", meaning that the toolbar is positioned under the menu bar. For programs with many tools, such as graphics programs, it may be interesting to replace this with "left", "right" or "bottom".
 
*'''<tt>position</tt>''': The default for this attribute is "top", meaning that the toolbar is positioned under the menu bar. For programs with many tools, such as graphics programs, it may be interesting to replace this with "left", "right" or "bottom".
   
== Dynamical menus ==
+
= Dynamical menus =
   
 
Obviously, an XML can only contain a static description of a user interface.
 
Obviously, an XML can only contain a static description of a user interface.
Line 182: Line 190:
 
openWithActions.clear();
 
openWithActions.clear();
 
for ( /* iterate over the relevant services */ ) {
 
for ( /* iterate over the relevant services */ ) {
KAction *action = new KAction( ...);
+
TDEAction *action = new KAction( ...);
 
openWithActions.append(action);
 
openWithActions.append(action);
 
}
 
}
Line 192: Line 200:
 
''not'' constructed with the action collection as parent, and you are
 
''not'' constructed with the action collection as parent, and you are
 
responsible for deleting them for yourself. The simplest way to achieve this
 
responsible for deleting them for yourself. The simplest way to achieve this
is by using <tt>openWithActions.setAutoDelete(true)</tt> in the above
+
is by using <code>openWithActions.setAutoDelete(true)</code> in the above
 
example.
 
example.
   
 
Also note that to be able to extend menus this way, you need to call
 
Also note that to be able to extend menus this way, you need to call
<tt>createGUI()</tt> with the second parameter (conserveMemory) set to "false".
+
<code>createGUI()</code> with the second parameter (conserveMemory) set to "false".
 
If you don't, you won't get any error but your actions won't appear in the
 
If you don't, you won't get any error but your actions won't appear in the
 
menu.
 
menu.
   
== Context menus ==
+
= Context menus =
   
 
The examples above only contained cases where a main window's menubar and
 
The examples above only contained cases where a main window's menubar and
 
toolbars were created. In the cases, the processes of constructing these
 
toolbars were created. In the cases, the processes of constructing these
containers is completely hidden from you behind the createGUI() call
+
containers is completely hidden from you behind the <code>createGUI()</code> call
 
(except if you have custom containers). However, there are cases, where
 
(except if you have custom containers). However, there are cases, where
 
you want to construct other containers and populate them with GUI definitions
 
you want to construct other containers and populate them with GUI definitions
Line 213: Line 221:
 
void MainWindow::popupRequested()
 
void MainWindow::popupRequested()
 
{
 
{
QWidget *w = factory()->container("context_popup", this);
+
TQWidget *w = factory()->container("context_popup", this);
QPopupMenu *popup = static_cast<QPopupMenu *>(w);
+
TQPopupMenu *popup = static_cast<TQPopupMenu *>(w);
popup->exec(QCursor::pos());
+
popup->exec(TQCursor::pos());
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 231: Line 239:
 
...
 
...
 
</syntaxhighlight>
 
</syntaxhighlight>
  +
   
 
''Initial Author:'' [mailto:bernd@kdevelop.org Bernd Gehrmann]
 
''Initial Author:'' [mailto:bernd@kdevelop.org Bernd Gehrmann]

Latest revision as of 15:33, 21 April 2022

While the Action Pattern allows to encapsulate actions triggered by the user in an object which can be "plugged" somewhere in the menu bars or toolbars, it does not by itself solve the problem of constructing the menus themselves. In particular, you have build all popup menus in C++ code and explicitly insert the actions in a certain order, under consideration of the style guide for standard actions. This makes it pretty difficult to allow the user to customize the menus or change shortcuts to fit his needs, without changing the source code.

This problem is solved by a set of classes called XMLGUI. Basically, this separates actions (coded in C++) from their appearance in menu bars and tool bars (coded in XML). Without modifying any source code, menus can be simply customized by adjusting an XML file. Furthermore, it helps to make sure that standard actions (such as File → Open or Help → About) appear in the locations suggested by the style guide. XMLGUI is especially important for modular programs, where the items appearing in the menu bar may come from many different plugins or parts.

Trinity's class for toplevel windows, TDEMainWindow, inherits KXMLGUIClient and therefore supports XMLGUI out of the box. All actions created within it must have the client's actionCollection() as parent. A call to createGUI() will then build the whole set of menu and tool bars defined the applications XML file (conventionally with the suffix ui.rc).

An example: Menu in KView

In the following, we take TDE's image viewer KView as example. It has a ui.rc file kviewui.rc, which is installed with the following CMakeLists.txt snippet:

install( FILES kviewui.rc DESTINATION ${DATA_INSTALL_DIR}/kview )


Here is an excerpt from the kviewui.rc file. For simplicity, we show only the definition of the View menu.

<!DOCTYPE kpartgui>
<kpartgui name="kview">
  <MenuBar>
    <Menu name="view" >
      <Action name="zoom50" />
      <Action name="zoom100" />
      <Action name="zoom200" />
      <Action name="zoomMaxpect" />
      <Separator/>
      <Action name="fullscreen" />
    </Menu>
  </MenuBar>
</kpartgui>

The corresponding part of the setup in C++ is:

KStdAction::zoomIn (this, SLOT(slotZoomIn()), actionCollection());
KStdAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection());
KStdAction::zoom   (this, SLOT(slotZoom()), actionCollection());
new TDEAction      (i18n("&Half size"), ALT+Key_0,
                    this, SLOT(slotHalfSize()),
                    actionCollection(), "zoom50");
new TDEAction      (i18n("&Normal size"), ALT+Key_1,
                    this, SLOT(slotDoubleSize()),
                    actionCollection(), "zoom100");
new TDEAction      (i18n("&Double size"), ALT+Key_2,
                    this, SLOT(slotDoubleSize()),
                    actionCollection(), "zoom200");
new TDEAction      (i18n("&Fill Screen"), ALT+Key_3,
                    this, SLOT(slotFillScreen()),
                    actionCollection(), "zoomMaxpect");
new TDEAction      (i18n("Fullscreen &Mode"), CTRL+SHIFT+Key_F,
                    this, SLOT(slotFullScreen()),
                    actionCollection(), "fullscreen");

The View menu resulting from this GUI definition looks like in this screenshot:

KView menu screenshot

The XML file begins with a document type declaration. The DTD for kpartgui can be found in the tdelibs sources in tdeui/kpartgui.dtd. The outermost element of the file contains the instance name of the application as attribute. It can also contain a version number in the form "version=2". This is useful when you release new versions of an application with a changed menu structure, e.g. with more features. If you bump up the version number of the ui.rc file, TDE makes sure that any customized version of the file is discarded and the new file is used instead.

The next line, <MenuBar> contains a declaration of a menu bar. You can also insert any number of <ToolBar> declarations in order to create some tool bars. The menu contains a submenu with the name "view". This name is already predefined, and thus you see a translated version of the word "View" in the screenshot. If you declare your own submenus, you have to add the title explicitly. For example, KView has a submenu with the title "Image" which is declared as follows:

<Menu name="image">
   <text>&amp;Image</text>
   ...
</Menu>

In TDE's framework, such titles are automatically extracted and put into the application's [kde-i18n-howto.html .po] file, so it is considered by translators. Note that you have to write the accelerator marker "&" in the XML compliant form "&amp;".

Let us come back to the example. KView's View menu contains a couple of custom actions: zoom50, zoom100, zoom200, zoomMaxpect and fullscreen, declared with a <Action> element. The separator in the screenshots corresponds with the <Separator> element.

You will note that some menu items have a corresponding element in the XML file. These are standard actions. Standard actions are created by the class KStdAction. When you create such actions in your application (such as in the C++ example above), they will automatically be inserted in a prescribed position, and possibly with an icon and a shortcut key. You can look up these locations in the file tdeui/ui_standards.rc in the tdelibs sources.

An example: Toolbars in Konqueror

For the discussion of toolbars, we switch to Konqueror's GUI definition. This excerpt defines the location bar, which contains the input field for URLs.

<ToolBar name="locationToolBar" fullWidth="true" newline="true" >
  <text>Location Toolbar</text>
  <Action name="clear_location" />
  <Action name="location_label" />
  <Action name="toolbar_url_combo" />
  <Action name="go_url" />
</ToolBar>

The first thing we notice is that there are a lot more attributes than for menu bars. These include:

  • fullWidth: Tells XMLGUI that the toolbar has the same width as the toplevel window. If this is "false", the toolbar only takes as much space as necessary, and further toolbars are put in the same row.
  • newline: This is related to the option above. If newline is "true", the toolbar starts a new row. Otherwise it may be put in the row together with the previous toolbar. The newline option should not be used with the top option. The toolbars defined after the toolbar with the newline option will automatically start on the same newline. These toolbars can contain the top option, but will not be placed above the newline.
  • noEdit: Normally toolbars can be customized by the user, e.g. in Settings->Configure Toolbars in Konqueror. Setting this option to "true" marks this toolbar as not editable. This is important for toolbars which are filled with items at runtime, e.g. Konqueror's bookmark toolbar.
  • iconText: Tells XMLGUI to show the text of the action next to the icon. Normally, the text is only shown as a tooltip when the mouse cursor remains over the icon for a while. Possible values for this attribute are "icononly" (shows only the icon), "textonly" (shows only the text), "icontextright" (shows the text on the right side of the icon) and "icontextbottom" (shows the text beneath the icon).
  • hidden: If this is "true", the toolbar is not visible initially and must be activated by some menu item.
  • position: The default for this attribute is "top", meaning that the toolbar is positioned under the menu bar. For programs with many tools, such as graphics programs, it may be interesting to replace this with "left", "right" or "bottom".

Dynamical menus

Obviously, an XML can only contain a static description of a user interface. Often, there are menus which change at runtime. For example, Konqueror's Location menu contains a set of items Open with Foo with the applications able to load a file with a given MIME type. Each time the document shown changes, the list of menu items is updated. XMLGUI is prepared to handle such cases with the notion of action lists. An action list is declared as one item in the XML file, but consists of several actions which are plugged into the menu at runtime. The above example is implemented with the following declaration in Konqueror's XML file:

<Menu name="file">
  <text>&amp;Location</text>
  ...
  <ActionList name="openwith">
  ...
</Menu>

The function KXMLGUIClient::plugActionList() is then used to add actions to be displayed, whereas the function KXMLGuiClient::unplugActionList() removes all plugged actions. The routine responsible for updating looks as follows:

void MainWindow::updateOpenWithActions()
{
    unplugActionList("openwith");
    openWithActions.clear();
    for ( /* iterate over the relevant services */ ) {
        TDEAction *action = new KAction( ...);
        openWithActions.append(action);
    }
    plugActionList("openwith", openWithActions);
}

Note that in contrast to the static actions, the ones created here are not constructed with the action collection as parent, and you are responsible for deleting them for yourself. The simplest way to achieve this is by using openWithActions.setAutoDelete(true) in the above example.

Also note that to be able to extend menus this way, you need to call createGUI() with the second parameter (conserveMemory) set to "false". If you don't, you won't get any error but your actions won't appear in the menu.

Context menus

The examples above only contained cases where a main window's menubar and toolbars were created. In the cases, the processes of constructing these containers is completely hidden from you behind the createGUI() call (except if you have custom containers). However, there are cases, where you want to construct other containers and populate them with GUI definitions from the XML file. One such example are context menus. In order to get a pointer to a context menu, you have to ask the client's factory for it:

void MainWindow::popupRequested()
{
    TQWidget *w = factory()->container("context_popup", this);
    TQPopupMenu *popup = static_cast<TQPopupMenu *>(w);
    popup->exec(TQCursor::pos());
}

The method KXMLGUIFactory::container() used above looks whether it finds a container in the XML file with the given name. Thus, a possible definition could look as follows:

...
<Menu name="context_popup">
  <Action name="file_add"/>
  <Action name="file_remove"/>
</Menu>
...


Initial Author: Bernd Gehrmann