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

KDEUI

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

kdelibs

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