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

KDE's Doxygen guidelines are available online.

KDEUI

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

kdelibs-4.9.5 API Reference

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

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