• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • dialogs
kedittoolbar.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
3  Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
4  Copyright 2007 David Faure <faure@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License version 2 as published by the Free Software Foundation.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 #include <kedittoolbar.h>
21 #include <kedittoolbar_p.h>
22 #include <QShowEvent>
23 
24 
25 #include <QtXml/QDomDocument>
26 #include <QtGui/QLayout>
27 #include <QtCore/QDir>
28 #include <QtCore/QFile>
29 #include <QHeaderView>
30 #include <QtGui/QToolButton>
31 #include <QtGui/QLabel>
32 #include <QtGui/QApplication>
33 #include <QtGui/QGridLayout>
34 #include <QtGui/QCheckBox>
35 #include <QMimeData>
36 
37 #include <kstandarddirs.h>
38 #include <klistwidgetsearchline.h>
39 #include <klocale.h>
40 #include <kicon.h>
41 #include <kiconloader.h>
42 #include <kcomponentdata.h>
43 #include <kmessagebox.h>
44 #include <kxmlguifactory.h>
45 #include <kseparator.h>
46 #include <kconfig.h>
47 #include <kdebug.h>
48 #include <kpushbutton.h>
49 #include <kprocess.h>
50 #include <ktoolbar.h>
51 #include <kdeversion.h>
52 #include <kcombobox.h>
53 #include <klineedit.h>
54 
55 #include "kaction.h"
56 #include "kactioncollection.h"
57 
58 static const char * const separatorstring = I18N_NOOP("--- separator ---");
59 
60 #define SEPARATORSTRING i18n(separatorstring)
61 
62 static const char* const s_XmlTypeToString[] = { "Shell", "Part", "Local", "Merged" };
63 
64 typedef QList<QDomElement> ToolBarList;
65 
66 namespace KDEPrivate {
67 
71 static ToolBarList findToolBars(const QDomElement& start)
72 {
73  static const QString &tagToolBar = KGlobal::staticQString( "ToolBar" );
74  static const QString &tagMenuBar = KGlobal::staticQString( "MenuBar" );
75  static const QString &attrNoEdit = KGlobal::staticQString( "noEdit" );
76  ToolBarList list;
77 
78  for( QDomElement elem = start; !elem.isNull(); elem = elem.nextSiblingElement() ) {
79  if (elem.tagName() == tagToolBar) {
80  if ( elem.attribute( attrNoEdit ) != "true" )
81  list.append(elem);
82  } else {
83  if (elem.tagName() != tagMenuBar) // there are no toolbars inside the menubar :)
84  list += findToolBars(elem.firstChildElement()); // recursive
85  }
86  }
87 
88  return list;
89 }
90 
91 class XmlData
92 {
93 public:
94  enum XmlType { Shell = 0, Part, Local, Merged };
95 
96  explicit XmlData( XmlType xmlType, const QString& xmlFile, KActionCollection* collection )
97  : m_isModified(false),
98  m_xmlFile(xmlFile),
99  m_type(xmlType),
100  m_actionCollection(collection)
101  {
102  }
103  void dump() const
104  {
105  kDebug(240) << "XmlData" << this << "type" << s_XmlTypeToString[m_type] << "xmlFile:" << m_xmlFile;
106  foreach (const QDomElement& element, m_barList) {
107  kDebug(240) << " ToolBar:" << toolBarText( element );
108  }
109  if ( m_actionCollection )
110  kDebug(240) << " " << m_actionCollection->actions().count() << "actions in the collection.";
111  else
112  kDebug(240) << " no action collection.";
113  }
114  QString xmlFile() const { return m_xmlFile; }
115  XmlType type() const { return m_type; }
116  KActionCollection* actionCollection() const { return m_actionCollection; }
117  void setDomDocument(const QDomDocument& domDoc)
118  {
119  m_document = domDoc;
120  m_barList = findToolBars(m_document.documentElement());
121  }
122  // Return reference, for e.g. actionPropertiesElement() to modify the document
123  QDomDocument& domDocument() { return m_document; }
124  const QDomDocument& domDocument() const { return m_document; }
125 
129  QString toolBarText( const QDomElement& it ) const;
130 
131 
132  bool m_isModified;
133  ToolBarList& barList() { return m_barList; }
134  const ToolBarList& barList() const { return m_barList; }
135 
136 private:
137  ToolBarList m_barList;
138  QString m_xmlFile;
139  QDomDocument m_document;
140  XmlType m_type;
141  KActionCollection* m_actionCollection;
142 };
143 
144 QString XmlData::toolBarText( const QDomElement& it ) const
145 {
146  static const QString &tagText = KGlobal::staticQString( "text" );
147  static const QString &tagText2 = KGlobal::staticQString( "Text" );
148  static const QString &attrName = KGlobal::staticQString( "name" );
149 
150  QString name;
151  QByteArray txt( it.namedItem( tagText ).toElement().text().toUtf8() );
152  if ( txt.isEmpty() )
153  txt = it.namedItem( tagText2 ).toElement().text().toUtf8();
154  if ( txt.isEmpty() )
155  name = it.attribute( attrName );
156  else
157  name = i18n( txt );
158 
159  // the name of the toolbar might depend on whether or not
160  // it is in kparts
161  if ( ( m_type == XmlData::Shell ) ||
162  ( m_type == XmlData::Part ) ) {
163  QString doc_name(m_document.documentElement().attribute( attrName ));
164  name += " <" + doc_name + '>';
165  }
166  return name;
167 }
168 
169 
170 typedef QList<XmlData> XmlDataList;
171 
172 class ToolBarItem : public QListWidgetItem
173 {
174 public:
175  ToolBarItem(QListWidget *parent, const QString& tag = QString(), const QString& name = QString(), const QString& statusText = QString())
176  : QListWidgetItem(parent),
177  m_internalTag(tag),
178  m_internalName(name),
179  m_statusText(statusText),
180  m_isSeparator(false),
181  m_isTextAlongsideIconHidden(false)
182  {
183  // Drop between items, not onto items
184  setFlags((flags() | Qt::ItemIsDragEnabled) & ~Qt::ItemIsDropEnabled);
185  }
186 
187  void setInternalTag(const QString &tag) { m_internalTag = tag; }
188  void setInternalName(const QString &name) { m_internalName = name; }
189  void setStatusText(const QString &text) { m_statusText = text; }
190  void setSeparator(bool sep) { m_isSeparator = sep; }
191  void setTextAlongsideIconHidden(bool hidden) { m_isTextAlongsideIconHidden = hidden; }
192  QString internalTag() const { return m_internalTag; }
193  QString internalName() const { return m_internalName; }
194  QString statusText() const { return m_statusText; }
195  bool isSeparator() const { return m_isSeparator; }
196  bool isTextAlongsideIconHidden() const { return m_isTextAlongsideIconHidden; }
197 
198  int index() const { return listWidget()->row(const_cast<ToolBarItem*>(this)); }
199 
200 private:
201  QString m_internalTag;
202  QString m_internalName;
203  QString m_statusText;
204  bool m_isSeparator;
205  bool m_isTextAlongsideIconHidden;
206 };
207 
208 static QDataStream & operator<< ( QDataStream & s, const ToolBarItem & item ) {
209  s << item.internalTag();
210  s << item.internalName();
211  s << item.statusText();
212  s << item.isSeparator();
213  s << item.isTextAlongsideIconHidden();
214  return s;
215 }
216 static QDataStream & operator>> ( QDataStream & s, ToolBarItem & item ) {
217  QString internalTag;
218  s >> internalTag;
219  item.setInternalTag(internalTag);
220  QString internalName;
221  s >> internalName;
222  item.setInternalName(internalName);
223  QString statusText;
224  s >> statusText;
225  item.setStatusText(statusText);
226  bool sep;
227  s >> sep;
228  item.setSeparator(sep);
229  bool hidden;
230  s >> hidden;
231  item.setTextAlongsideIconHidden(hidden);
232  return s;
233 }
234 
236 
237 ToolBarListWidget::ToolBarListWidget(QWidget *parent)
238  : QListWidget(parent),
239  m_activeList(true)
240 {
241  setDragDropMode(QAbstractItemView::DragDrop); // no internal moves
242 }
243 
244 QMimeData* ToolBarListWidget::mimeData(const QList<QListWidgetItem*> items) const
245 {
246  if (items.isEmpty())
247  return 0;
248  QMimeData* mimedata = new QMimeData();
249 
250  QByteArray data;
251  {
252  QDataStream stream(&data, QIODevice::WriteOnly);
253  // we only support single selection
254  ToolBarItem* item = static_cast<ToolBarItem *>(items.first());
255  stream << *item;
256  }
257 
258  mimedata->setData("application/x-kde-action-list", data);
259  mimedata->setData("application/x-kde-source-treewidget", m_activeList ? "active" : "inactive");
260 
261  return mimedata;
262 }
263 
264 bool ToolBarListWidget::dropMimeData(int index, const QMimeData * mimeData, Qt::DropAction action)
265 {
266  Q_UNUSED(action)
267  const QByteArray data = mimeData->data("application/x-kde-action-list");
268  if (data.isEmpty())
269  return false;
270  QDataStream stream(data);
271  const bool sourceIsActiveList = mimeData->data("application/x-kde-source-treewidget") == "active";
272  ToolBarItem* item = new ToolBarItem(this); // needs parent, use this temporarily
273  stream >> *item;
274  emit dropped(this, index, item, sourceIsActiveList);
275  return true;
276 }
277 
278 ToolBarItem* ToolBarListWidget::currentItem() const
279 {
280  return static_cast<ToolBarItem*>(QListWidget::currentItem());
281 }
282 
283 
284 IconTextEditDialog::IconTextEditDialog(QWidget *parent)
285  : KDialog(parent)
286 {
287  setCaption(i18n("Change Text"));
288  setButtons(Ok | Cancel);
289  setDefaultButton(Ok);
290  setModal(true);
291 
292  QWidget *mainWidget = new QWidget(this);
293  QGridLayout *layout = new QGridLayout(mainWidget);
294  layout->setMargin(0);
295 
296  m_lineEdit = new KLineEdit(mainWidget);
297  m_lineEdit->setClearButtonShown(true);
298  QLabel *label = new QLabel(i18n("Icon te&xt:"), this);
299  label->setBuddy(m_lineEdit);
300  layout->addWidget(label, 0, 0);
301  layout->addWidget(m_lineEdit, 0, 1);
302 
303  m_cbHidden = new QCheckBox(i18n("&Hide text when toolbar shows text alongside icons"), mainWidget);
304  layout->addWidget(m_cbHidden, 1, 1);
305 
306  connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(slotTextChanged(QString)));
307 
308  m_lineEdit->setFocus();
309  setMainWidget(mainWidget);
310  setFixedHeight(sizeHint().height());
311 }
312 
313 void IconTextEditDialog::setIconText(const QString &text)
314 {
315  m_lineEdit->setText(text);
316 }
317 
318 QString IconTextEditDialog::iconText() const
319 {
320  return m_lineEdit->text().trimmed();
321 }
322 
323 void IconTextEditDialog::setTextAlongsideIconHidden(bool hidden)
324 {
325  m_cbHidden->setChecked(hidden);
326 }
327 
328 bool IconTextEditDialog::textAlongsideIconHidden() const
329 {
330  return m_cbHidden->isChecked();
331 }
332 
333 void IconTextEditDialog::slotTextChanged(const QString &text)
334 {
335  // Do not allow empty icon text
336  enableButton(Ok, !text.trimmed().isEmpty());
337 }
338 
339 
340 class KEditToolBarWidgetPrivate
341 {
342 public:
350  KEditToolBarWidgetPrivate(KEditToolBarWidget* widget,
351  const KComponentData &cData, KActionCollection* collection)
352  : m_collection( collection ),
353  m_widget(widget),
354  m_factory(NULL),
355  m_loadedOnce( false )
356  {
357  m_componentData = cData;
358  m_isPart = false;
359  m_helpArea = 0L;
360  m_kdialogProcess = 0;
361  // We want items with an icon to align with items without icon
362  // So we use an empty QPixmap for that
363  const int iconSize = widget->style()->pixelMetric(QStyle::PM_SmallIconSize);
364  m_emptyIcon = QPixmap(iconSize, iconSize);
365  m_emptyIcon.fill(Qt::transparent);
366  }
367  ~KEditToolBarWidgetPrivate()
368  {
369  }
370 
371  // private slots
372  void slotToolBarSelected(int index);
373 
374  void slotInactiveSelectionChanged();
375  void slotActiveSelectionChanged();
376 
377  void slotInsertButton();
378  void slotRemoveButton();
379  void slotUpButton();
380  void slotDownButton();
381 
382  void selectActiveItem(const QString&);
383 
384  void slotChangeIcon();
385  void slotChangeIconText();
386 
387  void slotProcessExited();
388 
389  void slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList);
390 
391 
392  void setupLayout();
393 
394  void initOldStyle( const QString& file, bool global, const QString& defaultToolbar );
395  void initFromFactory( KXMLGUIFactory* factory, const QString& defaultToolbar );
396  void loadToolBarCombo( const QString& defaultToolbar );
397  void loadActions(const QDomElement& elem);
398 
399  QString xmlFile(const QString& xml_file) const
400  {
401  return xml_file.isEmpty() ? QString(m_componentData.componentName()) + "ui.rc" :
402  xml_file;
403  }
404 
408  QString loadXMLFile(const QString& _xml_file)
409  {
410  QString raw_xml;
411  QString xml_file = xmlFile(_xml_file);
412  //kDebug() << "loadXMLFile xml_file=" << xml_file;
413 
414  if ( !QDir::isRelativePath(xml_file) )
415  raw_xml = KXMLGUIFactory::readConfigFile(xml_file);
416  else
417  raw_xml = KXMLGUIFactory::readConfigFile(xml_file, m_componentData);
418 
419  return raw_xml;
420  }
421 
425  QDomElement findElementForToolBarItem( const ToolBarItem* item ) const
426  {
427  static const QString &attrName = KGlobal::staticQString( "name" );
428  //kDebug(240) << "looking for name=" << item->internalName() << "and tag=" << item->internalTag();
429  for(QDomNode n = m_currentToolBarElem.firstChild(); !n.isNull(); n = n.nextSibling())
430  {
431  QDomElement elem = n.toElement();
432  if ((elem.attribute(attrName) == item->internalName()) &&
433  (elem.tagName() == item->internalTag()))
434  return elem;
435  }
436  //kDebug(240) << "no item found in the DOM with name=" << item->internalName() << "and tag=" << item->internalTag();
437  return QDomElement();
438  }
439 
440  void insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend = false);
441  void removeActive(ToolBarItem *item);
442  void moveActive(ToolBarItem *item, ToolBarItem *before);
443  void updateLocal(QDomElement& elem);
444 
445 #ifndef NDEBUG
446  void dump() const
447  {
448  XmlDataList::const_iterator xit = m_xmlFiles.begin();
449  for ( ; xit != m_xmlFiles.end(); ++xit ) {
450  (*xit).dump();
451  }
452  }
453 #endif
454 
455  KComboBox *m_toolbarCombo;
456 
457  QToolButton *m_upAction;
458  QToolButton *m_removeAction;
459  QToolButton *m_insertAction;
460  QToolButton *m_downAction;
461 
462  //QValueList<KAction*> m_actionList;
463  KActionCollection* m_collection;
464  KEditToolBarWidget* m_widget;
465  KXMLGUIFactory* m_factory;
466  KComponentData m_componentData;
467 
468  QPixmap m_emptyIcon;
469 
470  XmlData* m_currentXmlData;
471  QDomElement m_currentToolBarElem;
472 
473  QString m_xmlFile;
474  QString m_globalFile;
475  QString m_rcFile;
476  QDomDocument m_localDoc;
477 
478  ToolBarList m_barList;
479  ToolBarListWidget *m_inactiveList;
480  ToolBarListWidget *m_activeList;
481 
482  XmlDataList m_xmlFiles;
483 
484  QLabel *m_comboLabel;
485  KSeparator *m_comboSeparator;
486  QLabel * m_helpArea;
487  KPushButton* m_changeIcon;
488  KPushButton* m_changeIconText;
489  KProcess* m_kdialogProcess;
490  bool m_isPart : 1;
491  bool m_hasKDialog : 1;
492  bool m_loadedOnce : 1;
493 };
494 
495 }
496 
497 using namespace KDEPrivate;
498 
499 
500 class KEditToolBarPrivate {
501 public:
502  KEditToolBarPrivate(KEditToolBar *q): q(q),
503  m_accept(false), m_global(false),
504  m_collection(0), m_factory(0), m_widget(0) {}
505 
506  void init();
507 
508  void _k_slotOk();
509  void _k_slotApply();
510  void _k_acceptOK(bool);
511  void _k_slotDefault();
512 
513  KEditToolBar *q;
514  bool m_accept;
515  // Save parameters for recreating widget after resetting toolbar
516  bool m_global;
517  KActionCollection* m_collection;
518  QString m_file;
519  QString m_defaultToolBar;
520  KXMLGUIFactory* m_factory;
521  KEditToolBarWidget *m_widget;
522 };
523 
524 K_GLOBAL_STATIC(QString, s_defaultToolBarName)
525 
526 KEditToolBar::KEditToolBar( KActionCollection *collection,
527  QWidget* parent )
528  : KDialog(parent),
529  d(new KEditToolBarPrivate(this))
530 {
531  d->m_widget = new KEditToolBarWidget( collection, this);
532  d->init();
533  d->m_collection = collection;
534 }
535 
536 KEditToolBar::KEditToolBar( KXMLGUIFactory* factory,
537  QWidget* parent )
538  : KDialog(parent),
539  d(new KEditToolBarPrivate(this))
540 {
541  d->m_widget = new KEditToolBarWidget( this);
542  d->init();
543  d->m_factory = factory;
544 }
545 
546 void KEditToolBarPrivate::init()
547 {
548  m_accept = false;
549  m_factory = 0;
550 
551  q->setDefaultToolBar( QString() );
552 
553  q->setCaption(i18n("Configure Toolbars"));
554  q->setButtons(KDialog::Default|KDialog::Ok|KDialog::Apply|KDialog::Cancel);
555  q->setDefaultButton(KDialog::Ok);
556 
557  q->setModal(false);
558 
559  q->setMainWidget(m_widget);
560 
561  q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
562  q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
563  q->enableButtonApply(false);
564 
565  q->connect(q, SIGNAL(okClicked()), SLOT(_k_slotOk()));
566  q->connect(q, SIGNAL(applyClicked()), SLOT(_k_slotApply()));
567  q->connect(q, SIGNAL(defaultClicked()), SLOT(_k_slotDefault()));
568 
569  q->setMinimumSize(q->sizeHint());
570 }
571 
572 void KEditToolBar::setResourceFile( const QString& file, bool global )
573 {
574  d->m_file = file;
575  d->m_global = global;
576  d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
577 }
578 
579 KEditToolBar::~KEditToolBar()
580 {
581  delete d;
582  s_defaultToolBarName->clear();
583 }
584 
585 void KEditToolBar::setDefaultToolBar( const QString& toolBarName )
586 {
587  if ( toolBarName.isEmpty() ) {
588  d->m_defaultToolBar = *s_defaultToolBarName;
589  } else {
590  d->m_defaultToolBar = toolBarName;
591  }
592 }
593 
594 void KEditToolBarPrivate::_k_acceptOK(bool b)
595 {
596  q->enableButtonOk(b);
597  m_accept = b;
598 }
599 
600 void KEditToolBarPrivate::_k_slotDefault()
601 {
602  if ( KMessageBox::warningContinueCancel(q, i18n("Do you really want to reset all toolbars of this application to their default? The changes will be applied immediately."), i18n("Reset Toolbars"),KGuiItem(i18n("Reset")))!=KMessageBox::Continue )
603  return;
604 
605  KEditToolBarWidget * oldWidget = m_widget;
606  m_widget = 0;
607  m_accept = false;
608 
609  if ( m_factory )
610  {
611  foreach (KXMLGUIClient* client, m_factory->clients())
612  {
613  const QString file = client->localXMLFile();
614  if (file.isEmpty())
615  continue;
616  kDebug(240) << "Deleting local xml file" << file;
617  // << "for client" << client << typeid(*client).name();
618  if ( QFile::exists( file ) )
619  if ( !QFile::remove( file ) )
620  kWarning() << "Could not delete" << file;
621  }
622 
623  // Reload the xml files in all clients, now that the local files are gone
624  oldWidget->rebuildKXMLGUIClients();
625 
626  m_widget = new KEditToolBarWidget( q );
627  m_widget->load( m_factory, m_defaultToolBar );
628  }
629  else
630  {
631  int slash = m_file.lastIndexOf('/')+1;
632  if (slash)
633  m_file = m_file.mid(slash);
634  QString xml_file = KStandardDirs::locateLocal("data", KGlobal::mainComponent().componentName() + '/' + m_file);
635 
636  if ( QFile::exists( xml_file ) )
637  if ( !QFile::remove( xml_file ) )
638  kWarning() << "Could not delete " << xml_file;
639 
640  m_widget = new KEditToolBarWidget( m_collection, q );
641  q->setResourceFile( m_file, m_global );
642  }
643 
644  // Copy the geometry to minimize UI flicker
645  m_widget->setGeometry( oldWidget->geometry() );
646  q->setMainWidget(m_widget);
647  delete oldWidget;
648 
649  q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
650  q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
651 
652  q->enableButtonApply(false);
653 
654  emit q->newToolBarConfig();
655  emit q->newToolbarConfig(); // compat
656 }
657 
658 void KEditToolBarPrivate::_k_slotOk()
659 {
660  if (!m_accept) {
661  q->reject();
662  return;
663  }
664 
665  if (!m_widget->save())
666  {
667  // some error box here is needed
668  }
669  else
670  {
671  // Do not emit the "newToolBarConfig" signal again here if the "Apply"
672  // button was already pressed and no further changes were made.
673  if (q->isButtonEnabled(KDialog::Apply)) {
674  emit q->newToolBarConfig();
675  emit q->newToolbarConfig(); // compat
676  }
677  q->accept();
678  }
679 }
680 
681 void KEditToolBarPrivate::_k_slotApply()
682 {
683  (void)m_widget->save();
684  q->enableButtonApply(false);
685  emit q->newToolBarConfig();
686  emit q->newToolbarConfig(); // compat
687 }
688 
689 void KEditToolBar::setGlobalDefaultToolBar(const char *toolbarName)
690 {
691  *s_defaultToolBarName = QString::fromLatin1(toolbarName);
692 }
693 
694 KEditToolBarWidget::KEditToolBarWidget( KActionCollection *collection,
695  QWidget *parent )
696  : QWidget(parent),
697  d(new KEditToolBarWidgetPrivate(this, componentData(), collection))
698 {
699  d->setupLayout();
700 }
701 
702 KEditToolBarWidget::KEditToolBarWidget( QWidget *parent )
703  : QWidget(parent),
704  d(new KEditToolBarWidgetPrivate(this, componentData(), KXMLGUIClient::actionCollection() /*create new one*/))
705 {
706  d->setupLayout();
707 }
708 
709 KEditToolBarWidget::~KEditToolBarWidget()
710 {
711  delete d;
712 }
713 
714 void KEditToolBarWidget::load( const QString& file, bool global, const QString& defaultToolBar )
715 {
716  d->initOldStyle( file, global, defaultToolBar );
717 }
718 
719 void KEditToolBarWidget::load( KXMLGUIFactory* factory, const QString& defaultToolBar )
720 {
721  d->initFromFactory( factory, defaultToolBar );
722 }
723 
724 void KEditToolBarWidgetPrivate::initOldStyle( const QString& resourceFile,
725  bool global,
726  const QString& defaultToolBar )
727 {
728  //TODO: make sure we can call this multiple times?
729  if ( m_loadedOnce ) {
730  return;
731  }
732 
733  m_loadedOnce = true;
734  //d->m_actionList = collection->actions();
735 
736  // handle the merging
737  if (global)
738  m_widget->loadStandardsXmlFile(); // ui_standards.rc
739  const QString localXML = loadXMLFile( resourceFile );
740  m_widget->setXML(localXML, global ? true /*merge*/ : false);
741 
742  // first, get all of the necessary info for our local xml
743  XmlData local(XmlData::Local, xmlFile(resourceFile), m_collection);
744  QDomDocument domDoc;
745  domDoc.setContent(localXML);
746  local.setDomDocument(domDoc);
747  m_xmlFiles.append(local);
748 
749  // then, the merged one (ui_standards + local xml)
750  XmlData merge(XmlData::Merged, QString(), m_collection);
751  merge.setDomDocument(m_widget->domDocument());
752  m_xmlFiles.append(merge);
753 
754 #ifndef NDEBUG
755  dump();
756 #endif
757 
758  // now load in our toolbar combo box
759  loadToolBarCombo( defaultToolBar );
760  m_widget->adjustSize();
761  m_widget->setMinimumSize( m_widget->sizeHint() );
762 }
763 
764 void KEditToolBarWidgetPrivate::initFromFactory(KXMLGUIFactory* factory,
765  const QString& defaultToolBar)
766 {
767  //TODO: make sure we can call this multiple times?
768  if ( m_loadedOnce ) {
769  return;
770  }
771 
772  m_loadedOnce = true;
773 
774  m_factory = factory;
775 
776  // add all of the client data
777  bool first = true;
778  foreach (KXMLGUIClient* client, factory->clients())
779  {
780  if (client->xmlFile().isEmpty())
781  continue;
782 
783  XmlData::XmlType type = XmlData::Part;
784  if ( first ) {
785  type = XmlData::Shell;
786  first = false;
787  Q_ASSERT(!client->localXMLFile().isEmpty()); // where would we save changes??
788  }
789 
790  XmlData data(type, client->localXMLFile(), client->actionCollection());
791  QDomDocument domDoc = client->domDocument();
792  data.setDomDocument(domDoc);
793  m_xmlFiles.append(data);
794 
795  //d->m_actionList += client->actionCollection()->actions();
796  }
797 
798 #ifndef NDEBUG
799  //d->dump();
800 #endif
801 
802  // now load in our toolbar combo box
803  loadToolBarCombo( defaultToolBar );
804  m_widget->adjustSize();
805  m_widget->setMinimumSize( m_widget->sizeHint() );
806 
807  m_widget->actionCollection()->addAssociatedWidget( m_widget );
808  foreach (QAction* action, m_widget->actionCollection()->actions())
809  action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
810 }
811 
812 bool KEditToolBarWidget::save()
813 {
814  //kDebug(240) << "KEditToolBarWidget::save";
815  XmlDataList::Iterator it = d->m_xmlFiles.begin();
816  for ( ; it != d->m_xmlFiles.end(); ++it)
817  {
818  // let's not save non-modified files
819  if ( !((*it).m_isModified) )
820  continue;
821 
822  // let's also skip (non-existent) merged files
823  if ( (*it).type() == XmlData::Merged )
824  continue;
825 
826  kDebug() << (*it).domDocument().toString();
827 
828  kDebug(240) << "Saving " << (*it).xmlFile();
829  // if we got this far, we might as well just save it
830  KXMLGUIFactory::saveConfigFile((*it).domDocument(), (*it).xmlFile());
831  }
832 
833  if (!d->m_factory)
834  return true;
835 
836  rebuildKXMLGUIClients();
837 
838  return true;
839 }
840 
841 void KEditToolBarWidget::rebuildKXMLGUIClients()
842 {
843  if (!d->m_factory)
844  return;
845 
846  const QList<KXMLGUIClient*> clients = d->m_factory->clients();
847  //kDebug(240) << "factory: " << clients.count() << " clients";
848 
849  // remove the elements starting from the last going to the first
850  if (!clients.count())
851  return;
852 
853  QListIterator<KXMLGUIClient*> clientIterator = clients;
854  clientIterator.toBack();
855  while (clientIterator.hasPrevious()) {
856  KXMLGUIClient* client = clientIterator.previous();
857  //kDebug(240) << "factory->removeClient " << client;
858  d->m_factory->removeClient(client);
859  }
860 
861  KXMLGUIClient *firstClient = clients.first();
862 
863  // now, rebuild the gui from the first to the last
864  //kDebug(240) << "rebuilding the gui";
865  foreach (KXMLGUIClient* client, clients)
866  {
867  //kDebug(240) << "updating client " << client << " " << client->componentData().componentName() << " xmlFile=" << client->xmlFile();
868  QString file( client->xmlFile() ); // before setting ui_standards!
869  if ( !file.isEmpty() )
870  {
871  // passing an empty stream forces the clients to reread the XML
872  client->setXMLGUIBuildDocument( QDomDocument() );
873 
874  // for the shell, merge in ui_standards.rc
875  if ( client == firstClient ) // same assumption as in the ctor: first==shell
876  client->loadStandardsXmlFile();
877 
878  // and this forces it to use the *new* XML file
879  client->setXMLFile( file, client == firstClient /* merge if shell */ );
880 
881  // [we can't use reloadXML, it doesn't load ui_standards.rc]
882  }
883  }
884 
885  // Now we can add the clients to the factory
886  // We don't do it in the loop above because adding a part automatically
887  // adds its plugins, so we must make sure the plugins were updated first.
888  foreach(KXMLGUIClient* client, clients) {
889  d->m_factory->addClient(client);
890  }
891 }
892 
893 void KEditToolBarWidgetPrivate::setupLayout()
894 {
895  // the toolbar name combo
896  m_comboLabel = new QLabel(i18n("&Toolbar:"), m_widget);
897  m_toolbarCombo = new KComboBox(m_widget);
898  m_comboLabel->setBuddy(m_toolbarCombo);
899  m_comboSeparator = new KSeparator(m_widget);
900  QObject::connect(m_toolbarCombo, SIGNAL(activated(int)),
901  m_widget, SLOT(slotToolBarSelected(int)));
902 
903 // QPushButton *new_toolbar = new QPushButton(i18n("&New"), this);
904 // new_toolbar->setPixmap(BarIcon("document-new", KIconLoader::SizeSmall));
905 // new_toolbar->setEnabled(false); // disabled until implemented
906 // QPushButton *del_toolbar = new QPushButton(i18n("&Delete"), this);
907 // del_toolbar->setPixmap(BarIcon("edit-delete", KIconLoader::SizeSmall));
908 // del_toolbar->setEnabled(false); // disabled until implemented
909 
910  // our list of inactive actions
911  QLabel *inactive_label = new QLabel(i18n("A&vailable actions:"), m_widget);
912  m_inactiveList = new ToolBarListWidget(m_widget);
913  m_inactiveList->setDragEnabled(true);
914  m_inactiveList->setActiveList(false);
915  m_inactiveList->setMinimumSize(180, 250);
916  m_inactiveList->setDropIndicatorShown(false); // #165663
917  inactive_label->setBuddy(m_inactiveList);
918  QObject::connect(m_inactiveList, SIGNAL(itemSelectionChanged()),
919  m_widget, SLOT(slotInactiveSelectionChanged()));
920  QObject::connect(m_inactiveList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
921  m_widget, SLOT(slotInsertButton()));
922  QObject::connect(m_inactiveList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
923  m_widget, SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
924 
925  KListWidgetSearchLine *inactiveListSearchLine = new KListWidgetSearchLine(m_widget, m_inactiveList);
926  inactiveListSearchLine->setClickMessage(i18n("Filter"));
927 
928  // our list of active actions
929  QLabel *active_label = new QLabel(i18n("Curr&ent actions:"), m_widget);
930  m_activeList = new ToolBarListWidget(m_widget);
931  m_activeList->setDragEnabled(true);
932  m_activeList->setActiveList(true);
933  // With Qt-4.1 only setting MiniumWidth results in a 0-width icon column ...
934  m_activeList->setMinimumSize(m_inactiveList->minimumWidth(), 100);
935  active_label->setBuddy(m_activeList);
936 
937  QObject::connect(m_activeList, SIGNAL(itemSelectionChanged()),
938  m_widget, SLOT(slotActiveSelectionChanged()));
939  QObject::connect(m_activeList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
940  m_widget, SLOT(slotRemoveButton()));
941  QObject::connect(m_activeList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
942  m_widget, SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
943 
944  KListWidgetSearchLine *activeListSearchLine = new KListWidgetSearchLine(m_widget, m_activeList);
945  activeListSearchLine->setClickMessage(i18n("Filter"));
946 
947  // "change icon" button
948  m_changeIcon = new KPushButton(i18n( "Change &Icon..." ), m_widget);
949  m_changeIcon->setIcon(KIcon("preferences-desktop-icons"));
950  QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
951  m_hasKDialog = !kdialogExe.isEmpty();
952  m_changeIcon->setEnabled(m_hasKDialog && m_activeList->currentItem());
953 
954  QObject::connect( m_changeIcon, SIGNAL(clicked()),
955  m_widget, SLOT(slotChangeIcon()) );
956 
957  // "change icon text" button
958  m_changeIconText = new KPushButton(i18n( "Change Te&xt..." ), m_widget);
959  m_changeIconText->setIcon(KIcon("edit-rename"));
960  m_changeIconText->setEnabled(m_activeList->currentItem() != 0);
961 
962  QObject::connect( m_changeIconText, SIGNAL(clicked()),
963  m_widget, SLOT(slotChangeIconText()) );
964 
965  // The buttons in the middle
966 
967  m_upAction = new QToolButton(m_widget);
968  m_upAction->setIcon( KIcon("go-up") );
969  m_upAction->setEnabled(false);
970  m_upAction->setAutoRepeat(true);
971  QObject::connect(m_upAction, SIGNAL(clicked()), m_widget, SLOT(slotUpButton()));
972 
973  m_insertAction = new QToolButton(m_widget);
974  m_insertAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-previous" : "go-next") );
975  m_insertAction->setEnabled(false);
976  QObject::connect(m_insertAction, SIGNAL(clicked()), m_widget, SLOT(slotInsertButton()));
977 
978  m_removeAction = new QToolButton(m_widget);
979  m_removeAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-next" : "go-previous") );
980  m_removeAction->setEnabled(false);
981  QObject::connect(m_removeAction, SIGNAL(clicked()), m_widget, SLOT(slotRemoveButton()));
982 
983  m_downAction = new QToolButton(m_widget);
984  m_downAction->setIcon( KIcon("go-down") );
985  m_downAction->setEnabled(false);
986  m_downAction->setAutoRepeat(true);
987  QObject::connect(m_downAction, SIGNAL(clicked()), m_widget, SLOT(slotDownButton()));
988 
989  m_helpArea = new QLabel(m_widget);
990  m_helpArea->setWordWrap(true);
991 
992  // now start with our layouts
993  QVBoxLayout *top_layout = new QVBoxLayout(m_widget);
994  top_layout->setMargin(0);
995 
996  QVBoxLayout *name_layout = new QVBoxLayout();
997  QHBoxLayout *list_layout = new QHBoxLayout();
998 
999  QVBoxLayout *inactive_layout = new QVBoxLayout();
1000  QVBoxLayout *active_layout = new QVBoxLayout();
1001  QHBoxLayout *changeIcon_layout = new QHBoxLayout();
1002 
1003  QGridLayout *button_layout = new QGridLayout();
1004 
1005  name_layout->addWidget(m_comboLabel);
1006  name_layout->addWidget(m_toolbarCombo);
1007 // name_layout->addWidget(new_toolbar);
1008 // name_layout->addWidget(del_toolbar);
1009 
1010  button_layout->setSpacing( 0 );
1011  button_layout->setRowStretch( 0, 10 );
1012  button_layout->addWidget(m_upAction, 1, 1);
1013  button_layout->addWidget(m_removeAction, 2, 0);
1014  button_layout->addWidget(m_insertAction, 2, 2);
1015  button_layout->addWidget(m_downAction, 3, 1);
1016  button_layout->setRowStretch( 4, 10 );
1017 
1018  inactive_layout->addWidget(inactive_label);
1019  inactive_layout->addWidget(inactiveListSearchLine);
1020  inactive_layout->addWidget(m_inactiveList, 1);
1021 
1022  active_layout->addWidget(active_label);
1023  active_layout->addWidget(activeListSearchLine);
1024  active_layout->addWidget(m_activeList, 1);
1025  active_layout->addLayout(changeIcon_layout);
1026 
1027  changeIcon_layout->addWidget(m_changeIcon);
1028  changeIcon_layout->addStretch( 1 );
1029  changeIcon_layout->addWidget(m_changeIconText);
1030 
1031  list_layout->addLayout(inactive_layout);
1032  list_layout->addLayout(button_layout);
1033  list_layout->addLayout(active_layout);
1034 
1035  top_layout->addLayout(name_layout);
1036  top_layout->addWidget(m_comboSeparator);
1037  top_layout->addLayout(list_layout,10);
1038  top_layout->addWidget(m_helpArea);
1039  top_layout->addWidget(new KSeparator(m_widget));
1040 }
1041 
1042 void KEditToolBarWidgetPrivate::loadToolBarCombo( const QString& defaultToolBar )
1043 {
1044  const QLatin1String attrName( "name" );
1045  // just in case, we clear our combo
1046  m_toolbarCombo->clear();
1047 
1048  int defaultToolBarId = -1;
1049  int count = 0;
1050  // load in all of the toolbar names into this combo box
1051  XmlDataList::const_iterator xit = m_xmlFiles.constBegin();
1052  for ( ; xit != m_xmlFiles.constEnd(); ++xit)
1053  {
1054  // skip the merged one in favor of the local one,
1055  // so that we can change icons
1056  // This also makes the app-defined named for "mainToolBar" appear rather than the ui_standards-defined name.
1057  if ( (*xit).type() == XmlData::Merged )
1058  continue;
1059 
1060  // each xml file may have any number of toolbars
1061  ToolBarList::const_iterator it = (*xit).barList().begin();
1062  for ( ; it != (*xit).barList().constEnd(); ++it)
1063  {
1064  const QString text = (*xit).toolBarText( *it );
1065  m_toolbarCombo->addItem( text );
1066  const QString name = (*it).attribute(attrName);
1067  if (defaultToolBarId == -1 && name == defaultToolBar)
1068  defaultToolBarId = count;
1069  count++;
1070  }
1071  }
1072  const bool showCombo = (count > 1);
1073  m_comboLabel->setVisible(showCombo);
1074  m_comboSeparator->setVisible(showCombo);
1075  m_toolbarCombo->setVisible(showCombo);
1076  if (defaultToolBarId == -1)
1077  defaultToolBarId = 0;
1078  // we want to the specified item selected and its actions loaded
1079  m_toolbarCombo->setCurrentIndex(defaultToolBarId);
1080  slotToolBarSelected(m_toolbarCombo->currentIndex());
1081 }
1082 
1083 void KEditToolBarWidgetPrivate::loadActions(const QDomElement& elem)
1084 {
1085  const QLatin1String tagSeparator( "Separator" );
1086  const QLatin1String tagMerge( "Merge" );
1087  const QLatin1String tagActionList( "ActionList" );
1088  const QLatin1String tagAction( "Action" );
1089  const QLatin1String attrName( "name" );
1090 
1091  int sep_num = 0;
1092  QString sep_name("separator_%1");
1093 
1094  // clear our lists
1095  m_inactiveList->clear();
1096  m_activeList->clear();
1097  m_insertAction->setEnabled(false);
1098  m_removeAction->setEnabled(false);
1099  m_upAction->setEnabled(false);
1100  m_downAction->setEnabled(false);
1101 
1102  // We'll use this action collection
1103  KActionCollection* actionCollection = m_currentXmlData->actionCollection();
1104 
1105  // store the names of our active actions
1106  QSet<QString> active_list;
1107 
1108  // Filtering message requested by translators (scripting).
1109  KLocalizedString nameFilter = ki18nc("@item:intable Action name in toolbar editor", "%1");
1110 
1111  // see if our current action is in this toolbar
1112  QDomNode n = elem.firstChild();
1113  for( ; !n.isNull(); n = n.nextSibling() )
1114  {
1115  QDomElement it = n.toElement();
1116  if (it.isNull()) continue;
1117  if (it.tagName() == tagSeparator)
1118  {
1119  ToolBarItem *act = new ToolBarItem(m_activeList, tagSeparator, sep_name.arg(sep_num++), QString());
1120  act->setSeparator(true);
1121  act->setText(SEPARATORSTRING);
1122  it.setAttribute( attrName, act->internalName() );
1123  continue;
1124  }
1125 
1126  if (it.tagName() == tagMerge)
1127  {
1128  // Merge can be named or not - use the name if there is one
1129  QString name = it.attribute( attrName );
1130  ToolBarItem *act = new ToolBarItem(m_activeList, tagMerge, name, i18n("This element will be replaced with all the elements of an embedded component."));
1131  if ( name.isEmpty() )
1132  act->setText(i18n("<Merge>"));
1133  else
1134  act->setText(i18n("<Merge %1>", name));
1135  continue;
1136  }
1137 
1138  if (it.tagName() == tagActionList)
1139  {
1140  ToolBarItem *act = new ToolBarItem(m_activeList, tagActionList, it.attribute(attrName), i18n("This is a dynamic list of actions. You can move it, but if you remove it you will not be able to re-add it.") );
1141  act->setText(i18n("ActionList: %1", it.attribute(attrName)));
1142  continue;
1143  }
1144 
1145  // iterate through this client's actions
1146  // This used to iterate through _all_ actions, but we don't support
1147  // putting any action into any client...
1148  foreach (QAction* action, actionCollection->actions())
1149  {
1150  // do we have a match?
1151  if (it.attribute( attrName ) == action->objectName())
1152  {
1153  // we have a match!
1154  ToolBarItem *act = new ToolBarItem(m_activeList, it.tagName(), action->objectName(), action->toolTip());
1155  act->setText(nameFilter.subs(KGlobal::locale()->removeAcceleratorMarker(action->iconText())).toString());
1156  act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
1157  act->setTextAlongsideIconHidden(action->priority() < QAction::NormalPriority);
1158 
1159  active_list.insert(action->objectName());
1160  break;
1161  }
1162  }
1163  }
1164 
1165  // go through the rest of the collection
1166  foreach (QAction* action, actionCollection->actions())
1167  {
1168  // skip our active ones
1169  if (active_list.contains(action->objectName()))
1170  continue;
1171 
1172  ToolBarItem *act = new ToolBarItem(m_inactiveList, tagAction, action->objectName(), action->toolTip());
1173  act->setText(nameFilter.subs(KGlobal::locale()->removeAcceleratorMarker(action->text())).toString());
1174  act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
1175  }
1176 
1177  m_inactiveList->sortItems(Qt::AscendingOrder);
1178 
1179  // finally, add default separators to the inactive list
1180  ToolBarItem *act = new ToolBarItem(0L, tagSeparator, sep_name.arg(sep_num++), QString());
1181  act->setSeparator(true);
1182  act->setText(SEPARATORSTRING);
1183  m_inactiveList->insertItem(0, act);
1184 }
1185 
1186 KActionCollection *KEditToolBarWidget::actionCollection() const
1187 {
1188  return d->m_collection;
1189 }
1190 
1191 void KEditToolBarWidgetPrivate::slotToolBarSelected(int index)
1192 {
1193  const QLatin1String attrName( "name" );
1194  // We need to find the XmlData and toolbar element for this index
1195  // To do that, we do the same iteration as the one which filled in the combobox.
1196 
1197  int toolbarNumber = 0;
1198  XmlDataList::iterator xit = m_xmlFiles.begin();
1199  for ( ; xit != m_xmlFiles.end(); ++xit) {
1200 
1201  // skip the merged one in favor of the local one,
1202  // so that we can change icons
1203  if ( (*xit).type() == XmlData::Merged )
1204  continue;
1205 
1206  // each xml file may have any number of toolbars
1207  ToolBarList::Iterator it = (*xit).barList().begin();
1208  for ( ; it != (*xit).barList().end(); ++it) {
1209 
1210  // is this our toolbar?
1211  if (toolbarNumber == index) {
1212 
1213  // save our current settings
1214  m_currentXmlData = & (*xit);
1215  m_currentToolBarElem = *it;
1216 
1217  kDebug() << "found toolbar" << m_currentXmlData->toolBarText(*it) << "m_currentXmlData set to";
1218  m_currentXmlData->dump();
1219 
1220  // If this is a Merged xmldata, clicking the "change icon" button would assert...
1221  Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
1222 
1223  // load in our values
1224  loadActions(m_currentToolBarElem);
1225 
1226  if ((*xit).type() == XmlData::Part || (*xit).type() == XmlData::Shell)
1227  m_widget->setDOMDocument( (*xit).domDocument() );
1228  return;
1229  }
1230  ++toolbarNumber;
1231 
1232  }
1233  }
1234 }
1235 
1236 void KEditToolBarWidgetPrivate::slotInactiveSelectionChanged()
1237 {
1238  if (m_inactiveList->selectedItems().count())
1239  {
1240  m_insertAction->setEnabled(true);
1241  QString statusText = static_cast<ToolBarItem*>(m_inactiveList->selectedItems().first())->statusText();
1242  m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
1243  }
1244  else
1245  {
1246  m_insertAction->setEnabled(false);
1247  m_helpArea->setText( QString() );
1248  }
1249 }
1250 
1251 void KEditToolBarWidgetPrivate::slotActiveSelectionChanged()
1252 {
1253  ToolBarItem* toolitem = 0;
1254  if (!m_activeList->selectedItems().isEmpty())
1255  toolitem = static_cast<ToolBarItem *>(m_activeList->selectedItems().first());
1256 
1257  m_removeAction->setEnabled( toolitem );
1258 
1259  m_changeIcon->setEnabled( toolitem &&
1260  m_hasKDialog &&
1261  toolitem->internalTag() == "Action" );
1262 
1263  m_changeIconText->setEnabled( toolitem &&
1264  toolitem->internalTag() == "Action" );
1265 
1266  if (toolitem)
1267  {
1268  m_upAction->setEnabled(toolitem->index() != 0);
1269  m_downAction->setEnabled(toolitem->index() != toolitem->listWidget()->count() - 1);
1270 
1271  QString statusText = toolitem->statusText();
1272  m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
1273  }
1274  else
1275  {
1276  m_upAction->setEnabled(false);
1277  m_downAction->setEnabled(false);
1278  m_helpArea->setText( QString() );
1279  }
1280 }
1281 
1282 void KEditToolBarWidgetPrivate::slotInsertButton()
1283 {
1284  QString internalName = static_cast<ToolBarItem *>(m_inactiveList->currentItem())->internalName();
1285 
1286  insertActive(m_inactiveList->currentItem(), m_activeList->currentItem(), false);
1287  // we're modified, so let this change
1288  emit m_widget->enableOk(true);
1289 
1290  slotToolBarSelected( m_toolbarCombo->currentIndex() );
1291 
1292  selectActiveItem( internalName );
1293 }
1294 
1295 void KEditToolBarWidgetPrivate::selectActiveItem(const QString& internalName)
1296 {
1297  int activeItemCount = m_activeList->count();
1298  for(int i = 0; i < activeItemCount; i++)
1299  {
1300  ToolBarItem * item = static_cast<ToolBarItem *>(m_activeList->item(i));
1301  if (item->internalName()==internalName)
1302  {
1303  m_activeList->setCurrentItem(item);
1304  break;
1305  }
1306  }
1307 }
1308 
1309 void KEditToolBarWidgetPrivate::slotRemoveButton()
1310 {
1311  removeActive( m_activeList->currentItem() );
1312 
1313  // we're modified, so let this change
1314  emit m_widget->enableOk(true);
1315 
1316  slotToolBarSelected( m_toolbarCombo->currentIndex() );
1317 }
1318 
1319 void KEditToolBarWidgetPrivate::insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend)
1320 {
1321  if (!item)
1322  return;
1323 
1324  static const QString &tagAction = KGlobal::staticQString( "Action" );
1325  static const QString &tagSeparator = KGlobal::staticQString( "Separator" );
1326  static const QString &attrName = KGlobal::staticQString( "name" );
1327  static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
1328 
1329  QDomElement new_item;
1330  // let's handle the separator specially
1331  if (item->isSeparator())
1332  new_item = m_widget->domDocument().createElement(tagSeparator);
1333  else
1334  new_item = m_widget->domDocument().createElement(tagAction);
1335 
1336  new_item.setAttribute(attrName, item->internalName());
1337 
1338  Q_ASSERT(!m_currentToolBarElem.isNull());
1339 
1340  if (before)
1341  {
1342  // we have the item in the active list which is before the new
1343  // item.. so let's try our best to add our new item right after it
1344  QDomElement elem = findElementForToolBarItem( before );
1345  Q_ASSERT( !elem.isNull() );
1346  m_currentToolBarElem.insertAfter(new_item, elem);
1347  }
1348  else
1349  {
1350  // simply put it at the beginning or the end of the list.
1351  if (prepend)
1352  m_currentToolBarElem.insertBefore(new_item, m_currentToolBarElem.firstChild());
1353  else
1354  m_currentToolBarElem.appendChild(new_item);
1355  }
1356 
1357  // and set this container as a noMerge
1358  m_currentToolBarElem.setAttribute( attrNoMerge, "1");
1359 
1360  // update the local doc
1361  updateLocal(m_currentToolBarElem);
1362 }
1363 
1364 void KEditToolBarWidgetPrivate::removeActive(ToolBarItem *item)
1365 {
1366  if (!item)
1367  return;
1368 
1369  static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
1370 
1371  // we're modified, so let this change
1372  emit m_widget->enableOk(true);
1373 
1374  // now iterate through to find the child to nuke
1375  QDomElement elem = findElementForToolBarItem( item );
1376  if ( !elem.isNull() )
1377  {
1378  // nuke myself!
1379  m_currentToolBarElem.removeChild(elem);
1380 
1381  // and set this container as a noMerge
1382  m_currentToolBarElem.setAttribute( attrNoMerge, "1");
1383 
1384  // update the local doc
1385  updateLocal(m_currentToolBarElem);
1386  }
1387 }
1388 
1389 void KEditToolBarWidgetPrivate::slotUpButton()
1390 {
1391  ToolBarItem *item = m_activeList->currentItem();
1392 
1393  if (!item) {
1394  Q_ASSERT(false);
1395  return;
1396  }
1397 
1398  int row = item->listWidget()->row(item) - 1;
1399  // make sure we're not the top item already
1400  if (row < 0) {
1401  Q_ASSERT(false);
1402  return;
1403  }
1404 
1405  // we're modified, so let this change
1406  emit m_widget->enableOk(true);
1407 
1408  moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(row - 1)) );
1409 }
1410 
1411 void KEditToolBarWidgetPrivate::moveActive( ToolBarItem* item, ToolBarItem* before )
1412 {
1413  QDomElement e = findElementForToolBarItem( item );
1414 
1415  if ( e.isNull() )
1416  return;
1417 
1418  // remove item
1419  m_activeList->takeItem(m_activeList->row(item));
1420 
1421  // put it where it's supposed to go
1422  m_activeList->insertItem(m_activeList->row(before) + 1, item);
1423 
1424  // make it selected again
1425  m_activeList->setCurrentItem(item);
1426 
1427  // and do the real move in the DOM
1428  if ( !before )
1429  m_currentToolBarElem.insertBefore(e, m_currentToolBarElem.firstChild() );
1430  else
1431  m_currentToolBarElem.insertAfter(e, findElementForToolBarItem( (ToolBarItem*)before ));
1432 
1433  // and set this container as a noMerge
1434  static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
1435  m_currentToolBarElem.setAttribute( attrNoMerge, "1");
1436 
1437  // update the local doc
1438  updateLocal(m_currentToolBarElem);
1439 }
1440 
1441 void KEditToolBarWidgetPrivate::slotDownButton()
1442 {
1443  ToolBarItem *item = m_activeList->currentItem();
1444 
1445  if (!item) {
1446  Q_ASSERT(false);
1447  return;
1448  }
1449 
1450  // make sure we're not the bottom item already
1451  int newRow = item->listWidget()->row(item) + 1;
1452  if (newRow >= item->listWidget()->count()) {
1453  Q_ASSERT(false);
1454  return;
1455  }
1456 
1457  // we're modified, so let this change
1458  emit m_widget->enableOk(true);
1459 
1460  moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(newRow)) );
1461 }
1462 
1463 void KEditToolBarWidgetPrivate::updateLocal(QDomElement& elem)
1464 {
1465  static const QString &attrName = KGlobal::staticQString( "name" );
1466 
1467  XmlDataList::Iterator xit = m_xmlFiles.begin();
1468  for ( ; xit != m_xmlFiles.end(); ++xit)
1469  {
1470  if ( (*xit).type() == XmlData::Merged )
1471  continue;
1472 
1473  if ( (*xit).type() == XmlData::Shell ||
1474  (*xit).type() == XmlData::Part )
1475  {
1476  if ( m_currentXmlData->xmlFile() == (*xit).xmlFile() )
1477  {
1478  (*xit).m_isModified = true;
1479  return;
1480  }
1481 
1482  continue;
1483  }
1484 
1485  (*xit).m_isModified = true;
1486 
1487  ToolBarList::Iterator it = (*xit).barList().begin();
1488  for ( ; it != (*xit).barList().end(); ++it)
1489  {
1490  QString name( (*it).attribute( attrName ) );
1491  QString tag( (*it).tagName() );
1492  if ( (tag != elem.tagName()) || (name != elem.attribute(attrName)) )
1493  continue;
1494 
1495  QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
1496  toolbar.replaceChild(elem, (*it));
1497  return;
1498  }
1499 
1500  // just append it
1501  QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
1502  Q_ASSERT(!toolbar.isNull());
1503  toolbar.appendChild(elem);
1504  }
1505 }
1506 
1507 void KEditToolBarWidgetPrivate::slotChangeIcon()
1508 {
1509  // We can't use KIconChooser here, since it's in libkio
1510  // ##### KDE4: reconsider this, e.g. move KEditToolBar to libkio,
1511  // ##### or better, dlopen libkfile from here like kio does.
1512 
1513  //if the process is already running (e.g. when somebody clicked the change button twice (see #127149)) - do nothing...
1514  //otherwise m_kdialogProcess will be overwritten and set to zero in slotProcessExited()...crash!
1515  if ( m_kdialogProcess && m_kdialogProcess->state() == QProcess::Running )
1516  return;
1517 
1518  m_currentXmlData->dump();
1519  Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
1520 
1521  m_kdialogProcess = new KProcess;
1522  QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
1523  (*m_kdialogProcess) << kdialogExe;
1524  (*m_kdialogProcess) << "--caption";
1525  (*m_kdialogProcess) << i18n( "Change Icon" );
1526  (*m_kdialogProcess) << "--embed";
1527  (*m_kdialogProcess) << QString::number( (quintptr)m_widget->window()->winId() );
1528  (*m_kdialogProcess) << "--geticon";
1529  (*m_kdialogProcess) << "Toolbar";
1530  (*m_kdialogProcess) << "Actions";
1531  m_kdialogProcess->setOutputChannelMode(KProcess::OnlyStdoutChannel);
1532  m_kdialogProcess->setNextOpenMode( QIODevice::ReadOnly | QIODevice::Text );
1533  m_kdialogProcess->start();
1534  if ( !m_kdialogProcess->waitForStarted() ) {
1535  kError(240) << "Can't run " << kdialogExe << endl;
1536  delete m_kdialogProcess;
1537  m_kdialogProcess = 0;
1538  return;
1539  }
1540 
1541  m_activeList->setEnabled( false ); // don't change the current item
1542  m_toolbarCombo->setEnabled( false ); // don't change the current toolbar
1543 
1544  QObject::connect( m_kdialogProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
1545  m_widget, SLOT(slotProcessExited()) );
1546 }
1547 
1548 void KEditToolBarWidgetPrivate::slotChangeIconText()
1549 {
1550  m_currentXmlData->dump();
1551  ToolBarItem *item = m_activeList->currentItem();
1552 
1553  if(item){
1554  QString iconText = item->text();
1555  bool hidden = item->isTextAlongsideIconHidden();
1556 
1557  IconTextEditDialog dialog(m_widget);
1558  dialog.setIconText(iconText);
1559  dialog.setTextAlongsideIconHidden(hidden);
1560 
1561  bool ok = dialog.exec() == KDialog::Accepted;
1562  iconText = dialog.iconText();
1563  hidden = dialog.textAlongsideIconHidden();
1564 
1565  bool hiddenChanged = hidden != item->isTextAlongsideIconHidden();
1566  bool iconTextChanged = iconText != item->text();
1567 
1568  if (!ok || (!hiddenChanged && !iconTextChanged))
1569  return;
1570 
1571  item->setText(iconText);
1572  item->setTextAlongsideIconHidden(hidden);
1573 
1574  Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
1575 
1576  m_currentXmlData->m_isModified = true;
1577 
1578  // Get hold of ActionProperties tag
1579  QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
1580  // Find or create an element for this action
1581  QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
1582  Q_ASSERT( !act_elem.isNull() );
1583  if (iconTextChanged)
1584  act_elem.setAttribute( "iconText", iconText );
1585  if (hiddenChanged)
1586  act_elem.setAttribute( "priority", hidden ? QAction::LowPriority : QAction::NormalPriority );
1587 
1588  // we're modified, so let this change
1589  emit m_widget->enableOk(true);
1590  }
1591 }
1592 
1593 void KEditToolBarWidgetPrivate::slotProcessExited()
1594 {
1595  m_activeList->setEnabled( true );
1596  m_toolbarCombo->setEnabled( true );
1597 
1598  QString icon;
1599 
1600  if (!m_kdialogProcess) {
1601  kError(240) << "Something is wrong here! m_kdialogProcess is zero!" << endl;
1602  return;
1603  }
1604 
1605  icon = QString::fromLocal8Bit( m_kdialogProcess->readLine() );
1606  icon = icon.left( icon.indexOf( '\n' ) );
1607  kDebug(240) << "icon=" << icon;
1608  if ( m_kdialogProcess->exitStatus() != QProcess::NormalExit ||
1609  icon.isEmpty() ) {
1610  delete m_kdialogProcess;
1611  m_kdialogProcess = 0;
1612  return;
1613  }
1614 
1615  ToolBarItem *item = m_activeList->currentItem();
1616  kDebug() << item;
1617  if(item){
1618  item->setIcon(KIcon(icon));
1619 
1620  Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
1621 
1622  m_currentXmlData->m_isModified = true;
1623 
1624  // Get hold of ActionProperties tag
1625  QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
1626  // Find or create an element for this action
1627  QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
1628  Q_ASSERT( !act_elem.isNull() );
1629  act_elem.setAttribute( "icon", icon );
1630 
1631  // we're modified, so let this change
1632  emit m_widget->enableOk(true);
1633  }
1634 
1635  delete m_kdialogProcess;
1636  m_kdialogProcess = 0;
1637 }
1638 
1639 void KEditToolBarWidgetPrivate::slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList)
1640 {
1641  //kDebug() << "slotDropped list=" << (list==m_activeList?"activeList":"inactiveList")
1642  // << "index=" << index << "sourceIsActiveList=" << sourceIsActiveList;
1643  if (list == m_activeList) {
1644  ToolBarItem* after = index > 0 ? static_cast<ToolBarItem *>(list->item(index-1)) : 0;
1645  //kDebug() << "after" << after->text() << after->internalTag();
1646  if (sourceIsActiveList) {
1647  // has been dragged within the active list (moved).
1648  moveActive(item, after);
1649  } else {
1650  // dragged from the inactive list to the active list
1651  insertActive(item, after, true);
1652  }
1653  } else if (list == m_inactiveList) {
1654  // has been dragged to the inactive list -> remove from the active list.
1655  removeActive(item);
1656  }
1657 
1658  delete item; // not needed anymore. must be deleted before slotToolBarSelected clears the lists
1659 
1660  // we're modified, so let this change
1661  emit m_widget->enableOk(true);
1662 
1663  slotToolBarSelected( m_toolbarCombo->currentIndex() );
1664 }
1665 
1666 
1667 void KEditToolBar::showEvent( QShowEvent * event )
1668 {
1669  if (!event->spontaneous()) {
1670  // The dialog has been shown, enable toolbar editing
1671  if ( d->m_factory ) {
1672  // call the xmlgui-factory version
1673  d->m_widget->load( d->m_factory, d->m_defaultToolBar );
1674  } else {
1675  // call the action collection version
1676  d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
1677  }
1678 
1679  KToolBar::setToolBarsEditable(true);
1680  }
1681  KDialog::showEvent(event);
1682 }
1683 
1684 void KEditToolBar::hideEvent(QHideEvent* event)
1685 {
1686  // The dialog has been hidden, disable toolbar editing
1687  KToolBar::setToolBarsEditable(false);
1688 
1689  KDialog::hideEvent(event);
1690 }
1691 
1692 #include "kedittoolbar.moc"
1693 #include "kedittoolbar_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Nov 16 2012 15:01:58 by doxygen 1.8.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal