• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

kedittoolbar.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
00003    Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
00004    Copyright     2007 David Faure <faure@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License version 2 as published by the Free Software Foundation.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 #include <kedittoolbar.h>
00021 #include <kedittoolbar_p.h>
00022 
00023 
00024 #include <QtXml/QDomDocument>
00025 #include <QtGui/QLayout>
00026 #include <QtCore/QDir>
00027 #include <QtCore/QFile>
00028 #include <QHeaderView>
00029 #include <QtGui/QToolButton>
00030 #include <QtGui/QLabel>
00031 #include <QtGui/QApplication>
00032 #include <QMimeData>
00033 
00034 #include <kstandarddirs.h>
00035 #include <klocale.h>
00036 #include <kicon.h>
00037 #include <kiconloader.h>
00038 #include <kcomponentdata.h>
00039 #include <kmessagebox.h>
00040 #include <kxmlguifactory.h>
00041 #include <kseparator.h>
00042 #include <kconfig.h>
00043 #include <kdebug.h>
00044 #include <kpushbutton.h>
00045 #include <kprocess.h>
00046 #include <ktoolbar.h>
00047 #include <kdeversion.h>
00048 #include <kcombobox.h>
00049 
00050 #include "kaction.h"
00051 #include "kactioncollection.h"
00052 
00053 static const char * const separatorstring = I18N_NOOP("--- separator ---");
00054 
00055 #define SEPARATORSTRING i18n(separatorstring)
00056 
00057 static const char* const s_XmlTypeToString[] = { "Shell", "Part", "Local", "Merged" };
00058 
00059 typedef QList<QDomElement> ToolBarList;
00060 
00061 namespace KDEPrivate {
00062 
00066 static ToolBarList findToolBars(const QDomElement& start)
00067 {
00068     static const QString &tagToolBar = KGlobal::staticQString( "ToolBar" );
00069     static const QString &tagMenuBar = KGlobal::staticQString( "MenuBar" );
00070     static const QString &attrNoEdit = KGlobal::staticQString( "noEdit" );
00071     ToolBarList list;
00072 
00073     for( QDomElement elem = start; !elem.isNull(); elem = elem.nextSiblingElement() ) {
00074         if (elem.tagName() == tagToolBar) {
00075             if ( elem.attribute( attrNoEdit ) != "true" )
00076                 list.append(elem);
00077         } else {
00078             if (elem.tagName() != tagMenuBar) // there are no toolbars inside the menubar :)
00079                 list += findToolBars(elem.firstChildElement()); // recursive
00080         }
00081     }
00082 
00083     return list;
00084 }
00085 
00086 class XmlData
00087 {
00088 public:
00089     enum XmlType { Shell = 0, Part, Local, Merged };
00090 
00091     explicit XmlData( XmlType xmlType, const QString& xmlFile, KActionCollection* collection )
00092         : m_isModified(false),
00093           m_xmlFile(xmlFile),
00094           m_type(xmlType),
00095           m_actionCollection(collection)
00096     {
00097     }
00098     void dump() const
00099     {
00100         kDebug(240) << "XmlData" << this << "type" << s_XmlTypeToString[m_type] << "xmlFile:" << m_xmlFile;
00101         foreach (const QDomElement& element, m_barList) {
00102             kDebug(240) << "    ToolBar:" << toolBarText( element );
00103         }
00104         if ( m_actionCollection )
00105             kDebug(240) << "    " << m_actionCollection->actions().count() << "actions in the collection.";
00106         else
00107             kDebug(240) << "    no action collection.";
00108     }
00109     QString xmlFile() const { return m_xmlFile; }
00110     XmlType type() const { return m_type; }
00111     KActionCollection* actionCollection() const { return m_actionCollection; }
00112     void setDomDocument(const QDomDocument& domDoc)
00113     {
00114         m_document = domDoc;
00115         m_barList = findToolBars(m_document.documentElement());
00116     }
00117     // Return reference, for e.g. actionPropertiesElement() to modify the document
00118     QDomDocument& domDocument() { return m_document; }
00119     const QDomDocument& domDocument() const { return m_document; }
00120 
00124     QString toolBarText( const QDomElement& it ) const;
00125 
00126 
00127     bool         m_isModified;
00128     ToolBarList& barList() { return m_barList; }
00129     const ToolBarList& barList() const { return m_barList; }
00130 
00131 private:
00132     ToolBarList  m_barList;
00133     QString      m_xmlFile;
00134     QDomDocument m_document;
00135     XmlType      m_type;
00136     KActionCollection* m_actionCollection;
00137 };
00138 
00139 QString XmlData::toolBarText( const QDomElement& it ) const
00140 {
00141     static const QString &tagText = KGlobal::staticQString( "text" );
00142     static const QString &tagText2 = KGlobal::staticQString( "Text" );
00143     static const QString &attrName = KGlobal::staticQString( "name" );
00144 
00145     QString name;
00146     QByteArray txt( it.namedItem( tagText ).toElement().text().toUtf8() );
00147     if ( txt.isEmpty() )
00148         txt = it.namedItem( tagText2 ).toElement().text().toUtf8();
00149     if ( txt.isEmpty() )
00150         name = it.attribute( attrName );
00151     else
00152         name = i18n( txt );
00153 
00154     // the name of the toolbar might depend on whether or not
00155     // it is in kparts
00156     if ( ( m_type == XmlData::Shell ) ||
00157          ( m_type == XmlData::Part ) ) {
00158         QString doc_name(m_document.documentElement().attribute( attrName ));
00159         name += " <" + doc_name + '>';
00160     }
00161     return name;
00162 }
00163 
00164 
00165 typedef QList<XmlData> XmlDataList;
00166 
00167 class ToolBarItem : public QListWidgetItem
00168 {
00169 public:
00170     ToolBarItem(QListWidget *parent, const QString& tag = QString(), const QString& name = QString(), const QString& statusText = QString())
00171         : QListWidgetItem(parent),
00172           m_internalTag(tag),
00173           m_internalName(name),
00174           m_statusText(statusText),
00175           m_isSeparator(false)
00176     {
00177         // Drop between items, not onto items
00178         setFlags((flags() | Qt::ItemIsDragEnabled) & ~Qt::ItemIsDropEnabled);
00179     }
00180 
00181     void setInternalTag(const QString &tag) { m_internalTag = tag; }
00182     void setInternalName(const QString &name) { m_internalName = name; }
00183     void setStatusText(const QString &text) { m_statusText = text; }
00184     void setSeparator(bool sep) { m_isSeparator = sep; }
00185     QString internalTag() const { return m_internalTag; }
00186     QString internalName() const { return m_internalName; }
00187     QString statusText() const { return m_statusText; }
00188     bool isSeparator() const { return m_isSeparator; }
00189 
00190     int index() const { return listWidget()->row(const_cast<ToolBarItem*>(this)); }
00191 
00192 private:
00193     QString m_internalTag;
00194     QString m_internalName;
00195     QString m_statusText;
00196     bool m_isSeparator;
00197 };
00198 
00199 static QDataStream & operator<< ( QDataStream & s, const ToolBarItem & item ) {
00200     s << item.internalTag();
00201     s << item.internalName();
00202     s << item.statusText();
00203     s << item.isSeparator();
00204     return s;
00205 }
00206 static QDataStream & operator>> ( QDataStream & s, ToolBarItem & item ) {
00207     QString internalTag;
00208     s >> internalTag;
00209     item.setInternalTag(internalTag);
00210     QString internalName;
00211     s >> internalName;
00212     item.setInternalName(internalName);
00213     QString statusText;
00214     s >> statusText;
00215     item.setStatusText(statusText);
00216     bool sep;
00217     s >> sep;
00218     item.setSeparator(sep);
00219     return s;
00220 }
00221 
00223 
00224 ToolBarListWidget::ToolBarListWidget(QWidget *parent)
00225     : QListWidget(parent),
00226       m_activeList(true)
00227 {
00228     setDragDropMode(QAbstractItemView::DragDrop); // no internal moves
00229 }
00230 
00231 QMimeData* ToolBarListWidget::mimeData(const QList<QListWidgetItem*> items) const
00232 {
00233     if (items.isEmpty())
00234         return 0;
00235     QMimeData* mimedata = new QMimeData();
00236 
00237     QByteArray data;
00238     {
00239         QDataStream stream(&data, QIODevice::WriteOnly);
00240         // we only support single selection
00241         ToolBarItem* item = static_cast<ToolBarItem *>(items.first());
00242         stream << *item;
00243     }
00244 
00245     mimedata->setData("application/x-kde-action-list", data);
00246     mimedata->setData("application/x-kde-source-treewidget", m_activeList ? "active" : "inactive");
00247 
00248     return mimedata;
00249 }
00250 
00251 bool ToolBarListWidget::dropMimeData(int index, const QMimeData * mimeData, Qt::DropAction action)
00252 {
00253     Q_UNUSED(action)
00254     const QByteArray data = mimeData->data("application/x-kde-action-list");
00255     if (data.isEmpty())
00256         return false;
00257     QDataStream stream(data);
00258     const bool sourceIsActiveList = mimeData->data("application/x-kde-source-treewidget") == "active";
00259     ToolBarItem* item = new ToolBarItem(this); // needs parent, use this temporarily
00260     stream >> *item;
00261     emit dropped(this, index, item, sourceIsActiveList);
00262     return true;
00263 }
00264 
00265 ToolBarItem* ToolBarListWidget::currentItem() const
00266 {
00267     return static_cast<ToolBarItem*>(QListWidget::currentItem());
00268 }
00269 
00270 class KEditToolBarWidgetPrivate
00271 {
00272 public:
00280     KEditToolBarWidgetPrivate(KEditToolBarWidget* widget,
00281                               const KComponentData &cData, KActionCollection* collection)
00282         : m_collection( collection ),
00283           m_widget (widget),
00284           m_loadedOnce( false )
00285     {
00286         m_componentData = cData;
00287         m_isPart   = false;
00288         m_helpArea = 0L;
00289         m_kdialogProcess = 0;
00290         // We want items with an icon to align with items without icon
00291         // So we use an empty QPixmap for that
00292         const int iconSize = widget->style()->pixelMetric(QStyle::PM_SmallIconSize);
00293         m_emptyIcon = QPixmap(iconSize, iconSize);
00294         m_emptyIcon.fill(Qt::transparent);
00295     }
00296     ~KEditToolBarWidgetPrivate()
00297     {
00298     }
00299 
00300     // private slots
00301     void slotToolBarSelected(int index);
00302 
00303     void slotInactiveSelectionChanged();
00304     void slotActiveSelectionChanged();
00305 
00306     void slotInsertButton();
00307     void slotRemoveButton();
00308     void slotUpButton();
00309     void slotDownButton();
00310 
00311     void slotChangeIcon();
00312 
00313     void slotProcessExited();
00314 
00315     void slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList);
00316 
00317 
00318     void setupLayout();
00319 
00320     void initNonKPart( const QString& file, bool global, const QString& defaultToolbar );
00321     void initKPart( KXMLGUIFactory* factory, const QString& defaultToolbar );
00322     void loadToolBarCombo( const QString& defaultToolbar );
00323     void loadActions(const QDomElement& elem);
00324 
00325     QString xmlFile(const QString& xml_file) const
00326     {
00327         return xml_file.isEmpty() ? QString(m_componentData.componentName()) + "ui.rc" :
00328             xml_file;
00329     }
00330 
00334     QString loadXMLFile(const QString& _xml_file)
00335     {
00336         QString raw_xml;
00337         QString xml_file = xmlFile(_xml_file);
00338         //kDebug() << "loadXMLFile xml_file=" << xml_file;
00339 
00340         if ( !QDir::isRelativePath(xml_file) )
00341             raw_xml = KXMLGUIFactory::readConfigFile(xml_file);
00342         else
00343             raw_xml = KXMLGUIFactory::readConfigFile(xml_file, m_componentData);
00344 
00345         return raw_xml;
00346     }
00347 
00351     QDomElement findElementForToolBarItem( const ToolBarItem* item ) const
00352     {
00353         static const QString &attrName    = KGlobal::staticQString( "name" );
00354         //kDebug(240) << "looking for name=" << item->internalName() << "and tag=" << item->internalTag();
00355         for(QDomNode n = m_currentToolBarElem.firstChild(); !n.isNull(); n = n.nextSibling())
00356         {
00357             QDomElement elem = n.toElement();
00358             if ((elem.attribute(attrName) == item->internalName()) &&
00359                 (elem.tagName() == item->internalTag()))
00360                 return elem;
00361         }
00362         //kDebug(240) << "no item found in the DOM with name=" << item->internalName() << "and tag=" << item->internalTag();
00363         return QDomElement();
00364     }
00365 
00366     void insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend = false);
00367     void removeActive(ToolBarItem *item);
00368     void moveActive(ToolBarItem *item, ToolBarItem *before);
00369     void updateLocal(QDomElement& elem);
00370 
00371 #ifndef NDEBUG
00372     void dump() const
00373     {
00374         XmlDataList::const_iterator xit = m_xmlFiles.begin();
00375         for ( ; xit != m_xmlFiles.end(); ++xit ) {
00376             (*xit).dump();
00377         }
00378     }
00379 #endif
00380 
00381     KComboBox *m_toolbarCombo;
00382 
00383     QToolButton *m_upAction;
00384     QToolButton *m_removeAction;
00385     QToolButton *m_insertAction;
00386     QToolButton *m_downAction;
00387 
00388     //QValueList<KAction*> m_actionList;
00389     KActionCollection* m_collection;
00390     KEditToolBarWidget* m_widget;
00391     KComponentData m_componentData;
00392 
00393     QPixmap m_emptyIcon;
00394 
00395     XmlData*     m_currentXmlData;
00396     QDomElement m_currentToolBarElem;
00397 
00398     QString            m_xmlFile;
00399     QString            m_globalFile;
00400     QString            m_rcFile;
00401     QDomDocument       m_localDoc;
00402 
00403     ToolBarList        m_barList;
00404     ToolBarListWidget *m_inactiveList;
00405     ToolBarListWidget *m_activeList;
00406 
00407     XmlDataList m_xmlFiles;
00408 
00409     QLabel     *m_comboLabel;
00410     KSeparator *m_comboSeparator;
00411     QLabel * m_helpArea;
00412     KPushButton* m_changeIcon;
00413     KProcess* m_kdialogProcess;
00414     bool m_isPart : 1;
00415     bool m_hasKDialog : 1;
00416     bool m_loadedOnce : 1;
00417 };
00418 
00419 }
00420 
00421 using namespace KDEPrivate;
00422 
00423 
00424 class KEditToolBarPrivate {
00425 public:
00426     KEditToolBarPrivate(KEditToolBar *q): q(q),
00427       m_accept(false), m_global(false),
00428       m_collection(0), m_factory(0), m_widget(0) {}
00429 
00430     void init();
00431 
00432     void _k_slotOk();
00433     void _k_slotApply();
00434     void _k_acceptOK(bool);
00435     void _k_slotDefault();
00436 
00437     KEditToolBar *q;
00438     bool m_accept;
00439     // Save parameters for recreating widget after resetting toolbar
00440     bool m_global;
00441     KActionCollection* m_collection;
00442     QString m_file;
00443     QString m_defaultToolBar;
00444     KXMLGUIFactory* m_factory;
00445     KEditToolBarWidget *m_widget;
00446 };
00447 
00448 K_GLOBAL_STATIC(QString, s_defaultToolBarName)
00449 
00450 KEditToolBar::KEditToolBar( KActionCollection *collection,
00451                             QWidget* parent )
00452   : KDialog(parent),
00453     d(new KEditToolBarPrivate(this))
00454 {
00455     d->m_widget = new KEditToolBarWidget( collection, this);
00456     d->init();
00457     d->m_collection = collection;
00458 }
00459 
00460 KEditToolBar::KEditToolBar( KXMLGUIFactory* factory,
00461                             QWidget* parent )
00462     : KDialog(parent),
00463       d(new KEditToolBarPrivate(this))
00464 {
00465     d->m_widget = new KEditToolBarWidget( this);
00466     d->init();
00467     d->m_factory = factory;
00468 }
00469 
00470 void KEditToolBarPrivate::init()
00471 {
00472     m_accept = false;
00473     m_factory = 0;
00474 
00475     q->setDefaultToolBar( QString() );
00476 
00477     q->setCaption(i18n("Configure Toolbars"));
00478     q->setButtons(KDialog::Default|KDialog::Ok|KDialog::Apply|KDialog::Cancel);
00479     q->setDefaultButton(KDialog::Ok);
00480 
00481     q->setModal(false);
00482 
00483     q->setMainWidget(m_widget);
00484 
00485     q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
00486     q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
00487     q->enableButtonApply(false);
00488 
00489     q->connect(q, SIGNAL(okClicked()), SLOT(_k_slotOk()));
00490     q->connect(q, SIGNAL(applyClicked()), SLOT(_k_slotApply()));
00491     q->connect(q, SIGNAL(defaultClicked()), SLOT(_k_slotDefault()));
00492 
00493     q->setMinimumSize(q->sizeHint());
00494 }
00495 
00496 void KEditToolBar::setResourceFile( const QString& file, bool global )
00497 {
00498     d->m_file = file;
00499     d->m_global = global;
00500     d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
00501 }
00502 
00503 KEditToolBar::~KEditToolBar()
00504 {
00505     delete d;
00506     s_defaultToolBarName->clear();
00507 }
00508 
00509 void KEditToolBar::setDefaultToolBar( const QString& toolBarName )
00510 {
00511     if ( toolBarName.isEmpty() ) {
00512         d->m_defaultToolBar = *s_defaultToolBarName;
00513     } else {
00514         d->m_defaultToolBar = toolBarName;
00515     }
00516 }
00517 
00518 void KEditToolBarPrivate::_k_acceptOK(bool b)
00519 {
00520     q->enableButtonOk(b);
00521     m_accept = b;
00522 }
00523 
00524 void KEditToolBarPrivate::_k_slotDefault()
00525 {
00526     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 )
00527         return;
00528 
00529     delete m_widget;
00530     m_widget = 0;
00531     m_accept = false;
00532 
00533     if ( m_factory )
00534     {
00535         const QString localPrefix = KStandardDirs::locateLocal("data", "");
00536         foreach (KXMLGUIClient* client, m_factory->clients())
00537         {
00538             QString file = client->xmlFile();
00539 
00540             if (file.isNull()) // ##### should be isEmpty?
00541                 continue;
00542 
00543             if (QDir::isRelativePath(file))
00544             {
00545                 const KComponentData cData = client->componentData().isValid() ? client->componentData() : KGlobal::mainComponent();
00546                 file = KStandardDirs::locateLocal("data", cData.componentName() + '/' + file);
00547             }
00548             else
00549             {
00550                 if (!file.startsWith(localPrefix))
00551                     continue;
00552             }
00553 
00554             if ( QFile::exists( file ) )
00555                 if ( !QFile::remove( file ) )
00556                     kWarning() << "Could not delete " << file;
00557         }
00558 
00559         m_widget = new KEditToolBarWidget( q );
00560         m_widget->load( m_factory, m_defaultToolBar );
00561         m_widget->rebuildKXMLGUIClients();
00562     }
00563     else
00564     {
00565         int slash = m_file.lastIndexOf('/')+1;
00566         if (slash)
00567             m_file = m_file.mid(slash);
00568         QString xml_file = KStandardDirs::locateLocal("data", KGlobal::mainComponent().componentName() + '/' + m_file);
00569 
00570         if ( QFile::exists( xml_file ) )
00571             if ( !QFile::remove( xml_file ) )
00572                 kWarning() << "Could not delete " << xml_file;
00573 
00574         m_widget = new KEditToolBarWidget( m_collection, q );
00575         q->setResourceFile( m_file, m_global );
00576     }
00577 
00578     q->setMainWidget(m_widget);
00579     m_widget->show();
00580 
00581     q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
00582     q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
00583 
00584     q->enableButtonApply(false);
00585     emit q->newToolBarConfig();
00586     emit q->newToolbarConfig(); // compat
00587 }
00588 
00589 void KEditToolBarPrivate::_k_slotOk()
00590 {
00591   if (!m_accept) {
00592       q->reject();
00593       return;
00594   }
00595 
00596   if (!m_widget->save())
00597   {
00598     // some error box here is needed
00599   }
00600   else
00601   {
00602     emit q->newToolBarConfig();
00603     emit q->newToolbarConfig(); // compat
00604     q->accept();
00605   }
00606 }
00607 
00608 void KEditToolBarPrivate::_k_slotApply()
00609 {
00610     (void)m_widget->save();
00611     q->enableButtonApply(false);
00612     emit q->newToolBarConfig();
00613     emit q->newToolbarConfig(); // compat
00614 }
00615 
00616 void KEditToolBar::setGlobalDefaultToolBar(const char *toolbarName)
00617 {
00618     *s_defaultToolBarName = QString::fromLatin1(toolbarName);
00619 }
00620 
00621 KEditToolBarWidget::KEditToolBarWidget( KActionCollection *collection,
00622                                         QWidget *parent )
00623   : QWidget(parent),
00624     d(new KEditToolBarWidgetPrivate(this, componentData(), collection))
00625 {
00626     d->setupLayout();
00627 }
00628 
00629 KEditToolBarWidget::KEditToolBarWidget( QWidget *parent )
00630   : QWidget(parent),
00631     d(new KEditToolBarWidgetPrivate(this, componentData(), KXMLGUIClient::actionCollection() /*create new one*/))
00632 {
00633     d->setupLayout();
00634 }
00635 
00636 KEditToolBarWidget::~KEditToolBarWidget()
00637 {
00638     delete d;
00639 }
00640 
00641 void KEditToolBarWidget::load( const QString& file, bool global, const QString& defaultToolBar )
00642 {
00643     d->initNonKPart( file, global, defaultToolBar );
00644 }
00645 
00646 void KEditToolBarWidget::load( KXMLGUIFactory* factory, const QString& defaultToolBar )
00647 {
00648     d->initKPart( factory, defaultToolBar );
00649 }
00650 
00651 void KEditToolBarWidgetPrivate::initNonKPart( const QString& resourceFile,
00652                                               bool global,
00653                                               const QString& defaultToolBar )
00654 {
00655     //TODO: make sure we can call this multiple times?
00656     if ( m_loadedOnce ) {
00657         return;
00658     }
00659 
00660     m_loadedOnce = true;
00661     //d->m_actionList = collection->actions();
00662 
00663     // handle the merging
00664     if (global)
00665         m_widget->setXMLFile(KStandardDirs::locate("config", "ui/ui_standards.rc"));
00666     const QString localXML = loadXMLFile( resourceFile );
00667     m_widget->setXML(localXML, global ? true /*merge*/ : false);
00668 
00669     // first, get all of the necessary info for our local xml
00670     XmlData local(XmlData::Local, xmlFile(resourceFile), m_collection);
00671     QDomDocument domDoc;
00672     domDoc.setContent(localXML);
00673     local.setDomDocument(domDoc);
00674     m_xmlFiles.append(local);
00675 
00676     // then, the merged one (ui_standards + local xml)
00677     XmlData merge(XmlData::Merged, QString(), m_collection);
00678     merge.setDomDocument(m_widget->domDocument());
00679     m_xmlFiles.append(merge);
00680 
00681 #ifndef NDEBUG
00682     dump();
00683 #endif
00684 
00685     // now load in our toolbar combo box
00686     loadToolBarCombo( defaultToolBar );
00687     m_widget->adjustSize();
00688     m_widget->setMinimumSize( m_widget->sizeHint() );
00689 }
00690 
00691 void KEditToolBarWidgetPrivate::initKPart( KXMLGUIFactory* factory,
00692                                            const QString& defaultToolBar )
00693 {
00694     //TODO: make sure we can call this multiple times?
00695     if ( m_loadedOnce ) {
00696         return;
00697     }
00698 
00699     m_loadedOnce = true;
00700 
00701   // reusable vars
00702   QDomElement elem;
00703 
00704   m_widget->setFactory( factory );
00705 
00706   // add all of the client data
00707   bool first = true;
00708   foreach (KXMLGUIClient* client, factory->clients())
00709   {
00710     if (client->xmlFile().isEmpty())
00711       continue;
00712 
00713     XmlData::XmlType type = XmlData::Part;
00714     if ( first ) {
00715       type = XmlData::Shell;
00716       first = false;
00717     }
00718 
00719     XmlData data(type, client->localXMLFile(), client->actionCollection());
00720     QDomDocument domDoc;
00721     domDoc.setContent( KXMLGUIFactory::readConfigFile( client->xmlFile(), client->componentData() ) );
00722     data.setDomDocument(domDoc);
00723     m_xmlFiles.append(data);
00724 
00725     //d->m_actionList += client->actionCollection()->actions();
00726   }
00727 
00728 #ifndef NDEBUG
00729   //d->dump();
00730 #endif
00731 
00732   // now load in our toolbar combo box
00733   loadToolBarCombo( defaultToolBar );
00734   m_widget->adjustSize();
00735   m_widget->setMinimumSize( m_widget->sizeHint() );
00736 
00737   m_widget->actionCollection()->addAssociatedWidget( m_widget );
00738   foreach (QAction* action, m_widget->actionCollection()->actions())
00739     action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00740 }
00741 
00742 bool KEditToolBarWidget::save()
00743 {
00744   //kDebug(240) << "KEditToolBarWidget::save";
00745   XmlDataList::Iterator it = d->m_xmlFiles.begin();
00746   for ( ; it != d->m_xmlFiles.end(); ++it)
00747   {
00748     // let's not save non-modified files
00749     if ( !((*it).m_isModified) )
00750       continue;
00751 
00752     // let's also skip (non-existent) merged files
00753     if ( (*it).type() == XmlData::Merged )
00754       continue;
00755 
00756     kDebug() << (*it).domDocument().toString();
00757 
00758     kDebug(240) << "Saving " << (*it).xmlFile();
00759     // if we got this far, we might as well just save it
00760     KXMLGUIFactory::saveConfigFile((*it).domDocument(), (*it).xmlFile());
00761   }
00762 
00763   if ( !factory() )
00764     return true;
00765 
00766   rebuildKXMLGUIClients();
00767 
00768   return true;
00769 }
00770 
00771 void KEditToolBarWidget::rebuildKXMLGUIClients()
00772 {
00773   if ( !factory() )
00774     return;
00775 
00776   QList<KXMLGUIClient*> clients = factory()->clients();
00777   //kDebug(240) << "factory: " << clients.count() << " clients";
00778 
00779   if (!clients.count())
00780     return;
00781 
00782   // remove the elements starting from the last going to the first
00783   QListIterator<KXMLGUIClient*> clientIterator = clients;
00784   clientIterator.toBack();
00785   while ( clientIterator.hasPrevious() )
00786   {
00787     //kDebug(240) << "factory->removeClient " << client;
00788     factory()->removeClient( clientIterator.previous() );
00789   }
00790 
00791   KXMLGUIClient *firstClient = clients.first();
00792 
00793   // now, rebuild the gui from the first to the last
00794   //kDebug(240) << "rebuilding the gui";
00795   foreach (KXMLGUIClient* client, clients)
00796   {
00797     //kDebug(240) << "updating client " << client << " " << client->componentData().componentName() << "  xmlFile=" << client->xmlFile();
00798     QString file( client->xmlFile() ); // before setting ui_standards!
00799     if ( !file.isEmpty() )
00800     {
00801         // passing an empty stream forces the clients to reread the XML
00802         client->setXMLGUIBuildDocument( QDomDocument() );
00803 
00804         // for the shell, merge in ui_standards.rc
00805         if ( client == firstClient ) // same assumption as in the ctor: first==shell
00806             client->setXMLFile(KStandardDirs::locate("config", "ui/ui_standards.rc"));
00807 
00808         // and this forces it to use the *new* XML file
00809         client->setXMLFile( file, client == firstClient /* merge if shell */ );
00810     }
00811   }
00812 
00813   // Now we can add the clients to the factory
00814   // We don't do it in the loop above because adding a part automatically
00815   // adds its plugins, so we must make sure the plugins were updated first.
00816   foreach (KXMLGUIClient* client, clients)
00817     factory()->addClient( client );
00818 }
00819 
00820 void KEditToolBarWidgetPrivate::setupLayout()
00821 {
00822   // the toolbar name combo
00823   m_comboLabel = new QLabel(i18n("&Toolbar:"), m_widget);
00824   m_toolbarCombo = new KComboBox(m_widget);
00825   m_comboLabel->setBuddy(m_toolbarCombo);
00826   m_comboSeparator = new KSeparator(m_widget);
00827   QObject::connect(m_toolbarCombo, SIGNAL(activated(int)),
00828                    m_widget,       SLOT(slotToolBarSelected(int)));
00829 
00830 //  QPushButton *new_toolbar = new QPushButton(i18n("&New"), this);
00831 //  new_toolbar->setPixmap(BarIcon("document-new", KIconLoader::SizeSmall));
00832 //  new_toolbar->setEnabled(false); // disabled until implemented
00833 //  QPushButton *del_toolbar = new QPushButton(i18n("&Delete"), this);
00834 //  del_toolbar->setPixmap(BarIcon("edit-delete", KIconLoader::SizeSmall));
00835 //  del_toolbar->setEnabled(false); // disabled until implemented
00836 
00837   // our list of inactive actions
00838   QLabel *inactive_label = new QLabel(i18n("A&vailable actions:"), m_widget);
00839   m_inactiveList = new ToolBarListWidget(m_widget);
00840   m_inactiveList->setDragEnabled(true);
00841   m_inactiveList->setActiveList(false);
00842   m_inactiveList->setMinimumSize(180, 250);
00843   m_inactiveList->setDropIndicatorShown(false); // #165663
00844   inactive_label->setBuddy(m_inactiveList);
00845   QObject::connect(m_inactiveList, SIGNAL(itemSelectionChanged()),
00846                    m_widget,       SLOT(slotInactiveSelectionChanged()));
00847   QObject::connect(m_inactiveList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
00848                    m_widget,       SLOT(slotInsertButton()));
00849   QObject::connect(m_inactiveList, SIGNAL(dropped(ToolBarListWidget*, int, ToolBarItem*, bool)),
00850                    m_widget,       SLOT(slotDropped(ToolBarListWidget*, int, ToolBarItem*, bool)));
00851 
00852   // our list of active actions
00853   QLabel *active_label = new QLabel(i18n("Curr&ent actions:"), m_widget);
00854   m_activeList = new ToolBarListWidget(m_widget);
00855   m_activeList->setDragEnabled(true);
00856   m_activeList->setActiveList(true);
00857   // With Qt-4.1 only setting MiniumWidth results in a 0-width icon column ...
00858   m_activeList->setMinimumSize(m_inactiveList->minimumWidth(), 100);
00859   active_label->setBuddy(m_activeList);
00860 
00861   QObject::connect(m_activeList, SIGNAL(itemSelectionChanged()),
00862                    m_widget,     SLOT(slotActiveSelectionChanged()));
00863   QObject::connect(m_activeList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
00864                    m_widget,     SLOT(slotRemoveButton()));
00865   QObject::connect(m_activeList, SIGNAL(dropped(ToolBarListWidget*, int, ToolBarItem*, bool)),
00866                    m_widget,     SLOT(slotDropped(ToolBarListWidget*, int, ToolBarItem*, bool)));
00867 
00868   // "change icon" button
00869   m_changeIcon = new KPushButton(i18n( "Change &Icon..." ), m_widget);
00870   QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
00871   m_hasKDialog = !kdialogExe.isEmpty();
00872   m_changeIcon->setEnabled(m_hasKDialog && m_activeList->currentItem());
00873 
00874   QObject::connect( m_changeIcon, SIGNAL( clicked() ),
00875                     m_widget, SLOT( slotChangeIcon() ) );
00876 
00877   // The buttons in the middle
00878 
00879   m_upAction     = new QToolButton(m_widget);
00880   m_upAction->setIcon( KIcon("go-up") );
00881   m_upAction->setEnabled(false);
00882   m_upAction->setAutoRepeat(true);
00883   QObject::connect(m_upAction, SIGNAL(clicked()), m_widget, SLOT(slotUpButton()));
00884 
00885   m_insertAction = new QToolButton(m_widget);
00886   m_insertAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-previous" : "go-next") );
00887   m_insertAction->setEnabled(false);
00888   QObject::connect(m_insertAction, SIGNAL(clicked()), m_widget, SLOT(slotInsertButton()));
00889 
00890   m_removeAction = new QToolButton(m_widget);
00891   m_removeAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-next" : "go-previous") );
00892   m_removeAction->setEnabled(false);
00893   QObject::connect(m_removeAction, SIGNAL(clicked()), m_widget, SLOT(slotRemoveButton()));
00894 
00895   m_downAction   = new QToolButton(m_widget);
00896   m_downAction->setIcon( KIcon("go-down") );
00897   m_downAction->setEnabled(false);
00898   m_downAction->setAutoRepeat(true);
00899   QObject::connect(m_downAction, SIGNAL(clicked()), m_widget, SLOT(slotDownButton()));
00900 
00901   m_helpArea = new QLabel(m_widget);
00902   m_helpArea->setWordWrap(true);
00903 
00904   // now start with our layouts
00905   QVBoxLayout *top_layout = new QVBoxLayout(m_widget);
00906   top_layout->setMargin(0);
00907   top_layout->setSpacing(KDialog::spacingHint());
00908 
00909   QVBoxLayout *name_layout = new QVBoxLayout();
00910   name_layout->setSpacing(KDialog::spacingHint());
00911   QHBoxLayout *list_layout = new QHBoxLayout();
00912   list_layout->setSpacing(KDialog::spacingHint());
00913 
00914   QVBoxLayout *inactive_layout = new QVBoxLayout();
00915   inactive_layout->setSpacing(KDialog::spacingHint());
00916   QVBoxLayout *active_layout = new QVBoxLayout();
00917   active_layout->setSpacing(KDialog::spacingHint());
00918   QHBoxLayout *changeIcon_layout = new QHBoxLayout();
00919   changeIcon_layout->setSpacing(KDialog::spacingHint());
00920 
00921   QGridLayout *button_layout = new QGridLayout();
00922 
00923   name_layout->addWidget(m_comboLabel);
00924   name_layout->addWidget(m_toolbarCombo);
00925 //  name_layout->addWidget(new_toolbar);
00926 //  name_layout->addWidget(del_toolbar);
00927 
00928   button_layout->setSpacing( 0 );
00929   button_layout->setRowStretch( 0, 10 );
00930   button_layout->addWidget(m_upAction, 1, 1);
00931   button_layout->addWidget(m_removeAction, 2, 0);
00932   button_layout->addWidget(m_insertAction, 2, 2);
00933   button_layout->addWidget(m_downAction, 3, 1);
00934   button_layout->setRowStretch( 4, 10 );
00935 
00936   inactive_layout->addWidget(inactive_label);
00937   inactive_layout->addWidget(m_inactiveList, 1);
00938 
00939   active_layout->addWidget(active_label);
00940   active_layout->addWidget(m_activeList, 1);
00941   active_layout->addLayout(changeIcon_layout);
00942 
00943   changeIcon_layout->addStretch( 1 );
00944   changeIcon_layout->addWidget(m_changeIcon);
00945   changeIcon_layout->addStretch( 1 );
00946 
00947   list_layout->addLayout(inactive_layout);
00948   list_layout->addLayout(button_layout);
00949   list_layout->addLayout(active_layout);
00950 
00951   top_layout->addLayout(name_layout);
00952   top_layout->addWidget(m_comboSeparator);
00953   top_layout->addLayout(list_layout,10);
00954   top_layout->addWidget(m_helpArea);
00955   top_layout->addWidget(new KSeparator(m_widget));
00956 }
00957 
00958 void KEditToolBarWidgetPrivate::loadToolBarCombo( const QString& defaultToolBar )
00959 {
00960   const QLatin1String attrName( "name" );
00961   // just in case, we clear our combo
00962   m_toolbarCombo->clear();
00963 
00964   int defaultToolBarId = -1;
00965   int count = 0;
00966   // load in all of the toolbar names into this combo box
00967   XmlDataList::const_iterator xit = m_xmlFiles.begin();
00968   for ( ; xit != m_xmlFiles.end(); ++xit)
00969   {
00970       // skip the merged one in favor of the local one,
00971       // so that we can change icons
00972       // This also makes the app-defined named for "mainToolBar" appear rather than the ui_standards-defined name.
00973     if ( (*xit).type() == XmlData::Merged )
00974       continue;
00975 
00976     // each xml file may have any number of toolbars
00977     ToolBarList::const_iterator it = (*xit).barList().begin();
00978     for ( ; it != (*xit).barList().end(); ++it)
00979     {
00980         const QString text = (*xit).toolBarText( *it );
00981         m_toolbarCombo->addItem( text );
00982         const QString name = (*it).attribute(attrName);
00983         if (defaultToolBarId == -1 && name == defaultToolBar)
00984             defaultToolBarId = count;
00985         count++;
00986     }
00987   }
00988   const bool showCombo = (count > 1);
00989   m_comboLabel->setVisible(showCombo);
00990   m_comboSeparator->setVisible(showCombo);
00991   m_toolbarCombo->setVisible(showCombo);
00992   if (defaultToolBarId == -1)
00993       defaultToolBarId = 0;
00994   // we want to the specified item selected and its actions loaded
00995   m_toolbarCombo->setCurrentIndex(defaultToolBarId);
00996   slotToolBarSelected(m_toolbarCombo->currentIndex());
00997 }
00998 
00999 void KEditToolBarWidgetPrivate::loadActions(const QDomElement& elem)
01000 {
01001   const QLatin1String tagSeparator( "Separator" );
01002   const QLatin1String tagMerge( "Merge" );
01003   const QLatin1String tagActionList( "ActionList" );
01004   const QLatin1String tagAction( "Action" );
01005   const QLatin1String attrName( "name" );
01006 
01007   int     sep_num = 0;
01008   QString sep_name("separator_%1");
01009 
01010   // clear our lists
01011   m_inactiveList->clear();
01012   m_activeList->clear();
01013   m_insertAction->setEnabled(false);
01014   m_removeAction->setEnabled(false);
01015   m_upAction->setEnabled(false);
01016   m_downAction->setEnabled(false);
01017 
01018   // We'll use this action collection
01019   KActionCollection* actionCollection = m_currentXmlData->actionCollection();
01020 
01021   // store the names of our active actions
01022   QSet<QString> active_list;
01023 
01024   // i18n filtering message for action names
01025   KLocalizedString nameFilter = ki18nc("@item:intable Action name in toolbar editor", "%1");
01026 
01027   // see if our current action is in this toolbar
01028   QDomNode n = elem.firstChild();
01029   for( ; !n.isNull(); n = n.nextSibling() )
01030   {
01031     QDomElement it = n.toElement();
01032     if (it.isNull()) continue;
01033     if (it.tagName() == tagSeparator)
01034     {
01035       ToolBarItem *act = new ToolBarItem(m_activeList, tagSeparator, sep_name.arg(sep_num++), QString());
01036       act->setSeparator(true);
01037       act->setText(SEPARATORSTRING);
01038       it.setAttribute( attrName, act->internalName() );
01039       continue;
01040     }
01041 
01042     if (it.tagName() == tagMerge)
01043     {
01044       // Merge can be named or not - use the name if there is one
01045       QString name = it.attribute( attrName );
01046       ToolBarItem *act = new ToolBarItem(m_activeList, tagMerge, name, i18n("This element will be replaced with all the elements of an embedded component."));
01047       if ( name.isEmpty() )
01048           act->setText(i18n("<Merge>"));
01049       else
01050           act->setText(i18n("<Merge %1>", name));
01051       continue;
01052     }
01053 
01054     if (it.tagName() == tagActionList)
01055     {
01056       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.") );
01057       act->setText(i18n("ActionList: %1", it.attribute(attrName)));
01058       continue;
01059     }
01060 
01061     // iterate through this client's actions
01062     // This used to iterate through _all_ actions, but we don't support
01063     // putting any action into any client...
01064     foreach (QAction* action, actionCollection->actions())
01065     {
01066       // do we have a match?
01067       if (it.attribute( attrName ) == action->objectName())
01068       {
01069         // we have a match!
01070         ToolBarItem *act = new ToolBarItem(m_activeList, it.tagName(), action->objectName(), action->toolTip());
01071         act->setText(nameFilter.subs(action->text().remove(QChar('&'))).toString());
01072         act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
01073 
01074         active_list.insert(action->objectName());
01075         break;
01076       }
01077     }
01078   }
01079 
01080   // go through the rest of the collection
01081   foreach (QAction* action, actionCollection->actions())
01082   {
01083     // skip our active ones
01084     if (active_list.contains(action->objectName()))
01085       continue;
01086 
01087     ToolBarItem *act = new ToolBarItem(m_inactiveList, tagAction, action->objectName(), action->toolTip());
01088     act->setText(nameFilter.subs(action->text().remove(QChar('&'))).toString());
01089     act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
01090   }
01091 
01092   m_inactiveList->sortItems(Qt::AscendingOrder);
01093 
01094   // finally, add default separators to the inactive list
01095   ToolBarItem *act = new ToolBarItem(0L, tagSeparator, sep_name.arg(sep_num++), QString());
01096   act->setSeparator(true);
01097   act->setText(SEPARATORSTRING);
01098   m_inactiveList->insertItem(0, act);
01099 }
01100 
01101 KActionCollection *KEditToolBarWidget::actionCollection() const
01102 {
01103   return d->m_collection;
01104 }
01105 
01106 void KEditToolBarWidgetPrivate::slotToolBarSelected(int index)
01107 {
01108     const QLatin1String attrName( "name" );
01109     // We need to find the XmlData and toolbar element for this index
01110     // To do that, we do the same iteration as the one which filled in the combobox.
01111 
01112     int toolbarNumber = 0;
01113     XmlDataList::iterator xit = m_xmlFiles.begin();
01114     for ( ; xit != m_xmlFiles.end(); ++xit) {
01115 
01116         // skip the merged one in favor of the local one,
01117         // so that we can change icons
01118         if ( (*xit).type() == XmlData::Merged )
01119             continue;
01120 
01121         // each xml file may have any number of toolbars
01122         ToolBarList::Iterator it = (*xit).barList().begin();
01123         for ( ; it != (*xit).barList().end(); ++it) {
01124 
01125             // is this our toolbar?
01126             if (toolbarNumber == index) {
01127 
01128                 // save our current settings
01129                 m_currentXmlData = & (*xit);
01130                 m_currentToolBarElem = *it;
01131 
01132                 kDebug() << "found toolbar" << m_currentXmlData->toolBarText(*it) << "m_currentXmlData set to";
01133                 m_currentXmlData->dump();
01134 
01135                 // If this is a Merged xmldata, clicking the "change icon" button would assert...
01136                 Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
01137 
01138                 // load in our values
01139                 loadActions(m_currentToolBarElem);
01140 
01141                 if ((*xit).type() == XmlData::Part || (*xit).type() == XmlData::Shell)
01142                     m_widget->setDOMDocument( (*xit).domDocument() );
01143                 return;
01144             }
01145             ++toolbarNumber;
01146 
01147         }
01148     }
01149 }
01150 
01151 void KEditToolBarWidgetPrivate::slotInactiveSelectionChanged()
01152 {
01153   if (m_inactiveList->selectedItems().count())
01154   {
01155     m_insertAction->setEnabled(true);
01156     QString statusText = static_cast<ToolBarItem*>(m_inactiveList->selectedItems().first())->statusText();
01157     m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
01158   }
01159   else
01160   {
01161     m_insertAction->setEnabled(false);
01162     m_helpArea->setText( QString() );
01163   }
01164 }
01165 
01166 void KEditToolBarWidgetPrivate::slotActiveSelectionChanged()
01167 {
01168   ToolBarItem* toolitem = 0;
01169   if (!m_activeList->selectedItems().isEmpty())
01170     toolitem = static_cast<ToolBarItem *>(m_activeList->selectedItems().first());
01171 
01172   m_removeAction->setEnabled( toolitem );
01173 
01174   m_changeIcon->setEnabled( toolitem &&
01175                             m_hasKDialog &&
01176                             toolitem->internalTag() == "Action" );
01177 
01178   if (toolitem)
01179   {
01180     m_upAction->setEnabled(toolitem->index() != 0);
01181     m_downAction->setEnabled(toolitem->index() != toolitem->listWidget()->count() - 1);
01182 
01183     QString statusText = toolitem->statusText();
01184     m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
01185   }
01186   else
01187   {
01188     m_upAction->setEnabled(false);
01189     m_downAction->setEnabled(false);
01190     m_helpArea->setText( QString() );
01191   }
01192 }
01193 
01194 void KEditToolBarWidgetPrivate::slotInsertButton()
01195 {
01196   insertActive(m_inactiveList->currentItem(), m_activeList->currentItem(), false);
01197 
01198   // we're modified, so let this change
01199   emit m_widget->enableOk(true);
01200 
01201   // TODO: #### this causes #97572.
01202   // It would be better to just "delete item; loadActions( ... , ActiveListOnly );" or something.
01203   slotToolBarSelected( m_toolbarCombo->currentIndex() );
01204 }
01205 
01206 void KEditToolBarWidgetPrivate::slotRemoveButton()
01207 {
01208   removeActive( m_activeList->currentItem() );
01209 
01210   // we're modified, so let this change
01211   emit m_widget->enableOk(true);
01212 
01213   slotToolBarSelected( m_toolbarCombo->currentIndex() );
01214 }
01215 
01216 void KEditToolBarWidgetPrivate::insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend)
01217 {
01218   if (!item)
01219     return;
01220 
01221   static const QString &tagAction    = KGlobal::staticQString( "Action" );
01222   static const QString &tagSeparator = KGlobal::staticQString( "Separator" );
01223   static const QString &attrName     = KGlobal::staticQString( "name" );
01224   static const QString &attrNoMerge  = KGlobal::staticQString( "noMerge" );
01225 
01226   QDomElement new_item;
01227   // let's handle the separator specially
01228   if (item->isSeparator())
01229     new_item = m_widget->domDocument().createElement(tagSeparator);
01230   else
01231     new_item = m_widget->domDocument().createElement(tagAction);
01232 
01233   new_item.setAttribute(attrName, item->internalName());
01234 
01235   Q_ASSERT(!m_currentToolBarElem.isNull());
01236 
01237   if (before)
01238   {
01239     // we have the item in the active list which is before the new
01240     // item.. so let's try our best to add our new item right after it
01241     QDomElement elem = findElementForToolBarItem( before );
01242     Q_ASSERT( !elem.isNull() );
01243     m_currentToolBarElem.insertAfter(new_item, elem);
01244   }
01245   else
01246   {
01247     // simply put it at the beginning or the end of the list.
01248     if (prepend)
01249       m_currentToolBarElem.insertBefore(new_item, m_currentToolBarElem.firstChild());
01250     else
01251       m_currentToolBarElem.appendChild(new_item);
01252   }
01253 
01254   // and set this container as a noMerge
01255   m_currentToolBarElem.setAttribute( attrNoMerge, "1");
01256 
01257   // update the local doc
01258   updateLocal(m_currentToolBarElem);
01259 }
01260 
01261 void KEditToolBarWidgetPrivate::removeActive(ToolBarItem *item)
01262 {
01263   if (!item)
01264     return;
01265 
01266   static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
01267 
01268   // we're modified, so let this change
01269   emit m_widget->enableOk(true);
01270 
01271   // now iterate through to find the child to nuke
01272   QDomElement elem = findElementForToolBarItem( item );
01273   if ( !elem.isNull() )
01274   {
01275     // nuke myself!
01276     m_currentToolBarElem.removeChild(elem);
01277 
01278     // and set this container as a noMerge
01279     m_currentToolBarElem.setAttribute( attrNoMerge, "1");
01280 
01281     // update the local doc
01282     updateLocal(m_currentToolBarElem);
01283   }
01284 }
01285 
01286 void KEditToolBarWidgetPrivate::slotUpButton()
01287 {
01288   ToolBarItem *item = m_activeList->currentItem();
01289 
01290   if (!item) {
01291     Q_ASSERT(false);
01292     return;
01293   }
01294 
01295   int row = item->listWidget()->row(item) - 1;
01296   // make sure we're not the top item already
01297   if (row < 0) {
01298     Q_ASSERT(false);
01299     return;
01300   }
01301 
01302   // we're modified, so let this change
01303   emit m_widget->enableOk(true);
01304 
01305   moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(row - 1)) );
01306 }
01307 
01308 void KEditToolBarWidgetPrivate::moveActive( ToolBarItem* item, ToolBarItem* before )
01309 {
01310   QDomElement e = findElementForToolBarItem( item );
01311 
01312   if ( e.isNull() )
01313     return;
01314 
01315   // remove item
01316   m_activeList->takeItem(m_activeList->row(item));
01317 
01318   // put it where it's supposed to go
01319   m_activeList->insertItem(m_activeList->row(before) + 1, item);
01320 
01321   // make it selected again
01322   m_activeList->setCurrentItem(item);
01323 
01324   // and do the real move in the DOM
01325   if ( !before )
01326     m_currentToolBarElem.insertBefore(e, m_currentToolBarElem.firstChild() );
01327   else
01328     m_currentToolBarElem.insertAfter(e, findElementForToolBarItem( (ToolBarItem*)before ));
01329 
01330   // and set this container as a noMerge
01331   static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
01332   m_currentToolBarElem.setAttribute( attrNoMerge, "1");
01333 
01334   // update the local doc
01335   updateLocal(m_currentToolBarElem);
01336 }
01337 
01338 void KEditToolBarWidgetPrivate::slotDownButton()
01339 {
01340   ToolBarItem *item = m_activeList->currentItem();
01341 
01342   if (!item) {
01343     Q_ASSERT(false);
01344     return;
01345   }
01346 
01347   // make sure we're not the bottom item already
01348   int newRow = item->listWidget()->row(item) + 1;
01349   if (newRow >= item->listWidget()->count()) {
01350     Q_ASSERT(false);
01351     return;
01352   }
01353 
01354   // we're modified, so let this change
01355   emit m_widget->enableOk(true);
01356 
01357   moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(newRow)) );
01358 }
01359 
01360 void KEditToolBarWidgetPrivate::updateLocal(QDomElement& elem)
01361 {
01362   static const QString &attrName = KGlobal::staticQString( "name" );
01363 
01364   XmlDataList::Iterator xit = m_xmlFiles.begin();
01365   for ( ; xit != m_xmlFiles.end(); ++xit)
01366   {
01367     if ( (*xit).type() == XmlData::Merged )
01368       continue;
01369 
01370     if ( (*xit).type() == XmlData::Shell ||
01371          (*xit).type() == XmlData::Part )
01372     {
01373       if ( m_currentXmlData->xmlFile() == (*xit).xmlFile() )
01374       {
01375         (*xit).m_isModified = true;
01376         return;
01377       }
01378 
01379       continue;
01380     }
01381 
01382     (*xit).m_isModified = true;
01383 
01384     ToolBarList::Iterator it = (*xit).barList().begin();
01385     for ( ; it != (*xit).barList().end(); ++it)
01386     {
01387       QString name( (*it).attribute( attrName ) );
01388       QString tag( (*it).tagName() );
01389       if ( (tag != elem.tagName()) || (name != elem.attribute(attrName)) )
01390         continue;
01391 
01392       QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
01393       toolbar.replaceChild(elem, (*it));
01394       return;
01395     }
01396 
01397     // just append it
01398     QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
01399     Q_ASSERT(!toolbar.isNull());
01400     toolbar.appendChild(elem);
01401   }
01402 }
01403 
01404 void KEditToolBarWidgetPrivate::slotChangeIcon()
01405 {
01406   // We can't use KIconChooser here, since it's in libkio
01407   // ##### KDE4: reconsider this, e.g. move KEditToolBar to libkio,
01408   // ##### or better, dlopen libkfile from here like kio does.
01409 
01410   //if the process is already running (e.g. when somebody clicked the change button twice (see #127149)) - do nothing...
01411   //otherwise m_kdialogProcess will be overwritten and set to zero in slotProcessExited()...crash!
01412   if ( m_kdialogProcess && m_kdialogProcess->state() == QProcess::Running )
01413         return;
01414 
01415   m_currentXmlData->dump();
01416   Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
01417 
01418   m_kdialogProcess = new KProcess;
01419   QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
01420   (*m_kdialogProcess) << kdialogExe;
01421   (*m_kdialogProcess) << "--caption";
01422   (*m_kdialogProcess) << i18n( "Change Icon" );
01423   (*m_kdialogProcess) << "--embed";
01424   (*m_kdialogProcess) << QString::number( (ulong)m_widget->window()->winId() );
01425   (*m_kdialogProcess) << "--geticon";
01426   (*m_kdialogProcess) << "Toolbar";
01427   (*m_kdialogProcess) << "Actions";
01428   m_kdialogProcess->setOutputChannelMode(KProcess::OnlyStdoutChannel);
01429   m_kdialogProcess->setNextOpenMode( QIODevice::ReadOnly | QIODevice::Text );
01430   m_kdialogProcess->start();
01431   if ( !m_kdialogProcess->waitForStarted() ) {
01432     kError(240) << "Can't run " << kdialogExe << endl;
01433     delete m_kdialogProcess;
01434     m_kdialogProcess = 0;
01435     return;
01436   }
01437 
01438   m_activeList->setEnabled( false ); // don't change the current item
01439   m_toolbarCombo->setEnabled( false ); // don't change the current toolbar
01440 
01441   QObject::connect( m_kdialogProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
01442                     m_widget, SLOT( slotProcessExited() ) );
01443 }
01444 
01445 void KEditToolBarWidgetPrivate::slotProcessExited()
01446 {
01447   m_activeList->setEnabled( true );
01448   m_toolbarCombo->setEnabled( true );
01449 
01450   QString icon;
01451 
01452   if (!m_kdialogProcess) {
01453          kError(240) << "Something is wrong here! m_kdialogProcess is zero!" << endl;
01454          return;
01455   }
01456 
01457   icon = QString::fromLocal8Bit( m_kdialogProcess->readLine() );
01458   icon = icon.left( icon.indexOf( '\n' ) );
01459   kDebug(240) << "icon=" << icon;
01460   if ( m_kdialogProcess->exitStatus() != QProcess::NormalExit ||
01461        icon.isEmpty() ) {
01462     delete m_kdialogProcess;
01463     m_kdialogProcess = 0;
01464     return;
01465   }
01466 
01467   ToolBarItem *item = m_activeList->currentItem();
01468   kDebug() << item;
01469   if(item){
01470     item->setIcon(KIcon(icon));
01471 
01472     Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
01473 
01474     m_currentXmlData->m_isModified = true;
01475 
01476     // Get hold of ActionProperties tag
01477     QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
01478     // Find or create an element for this action
01479     QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
01480     Q_ASSERT( !act_elem.isNull() );
01481     act_elem.setAttribute( "icon", icon );
01482 
01483     // we're modified, so let this change
01484     emit m_widget->enableOk(true);
01485   }
01486 
01487   delete m_kdialogProcess;
01488   m_kdialogProcess = 0;
01489 }
01490 
01491 void KEditToolBarWidgetPrivate::slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList)
01492 {
01493     //kDebug() << "slotDropped list=" << (list==m_activeList?"activeList":"inactiveList")
01494     //         << "index=" << index << "sourceIsActiveList=" << sourceIsActiveList;
01495     if (list == m_activeList) {
01496         ToolBarItem* after = index > 0 ? static_cast<ToolBarItem *>(list->item(index-1)) : 0;
01497         //kDebug() << "after" << after->text() << after->internalTag();
01498         if (sourceIsActiveList) {
01499             // has been dragged within the active list (moved).
01500             moveActive(item, after);
01501         } else {
01502             // dragged from the inactive list to the active list
01503             insertActive(item, after, true);
01504         }
01505     } else if (list == m_inactiveList) {
01506         // has been dragged to the inactive list -> remove from the active list.
01507         removeActive(item);
01508     }
01509 
01510     delete item; // not needed anymore. must be deleted before slotToolBarSelected clears the lists
01511 
01512     // we're modified, so let this change
01513     emit m_widget->enableOk(true);
01514 
01515     slotToolBarSelected( m_toolbarCombo->currentIndex() );
01516 }
01517 
01518 
01519 void KEditToolBar::showEvent( QShowEvent * event )
01520 {
01521   // The dialog has been shown, enable toolbar editing
01522     if ( d->m_factory ) {
01523         // call the kpart version
01524         d->m_widget->load( d->m_factory, d->m_defaultToolBar );
01525     } else {
01526         // call the action collection version
01527         d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
01528     }
01529 
01530     KToolBar::setToolBarsEditable(true);
01531     KDialog::showEvent(event);
01532 }
01533 
01534 void KEditToolBar::hideEvent(QHideEvent* event)
01535 {
01536   // The dialog has been hidden, disable toolbar editing
01537   KToolBar::setToolBarsEditable(false);
01538 
01539   KDialog::hideEvent(event);
01540 }
01541 
01542 #include "kedittoolbar.moc"
01543 #include "kedittoolbar_p.moc"

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal