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