[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-core-devel
Subject: Icon choosing in kedittoolbar
From: David Faure <faure () kde ! org>
Date: 2004-04-28 10:11:55
Message-ID: 200404281211.55728.faure () kde ! org
[Download RAW message or body]
I implemented today something that I wanted to do for a long time:
being able to set a custom icon to an action in kedittoolbar.
(I was reminded by wish #80450, but I'm sure there are older wishes for it)
It works perfectly, see attached patch (which also factorizes some code)
- except that one cannot choose the icon :-}
KIconChooser is in libkio (kio/kfile/) since it needs KFileDialog, and
KEditToolbar is in kdeui so it can't use it.
The only solutions I can think of are:
1) using KProcess to launch "kdialog --chooseicon" (which doesn't exist yet)
2) moving KEditToolbar to kio/kfile - but this isn't BC, for the (rare?) applications
that would use kdeui and not kio.
3) waiting for KDE 4 before moving kedittoolbar to kio/kfile :(
4) implementing a custom iconchooser with no filedialog. Code duplication and limited functionality...
Any other solution I'm missing?
I guess 1) is the best bet, assuming that the window manager behaves properly
(--embed <winid> will make it modal to the kedittoolbar dialog, right?).
--
David Faure, faure@kde.org, sponsored by Trolltech to work on KDE,
Konqueror (http://www.konqueror.org), and KOffice (http://www.koffice.org).
["changeicon.diff" (text/x-diff)]
Index: kactioncollection.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kactioncollection.cpp,v
retrieving revision 1.315
diff -u -p -r1.315 kactioncollection.cpp
--- kactioncollection.cpp 1 Apr 2004 12:27:01 -0000 1.315
+++ kactioncollection.cpp 28 Apr 2004 10:01:44 -0000
@@ -710,9 +710,6 @@ bool KActionShortcutList::save() const
if( m_actions.xmlFile().isEmpty() )
return writeSettings();
- QString tagActionProp = QString::fromLatin1("ActionProperties");
- QString tagAction = QString::fromLatin1("Action");
- QString attrName = QString::fromLatin1("name");
QString attrShortcut = QString::fromLatin1("shortcut");
QString attrAccel = QString::fromLatin1("accel"); // Depricated attribute
@@ -723,22 +720,8 @@ bool KActionShortcutList::save() const
// Process XML data
- // first, lets see if we have existing properties
- QDomElement elem;
- QDomNode it = doc.documentElement().firstChild();
- for( ; !it.isNull(); it = it.nextSibling() ) {
- QDomElement e = it.toElement();
- if( e.tagName() == tagActionProp ) {
- elem = e;
- break;
- }
- }
-
- // if there was none, create one
- if( elem.isNull() ) {
- elem = doc.createElement( tagActionProp );
- doc.documentElement().appendChild( elem );
- }
+ // Get hold of ActionProperties tag
+ QDomElement elem = KXMLGUIFactory::actionPropertiesElement( doc );
// now, iterate through our actions
uint nSize = count();
@@ -749,23 +732,10 @@ bool KActionShortcutList::save() const
//kdDebug(129) << "name = " << sName << " shortcut = " << shortcut(i).toStringInternal() << \
" def = " << shortcutDefault(i).toStringInternal() << endl;
// now see if this element already exists
- QDomElement act_elem;
- for( it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
- QDomElement e = it.toElement();
- if( e.attribute( attrName ) == sName ) {
- act_elem = e;
- break;
- }
- }
-
- // nope, create a new one
- if( act_elem.isNull() ) {
- if( bSameAsDefault )
- continue;
- //kdDebug(129) << "\tnode doesn't exist." << endl;
- act_elem = doc.createElement( tagAction );
- act_elem.setAttribute( attrName, sName );
- }
+ // and create it if necessary (unless bSameAsDefault)
+ QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, sName, !bSameAsDefault );
+ if ( act_elem.isNull() )
+ continue;
act_elem.removeAttribute( attrAccel );
if( bSameAsDefault ) {
@@ -775,7 +745,6 @@ bool KActionShortcutList::save() const
elem.removeChild( act_elem );
} else {
act_elem.setAttribute( attrShortcut, shortcut(i).toStringInternal() );
- elem.appendChild( act_elem );
}
}
Index: kedittoolbar.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kedittoolbar.cpp,v
retrieving revision 1.83
diff -u -p -r1.83 kedittoolbar.cpp
--- kedittoolbar.cpp 7 Apr 2004 10:47:23 -0000 1.83
+++ kedittoolbar.cpp 28 Apr 2004 10:01:45 -0000
@@ -42,6 +42,7 @@
#include <qtextstream.h>
#include <qfile.h>
#include <kdebug.h>
+#include "kpushbutton.h"
#define LINESEPARATORSTRING i18n("--- line separator ---")
#define SEPARATORSTRING i18n("--- separator ---")
@@ -171,6 +172,22 @@ public:
return list;
}
+ /**
+ * Look for a given item in the current toolbar
+ */
+ QDomElement findElementForToolbarItem( const ToolbarItem* item ) const
+ {
+ static const QString &attrName = KGlobal::staticQString( "name" );
+ QDomElement elem = m_currentToolbarElem.firstChild().toElement();
+ for( ; !elem.isNull(); elem = elem.nextSibling().toElement())
+ {
+ if ((elem.attribute(attrName) == item->internalName()) &&
+ (elem.tagName() == item->internalTag()))
+ return elem;
+ }
+ return QDomElement();
+ }
+
QValueList<KAction*> m_actionList;
KActionCollection* m_collection;
KInstance *m_instance;
@@ -189,7 +206,7 @@ public:
XmlDataList m_xmlFiles;
QLabel * m_helpArea;
-
+ KPushButton* m_changeIcon;
};
class KEditToolbarPrivate {
@@ -499,8 +516,8 @@ void KEditToolbarWidget::setupLayout()
m_inactiveList->setAllColumnsShowFocus(true);
m_inactiveList->setMinimumSize(180, 250);
m_inactiveList->header()->hide();
- m_inactiveList->addColumn("");
- int column2 = m_inactiveList->addColumn("");
+ m_inactiveList->addColumn(""); // icon
+ int column2 = m_inactiveList->addColumn(""); // text
m_inactiveList->setSorting( column2 );
inactive_label->setBuddy(m_inactiveList);
connect(m_inactiveList, SIGNAL(selectionChanged(QListViewItem *)),
@@ -512,14 +529,21 @@ void KEditToolbarWidget::setupLayout()
m_activeList->setAllColumnsShowFocus(true);
m_activeList->setMinimumWidth(m_inactiveList->minimumWidth());
m_activeList->header()->hide();
- m_activeList->addColumn("");
- m_activeList->addColumn("");
- m_activeList->setSorting (-1);
+ m_activeList->addColumn(""); // icon
+ m_activeList->addColumn(""); // text
+ m_activeList->setSorting(-1);
active_label->setBuddy(m_activeList);
connect(m_activeList, SIGNAL(selectionChanged(QListViewItem *)),
this, SLOT(slotActiveSelected(QListViewItem *)));
+ // "change icon" button
+ d->m_changeIcon = new KPushButton( i18n( "Change Icon" ), this );
+
+ connect( d->m_changeIcon, SIGNAL( clicked() ),
+ this, SLOT( slotChangeIcon() ) );
+
+ // The buttons in the middle
QIconSet iconSet;
m_upAction = new QToolButton(this);
@@ -559,6 +583,7 @@ void KEditToolbarWidget::setupLayout()
QVBoxLayout *inactive_layout = new QVBoxLayout(KDialog::spacingHint());
QVBoxLayout *active_layout = new QVBoxLayout(KDialog::spacingHint());
+ QHBoxLayout *changeIcon_layout = new QHBoxLayout(KDialog::spacingHint());
QGridLayout *button_layout = new QGridLayout(5, 3, 0);
@@ -579,6 +604,11 @@ void KEditToolbarWidget::setupLayout()
active_layout->addWidget(active_label);
active_layout->addWidget(m_activeList, 1);
+ active_layout->addLayout(changeIcon_layout);
+
+ changeIcon_layout->addStretch( 1 );
+ changeIcon_layout->addWidget( d->m_changeIcon );
+ changeIcon_layout->addStretch( 1 );
list_layout->addLayout(inactive_layout);
list_layout->addLayout(button_layout);
@@ -822,10 +852,11 @@ void KEditToolbarWidget::slotInactiveSel
void KEditToolbarWidget::slotActiveSelected(QListViewItem *item)
{
+ m_removeAction->setEnabled( item != 0 );
+ d->m_changeIcon->setEnabled( item != 0 );
+
if (item)
{
- m_removeAction->setEnabled(true);
-
if (item->itemAbove())
m_upAction->setEnabled(true);
else
@@ -840,7 +871,6 @@ void KEditToolbarWidget::slotActiveSelec
}
else
{
- m_removeAction->setEnabled(false);
m_upAction->setEnabled(false);
m_downAction->setEnabled(false);
d->m_helpArea->setText( QString::null );
@@ -875,16 +905,9 @@ void KEditToolbarWidget::slotInsertButto
// we have a selected item in the active list.. so let's try
// our best to add our new item right after the selected one
ToolbarItem *act_item = (ToolbarItem*)m_activeList->currentItem();
- QDomElement elem = d->m_currentToolbarElem.firstChild().toElement();
- for( ; !elem.isNull(); elem = elem.nextSibling().toElement())
- {
- if ((elem.attribute(attrName) == act_item->internalName()) &&
- (elem.tagName() == act_item->internalTag()))
- {
- d->m_currentToolbarElem.insertAfter(new_item, elem);
- break;
- }
- }
+ QDomElement elem = d->findElementForToolbarItem( act_item );
+ Q_ASSERT( !elem.isNull() );
+ d->m_currentToolbarElem.insertAfter(new_item, elem);
}
else
{
@@ -903,7 +926,6 @@ void KEditToolbarWidget::slotInsertButto
void KEditToolbarWidget::slotRemoveButton()
{
- static const QString &attrName = KGlobal::staticQString( "name" );
static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
// we're modified, so let this change
@@ -911,22 +933,17 @@ void KEditToolbarWidget::slotRemoveButto
ToolbarItem *item = (ToolbarItem*)m_activeList->currentItem();
// now iterate through to find the child to nuke
- QDomElement elem = d->m_currentToolbarElem.firstChild().toElement();
- for( ; !elem.isNull(); elem = elem.nextSibling().toElement())
+ QDomElement elem = d->findElementForToolbarItem( item );
+ if ( !elem.isNull() )
{
- if ((elem.attribute(attrName) == item->internalName()) &&
- (elem.tagName() == item->internalTag()))
- {
- // nuke myself!
- d->m_currentToolbarElem.removeChild(elem);
+ // nuke myself!
+ d->m_currentToolbarElem.removeChild(elem);
- // and set this container as a noMerge
- d->m_currentToolbarElem.setAttribute( attrNoMerge, "1");
+ // and set this container as a noMerge
+ d->m_currentToolbarElem.setAttribute( attrNoMerge, "1");
- // update the local doc
- updateLocal(d->m_currentToolbarElem);
- break;
- }
+ // update the local doc
+ updateLocal(d->m_currentToolbarElem);
}
slotToolbarSelected( m_toolbarCombo->currentText() );
}
@@ -939,55 +956,48 @@ void KEditToolbarWidget::slotUpButton()
if (!item->itemAbove())
return;
- static const QString &attrName = KGlobal::staticQString( "name" );
static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
// we're modified, so let this change
emit enableOk(true);
// now iterate through to find where we are
- QDomElement elem = d->m_currentToolbarElem.firstChild().toElement();
- for( ; !elem.isNull(); elem = elem.nextSibling().toElement())
+ QDomElement elem = d->findElementForToolbarItem( item );
+ if ( !elem.isNull() )
{
- if ((elem.attribute(attrName) == item->internalName()) &&
- (elem.tagName() == item->internalTag()))
- {
- // cool, i found me. now clone myself
- ToolbarItem *clone = new ToolbarItem(m_activeList,
- item->itemAbove()->itemAbove(),
- item->internalTag(),
- item->internalName(),
- item->statusText());
- clone->setText(1, item->text(1));
-
- // only set new pixmap if exists
- if( item->pixmap(0) )
- clone->setPixmap(0, *item->pixmap(0));
-
- // remove the old me
- m_activeList->takeItem(item);
- delete item;
-
- // select my clone
- m_activeList->setSelected(clone, true);
-
- // make clone visible
- m_activeList->ensureItemVisible(clone);
-
- // and do the real move in the DOM
- QDomNode prev = elem.previousSibling();
- while ( prev.toElement().tagName() == QString( "WeakSeparator" ) )
+ // cool, i found me. now clone myself
+ ToolbarItem *clone = new ToolbarItem(m_activeList,
+ item->itemAbove()->itemAbove(),
+ item->internalTag(),
+ item->internalName(),
+ item->statusText());
+ clone->setText(1, item->text(1));
+
+ // only set new pixmap if exists
+ if( item->pixmap(0) )
+ clone->setPixmap(0, *item->pixmap(0));
+
+ // remove the old me
+ m_activeList->takeItem(item);
+ delete item;
+
+ // select my clone
+ m_activeList->setSelected(clone, true);
+
+ // make clone visible
+ m_activeList->ensureItemVisible(clone);
+
+ // and do the real move in the DOM
+ QDomNode prev = elem.previousSibling();
+ while ( prev.toElement().tagName() == QString( "WeakSeparator" ) )
prev = prev.previousSibling();
- d->m_currentToolbarElem.insertBefore(elem, prev);
+ d->m_currentToolbarElem.insertBefore(elem, prev);
- // and set this container as a noMerge
- d->m_currentToolbarElem.setAttribute( attrNoMerge, "1");
+ // and set this container as a noMerge
+ d->m_currentToolbarElem.setAttribute( attrNoMerge, "1");
- // update the local doc
- updateLocal(d->m_currentToolbarElem);
-
- break;
- }
+ // update the local doc
+ updateLocal(d->m_currentToolbarElem);
}
}
@@ -999,55 +1009,48 @@ void KEditToolbarWidget::slotDownButton(
if (!item->itemBelow())
return;
- static const QString &attrName = KGlobal::staticQString( "name" );
static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" );
// we're modified, so let this change
emit enableOk(true);
// now iterate through to find where we are
- QDomElement elem = d->m_currentToolbarElem.firstChild().toElement();
- for( ; !elem.isNull(); elem = elem.nextSibling().toElement())
+ QDomElement elem = d->findElementForToolbarItem( item );
+ if ( !elem.isNull() )
{
- if ((elem.attribute(attrName) == item->internalName()) &&
- (elem.tagName() == item->internalTag()))
- {
- // cool, i found me. now clone myself
- ToolbarItem *clone = new ToolbarItem(m_activeList,
- item->itemBelow(),
- item->internalTag(),
- item->internalName(),
- item->statusText());
- clone->setText(1, item->text(1));
-
- // only set new pixmap if exists
- if( item->pixmap(0) )
- clone->setPixmap(0, *item->pixmap(0));
-
- // remove the old me
- m_activeList->takeItem(item);
- delete item;
-
- // select my clone
- m_activeList->setSelected(clone, true);
-
- // make clone visible
- m_activeList->ensureItemVisible(clone);
-
- // and do the real move in the DOM
- QDomNode next = elem.nextSibling();
- while ( next.toElement().tagName() == QString( "WeakSeparator" ) )
- next = next.nextSibling();
- d->m_currentToolbarElem.insertAfter(elem, next);
-
- // and set this container as a noMerge
- d->m_currentToolbarElem.setAttribute( attrNoMerge, "1");
+ // cool, i found me. now clone myself
+ ToolbarItem *clone = new ToolbarItem(m_activeList,
+ item->itemBelow(),
+ item->internalTag(),
+ item->internalName(),
+ item->statusText());
+ clone->setText(1, item->text(1));
+
+ // only set new pixmap if exists
+ if( item->pixmap(0) )
+ clone->setPixmap(0, *item->pixmap(0));
+
+ // remove the old me
+ m_activeList->takeItem(item);
+ delete item;
+
+ // select my clone
+ m_activeList->setSelected(clone, true);
+
+ // make clone visible
+ m_activeList->ensureItemVisible(clone);
+
+ // and do the real move in the DOM
+ QDomNode next = elem.nextSibling();
+ while ( next.toElement().tagName() == QString( "WeakSeparator" ) )
+ next = next.nextSibling();
+ d->m_currentToolbarElem.insertAfter(elem, next);
- // update the local doc
- updateLocal(d->m_currentToolbarElem);
+ // and set this container as a noMerge
+ d->m_currentToolbarElem.setAttribute( attrNoMerge, "1");
- break;
- }
+ // update the local doc
+ updateLocal(d->m_currentToolbarElem);
}
}
@@ -1094,6 +1097,45 @@ void KEditToolbarWidget::updateLocal(QDo
}
}
+void KEditToolbarWidget::slotChangeIcon()
+{
+ // we're modified, so let this change
+ emit enableOk(true);
+
+ ToolbarItem *item = (ToolbarItem*)m_activeList->currentItem();
+ /// ############ TODO icon chooser. But how? It's in libkio (kfile/)....
+ QString icon = "www";
+ item->setPixmap(0, BarIcon(icon, 16));
+
+ // Very much like the beginning of updateLocal
+ XmlDataList::Iterator xit = d->m_xmlFiles.begin();
+ for ( ; xit != d->m_xmlFiles.end(); ++xit)
+ {
+ if ( (*xit).m_type == XmlData::Merged )
+ continue;
+
+ if ( (*xit).m_type == XmlData::Shell ||
+ (*xit).m_type == XmlData::Part )
+ {
+ if ( d->m_currentXmlData.m_xmlFile == (*xit).m_xmlFile )
+ {
+ (*xit).m_isModified = true;
+ return;
+ }
+ continue;
+ }
+
+ (*xit).m_isModified = true;
+
+ // Get hold of ActionProperties tag
+ QDomElement elem = KXMLGUIFactory::actionPropertiesElement( (*xit).m_document );
+ // Find or create an element for this action
+ QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true \
/*create*/ ); + Q_ASSERT( !act_elem.isNull() );
+ act_elem.setAttribute( "icon", icon );
+ }
+}
+
void KEditToolbar::virtual_hook( int id, void* data )
{ KDialogBase::virtual_hook( id, data ); }
Index: kedittoolbar.h
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kedittoolbar.h,v
retrieving revision 1.36
diff -u -p -r1.36 kedittoolbar.h
--- kedittoolbar.h 17 Aug 2003 19:24:45 -0000 1.36
+++ kedittoolbar.h 28 Apr 2004 10:01:45 -0000
@@ -1,3 +1,4 @@
+// -*- mode: c++; c-basic-offset: 2 -*-
/* This file is part of the KDE libraries
Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
@@ -376,6 +377,8 @@ protected slots:
void slotUpButton();
void slotDownButton();
+ void slotChangeIcon();
+
protected:
void setupLayout();
Index: kxmlguifactory.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kxmlguifactory.cpp,v
retrieving revision 1.143
diff -u -p -r1.143 kxmlguifactory.cpp
--- kxmlguifactory.cpp 29 Mar 2004 21:30:53 -0000 1.143
+++ kxmlguifactory.cpp 28 Apr 2004 10:01:46 -0000
@@ -534,7 +534,7 @@ void KXMLGUIFactory::configureAction( KA
else
propertyValue = QVariant( attribute.value() );
- action->setProperty( attrName.latin1() /* ???????? */, propertyValue );
+ action->setProperty( attrName.latin1(), propertyValue );
}
@@ -552,6 +552,46 @@ int KXMLGUIFactory::configureShortcuts(b
return dlg.configure(bSaveSettings);
}
+QDomElement KXMLGUIFactory::actionPropertiesElement( QDomDocument& doc )
+{
+ const QString tagActionProp = QString::fromLatin1("ActionProperties");
+ // first, lets see if we have existing properties
+ QDomElement elem;
+ QDomNode it = doc.documentElement().firstChild();
+ for( ; !it.isNull(); it = it.nextSibling() ) {
+ QDomElement e = it.toElement();
+ if( e.tagName() == tagActionProp ) {
+ elem = e;
+ break;
+ }
+ }
+
+ // if there was none, create one
+ if( elem.isNull() ) {
+ elem = doc.createElement( tagActionProp );
+ doc.documentElement().appendChild( elem );
+ }
+ return elem;
+}
+
+QDomElement KXMLGUIFactory::findActionByName( QDomElement& elem, const QString& sName, bool \
create ) +{
+ static const QString& attrName = KGlobal::staticQString( "name" );
+ static const QString& tagAction = KGlobal::staticQString( "Action" );
+ for( QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
+ QDomElement e = it.toElement();
+ if( e.attribute( attrName ) == sName )
+ return e;
+ }
+
+ if( create ) {
+ QDomElement act_elem = elem.ownerDocument().createElement( tagAction );
+ act_elem.setAttribute( attrName, sName );
+ elem.appendChild( act_elem );
+ return act_elem;
+ }
+ return QDomElement();
+}
void KXMLGUIFactory::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }
Index: kxmlguifactory.h
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kxmlguifactory.h,v
retrieving revision 1.78
diff -u -p -r1.78 kxmlguifactory.h
--- kxmlguifactory.h 23 Feb 2004 18:24:16 -0000 1.78
+++ kxmlguifactory.h 28 Apr 2004 10:01:46 -0000
@@ -1,3 +1,4 @@
+// -*- mode: c++; c-basic-offset: 2 -*-
/* This file is part of the KDE libraries
Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
@@ -90,6 +91,19 @@ class KXMLGUIFactory : public QObject
static void removeDOMComments( QDomNode &node );
/**
+ * @internal
+ * Find or create the ActionProperties element, used when saving custom action properties
+ */
+ static QDomElement actionPropertiesElement( QDomDocument& doc );
+
+ /**
+ * @internal
+ * Find or create the element for a given action, by name.
+ * Used when saving custom action properties
+ */
+ static QDomElement findActionByName( QDomElement& elem, const QString& sName, bool create );
+
+ /**
* Creates the GUI described by the QDomDocument of the client,
* using the client's actions, and merges it with the previously
* created GUI.
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic