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"
KDE 4.6 API Reference