You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
690 lines
18 KiB
690 lines
18 KiB
15 years ago
|
/* This file is part of the KDE libraries
|
||
|
Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org>
|
||
|
Copyright (C) 2002 Hamish Rodda <rodda@kde.org>
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Library General Public
|
||
|
License version 2 as published by the Free Software Foundation.
|
||
|
|
||
|
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
|
||
|
Library General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Library General Public License
|
||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
Boston, MA 02110-1301, USA.
|
||
|
*/
|
||
|
#include <qcursor.h>
|
||
|
#include <qpainter.h>
|
||
|
#include <qtimer.h>
|
||
|
#include <qfontmetrics.h>
|
||
|
#include <qstyle.h>
|
||
|
|
||
|
#include "kpopupmenu.h"
|
||
|
|
||
|
#include <kdebug.h>
|
||
|
#include <kapplication.h>
|
||
|
|
||
|
KPopupTitle::KPopupTitle(QWidget *parent, const char *name)
|
||
|
: QWidget(parent, name)
|
||
|
{
|
||
|
setMinimumSize(16, fontMetrics().height()+8);
|
||
|
}
|
||
|
|
||
|
KPopupTitle::KPopupTitle(KPixmapEffect::GradientType /* gradient */,
|
||
|
const QColor &/* color */, const QColor &/* textColor */,
|
||
|
QWidget *parent, const char *name)
|
||
|
: QWidget(parent, name)
|
||
|
{
|
||
|
calcSize();
|
||
|
}
|
||
|
|
||
|
KPopupTitle::KPopupTitle(const KPixmap & /* background */, const QColor &/* color */,
|
||
|
const QColor &/* textColor */, QWidget *parent,
|
||
|
const char *name)
|
||
|
: QWidget(parent, name)
|
||
|
{
|
||
|
calcSize();
|
||
|
}
|
||
|
|
||
|
void KPopupTitle::setTitle(const QString &text, const QPixmap *icon)
|
||
|
{
|
||
|
titleStr = text;
|
||
|
if (icon)
|
||
|
miniicon = *icon;
|
||
|
else
|
||
|
miniicon.resize(0, 0);
|
||
|
|
||
|
calcSize();
|
||
|
}
|
||
|
|
||
|
void KPopupTitle::setText( const QString &text )
|
||
|
{
|
||
|
titleStr = text;
|
||
|
calcSize();
|
||
|
}
|
||
|
|
||
|
void KPopupTitle::setIcon( const QPixmap &pix )
|
||
|
{
|
||
|
miniicon = pix;
|
||
|
calcSize();
|
||
|
}
|
||
|
|
||
|
void KPopupTitle::calcSize()
|
||
|
{
|
||
|
QFont f = font();
|
||
|
f.setBold(true);
|
||
|
int w = miniicon.width()+QFontMetrics(f).width(titleStr);
|
||
|
int h = QMAX( fontMetrics().height(), miniicon.height() );
|
||
|
setMinimumSize( w+16, h+8 );
|
||
|
}
|
||
|
|
||
|
void KPopupTitle::paintEvent(QPaintEvent *)
|
||
|
{
|
||
|
QRect r(rect());
|
||
|
QPainter p(this);
|
||
|
kapp->style().drawPrimitive(QStyle::PE_HeaderSection, &p, r, palette().active());
|
||
|
|
||
|
if (!miniicon.isNull())
|
||
|
p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon);
|
||
|
|
||
|
if (!titleStr.isNull())
|
||
|
{
|
||
|
p.setPen(palette().active().text());
|
||
|
QFont f = p.font();
|
||
|
f.setBold(true);
|
||
|
p.setFont(f);
|
||
|
if(!miniicon.isNull())
|
||
|
{
|
||
|
p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8),
|
||
|
height(), AlignLeft | AlignVCenter | SingleLine,
|
||
|
titleStr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p.drawText(0, 0, width(), height(),
|
||
|
AlignCenter | SingleLine, titleStr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QSize KPopupTitle::sizeHint() const
|
||
|
{
|
||
|
return minimumSize();
|
||
|
}
|
||
|
|
||
|
class KPopupMenu::KPopupMenuPrivate
|
||
|
{
|
||
|
public:
|
||
|
KPopupMenuPrivate ()
|
||
|
: noMatches(false)
|
||
|
, shortcuts(false)
|
||
|
, autoExec(false)
|
||
|
, lastHitIndex(-1)
|
||
|
, state(Qt::NoButton)
|
||
|
, m_ctxMenu(0)
|
||
|
{}
|
||
|
|
||
|
~KPopupMenuPrivate ()
|
||
|
{
|
||
|
delete m_ctxMenu;
|
||
|
}
|
||
|
|
||
|
QString m_lastTitle;
|
||
|
|
||
|
// variables for keyboard navigation
|
||
|
QTimer clearTimer;
|
||
|
|
||
|
bool noMatches : 1;
|
||
|
bool shortcuts : 1;
|
||
|
bool autoExec : 1;
|
||
|
|
||
|
QString keySeq;
|
||
|
QString originalText;
|
||
|
|
||
|
int lastHitIndex;
|
||
|
Qt::ButtonState state;
|
||
|
|
||
|
// support for RMB menus on menus
|
||
|
QPopupMenu* m_ctxMenu;
|
||
|
static bool s_continueCtxMenuShow;
|
||
|
static int s_highlightedItem;
|
||
|
static KPopupMenu* s_contextedMenu;
|
||
|
};
|
||
|
|
||
|
int KPopupMenu::KPopupMenuPrivate::s_highlightedItem(-1);
|
||
|
KPopupMenu* KPopupMenu::KPopupMenuPrivate::s_contextedMenu(0);
|
||
|
bool KPopupMenu::KPopupMenuPrivate::s_continueCtxMenuShow(true);
|
||
|
|
||
|
KPopupMenu::KPopupMenu(QWidget *parent, const char *name)
|
||
|
: QPopupMenu(parent, name)
|
||
|
{
|
||
|
d = new KPopupMenuPrivate;
|
||
|
resetKeyboardVars();
|
||
|
connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars()));
|
||
|
}
|
||
|
|
||
|
KPopupMenu::~KPopupMenu()
|
||
|
{
|
||
|
if (KPopupMenuPrivate::s_contextedMenu == this)
|
||
|
{
|
||
|
KPopupMenuPrivate::s_contextedMenu = 0;
|
||
|
KPopupMenuPrivate::s_highlightedItem = -1;
|
||
|
}
|
||
|
|
||
|
delete d;
|
||
|
}
|
||
|
|
||
|
int KPopupMenu::insertTitle(const QString &text, int id, int index)
|
||
|
{
|
||
|
KPopupTitle *titleItem = new KPopupTitle();
|
||
|
titleItem->setTitle(text);
|
||
|
int ret = insertItem(titleItem, id, index);
|
||
|
setItemEnabled(ret, false);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int KPopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id,
|
||
|
int index)
|
||
|
{
|
||
|
KPopupTitle *titleItem = new KPopupTitle();
|
||
|
titleItem->setTitle(text, &icon);
|
||
|
int ret = insertItem(titleItem, id, index);
|
||
|
setItemEnabled(ret, false);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::changeTitle(int id, const QString &text)
|
||
|
{
|
||
|
QMenuItem *item = findItem(id);
|
||
|
if(item){
|
||
|
if(item->widget())
|
||
|
((KPopupTitle *)item->widget())->setTitle(text);
|
||
|
#ifndef NDEBUG
|
||
|
else
|
||
|
kdWarning() << "KPopupMenu: changeTitle() called with non-title id "<< id << endl;
|
||
|
#endif
|
||
|
}
|
||
|
#ifndef NDEBUG
|
||
|
else
|
||
|
kdWarning() << "KPopupMenu: changeTitle() called with invalid id " << id << endl;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text)
|
||
|
{
|
||
|
QMenuItem *item = findItem(id);
|
||
|
if(item){
|
||
|
if(item->widget())
|
||
|
((KPopupTitle *)item->widget())->setTitle(text, &icon);
|
||
|
#ifndef NDEBUG
|
||
|
else
|
||
|
kdWarning() << "KPopupMenu: changeTitle() called with non-title id "<< id << endl;
|
||
|
#endif
|
||
|
}
|
||
|
#ifndef NDEBUG
|
||
|
else
|
||
|
kdWarning() << "KPopupMenu: changeTitle() called with invalid id " << id << endl;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
QString KPopupMenu::title(int id) const
|
||
|
{
|
||
|
if(id == -1) // obsolete
|
||
|
return d->m_lastTitle;
|
||
|
QMenuItem *item = findItem(id);
|
||
|
if(item){
|
||
|
if(item->widget())
|
||
|
return ((KPopupTitle *)item->widget())->title();
|
||
|
else
|
||
|
qWarning("KPopupMenu: title() called with non-title id %d.", id);
|
||
|
}
|
||
|
else
|
||
|
qWarning("KPopupMenu: title() called with invalid id %d.", id);
|
||
|
return QString::null;
|
||
|
}
|
||
|
|
||
|
QPixmap KPopupMenu::titlePixmap(int id) const
|
||
|
{
|
||
|
QMenuItem *item = findItem(id);
|
||
|
if(item){
|
||
|
if(item->widget())
|
||
|
return ((KPopupTitle *)item->widget())->icon();
|
||
|
else
|
||
|
qWarning("KPopupMenu: titlePixmap() called with non-title id %d.", id);
|
||
|
}
|
||
|
else
|
||
|
qWarning("KPopupMenu: titlePixmap() called with invalid id %d.", id);
|
||
|
QPixmap tmp;
|
||
|
return tmp;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This is re-implemented for keyboard navigation.
|
||
|
*/
|
||
|
void KPopupMenu::closeEvent(QCloseEvent*e)
|
||
|
{
|
||
|
if (d->shortcuts)
|
||
|
resetKeyboardVars();
|
||
|
QPopupMenu::closeEvent(e);
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::activateItemAt(int index)
|
||
|
{
|
||
|
d->state = Qt::NoButton;
|
||
|
QPopupMenu::activateItemAt(index);
|
||
|
}
|
||
|
|
||
|
Qt::ButtonState KPopupMenu::state() const
|
||
|
{
|
||
|
return d->state;
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::keyPressEvent(QKeyEvent* e)
|
||
|
{
|
||
|
d->state = Qt::NoButton;
|
||
|
if (!d->shortcuts) {
|
||
|
// continue event processing by Qpopup
|
||
|
//e->ignore();
|
||
|
d->state = e->state();
|
||
|
QPopupMenu::keyPressEvent(e);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int i = 0;
|
||
|
bool firstpass = true;
|
||
|
QString keyString = e->text();
|
||
|
|
||
|
// check for common commands dealt with by QPopup
|
||
|
int key = e->key();
|
||
|
if (key == Key_Escape || key == Key_Return || key == Key_Enter
|
||
|
|| key == Key_Up || key == Key_Down || key == Key_Left
|
||
|
|| key == Key_Right || key == Key_F1) {
|
||
|
|
||
|
resetKeyboardVars();
|
||
|
// continue event processing by Qpopup
|
||
|
//e->ignore();
|
||
|
d->state = e->state();
|
||
|
QPopupMenu::keyPressEvent(e);
|
||
|
return;
|
||
|
} else if ( key == Key_Shift || key == Key_Control || key == Key_Alt || key == Key_Meta )
|
||
|
return QPopupMenu::keyPressEvent(e);
|
||
|
|
||
|
// check to see if the user wants to remove a key from the sequence (backspace)
|
||
|
// or clear the sequence (delete)
|
||
|
if (!d->keySeq.isNull()) {
|
||
|
|
||
|
if (key == Key_Backspace) {
|
||
|
|
||
|
if (d->keySeq.length() == 1) {
|
||
|
resetKeyboardVars();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// keep the last sequence in keyString
|
||
|
keyString = d->keySeq.left(d->keySeq.length() - 1);
|
||
|
|
||
|
// allow sequence matching to be tried again
|
||
|
resetKeyboardVars();
|
||
|
|
||
|
} else if (key == Key_Delete) {
|
||
|
resetKeyboardVars();
|
||
|
|
||
|
// clear active item
|
||
|
setActiveItem(0);
|
||
|
return;
|
||
|
|
||
|
} else if (d->noMatches) {
|
||
|
// clear if there are no matches
|
||
|
resetKeyboardVars();
|
||
|
|
||
|
// clear active item
|
||
|
setActiveItem(0);
|
||
|
|
||
|
} else {
|
||
|
// the key sequence is not a null string
|
||
|
// therefore the lastHitIndex is valid
|
||
|
i = d->lastHitIndex;
|
||
|
}
|
||
|
} else if (key == Key_Backspace && parentMenu) {
|
||
|
// backspace with no chars in the buffer... go back a menu.
|
||
|
hide();
|
||
|
resetKeyboardVars();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
d->keySeq += keyString;
|
||
|
int seqLen = d->keySeq.length();
|
||
|
|
||
|
for (; i < (int)count(); i++) {
|
||
|
// compare typed text with text of this entry
|
||
|
int j = idAt(i);
|
||
|
|
||
|
// don't search disabled entries
|
||
|
if (!isItemEnabled(j))
|
||
|
continue;
|
||
|
|
||
|
QString thisText;
|
||
|
|
||
|
// retrieve the right text
|
||
|
// (the last selected item one may have additional ampersands)
|
||
|
if (i == d->lastHitIndex)
|
||
|
thisText = d->originalText;
|
||
|
else
|
||
|
thisText = text(j);
|
||
|
|
||
|
// if there is an accelerator present, remove it
|
||
|
if ((int)accel(j) != 0)
|
||
|
thisText = thisText.replace("&", QString::null);
|
||
|
|
||
|
// chop text to the search length
|
||
|
thisText = thisText.left(seqLen);
|
||
|
|
||
|
// do the search
|
||
|
if (!thisText.find(d->keySeq, 0, false)) {
|
||
|
|
||
|
if (firstpass) {
|
||
|
// match
|
||
|
setActiveItem(i);
|
||
|
|
||
|
// check to see if we're underlining a different item
|
||
|
if (d->lastHitIndex != i)
|
||
|
// yes; revert the underlining
|
||
|
changeItem(idAt(d->lastHitIndex), d->originalText);
|
||
|
|
||
|
// set the original text if it's a different item
|
||
|
if (d->lastHitIndex != i || d->lastHitIndex == -1)
|
||
|
d->originalText = text(j);
|
||
|
|
||
|
// underline the currently selected item
|
||
|
changeItem(j, underlineText(d->originalText, d->keySeq.length()));
|
||
|
|
||
|
// remember what's going on
|
||
|
d->lastHitIndex = i;
|
||
|
|
||
|
// start/restart the clear timer
|
||
|
d->clearTimer.start(5000, true);
|
||
|
|
||
|
// go around for another try, to see if we can execute
|
||
|
firstpass = false;
|
||
|
} else {
|
||
|
// don't allow execution
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// fall through to allow execution
|
||
|
}
|
||
|
|
||
|
if (!firstpass) {
|
||
|
if (d->autoExec) {
|
||
|
// activate anything
|
||
|
activateItemAt(d->lastHitIndex);
|
||
|
resetKeyboardVars();
|
||
|
|
||
|
} else if (findItem(idAt(d->lastHitIndex)) &&
|
||
|
findItem(idAt(d->lastHitIndex))->popup()) {
|
||
|
// only activate sub-menus
|
||
|
activateItemAt(d->lastHitIndex);
|
||
|
resetKeyboardVars();
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// no matches whatsoever, clean up
|
||
|
resetKeyboardVars(true);
|
||
|
//e->ignore();
|
||
|
QPopupMenu::keyPressEvent(e);
|
||
|
}
|
||
|
|
||
|
bool KPopupMenu::focusNextPrevChild( bool next )
|
||
|
{
|
||
|
resetKeyboardVars();
|
||
|
return QPopupMenu::focusNextPrevChild( next );
|
||
|
}
|
||
|
|
||
|
QString KPopupMenu::underlineText(const QString& text, uint length)
|
||
|
{
|
||
|
QString ret = text;
|
||
|
for (uint i = 0; i < length; i++) {
|
||
|
if (ret[2*i] != '&')
|
||
|
ret.insert(2*i, "&");
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::resetKeyboardVars(bool noMatches /* = false */)
|
||
|
{
|
||
|
// Clean up keyboard variables
|
||
|
if (d->lastHitIndex != -1) {
|
||
|
changeItem(idAt(d->lastHitIndex), d->originalText);
|
||
|
d->lastHitIndex = -1;
|
||
|
}
|
||
|
|
||
|
if (!noMatches) {
|
||
|
d->keySeq = QString::null;
|
||
|
}
|
||
|
|
||
|
d->noMatches = noMatches;
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::setKeyboardShortcutsEnabled(bool enable)
|
||
|
{
|
||
|
d->shortcuts = enable;
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::setKeyboardShortcutsExecute(bool enable)
|
||
|
{
|
||
|
d->autoExec = enable;
|
||
|
}
|
||
|
/**
|
||
|
* End keyboard navigation.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* RMB menus on menus
|
||
|
*/
|
||
|
|
||
|
void KPopupMenu::mousePressEvent(QMouseEvent* e)
|
||
|
{
|
||
|
if (d->m_ctxMenu && d->m_ctxMenu->isVisible())
|
||
|
{
|
||
|
// hide on a second context menu event
|
||
|
d->m_ctxMenu->hide();
|
||
|
}
|
||
|
|
||
|
QPopupMenu::mousePressEvent(e);
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::mouseReleaseEvent(QMouseEvent* e)
|
||
|
{
|
||
|
// Save the button, and the modifiers from state()
|
||
|
d->state = Qt::ButtonState(e->button() | (e->state() & KeyButtonMask));
|
||
|
|
||
|
if ( !d->m_ctxMenu || !d->m_ctxMenu->isVisible() )
|
||
|
QPopupMenu::mouseReleaseEvent(e);
|
||
|
}
|
||
|
|
||
|
QPopupMenu* KPopupMenu::contextMenu()
|
||
|
{
|
||
|
if (!d->m_ctxMenu)
|
||
|
{
|
||
|
d->m_ctxMenu = new QPopupMenu(this);
|
||
|
connect(d->m_ctxMenu, SIGNAL(aboutToHide()), this, SLOT(ctxMenuHiding()));
|
||
|
}
|
||
|
|
||
|
return d->m_ctxMenu;
|
||
|
}
|
||
|
|
||
|
const QPopupMenu* KPopupMenu::contextMenu() const
|
||
|
{
|
||
|
return const_cast< KPopupMenu* >( this )->contextMenu();
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::hideContextMenu()
|
||
|
{
|
||
|
KPopupMenuPrivate::s_continueCtxMenuShow = false;
|
||
|
}
|
||
|
|
||
|
int KPopupMenu::contextMenuFocusItem()
|
||
|
{
|
||
|
return KPopupMenuPrivate::s_highlightedItem;
|
||
|
}
|
||
|
|
||
|
KPopupMenu* KPopupMenu::contextMenuFocus()
|
||
|
{
|
||
|
return KPopupMenuPrivate::s_contextedMenu;
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::itemHighlighted(int /* whichItem */)
|
||
|
{
|
||
|
if (!d->m_ctxMenu || !d->m_ctxMenu->isVisible())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
d->m_ctxMenu->hide();
|
||
|
showCtxMenu(mapFromGlobal(QCursor::pos()));
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::showCtxMenu(QPoint pos)
|
||
|
{
|
||
|
QMenuItem* item = findItem(KPopupMenuPrivate::s_highlightedItem);
|
||
|
if (item)
|
||
|
{
|
||
|
QPopupMenu* subMenu = item->popup();
|
||
|
if (subMenu)
|
||
|
{
|
||
|
disconnect(subMenu, SIGNAL(aboutToShow()), this, SLOT(ctxMenuHideShowingMenu()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
KPopupMenuPrivate::s_highlightedItem = idAt(pos);
|
||
|
|
||
|
if (KPopupMenuPrivate::s_highlightedItem == -1)
|
||
|
{
|
||
|
KPopupMenuPrivate::s_contextedMenu = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
emit aboutToShowContextMenu(this, KPopupMenuPrivate::s_highlightedItem, d->m_ctxMenu);
|
||
|
|
||
|
QPopupMenu* subMenu = findItem(KPopupMenuPrivate::s_highlightedItem)->popup();
|
||
|
if (subMenu)
|
||
|
{
|
||
|
connect(subMenu, SIGNAL(aboutToShow()), SLOT(ctxMenuHideShowingMenu()));
|
||
|
QTimer::singleShot(100, subMenu, SLOT(hide()));
|
||
|
}
|
||
|
|
||
|
if (!KPopupMenuPrivate::s_continueCtxMenuShow)
|
||
|
{
|
||
|
KPopupMenuPrivate::s_continueCtxMenuShow = true;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
KPopupMenuPrivate::s_contextedMenu = this;
|
||
|
d->m_ctxMenu->popup(this->mapToGlobal(pos));
|
||
|
connect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int)));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* this method helps prevent submenus popping up while we have a context menu
|
||
|
* showing
|
||
|
*/
|
||
|
void KPopupMenu::ctxMenuHideShowingMenu()
|
||
|
{
|
||
|
QMenuItem* item = findItem(KPopupMenuPrivate::s_highlightedItem);
|
||
|
if (item)
|
||
|
{
|
||
|
QPopupMenu* subMenu = item->popup();
|
||
|
if (subMenu)
|
||
|
{
|
||
|
QTimer::singleShot(0, subMenu, SLOT(hide()));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::ctxMenuHiding()
|
||
|
{
|
||
|
if (KPopupMenuPrivate::s_highlightedItem)
|
||
|
{
|
||
|
QPopupMenu* subMenu = findItem(KPopupMenuPrivate::s_highlightedItem)->popup();
|
||
|
if (subMenu)
|
||
|
{
|
||
|
disconnect(subMenu, SIGNAL(aboutToShow()), this, SLOT(ctxMenuHideShowingMenu()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
disconnect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int)));
|
||
|
KPopupMenuPrivate::s_continueCtxMenuShow = true;
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::contextMenuEvent(QContextMenuEvent* e)
|
||
|
{
|
||
|
if (d->m_ctxMenu)
|
||
|
{
|
||
|
if (e->reason() == QContextMenuEvent::Mouse)
|
||
|
{
|
||
|
showCtxMenu(e->pos());
|
||
|
}
|
||
|
else if (actItem != -1)
|
||
|
{
|
||
|
showCtxMenu(itemGeometry(actItem).center());
|
||
|
}
|
||
|
|
||
|
e->accept();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
QPopupMenu::contextMenuEvent(e);
|
||
|
}
|
||
|
|
||
|
void KPopupMenu::hideEvent(QHideEvent*)
|
||
|
{
|
||
|
if (d->m_ctxMenu && d->m_ctxMenu->isVisible())
|
||
|
{
|
||
|
// we need to block signals here when the ctxMenu is showing
|
||
|
// to prevent the QPopupMenu::activated(int) signal from emitting
|
||
|
// when hiding with a context menu, the user doesn't expect the
|
||
|
// menu to actually do anything.
|
||
|
// since hideEvent gets called very late in the process of hiding
|
||
|
// (deep within QWidget::hide) the activated(int) signal is the
|
||
|
// last signal to be emitted, even after things like aboutToHide()
|
||
|
// AJS
|
||
|
blockSignals(true);
|
||
|
d->m_ctxMenu->hide();
|
||
|
blockSignals(false);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* end of RMB menus on menus support
|
||
|
*/
|
||
|
|
||
|
// Obsolete
|
||
|
KPopupMenu::KPopupMenu(const QString& title, QWidget *parent, const char *name)
|
||
|
: QPopupMenu(parent, name)
|
||
|
{
|
||
|
d = new KPopupMenuPrivate;
|
||
|
insertTitle(title);
|
||
|
}
|
||
|
|
||
|
// Obsolete
|
||
|
void KPopupMenu::setTitle(const QString &title)
|
||
|
{
|
||
|
KPopupTitle *titleItem = new KPopupTitle();
|
||
|
titleItem->setTitle(title);
|
||
|
insertItem(titleItem);
|
||
|
d->m_lastTitle = title;
|
||
|
}
|
||
|
|
||
|
void KPopupTitle::virtual_hook( int, void* )
|
||
|
{ /*BASE::virtual_hook( id, data );*/ }
|
||
|
|
||
|
void KPopupMenu::virtual_hook( int, void* )
|
||
|
{ /*BASE::virtual_hook( id, data );*/ }
|
||
|
|
||
|
#include "kpopupmenu.moc"
|