00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "k3popupmenu.h"
00021
00022 #include <QtGui/QCursor>
00023 #include <QtGui/QPainter>
00024 #include <QtCore/QTimer>
00025 #include <QtGui/QFontMetrics>
00026 #include <QKeyEvent>
00027 #include <QPointer>
00028 #include <QMenuItem>
00029
00030 #include <kdebug.h>
00031
00032 class K3PopupMenu::K3PopupMenuPrivate
00033 {
00034 public:
00035 K3PopupMenuPrivate ()
00036 : noMatches(false)
00037 , shortcuts(false)
00038 , autoExec(false)
00039 , lastHitAction(0L)
00040 #ifdef QT3_SUPPORT
00041 , state(Qt::NoButton)
00042 #endif
00043 , mouseButtons(Qt::NoButton)
00044 , keyboardModifiers(Qt::NoModifier)
00045 , m_ctxMenu(0)
00046 {}
00047
00048 ~K3PopupMenuPrivate ()
00049 {
00050 delete m_ctxMenu;
00051 }
00052
00053 QString m_lastTitle;
00054
00055
00056 QTimer clearTimer;
00057
00058 bool noMatches : 1;
00059 bool shortcuts : 1;
00060 bool autoExec : 1;
00061
00062 QString keySeq;
00063 QString originalText;
00064
00065 QAction* lastHitAction;
00066 #ifdef QT3_SUPPORT
00067 Qt::ButtonState state;
00068 Qt::MouseButtons mouseButtons;
00069 Qt::KeyboardModifiers keyboardModifiers;
00070 #endif
00071
00072
00073 Q3PopupMenu* m_ctxMenu;
00074 static bool s_continueCtxMenuShow;
00075 static QPointer<QAction> s_highlightedAction;
00076
00077 static int s_highlightedItem;
00078 static K3PopupMenu* s_contextedMenu;
00079 };
00080
00081 QPointer<QAction> K3PopupMenu::K3PopupMenuPrivate::s_highlightedAction(0L);
00082 int K3PopupMenu::K3PopupMenuPrivate::s_highlightedItem(-1);
00083 K3PopupMenu* K3PopupMenu::K3PopupMenuPrivate::s_contextedMenu(0);
00084 bool K3PopupMenu::K3PopupMenuPrivate::s_continueCtxMenuShow(true);
00085
00086 K3PopupMenu::K3PopupMenu(QWidget *parent)
00087 : Q3PopupMenu(parent)
00088 , d(new K3PopupMenuPrivate())
00089 {
00090 resetKeyboardVars();
00091 connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars()));
00092 }
00093
00094 K3PopupMenu::~K3PopupMenu()
00095 {
00096 if (K3PopupMenuPrivate::s_contextedMenu == this)
00097 {
00098 K3PopupMenuPrivate::s_contextedMenu = 0;
00099 K3PopupMenuPrivate::s_highlightedAction = 0L;
00100 K3PopupMenuPrivate::s_highlightedItem = -1;
00101 }
00102
00103 delete d;
00104 }
00105
00106 QAction* K3PopupMenu::addTitle(const QString &text, QAction* before)
00107 {
00108 QAction* action = new QAction(text, this);
00109 action->setEnabled(false);
00110 QFont f = action->font();
00111 f.setBold(true);
00112 action->setFont(f);
00113 insertAction(before, action);
00114 return action;
00115 }
00116
00117 QAction* K3PopupMenu::addTitle(const QIcon &icon, const QString &text, QAction* before)
00118 {
00119 QAction* action = new QAction(icon, text, this);
00120 action->setEnabled(false);
00121 QFont f = action->font();
00122 f.setBold(true);
00123 action->setFont(f);
00124 insertAction(before, action);
00125 return action;
00126 }
00127
00131 void K3PopupMenu::closeEvent(QCloseEvent*e)
00132 {
00133 if (d->shortcuts)
00134 resetKeyboardVars();
00135 Q3PopupMenu::closeEvent(e);
00136 }
00137
00138 void K3PopupMenu::activateItemAt(int index)
00139 {
00140 #ifdef QT3_SUPPORT
00141 d->state = Qt::NoButton;
00142 #endif
00143 d->mouseButtons = Qt::NoButton;
00144 d->keyboardModifiers = Qt::NoModifier;
00145 Q3PopupMenu::activateItemAt(index);
00146 }
00147
00148 #ifdef QT3_SUPPORT
00149 Qt::ButtonState K3PopupMenu::state() const
00150 {
00151 return d->state;
00152 }
00153 #endif
00154
00155 Qt::MouseButtons K3PopupMenu::mouseButtons() const
00156 {
00157 return d->mouseButtons;
00158 }
00159
00160 Qt::KeyboardModifiers K3PopupMenu::keyboardModifiers() const
00161 {
00162 return d->keyboardModifiers;
00163 }
00164
00165 void K3PopupMenu::keyPressEvent(QKeyEvent* e)
00166 {
00167 #ifdef QT3_SUPPORT
00168 d->state = Qt::NoButton;
00169 #endif
00170 d->mouseButtons = Qt::NoButton;
00171 d->keyboardModifiers = Qt::NoModifier;
00172 if (!d->shortcuts) {
00173
00174
00175 #ifdef QT3_SUPPORT
00176 d->state = e->state();
00177 #endif
00178 d->keyboardModifiers = e->modifiers();
00179 Q3PopupMenu::keyPressEvent(e);
00180 return;
00181 }
00182
00183 QAction* a = 0L;
00184 bool firstpass = true;
00185 QString keyString = e->text();
00186
00187
00188 int key = e->key();
00189 if (key == Qt::Key_Escape || key == Qt::Key_Return || key == Qt::Key_Enter
00190 || key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_Left
00191 || key == Qt::Key_Right || key == Qt::Key_F1) {
00192
00193 resetKeyboardVars();
00194
00195
00196 #ifdef QT3_SUPPORT
00197 d->state = e->state();
00198 #endif
00199 d->keyboardModifiers = e->modifiers();
00200 Q3PopupMenu::keyPressEvent(e);
00201 return;
00202 } else if ( key == Qt::Key_Shift || key == Qt::Key_Control || key == Qt::Key_Alt || key == Qt::Key_Meta )
00203 return Q3PopupMenu::keyPressEvent(e);
00204
00205
00206
00207 if (!d->keySeq.isNull()) {
00208 if (key == Qt::Key_Backspace) {
00209
00210 if (d->keySeq.length() == 1) {
00211 resetKeyboardVars();
00212 return;
00213 }
00214
00215
00216 keyString = d->keySeq.left(d->keySeq.length() - 1);
00217
00218
00219 resetKeyboardVars();
00220
00221 } else if (key == Qt::Key_Delete) {
00222 resetKeyboardVars();
00223
00224
00225 setActiveAction(0L);
00226 return;
00227
00228 } else if (d->noMatches) {
00229
00230 resetKeyboardVars();
00231
00232
00233 setActiveAction(0L);
00234
00235 } else {
00236
00237
00238 a = d->lastHitAction;
00239 }
00240
00241 } else if (key == Qt::Key_Backspace && menuAction()) {
00242
00243 hide();
00244 resetKeyboardVars();
00245 return;
00246 }
00247
00248 d->keySeq += keyString;
00249 int seqLen = d->keySeq.length();
00250
00251 foreach (a, actions()) {
00252
00253 if (!a->isEnabled())
00254 continue;
00255
00256 QString thisText;
00257
00258
00259
00260 if (a == d->lastHitAction)
00261 thisText = d->originalText;
00262 else
00263 thisText = a->text();
00264
00265
00266 thisText = thisText.remove("&");
00267
00268
00269 thisText = thisText.left(seqLen);
00270
00271
00272 if (!thisText.contains(d->keySeq, Qt::CaseInsensitive)) {
00273
00274 if (firstpass) {
00275
00276 setActiveAction(a);
00277
00278
00279 if (d->lastHitAction != a)
00280
00281 d->lastHitAction->setText(d->originalText);
00282
00283
00284 if (d->lastHitAction != a || d->lastHitAction == 0L)
00285 d->originalText = a->text();
00286
00287
00288 a->setText(underlineText(d->originalText, d->keySeq.length()));
00289
00290
00291 d->lastHitAction = a;
00292
00293
00294 d->clearTimer.start(5000, true);
00295
00296
00297 firstpass = false;
00298 } else {
00299
00300 return;
00301 }
00302 }
00303
00304
00305 }
00306
00307 if (!firstpass) {
00308 if (d->autoExec) {
00309
00310 d->lastHitAction->activate(QAction::Trigger);
00311 resetKeyboardVars();
00312
00313 } else if (d->lastHitAction && d->lastHitAction->menu()) {
00314
00315 d->lastHitAction->activate(QAction::Trigger);
00316 resetKeyboardVars();
00317 }
00318
00319 return;
00320 }
00321
00322
00323 resetKeyboardVars(true);
00324
00325 Q3PopupMenu::keyPressEvent(e);
00326 }
00327
00328 bool K3PopupMenu::focusNextPrevChild( bool next )
00329 {
00330 resetKeyboardVars();
00331 return Q3PopupMenu::focusNextPrevChild( next );
00332 }
00333
00334 QString K3PopupMenu::underlineText(const QString& text, uint length)
00335 {
00336 QString ret = text;
00337 for (uint i = 0; i < length; i++) {
00338 if (ret[2*i] != '&')
00339 ret.insert(2*i, "&");
00340 }
00341 return ret;
00342 }
00343
00344 void K3PopupMenu::resetKeyboardVars(bool noMatches )
00345 {
00346
00347 if (d->lastHitAction) {
00348 d->lastHitAction->setText(d->originalText);
00349 d->lastHitAction = 0L;
00350 }
00351
00352 if (!noMatches) {
00353 d->keySeq.clear();
00354 }
00355
00356 d->noMatches = noMatches;
00357 }
00358
00359 void K3PopupMenu::setKeyboardShortcutsEnabled(bool enable)
00360 {
00361 d->shortcuts = enable;
00362 }
00363
00364 void K3PopupMenu::setKeyboardShortcutsExecute(bool enable)
00365 {
00366 d->autoExec = enable;
00367 }
00376 void K3PopupMenu::mousePressEvent(QMouseEvent* e)
00377 {
00378 if (d->m_ctxMenu && d->m_ctxMenu->isVisible())
00379 {
00380
00381 d->m_ctxMenu->hide();
00382 }
00383
00384 Q3PopupMenu::mousePressEvent(e);
00385 }
00386
00387 void K3PopupMenu::mouseReleaseEvent(QMouseEvent* e)
00388 {
00389 #ifdef QT3_SUPPORT
00390
00391 d->state = Qt::ButtonState(e->button() | (e->state() & Qt::KeyboardModifierMask));
00392 #endif
00393
00394 d->keyboardModifiers = e->modifiers();
00395 d->mouseButtons = e->buttons();
00396
00397 if ( !d->m_ctxMenu || !d->m_ctxMenu->isVisible() )
00398 Q3PopupMenu::mouseReleaseEvent(e);
00399 }
00400
00401 Q3PopupMenu* K3PopupMenu::contextMenu()
00402 {
00403 if (!d->m_ctxMenu)
00404 {
00405 d->m_ctxMenu = new Q3PopupMenu(this);
00406 connect(d->m_ctxMenu, SIGNAL(aboutToHide()), this, SLOT(ctxMenuHiding()));
00407 }
00408
00409 return d->m_ctxMenu;
00410 }
00411
00412 const Q3PopupMenu* K3PopupMenu::contextMenu() const
00413 {
00414 return const_cast< K3PopupMenu* >( this )->contextMenu();
00415 }
00416
00417 void K3PopupMenu::hideContextMenu()
00418 {
00419 K3PopupMenuPrivate::s_continueCtxMenuShow = false;
00420 }
00421
00422 QAction* K3PopupMenu::contextMenuFocusAction()
00423 {
00424 return K3PopupMenuPrivate::s_highlightedAction;
00425 }
00426
00427 K3PopupMenu* K3PopupMenu::contextMenuFocus()
00428 {
00429 return K3PopupMenuPrivate::s_contextedMenu;
00430 }
00431
00432 void K3PopupMenu::actionHovered(QAction* action)
00433 {
00434 if (!d->m_ctxMenu || !d->m_ctxMenu->isVisible())
00435 {
00436 return;
00437 }
00438
00439 d->m_ctxMenu->hide();
00440 showCtxMenu(actionGeometry(action).center());
00441 }
00442
00443 void K3PopupMenu::showCtxMenu(const QPoint &pos)
00444 {
00445 if (K3PopupMenuPrivate::s_highlightedAction)
00446 if (QMenu* subMenu = K3PopupMenuPrivate::s_highlightedAction->menu())
00447 disconnect(subMenu, SIGNAL(aboutToShow()), this, SLOT(ctxMenuHideShowingMenu()));
00448
00449 K3PopupMenuPrivate::s_highlightedAction = activeAction();
00450 K3PopupMenuPrivate::s_highlightedItem = itemAtPos(pos);
00451
00452 if (!K3PopupMenuPrivate::s_highlightedAction)
00453 {
00454 K3PopupMenuPrivate::s_contextedMenu = 0;
00455 return;
00456 }
00457
00458 emit aboutToShowContextMenu(this, K3PopupMenuPrivate::s_highlightedAction, d->m_ctxMenu);
00459 emit aboutToShowContextMenu(this, K3PopupMenuPrivate::s_highlightedItem, d->m_ctxMenu);
00460
00461 if (QMenu* subMenu = K3PopupMenuPrivate::s_highlightedAction->menu())
00462 {
00463 connect(subMenu, SIGNAL(aboutToShow()), SLOT(ctxMenuHideShowingMenu()));
00464 QTimer::singleShot(100, subMenu, SLOT(hide()));
00465 }
00466
00467 if (!K3PopupMenuPrivate::s_continueCtxMenuShow)
00468 {
00469 K3PopupMenuPrivate::s_continueCtxMenuShow = true;
00470 return;
00471 }
00472
00473 K3PopupMenuPrivate::s_contextedMenu = this;
00474 d->m_ctxMenu->exec(this->mapToGlobal(pos));
00475 connect(this, SIGNAL(hovered(QAction*)), SLOT(actionHovered(QAction*)));
00476 }
00477
00478
00479
00480
00481
00482 void K3PopupMenu::ctxMenuHideShowingMenu()
00483 {
00484 if (K3PopupMenuPrivate::s_highlightedAction)
00485 if (QMenu* subMenu = K3PopupMenuPrivate::s_highlightedAction->menu())
00486 QTimer::singleShot(0, subMenu, SLOT(hide()));
00487 }
00488
00489 void K3PopupMenu::ctxMenuHiding()
00490 {
00491 if (K3PopupMenuPrivate::s_highlightedAction)
00492 if (QMenu* subMenu = K3PopupMenuPrivate::s_highlightedAction->menu())
00493 disconnect(subMenu, SIGNAL(aboutToShow()), this, SLOT(ctxMenuHideShowingMenu()));
00494
00495 connect(this, SIGNAL(hovered(QAction*)), this, SLOT(actionHovered(QAction*)));
00496 K3PopupMenuPrivate::s_continueCtxMenuShow = true;
00497 }
00498
00499 void K3PopupMenu::contextMenuEvent(QContextMenuEvent* e)
00500 {
00501 if (d->m_ctxMenu)
00502 {
00503 if (e->reason() == QContextMenuEvent::Mouse)
00504 {
00505 showCtxMenu(e->pos());
00506 }
00507 else if (activeAction())
00508 {
00509 showCtxMenu(actionGeometry(activeAction()).center());
00510 }
00511
00512 e->accept();
00513 return;
00514 }
00515
00516 Q3PopupMenu::contextMenuEvent(e);
00517 }
00518
00519 void K3PopupMenu::hideEvent(QHideEvent *e)
00520 {
00521 if (d->m_ctxMenu && d->m_ctxMenu->isVisible())
00522 {
00523
00524
00525
00526
00527
00528
00529
00530
00531 bool blocked = blockSignals(true);
00532 d->m_ctxMenu->hide();
00533 blockSignals(blocked);
00534 }
00535 Q3PopupMenu::hideEvent(e);
00536 }
00541 void K3PopupMenu::virtual_hook( int, void* )
00542 { }
00543
00544
00545 K3PopupMenu::K3PopupMenu(const QString &title, QWidget *parent)
00546 : Q3PopupMenu(parent)
00547 , d(new K3PopupMenuPrivate())
00548 {
00549 resetKeyboardVars();
00550 connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars()));
00551 addAction(title);
00552 }
00553
00554 #ifdef QT3_SUPPORT
00555 int K3PopupMenu::insertTitle(const QString &text, int id, int index)
00556 {
00557 int newid = insertItem(text, id, index);
00558 QMenuItem* menuItem = findItem(newid);
00559 Q_ASSERT(menuItem);
00560 menuItem->setEnabled(false);
00561 QFont f = menuItem->font();
00562 f.setBold(true);
00563 menuItem->setFont(f);
00564 return newid;
00565 }
00566
00567 int K3PopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id, int index)
00568 {
00569 int newid = insertItem(text, id, index);
00570 QMenuItem* menuItem = findItem(newid);
00571 Q_ASSERT(menuItem);
00572 menuItem->setEnabled(false);
00573 menuItem->setIcon(icon);
00574 QFont f = menuItem->font();
00575 f.setBold(true);
00576 menuItem->setFont(f);
00577 return newid;
00578 }
00579
00580 void K3PopupMenu::changeTitle(int id, const QString &text)
00581 {
00582 QMenuItem* menuItem = findItem(id);
00583 Q_ASSERT(menuItem);
00584 if (!menuItem)
00585 return;
00586 menuItem->setText(text);
00587 menuItem->setIcon(QIcon());
00588 return;
00589 }
00590
00591 void K3PopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text)
00592 {
00593 QMenuItem* menuItem = findItem(id);
00594 Q_ASSERT(menuItem);
00595 if (!menuItem)
00596 return;
00597 menuItem->setText(text);
00598 menuItem->setIcon(icon);
00599 return;
00600 }
00601
00602 QString K3PopupMenu::title(int id) const
00603 {
00604 QMenuItem* menuItem = findItem(id);
00605 Q_ASSERT(menuItem);
00606 if (!menuItem)
00607 return QString();
00608 return menuItem->text();
00609 }
00610
00611 QPixmap K3PopupMenu::titlePixmap(int id) const
00612 {
00613 QMenuItem* menuItem = findItem(id);
00614 Q_ASSERT(menuItem);
00615 if (!menuItem)
00616 return QPixmap();
00617 return menuItem->icon().pixmap();
00618 }
00619
00620 void K3PopupMenu::setTitle(const QString &title)
00621 {
00622 addAction(title);
00623 }
00624
00625 int K3PopupMenu::contextMenuFocusItem()
00626 {
00627 return K3PopupMenuPrivate::s_highlightedItem;
00628 }
00629
00630 #endif // END compat methods
00631
00632 #include "k3popupmenu.moc"