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