• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 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     kDebug() << (*it).domDocument().toString();
00827 
00828     kDebug(240) << "Saving " << (*it).xmlFile();
00829     // if we got this far, we might as well just save it
00830     KXMLGUIFactory::saveConfigFile((*it).domDocument(), (*it).xmlFile());
00831   }
00832 
00833     if (!d->m_factory)
00834         return true;
00835 
00836   rebuildKXMLGUIClients();
00837 
00838   return true;
00839 }
00840 
00841 void KEditToolBarWidget::rebuildKXMLGUIClients()
00842 {
00843     if (!d->m_factory)
00844         return;
00845 
00846     const QList<KXMLGUIClient*> clients = d->m_factory->clients();
00847     //kDebug(240) << "factory: " << clients.count() << " clients";
00848 
00849     // remove the elements starting from the last going to the first
00850     if (!clients.count())
00851         return;
00852 
00853     QListIterator<KXMLGUIClient*> clientIterator = clients;
00854     clientIterator.toBack();
00855     while (clientIterator.hasPrevious()) {
00856         KXMLGUIClient* client = clientIterator.previous();
00857         //kDebug(240) << "factory->removeClient " << client;
00858         d->m_factory->removeClient(client);
00859     }
00860 
00861   KXMLGUIClient *firstClient = clients.first();
00862 
00863   // now, rebuild the gui from the first to the last
00864   //kDebug(240) << "rebuilding the gui";
00865   foreach (KXMLGUIClient* client, clients)
00866   {
00867     //kDebug(240) << "updating client " << client << " " << client->componentData().componentName() << "  xmlFile=" << client->xmlFile();
00868     QString file( client->xmlFile() ); // before setting ui_standards!
00869     if ( !file.isEmpty() )
00870     {
00871         // passing an empty stream forces the clients to reread the XML
00872         client->setXMLGUIBuildDocument( QDomDocument() );
00873 
00874         // for the shell, merge in ui_standards.rc
00875         if ( client == firstClient ) // same assumption as in the ctor: first==shell
00876             client->loadStandardsXmlFile();
00877 
00878         // and this forces it to use the *new* XML file
00879         client->setXMLFile( file, client == firstClient /* merge if shell */ );
00880 
00881         // [we can't use reloadXML, it doesn't load ui_standards.rc]
00882     }
00883   }
00884 
00885     // Now we can add the clients to the factory
00886     // We don't do it in the loop above because adding a part automatically
00887     // adds its plugins, so we must make sure the plugins were updated first.
00888     foreach(KXMLGUIClient* client, clients) {
00889         d->m_factory->addClient(client);
00890     }
00891 }
00892 
00893 void KEditToolBarWidgetPrivate::setupLayout()
00894 {
00895   // the toolbar name combo
00896   m_comboLabel = new QLabel(i18n("&Toolbar:"), m_widget);
00897   m_toolbarCombo = new KComboBox(m_widget);
00898   m_comboLabel->setBuddy(m_toolbarCombo);
00899   m_comboSeparator = new KSeparator(m_widget);
00900   QObject::connect(m_toolbarCombo, SIGNAL(activated(int)),
00901                    m_widget,       SLOT(slotToolBarSelected(int)));
00902 
00903 //  QPushButton *new_toolbar = new QPushButton(i18n("&New"), this);
00904 //  new_toolbar->setPixmap(BarIcon("document-new", KIconLoader::SizeSmall));
00905 //  new_toolbar->setEnabled(false); // disabled until implemented
00906 //  QPushButton *del_toolbar = new QPushButton(i18n("&Delete"), this);
00907 //  del_toolbar->setPixmap(BarIcon("edit-delete", KIconLoader::SizeSmall));
00908 //  del_toolbar->setEnabled(false); // disabled until implemented
00909 
00910   // our list of inactive actions
00911   QLabel *inactive_label = new QLabel(i18n("A&vailable actions:"), m_widget);
00912   m_inactiveList = new ToolBarListWidget(m_widget);
00913   m_inactiveList->setDragEnabled(true);
00914   m_inactiveList->setActiveList(false);
00915   m_inactiveList->setMinimumSize(180, 250);
00916   m_inactiveList->setDropIndicatorShown(false); // #165663
00917   inactive_label->setBuddy(m_inactiveList);
00918   QObject::connect(m_inactiveList, SIGNAL(itemSelectionChanged()),
00919                    m_widget,       SLOT(slotInactiveSelectionChanged()));
00920   QObject::connect(m_inactiveList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
00921                    m_widget,       SLOT(slotInsertButton()));
00922   QObject::connect(m_inactiveList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
00923                    m_widget,       SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
00924 
00925   KListWidgetSearchLine *inactiveListSearchLine = new KListWidgetSearchLine(m_widget, m_inactiveList);
00926   inactiveListSearchLine->setClickMessage(i18n("Filter"));
00927 
00928   // our list of active actions
00929   QLabel *active_label = new QLabel(i18n("Curr&ent actions:"), m_widget);
00930   m_activeList = new ToolBarListWidget(m_widget);
00931   m_activeList->setDragEnabled(true);
00932   m_activeList->setActiveList(true);
00933   // With Qt-4.1 only setting MiniumWidth results in a 0-width icon column ...
00934   m_activeList->setMinimumSize(m_inactiveList->minimumWidth(), 100);
00935   active_label->setBuddy(m_activeList);
00936 
00937   QObject::connect(m_activeList, SIGNAL(itemSelectionChanged()),
00938                    m_widget,     SLOT(slotActiveSelectionChanged()));
00939   QObject::connect(m_activeList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
00940                    m_widget,     SLOT(slotRemoveButton()));
00941   QObject::connect(m_activeList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
00942                    m_widget,     SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
00943 
00944   KListWidgetSearchLine *activeListSearchLine = new KListWidgetSearchLine(m_widget, m_activeList);
00945   activeListSearchLine->setClickMessage(i18n("Filter"));
00946 
00947   // "change icon" button
00948   m_changeIcon = new KPushButton(i18n( "Change &Icon..." ), m_widget);
00949   m_changeIcon->setIcon(KIcon("preferences-desktop-icons"));
00950   QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
00951   m_hasKDialog = !kdialogExe.isEmpty();
00952   m_changeIcon->setEnabled(m_hasKDialog && m_activeList->currentItem());
00953 
00954   QObject::connect( m_changeIcon, SIGNAL(clicked()),
00955                     m_widget, SLOT(slotChangeIcon()) );
00956 
00957   // "change icon text" button
00958   m_changeIconText = new KPushButton(i18n( "Change Te&xt..." ), m_widget);
00959   m_changeIconText->setIcon(KIcon("edit-rename"));
00960   m_changeIconText->setEnabled(m_activeList->currentItem() != 0);
00961 
00962   QObject::connect( m_changeIconText, SIGNAL(clicked()),
00963                     m_widget, SLOT(slotChangeIconText()) );
00964 
00965   // The buttons in the middle
00966 
00967   m_upAction     = new QToolButton(m_widget);
00968   m_upAction->setIcon( KIcon("go-up") );
00969   m_upAction->setEnabled(false);
00970   m_upAction->setAutoRepeat(true);
00971   QObject::connect(m_upAction, SIGNAL(clicked()), m_widget, SLOT(slotUpButton()));
00972 
00973   m_insertAction = new QToolButton(m_widget);
00974   m_insertAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-previous" : "go-next") );
00975   m_insertAction->setEnabled(false);
00976   QObject::connect(m_insertAction, SIGNAL(clicked()), m_widget, SLOT(slotInsertButton()));
00977 
00978   m_removeAction = new QToolButton(m_widget);
00979   m_removeAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-next" : "go-previous") );
00980   m_removeAction->setEnabled(false);
00981   QObject::connect(m_removeAction, SIGNAL(clicked()), m_widget, SLOT(slotRemoveButton()));
00982 
00983   m_downAction   = new QToolButton(m_widget);
00984   m_downAction->setIcon( KIcon("go-down") );
00985   m_downAction->setEnabled(false);
00986   m_downAction->setAutoRepeat(true);
00987   QObject::connect(m_downAction, SIGNAL(clicked()), m_widget, SLOT(slotDownButton()));
00988 
00989   m_helpArea = new QLabel(m_widget);
00990   m_helpArea->setWordWrap(true);
00991 
00992   // now start with our layouts
00993   QVBoxLayout *top_layout = new QVBoxLayout(m_widget);
00994   top_layout->setMargin(0);
00995 
00996   QVBoxLayout *name_layout = new QVBoxLayout();
00997   QHBoxLayout *list_layout = new QHBoxLayout();
00998 
00999   QVBoxLayout *inactive_layout = new QVBoxLayout();
01000   QVBoxLayout *active_layout = new QVBoxLayout();
01001   QHBoxLayout *changeIcon_layout = new QHBoxLayout();
01002 
01003   QGridLayout *button_layout = new QGridLayout();
01004 
01005   name_layout->addWidget(m_comboLabel);
01006   name_layout->addWidget(m_toolbarCombo);
01007 //  name_layout->addWidget(new_toolbar);
01008 //  name_layout->addWidget(del_toolbar);
01009 
01010   button_layout->setSpacing( 0 );
01011   button_layout->setRowStretch( 0, 10 );
01012   button_layout->addWidget(m_upAction, 1, 1);
01013   button_layout->addWidget(m_removeAction, 2, 0);
01014   button_layout->addWidget(m_insertAction, 2, 2);
01015   button_layout->addWidget(m_downAction, 3, 1);
01016   button_layout->setRowStretch( 4, 10 );
01017 
01018   inactive_layout->addWidget(inactive_label);
01019   inactive_layout->addWidget(inactiveListSearchLine);
01020   inactive_layout->addWidget(m_inactiveList, 1);
01021 
01022   active_layout->addWidget(active_label);
01023   active_layout->addWidget(activeListSearchLine);
01024   active_layout->addWidget(m_activeList, 1);
01025   active_layout->addLayout(changeIcon_layout);
01026 
01027   changeIcon_layout->addWidget(m_changeIcon);
01028   changeIcon_layout->addStretch( 1 );
01029   changeIcon_layout->addWidget(m_changeIconText);
01030 
01031   list_layout->addLayout(inactive_layout);
01032   list_layout->addLayout(button_layout);
01033   list_layout->addLayout(active_layout);
01034 
01035   top_layout->addLayout(name_layout);
01036   top_layout->addWidget(m_comboSeparator);
01037   top_layout->addLayout(list_layout,10);
01038   top_layout->addWidget(m_helpArea);
01039   top_layout->addWidget(new KSeparator(m_widget));
01040 }
01041 
01042 void KEditToolBarWidgetPrivate::loadToolBarCombo( const QString& defaultToolBar )
01043 {
01044   const QLatin1String attrName( "name" );
01045   // just in case, we clear our combo
01046   m_toolbarCombo->clear();
01047 
01048   int defaultToolBarId = -1;
01049   int count = 0;
01050   // load in all of the toolbar names into this combo box
01051   XmlDataList::const_iterator xit = m_xmlFiles.constBegin();
01052   for ( ; xit != m_xmlFiles.constEnd(); ++xit)
01053   {
01054       // skip the merged one in favor of the local one,
01055       // so that we can change icons
01056       // This also makes the app-defined named for "mainToolBar" appear rather than the ui_standards-defined name.
01057     if ( (*xit).type() == XmlData::Merged )
01058       continue;
01059 
01060     // each xml file may have any number of toolbars
01061     ToolBarList::const_iterator it = (*xit).barList().begin();
01062     for ( ; it != (*xit).barList().constEnd(); ++it)
01063     {
01064         const QString text = (*xit).toolBarText( *it );
01065         m_toolbarCombo->addItem( text );
01066         const QString name = (*it).attribute(attrName);
01067         if (defaultToolBarId == -1 && name == defaultToolBar)
01068             defaultToolBarId = count;
01069         count++;
01070     }
01071   }
01072   const bool showCombo = (count > 1);
01073   m_comboLabel->setVisible(showCombo);
01074   m_comboSeparator->setVisible(showCombo);
01075   m_toolbarCombo->setVisible(showCombo);
01076   if (defaultToolBarId == -1)
01077       defaultToolBarId = 0;
01078   // we want to the specified item selected and its actions loaded
01079   m_toolbarCombo->setCurrentIndex(defaultToolBarId);
01080   slotToolBarSelected(m_toolbarCombo->currentIndex());
01081 }
01082 
01083 void KEditToolBarWidgetPrivate::loadActions(const QDomElement& elem)
01084 {
01085   const QLatin1String tagSeparator( "Separator" );
01086   const QLatin1String tagMerge( "Merge" );
01087   const QLatin1String tagActionList( "ActionList" );
01088   const QLatin1String tagAction( "Action" );
01089   const QLatin1String attrName( "name" );
01090 
01091   int     sep_num = 0;
01092   QString sep_name("separator_%1");
01093 
01094   // clear our lists
01095   m_inactiveList->clear();
01096   m_activeList->clear();
01097   m_insertAction->setEnabled(false);
01098   m_removeAction->setEnabled(false);
01099   m_upAction->setEnabled(false);
01100   m_downAction->setEnabled(false);
01101 
01102   // We'll use this action collection
01103   KActionCollection* actionCollection = m_currentXmlData->actionCollection();
01104 
01105   // store the names of our active actions
01106   QSet<QString> active_list;
01107 
01108   // Filtering message requested by translators (scripting).
01109   KLocalizedString nameFilter = ki18nc("@item:intable Action name in toolbar editor", "%1");
01110 
01111   // see if our current action is in this toolbar
01112   QDomNode n = elem.firstChild();
01113   for( ; !n.isNull(); n = n.nextSibling() )
01114   {
01115     QDomElement it = n.toElement();
01116     if (it.isNull()) continue;
01117     if (it.tagName() == tagSeparator)
01118     {
01119       ToolBarItem *act = new ToolBarItem(m_activeList, tagSeparator, sep_name.arg(sep_num++), QString());
01120       act->setSeparator(true);
01121       act->setText(SEPARATORSTRING);
01122       it.setAttribute( attrName, act->internalName() );
01123       continue;
01124     }
01125 
01126     if (it.tagName() == tagMerge)
01127     {
01128       // Merge can be named or not - use the name if there is one
01129       QString name = it.attribute( attrName );
01130       ToolBarItem *act = new ToolBarItem(m_activeList, tagMerge, name, i18n("This element will be replaced with all the elements of an embedded component."));
01131       if ( name.isEmpty() )
01132           act->setText(i18n("<Merge>"));
01133       else
01134           act->setText(i18n("<Merge %1>", name));
01135       continue;
01136     }
01137 
01138     if (it.tagName() == tagActionList)
01139     {
01140       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.") );
01141       act->setText(i18n("ActionList: %1", it.attribute(attrName)));
01142       continue;
01143     }
01144 
01145     // iterate through this client's actions
01146     // This used to iterate through _all_ actions, but we don't support
01147     // putting any action into any client...
01148     foreach (QAction* action, actionCollection->actions())
01149     {
01150       // do we have a match?
01151       if (it.attribute( attrName ) == action->objectName())
01152       {
01153         // we have a match!
01154         ToolBarItem *act = new ToolBarItem(m_activeList, it.tagName(), action->objectName(), action->toolTip());
01155         act->setText(nameFilter.subs(KGlobal::locale()->removeAcceleratorMarker(action->iconText())).toString());
01156         act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
01157         act->setTextAlongsideIconHidden(action->priority() < QAction::NormalPriority);
01158 
01159         active_list.insert(action->objectName());
01160         break;
01161       }
01162     }
01163   }
01164 
01165   // go through the rest of the collection
01166   foreach (QAction* action, actionCollection->actions())
01167   {
01168     // skip our active ones
01169     if (active_list.contains(action->objectName()))
01170       continue;
01171 
01172     ToolBarItem *act = new ToolBarItem(m_inactiveList, tagAction, action->objectName(), action->toolTip());
01173     act->setText(nameFilter.subs(KGlobal::locale()->removeAcceleratorMarker(action->text())).toString());
01174     act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
01175   }
01176 
01177   m_inactiveList->sortItems(Qt::AscendingOrder);
01178 
01179   // finally, add default separators to the inactive list
01180   ToolBarItem *act = new ToolBarItem(0L, tagSeparator, sep_name.arg(sep_num++), QString());
01181   act->setSeparator(true);
01182   act->setText(SEPARATORSTRING);
01183   m_inactiveList->insertItem(0, act);
01184 }
01185 
01186 KActionCollection *KEditToolBarWidget::actionCollection() const
01187 {
01188   return d->m_collection;
01189 }
01190 
01191 void KEditToolBarWidgetPrivate::slotToolBarSelected(int index)
01192 {
01193     const QLatin1String attrName( "name" );
01194     // We need to find the XmlData and toolbar element for this index
01195     // To do that, we do the same iteration as the one which filled in the combobox.
01196 
01197     int toolbarNumber = 0;
01198     XmlDataList::iterator xit = m_xmlFiles.begin();
01199     for ( ; xit != m_xmlFiles.end(); ++xit) {
01200 
01201         // skip the merged one in favor of the local one,
01202         // so that we can change icons
01203         if ( (*xit).type() == XmlData::Merged )
01204             continue;
01205 
01206         // each xml file may have any number of toolbars
01207         ToolBarList::Iterator it = (*xit).barList().begin();
01208         for ( ; it != (*xit).barList().end(); ++it) {
01209 
01210             // is this our toolbar?
01211             if (toolbarNumber == index) {
01212 
01213                 // save our current settings
01214                 m_currentXmlData = & (*xit);
01215                 m_currentToolBarElem = *it;
01216 
01217                 kDebug() << "found toolbar" << m_currentXmlData->toolBarText(*it) << "m_currentXmlData set to";
01218                 m_currentXmlData->dump();
01219 
01220                 // If this is a Merged xmldata, clicking the "change icon" button would assert...
01221                 Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
01222 
01223                 // load in our values
01224                 loadActions(m_currentToolBarElem);
01225 
01226                 if ((*xit).type() == XmlData::Part || (*xit).type() == XmlData::Shell)
01227                     m_widget->setDOMDocument( (*xit).domDocument() );
01228                 return;
01229             }
01230             ++toolbarNumber;
01231 
01232         }
01233     }
01234 }
01235 
01236 void KEditToolBarWidgetPrivate::slotInactiveSelectionChanged()
01237 {
01238   if (m_inactiveList->selectedItems().count())
01239   {
01240     m_insertAction->setEnabled(true);
01241     QString statusText = static_cast<ToolBarItem*>(m_inactiveList->selectedItems().first())->statusText();
01242     m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
01243   }
01244   else
01245   {
01246     m_insertAction->setEnabled(false);
01247     m_helpArea->setText( QString() );
01248   }
01249 }
01250 
01251 void KEditToolBarWidgetPrivate::slotActiveSelectionChanged()
01252 {
01253   ToolBarItem* toolitem = 0;
01254   if (!m_activeList->selectedItems().isEmpty())
01255     toolitem = static_cast<ToolBarItem *>(m_activeList->selectedItems().first());
01256 
01257   m_removeAction->setEnabled( toolitem );
01258 
01259   m_changeIcon->setEnabled( toolitem &&
01260                             m_hasKDialog &&
01261                             toolitem->internalTag() == "Action" );
01262 
01263   m_changeIconText->setEnabled( toolitem &&
01264                                 toolitem->internalTag() == "Action" );
01265 
01266   if (toolitem)
01267   {
01268     m_upAction->setEnabled(toolitem->index() != 0);
01269     m_downAction->setEnabled(toolitem->index() != toolitem->listWidget()->count() - 1);
01270 
01271     QString statusText = toolitem->statusText();
01272     m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
01273   }
01274   else
01275   {
01276     m_upAction->setEnabled(false);
01277     m_downAction->setEnabled(false);
01278     m_helpArea->setText( QString() );
01279   }
01280 }
01281 
01282 void KEditToolBarWidgetPrivate::slotInsertButton()
01283 {
01284   QString internalName = static_cast<ToolBarItem *>(m_inactiveList->currentItem())->internalName();
01285 
01286   insertActive(m_inactiveList->currentItem(), m_activeList->currentItem(), false);
01287   // we're modified, so let this change
01288   emit m_widget->enableOk(true);
01289 
01290   slotToolBarSelected( m_toolbarCombo->currentIndex() );
01291 
01292   selectActiveItem( internalName );
01293 }
01294 
01295 void KEditToolBarWidgetPrivate::selectActiveItem(const QString& internalName)
01296 {
01297   int activeItemCount = m_activeList->count();
01298   for(int i = 0; i < activeItemCount; i++)
01299   {
01300     ToolBarItem * item = static_cast<ToolBarItem *>(m_activeList->item(i));
01301     if (item->internalName()==internalName)
01302     {
01303       m_activeList->setCurrentItem(item);
01304       break;
01305     }
01306   }
01307 }
01308 
01309 void KEditToolBarWidgetPrivate::slotRemoveButton()
01310 {
01311   removeActive( m_activeList->currentItem() );
01312 
01313   // we're modified, so let this change
01314   emit m_widget->enableOk(true);
01315 
01316   slotToolBarSelected( m_toolbarCombo->currentIndex() );
01317 }
01318 
01319 void KEditToolBarWidgetPrivate::insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend)
01320 {
01321   if (!item)
01322     return;
01323 
01324   static const QString &tagAction    = KGlobal::staticQString( "Action" );
01325   static const QString &tagSeparator = KGlobal::staticQString( "Separator" );
01326   static const QString &attrName     = KGlobal::staticQString( "name" );
01327   static const QString &attrNoMerge  = KGlobal::staticQString( "noMerge" );
01328 
01329   QDomElement new_item;
01330   // let's handle the separator specially
01331   if (item->isSeparator())
01332     new_item = m_widget->domDocument().createElement(tagSeparator);
01333   else
01334     new_item = m_widget->domDocument().createElement(tagAction);
01335 
01336   new_item.setAttribute(attrName, item->internalName());
01337 
01338   Q_ASSERT(!m_currentToolBarElem.isNull());
01339 
01340   if (before)
01341   {
01342     // we have the item in the active list which is before the new
01343     // item.. so let's try our best to add our new item right after it
01344     QDomElement elem = findElementForToolBarItem( before );
01345     Q_ASSERT( !elem.isNull() );
01346     m_currentToolBarElem.insertAfter(new_item, elem);
01347   }
01348   else
01349   {
01350     // simply put it at the beginning or the end of the list.
01351     if (prepend)
01352       m_currentToolBarElem.insertBefore(new_item, m_currentToolBarElem.firstChild());
01353     else
01354       m_currentToolBarElem.appendChild(new_item);
01355   }
01356 
01357   // and set this container as a noMerge
01358   m_currentToolBarElem.setAttribute( attrNoMerge, "1");
01359 
01360   // update the local doc
01361   updateLocal(m_currentToolBarElem);
01362 }
01363 
01364 void KEditToolBarWidgetPrivate::removeActive(ToolBarItem *item)
01365 {
01366   if (!item)
01367     return;
01368 
01369   static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
01370 
01371   // we're modified, so let this change
01372   emit m_widget->enableOk(true);
01373 
01374   // now iterate through to find the child to nuke
01375   QDomElement elem = findElementForToolBarItem( item );
01376   if ( !elem.isNull() )
01377   {
01378     // nuke myself!
01379     m_currentToolBarElem.removeChild(elem);
01380 
01381     // and set this container as a noMerge
01382     m_currentToolBarElem.setAttribute( attrNoMerge, "1");
01383 
01384     // update the local doc
01385     updateLocal(m_currentToolBarElem);
01386   }
01387 }
01388 
01389 void KEditToolBarWidgetPrivate::slotUpButton()
01390 {
01391   ToolBarItem *item = m_activeList->currentItem();
01392 
01393   if (!item) {
01394     Q_ASSERT(false);
01395     return;
01396   }
01397 
01398   int row = item->listWidget()->row(item) - 1;
01399   // make sure we're not the top item already
01400   if (row < 0) {
01401     Q_ASSERT(false);
01402     return;
01403   }
01404 
01405   // we're modified, so let this change
01406   emit m_widget->enableOk(true);
01407 
01408   moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(row - 1)) );
01409 }
01410 
01411 void KEditToolBarWidgetPrivate::moveActive( ToolBarItem* item, ToolBarItem* before )
01412 {
01413   QDomElement e = findElementForToolBarItem( item );
01414 
01415   if ( e.isNull() )
01416     return;
01417 
01418   // remove item
01419   m_activeList->takeItem(m_activeList->row(item));
01420 
01421   // put it where it's supposed to go
01422   m_activeList->insertItem(m_activeList->row(before) + 1, item);
01423 
01424   // make it selected again
01425   m_activeList->setCurrentItem(item);
01426 
01427   // and do the real move in the DOM
01428   if ( !before )
01429     m_currentToolBarElem.insertBefore(e, m_currentToolBarElem.firstChild() );
01430   else
01431     m_currentToolBarElem.insertAfter(e, findElementForToolBarItem( (ToolBarItem*)before ));
01432 
01433   // and set this container as a noMerge
01434   static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
01435   m_currentToolBarElem.setAttribute( attrNoMerge, "1");
01436 
01437   // update the local doc
01438   updateLocal(m_currentToolBarElem);
01439 }
01440 
01441 void KEditToolBarWidgetPrivate::slotDownButton()
01442 {
01443   ToolBarItem *item = m_activeList->currentItem();
01444 
01445   if (!item) {
01446     Q_ASSERT(false);
01447     return;
01448   }
01449 
01450   // make sure we're not the bottom item already
01451   int newRow = item->listWidget()->row(item) + 1;
01452   if (newRow >= item->listWidget()->count()) {
01453     Q_ASSERT(false);
01454     return;
01455   }
01456 
01457   // we're modified, so let this change
01458   emit m_widget->enableOk(true);
01459 
01460   moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(newRow)) );
01461 }
01462 
01463 void KEditToolBarWidgetPrivate::updateLocal(QDomElement& elem)
01464 {
01465   static const QString &attrName = KGlobal::staticQString( "name" );
01466 
01467   XmlDataList::Iterator xit = m_xmlFiles.begin();
01468   for ( ; xit != m_xmlFiles.end(); ++xit)
01469   {
01470     if ( (*xit).type() == XmlData::Merged )
01471       continue;
01472 
01473     if ( (*xit).type() == XmlData::Shell ||
01474          (*xit).type() == XmlData::Part )
01475     {
01476       if ( m_currentXmlData->xmlFile() == (*xit).xmlFile() )
01477       {
01478         (*xit).m_isModified = true;
01479         return;
01480       }
01481 
01482       continue;
01483     }
01484 
01485     (*xit).m_isModified = true;
01486 
01487     ToolBarList::Iterator it = (*xit).barList().begin();
01488     for ( ; it != (*xit).barList().end(); ++it)
01489     {
01490       QString name( (*it).attribute( attrName ) );
01491       QString tag( (*it).tagName() );
01492       if ( (tag != elem.tagName()) || (name != elem.attribute(attrName)) )
01493         continue;
01494 
01495       QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
01496       toolbar.replaceChild(elem, (*it));
01497       return;
01498     }
01499 
01500     // just append it
01501     QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
01502     Q_ASSERT(!toolbar.isNull());
01503     toolbar.appendChild(elem);
01504   }
01505 }
01506 
01507 void KEditToolBarWidgetPrivate::slotChangeIcon()
01508 {
01509   // We can't use KIconChooser here, since it's in libkio
01510   // ##### KDE4: reconsider this, e.g. move KEditToolBar to libkio,
01511   // ##### or better, dlopen libkfile from here like kio does.
01512 
01513   //if the process is already running (e.g. when somebody clicked the change button twice (see #127149)) - do nothing...
01514   //otherwise m_kdialogProcess will be overwritten and set to zero in slotProcessExited()...crash!
01515   if ( m_kdialogProcess && m_kdialogProcess->state() == QProcess::Running )
01516         return;
01517 
01518   m_currentXmlData->dump();
01519   Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
01520 
01521   m_kdialogProcess = new KProcess;
01522   QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
01523   (*m_kdialogProcess) << kdialogExe;
01524   (*m_kdialogProcess) << "--caption";
01525   (*m_kdialogProcess) << i18n( "Change Icon" );
01526   (*m_kdialogProcess) << "--embed";
01527   (*m_kdialogProcess) << QString::number( (quintptr)m_widget->window()->winId() );
01528   (*m_kdialogProcess) << "--geticon";
01529   (*m_kdialogProcess) << "Toolbar";
01530   (*m_kdialogProcess) << "Actions";
01531   m_kdialogProcess->setOutputChannelMode(KProcess::OnlyStdoutChannel);
01532   m_kdialogProcess->setNextOpenMode( QIODevice::ReadOnly | QIODevice::Text );
01533   m_kdialogProcess->start();
01534   if ( !m_kdialogProcess->waitForStarted() ) {
01535     kError(240) << "Can't run " << kdialogExe << endl;
01536     delete m_kdialogProcess;
01537     m_kdialogProcess = 0;
01538     return;
01539   }
01540 
01541   m_activeList->setEnabled( false ); // don't change the current item
01542   m_toolbarCombo->setEnabled( false ); // don't change the current toolbar
01543 
01544   QObject::connect( m_kdialogProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
01545                     m_widget, SLOT(slotProcessExited()) );
01546 }
01547 
01548 void KEditToolBarWidgetPrivate::slotChangeIconText()
01549 {
01550   m_currentXmlData->dump();
01551   ToolBarItem *item = m_activeList->currentItem();
01552 
01553   if(item){
01554     QString iconText = item->text();
01555     bool hidden = item->isTextAlongsideIconHidden();
01556 
01557     IconTextEditDialog dialog(m_widget);
01558     dialog.setIconText(iconText);
01559     dialog.setTextAlongsideIconHidden(hidden);
01560 
01561     bool ok = dialog.exec() == KDialog::Accepted;
01562     iconText = dialog.iconText();
01563     hidden = dialog.textAlongsideIconHidden();
01564 
01565     bool hiddenChanged = hidden != item->isTextAlongsideIconHidden();
01566     bool iconTextChanged = iconText != item->text();
01567 
01568     if (!ok || (!hiddenChanged && !iconTextChanged))
01569       return;
01570 
01571     item->setText(iconText);
01572     item->setTextAlongsideIconHidden(hidden);
01573 
01574     Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
01575 
01576     m_currentXmlData->m_isModified = true;
01577 
01578     // Get hold of ActionProperties tag
01579     QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
01580     // Find or create an element for this action
01581     QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
01582     Q_ASSERT( !act_elem.isNull() );
01583     if (iconTextChanged)
01584         act_elem.setAttribute( "iconText", iconText );
01585     if (hiddenChanged)
01586         act_elem.setAttribute( "priority", hidden ? QAction::LowPriority : QAction::NormalPriority );
01587 
01588     // we're modified, so let this change
01589     emit m_widget->enableOk(true);
01590   }
01591 }
01592 
01593 void KEditToolBarWidgetPrivate::slotProcessExited()
01594 {
01595   m_activeList->setEnabled( true );
01596   m_toolbarCombo->setEnabled( true );
01597 
01598   QString icon;
01599 
01600   if (!m_kdialogProcess) {
01601          kError(240) << "Something is wrong here! m_kdialogProcess is zero!" << endl;
01602          return;
01603   }
01604 
01605   icon = QString::fromLocal8Bit( m_kdialogProcess->readLine() );
01606   icon = icon.left( icon.indexOf( '\n' ) );
01607   kDebug(240) << "icon=" << icon;
01608   if ( m_kdialogProcess->exitStatus() != QProcess::NormalExit ||
01609        icon.isEmpty() ) {
01610     delete m_kdialogProcess;
01611     m_kdialogProcess = 0;
01612     return;
01613   }
01614 
01615   ToolBarItem *item = m_activeList->currentItem();
01616   kDebug() << item;
01617   if(item){
01618     item->setIcon(KIcon(icon));
01619 
01620     Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
01621 
01622     m_currentXmlData->m_isModified = true;
01623 
01624     // Get hold of ActionProperties tag
01625     QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
01626     // Find or create an element for this action
01627     QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
01628     Q_ASSERT( !act_elem.isNull() );
01629     act_elem.setAttribute( "icon", icon );
01630 
01631     // we're modified, so let this change
01632     emit m_widget->enableOk(true);
01633   }
01634 
01635   delete m_kdialogProcess;
01636   m_kdialogProcess = 0;
01637 }
01638 
01639 void KEditToolBarWidgetPrivate::slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList)
01640 {
01641     //kDebug() << "slotDropped list=" << (list==m_activeList?"activeList":"inactiveList")
01642     //         << "index=" << index << "sourceIsActiveList=" << sourceIsActiveList;
01643     if (list == m_activeList) {
01644         ToolBarItem* after = index > 0 ? static_cast<ToolBarItem *>(list->item(index-1)) : 0;
01645         //kDebug() << "after" << after->text() << after->internalTag();
01646         if (sourceIsActiveList) {
01647             // has been dragged within the active list (moved).
01648             moveActive(item, after);
01649         } else {
01650             // dragged from the inactive list to the active list
01651             insertActive(item, after, true);
01652         }
01653     } else if (list == m_inactiveList) {
01654         // has been dragged to the inactive list -> remove from the active list.
01655         removeActive(item);
01656     }
01657 
01658     delete item; // not needed anymore. must be deleted before slotToolBarSelected clears the lists
01659 
01660     // we're modified, so let this change
01661     emit m_widget->enableOk(true);
01662 
01663     slotToolBarSelected( m_toolbarCombo->currentIndex() );
01664 }
01665 
01666 
01667 void KEditToolBar::showEvent( QShowEvent * event )
01668 {
01669     if (!event->spontaneous()) {
01670         // The dialog has been shown, enable toolbar editing
01671         if ( d->m_factory ) {
01672             // call the xmlgui-factory version
01673             d->m_widget->load( d->m_factory, d->m_defaultToolBar );
01674         } else {
01675             // call the action collection version
01676             d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
01677         }
01678 
01679         KToolBar::setToolBarsEditable(true);
01680     }
01681     KDialog::showEvent(event);
01682 }
01683 
01684 void KEditToolBar::hideEvent(QHideEvent* event)
01685 {
01686   // The dialog has been hidden, disable toolbar editing
01687   KToolBar::setToolBarsEditable(false);
01688 
01689   KDialog::hideEvent(event);
01690 }
01691 
01692 #include "kedittoolbar.moc"
01693 #include "kedittoolbar_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:53:03 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

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

kdelibs-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 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