• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • dialogs
kedittoolbar.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
3 Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
4 Copyright 2007 David Faure <faure@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License version 2 as published by the Free Software Foundation.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20#include <kedittoolbar.h>
21#include <kedittoolbar_p.h>
22#include <QShowEvent>
23
24
25#include <QtXml/QDomDocument>
26#include <QtGui/QLayout>
27#include <QtCore/QDir>
28#include <QtCore/QFile>
29#include <QHeaderView>
30#include <QtGui/QToolButton>
31#include <QtGui/QLabel>
32#include <QtGui/QApplication>
33#include <QtGui/QGridLayout>
34#include <QtGui/QCheckBox>
35#include <QMimeData>
36
37#include <kstandarddirs.h>
38#include <klistwidgetsearchline.h>
39#include <klocale.h>
40#include <kicon.h>
41#include <kiconloader.h>
42#include <kcomponentdata.h>
43#include <kmessagebox.h>
44#include <kxmlguifactory.h>
45#include <kseparator.h>
46#include <kconfig.h>
47#include <kdebug.h>
48#include <kpushbutton.h>
49#include <kprocess.h>
50#include <ktoolbar.h>
51#include <kdeversion.h>
52#include <kcombobox.h>
53#include <klineedit.h>
54
55#include "kaction.h"
56#include "kactioncollection.h"
57
58static const char * const separatorstring = I18N_NOOP("--- separator ---");
59
60#define SEPARATORSTRING i18n(separatorstring)
61
62static const char* const s_XmlTypeToString[] = { "Shell", "Part", "Local", "Merged" };
63
64typedef QList<QDomElement> ToolBarList;
65
66namespace KDEPrivate {
67
71static ToolBarList findToolBars(const QDomElement& start)
72{
73 static const QString &tagToolBar = KGlobal::staticQString( "ToolBar" );
74 static const QString &tagMenuBar = KGlobal::staticQString( "MenuBar" );
75 static const QString &attrNoEdit = KGlobal::staticQString( "noEdit" );
76 ToolBarList list;
77
78 for( QDomElement elem = start; !elem.isNull(); elem = elem.nextSiblingElement() ) {
79 if (elem.tagName() == tagToolBar) {
80 if ( elem.attribute( attrNoEdit ) != "true" )
81 list.append(elem);
82 } else {
83 if (elem.tagName() != tagMenuBar) // there are no toolbars inside the menubar :)
84 list += findToolBars(elem.firstChildElement()); // recursive
85 }
86 }
87
88 return list;
89}
90
91class XmlData
92{
93public:
94 enum XmlType { Shell = 0, Part, Local, Merged };
95
96 explicit XmlData( XmlType xmlType, const QString& xmlFile, KActionCollection* collection )
97 : m_isModified(false),
98 m_xmlFile(xmlFile),
99 m_type(xmlType),
100 m_actionCollection(collection)
101 {
102 }
103 void dump() const
104 {
105 kDebug(240) << "XmlData" << this << "type" << s_XmlTypeToString[m_type] << "xmlFile:" << m_xmlFile;
106 foreach (const QDomElement& element, m_barList) {
107 kDebug(240) << " ToolBar:" << toolBarText( element );
108 }
109 if ( m_actionCollection )
110 kDebug(240) << " " << m_actionCollection->actions().count() << "actions in the collection.";
111 else
112 kDebug(240) << " no action collection.";
113 }
114 QString xmlFile() const { return m_xmlFile; }
115 XmlType type() const { return m_type; }
116 KActionCollection* actionCollection() const { return m_actionCollection; }
117 void setDomDocument(const QDomDocument& domDoc)
118 {
119 m_document = domDoc.cloneNode().toDocument();
120 m_barList = findToolBars(m_document.documentElement());
121 }
122 // Return reference, for e.g. actionPropertiesElement() to modify the document
123 QDomDocument& domDocument() { return m_document; }
124 const QDomDocument& domDocument() const { return m_document; }
125
129 QString toolBarText( const QDomElement& it ) const;
130
131
132 bool m_isModified;
133 ToolBarList& barList() { return m_barList; }
134 const ToolBarList& barList() const { return m_barList; }
135
136private:
137 ToolBarList m_barList;
138 QString m_xmlFile;
139 QDomDocument m_document;
140 XmlType m_type;
141 KActionCollection* m_actionCollection;
142};
143
144QString XmlData::toolBarText( const QDomElement& it ) const
145{
146 static const QString &tagText = KGlobal::staticQString( "text" );
147 static const QString &tagText2 = KGlobal::staticQString( "Text" );
148 static const QString &attrName = KGlobal::staticQString( "name" );
149
150 QString name;
151 QByteArray txt( it.namedItem( tagText ).toElement().text().toUtf8() );
152 if ( txt.isEmpty() )
153 txt = it.namedItem( tagText2 ).toElement().text().toUtf8();
154 if ( txt.isEmpty() )
155 name = it.attribute( attrName );
156 else
157 name = i18n( txt );
158
159 // the name of the toolbar might depend on whether or not
160 // it is in kparts
161 if ( ( m_type == XmlData::Shell ) ||
162 ( m_type == XmlData::Part ) ) {
163 QString doc_name(m_document.documentElement().attribute( attrName ));
164 name += " <" + doc_name + '>';
165 }
166 return name;
167}
168
169
170typedef QList<XmlData> XmlDataList;
171
172class ToolBarItem : public QListWidgetItem
173{
174public:
175 ToolBarItem(QListWidget *parent, const QString& tag = QString(), const QString& name = QString(), const QString& statusText = QString())
176 : QListWidgetItem(parent),
177 m_internalTag(tag),
178 m_internalName(name),
179 m_statusText(statusText),
180 m_isSeparator(false),
181 m_isTextAlongsideIconHidden(false)
182 {
183 // Drop between items, not onto items
184 setFlags((flags() | Qt::ItemIsDragEnabled) & ~Qt::ItemIsDropEnabled);
185 }
186
187 void setInternalTag(const QString &tag) { m_internalTag = tag; }
188 void setInternalName(const QString &name) { m_internalName = name; }
189 void setStatusText(const QString &text) { m_statusText = text; }
190 void setSeparator(bool sep) { m_isSeparator = sep; }
191 void setTextAlongsideIconHidden(bool hidden) { m_isTextAlongsideIconHidden = hidden; }
192 QString internalTag() const { return m_internalTag; }
193 QString internalName() const { return m_internalName; }
194 QString statusText() const { return m_statusText; }
195 bool isSeparator() const { return m_isSeparator; }
196 bool isTextAlongsideIconHidden() const { return m_isTextAlongsideIconHidden; }
197
198 int index() const { return listWidget()->row(const_cast<ToolBarItem*>(this)); }
199
200private:
201 QString m_internalTag;
202 QString m_internalName;
203 QString m_statusText;
204 bool m_isSeparator;
205 bool m_isTextAlongsideIconHidden;
206};
207
208static QDataStream & operator<< ( QDataStream & s, const ToolBarItem & item ) {
209 s << item.internalTag();
210 s << item.internalName();
211 s << item.statusText();
212 s << item.isSeparator();
213 s << item.isTextAlongsideIconHidden();
214 return s;
215}
216static QDataStream & operator>> ( QDataStream & s, ToolBarItem & item ) {
217 QString internalTag;
218 s >> internalTag;
219 item.setInternalTag(internalTag);
220 QString internalName;
221 s >> internalName;
222 item.setInternalName(internalName);
223 QString statusText;
224 s >> statusText;
225 item.setStatusText(statusText);
226 bool sep;
227 s >> sep;
228 item.setSeparator(sep);
229 bool hidden;
230 s >> hidden;
231 item.setTextAlongsideIconHidden(hidden);
232 return s;
233}
234
236
237ToolBarListWidget::ToolBarListWidget(QWidget *parent)
238 : QListWidget(parent),
239 m_activeList(true)
240{
241 setDragDropMode(QAbstractItemView::DragDrop); // no internal moves
242}
243
244QMimeData* ToolBarListWidget::mimeData(const QList<QListWidgetItem*> items) const
245{
246 if (items.isEmpty())
247 return 0;
248 QMimeData* mimedata = new QMimeData();
249
250 QByteArray data;
251 {
252 QDataStream stream(&data, QIODevice::WriteOnly);
253 // we only support single selection
254 ToolBarItem* item = static_cast<ToolBarItem *>(items.first());
255 stream << *item;
256 }
257
258 mimedata->setData("application/x-kde-action-list", data);
259 mimedata->setData("application/x-kde-source-treewidget", m_activeList ? "active" : "inactive");
260
261 return mimedata;
262}
263
264bool ToolBarListWidget::dropMimeData(int index, const QMimeData * mimeData, Qt::DropAction action)
265{
266 Q_UNUSED(action)
267 const QByteArray data = mimeData->data("application/x-kde-action-list");
268 if (data.isEmpty())
269 return false;
270 QDataStream stream(data);
271 const bool sourceIsActiveList = mimeData->data("application/x-kde-source-treewidget") == "active";
272 ToolBarItem* item = new ToolBarItem(this); // needs parent, use this temporarily
273 stream >> *item;
274 emit dropped(this, index, item, sourceIsActiveList);
275 return true;
276}
277
278ToolBarItem* ToolBarListWidget::currentItem() const
279{
280 return static_cast<ToolBarItem*>(QListWidget::currentItem());
281}
282
283
284IconTextEditDialog::IconTextEditDialog(QWidget *parent)
285 : KDialog(parent)
286{
287 setCaption(i18n("Change Text"));
288 setButtons(Ok | Cancel);
289 setDefaultButton(Ok);
290 setModal(true);
291
292 QWidget *mainWidget = new QWidget(this);
293 QGridLayout *layout = new QGridLayout(mainWidget);
294 layout->setMargin(0);
295
296 m_lineEdit = new KLineEdit(mainWidget);
297 m_lineEdit->setClearButtonShown(true);
298 QLabel *label = new QLabel(i18n("Icon te&xt:"), this);
299 label->setBuddy(m_lineEdit);
300 layout->addWidget(label, 0, 0);
301 layout->addWidget(m_lineEdit, 0, 1);
302
303 m_cbHidden = new QCheckBox(i18n("&Hide text when toolbar shows text alongside icons"), mainWidget);
304 layout->addWidget(m_cbHidden, 1, 1);
305
306 connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(slotTextChanged(QString)));
307
308 m_lineEdit->setFocus();
309 setMainWidget(mainWidget);
310 setFixedHeight(sizeHint().height());
311}
312
313void IconTextEditDialog::setIconText(const QString &text)
314{
315 m_lineEdit->setText(text);
316}
317
318QString IconTextEditDialog::iconText() const
319{
320 return m_lineEdit->text().trimmed();
321}
322
323void IconTextEditDialog::setTextAlongsideIconHidden(bool hidden)
324{
325 m_cbHidden->setChecked(hidden);
326}
327
328bool IconTextEditDialog::textAlongsideIconHidden() const
329{
330 return m_cbHidden->isChecked();
331}
332
333void IconTextEditDialog::slotTextChanged(const QString &text)
334{
335 // Do not allow empty icon text
336 enableButton(Ok, !text.trimmed().isEmpty());
337}
338
339
340class KEditToolBarWidgetPrivate
341{
342public:
350 KEditToolBarWidgetPrivate(KEditToolBarWidget* widget,
351 const KComponentData &cData, KActionCollection* collection)
352 : m_collection( collection ),
353 m_widget(widget),
354 m_factory(NULL),
355 m_loadedOnce( false )
356 {
357 m_componentData = cData;
358 m_isPart = false;
359 m_helpArea = 0L;
360 m_kdialogProcess = 0;
361 // We want items with an icon to align with items without icon
362 // So we use an empty QPixmap for that
363 const int iconSize = widget->style()->pixelMetric(QStyle::PM_SmallIconSize);
364 m_emptyIcon = QPixmap(iconSize, iconSize);
365 m_emptyIcon.fill(Qt::transparent);
366 }
367 ~KEditToolBarWidgetPrivate()
368 {
369 }
370
371 // private slots
372 void slotToolBarSelected(int index);
373
374 void slotInactiveSelectionChanged();
375 void slotActiveSelectionChanged();
376
377 void slotInsertButton();
378 void slotRemoveButton();
379 void slotUpButton();
380 void slotDownButton();
381
382 void selectActiveItem(const QString&);
383
384 void slotChangeIcon();
385 void slotChangeIconText();
386
387 void slotProcessExited();
388
389 void slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList);
390
391
392 void setupLayout();
393
394 void initOldStyle( const QString& file, bool global, const QString& defaultToolbar );
395 void initFromFactory( KXMLGUIFactory* factory, const QString& defaultToolbar );
396 void loadToolBarCombo( const QString& defaultToolbar );
397 void loadActions(const QDomElement& elem);
398
399 QString xmlFile(const QString& xml_file) const
400 {
401 return xml_file.isEmpty() ? QString(m_componentData.componentName()) + "ui.rc" :
402 xml_file;
403 }
404
408 QString loadXMLFile(const QString& _xml_file)
409 {
410 QString raw_xml;
411 QString xml_file = xmlFile(_xml_file);
412 //kDebug() << "loadXMLFile xml_file=" << xml_file;
413
414 if ( !QDir::isRelativePath(xml_file) )
415 raw_xml = KXMLGUIFactory::readConfigFile(xml_file);
416 else
417 raw_xml = KXMLGUIFactory::readConfigFile(xml_file, m_componentData);
418
419 return raw_xml;
420 }
421
425 QDomElement findElementForToolBarItem( const ToolBarItem* item ) const
426 {
427 static const QString &attrName = KGlobal::staticQString( "name" );
428 //kDebug(240) << "looking for name=" << item->internalName() << "and tag=" << item->internalTag();
429 for(QDomNode n = m_currentToolBarElem.firstChild(); !n.isNull(); n = n.nextSibling())
430 {
431 QDomElement elem = n.toElement();
432 if ((elem.attribute(attrName) == item->internalName()) &&
433 (elem.tagName() == item->internalTag()))
434 return elem;
435 }
436 //kDebug(240) << "no item found in the DOM with name=" << item->internalName() << "and tag=" << item->internalTag();
437 return QDomElement();
438 }
439
440 void insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend = false);
441 void removeActive(ToolBarItem *item);
442 void moveActive(ToolBarItem *item, ToolBarItem *before);
443 void updateLocal(QDomElement& elem);
444
445#ifndef NDEBUG
446 void dump() const
447 {
448 XmlDataList::const_iterator xit = m_xmlFiles.begin();
449 for ( ; xit != m_xmlFiles.end(); ++xit ) {
450 (*xit).dump();
451 }
452 }
453#endif
454
455 KComboBox *m_toolbarCombo;
456
457 QToolButton *m_upAction;
458 QToolButton *m_removeAction;
459 QToolButton *m_insertAction;
460 QToolButton *m_downAction;
461
462 //QValueList<KAction*> m_actionList;
463 KActionCollection* m_collection;
464 KEditToolBarWidget* m_widget;
465 KXMLGUIFactory* m_factory;
466 KComponentData m_componentData;
467
468 QPixmap m_emptyIcon;
469
470 XmlData* m_currentXmlData;
471 QDomElement m_currentToolBarElem;
472
473 QString m_xmlFile;
474 QString m_globalFile;
475 QString m_rcFile;
476 QDomDocument m_localDoc;
477
478 ToolBarList m_barList;
479 ToolBarListWidget *m_inactiveList;
480 ToolBarListWidget *m_activeList;
481
482 XmlDataList m_xmlFiles;
483
484 QLabel *m_comboLabel;
485 KSeparator *m_comboSeparator;
486 QLabel * m_helpArea;
487 KPushButton* m_changeIcon;
488 KPushButton* m_changeIconText;
489 KProcess* m_kdialogProcess;
490 bool m_isPart : 1;
491 bool m_hasKDialog : 1;
492 bool m_loadedOnce : 1;
493};
494
495}
496
497using namespace KDEPrivate;
498
499
500class KEditToolBarPrivate {
501public:
502 KEditToolBarPrivate(KEditToolBar *q): q(q),
503 m_accept(false), m_global(false),
504 m_collection(0), m_factory(0), m_widget(0) {}
505
506 void init();
507
508 void _k_slotOk();
509 void _k_slotApply();
510 void _k_acceptOK(bool);
511 void _k_slotDefault();
512
513 KEditToolBar *q;
514 bool m_accept;
515 // Save parameters for recreating widget after resetting toolbar
516 bool m_global;
517 KActionCollection* m_collection;
518 QString m_file;
519 QString m_defaultToolBar;
520 KXMLGUIFactory* m_factory;
521 KEditToolBarWidget *m_widget;
522};
523
524K_GLOBAL_STATIC(QString, s_defaultToolBarName)
525
526KEditToolBar::KEditToolBar( KActionCollection *collection,
527 QWidget* parent )
528 : KDialog(parent),
529 d(new KEditToolBarPrivate(this))
530{
531 d->m_widget = new KEditToolBarWidget( collection, this);
532 d->init();
533 d->m_collection = collection;
534}
535
536KEditToolBar::KEditToolBar( KXMLGUIFactory* factory,
537 QWidget* parent )
538 : KDialog(parent),
539 d(new KEditToolBarPrivate(this))
540{
541 d->m_widget = new KEditToolBarWidget( this);
542 d->init();
543 d->m_factory = factory;
544}
545
546void KEditToolBarPrivate::init()
547{
548 m_accept = false;
549 m_factory = 0;
550
551 q->setDefaultToolBar( QString() );
552
553 q->setCaption(i18n("Configure Toolbars"));
554 q->setButtons(KDialog::Default|KDialog::Ok|KDialog::Apply|KDialog::Cancel);
555 q->setDefaultButton(KDialog::Ok);
556
557 q->setModal(false);
558
559 q->setMainWidget(m_widget);
560
561 q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
562 q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
563 q->enableButtonApply(false);
564
565 q->connect(q, SIGNAL(okClicked()), SLOT(_k_slotOk()));
566 q->connect(q, SIGNAL(applyClicked()), SLOT(_k_slotApply()));
567 q->connect(q, SIGNAL(defaultClicked()), SLOT(_k_slotDefault()));
568
569 q->setMinimumSize(q->sizeHint());
570}
571
572void KEditToolBar::setResourceFile( const QString& file, bool global )
573{
574 d->m_file = file;
575 d->m_global = global;
576 d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
577}
578
579KEditToolBar::~KEditToolBar()
580{
581 delete d;
582 s_defaultToolBarName->clear();
583}
584
585void KEditToolBar::setDefaultToolBar( const QString& toolBarName )
586{
587 if ( toolBarName.isEmpty() ) {
588 d->m_defaultToolBar = *s_defaultToolBarName;
589 } else {
590 d->m_defaultToolBar = toolBarName;
591 }
592}
593
594void KEditToolBarPrivate::_k_acceptOK(bool b)
595{
596 q->enableButtonOk(b);
597 m_accept = b;
598}
599
600void KEditToolBarPrivate::_k_slotDefault()
601{
602 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 )
603 return;
604
605 KEditToolBarWidget * oldWidget = m_widget;
606 m_widget = 0;
607 m_accept = false;
608
609 if ( m_factory )
610 {
611 foreach (KXMLGUIClient* client, m_factory->clients())
612 {
613 const QString file = client->localXMLFile();
614 if (file.isEmpty())
615 continue;
616 kDebug(240) << "Deleting local xml file" << file;
617 // << "for client" << client << typeid(*client).name();
618 if ( QFile::exists( file ) )
619 if ( !QFile::remove( file ) )
620 kWarning() << "Could not delete" << file;
621 }
622
623 // Reload the xml files in all clients, now that the local files are gone
624 oldWidget->rebuildKXMLGUIClients();
625
626 m_widget = new KEditToolBarWidget( q );
627 m_widget->load( m_factory, m_defaultToolBar );
628 }
629 else
630 {
631 int slash = m_file.lastIndexOf('/')+1;
632 if (slash)
633 m_file = m_file.mid(slash);
634 QString xml_file = KStandardDirs::locateLocal("data", KGlobal::mainComponent().componentName() + '/' + m_file);
635
636 if ( QFile::exists( xml_file ) )
637 if ( !QFile::remove( xml_file ) )
638 kWarning() << "Could not delete " << xml_file;
639
640 m_widget = new KEditToolBarWidget( m_collection, q );
641 q->setResourceFile( m_file, m_global );
642 }
643
644 // Copy the geometry to minimize UI flicker
645 m_widget->setGeometry( oldWidget->geometry() );
646 q->setMainWidget(m_widget);
647 delete oldWidget;
648
649 q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
650 q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
651
652 q->enableButtonApply(false);
653
654 emit q->newToolBarConfig();
655 emit q->newToolbarConfig(); // compat
656}
657
658void KEditToolBarPrivate::_k_slotOk()
659{
660 if (!m_accept) {
661 q->reject();
662 return;
663 }
664
665 if (!m_widget->save())
666 {
667 // some error box here is needed
668 }
669 else
670 {
671 // Do not emit the "newToolBarConfig" signal again here if the "Apply"
672 // button was already pressed and no further changes were made.
673 if (q->isButtonEnabled(KDialog::Apply)) {
674 emit q->newToolBarConfig();
675 emit q->newToolbarConfig(); // compat
676 }
677 q->accept();
678 }
679}
680
681void KEditToolBarPrivate::_k_slotApply()
682{
683 (void)m_widget->save();
684 q->enableButtonApply(false);
685 emit q->newToolBarConfig();
686 emit q->newToolbarConfig(); // compat
687}
688
689void KEditToolBar::setGlobalDefaultToolBar(const char *toolbarName)
690{
691 *s_defaultToolBarName = QString::fromLatin1(toolbarName);
692}
693
694KEditToolBarWidget::KEditToolBarWidget( KActionCollection *collection,
695 QWidget *parent )
696 : QWidget(parent),
697 d(new KEditToolBarWidgetPrivate(this, componentData(), collection))
698{
699 d->setupLayout();
700}
701
702KEditToolBarWidget::KEditToolBarWidget( QWidget *parent )
703 : QWidget(parent),
704 d(new KEditToolBarWidgetPrivate(this, componentData(), KXMLGUIClient::actionCollection() /*create new one*/))
705{
706 d->setupLayout();
707}
708
709KEditToolBarWidget::~KEditToolBarWidget()
710{
711 delete d;
712}
713
714void KEditToolBarWidget::load( const QString& file, bool global, const QString& defaultToolBar )
715{
716 d->initOldStyle( file, global, defaultToolBar );
717}
718
719void KEditToolBarWidget::load( KXMLGUIFactory* factory, const QString& defaultToolBar )
720{
721 d->initFromFactory( factory, defaultToolBar );
722}
723
724void KEditToolBarWidgetPrivate::initOldStyle( const QString& resourceFile,
725 bool global,
726 const QString& defaultToolBar )
727{
728 //TODO: make sure we can call this multiple times?
729 if ( m_loadedOnce ) {
730 return;
731 }
732
733 m_loadedOnce = true;
734 //d->m_actionList = collection->actions();
735
736 // handle the merging
737 if (global)
738 m_widget->loadStandardsXmlFile(); // ui_standards.rc
739 const QString localXML = loadXMLFile( resourceFile );
740 m_widget->setXML(localXML, global ? true /*merge*/ : false);
741
742 // first, get all of the necessary info for our local xml
743 XmlData local(XmlData::Local, xmlFile(resourceFile), m_collection);
744 QDomDocument domDoc;
745 domDoc.setContent(localXML);
746 local.setDomDocument(domDoc);
747 m_xmlFiles.append(local);
748
749 // then, the merged one (ui_standards + local xml)
750 XmlData merge(XmlData::Merged, QString(), m_collection);
751 merge.setDomDocument(m_widget->domDocument());
752 m_xmlFiles.append(merge);
753
754#ifndef NDEBUG
755 dump();
756#endif
757
758 // now load in our toolbar combo box
759 loadToolBarCombo( defaultToolBar );
760 m_widget->adjustSize();
761 m_widget->setMinimumSize( m_widget->sizeHint() );
762}
763
764void KEditToolBarWidgetPrivate::initFromFactory(KXMLGUIFactory* factory,
765 const QString& defaultToolBar)
766{
767 //TODO: make sure we can call this multiple times?
768 if ( m_loadedOnce ) {
769 return;
770 }
771
772 m_loadedOnce = true;
773
774 m_factory = factory;
775
776 // add all of the client data
777 bool first = true;
778 foreach (KXMLGUIClient* client, factory->clients())
779 {
780 if (client->xmlFile().isEmpty())
781 continue;
782
783 XmlData::XmlType type = XmlData::Part;
784 if ( first ) {
785 type = XmlData::Shell;
786 first = false;
787 Q_ASSERT(!client->localXMLFile().isEmpty()); // where would we save changes??
788 }
789
790 XmlData data(type, client->localXMLFile(), client->actionCollection());
791 QDomDocument domDoc = client->domDocument();
792 data.setDomDocument(domDoc);
793 m_xmlFiles.append(data);
794
795 //d->m_actionList += client->actionCollection()->actions();
796 }
797
798#ifndef NDEBUG
799 //d->dump();
800#endif
801
802 // now load in our toolbar combo box
803 loadToolBarCombo( defaultToolBar );
804 m_widget->adjustSize();
805 m_widget->setMinimumSize( m_widget->sizeHint() );
806
807 m_widget->actionCollection()->addAssociatedWidget( m_widget );
808 foreach (QAction* action, m_widget->actionCollection()->actions())
809 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
810}
811
812bool KEditToolBarWidget::save()
813{
814 //kDebug(240) << "KEditToolBarWidget::save";
815 XmlDataList::Iterator it = d->m_xmlFiles.begin();
816 for ( ; it != d->m_xmlFiles.end(); ++it)
817 {
818 // let's not save non-modified files
819 if ( !((*it).m_isModified) )
820 continue;
821
822 // let's also skip (non-existent) merged files
823 if ( (*it).type() == XmlData::Merged )
824 continue;
825
826 // Add noMerge="1" to all the menus since we are saving the merged data
827 QDomNodeList menuNodes = (*it).domDocument().elementsByTagName( "Menu" );
828 for (uint i = 0; i < menuNodes.length(); ++i)
829 {
830 QDomNode menuNode = menuNodes.item(i);
831 QDomElement menuElement = menuNode.toElement();
832 if (menuElement.isNull()) continue;
833 menuElement.setAttribute( "noMerge", "1" );
834 }
835
836 kDebug() << (*it).domDocument().toString();
837
838 kDebug(240) << "Saving " << (*it).xmlFile();
839 // if we got this far, we might as well just save it
840 KXMLGUIFactory::saveConfigFile((*it).domDocument(), (*it).xmlFile());
841 }
842
843 if (!d->m_factory)
844 return true;
845
846 rebuildKXMLGUIClients();
847
848 return true;
849}
850
851void KEditToolBarWidget::rebuildKXMLGUIClients()
852{
853 if (!d->m_factory)
854 return;
855
856 const QList<KXMLGUIClient*> clients = d->m_factory->clients();
857 //kDebug(240) << "factory: " << clients.count() << " clients";
858
859 // remove the elements starting from the last going to the first
860 if (!clients.count())
861 return;
862
863 QListIterator<KXMLGUIClient*> clientIterator = clients;
864 clientIterator.toBack();
865 while (clientIterator.hasPrevious()) {
866 KXMLGUIClient* client = clientIterator.previous();
867 //kDebug(240) << "factory->removeClient " << client;
868 d->m_factory->removeClient(client);
869 }
870
871 KXMLGUIClient *firstClient = clients.first();
872
873 // now, rebuild the gui from the first to the last
874 //kDebug(240) << "rebuilding the gui";
875 foreach (KXMLGUIClient* client, clients)
876 {
877 //kDebug(240) << "updating client " << client << " " << client->componentData().componentName() << " xmlFile=" << client->xmlFile();
878 QString file( client->xmlFile() ); // before setting ui_standards!
879 if ( !file.isEmpty() )
880 {
881 // passing an empty stream forces the clients to reread the XML
882 client->setXMLGUIBuildDocument( QDomDocument() );
883
884 // for the shell, merge in ui_standards.rc
885 if ( client == firstClient ) // same assumption as in the ctor: first==shell
886 client->loadStandardsXmlFile();
887
888 // and this forces it to use the *new* XML file
889 client->setXMLFile( file, client == firstClient /* merge if shell */ );
890
891 // [we can't use reloadXML, it doesn't load ui_standards.rc]
892 }
893 }
894
895 // Now we can add the clients to the factory
896 // We don't do it in the loop above because adding a part automatically
897 // adds its plugins, so we must make sure the plugins were updated first.
898 foreach(KXMLGUIClient* client, clients) {
899 d->m_factory->addClient(client);
900 }
901}
902
903void KEditToolBarWidgetPrivate::setupLayout()
904{
905 // the toolbar name combo
906 m_comboLabel = new QLabel(i18n("&Toolbar:"), m_widget);
907 m_toolbarCombo = new KComboBox(m_widget);
908 m_comboLabel->setBuddy(m_toolbarCombo);
909 m_comboSeparator = new KSeparator(m_widget);
910 QObject::connect(m_toolbarCombo, SIGNAL(activated(int)),
911 m_widget, SLOT(slotToolBarSelected(int)));
912
913// QPushButton *new_toolbar = new QPushButton(i18n("&New"), this);
914// new_toolbar->setPixmap(BarIcon("document-new", KIconLoader::SizeSmall));
915// new_toolbar->setEnabled(false); // disabled until implemented
916// QPushButton *del_toolbar = new QPushButton(i18n("&Delete"), this);
917// del_toolbar->setPixmap(BarIcon("edit-delete", KIconLoader::SizeSmall));
918// del_toolbar->setEnabled(false); // disabled until implemented
919
920 // our list of inactive actions
921 QLabel *inactive_label = new QLabel(i18n("A&vailable actions:"), m_widget);
922 m_inactiveList = new ToolBarListWidget(m_widget);
923 m_inactiveList->setDragEnabled(true);
924 m_inactiveList->setActiveList(false);
925 m_inactiveList->setMinimumSize(180, 250);
926 m_inactiveList->setDropIndicatorShown(false); // #165663
927 inactive_label->setBuddy(m_inactiveList);
928 QObject::connect(m_inactiveList, SIGNAL(itemSelectionChanged()),
929 m_widget, SLOT(slotInactiveSelectionChanged()));
930 QObject::connect(m_inactiveList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
931 m_widget, SLOT(slotInsertButton()));
932 QObject::connect(m_inactiveList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
933 m_widget, SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
934
935 KListWidgetSearchLine *inactiveListSearchLine = new KListWidgetSearchLine(m_widget, m_inactiveList);
936 inactiveListSearchLine->setClickMessage(i18n("Filter"));
937
938 // our list of active actions
939 QLabel *active_label = new QLabel(i18n("Curr&ent actions:"), m_widget);
940 m_activeList = new ToolBarListWidget(m_widget);
941 m_activeList->setDragEnabled(true);
942 m_activeList->setActiveList(true);
943 // With Qt-4.1 only setting MiniumWidth results in a 0-width icon column ...
944 m_activeList->setMinimumSize(m_inactiveList->minimumWidth(), 100);
945 active_label->setBuddy(m_activeList);
946
947 QObject::connect(m_activeList, SIGNAL(itemSelectionChanged()),
948 m_widget, SLOT(slotActiveSelectionChanged()));
949 QObject::connect(m_activeList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
950 m_widget, SLOT(slotRemoveButton()));
951 QObject::connect(m_activeList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
952 m_widget, SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
953
954 KListWidgetSearchLine *activeListSearchLine = new KListWidgetSearchLine(m_widget, m_activeList);
955 activeListSearchLine->setClickMessage(i18n("Filter"));
956
957 // "change icon" button
958 m_changeIcon = new KPushButton(i18n( "Change &Icon..." ), m_widget);
959 m_changeIcon->setIcon(KIcon("preferences-desktop-icons"));
960 QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
961 m_hasKDialog = !kdialogExe.isEmpty();
962 m_changeIcon->setEnabled(m_hasKDialog && m_activeList->currentItem());
963
964 QObject::connect( m_changeIcon, SIGNAL(clicked()),
965 m_widget, SLOT(slotChangeIcon()) );
966
967 // "change icon text" button
968 m_changeIconText = new KPushButton(i18n( "Change Te&xt..." ), m_widget);
969 m_changeIconText->setIcon(KIcon("edit-rename"));
970 m_changeIconText->setEnabled(m_activeList->currentItem() != 0);
971
972 QObject::connect( m_changeIconText, SIGNAL(clicked()),
973 m_widget, SLOT(slotChangeIconText()) );
974
975 // The buttons in the middle
976
977 m_upAction = new QToolButton(m_widget);
978 m_upAction->setIcon( KIcon("go-up") );
979 m_upAction->setEnabled(false);
980 m_upAction->setAutoRepeat(true);
981 QObject::connect(m_upAction, SIGNAL(clicked()), m_widget, SLOT(slotUpButton()));
982
983 m_insertAction = new QToolButton(m_widget);
984 m_insertAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-previous" : "go-next") );
985 m_insertAction->setEnabled(false);
986 QObject::connect(m_insertAction, SIGNAL(clicked()), m_widget, SLOT(slotInsertButton()));
987
988 m_removeAction = new QToolButton(m_widget);
989 m_removeAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-next" : "go-previous") );
990 m_removeAction->setEnabled(false);
991 QObject::connect(m_removeAction, SIGNAL(clicked()), m_widget, SLOT(slotRemoveButton()));
992
993 m_downAction = new QToolButton(m_widget);
994 m_downAction->setIcon( KIcon("go-down") );
995 m_downAction->setEnabled(false);
996 m_downAction->setAutoRepeat(true);
997 QObject::connect(m_downAction, SIGNAL(clicked()), m_widget, SLOT(slotDownButton()));
998
999 m_helpArea = new QLabel(m_widget);
1000 m_helpArea->setWordWrap(true);
1001
1002 // now start with our layouts
1003 QVBoxLayout *top_layout = new QVBoxLayout(m_widget);
1004 top_layout->setMargin(0);
1005
1006 QVBoxLayout *name_layout = new QVBoxLayout();
1007 QHBoxLayout *list_layout = new QHBoxLayout();
1008
1009 QVBoxLayout *inactive_layout = new QVBoxLayout();
1010 QVBoxLayout *active_layout = new QVBoxLayout();
1011 QHBoxLayout *changeIcon_layout = new QHBoxLayout();
1012
1013 QGridLayout *button_layout = new QGridLayout();
1014
1015 name_layout->addWidget(m_comboLabel);
1016 name_layout->addWidget(m_toolbarCombo);
1017// name_layout->addWidget(new_toolbar);
1018// name_layout->addWidget(del_toolbar);
1019
1020 button_layout->setSpacing( 0 );
1021 button_layout->setRowStretch( 0, 10 );
1022 button_layout->addWidget(m_upAction, 1, 1);
1023 button_layout->addWidget(m_removeAction, 2, 0);
1024 button_layout->addWidget(m_insertAction, 2, 2);
1025 button_layout->addWidget(m_downAction, 3, 1);
1026 button_layout->setRowStretch( 4, 10 );
1027
1028 inactive_layout->addWidget(inactive_label);
1029 inactive_layout->addWidget(inactiveListSearchLine);
1030 inactive_layout->addWidget(m_inactiveList, 1);
1031
1032 active_layout->addWidget(active_label);
1033 active_layout->addWidget(activeListSearchLine);
1034 active_layout->addWidget(m_activeList, 1);
1035 active_layout->addLayout(changeIcon_layout);
1036
1037 changeIcon_layout->addWidget(m_changeIcon);
1038 changeIcon_layout->addStretch( 1 );
1039 changeIcon_layout->addWidget(m_changeIconText);
1040
1041 list_layout->addLayout(inactive_layout);
1042 list_layout->addLayout(button_layout);
1043 list_layout->addLayout(active_layout);
1044
1045 top_layout->addLayout(name_layout);
1046 top_layout->addWidget(m_comboSeparator);
1047 top_layout->addLayout(list_layout,10);
1048 top_layout->addWidget(m_helpArea);
1049 top_layout->addWidget(new KSeparator(m_widget));
1050}
1051
1052void KEditToolBarWidgetPrivate::loadToolBarCombo( const QString& defaultToolBar )
1053{
1054 const QLatin1String attrName( "name" );
1055 // just in case, we clear our combo
1056 m_toolbarCombo->clear();
1057
1058 int defaultToolBarId = -1;
1059 int count = 0;
1060 // load in all of the toolbar names into this combo box
1061 XmlDataList::const_iterator xit = m_xmlFiles.constBegin();
1062 for ( ; xit != m_xmlFiles.constEnd(); ++xit)
1063 {
1064 // skip the merged one in favor of the local one,
1065 // so that we can change icons
1066 // This also makes the app-defined named for "mainToolBar" appear rather than the ui_standards-defined name.
1067 if ( (*xit).type() == XmlData::Merged )
1068 continue;
1069
1070 // each xml file may have any number of toolbars
1071 ToolBarList::const_iterator it = (*xit).barList().begin();
1072 for ( ; it != (*xit).barList().constEnd(); ++it)
1073 {
1074 const QString text = (*xit).toolBarText( *it );
1075 m_toolbarCombo->addItem( text );
1076 const QString name = (*it).attribute(attrName);
1077 if (defaultToolBarId == -1 && name == defaultToolBar)
1078 defaultToolBarId = count;
1079 count++;
1080 }
1081 }
1082 const bool showCombo = (count > 1);
1083 m_comboLabel->setVisible(showCombo);
1084 m_comboSeparator->setVisible(showCombo);
1085 m_toolbarCombo->setVisible(showCombo);
1086 if (defaultToolBarId == -1)
1087 defaultToolBarId = 0;
1088 // we want to the specified item selected and its actions loaded
1089 m_toolbarCombo->setCurrentIndex(defaultToolBarId);
1090 slotToolBarSelected(m_toolbarCombo->currentIndex());
1091}
1092
1093void KEditToolBarWidgetPrivate::loadActions(const QDomElement& elem)
1094{
1095 const QLatin1String tagSeparator( "Separator" );
1096 const QLatin1String tagMerge( "Merge" );
1097 const QLatin1String tagActionList( "ActionList" );
1098 const QLatin1String tagAction( "Action" );
1099 const QLatin1String attrName( "name" );
1100
1101 int sep_num = 0;
1102 QString sep_name("separator_%1");
1103
1104 // clear our lists
1105 m_inactiveList->clear();
1106 m_activeList->clear();
1107 m_insertAction->setEnabled(false);
1108 m_removeAction->setEnabled(false);
1109 m_upAction->setEnabled(false);
1110 m_downAction->setEnabled(false);
1111
1112 // We'll use this action collection
1113 KActionCollection* actionCollection = m_currentXmlData->actionCollection();
1114
1115 // store the names of our active actions
1116 QSet<QString> active_list;
1117
1118 // Filtering message requested by translators (scripting).
1119 KLocalizedString nameFilter = ki18nc("@item:intable Action name in toolbar editor", "%1");
1120
1121 // see if our current action is in this toolbar
1122 QDomNode n = elem.firstChild();
1123 for( ; !n.isNull(); n = n.nextSibling() )
1124 {
1125 QDomElement it = n.toElement();
1126 if (it.isNull()) continue;
1127 if (it.tagName() == tagSeparator)
1128 {
1129 ToolBarItem *act = new ToolBarItem(m_activeList, tagSeparator, sep_name.arg(sep_num++), QString());
1130 act->setSeparator(true);
1131 act->setText(SEPARATORSTRING);
1132 it.setAttribute( attrName, act->internalName() );
1133 continue;
1134 }
1135
1136 if (it.tagName() == tagMerge)
1137 {
1138 // Merge can be named or not - use the name if there is one
1139 QString name = it.attribute( attrName );
1140 ToolBarItem *act = new ToolBarItem(m_activeList, tagMerge, name, i18n("This element will be replaced with all the elements of an embedded component."));
1141 if ( name.isEmpty() )
1142 act->setText(i18n("<Merge>"));
1143 else
1144 act->setText(i18n("<Merge %1>", name));
1145 continue;
1146 }
1147
1148 if (it.tagName() == tagActionList)
1149 {
1150 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.") );
1151 act->setText(i18n("ActionList: %1", it.attribute(attrName)));
1152 continue;
1153 }
1154
1155 // iterate through this client's actions
1156 // This used to iterate through _all_ actions, but we don't support
1157 // putting any action into any client...
1158 foreach (QAction* action, actionCollection->actions())
1159 {
1160 // do we have a match?
1161 if (it.attribute( attrName ) == action->objectName())
1162 {
1163 // we have a match!
1164 ToolBarItem *act = new ToolBarItem(m_activeList, it.tagName(), action->objectName(), action->toolTip());
1165 act->setText(nameFilter.subs(KGlobal::locale()->removeAcceleratorMarker(action->iconText())).toString());
1166 act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
1167 act->setTextAlongsideIconHidden(action->priority() < QAction::NormalPriority);
1168
1169 active_list.insert(action->objectName());
1170 break;
1171 }
1172 }
1173 }
1174
1175 // go through the rest of the collection
1176 foreach (QAction* action, actionCollection->actions())
1177 {
1178 // skip our active ones
1179 if (active_list.contains(action->objectName()))
1180 continue;
1181
1182 ToolBarItem *act = new ToolBarItem(m_inactiveList, tagAction, action->objectName(), action->toolTip());
1183 act->setText(nameFilter.subs(KGlobal::locale()->removeAcceleratorMarker(action->text())).toString());
1184 act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
1185 }
1186
1187 m_inactiveList->sortItems(Qt::AscendingOrder);
1188
1189 // finally, add default separators to the inactive list
1190 ToolBarItem *act = new ToolBarItem(0L, tagSeparator, sep_name.arg(sep_num++), QString());
1191 act->setSeparator(true);
1192 act->setText(SEPARATORSTRING);
1193 m_inactiveList->insertItem(0, act);
1194}
1195
1196KActionCollection *KEditToolBarWidget::actionCollection() const
1197{
1198 return d->m_collection;
1199}
1200
1201void KEditToolBarWidgetPrivate::slotToolBarSelected(int index)
1202{
1203 const QLatin1String attrName( "name" );
1204 // We need to find the XmlData and toolbar element for this index
1205 // To do that, we do the same iteration as the one which filled in the combobox.
1206
1207 int toolbarNumber = 0;
1208 XmlDataList::iterator xit = m_xmlFiles.begin();
1209 for ( ; xit != m_xmlFiles.end(); ++xit) {
1210
1211 // skip the merged one in favor of the local one,
1212 // so that we can change icons
1213 if ( (*xit).type() == XmlData::Merged )
1214 continue;
1215
1216 // each xml file may have any number of toolbars
1217 ToolBarList::Iterator it = (*xit).barList().begin();
1218 for ( ; it != (*xit).barList().end(); ++it) {
1219
1220 // is this our toolbar?
1221 if (toolbarNumber == index) {
1222
1223 // save our current settings
1224 m_currentXmlData = & (*xit);
1225 m_currentToolBarElem = *it;
1226
1227 kDebug() << "found toolbar" << m_currentXmlData->toolBarText(*it) << "m_currentXmlData set to";
1228 m_currentXmlData->dump();
1229
1230 // If this is a Merged xmldata, clicking the "change icon" button would assert...
1231 Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
1232
1233 // load in our values
1234 loadActions(m_currentToolBarElem);
1235
1236 if ((*xit).type() == XmlData::Part || (*xit).type() == XmlData::Shell)
1237 m_widget->setDOMDocument( (*xit).domDocument() );
1238 return;
1239 }
1240 ++toolbarNumber;
1241
1242 }
1243 }
1244}
1245
1246void KEditToolBarWidgetPrivate::slotInactiveSelectionChanged()
1247{
1248 if (m_inactiveList->selectedItems().count())
1249 {
1250 m_insertAction->setEnabled(true);
1251 QString statusText = static_cast<ToolBarItem*>(m_inactiveList->selectedItems().first())->statusText();
1252 m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
1253 }
1254 else
1255 {
1256 m_insertAction->setEnabled(false);
1257 m_helpArea->setText( QString() );
1258 }
1259}
1260
1261void KEditToolBarWidgetPrivate::slotActiveSelectionChanged()
1262{
1263 ToolBarItem* toolitem = 0;
1264 if (!m_activeList->selectedItems().isEmpty())
1265 toolitem = static_cast<ToolBarItem *>(m_activeList->selectedItems().first());
1266
1267 m_removeAction->setEnabled( toolitem );
1268
1269 m_changeIcon->setEnabled( toolitem &&
1270 m_hasKDialog &&
1271 toolitem->internalTag() == "Action" );
1272
1273 m_changeIconText->setEnabled( toolitem &&
1274 toolitem->internalTag() == "Action" );
1275
1276 if (toolitem)
1277 {
1278 m_upAction->setEnabled(toolitem->index() != 0);
1279 m_downAction->setEnabled(toolitem->index() != toolitem->listWidget()->count() - 1);
1280
1281 QString statusText = toolitem->statusText();
1282 m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
1283 }
1284 else
1285 {
1286 m_upAction->setEnabled(false);
1287 m_downAction->setEnabled(false);
1288 m_helpArea->setText( QString() );
1289 }
1290}
1291
1292void KEditToolBarWidgetPrivate::slotInsertButton()
1293{
1294 QString internalName = static_cast<ToolBarItem *>(m_inactiveList->currentItem())->internalName();
1295
1296 insertActive(m_inactiveList->currentItem(), m_activeList->currentItem(), false);
1297 // we're modified, so let this change
1298 emit m_widget->enableOk(true);
1299
1300 slotToolBarSelected( m_toolbarCombo->currentIndex() );
1301
1302 selectActiveItem( internalName );
1303}
1304
1305void KEditToolBarWidgetPrivate::selectActiveItem(const QString& internalName)
1306{
1307 int activeItemCount = m_activeList->count();
1308 for(int i = 0; i < activeItemCount; i++)
1309 {
1310 ToolBarItem * item = static_cast<ToolBarItem *>(m_activeList->item(i));
1311 if (item->internalName()==internalName)
1312 {
1313 m_activeList->setCurrentItem(item);
1314 break;
1315 }
1316 }
1317}
1318
1319void KEditToolBarWidgetPrivate::slotRemoveButton()
1320{
1321 removeActive( m_activeList->currentItem() );
1322
1323 slotToolBarSelected( m_toolbarCombo->currentIndex() );
1324}
1325
1326void KEditToolBarWidgetPrivate::insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend)
1327{
1328 if (!item)
1329 return;
1330
1331 static const QString &tagAction = KGlobal::staticQString( "Action" );
1332 static const QString &tagSeparator = KGlobal::staticQString( "Separator" );
1333 static const QString &attrName = KGlobal::staticQString( "name" );
1334 static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
1335
1336 QDomElement new_item;
1337 // let's handle the separator specially
1338 if (item->isSeparator())
1339 new_item = m_widget->domDocument().createElement(tagSeparator);
1340 else
1341 new_item = m_widget->domDocument().createElement(tagAction);
1342
1343 new_item.setAttribute(attrName, item->internalName());
1344
1345 Q_ASSERT(!m_currentToolBarElem.isNull());
1346
1347 if (before)
1348 {
1349 // we have the item in the active list which is before the new
1350 // item.. so let's try our best to add our new item right after it
1351 QDomElement elem = findElementForToolBarItem( before );
1352 Q_ASSERT( !elem.isNull() );
1353 m_currentToolBarElem.insertAfter(new_item, elem);
1354 }
1355 else
1356 {
1357 // simply put it at the beginning or the end of the list.
1358 if (prepend)
1359 m_currentToolBarElem.insertBefore(new_item, m_currentToolBarElem.firstChild());
1360 else
1361 m_currentToolBarElem.appendChild(new_item);
1362 }
1363
1364 // and set this container as a noMerge
1365 m_currentToolBarElem.setAttribute( attrNoMerge, "1");
1366
1367 // update the local doc
1368 updateLocal(m_currentToolBarElem);
1369}
1370
1371void KEditToolBarWidgetPrivate::removeActive(ToolBarItem *item)
1372{
1373 if (!item)
1374 return;
1375
1376 static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
1377
1378 // we're modified, so let this change
1379 emit m_widget->enableOk(true);
1380
1381 // now iterate through to find the child to nuke
1382 QDomElement elem = findElementForToolBarItem( item );
1383 if ( !elem.isNull() )
1384 {
1385 // nuke myself!
1386 m_currentToolBarElem.removeChild(elem);
1387
1388 // and set this container as a noMerge
1389 m_currentToolBarElem.setAttribute( attrNoMerge, "1");
1390
1391 // update the local doc
1392 updateLocal(m_currentToolBarElem);
1393 }
1394}
1395
1396void KEditToolBarWidgetPrivate::slotUpButton()
1397{
1398 ToolBarItem *item = m_activeList->currentItem();
1399
1400 if (!item) {
1401 Q_ASSERT(false);
1402 return;
1403 }
1404
1405 int row = item->listWidget()->row(item) - 1;
1406 // make sure we're not the top item already
1407 if (row < 0) {
1408 Q_ASSERT(false);
1409 return;
1410 }
1411
1412 // we're modified, so let this change
1413 emit m_widget->enableOk(true);
1414
1415 moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(row - 1)) );
1416}
1417
1418void KEditToolBarWidgetPrivate::moveActive( ToolBarItem* item, ToolBarItem* before )
1419{
1420 QDomElement e = findElementForToolBarItem( item );
1421
1422 if ( e.isNull() )
1423 return;
1424
1425 // remove item
1426 m_activeList->takeItem(m_activeList->row(item));
1427
1428 // put it where it's supposed to go
1429 m_activeList->insertItem(m_activeList->row(before) + 1, item);
1430
1431 // make it selected again
1432 m_activeList->setCurrentItem(item);
1433
1434 // and do the real move in the DOM
1435 if ( !before )
1436 m_currentToolBarElem.insertBefore(e, m_currentToolBarElem.firstChild() );
1437 else
1438 m_currentToolBarElem.insertAfter(e, findElementForToolBarItem( (ToolBarItem*)before ));
1439
1440 // and set this container as a noMerge
1441 static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
1442 m_currentToolBarElem.setAttribute( attrNoMerge, "1");
1443
1444 // update the local doc
1445 updateLocal(m_currentToolBarElem);
1446}
1447
1448void KEditToolBarWidgetPrivate::slotDownButton()
1449{
1450 ToolBarItem *item = m_activeList->currentItem();
1451
1452 if (!item) {
1453 Q_ASSERT(false);
1454 return;
1455 }
1456
1457 // make sure we're not the bottom item already
1458 int newRow = item->listWidget()->row(item) + 1;
1459 if (newRow >= item->listWidget()->count()) {
1460 Q_ASSERT(false);
1461 return;
1462 }
1463
1464 // we're modified, so let this change
1465 emit m_widget->enableOk(true);
1466
1467 moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(newRow)) );
1468}
1469
1470void KEditToolBarWidgetPrivate::updateLocal(QDomElement& elem)
1471{
1472 static const QString &attrName = KGlobal::staticQString( "name" );
1473
1474 XmlDataList::Iterator xit = m_xmlFiles.begin();
1475 for ( ; xit != m_xmlFiles.end(); ++xit)
1476 {
1477 if ( (*xit).type() == XmlData::Merged )
1478 continue;
1479
1480 if ( (*xit).type() == XmlData::Shell ||
1481 (*xit).type() == XmlData::Part )
1482 {
1483 if ( m_currentXmlData->xmlFile() == (*xit).xmlFile() )
1484 {
1485 (*xit).m_isModified = true;
1486 return;
1487 }
1488
1489 continue;
1490 }
1491
1492 (*xit).m_isModified = true;
1493
1494 ToolBarList::Iterator it = (*xit).barList().begin();
1495 for ( ; it != (*xit).barList().end(); ++it)
1496 {
1497 QString name( (*it).attribute( attrName ) );
1498 QString tag( (*it).tagName() );
1499 if ( (tag != elem.tagName()) || (name != elem.attribute(attrName)) )
1500 continue;
1501
1502 QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
1503 toolbar.replaceChild(elem, (*it));
1504 return;
1505 }
1506
1507 // just append it
1508 QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
1509 Q_ASSERT(!toolbar.isNull());
1510 toolbar.appendChild(elem);
1511 }
1512}
1513
1514void KEditToolBarWidgetPrivate::slotChangeIcon()
1515{
1516 // We can't use KIconChooser here, since it's in libkio
1517 // ##### KDE4: reconsider this, e.g. move KEditToolBar to libkio,
1518 // ##### or better, dlopen libkfile from here like kio does.
1519
1520 //if the process is already running (e.g. when somebody clicked the change button twice (see #127149)) - do nothing...
1521 //otherwise m_kdialogProcess will be overwritten and set to zero in slotProcessExited()...crash!
1522 if ( m_kdialogProcess && m_kdialogProcess->state() == QProcess::Running )
1523 return;
1524
1525 m_currentXmlData->dump();
1526 Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
1527
1528 m_kdialogProcess = new KProcess;
1529 QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
1530 (*m_kdialogProcess) << kdialogExe;
1531 (*m_kdialogProcess) << "--caption";
1532 (*m_kdialogProcess) << i18n( "Change Icon" );
1533 (*m_kdialogProcess) << "--embed";
1534 (*m_kdialogProcess) << QString::number( (quintptr)m_widget->window()->winId() );
1535 (*m_kdialogProcess) << "--geticon";
1536 (*m_kdialogProcess) << "Toolbar";
1537 (*m_kdialogProcess) << "Actions";
1538 m_kdialogProcess->setOutputChannelMode(KProcess::OnlyStdoutChannel);
1539 m_kdialogProcess->setNextOpenMode( QIODevice::ReadOnly | QIODevice::Text );
1540 m_kdialogProcess->start();
1541 if ( !m_kdialogProcess->waitForStarted() ) {
1542 kError(240) << "Can't run " << kdialogExe << endl;
1543 delete m_kdialogProcess;
1544 m_kdialogProcess = 0;
1545 return;
1546 }
1547
1548 m_activeList->setEnabled( false ); // don't change the current item
1549 m_toolbarCombo->setEnabled( false ); // don't change the current toolbar
1550
1551 QObject::connect( m_kdialogProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
1552 m_widget, SLOT(slotProcessExited()) );
1553}
1554
1555void KEditToolBarWidgetPrivate::slotChangeIconText()
1556{
1557 m_currentXmlData->dump();
1558 ToolBarItem *item = m_activeList->currentItem();
1559
1560 if(item){
1561 QString iconText = item->text();
1562 bool hidden = item->isTextAlongsideIconHidden();
1563
1564 IconTextEditDialog dialog(m_widget);
1565 dialog.setIconText(iconText);
1566 dialog.setTextAlongsideIconHidden(hidden);
1567
1568 bool ok = dialog.exec() == KDialog::Accepted;
1569 iconText = dialog.iconText();
1570 hidden = dialog.textAlongsideIconHidden();
1571
1572 bool hiddenChanged = hidden != item->isTextAlongsideIconHidden();
1573 bool iconTextChanged = iconText != item->text();
1574
1575 if (!ok || (!hiddenChanged && !iconTextChanged))
1576 return;
1577
1578 item->setText(iconText);
1579 item->setTextAlongsideIconHidden(hidden);
1580
1581 Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
1582
1583 m_currentXmlData->m_isModified = true;
1584
1585 // Get hold of ActionProperties tag
1586 QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
1587 // Find or create an element for this action
1588 QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
1589 Q_ASSERT( !act_elem.isNull() );
1590 if (iconTextChanged)
1591 act_elem.setAttribute( "iconText", iconText );
1592 if (hiddenChanged)
1593 act_elem.setAttribute( "priority", hidden ? QAction::LowPriority : QAction::NormalPriority );
1594
1595 // we're modified, so let this change
1596 emit m_widget->enableOk(true);
1597 }
1598}
1599
1600void KEditToolBarWidgetPrivate::slotProcessExited()
1601{
1602 m_activeList->setEnabled( true );
1603 m_toolbarCombo->setEnabled( true );
1604
1605 QString icon;
1606
1607 if (!m_kdialogProcess) {
1608 kError(240) << "Something is wrong here! m_kdialogProcess is zero!" << endl;
1609 return;
1610 }
1611
1612 icon = QString::fromLocal8Bit( m_kdialogProcess->readLine() );
1613 icon = icon.left( icon.indexOf( '\n' ) );
1614 kDebug(240) << "icon=" << icon;
1615 if ( m_kdialogProcess->exitStatus() != QProcess::NormalExit ||
1616 icon.isEmpty() ) {
1617 delete m_kdialogProcess;
1618 m_kdialogProcess = 0;
1619 return;
1620 }
1621
1622 ToolBarItem *item = m_activeList->currentItem();
1623 kDebug() << item;
1624 if(item){
1625 item->setIcon(KIcon(icon));
1626
1627 Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
1628
1629 m_currentXmlData->m_isModified = true;
1630
1631 // Get hold of ActionProperties tag
1632 QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
1633 // Find or create an element for this action
1634 QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
1635 Q_ASSERT( !act_elem.isNull() );
1636 act_elem.setAttribute( "icon", icon );
1637
1638 // we're modified, so let this change
1639 emit m_widget->enableOk(true);
1640 }
1641
1642 delete m_kdialogProcess;
1643 m_kdialogProcess = 0;
1644}
1645
1646void KEditToolBarWidgetPrivate::slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList)
1647{
1648 //kDebug() << "slotDropped list=" << (list==m_activeList?"activeList":"inactiveList")
1649 // << "index=" << index << "sourceIsActiveList=" << sourceIsActiveList;
1650 if (list == m_activeList) {
1651 ToolBarItem* after = index > 0 ? static_cast<ToolBarItem *>(list->item(index-1)) : 0;
1652 //kDebug() << "after" << after->text() << after->internalTag();
1653 if (sourceIsActiveList) {
1654 // has been dragged within the active list (moved).
1655 moveActive(item, after);
1656 } else {
1657 // dragged from the inactive list to the active list
1658 insertActive(item, after, true);
1659 }
1660 } else if (list == m_inactiveList) {
1661 // has been dragged to the inactive list -> remove from the active list.
1662 removeActive(item);
1663 }
1664
1665 delete item; // not needed anymore. must be deleted before slotToolBarSelected clears the lists
1666
1667 // we're modified, so let this change
1668 emit m_widget->enableOk(true);
1669
1670 slotToolBarSelected( m_toolbarCombo->currentIndex() );
1671}
1672
1673
1674void KEditToolBar::showEvent( QShowEvent * event )
1675{
1676 if (!event->spontaneous()) {
1677 // The dialog has been shown, enable toolbar editing
1678 if ( d->m_factory ) {
1679 // call the xmlgui-factory version
1680 d->m_widget->load( d->m_factory, d->m_defaultToolBar );
1681 } else {
1682 // call the action collection version
1683 d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
1684 }
1685
1686 KToolBar::setToolBarsEditable(true);
1687 }
1688 KDialog::showEvent(event);
1689}
1690
1691void KEditToolBar::hideEvent(QHideEvent* event)
1692{
1693 // The dialog has been hidden, disable toolbar editing
1694 KToolBar::setToolBarsEditable(false);
1695
1696 KDialog::hideEvent(event);
1697}
1698
1699#include "kedittoolbar.moc"
1700#include "kedittoolbar_p.moc"
KActionCollection
A container for a set of QAction objects.
Definition: kactioncollection.h:57
KActionCollection::actions
QList< QAction * > actions() const
Returns the list of KActions which belong to this action collection.
Definition: kactioncollection.cpp:186
KComboBox
An enhanced combo box.
Definition: kcombobox.h:149
KComponentData
KDialog
A dialog base class with standard buttons and predefined layouts.
Definition: kdialog.h:129
KDialog::hideEvent
virtual void hideEvent(QHideEvent *)
Emits the #hidden signal.
Definition: kdialog.cpp:993
KDialog::Ok
@ Ok
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
Definition: kdialog.h:141
KDialog::Default
@ Default
Show Default button.
Definition: kdialog.h:140
KDialog::Cancel
@ Cancel
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
Definition: kdialog.h:144
KDialog::Apply
@ Apply
Show Apply button.
Definition: kdialog.h:142
KEditToolBar
A dialog used to customize or configure toolbars.
Definition: kedittoolbar.h:69
KEditToolBar::hideEvent
virtual void hideEvent(QHideEvent *event)
Emits the #hidden signal.
Definition: kedittoolbar.cpp:1691
KEditToolBar::setResourceFile
void setResourceFile(const QString &file, bool global=true)
The name (absolute or relative) of your application's UI resource file is assumed to be share/apps/ap...
Definition: kedittoolbar.cpp:572
KEditToolBar::KEditToolBar
KEditToolBar(KActionCollection *collection, QWidget *parent=0)
Old constructor for apps that do not use components.
Definition: kedittoolbar.cpp:526
KEditToolBar::setDefaultToolBar
void setDefaultToolBar(const QString &toolBarName)
Sets the default toolbar that will be selected when the dialog is shown.
Definition: kedittoolbar.cpp:585
KEditToolBar::setGlobalDefaultToolBar
static void setGlobalDefaultToolBar(const char *toolBarName)
Sets the default toolbar which will be auto-selected for all KEditToolBar instances.
Definition: kedittoolbar.cpp:689
KEditToolBar::~KEditToolBar
~KEditToolBar()
destructor
Definition: kedittoolbar.cpp:579
KEditToolBar::showEvent
virtual void showEvent(QShowEvent *event)
Definition: kedittoolbar.cpp:1674
KGuiItem
An abstract class for GUI data such as ToolTip and Icon.
Definition: kguiitem.h:37
KGuiItem::text
QString text() const
Definition: kguiitem.cpp:117
KIcon
A wrapper around QIcon that provides KDE icon features.
Definition: kicon.h:41
KLineEdit
An enhanced QLineEdit widget for inputting text.
Definition: klineedit.h:150
KLineEdit::setClickMessage
void setClickMessage(const QString &msg)
This makes the line edit display a grayed-out hinting text as long as the user didn't enter any text.
Definition: klineedit.cpp:1815
KListWidgetSearchLine
This class makes it easy to add a search line for filtering the items in a listwidget based on a simp...
Definition: klistwidgetsearchline.h:38
KLocale::removeAcceleratorMarker
QString removeAcceleratorMarker(const QString &label) const
KLocalizedString
KLocalizedString::toString
QString toString() const
KLocalizedString::subs
KLocalizedString subs(const QString &a, int fieldWidth=0, const QChar &fillChar=QLatin1Char(' ')) const
KMessageBox::warningContinueCancel
static int warningContinueCancel(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
Display a "warning" dialog.
Definition: kmessagebox.cpp:644
KMessageBox::Continue
@ Continue
Definition: kmessagebox.h:74
KProcess
KProcess::OnlyStdoutChannel
OnlyStdoutChannel
KPushButton
A QPushButton with drag-support and KGuiItem support.
Definition: kpushbutton.h:47
KSeparator
Standard horizontal or vertical separator.
Definition: kseparator.h:35
KStandardDirs::findExe
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
KStandardDirs::locateLocal
static QString locateLocal(const char *type, const QString &filename, bool createDir, const KComponentData &cData=KGlobal::mainComponent())
KToolBar::setToolBarsEditable
static void setToolBarsEditable(bool editable)
Enable or disable toolbar editing via drag & drop of actions.
Definition: ktoolbar.cpp:1410
KXMLGUIClient
A KXMLGUIClient can be used with KXMLGUIFactory to create a GUI from actions and an XML document,...
Definition: kxmlguiclient.h:47
KXMLGUIClient::xmlFile
virtual QString xmlFile() const
This will return the name of the XML file as set by setXMLFile().
Definition: kxmlguiclient.cpp:154
KXMLGUIClient::domDocument
virtual QDomDocument domDocument() const
Definition: kxmlguiclient.cpp:149
KXMLGUIClient::actionCollection
virtual KActionCollection * actionCollection() const
Retrieves the entire action collection for the GUI client.
Definition: kxmlguiclient.cpp:128
KXMLGUIClient::setXMLFile
virtual void setXMLFile(const QString &file, bool merge=false, bool setXMLDoc=true)
Sets the name of the rc file containing the XML for the part.
Definition: kxmlguiclient.cpp:203
KXMLGUIClient::localXMLFile
virtual QString localXMLFile() const
Definition: kxmlguiclient.cpp:159
KXMLGUIClient::setXMLGUIBuildDocument
void setXMLGUIBuildDocument(const QDomDocument &doc)
Definition: kxmlguiclient.cpp:587
KXMLGUIClient::loadStandardsXmlFile
void loadStandardsXmlFile()
Load the ui_standards.rc file.
Definition: kxmlguiclient.cpp:192
KXMLGUIFactory
KXMLGUIFactory, together with KXMLGUIClient objects, can be used to create a GUI of container widgets...
Definition: kxmlguifactory.h:66
KXMLGUIFactory::readConfigFile
static QString readConfigFile(const QString &filename, const KComponentData &componentData=KComponentData())
Definition: kxmlguifactory.cpp:117
KXMLGUIFactory::clients
QList< KXMLGUIClient * > clients() const
Returns a list of all clients currently added to this factory.
Definition: kxmlguifactory.cpp:469
KXMLGUIFactory::actionPropertiesElement
static QDomElement actionPropertiesElement(QDomDocument &doc)
Definition: kxmlguifactory.cpp:769
KXMLGUIFactory::findActionByName
static QDomElement findActionByName(QDomElement &elem, const QString &sName, bool create)
Definition: kxmlguifactory.cpp:783
KXMLGUIFactory::saveConfigFile
static bool saveConfigFile(const QDomDocument &doc, const QString &filename, const KComponentData &componentData=KComponentData())
Definition: kxmlguifactory.cpp:142
QAction
QLabel
QListWidget
QList
QSet
QToolButton
QWidget
K_GLOBAL_STATIC
#define K_GLOBAL_STATIC(TYPE, NAME)
kDebug
#define kDebug
kWarning
#define kWarning
kaction.h
kactioncollection.h
kcombobox.h
kcomponentdata.h
kconfig.h
kdebug.h
s_XmlTypeToString
static const char *const s_XmlTypeToString[]
Definition: kedittoolbar.cpp:62
ToolBarList
QList< QDomElement > ToolBarList
Definition: kedittoolbar.cpp:64
SEPARATORSTRING
#define SEPARATORSTRING
Definition: kedittoolbar.cpp:60
separatorstring
static const char *const separatorstring
Definition: kedittoolbar.cpp:58
kedittoolbar.h
kicon.h
kiconloader.h
klineedit.h
klistwidgetsearchline.h
klocale.h
ki18nc
KLocalizedString ki18nc(const char *ctxt, const char *msg)
i18n
QString i18n(const char *text)
I18N_NOOP
#define I18N_NOOP(x)
i18nc
QString i18nc(const char *ctxt, const char *text)
kmessagebox.h
kprocess.h
kpushbutton.h
kseparator.h
kstandarddirs.h
ktoolbar.h
kxmlguifactory.h
KDEPrivate
Definition: kcolorchoosermode.cpp:24
KDEPrivate::XmlDataList
QList< XmlData > XmlDataList
Definition: kedittoolbar.cpp:170
KDEPrivate::findToolBars
static ToolBarList findToolBars(const QDomElement &start)
Return a list of toolbar elements given a toplevel element.
Definition: kedittoolbar.cpp:71
KDEPrivate::operator>>
static QDataStream & operator>>(QDataStream &s, ToolBarItem &item)
Definition: kedittoolbar.cpp:216
KDEPrivate::operator<<
static QDataStream & operator<<(QDataStream &s, const ToolBarItem &item)
Definition: kedittoolbar.cpp:208
KGlobal::staticQString
const QString & staticQString(const char *str)
KGlobal::mainComponent
const KComponentData & mainComponent()
KGlobal::locale
KLocale * locale()
KStandardAction::name
const char * name(StandardAction id)
This will return the internal name of a given standard action.
Definition: kstandardaction.cpp:223
KStandardGuiItem::ok
KGuiItem ok()
Returns the 'Ok' gui item.
Definition: kstandardguiitem.cpp:107
KStandardShortcut::label
QString label(StandardShortcut id)
Returns a localized label for user-visible display.
Definition: kstandardshortcut.cpp:267
KStandardShortcut::end
const KShortcut & end()
Goto end of the document.
Definition: kstandardshortcut.cpp:348
Shell
Shell
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

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

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal