/* * iconaction.cpp - the QAction subclass that uses Icons and supports animation * Copyright (C) 2003-2004 Michail Pishchagin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "iconaction.h" #include "iconwidget.h" #include "iconset.h" #include #include #include #include #include //---------------------------------------------------------------------------- // IconAction //---------------------------------------------------------------------------- class IconAction::Private : public QObject { Q_OBJECT public: QPtrList buttons; QMap popups; Icon *icon; IconAction *action; QPopupMenu *popup; Private(IconAction *act) { icon = 0; action = act; popup = 0; } QString menuText() { QString txt = action->menuText(); if ( !action->accel().isEmpty() ) txt += '\t' + (QString)action->accel(); return txt; } public slots: void menuClicked() { action->setOn( !action->isOn() ); emit action->setOn( action->isOn() ); emit action->activated(); // required for our lovely status change actions } void popupDestroyed( QObject *obj ) { bool dirty = true; while ( dirty ) { dirty = false; QMap::Iterator it = popups.begin(); for ( ; it != popups.end(); ++it ) { if ( it.key() == obj ) { dirty = true; popups.remove( it ); break; } } } } }; IconAction::IconAction(QObject *parent, const char *name) : QAction(parent, name) { d = new Private(this); } IconAction::IconAction(const QString &text, const QString &icon, const QString &menuText, QKeySequence accel, QObject *parent, const char *name, bool toggle) : QAction(text, menuText, accel, parent, name, toggle) { d = new Private(this); setIcon(icon); } IconAction::IconAction(const QString &text, const QString &menuText, QKeySequence accel, QObject *parent, const char *name, bool toggle) : QAction(text, menuText, accel, parent, name, toggle) { d = new Private(this); } IconAction::~IconAction() { // delete the buttons list before our own destruction d->buttons.setAutoDelete(true); d->buttons.clear(); delete d; } const Icon *IconAction::icon() const { return d->icon; } void IconAction::setIcon(const Icon *i) { if ( d->icon ) { disconnect(d->icon, 0, this, 0 ); d->icon->stop(); delete d->icon; d->icon = 0; } QIconSet is; if ( i ) { d->icon = new Icon(*i); connect(d->icon, SIGNAL(iconModified(const QPixmap &)), SLOT(iconUpdated(const QPixmap &))); d->icon->activated(true); is = d->icon->iconSet(); } QAction::setIconSet( is ); for ( QPtrListIterator it(d->buttons); it.current(); ++it ) { IconToolButton *btn = it.current(); btn->setIcon ( d->icon ); } #ifndef Q_WS_MAC is = QIconSet(); #endif QMap::Iterator it2 = d->popups.begin(); for ( ; it2 != d->popups.end(); ++it2 ) { it2.key()->changeItem( it2.data(), iconSet(), d->menuText() ); } } void IconAction::setIcon(const QString &name) { setIcon( IconsetFactory::iconPtr(name) ); } const QString &IconAction::iconName() const { if ( d->icon ) return d->icon->name(); return QString::null; } bool IconAction::addTo(QWidget *w) { if ( w->inherits("QToolBar") || w->isA("QWidget") ) { QCString bname = name() + QCString("_action_button"); IconToolButton *btn = new IconToolButton ( w, bname ); d->buttons.append ( btn ); btn->setToggleButton ( isToggleAction() ); btn->setOn( isOn() ); btn->setTextLabel ( text() ); btn->setIcon ( d->icon, false ); btn->setEnabled ( isEnabled() ); if ( d->popup ) btn->setPopup( d->popup ); btn->setPopupDelay (1); // the popup will be displayed immediately QToolTip::add (btn, toolTipFromMenuText()); if ( w->isA("QWidget") ) if ( w->layout() ) w->layout()->add( btn ); connect(btn, SIGNAL(clicked()), this, SIGNAL(activated())); connect(btn, SIGNAL(toggled(bool)), this, SLOT(setOn(bool))); connect(btn, SIGNAL(destroyed()), SLOT(objectDestroyed())); addingToolButton(btn); } else if ( w->inherits("QPopupMenu") ) { //if ( !isVisible() ) // return true; QPopupMenu *popup = (QPopupMenu *)w; int id; QIconSet iconset; #ifndef Q_WS_MAC iconset = iconSet(); #endif if ( d->popup ) id = popup->insertItem (iconset, d->menuText(), d->popup); else id = popup->insertItem (iconset, d->menuText()); d->popups.insert( popup, id ); connect( popup, SIGNAL( destroyed( QObject * ) ), d, SLOT( popupDestroyed( QObject * ) ) ); popup->setItemEnabled(id, isEnabled()); popup->setWhatsThis(id, whatsThis()); popup->setItemVisible(id, isVisible()); // will not work for actions with d->popup :-/ if ( isToggleAction() ) { popup->setCheckable( true ); popup->setItemChecked(id, isOn()); popup->connectItem(id, d, SLOT(menuClicked())); } else popup->connectItem(id, this, SIGNAL(activated())); addingMenuItem( popup, id ); } else return QAction::addTo(w); return true; } void IconAction::objectDestroyed() { const QObject *obj = sender(); d->buttons.removeRef((IconToolButton *)obj); } void IconAction::setOn(bool b) { QAction::setOn(b); for ( QPtrListIterator it(d->buttons); it.current(); ++it ) { IconToolButton *btn = it.current(); btn->setOn(b); } QMap::Iterator it2 = d->popups.begin(); for ( ; it2 != d->popups.end(); ++it2 ) { it2.key()->setItemChecked( it2.data(), b ); } } void IconAction::toolButtonToggled(bool b) { setOn(b); } void IconAction::setEnabled(bool e) { QAction::setEnabled(e); for ( QPtrListIterator it(d->buttons); it.current(); ++it ) { IconToolButton *btn = it.current(); btn->setEnabled (e); } QMap::Iterator it2 = d->popups.begin(); for ( ; it2 != d->popups.end(); ++it2 ) { it2.key()->setItemEnabled( it2.data(), e ); } } void IconAction::setText(const QString &t) { QAction::setText(t); for ( QPtrListIterator it(d->buttons); it.current(); ++it ) { IconToolButton *btn = it.current(); btn->setTextLabel(t); } #ifndef Q_WS_MAC QIconSet is = iconSet(); #else QIconSet is; #endif QMap::Iterator it2 = d->popups.begin(); for ( ; it2 != d->popups.end(); ++it2 ) { it2.key()->changeItem( it2.data(), is, d->menuText() ); } } QPtrList IconAction::buttonList() { return d->buttons; } void IconAction::iconUpdated(const QPixmap &pix) { QAction::setIconSet( d->icon->iconSet() ); #ifndef Q_WS_MAC QPixmap p = pix; #else Q_UNUSED( pix ); QPixmap p; #endif QMap::Iterator it2 = d->popups.begin(); for ( ; it2 != d->popups.end(); ++it2 ) { it2.key()->changeItem( it2.data(), p, d->menuText() ); } } QString IconAction::toolTipFromMenuText() const { QString tt, str = menuText(); for (int i = 0; i < (int)str.length(); i++) if ( str[i] == '&' && str[i+1] != '&' ) continue; else tt += str[i]; return tt; } QPopupMenu *IconAction::popup() const { return d->popup; } void IconAction::setPopup( QPopupMenu *p ) { d->popup = p; QPtrList btns = buttonList(); for ( QPtrListIterator it(btns); it.current(); ++it ) { QToolButton *btn = it.current(); btn->setPopup (0); if ( p ) btn->setPopup ( p ); } } void IconAction::setIconSet( const QIconSet &ic ) { QAction::setIconSet( ic ); QPtrList btns = buttonList(); for ( QPtrListIterator it(btns); it.current(); ++it ) { QToolButton *btn = it.current(); btn->setIconSet( ic ); } #ifndef Q_WS_MAC QIconSet is = ic; #else QIconSet is; #endif QMap::Iterator it2 = d->popups.begin(); for ( ; it2 != d->popups.end(); ++it2 ) { it2.key()->changeItem( it2.data(), is, d->menuText() ); } } void IconAction::setVisible( bool b ) { QAction::setVisible( b ); QPtrList btns = buttonList(); for ( QPtrListIterator it(btns); it.current(); ++it ) { QToolButton *btn = it.current(); if ( b ) btn->show(); else btn->hide(); } QMap::Iterator it2 = d->popups.begin(); for ( ; it2 != d->popups.end(); ++it2 ) { it2.key()->setItemVisible( it2.data(), b ); } } IconAction *IconAction::copy() const { IconAction *act = new IconAction(text(), iconName(), menuText(), accel(), 0, name(), isToggleAction()); *act = *this; return act; } IconAction &IconAction::operator=( const IconAction &from ) { setText( from.text() ); setIcon( from.iconName() ); setMenuText( from.menuText() ); setAccel( from.accel() ); setName( from.name() ); setToggleAction( from.isToggleAction() ); setWhatsThis( whatsThis() ); // TODO: add more return *this; } //---------------------------------------------------------------------------- // IconActionGroup //---------------------------------------------------------------------------- class IconActionGroup::Private : public QObject { Q_OBJECT public: Private(IconActionGroup *_group) { group = _group; dirty = false; } IconActionGroup *group; QPopupMenu *popup; bool exclusive; bool usesDropDown; bool dirty; public slots: void updatePopup(); }; void IconActionGroup::Private::updatePopup() { if ( !dirty ) return; if ( !usesDropDown ) qWarning("IconActionGroup does not support !usesDropDown yet"); popup->clear(); QObjectList *l = group->queryList("QAction"); QObjectListIt it( *l ); QObject *obj; for ( ; (obj = it.current()); ++it) { QAction *action = (QAction *)obj; if ( !group->icon() && action->inherits( "IconAction" ) ) group->setIcon( ((IconAction * )action)->icon() ); action->addTo( popup ); } delete l; group->setPopup( popup ); dirty = false; } IconActionGroup::IconActionGroup(QObject *parent, const char *name, bool exclusive) : IconAction( parent, name ) { d = new Private(this); d->popup = new QPopupMenu(); d->exclusive = exclusive; } IconActionGroup::~IconActionGroup() { delete d->popup; delete d; } void IconActionGroup::insertChild( QObject *obj ) { IconAction::insertChild( obj ); d->dirty = true; QTimer::singleShot( 0, d, SLOT( updatePopup() ) ); } void IconActionGroup::removeChild( QObject *obj ) { IconAction::removeChild( obj ); d->dirty = true; QTimer::singleShot( 0, d, SLOT( updatePopup() ) ); } void IconActionGroup::add( QAction * ) { qWarning("IconActionGroup::add(): not implemented"); } void IconActionGroup::addSeparator() { QAction *separatorAction = new QAction(this, "qt_separator_action"); Q_UNUSED( separatorAction ); } bool IconActionGroup::addTo( QWidget *w ) { if ( w->inherits("QPopupMenu") ) { QPopupMenu *popup = (QPopupMenu *)w; QObjectList *l = queryList("QAction"); QObjectListIt it( *l ); QObject *obj; for ( ; (obj = it.current()); ++it) { QAction *action = (QAction *)obj; action->addTo( popup ); } delete l; return true; } return IconAction::addTo( w ); } IconAction *IconActionGroup::copy() const { qWarning("IconActionGroup::copy() doesn't work!"); return (IconAction *)this; } void IconActionGroup::setExclusive( bool e ) { d->exclusive = e; } bool IconActionGroup::isExclusive() const { return d->exclusive; } void IconActionGroup::setUsesDropDown( bool u ) { d->usesDropDown = u; } bool IconActionGroup::usesDropDown() const { return d->usesDropDown; } void IconActionGroup::addingToolButton(IconToolButton *btn) { btn->setPopupDelay( 0 ); } #include "iconaction.moc"