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