KXmlGui

kxmlguibuilder.cpp
1 /*
2  This file is part of the KDE project
3  SPDX-FileCopyrightText: 2000 Simon Hausmann <[email protected]>
4  SPDX-FileCopyrightText: 2000 David Faure <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "kxmlguibuilder.h"
10 
11 #include "debug.h"
12 #include "kmainwindow.h"
13 #include "kmenumenuhandler_p.h"
14 #include "ktoolbar.h"
15 #include "kxmlguiclient.h"
16 #include "kxmlguiwindow.h"
17 
18 #include <KAuthorized>
19 #include <KLocalizedString>
20 
21 #include <QAction>
22 #include <QDomElement>
23 #include <QMenu>
24 #include <QMenuBar>
25 #include <QObject>
26 #include <QStatusBar>
27 
28 using namespace KDEPrivate;
29 
30 class KXMLGUIBuilderPrivate
31 {
32 public:
33  KXMLGUIBuilderPrivate()
34  {
35  }
36  ~KXMLGUIBuilderPrivate()
37  {
38  }
39 
40  QWidget *m_widget = nullptr;
41 
42  QString tagMainWindow;
43  QString tagMenuBar;
44  QString tagMenu;
45  QString tagToolBar;
46  QString tagStatusBar;
47 
48  QString tagSeparator;
49  QString tagSpacer;
50  QString tagTearOffHandle;
51  QString tagMenuTitle;
52 
53  QString attrName;
54  QString attrLineSeparator;
55 
56  QString attrDomain;
57  QString attrText1;
58  QString attrText2;
59  QString attrContext;
60 
61  QString attrIcon;
62 
63  KXMLGUIClient *m_client = nullptr;
64 
65  KMenuMenuHandler *m_menumenuhandler = nullptr;
66 };
67 
68 KXMLGUIBuilder::KXMLGUIBuilder(QWidget *widget)
69  : d(new KXMLGUIBuilderPrivate)
70 {
71  d->m_widget = widget;
72 
73  d->tagMainWindow = QStringLiteral("mainwindow");
74  d->tagMenuBar = QStringLiteral("menubar");
75  d->tagMenu = QStringLiteral("menu");
76  d->tagToolBar = QStringLiteral("toolbar");
77  d->tagStatusBar = QStringLiteral("statusbar");
78 
79  d->tagSeparator = QStringLiteral("separator");
80  d->tagSpacer = QStringLiteral("spacer");
81  d->tagTearOffHandle = QStringLiteral("tearoffhandle");
82  d->tagMenuTitle = QStringLiteral("title");
83 
84  d->attrName = QStringLiteral("name");
85  d->attrLineSeparator = QStringLiteral("lineseparator");
86 
87  d->attrDomain = QStringLiteral("translationDomain");
88  d->attrText1 = QStringLiteral("text");
89  d->attrText2 = QStringLiteral("Text");
90  d->attrContext = QStringLiteral("context");
91 
92  d->attrIcon = QStringLiteral("icon");
93 
94  d->m_menumenuhandler = new KMenuMenuHandler(this);
95 }
96 
97 KXMLGUIBuilder::~KXMLGUIBuilder()
98 {
99  delete d->m_menumenuhandler;
100 }
101 
102 QWidget *KXMLGUIBuilder::widget()
103 {
104  return d->m_widget;
105 }
106 
107 QStringList KXMLGUIBuilder::containerTags() const
108 {
109  QStringList res;
110  res << d->tagMenu << d->tagToolBar << d->tagMainWindow << d->tagMenuBar << d->tagStatusBar;
111 
112  return res;
113 }
114 
115 QWidget *KXMLGUIBuilder::createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction)
116 {
117  containerAction = nullptr;
118 
119  if (element.attribute(QStringLiteral("deleted")).toLower() == QLatin1String("true")) {
120  return nullptr;
121  }
122 
123  const QString tagName = element.tagName().toLower();
124  if (tagName == d->tagMainWindow) {
125  KMainWindow *mainwindow = qobject_cast<KMainWindow *>(d->m_widget); // could be 0
126  return mainwindow;
127  }
128 
129  if (tagName == d->tagMenuBar) {
130  KMainWindow *mainWin = qobject_cast<KMainWindow *>(d->m_widget);
131  QMenuBar *bar = nullptr;
132  if (mainWin) {
133  bar = mainWin->menuBar();
134  }
135  if (!bar) {
136  bar = new QMenuBar(d->m_widget);
137  }
138  bar->show();
139  return bar;
140  }
141 
142  if (tagName == d->tagMenu) {
143  // Look up to see if we are inside a mainwindow. If yes, then
144  // use it as parent widget (to get kaction to plug itself into the
145  // mainwindow). Don't use a popupmenu as parent widget, otherwise
146  // the popup won't be hidden if it is used as a standalone menu as well.
147  // Note: menus with a parent of 0, coming from child clients, can be
148  // leaked if the child client is deleted without a proper removeClient call, though.
149  QWidget *p = parent;
150 
151  if (!p && qobject_cast<QMainWindow *>(d->m_widget)) {
152  p = d->m_widget;
153  }
154 
155  while (p && !qobject_cast<QMainWindow *>(p)) {
156  p = p->parentWidget();
157  }
158 
159  QString name = element.attribute(d->attrName);
160 
161  if (!KAuthorized::authorizeAction(name)) {
162  return nullptr;
163  }
164 
165  QMenu *popup = new QMenu(p);
166  popup->setObjectName(name);
167 
168  d->m_menumenuhandler->insertMenu(popup);
169 
170  QString i18nText;
171  QDomElement textElem = element.namedItem(d->attrText1).toElement();
172  if (textElem.isNull()) { // try with capital T
173  textElem = element.namedItem(d->attrText2).toElement();
174  }
175  const QString text = textElem.text();
176  const QString context = textElem.attribute(d->attrContext);
177 
178  // qCDebug(DEBUG_KXMLGUI) << "DOMAIN" << KLocalizedString::applicationDomain();
179  // qCDebug(DEBUG_KXMLGUI) << "ELEMENT TEXT:" << text;
180 
181  if (text.isEmpty()) { // still no luck
182  i18nText = i18n("No text");
183  } else {
184  QByteArray domain = textElem.attribute(d->attrDomain).toUtf8();
185  if (domain.isEmpty()) {
186  domain = element.ownerDocument().documentElement().attribute(d->attrDomain).toUtf8();
187  if (domain.isEmpty()) {
189  }
190  }
191  if (context.isEmpty()) {
192  i18nText = i18nd(domain.constData(), text.toUtf8().constData());
193  } else {
194  i18nText = i18ndc(domain.constData(), context.toUtf8().constData(), text.toUtf8().constData());
195  }
196  }
197 
198  // qCDebug(DEBUG_KXMLGUI) << "ELEMENT i18n TEXT:" << i18nText;
199 
200  const QString icon = element.attribute(d->attrIcon);
201  QIcon pix;
202  if (!icon.isEmpty()) {
203  pix = QIcon::fromTheme(icon);
204  }
205 
206  if (parent) {
207  QAction *act = popup->menuAction();
208  if (!icon.isEmpty()) {
209  act->setIcon(pix);
210  }
211  act->setText(i18nText);
212  if (index == -1 || index >= parent->actions().count()) {
213  parent->addAction(act);
214  } else {
215  parent->insertAction(parent->actions().value(index), act);
216  }
217  containerAction = act;
218  containerAction->setObjectName(name);
219  }
220 
221  return popup;
222  }
223 
224  if (tagName == d->tagToolBar) {
225  QString name = element.attribute(d->attrName);
226 
227  KToolBar *bar = static_cast<KToolBar *>(d->m_widget->findChild<KToolBar *>(name));
228  if (!bar) {
229  bar = new KToolBar(name, d->m_widget, false);
230  }
231 
232  if (qobject_cast<KMainWindow *>(d->m_widget)) {
233  if (d->m_client && !d->m_client->xmlFile().isEmpty()) {
234  bar->addXMLGUIClient(d->m_client);
235  }
236  }
237  if (!bar->mainWindow()) {
238  bar->show();
239  }
240 
241  bar->loadState(element);
242 
243  return bar;
244  }
245 
246  if (tagName == d->tagStatusBar) {
247  KMainWindow *mainWin = qobject_cast<KMainWindow *>(d->m_widget);
248  if (mainWin) {
249  mainWin->statusBar()->show();
250  return mainWin->statusBar();
251  }
252  QStatusBar *bar = new QStatusBar(d->m_widget);
253  return bar;
254  }
255 
256  return nullptr;
257 }
258 
259 void KXMLGUIBuilder::removeContainer(QWidget *container, QWidget *parent, QDomElement &element, QAction *containerAction)
260 {
261  // Warning parent can be 0L
262 
263  if (qobject_cast<QMenu *>(container)) {
264  if (parent) {
265  parent->removeAction(containerAction);
266  }
267 
268  delete container;
269  } else if (qobject_cast<KToolBar *>(container)) {
270  KToolBar *tb = static_cast<KToolBar *>(container);
271 
272  tb->saveState(element);
273  if (tb->mainWindow()) {
274  delete tb;
275  } else {
276  tb->clear();
277  tb->hide();
278  }
279  } else if (qobject_cast<QMenuBar *>(container)) {
280  QMenuBar *mb = static_cast<QMenuBar *>(container);
281  mb->hide();
282  // Don't delete menubar - it can be reused by createContainer.
283  // If you decide that you do need to delete the menubar, make
284  // sure that QMainWindow::d->mb does not point to a deleted
285  // menubar object.
286  } else if (qobject_cast<QStatusBar *>(container)) {
287  if (qobject_cast<KMainWindow *>(d->m_widget)) {
288  container->hide();
289  } else {
290  delete static_cast<QStatusBar *>(container);
291  }
292  } else {
293  qCWarning(DEBUG_KXMLGUI) << "Unhandled container to remove : " << container->metaObject()->className();
294  }
295 }
296 
297 QStringList KXMLGUIBuilder::customTags() const
298 {
299  QStringList res;
300  res << d->tagSeparator << d->tagSpacer << d->tagTearOffHandle << d->tagMenuTitle;
301  return res;
302 }
303 
304 QAction *KXMLGUIBuilder::createCustomElement(QWidget *parent, int index, const QDomElement &element)
305 {
306  QAction *before = nullptr;
307  if (index > 0 && index < parent->actions().count()) {
308  before = parent->actions().at(index);
309  }
310 
311  const QString tagName = element.tagName().toLower();
312  if (tagName == d->tagSeparator) {
313  if (QMenu *menu = qobject_cast<QMenu *>(parent)) {
314  // QMenu already cares for leading/trailing/repeated separators
315  // no need to check anything
316  return menu->insertSeparator(before);
317  } else if (QMenuBar *bar = qobject_cast<QMenuBar *>(parent)) {
318  QAction *separatorAction = new QAction(bar);
319  separatorAction->setSeparator(true);
320  bar->insertAction(before, separatorAction);
321  return separatorAction;
322  } else if (KToolBar *bar = qobject_cast<KToolBar *>(parent)) {
323  /* FIXME KAction port - any need to provide a replacement for lineSeparator/normal separator?
324  bool isLineSep = true;
325 
326  QDomNamedNodeMap attributes = element.attributes();
327  unsigned int i = 0;
328  for (; i < attributes.length(); i++ )
329  {
330  QDomAttr attr = attributes.item( i ).toAttr();
331 
332  if ( attr.name().toLower() == d->attrLineSeparator &&
333  attr.value().toLower() == QLatin1String("false") )
334  {
335  isLineSep = false;
336  break;
337  }
338  }
339 
340  if ( isLineSep )
341  return bar->insertSeparator( index ? bar->actions()[index - 1] : 0L );
342  else*/
343 
344  return bar->insertSeparator(before);
345  }
346  } else if (tagName == d->tagSpacer) {
347  if (QToolBar *bar = qobject_cast<QToolBar *>(parent)) {
348  // Create the simple spacer widget
349  QWidget *spacer = new QWidget(parent);
351  return bar->insertWidget(before, spacer);
352  }
353  } else if (tagName == d->tagTearOffHandle) {
354  static_cast<QMenu *>(parent)->setTearOffEnabled(true);
355  } else if (tagName == d->tagMenuTitle) {
356  if (QMenu *m = qobject_cast<QMenu *>(parent)) {
357  QString i18nText;
358  const QString text = element.text();
359 
360  if (text.isEmpty()) {
361  i18nText = i18n("No text");
362  } else {
363  QByteArray domain = element.attribute(d->attrDomain).toUtf8();
364  if (domain.isEmpty()) {
365  domain = element.ownerDocument().documentElement().attribute(d->attrDomain).toUtf8();
366  if (domain.isEmpty()) {
368  }
369  }
370  i18nText = i18nd(domain.constData(), qPrintable(text));
371  }
372 
373  QString icon = element.attribute(d->attrIcon);
374  QIcon pix;
375 
376  if (!icon.isEmpty()) {
377  pix = QIcon::fromTheme(icon);
378  }
379 
380  if (!icon.isEmpty()) {
381  return m->insertSection(before, pix, i18nText);
382  } else {
383  return m->insertSection(before, i18nText);
384  }
385  }
386  }
387 
388  QAction *blank = new QAction(parent);
389  blank->setVisible(false);
390  parent->insertAction(before, blank);
391  return blank;
392 }
393 
394 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
396 {
397  parent->removeAction(action);
398 }
399 #endif
400 
401 KXMLGUIClient *KXMLGUIBuilder::builderClient() const
402 {
403  return d->m_client;
404 }
405 
406 void KXMLGUIBuilder::setBuilderClient(KXMLGUIClient *client)
407 {
408  d->m_client = client;
409 }
410 
411 void KXMLGUIBuilder::finalizeGUI(KXMLGUIClient *)
412 {
413  KXmlGuiWindow *window = qobject_cast<KXmlGuiWindow *>(d->m_widget);
414  if (window) {
415  window->finalizeGUI(false);
416  }
417 }
418 
419 void KXMLGUIBuilder::virtual_hook(int, void *)
420 {
421  /*BASE::virtual_hook( id, data );*/
422 }
void clear()
QString text() const const
QDomElement toElement() const const
QList< QAction * > actions() const const
void setSizePolicy(QSizePolicy)
QString tagName() const const
int count(const T &value) const const
bool isNull() const const
QIcon fromTheme(const QString &name)
virtual QWidget * createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction)
Creates a container (menubar/menu/toolbar/statusbar/separator/...) from an element in the XML file.
Floatable toolbar with auto resize.
Definition: ktoolbar.h:67
void insertAction(QAction *before, QAction *action)
void hide()
void setIcon(const QIcon &icon)
QString i18ndc(const char *domain, const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
virtual void removeCustomElement(QWidget *parent, QAction *action)
KCONFIGCORE_EXPORT bool authorizeAction(const QString &action)
bool isEmpty() const const
QByteArray toUtf8() const const
void saveState(QDomElement &element) const
Save state into an XML.
Definition: ktoolbar.cpp:1070
const T & at(int i) const const
QDomDocument ownerDocument() const const
void setText(const QString &text)
QMenuBar * menuBar() const const
void addXMLGUIClient(KXMLGUIClient *client)
Adds an XML gui client that uses this toolbar.
Definition: ktoolbar.cpp:948
QDomElement documentElement() const const
QString i18nd(const char *domain, const char *text, const TYPE &arg...)
virtual const QMetaObject * metaObject() const const
QStatusBar * statusBar() const const
void show()
void removeAction(QAction *action)
void loadState(const QDomElement &element)
Load state from an XML.
Definition: ktoolbar.cpp:977
void setVisible(bool)
const char * className() const const
KMainWindow with convenience functions and integration with XmlGui files.
Definition: kxmlguiwindow.h:87
QString toLower() const const
bool isEmpty() const const
const char * constData() const const
KMainWindow represents a top-level main window.
Definition: kmainwindow.h:69
void setObjectName(const QString &name)
QString attribute(const QString &name, const QString &defValue) const const
virtual void removeContainer(QWidget *container, QWidget *parent, QDomElement &element, QAction *containerAction)
Removes the given (and previously via createContainer ) created container.
void addAction(QAction *action)
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
QAction * menuAction() const const
void setSeparator(bool b)
KMainWindow * mainWindow() const
Returns the main window that this toolbar is docked with.
Definition: ktoolbar.cpp:1119
QWidget * parentWidget() const const
static QByteArray applicationDomain()
T value(int i) const const
QDomNode namedItem(const QString &name) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Sep 26 2023 04:02:38 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.