kedittoolbar.cpp
00001 // -*- mode: c++; c-basic-offset: 2 -*- 00002 /* This file is part of the KDE libraries 00003 Copyright (C) 2000 Kurt Granroth <granroth@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 #include <kedittoolbar.h> 00020 00021 #include <qdom.h> 00022 #include <qlayout.h> 00023 #include <qdir.h> 00024 #include <qfile.h> 00025 #include <qheader.h> 00026 #include <qcombobox.h> 00027 #include <qdragobject.h> 00028 #include <qtoolbutton.h> 00029 #include <qlabel.h> 00030 #include <qvaluelist.h> 00031 #include <qapplication.h> 00032 #include <qtextstream.h> 00033 00034 #include <kaction.h> 00035 #include <kstandarddirs.h> 00036 #include <klocale.h> 00037 #include <kicontheme.h> 00038 #include <kiconloader.h> 00039 #include <kinstance.h> 00040 #include <kmessagebox.h> 00041 #include <kxmlguifactory.h> 00042 #include <kseparator.h> 00043 #include <kconfig.h> 00044 #include <klistview.h> 00045 #include <kdebug.h> 00046 #include <kpushbutton.h> 00047 #include <kprocio.h> 00048 00049 static const char * const lineseparatorstring = I18N_NOOP("--- line separator ---"); 00050 static const char * const separatorstring = I18N_NOOP("--- separator ---"); 00051 00052 #define LINESEPARATORSTRING i18n(lineseparatorstring) 00053 #define SEPARATORSTRING i18n(separatorstring) 00054 00055 static void dump_xml(const QDomDocument& doc) 00056 { 00057 QString str; 00058 QTextStream ts(&str, IO_WriteOnly); 00059 ts << doc; 00060 kdDebug() << str << endl; 00061 } 00062 00063 typedef QValueList<QDomElement> ToolbarList; 00064 00065 namespace 00066 { 00067 class XmlData 00068 { 00069 public: 00070 enum XmlType { Shell = 0, Part, Local, Merged }; 00071 XmlData() 00072 { 00073 m_isModified = false; 00074 m_actionCollection = 0; 00075 } 00076 00077 QString m_xmlFile; 00078 QDomDocument m_document; 00079 XmlType m_type; 00080 bool m_isModified; 00081 KActionCollection* m_actionCollection; 00082 00083 ToolbarList m_barList; 00084 }; 00085 00086 typedef QValueList<XmlData> XmlDataList; 00087 00088 class ToolbarItem : public QListViewItem 00089 { 00090 public: 00091 ToolbarItem(KListView *parent, const QString& tag = QString::null, const QString& name = QString::null, const QString& statusText = QString::null) 00092 : QListViewItem(parent), 00093 m_tag(tag), 00094 m_name(name), 00095 m_statusText(statusText) 00096 { 00097 } 00098 00099 ToolbarItem(KListView *parent, QListViewItem *item, const QString &tag = QString::null, const QString& name = QString::null, const QString& statusText = QString::null) 00100 : QListViewItem(parent, item), 00101 m_tag(tag), 00102 m_name(name), 00103 m_statusText(statusText) 00104 { 00105 } 00106 00107 virtual QString key(int column, bool) const 00108 { 00109 QString s = text( column ); 00110 if ( s == LINESEPARATORSTRING ) 00111 return "0"; 00112 if ( s == SEPARATORSTRING ) 00113 return "1"; 00114 return "2" + s; 00115 } 00116 00117 void setInternalTag(const QString &tag) { m_tag = tag; } 00118 void setInternalName(const QString &name) { m_name = name; } 00119 void setStatusText(const QString &text) { m_statusText = text; } 00120 QString internalTag() const { return m_tag; } 00121 QString internalName() const { return m_name; } 00122 QString statusText() const { return m_statusText; } 00123 private: 00124 QString m_tag; 00125 QString m_name; 00126 QString m_statusText; 00127 }; 00128 00129 #define TOOLBARITEMMIMETYPE "data/x-kde.toolbar.item" 00130 class ToolbarItemDrag : public QStoredDrag 00131 { 00132 public: 00133 ToolbarItemDrag(ToolbarItem *toolbarItem, 00134 QWidget *dragSource = 0, const char *name = 0) 00135 : QStoredDrag( TOOLBARITEMMIMETYPE, dragSource, name ) 00136 { 00137 if (toolbarItem) { 00138 QByteArray data; 00139 QDataStream out(data, IO_WriteOnly); 00140 out << toolbarItem->internalTag(); 00141 out << toolbarItem->internalName(); 00142 out << toolbarItem->statusText(); 00143 out << toolbarItem->text(1); // separators need this. 00144 setEncodedData(data); 00145 } 00146 } 00147 00148 static bool canDecode(QMimeSource* e) 00149 { 00150 return e->provides(TOOLBARITEMMIMETYPE); 00151 } 00152 00153 static bool decode( const QMimeSource* e, ToolbarItem& item ) 00154 { 00155 if (!e) 00156 return false; 00157 00158 QByteArray data = e->encodedData(TOOLBARITEMMIMETYPE); 00159 if ( data.isEmpty() ) 00160 return false; 00161 00162 QString internalTag, internalName, statusText, text; 00163 QDataStream in(data, IO_ReadOnly); 00164 in >> internalTag; 00165 in >> internalName; 00166 in >> statusText; 00167 in >> text; 00168 00169 item.setInternalTag( internalTag ); 00170 item.setInternalName( internalName ); 00171 item.setStatusText( statusText ); 00172 item.setText(1, text); 00173 00174 return true; 00175 } 00176 }; 00177 00178 class ToolbarListView : public KListView 00179 { 00180 public: 00181 ToolbarListView(QWidget *parent=0, const char *name=0) 00182 : KListView(parent, name) 00183 { 00184 } 00185 protected: 00186 virtual QDragObject *dragObject() 00187 { 00188 ToolbarItem *item = dynamic_cast<ToolbarItem*>(selectedItem()); 00189 if ( item ) { 00190 ToolbarItemDrag *obj = new ToolbarItemDrag(item, 00191 this, "ToolbarAction drag item"); 00192 const QPixmap *pm = item->pixmap(0); 00193 if( pm ) 00194 obj->setPixmap( *pm ); 00195 return obj; 00196 } 00197 return 0; 00198 } 00199 00200 virtual bool acceptDrag(QDropEvent *event) const 00201 { 00202 return ToolbarItemDrag::canDecode( event ); 00203 } 00204 }; 00205 } // namespace 00206 00207 class KEditToolbarWidgetPrivate 00208 { 00209 public: 00217 KEditToolbarWidgetPrivate(KInstance *instance, KActionCollection* collection) 00218 : m_collection( collection ) 00219 { 00220 m_instance = instance; 00221 m_isPart = false; 00222 m_helpArea = 0L; 00223 m_kdialogProcess = 0; 00224 } 00225 ~KEditToolbarWidgetPrivate() 00226 { 00227 } 00228 00229 QString xmlFile(const QString& xml_file) 00230 { 00231 return xml_file.isNull() ? QString(m_instance->instanceName()) + "ui.rc" : 00232 xml_file; 00233 } 00234 00238 QString loadXMLFile(const QString& _xml_file) 00239 { 00240 QString raw_xml; 00241 QString xml_file = xmlFile(_xml_file); 00242 //kdDebug() << "loadXMLFile xml_file=" << xml_file << endl; 00243 00244 if ( !QDir::isRelativePath(xml_file) ) 00245 raw_xml = KXMLGUIFactory::readConfigFile(xml_file); 00246 else 00247 raw_xml = KXMLGUIFactory::readConfigFile(xml_file, m_instance); 00248 00249 return raw_xml; 00250 } 00251 00255 ToolbarList findToolbars(QDomNode n) 00256 { 00257 static const QString &tagToolbar = KGlobal::staticQString( "ToolBar" ); 00258 static const QString &attrNoEdit = KGlobal::staticQString( "noEdit" ); 00259 ToolbarList list; 00260 00261 for( ; !n.isNull(); n = n.nextSibling() ) 00262 { 00263 QDomElement elem = n.toElement(); 00264 if (elem.isNull()) 00265 continue; 00266 00267 if (elem.tagName() == tagToolbar && elem.attribute( attrNoEdit ) != "true" ) 00268 list.append(elem); 00269 00270 list += findToolbars(elem.firstChild()); 00271 } 00272 00273 return list; 00274 } 00275 00279 QString toolbarName( const XmlData& xmlData, const QDomElement& it ) const 00280 { 00281 static const QString &tagText = KGlobal::staticQString( "text" ); 00282 static const QString &tagText2 = KGlobal::staticQString( "Text" ); 00283 static const QString &attrName = KGlobal::staticQString( "name" ); 00284 00285 QString name; 00286 QCString txt( it.namedItem( tagText ).toElement().text().utf8() ); 00287 if ( txt.isEmpty() ) 00288 txt = it.namedItem( tagText2 ).toElement().text().utf8(); 00289 if ( txt.isEmpty() ) 00290 name = it.attribute( attrName ); 00291 else 00292 name = i18n( txt ); 00293 00294 // the name of the toolbar might depend on whether or not 00295 // it is in kparts 00296 if ( ( xmlData.m_type == XmlData::Shell ) || 00297 ( xmlData.m_type == XmlData::Part ) ) 00298 { 00299 QString doc_name(xmlData.m_document.documentElement().attribute( attrName )); 00300 name += " <" + doc_name + ">"; 00301 } 00302 return name; 00303 } 00307 QDomElement findElementForToolbarItem( const ToolbarItem* item ) const 00308 { 00309 static const QString &attrName = KGlobal::staticQString( "name" ); 00310 for(QDomNode n = m_currentToolbarElem.firstChild(); !n.isNull(); n = n.nextSibling()) 00311 { 00312 QDomElement elem = n.toElement(); 00313 if ((elem.attribute(attrName) == item->internalName()) && 00314 (elem.tagName() == item->internalTag())) 00315 return elem; 00316 } 00317 return QDomElement(); 00318 } 00319 00320 #ifndef NDEBUG 00321 void dump() 00322 { 00323 static const char* s_XmlTypeToString[] = { "Shell", "Part", "Local", "Merged" }; 00324 XmlDataList::Iterator xit = m_xmlFiles.begin(); 00325 for ( ; xit != m_xmlFiles.end(); ++xit ) 00326 { 00327 kdDebug(240) << "XmlData type " << s_XmlTypeToString[(*xit).m_type] << " xmlFile: " << (*xit).m_xmlFile << endl; 00328 for( QValueList<QDomElement>::Iterator it = (*xit).m_barList.begin(); 00329 it != (*xit).m_barList.end(); ++it ) { 00330 kdDebug(240) << " Toolbar: " << toolbarName( *xit, *it ) << endl; 00331 } 00332 if ( (*xit).m_actionCollection ) 00333 kdDebug(240) << " " << (*xit).m_actionCollection->count() << " actions in the collection." << endl; 00334 else 00335 kdDebug(240) << " no action collection." << endl; 00336 } 00337 } 00338 #endif 00339 00340 //QValueList<KAction*> m_actionList; 00341 KActionCollection* m_collection; 00342 KInstance *m_instance; 00343 00344 XmlData* m_currentXmlData; 00345 QDomElement m_currentToolbarElem; 00346 00347 QString m_xmlFile; 00348 QString m_globalFile; 00349 QString m_rcFile; 00350 QDomDocument m_localDoc; 00351 bool m_isPart; 00352 00353 ToolbarList m_barList; 00354 00355 XmlDataList m_xmlFiles; 00356 00357 QLabel *m_comboLabel; 00358 KSeparator *m_comboSeparator; 00359 QLabel * m_helpArea; 00360 KPushButton* m_changeIcon; 00361 KProcIO* m_kdialogProcess; 00362 bool m_hasKDialog; 00363 }; 00364 00365 class KEditToolbarPrivate { 00366 public: 00367 bool m_accept; 00368 00369 // Save parameters for recreating widget after resetting toolbar 00370 bool m_global; 00371 KActionCollection* m_collection; 00372 QString m_file; 00373 KXMLGUIFactory* m_factory; 00374 }; 00375 00376 const char *KEditToolbar::s_defaultToolbar = 0L; 00377 00378 KEditToolbar::KEditToolbar(KActionCollection *collection, const QString& file, 00379 bool global, QWidget* parent, const char* name) 00380 : KDialogBase(Swallow, i18n("Configure Toolbars"), Default|Ok|Apply|Cancel, Ok, parent, name), 00381 m_widget(new KEditToolbarWidget(QString::fromLatin1(s_defaultToolbar), collection, file, global, this)) 00382 { 00383 init(); 00384 d->m_global = global; 00385 d->m_collection = collection; 00386 d->m_file = file; 00387 } 00388 00389 KEditToolbar::KEditToolbar(const QString& defaultToolbar, KActionCollection *collection, 00390 const QString& file, bool global, 00391 QWidget* parent, const char* name) 00392 : KDialogBase(Swallow, i18n("Configure Toolbars"), Default|Ok|Apply|Cancel, Ok, parent, name), 00393 m_widget(new KEditToolbarWidget(defaultToolbar, collection, file, global, this)) 00394 { 00395 init(); 00396 d->m_global = global; 00397 d->m_collection = collection; 00398 d->m_file = file; 00399 } 00400 00401 KEditToolbar::KEditToolbar(KXMLGUIFactory* factory, QWidget* parent, const char* name) 00402 : KDialogBase(Swallow, i18n("Configure Toolbars"), Default|Ok|Apply|Cancel, Ok, parent, name), 00403 m_widget(new KEditToolbarWidget(QString::fromLatin1(s_defaultToolbar), factory, this)) 00404 { 00405 init(); 00406 d->m_factory = factory; 00407 } 00408 00409 KEditToolbar::KEditToolbar(const QString& defaultToolbar,KXMLGUIFactory* factory, 00410 QWidget* parent, const char* name) 00411 : KDialogBase(Swallow, i18n("Configure Toolbars"), Default|Ok|Apply|Cancel, Ok, parent, name), 00412 m_widget(new KEditToolbarWidget(defaultToolbar, factory, this)) 00413 { 00414 init(); 00415 d->m_factory = factory; 00416 } 00417 00418 void KEditToolbar::init() 00419 { 00420 d = new KEditToolbarPrivate(); 00421 d->m_accept = false; 00422 d->m_factory = 0; 00423 00424 setMainWidget(m_widget); 00425 00426 connect(m_widget, SIGNAL(enableOk(bool)), SLOT(acceptOK(bool))); 00427 connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool))); 00428 enableButtonApply(false); 00429 00430 setMinimumSize(sizeHint()); 00431 s_defaultToolbar = 0L; 00432 } 00433 00434 KEditToolbar::~KEditToolbar() 00435 { 00436 delete d; 00437 } 00438 00439 void KEditToolbar::acceptOK(bool b) 00440 { 00441 enableButtonOK(b); 00442 d->m_accept = b; 00443 } 00444 00445 void KEditToolbar::slotDefault() 00446 { 00447 if ( KMessageBox::warningContinueCancel(this, i18n("Do you really want to reset all toolbars of this application to their default? The changes will be applied immediately."), i18n("Reset Toolbars"),i18n("Reset"))!=KMessageBox::Continue ) 00448 return; 00449 00450 delete m_widget; 00451 d->m_accept = false; 00452 00453 if ( d->m_factory ) 00454 { 00455 const QString localPrefix = locateLocal("data", ""); 00456 QPtrList<KXMLGUIClient> clients(d->m_factory->clients()); 00457 QPtrListIterator<KXMLGUIClient> it( clients ); 00458 00459 for( ; it.current(); ++it) 00460 { 00461 KXMLGUIClient *client = it.current(); 00462 QString file = client->xmlFile(); 00463 00464 if (file.isNull()) 00465 continue; 00466 00467 if (QDir::isRelativePath(file)) 00468 { 00469 const KInstance *instance = client->instance() ? client->instance() : KGlobal::instance(); 00470 file = locateLocal("data", QString::fromLatin1( instance->instanceName() + '/' ) + file); 00471 } 00472 else 00473 { 00474 if (!file.startsWith(localPrefix)) 00475 continue; 00476 } 00477 00478 if ( QFile::exists( file ) ) 00479 if ( !QFile::remove( file ) ) 00480 kdWarning() << "Could not delete " << file << endl; 00481 } 00482 00483 m_widget = new KEditToolbarWidget(QString::null, d->m_factory, this); 00484 m_widget->rebuildKXMLGUIClients(); 00485 } 00486 else 00487 { 00488 int slash = d->m_file.findRev('/')+1; 00489 if (slash) 00490 d->m_file = d->m_file.mid(slash); 00491 QString xml_file = locateLocal("data", QString::fromLatin1( KGlobal::instance()->instanceName() + '/' ) + d->m_file); 00492 00493 if ( QFile::exists( xml_file ) ) 00494 if ( !QFile::remove( xml_file ) ) 00495 kdWarning() << "Could not delete " << xml_file << endl; 00496 00497 m_widget = new KEditToolbarWidget(QString::null, d->m_collection, d->m_file, d->m_global, this); 00498 } 00499 00500 setMainWidget(m_widget); 00501 m_widget->show(); 00502 00503 connect(m_widget, SIGNAL(enableOk(bool)), SLOT(acceptOK(bool))); 00504 connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool))); 00505 00506 enableButtonApply(false); 00507 emit newToolbarConfig(); 00508 } 00509 00510 void KEditToolbar::slotOk() 00511 { 00512 if (!d->m_accept) { 00513 reject(); 00514 return; 00515 } 00516 00517 if (!m_widget->save()) 00518 { 00519 // some error box here is needed 00520 } 00521 else 00522 { 00523 emit newToolbarConfig(); 00524 accept(); 00525 } 00526 } 00527 00528 void KEditToolbar::slotApply() 00529 { 00530 (void)m_widget->save(); 00531 enableButtonApply(false); 00532 emit newToolbarConfig(); 00533 } 00534 00535 void KEditToolbar::setDefaultToolbar(const char *toolbarName) 00536 { 00537 s_defaultToolbar = toolbarName; 00538 } 00539 00540 KEditToolbarWidget::KEditToolbarWidget(KActionCollection *collection, 00541 const QString& file, 00542 bool global, QWidget *parent) 00543 : QWidget(parent), 00544 d(new KEditToolbarWidgetPrivate(instance(), collection)) 00545 { 00546 initNonKPart(collection, file, global); 00547 // now load in our toolbar combo box 00548 loadToolbarCombo(); 00549 adjustSize(); 00550 setMinimumSize(sizeHint()); 00551 } 00552 00553 KEditToolbarWidget::KEditToolbarWidget(const QString& defaultToolbar, 00554 KActionCollection *collection, 00555 const QString& file, bool global, 00556 QWidget *parent) 00557 : QWidget(parent), 00558 d(new KEditToolbarWidgetPrivate(instance(), collection)) 00559 { 00560 initNonKPart(collection, file, global); 00561 // now load in our toolbar combo box 00562 loadToolbarCombo(defaultToolbar); 00563 adjustSize(); 00564 setMinimumSize(sizeHint()); 00565 } 00566 00567 KEditToolbarWidget::KEditToolbarWidget( KXMLGUIFactory* factory, 00568 QWidget *parent) 00569 : QWidget(parent), 00570 d(new KEditToolbarWidgetPrivate(instance(), KXMLGUIClient::actionCollection() /*create new one*/)) 00571 { 00572 initKPart(factory); 00573 // now load in our toolbar combo box 00574 loadToolbarCombo(); 00575 adjustSize(); 00576 setMinimumSize(sizeHint()); 00577 } 00578 00579 KEditToolbarWidget::KEditToolbarWidget( const QString& defaultToolbar, 00580 KXMLGUIFactory* factory, 00581 QWidget *parent) 00582 : QWidget(parent), 00583 d(new KEditToolbarWidgetPrivate(instance(), KXMLGUIClient::actionCollection() /*create new one*/)) 00584 { 00585 initKPart(factory); 00586 // now load in our toolbar combo box 00587 loadToolbarCombo(defaultToolbar); 00588 adjustSize(); 00589 setMinimumSize(sizeHint()); 00590 } 00591 00592 KEditToolbarWidget::~KEditToolbarWidget() 00593 { 00594 delete d; 00595 } 00596 00597 void KEditToolbarWidget::initNonKPart(KActionCollection *collection, 00598 const QString& file, bool global) 00599 { 00600 //d->m_actionList = collection->actions(); 00601 00602 // handle the merging 00603 if (global) 00604 setXMLFile(locate("config", "ui/ui_standards.rc")); 00605 QString localXML = d->loadXMLFile(file); 00606 setXML(localXML, true); 00607 00608 // reusable vars 00609 QDomElement elem; 00610 00611 // first, get all of the necessary info for our local xml 00612 XmlData local; 00613 local.m_xmlFile = d->xmlFile(file); 00614 local.m_type = XmlData::Local; 00615 local.m_document.setContent(localXML); 00616 elem = local.m_document.documentElement().toElement(); 00617 local.m_barList = d->findToolbars(elem); 00618 local.m_actionCollection = collection; 00619 d->m_xmlFiles.append(local); 00620 00621 // then, the merged one (ui_standards + local xml) 00622 XmlData merge; 00623 merge.m_xmlFile = QString::null; 00624 merge.m_type = XmlData::Merged; 00625 merge.m_document = domDocument(); 00626 elem = merge.m_document.documentElement().toElement(); 00627 merge.m_barList = d->findToolbars(elem); 00628 merge.m_actionCollection = collection; 00629 d->m_xmlFiles.append(merge); 00630 00631 #ifndef NDEBUG 00632 //d->dump(); 00633 #endif 00634 00635 // okay, that done, we concern ourselves with the GUI aspects 00636 setupLayout(); 00637 } 00638 00639 void KEditToolbarWidget::initKPart(KXMLGUIFactory* factory) 00640 { 00641 // reusable vars 00642 QDomElement elem; 00643 00644 setFactory( factory ); 00645 actionCollection()->setWidget( this ); 00646 00647 // add all of the client data 00648 QPtrList<KXMLGUIClient> clients(factory->clients()); 00649 QPtrListIterator<KXMLGUIClient> it( clients ); 00650 for( ; it.current(); ++it) 00651 { 00652 KXMLGUIClient *client = it.current(); 00653 00654 if (client->xmlFile().isNull()) 00655 continue; 00656 00657 XmlData data; 00658 data.m_xmlFile = client->localXMLFile(); 00659 if ( it.atFirst() ) 00660 data.m_type = XmlData::Shell; 00661 else 00662 data.m_type = XmlData::Part; 00663 data.m_document.setContent( KXMLGUIFactory::readConfigFile( client->xmlFile(), client->instance() ) ); 00664 elem = data.m_document.documentElement().toElement(); 00665 data.m_barList = d->findToolbars(elem); 00666 data.m_actionCollection = client->actionCollection(); 00667 d->m_xmlFiles.append(data); 00668 00669 //d->m_actionList += client->actionCollection()->actions(); 00670 } 00671 00672 #ifndef NDEBUG 00673 //d->dump(); 00674 #endif 00675 00676 // okay, that done, we concern ourselves with the GUI aspects 00677 setupLayout(); 00678 } 00679 00680 bool KEditToolbarWidget::save() 00681 { 00682 //kdDebug(240) << "KEditToolbarWidget::save" << endl; 00683 XmlDataList::Iterator it = d->m_xmlFiles.begin(); 00684 for ( ; it != d->m_xmlFiles.end(); ++it) 00685 { 00686 // let's not save non-modified files 00687 if ( !((*it).m_isModified) ) 00688 continue; 00689 00690 // let's also skip (non-existent) merged files 00691 if ( (*it).m_type == XmlData::Merged ) 00692 continue; 00693 00694 dump_xml((*it).m_document); 00695 00696 kdDebug(240) << "Saving " << (*it).m_xmlFile << endl; 00697 // if we got this far, we might as well just save it 00698 KXMLGUIFactory::saveConfigFile((*it).m_document, (*it).m_xmlFile); 00699 } 00700 00701 if ( !factory() ) 00702 return true; 00703 00704 rebuildKXMLGUIClients(); 00705 00706 return true; 00707 } 00708 00709 void KEditToolbarWidget::rebuildKXMLGUIClients() 00710 { 00711 if ( !factory() ) 00712 return; 00713 00714 QPtrList<KXMLGUIClient> clients(factory()->clients()); 00715 //kdDebug(240) << "factory: " << clients.count() << " clients" << endl; 00716 00717 // remove the elements starting from the last going to the first 00718 KXMLGUIClient *client = clients.last(); 00719 while ( client ) 00720 { 00721 //kdDebug(240) << "factory->removeClient " << client << endl; 00722 factory()->removeClient( client ); 00723 client = clients.prev(); 00724 } 00725 00726 KXMLGUIClient *firstClient = clients.first(); 00727 00728 // now, rebuild the gui from the first to the last 00729 //kdDebug(240) << "rebuilding the gui" << endl; 00730 QPtrListIterator<KXMLGUIClient> cit( clients ); 00731 for( ; cit.current(); ++cit) 00732 { 00733 KXMLGUIClient* client = cit.current(); 00734 //kdDebug(240) << "updating client " << client << " " << client->instance()->instanceName() << " xmlFile=" << client->xmlFile() << endl; 00735 QString file( client->xmlFile() ); // before setting ui_standards! 00736 if ( !file.isEmpty() ) 00737 { 00738 // passing an empty stream forces the clients to reread the XML 00739 client->setXMLGUIBuildDocument( QDomDocument() ); 00740 00741 // for the shell, merge in ui_standards.rc 00742 if ( client == firstClient ) // same assumption as in the ctor: first==shell 00743 client->setXMLFile(locate("config", "ui/ui_standards.rc")); 00744 00745 // and this forces it to use the *new* XML file 00746 client->setXMLFile( file, client == firstClient /* merge if shell */ ); 00747 } 00748 } 00749 00750 // Now we can add the clients to the factory 00751 // We don't do it in the loop above because adding a part automatically 00752 // adds its plugins, so we must make sure the plugins were updated first. 00753 cit.toFirst(); 00754 for( ; cit.current(); ++cit) 00755 factory()->addClient( cit.current() ); 00756 } 00757 00758 void KEditToolbarWidget::setupLayout() 00759 { 00760 // the toolbar name combo 00761 d->m_comboLabel = new QLabel(i18n("&Toolbar:"), this); 00762 m_toolbarCombo = new QComboBox(this); 00763 m_toolbarCombo->setEnabled(false); 00764 d->m_comboLabel->setBuddy(m_toolbarCombo); 00765 d->m_comboSeparator = new KSeparator(this); 00766 connect(m_toolbarCombo, SIGNAL(activated(const QString&)), 00767 this, SLOT(slotToolbarSelected(const QString&))); 00768 00769 // QPushButton *new_toolbar = new QPushButton(i18n("&New"), this); 00770 // new_toolbar->setPixmap(BarIcon("filenew", KIcon::SizeSmall)); 00771 // new_toolbar->setEnabled(false); // disabled until implemented 00772 // QPushButton *del_toolbar = new QPushButton(i18n("&Delete"), this); 00773 // del_toolbar->setPixmap(BarIcon("editdelete", KIcon::SizeSmall)); 00774 // del_toolbar->setEnabled(false); // disabled until implemented 00775 00776 // our list of inactive actions 00777 QLabel *inactive_label = new QLabel(i18n("A&vailable actions:"), this); 00778 m_inactiveList = new ToolbarListView(this); 00779 m_inactiveList->setDragEnabled(true); 00780 m_inactiveList->setAcceptDrops(true); 00781 m_inactiveList->setDropVisualizer(false); 00782 m_inactiveList->setAllColumnsShowFocus(true); 00783 m_inactiveList->setMinimumSize(180, 250); 00784 m_inactiveList->header()->hide(); 00785 m_inactiveList->addColumn(""); // icon 00786 int column2 = m_inactiveList->addColumn(""); // text 00787 m_inactiveList->setSorting( column2 ); 00788 inactive_label->setBuddy(m_inactiveList); 00789 connect(m_inactiveList, SIGNAL(selectionChanged(QListViewItem *)), 00790 this, SLOT(slotInactiveSelected(QListViewItem *))); 00791 connect(m_inactiveList, SIGNAL( doubleClicked( QListViewItem *, const QPoint &, int )), 00792 this, SLOT(slotInsertButton())); 00793 00794 // our list of active actions 00795 QLabel *active_label = new QLabel(i18n("Curr&ent actions:"), this); 00796 m_activeList = new ToolbarListView(this); 00797 m_activeList->setDragEnabled(true); 00798 m_activeList->setAcceptDrops(true); 00799 m_activeList->setDropVisualizer(true); 00800 m_activeList->setAllColumnsShowFocus(true); 00801 m_activeList->setMinimumWidth(m_inactiveList->minimumWidth()); 00802 m_activeList->header()->hide(); 00803 m_activeList->addColumn(""); // icon 00804 m_activeList->addColumn(""); // text 00805 m_activeList->setSorting(-1); 00806 active_label->setBuddy(m_activeList); 00807 00808 connect(m_inactiveList, SIGNAL(dropped(KListView*,QDropEvent*,QListViewItem*)), 00809 this, SLOT(slotDropped(KListView*,QDropEvent*,QListViewItem*))); 00810 connect(m_activeList, SIGNAL(dropped(KListView*,QDropEvent*,QListViewItem*)), 00811 this, SLOT(slotDropped(KListView*,QDropEvent*,QListViewItem*))); 00812 connect(m_activeList, SIGNAL(selectionChanged(QListViewItem *)), 00813 this, SLOT(slotActiveSelected(QListViewItem *))); 00814 connect(m_activeList, SIGNAL( doubleClicked( QListViewItem *, const QPoint &, int )), 00815 this, SLOT(slotRemoveButton())); 00816 00817 // "change icon" button 00818 d->m_changeIcon = new KPushButton( i18n( "Change &Icon..." ), this ); 00819 QString kdialogExe = KStandardDirs::findExe(QString::fromLatin1("kdialog")); 00820 d->m_hasKDialog = !kdialogExe.isEmpty(); 00821 d->m_changeIcon->setEnabled( d->m_hasKDialog ); 00822 00823 connect( d->m_changeIcon, SIGNAL( clicked() ), 00824 this, SLOT( slotChangeIcon() ) ); 00825 00826 // The buttons in the middle 00827 QIconSet iconSet; 00828 00829 m_upAction = new QToolButton(this); 00830 iconSet = SmallIconSet( "up" ); 00831 m_upAction->setIconSet( iconSet ); 00832 m_upAction->setEnabled(false); 00833 m_upAction->setAutoRepeat(true); 00834 connect(m_upAction, SIGNAL(clicked()), SLOT(slotUpButton())); 00835 00836 m_insertAction = new QToolButton(this); 00837 iconSet = QApplication::reverseLayout() ? SmallIconSet( "back" ) : SmallIconSet( "forward" ); 00838 m_insertAction->setIconSet( iconSet ); 00839 m_insertAction->setEnabled(false); 00840 connect(m_insertAction, SIGNAL(clicked()), SLOT(slotInsertButton())); 00841 00842 m_removeAction = new QToolButton(this); 00843 iconSet = QApplication::reverseLayout() ? SmallIconSet( "forward" ) : SmallIconSet( "back" ); 00844 m_removeAction->setIconSet( iconSet ); 00845 m_removeAction->setEnabled(false); 00846 connect(m_removeAction, SIGNAL(clicked()), SLOT(slotRemoveButton())); 00847 00848 m_downAction = new QToolButton(this); 00849 iconSet = SmallIconSet( "down" ); 00850 m_downAction->setIconSet( iconSet ); 00851 m_downAction->setEnabled(false); 00852 m_downAction->setAutoRepeat(true); 00853 connect(m_downAction, SIGNAL(clicked()), SLOT(slotDownButton())); 00854 00855 d->m_helpArea = new QLabel(this); 00856 d->m_helpArea->setAlignment( Qt::WordBreak ); 00857 00858 // now start with our layouts 00859 QVBoxLayout *top_layout = new QVBoxLayout(this, 0, KDialog::spacingHint()); 00860 00861 QVBoxLayout *name_layout = new QVBoxLayout(KDialog::spacingHint()); 00862 QHBoxLayout *list_layout = new QHBoxLayout(KDialog::spacingHint()); 00863 00864 QVBoxLayout *inactive_layout = new QVBoxLayout(KDialog::spacingHint()); 00865 QVBoxLayout *active_layout = new QVBoxLayout(KDialog::spacingHint()); 00866 QHBoxLayout *changeIcon_layout = new QHBoxLayout(KDialog::spacingHint()); 00867 00868 QGridLayout *button_layout = new QGridLayout(5, 3, 0); 00869 00870 name_layout->addWidget(d->m_comboLabel); 00871 name_layout->addWidget(m_toolbarCombo); 00872 // name_layout->addWidget(new_toolbar); 00873 // name_layout->addWidget(del_toolbar); 00874 00875 button_layout->setRowStretch( 0, 10 ); 00876 button_layout->addWidget(m_upAction, 1, 1); 00877 button_layout->addWidget(m_removeAction, 2, 0); 00878 button_layout->addWidget(m_insertAction, 2, 2); 00879 button_layout->addWidget(m_downAction, 3, 1); 00880 button_layout->setRowStretch( 4, 10 ); 00881 00882 inactive_layout->addWidget(inactive_label); 00883 inactive_layout->addWidget(m_inactiveList, 1); 00884 00885 active_layout->addWidget(active_label); 00886 active_layout->addWidget(m_activeList, 1); 00887 active_layout->addLayout(changeIcon_layout); 00888 00889 changeIcon_layout->addStretch( 1 ); 00890 changeIcon_layout->addWidget( d->m_changeIcon ); 00891 changeIcon_layout->addStretch( 1 ); 00892 00893 list_layout->addLayout(inactive_layout); 00894 list_layout->addLayout(button_layout); 00895 list_layout->addLayout(active_layout); 00896 00897 top_layout->addLayout(name_layout); 00898 top_layout->addWidget(d->m_comboSeparator); 00899 top_layout->addLayout(list_layout,10); 00900 top_layout->addWidget(d->m_helpArea); 00901 top_layout->addWidget(new KSeparator(this)); 00902 } 00903 00904 void KEditToolbarWidget::loadToolbarCombo(const QString& defaultToolbar) 00905 { 00906 static const QString &attrName = KGlobal::staticQString( "name" ); 00907 // just in case, we clear our combo 00908 m_toolbarCombo->clear(); 00909 00910 int defaultToolbarId = -1; 00911 int count = 0; 00912 // load in all of the toolbar names into this combo box 00913 XmlDataList::Iterator xit = d->m_xmlFiles.begin(); 00914 for ( ; xit != d->m_xmlFiles.end(); ++xit) 00915 { 00916 // skip the local one in favor of the merged 00917 if ( (*xit).m_type == XmlData::Local ) 00918 continue; 00919 00920 // each xml file may have any number of toolbars 00921 ToolbarList::Iterator it = (*xit).m_barList.begin(); 00922 for ( ; it != (*xit).m_barList.end(); ++it) 00923 { 00924 QString name = d->toolbarName( *xit, *it ); 00925 m_toolbarCombo->setEnabled( true ); 00926 m_toolbarCombo->insertItem( name ); 00927 if (defaultToolbarId == -1 && (name == defaultToolbar || defaultToolbar == (*it).attribute( attrName ))) 00928 defaultToolbarId = count; 00929 count++; 00930 } 00931 } 00932 bool showCombo = (count > 1); 00933 d->m_comboLabel->setShown(showCombo); 00934 d->m_comboSeparator->setShown(showCombo); 00935 m_toolbarCombo->setShown(showCombo); 00936 if (defaultToolbarId == -1) 00937 defaultToolbarId = 0; 00938 // we want to the specified item selected and its actions loaded 00939 m_toolbarCombo->setCurrentItem(defaultToolbarId); 00940 slotToolbarSelected(m_toolbarCombo->currentText()); 00941 } 00942 00943 void KEditToolbarWidget::loadActionList(QDomElement& elem) 00944 { 00945 static const QString &tagSeparator = KGlobal::staticQString( "Separator" ); 00946 static const QString &tagMerge = KGlobal::staticQString( "Merge" ); 00947 static const QString &tagActionList= KGlobal::staticQString( "ActionList" ); 00948 static const QString &attrName = KGlobal::staticQString( "name" ); 00949 static const QString &attrLineSeparator = KGlobal::staticQString( "lineSeparator" ); 00950 00951 int sep_num = 0; 00952 QString sep_name("separator_%1"); 00953 00954 // clear our lists 00955 m_inactiveList->clear(); 00956 m_activeList->clear(); 00957 m_insertAction->setEnabled(false); 00958 m_removeAction->setEnabled(false); 00959 m_upAction->setEnabled(false); 00960 m_downAction->setEnabled(false); 00961 00962 // We'll use this action collection 00963 KActionCollection* actionCollection = d->m_currentXmlData->m_actionCollection; 00964 00965 // store the names of our active actions 00966 QMap<QString, bool> active_list; 00967 00968 // see if our current action is in this toolbar 00969 KIconLoader *loader = KGlobal::instance()->iconLoader(); 00970 QDomNode n = elem.lastChild(); 00971 for( ; !n.isNull(); n = n.previousSibling() ) 00972 { 00973 QDomElement it = n.toElement(); 00974 if (it.isNull()) continue; 00975 if (it.tagName() == tagSeparator) 00976 { 00977 ToolbarItem *act = new ToolbarItem(m_activeList, tagSeparator, sep_name.arg(sep_num++), QString::null); 00978 bool isLineSep = ( it.attribute(attrLineSeparator, "true").lower() == QString::fromLatin1("true") ); 00979 if(isLineSep) 00980 act->setText(1, LINESEPARATORSTRING); 00981 else 00982 act->setText(1, SEPARATORSTRING); 00983 it.setAttribute( attrName, act->internalName() ); 00984 continue; 00985 } 00986 00987 if (it.tagName() == tagMerge) 00988 { 00989 // Merge can be named or not - use the name if there is one 00990 QString name = it.attribute( attrName ); 00991 ToolbarItem *act = new ToolbarItem(m_activeList, tagMerge, name, i18n("This element will be replaced with all the elements of an embedded component.")); 00992 if ( name.isEmpty() ) 00993 act->setText(1, i18n("<Merge>")); 00994 else 00995 act->setText(1, i18n("<Merge %1>").arg(name)); 00996 continue; 00997 } 00998 00999 if (it.tagName() == tagActionList) 01000 { 01001 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 won't be able to re-add it.") ); 01002 act->setText(1, i18n("ActionList: %1").arg(it.attribute(attrName))); 01003 continue; 01004 } 01005 01006 // iterate through this client's actions 01007 // This used to iterate through _all_ actions, but we don't support 01008 // putting any action into any client... 01009 for (unsigned int i = 0; i < actionCollection->count(); i++) 01010 { 01011 KAction *action = actionCollection->action( i ); 01012 01013 // do we have a match? 01014 if (it.attribute( attrName ) == action->name()) 01015 { 01016 // we have a match! 01017 ToolbarItem *act = new ToolbarItem(m_activeList, it.tagName(), action->name(), action->toolTip()); 01018 act->setText(1, action->plainText()); 01019 if (action->hasIcon()) 01020 if (!action->icon().isEmpty()) 01021 act->setPixmap(0, loader->loadIcon(action->icon(), KIcon::Toolbar, 16, KIcon::DefaultState, 0, true) ); 01022 else // Has iconset 01023 act->setPixmap(0, action->iconSet(KIcon::Toolbar).pixmap()); 01024 01025 active_list.insert(action->name(), true); 01026 break; 01027 } 01028 } 01029 } 01030 01031 // go through the rest of the collection 01032 for (int i = actionCollection->count() - 1; i > -1; --i) 01033 { 01034 KAction *action = actionCollection->action( i ); 01035 01036 // skip our active ones 01037 if (active_list.contains(action->name())) 01038 continue; 01039 01040 ToolbarItem *act = new ToolbarItem(m_inactiveList, tagActionList, action->name(), action->toolTip()); 01041 act->setText(1, action->plainText()); 01042 if (action->hasIcon()) 01043 if (!action->icon().isEmpty()) 01044 act->setPixmap(0, loader->loadIcon(action->icon(), KIcon::Toolbar, 16, KIcon::DefaultState, 0, true) ); 01045 else // Has iconset 01046 act->setPixmap(0, action->iconSet(KIcon::Toolbar).pixmap()); 01047 } 01048 01049 // finally, add default separators to the inactive list 01050 ToolbarItem *act = new ToolbarItem(m_inactiveList, tagSeparator, sep_name.arg(sep_num++), QString::null); 01051 act->setText(1, LINESEPARATORSTRING); 01052 act = new ToolbarItem(m_inactiveList, tagSeparator, sep_name.arg(sep_num++), QString::null); 01053 act->setText(1, SEPARATORSTRING); 01054 } 01055 01056 KActionCollection *KEditToolbarWidget::actionCollection() const 01057 { 01058 return d->m_collection; 01059 } 01060 01061 void KEditToolbarWidget::slotToolbarSelected(const QString& _text) 01062 { 01063 // iterate through everything 01064 XmlDataList::Iterator xit = d->m_xmlFiles.begin(); 01065 for ( ; xit != d->m_xmlFiles.end(); ++xit) 01066 { 01067 // each xml file may have any number of toolbars 01068 ToolbarList::Iterator it = (*xit).m_barList.begin(); 01069 for ( ; it != (*xit).m_barList.end(); ++it) 01070 { 01071 QString name = d->toolbarName( *xit, *it ); 01072 // is this our toolbar? 01073 if ( name == _text ) 01074 { 01075 // save our current settings 01076 d->m_currentXmlData = & (*xit); 01077 d->m_currentToolbarElem = (*it); 01078 01079 // load in our values 01080 loadActionList(d->m_currentToolbarElem); 01081 01082 if ((*xit).m_type == XmlData::Part || (*xit).m_type == XmlData::Shell) 01083 setDOMDocument( (*xit).m_document ); 01084 return; 01085 } 01086 } 01087 } 01088 } 01089 01090 void KEditToolbarWidget::slotInactiveSelected(QListViewItem *item) 01091 { 01092 ToolbarItem* toolitem = static_cast<ToolbarItem *>(item); 01093 if (item) 01094 { 01095 m_insertAction->setEnabled(true); 01096 QString statusText = toolitem->statusText(); 01097 d->m_helpArea->setText( statusText ); 01098 } 01099 else 01100 { 01101 m_insertAction->setEnabled(false); 01102 d->m_helpArea->setText( QString::null ); 01103 } 01104 } 01105 01106 void KEditToolbarWidget::slotActiveSelected(QListViewItem *item) 01107 { 01108 ToolbarItem* toolitem = static_cast<ToolbarItem *>(item); 01109 m_removeAction->setEnabled( item ); 01110 01111 static const QString &tagAction = KGlobal::staticQString( "Action" ); 01112 d->m_changeIcon->setEnabled( item && 01113 d->m_hasKDialog && 01114 toolitem->internalTag() == tagAction ); 01115 01116 if (item) 01117 { 01118 if (item->itemAbove()) 01119 m_upAction->setEnabled(true); 01120 else 01121 m_upAction->setEnabled(false); 01122 01123 if (item->itemBelow()) 01124 m_downAction->setEnabled(true); 01125 else 01126 m_downAction->setEnabled(false); 01127 QString statusText = toolitem->statusText(); 01128 d->m_helpArea->setText( statusText ); 01129 } 01130 else 01131 { 01132 m_upAction->setEnabled(false); 01133 m_downAction->setEnabled(false); 01134 d->m_helpArea->setText( QString::null ); 01135 } 01136 } 01137 01138 void KEditToolbarWidget::slotDropped(KListView *list, QDropEvent *e, QListViewItem *after) 01139 { 01140 ToolbarItem *item = new ToolbarItem(m_inactiveList); // needs parent, use inactiveList temporarily 01141 if(!ToolbarItemDrag::decode(e, *item)) { 01142 delete item; 01143 return; 01144 } 01145 01146 if (list == m_activeList) { 01147 if (e->source() == m_activeList) { 01148 // has been dragged within the active list (moved). 01149 moveActive(item, after); 01150 } 01151 else 01152 insertActive(item, after, true); 01153 } else if (list == m_inactiveList) { 01154 // has been dragged to the inactive list -> remove from the active list. 01155 removeActive(item); 01156 } 01157 01158 delete item; item = 0; // not neded anymore 01159 01160 // we're modified, so let this change 01161 emit enableOk(true); 01162 01163 slotToolbarSelected( m_toolbarCombo->currentText() ); 01164 } 01165 01166 void KEditToolbarWidget::slotInsertButton() 01167 { 01168 ToolbarItem *item = (ToolbarItem*)m_inactiveList->currentItem(); 01169 insertActive(item, m_activeList->currentItem(), false); 01170 01171 // we're modified, so let this change 01172 emit enableOk(true); 01173 01174 // TODO: #### this causes #97572. 01175 // It would be better to just "delete item; loadActions( ... , ActiveListOnly );" or something. 01176 slotToolbarSelected( m_toolbarCombo->currentText() ); 01177 } 01178 01179 void KEditToolbarWidget::slotRemoveButton() 01180 { 01181 removeActive( dynamic_cast<ToolbarItem*>(m_activeList->currentItem()) ); 01182 01183 // we're modified, so let this change 01184 emit enableOk(true); 01185 01186 slotToolbarSelected( m_toolbarCombo->currentText() ); 01187 } 01188 01189 void KEditToolbarWidget::insertActive(ToolbarItem *item, QListViewItem *before, bool prepend) 01190 { 01191 if (!item) 01192 return; 01193 01194 static const QString &tagAction = KGlobal::staticQString( "Action" ); 01195 static const QString &tagSeparator = KGlobal::staticQString( "Separator" ); 01196 static const QString &attrName = KGlobal::staticQString( "name" ); 01197 static const QString &attrLineSeparator = KGlobal::staticQString( "lineSeparator" ); 01198 static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" ); 01199 01200 QDomElement new_item; 01201 // let's handle the separator specially 01202 if (item->text(1) == LINESEPARATORSTRING) { 01203 new_item = domDocument().createElement(tagSeparator); 01204 } else if (item->text(1) == SEPARATORSTRING) { 01205 new_item = domDocument().createElement(tagSeparator); 01206 new_item.setAttribute(attrLineSeparator, "false"); 01207 } else 01208 new_item = domDocument().createElement(tagAction); 01209 new_item.setAttribute(attrName, item->internalName()); 01210 01211 if (before) 01212 { 01213 // we have the item in the active list which is before the new 01214 // item.. so let's try our best to add our new item right after it 01215 ToolbarItem *act_item = (ToolbarItem*)before; 01216 QDomElement elem = d->findElementForToolbarItem( act_item ); 01217 Q_ASSERT( !elem.isNull() ); 01218 d->m_currentToolbarElem.insertAfter(new_item, elem); 01219 } 01220 else 01221 { 01222 // simply put it at the beginning or the end of the list. 01223 if (prepend) 01224 d->m_currentToolbarElem.insertBefore(new_item, d->m_currentToolbarElem.firstChild()); 01225 else 01226 d->m_currentToolbarElem.appendChild(new_item); 01227 } 01228 01229 // and set this container as a noMerge 01230 d->m_currentToolbarElem.setAttribute( attrNoMerge, "1"); 01231 01232 // update the local doc 01233 updateLocal(d->m_currentToolbarElem); 01234 } 01235 01236 void KEditToolbarWidget::removeActive(ToolbarItem *item) 01237 { 01238 if (!item) 01239 return; 01240 01241 static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" ); 01242 01243 // we're modified, so let this change 01244 emit enableOk(true); 01245 01246 // now iterate through to find the child to nuke 01247 QDomElement elem = d->findElementForToolbarItem( item ); 01248 if ( !elem.isNull() ) 01249 { 01250 // nuke myself! 01251 d->m_currentToolbarElem.removeChild(elem); 01252 01253 // and set this container as a noMerge 01254 d->m_currentToolbarElem.setAttribute( attrNoMerge, "1"); 01255 01256 // update the local doc 01257 updateLocal(d->m_currentToolbarElem); 01258 } 01259 } 01260 01261 void KEditToolbarWidget::slotUpButton() 01262 { 01263 ToolbarItem *item = (ToolbarItem*)m_activeList->currentItem(); 01264 01265 // make sure we're not the top item already 01266 if (!item->itemAbove()) 01267 return; 01268 01269 // we're modified, so let this change 01270 emit enableOk(true); 01271 01272 moveActive( item, item->itemAbove()->itemAbove() ); 01273 delete item; 01274 } 01275 01276 void KEditToolbarWidget::moveActive( ToolbarItem* item, QListViewItem* before ) 01277 { 01278 QDomElement e = d->findElementForToolbarItem( item ); 01279 01280 if ( e.isNull() ) 01281 return; 01282 01283 // cool, i found me. now clone myself 01284 ToolbarItem *clone = new ToolbarItem(m_activeList, 01285 before, 01286 item->internalTag(), 01287 item->internalName(), 01288 item->statusText()); 01289 01290 clone->setText(1, item->text(1)); 01291 01292 // only set new pixmap if exists 01293 if( item->pixmap(0) ) 01294 clone->setPixmap(0, *item->pixmap(0)); 01295 01296 // select my clone 01297 m_activeList->setSelected(clone, true); 01298 01299 // make clone visible 01300 m_activeList->ensureItemVisible(clone); 01301 01302 // and do the real move in the DOM 01303 if ( !before ) 01304 d->m_currentToolbarElem.insertBefore(e, d->m_currentToolbarElem.firstChild() ); 01305 else 01306 d->m_currentToolbarElem.insertAfter(e, d->findElementForToolbarItem( (ToolbarItem*)before )); 01307 01308 // and set this container as a noMerge 01309 static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" ); 01310 d->m_currentToolbarElem.setAttribute( attrNoMerge, "1"); 01311 01312 // update the local doc 01313 updateLocal(d->m_currentToolbarElem); 01314 } 01315 01316 void KEditToolbarWidget::slotDownButton() 01317 { 01318 ToolbarItem *item = (ToolbarItem*)m_activeList->currentItem(); 01319 01320 // make sure we're not the bottom item already 01321 if (!item->itemBelow()) 01322 return; 01323 01324 // we're modified, so let this change 01325 emit enableOk(true); 01326 01327 moveActive( item, item->itemBelow() ); 01328 delete item; 01329 } 01330 01331 void KEditToolbarWidget::updateLocal(QDomElement& elem) 01332 { 01333 static const QString &attrName = KGlobal::staticQString( "name" ); 01334 01335 XmlDataList::Iterator xit = d->m_xmlFiles.begin(); 01336 for ( ; xit != d->m_xmlFiles.end(); ++xit) 01337 { 01338 if ( (*xit).m_type == XmlData::Merged ) 01339 continue; 01340 01341 if ( (*xit).m_type == XmlData::Shell || 01342 (*xit).m_type == XmlData::Part ) 01343 { 01344 if ( d->m_currentXmlData->m_xmlFile == (*xit).m_xmlFile ) 01345 { 01346 (*xit).m_isModified = true; 01347 return; 01348 } 01349 01350 continue; 01351 } 01352 01353 (*xit).m_isModified = true; 01354 01355 ToolbarList::Iterator it = (*xit).m_barList.begin(); 01356 for ( ; it != (*xit).m_barList.end(); ++it) 01357 { 01358 QString name( (*it).attribute( attrName ) ); 01359 QString tag( (*it).tagName() ); 01360 if ( (tag != elem.tagName()) || (name != elem.attribute(attrName)) ) 01361 continue; 01362 01363 QDomElement toolbar = (*xit).m_document.documentElement().toElement(); 01364 toolbar.replaceChild(elem, (*it)); 01365 return; 01366 } 01367 01368 // just append it 01369 QDomElement toolbar = (*xit).m_document.documentElement().toElement(); 01370 toolbar.appendChild(elem); 01371 } 01372 } 01373 01374 void KEditToolbarWidget::slotChangeIcon() 01375 { 01376 // We can't use KIconChooser here, since it's in libkio 01377 // ##### KDE4: reconsider this, e.g. move KEditToolbar to libkio 01378 01379 //if the process is already running (e.g. when somebody clicked the change button twice (see #127149)) - do nothing... 01380 //otherwise m_kdialogProcess will be overwritten and set to zero in slotProcessExited()...crash! 01381 if ( d->m_kdialogProcess && d->m_kdialogProcess->isRunning() ) 01382 return; 01383 01384 d->m_kdialogProcess = new KProcIO; 01385 QString kdialogExe = KStandardDirs::findExe(QString::fromLatin1("kdialog")); 01386 (*d->m_kdialogProcess) << kdialogExe; 01387 (*d->m_kdialogProcess) << "--embed"; 01388 (*d->m_kdialogProcess) << QString::number( (ulong)topLevelWidget()->winId() ); 01389 (*d->m_kdialogProcess) << "--geticon"; 01390 (*d->m_kdialogProcess) << "Toolbar"; 01391 (*d->m_kdialogProcess) << "Actions"; 01392 if ( !d->m_kdialogProcess->start( KProcess::NotifyOnExit ) ) { 01393 kdError(240) << "Can't run " << kdialogExe << endl; 01394 delete d->m_kdialogProcess; 01395 d->m_kdialogProcess = 0; 01396 return; 01397 } 01398 01399 m_activeList->setEnabled( false ); // don't change the current item 01400 m_toolbarCombo->setEnabled( false ); // don't change the current toolbar 01401 01402 connect( d->m_kdialogProcess, SIGNAL( processExited( KProcess* ) ), 01403 this, SLOT( slotProcessExited( KProcess* ) ) ); 01404 } 01405 01406 void KEditToolbarWidget::slotProcessExited( KProcess* ) 01407 { 01408 m_activeList->setEnabled( true ); 01409 m_toolbarCombo->setEnabled( true ); 01410 01411 QString icon; 01412 01413 if (!d->m_kdialogProcess) { 01414 kdError(240) << "Something is wrong here! m_kdialogProcess is zero!" << endl; 01415 return; 01416 } 01417 01418 if ( !d->m_kdialogProcess->normalExit() || 01419 d->m_kdialogProcess->exitStatus() || 01420 d->m_kdialogProcess->readln(icon, true) <= 0 ) { 01421 delete d->m_kdialogProcess; 01422 d->m_kdialogProcess = 0; 01423 return; 01424 } 01425 01426 ToolbarItem *item = (ToolbarItem*)m_activeList->currentItem(); 01427 if(item){ 01428 item->setPixmap(0, BarIcon(icon, 16)); 01429 01430 Q_ASSERT( d->m_currentXmlData->m_type != XmlData::Merged ); 01431 01432 d->m_currentXmlData->m_isModified = true; 01433 01434 // Get hold of ActionProperties tag 01435 QDomElement elem = KXMLGUIFactory::actionPropertiesElement( d->m_currentXmlData->m_document ); 01436 // Find or create an element for this action 01437 QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ ); 01438 Q_ASSERT( !act_elem.isNull() ); 01439 act_elem.setAttribute( "icon", icon ); 01440 01441 // we're modified, so let this change 01442 emit enableOk(true); 01443 } 01444 01445 delete d->m_kdialogProcess; 01446 d->m_kdialogProcess = 0; 01447 } 01448 01449 void KEditToolbar::virtual_hook( int id, void* data ) 01450 { KDialogBase::virtual_hook( id, data ); } 01451 01452 void KEditToolbarWidget::virtual_hook( int id, void* data ) 01453 { KXMLGUIClient::virtual_hook( id, data ); } 01454 01455 #include "kedittoolbar.moc"