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