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