00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "kselectaction.h"
00033 #include "kselectaction_p.h"
00034
00035 #include <QActionEvent>
00036 #include <QEvent>
00037 #include <QToolButton>
00038 #include <QToolBar>
00039 #include <kicon.h>
00040 #include <kdebug.h>
00041
00042 #include "kcombobox.h"
00043 #include "kmenu.h"
00044
00045
00046
00047
00048 static QString DropAmpersands(const QString &text)
00049 {
00050 QString result;
00051 for (int i = 0; i < text.count(); ++i) {
00052 if (text.at(i) == '&') {
00053 if (i + 1 < text.count() && text.at(i + 1) == '&')
00054 result.append(text.at(i++));
00055
00056 }
00057 else
00058 result.append(text.at(i));
00059 }
00060 return result;
00061 }
00062
00063
00064 KSelectAction::KSelectAction(QObject *parent)
00065 : KAction(parent)
00066 , d_ptr(new KSelectActionPrivate())
00067 {
00068 Q_D(KSelectAction);
00069 d->init(this);
00070 }
00071
00072 KSelectAction::KSelectAction(const QString &text, QObject *parent)
00073 : KAction(parent)
00074 , d_ptr(new KSelectActionPrivate())
00075 {
00076 Q_D(KSelectAction);
00077 d->init(this);
00078 setText(text);
00079 }
00080
00081 KSelectAction::KSelectAction(const KIcon & icon, const QString &text, QObject *parent)
00082 : KAction(icon, text, parent)
00083 , d_ptr(new KSelectActionPrivate())
00084 {
00085 Q_D(KSelectAction);
00086 d->init(this);
00087 }
00088
00089 KSelectAction::KSelectAction(KSelectActionPrivate &dd, QObject *parent)
00090 : KAction(parent)
00091 , d_ptr(&dd)
00092 {
00093 Q_D(KSelectAction);
00094 d->init(this);
00095 }
00096
00097 KSelectAction::~KSelectAction()
00098 {
00099 delete d_ptr;
00100 delete menu();
00101 }
00102
00103 void KSelectActionPrivate::init(KSelectAction *q)
00104 {
00105 q_ptr = q;
00106 QObject::connect(q_ptr->selectableActionGroup(), SIGNAL(triggered(QAction*)), q_ptr, SLOT(actionTriggered(QAction*)));
00107 QObject::connect(q_ptr, SIGNAL(toggled(bool)), q_ptr, SLOT(slotToggled(bool)));
00108 q_ptr->setMenu(new KMenu());
00109 }
00110
00111 QActionGroup * KSelectAction::selectableActionGroup( ) const
00112 {
00113 Q_D(const KSelectAction);
00114 return d->m_actionGroup;
00115 }
00116
00117 QList<QAction*> KSelectAction::actions( ) const
00118 {
00119 return selectableActionGroup()->actions();
00120 }
00121
00122 QAction* KSelectAction::currentAction() const
00123 {
00124 return selectableActionGroup()->checkedAction();
00125 }
00126
00127 int KSelectAction::currentItem() const
00128 {
00129 return selectableActionGroup()->actions().indexOf(currentAction());
00130 }
00131
00132 QString KSelectAction::currentText( ) const
00133 {
00134 if (QAction* a = currentAction())
00135 return ::DropAmpersands(a->text());
00136
00137 return QString();
00138 }
00139
00140 bool KSelectAction::setCurrentAction(QAction* action)
00141 {
00142
00143 if (action) {
00144 if (actions().contains(action)) {
00145 if (action->isVisible() && action->isEnabled() && action->isCheckable()) {
00146 action->setChecked(true);
00147 if (isCheckable())
00148 setChecked(true);
00149 return true;
00150 } else
00151 kWarning (129) << "Action does not have the correct properties to be current:" << action->text();
00152 } else
00153 kWarning (129) << "Action does not belong to group:" << action->text();
00154 return false;
00155 }
00156
00157 if (currentAction())
00158 currentAction()->setChecked(false);
00159
00160 return false;
00161 }
00162
00163 bool KSelectAction::setCurrentItem( int index )
00164 {
00165
00166 return setCurrentAction(action(index));
00167 }
00168
00169 QAction * KSelectAction::action( int index ) const
00170 {
00171 if (index >= 0 && index < selectableActionGroup()->actions().count())
00172 return selectableActionGroup()->actions().at(index);
00173
00174 return 0L;
00175 }
00176
00177 QAction * KSelectAction::action( const QString & text, Qt::CaseSensitivity cs ) const
00178 {
00179 QString compare;
00180 if (cs == Qt::CaseSensitive)
00181 compare = text;
00182 else
00183 compare = text.toLower();
00184
00185 foreach (QAction* action, selectableActionGroup()->actions()) {
00186 const QString text = ::DropAmpersands(action->text());
00187 if (cs == Qt::CaseSensitive) {
00188 if (text == compare) {
00189 return action;
00190 }
00191
00192 } else if (cs == Qt::CaseInsensitive) {
00193 if (text.toLower() == compare) {
00194 return action;
00195 }
00196 }
00197 }
00198
00199 return 0L;
00200 }
00201
00202 bool KSelectAction::setCurrentAction( const QString & text, Qt::CaseSensitivity cs)
00203 {
00204
00205 return setCurrentAction(action(text, cs));
00206 }
00207
00208 void KSelectAction::setComboWidth( int width )
00209 {
00210 Q_D(KSelectAction);
00211 if ( width < 0 )
00212 return;
00213
00214 d->m_comboWidth = width;
00215
00216 foreach (KComboBox* box, d->m_comboBoxes)
00217 box->setMaximumWidth(d->m_comboWidth);
00218
00219 emit changed();
00220 }
00221
00222 void KSelectAction::setMaxComboViewCount( int n )
00223 {
00224 Q_D(KSelectAction);
00225 d->m_maxComboViewCount = n;
00226
00227 foreach (KComboBox* box, d->m_comboBoxes)
00228 if ( d->m_maxComboViewCount != -1 )
00229 box->setMaxVisibleItems(d->m_maxComboViewCount);
00230 else
00231
00232 box->setMaxVisibleItems(10);
00233
00234 emit changed();
00235 }
00236
00237 void KSelectAction::addAction(QAction* action)
00238 {
00239 Q_D(KSelectAction);
00240
00241
00242 action->setActionGroup(selectableActionGroup());
00243
00244
00245 foreach (QToolButton* button, d->m_buttons)
00246 button->addAction(action);
00247
00248 foreach (KComboBox* comboBox, d->m_comboBoxes)
00249 comboBox->addAction(action);
00250
00251 menu()->addAction(action);
00252 }
00253
00254 KAction* KSelectAction::addAction(const QString &text)
00255 {
00256 Q_D(KSelectAction);
00257 KAction* newAction = new KAction(parent());
00258 newAction->setText(text);
00259 newAction->setCheckable( true );
00260 newAction->setShortcutConfigurable(false);
00261
00262 if (!d->m_menuAccelsEnabled) {
00263 newAction->setText(text);
00264 newAction->setShortcut(QKeySequence());
00265 }
00266
00267 addAction(newAction);
00268 return newAction;
00269 }
00270
00271 KAction* KSelectAction::addAction(const KIcon& icon, const QString& text)
00272 {
00273 KAction* newAction = addAction(text);
00274 newAction->setIcon(icon);
00275 return newAction;
00276 }
00277
00278 QAction* KSelectAction::removeAction(QAction* action)
00279 {
00280 Q_D(KSelectAction);
00281
00282
00283
00284
00285
00286 d->m_actionGroup->removeAction(action);
00287
00288 foreach (QToolButton* button, d->m_buttons)
00289 button->removeAction(action);
00290
00291 foreach (KComboBox* comboBox, d->m_comboBoxes)
00292 comboBox->removeAction(action);
00293
00294 menu()->removeAction(action);
00295
00296 return action;
00297 }
00298
00299 void KSelectAction::actionTriggered(QAction* action)
00300 {
00301
00302
00303 const QString text = ::DropAmpersands(action->text());
00304 const int index = selectableActionGroup()->actions().indexOf(action);
00305
00306
00307
00308 if (isCheckable())
00309 trigger();
00310
00311 emit triggered(action);
00312 emit triggered(index);
00313 emit triggered(text);
00314 }
00315
00316 QStringList KSelectAction::items() const
00317 {
00318 Q_D(const KSelectAction);
00319 QStringList ret;
00320
00321 foreach (QAction* action, d->m_actionGroup->actions())
00322 ret << ::DropAmpersands(action->text());
00323
00324 return ret;
00325 }
00326
00327 void KSelectAction::changeItem( int index, const QString& text )
00328 {
00329 Q_D(KSelectAction);
00330 if ( index < 0 || index >= actions().count() )
00331 {
00332 kWarning() << "KSelectAction::changeItem Index out of scope";
00333 return;
00334 }
00335
00336 actions()[index]->setText( d->makeMenuText( text ) );
00337 }
00338
00339 void KSelectAction::setItems( const QStringList &lst )
00340 {
00341 Q_D(KSelectAction);
00342
00343
00344 clear();
00345
00346 foreach (const QString& string, lst) {
00347 if ( !string.isEmpty() ) {
00348 addAction(string);
00349 } else {
00350 QAction* action = new QAction(this);
00351 action->setSeparator(true);
00352 addAction(action);
00353 }
00354 }
00355
00356
00357 setEnabled( lst.count() > 0 || d->m_edit );
00358 }
00359
00360 int KSelectAction::comboWidth() const
00361 {
00362 Q_D(const KSelectAction);
00363 return d->m_comboWidth;
00364 }
00365
00366 void KSelectAction::clear()
00367 {
00368 Q_D(KSelectAction);
00369
00370
00371
00372
00373 const QList<QAction*> actions = d->m_actionGroup->actions();
00374 for (int i = 0; i < actions.count(); ++i)
00375 {
00376
00377
00378
00379
00380
00381 removeAction(actions[i]);
00382
00383 actions[i]->deleteLater();
00384 }
00385 }
00386
00387 void KSelectAction::removeAllActions( )
00388 {
00389 Q_D(KSelectAction);
00390 while (d->m_actionGroup->actions().count())
00391 removeAction(d->m_actionGroup->actions().first());
00392 }
00393
00394 void KSelectAction::setEditable( bool edit )
00395 {
00396 Q_D(KSelectAction);
00397 d->m_edit = edit;
00398
00399 foreach (KComboBox* comboBox, d->m_comboBoxes)
00400 comboBox->setEditable(edit);
00401
00402 emit changed();
00403 }
00404
00405 bool KSelectAction::isEditable() const
00406 {
00407 Q_D(const KSelectAction);
00408 return d->m_edit;
00409 }
00410
00411 void KSelectAction::slotToggled(bool checked)
00412 {
00413
00414 if (!checked && currentAction())
00415 currentAction()->setChecked(false);
00416 }
00417
00418 KSelectAction::ToolBarMode KSelectAction::toolBarMode() const
00419 {
00420 Q_D(const KSelectAction);
00421 return d->m_toolBarMode;
00422 }
00423
00424 void KSelectAction::setToolBarMode( ToolBarMode mode )
00425 {
00426 Q_D(KSelectAction);
00427 d->m_toolBarMode = mode;
00428 }
00429
00430 QToolButton::ToolButtonPopupMode KSelectAction::toolButtonPopupMode( ) const
00431 {
00432 Q_D(const KSelectAction);
00433 return d->m_toolButtonPopupMode;
00434 }
00435
00436 void KSelectAction::setToolButtonPopupMode( QToolButton::ToolButtonPopupMode mode )
00437 {
00438 Q_D(KSelectAction);
00439 d->m_toolButtonPopupMode = mode;
00440 }
00441
00442 void KSelectActionPrivate::_k_comboBoxDeleted(QObject* object)
00443 {
00444 foreach (KComboBox* comboBox, m_comboBoxes)
00445 if (object == comboBox) {
00446 m_comboBoxes.removeAll(static_cast<KComboBox*>(object));
00447 break;
00448 }
00449 }
00450
00451 void KSelectActionPrivate::_k_comboBoxCurrentIndexChanged(int index)
00452 {
00453 Q_Q(KSelectAction);
00454
00455
00456 KComboBox *triggeringCombo = qobject_cast <KComboBox *> (q->sender ());
00457
00458 QAction *a = q->action(index);
00459
00460 if (a) {
00461
00462 a->trigger();
00463
00464 } else if (q->isEditable () &&
00465 triggeringCombo && triggeringCombo->count () > 0 &&
00466 index == triggeringCombo->count () - 1) {
00467
00468
00469 const QString newItemText = triggeringCombo->currentText ();
00470
00471
00472
00473 bool blocked = triggeringCombo->blockSignals (true);
00474 triggeringCombo->removeItem (index);
00475 triggeringCombo->blockSignals (blocked);
00476
00477 KAction *newAction = q->addAction (newItemText);
00478
00479 newAction->trigger();
00480 } else {
00481 if (q->selectableActionGroup()->checkedAction())
00482 q->selectableActionGroup()->checkedAction()->setChecked(false);
00483 }
00484 }
00485
00486
00487
00488 void KSelectAction::setMenuAccelsEnabled( bool b )
00489 {
00490 Q_D(KSelectAction);
00491 d->m_menuAccelsEnabled = b;
00492 }
00493
00494 bool KSelectAction::menuAccelsEnabled() const
00495 {
00496 Q_D(const KSelectAction);
00497 return d->m_menuAccelsEnabled;
00498 }
00499
00500 QWidget * KSelectAction::createWidget( QWidget * parent )
00501 {
00502 Q_D(KSelectAction);
00503 QToolBar *toolBar = qobject_cast<QToolBar *>(parent);
00504 if (!toolBar)
00505 return 0;
00506 switch (toolBarMode()) {
00507 case MenuMode: {
00508 QToolButton* button = new QToolButton(toolBar);
00509 button->setAutoRaise(true);
00510 button->setFocusPolicy(Qt::NoFocus);
00511 button->setIconSize(toolBar->iconSize());
00512 button->setToolButtonStyle(toolBar->toolButtonStyle());
00513 QObject::connect(toolBar, SIGNAL(iconSizeChanged(const QSize&)),
00514 button, SLOT(setIconSize(const QSize&)));
00515 QObject::connect(toolBar, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
00516 button, SLOT(setToolButtonStyle(Qt::ToolButtonStyle)));
00517 button->setDefaultAction(this);
00518 QObject::connect(button, SIGNAL(triggered(QAction*)), toolBar, SIGNAL(actionTriggered(QAction*)));
00519
00520 button->setPopupMode(toolButtonPopupMode());
00521
00522 button->addActions(selectableActionGroup()->actions());
00523
00524 d->m_buttons.append(button);
00525 return button;
00526 }
00527
00528 case ComboBoxMode: {
00529 KComboBox* comboBox = new KComboBox(toolBar);
00530 comboBox->installEventFilter (this);
00531
00532 if ( d->m_maxComboViewCount != -1 )
00533 comboBox->setMaxVisibleItems( d->m_maxComboViewCount );
00534
00535 if ( d->m_comboWidth > 0 )
00536 comboBox->setMaximumWidth( d->m_comboWidth );
00537
00538 comboBox->setEditable(isEditable());
00539
00540 foreach (QAction* action, selectableActionGroup()->actions())
00541 comboBox->addAction(action);
00542
00543 connect(comboBox, SIGNAL(destroyed(QObject*)), SLOT(_k_comboBoxDeleted(QObject*)));
00544 connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(_k_comboBoxCurrentIndexChanged(int)));
00545 d->m_comboBoxes.append(comboBox);
00546
00547 return comboBox;
00548 }
00549 }
00550
00551 return 0L;
00552 }
00553
00554 void KSelectAction::deleteWidget(QWidget *widget)
00555 {
00556 Q_D(KSelectAction);
00557 if (QToolButton *toolButton = qobject_cast<QToolButton *>(widget))
00558 d->m_buttons.removeAll(toolButton);
00559 else if (KComboBox *comboBox = qobject_cast<KComboBox *>(widget))
00560 d->m_comboBoxes.removeAll(comboBox);
00561 KAction::deleteWidget(widget);
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 static int TrueCurrentItem (KSelectAction *sa)
00577 {
00578 QAction *curAction = sa->currentAction ();
00579
00580
00581 foreach (QAction *action, sa->actions ())
00582 {
00583 if (action->isChecked ())
00584 {
00585
00586
00587
00588 if (action != curAction)
00589 {
00590
00591 return sa->actions ().indexOf (action);
00592 }
00593 }
00594 }
00595
00596
00597
00598 return (curAction && curAction->isChecked ()) ? sa->actions ().indexOf (curAction) : -1;
00599 }
00600
00601
00602
00603 static QVariant QVariantFromQAction (QAction *action)
00604 {
00605
00606
00607 return qVariantFromValue ((qlonglong) action);
00608 }
00609
00610 bool KSelectAction::eventFilter (QObject *watched, QEvent *event)
00611 {
00612 KComboBox *comboBox = qobject_cast <KComboBox *> (watched);
00613 if (!comboBox)
00614 return false;
00615
00616
00617
00618
00619 if (event->type () == QEvent::FocusOut) {
00620 QFocusEvent * const e = static_cast <QFocusEvent *> (event);
00621
00622
00623
00624
00625
00626 if (e->reason () != Qt::ActiveWindowFocusReason &&
00627 e->reason () != Qt::PopupFocusReason &&
00628 e->reason () != Qt::OtherFocusReason) {
00629
00630
00631 comboBox->setEditText (comboBox->itemText (comboBox->currentIndex ()));
00632 }
00633
00634 return false;
00635 }
00636
00637
00638 bool blocked = comboBox->blockSignals (true);
00639
00640 if (event->type () == QEvent::ActionAdded)
00641 {
00642 QActionEvent * const e = static_cast <QActionEvent *> (event);
00643
00644 const int index = e->before () ?
00645 comboBox->findData (QVariantFromQAction (e->before ())) :
00646 comboBox->count ();
00647 const int newItem = ::TrueCurrentItem (this);
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658 comboBox->insertItem (index,
00659 e->action()->icon(),
00660 ::DropAmpersands (e->action()->text()),
00661 QVariantFromQAction (e->action ()));
00662
00663
00664
00665 comboBox->setCurrentIndex (newItem);
00666 }
00667 else if (event->type () == QEvent::ActionChanged)
00668 {
00669 QActionEvent * const e = static_cast <QActionEvent *> (event);
00670
00671 const int index = comboBox->findData (QVariantFromQAction (e->action ()));
00672 const int newItem = ::TrueCurrentItem (this);
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682 comboBox->setItemIcon (index, e->action ()->icon ());
00683 comboBox->setItemText (index, ::DropAmpersands (e->action ()->text ()));
00684
00685
00686
00687 comboBox->setCurrentIndex (newItem);
00688 }
00689 else if (event->type () == QEvent::ActionRemoved)
00690 {
00691 QActionEvent * const e = static_cast <QActionEvent *> (event);
00692
00693 const int index = comboBox->findData (QVariantFromQAction (e->action ()));
00694 const int newItem = ::TrueCurrentItem (this);
00695
00696
00697
00698
00699
00700
00701 comboBox->removeItem (index);
00702
00703
00704
00705 comboBox->setCurrentIndex (newItem);
00706 }
00707
00708 comboBox->blockSignals (blocked);
00709
00710 return false;
00711 }
00712
00713
00714
00715
00716
00717
00718 #include "kselectaction.moc"