# kdeui Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kpopupmenu.cpp

    00001 /* This file is part of the KDE libraries
    00002    Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org>
    00003    Copyright (C) 2002 Hamish Rodda <meddie@yoyo.its.monash.edu.au>
    00004
    00005    This library is free software; you can redistribute it and/or
    00006    modify it under the terms of the GNU Library General Public
    00007    License version 2 as published by the Free Software Foundation.
    00008
    00009    This library is distributed in the hope that it will be useful,
    00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012    Library General Public License for more details.
    00013
    00014    You should have received a copy of the GNU Library General Public License
    00015    along with this library; see the file COPYING.LIB.  If not, write to
    00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00017    Boston, MA 02111-1307, USA.
    00018 */
    00019 #include <qpainter.h>
    00020 #include <qdrawutil.h>
    00021 #include <qtimer.h>
    00022 #include <qfont.h>
    00023 #include <qfontmetrics.h>
    00024 #include <qregexp.h>
    00025
    00026 #include "kpopupmenu.h"
    00027
    00028 #include <kconfig.h>
    00029 #include <kdebug.h>
    00030 #include <kapplication.h>
    00031 #include <kipc.h>
    00032 #include <kiconloader.h>
    00033 #include <klocale.h>
    00034 #include <kglobal.h>
    00035 #include <kglobalsettings.h>
    00036 #include <kstandarddirs.h>
    00037
    00038 KPopupTitle::KPopupTitle(QWidget *parent, const char *name)
    00039     : QWidget(parent, name)
    00040 {
    00041     KConfig *config = KGlobal::config();
    00042     QString oldGroup = config->group();
    00043     QString tmpStr;
    00044
    00045     config->setGroup(QString::fromLatin1("PopupTitle"));
    00046     bgColor = config->readColorEntry(QString::fromLatin1("Color"), &colorGroup().mid());
    00047     grHigh = bgColor.light(150);
    00048     grLow = bgColor.dark(150);
    00049     fgColor = config->readColorEntry(QString::fromLatin1("TextColor"), &colorGroup().highlightedText());
    00050
    00051     tmpStr = config->readEntry(QString::fromLatin1("Pixmap"));
    00052     if(!tmpStr.isEmpty())
    00053         fill.load(KGlobal::dirs()->findResource("wallpaper", tmpStr));
    00054     if(!fill.isNull()){
    00055         config->setGroup(oldGroup);
    00056         useGradient = false;
    00057         return;
    00058     }
    00059
    00060     tmpStr = config->readEntry(QString::fromLatin1("Gradient"));
    00061     if(tmpStr.isEmpty()) {
    00062         config->setGroup(oldGroup);
    00063         useGradient = false;
    00064         return;
    00065     }
    00066
    00067     if(tmpStr == QString::fromLatin1("Horizontal"))
    00068         grType = KPixmapEffect::HorizontalGradient;
    00069     else if(tmpStr == QString::fromLatin1("Vertical"))
    00070         grType = KPixmapEffect::VerticalGradient;
    00071     else if(tmpStr == QString::fromLatin1("Diagonal"))
    00072         grType = KPixmapEffect::DiagonalGradient;
    00073     else if(tmpStr == QString::fromLatin1("Pyramid"))
    00074         grType = KPixmapEffect::PyramidGradient;
    00075     else if(tmpStr == QString::fromLatin1("Rectangle"))
    00076         grType = KPixmapEffect::RectangleGradient;
    00077     else if(tmpStr == QString::fromLatin1("Elliptic"))
    00078         grType = KPixmapEffect::EllipticGradient;
    00079     else{
    00080         kdWarning() << "KPopupMenu: Unknown gradient type " << tmpStr << " for title item" << endl;
    00081         grType = KPixmapEffect::HorizontalGradient;
    00082     }
    00083
    00084     useGradient = true;
    00085     setMinimumSize(16, fontMetrics().height()+8);
    00086     config->setGroup(oldGroup);
    00087 }
    00088
    00089 KPopupTitle::KPopupTitle(KPixmapEffect::GradientType gradient,
    00090                          const QColor &color, const QColor &textColor,
    00091                          QWidget *parent, const char *name)
    00092    : QWidget(parent, name)
    00093 {
    00094     grType = gradient;
    00095     fgColor = textColor;
    00096     bgColor = color;
    00097     grHigh = bgColor.light(150);
    00098     grLow = bgColor.dark(150);
    00099     useGradient = true;
    00100     setMinimumSize(16, fontMetrics().height()+8);
    00101 }
    00102
    00103 KPopupTitle::KPopupTitle(const KPixmap &background, const QColor &color,
    00104                          const QColor &textColor, QWidget *parent,
    00105                          const char *name)
    00106     : QWidget(parent, name)
    00107 {
    00108     if(!background.isNull())
    00109         fill = background;
    00110     else
    00111         kdWarning() << "KPopupMenu: Empty pixmap used for title." << endl;
    00112     useGradient = false;
    00113
    00114     fgColor = textColor;
    00115     bgColor = color;
    00116     grHigh = bgColor.light(150);
    00117     grLow = bgColor.dark(150);
    00118     setMinimumSize(16, fontMetrics().height()+8);
    00119 }
    00120
    00121 void KPopupTitle::setTitle(const QString &text, const QPixmap *icon)
    00122 {
    00123     titleStr = text;
    00124     if(icon){
    00125         miniicon = *icon;
    00126     }
    00127     else
    00128         miniicon.resize(0, 0);
    00129
    00130     int w = miniicon.width()+fontMetrics().width(titleStr);
    00131     int h = QMAX( fontMetrics().height(), miniicon.height() );
    00132     setMinimumSize( w+16, h+8 );
    00133 }
    00134
    00135 void KPopupTitle::setText( const QString &text )
    00136 {
    00137     titleStr = text;
    00138     int w = miniicon.width()+fontMetrics().width(titleStr);
    00139     int h = QMAX( fontMetrics().height(), miniicon.height() );
    00140     setMinimumSize( w+16, h+8 );
    00141 }
    00142
    00143 void KPopupTitle::setIcon( const QPixmap &pix )
    00144 {
    00145     miniicon = pix;
    00146     int w = miniicon.width()+fontMetrics().width(titleStr);
    00147     int h = QMAX( fontMetrics().height(), miniicon.height() );
    00148     setMinimumSize( w+16, h+8 );
    00149 }
    00150
    00151 void KPopupTitle::paintEvent(QPaintEvent *)
    00152 {
    00153     QRect r(rect());
    00154     QPainter p(this);
    00155
    00156     if(useGradient){
    00157
    00158         if(fill.width() != r.width()-4 || fill.height() != r.height()-4){
    00159             fill.resize(r.width()-4, r.height()-4);
    00160             KPixmapEffect::gradient(fill, grHigh, grLow, grType);
    00161         }
    00162         p.drawPixmap(2, 2, fill);
    00163     }
    00164     else if(!fill.isNull())
    00165         p.drawTiledPixmap(2, 2, r.width()-4, r.height()-4, fill);
    00166     else{
    00167         p.fillRect(2, 2, r.width()-4, r.height()-4, QBrush(bgColor));
    00168     }
    00169
    00170     if(!miniicon.isNull())
    00171         p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon);
    00172     if(!titleStr.isNull()){
    00173         p.setPen(fgColor);
    00174         if(!miniicon.isNull())
    00175             p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8),
    00176                        height(), AlignLeft | AlignVCenter | SingleLine,
    00177                        titleStr);
    00178         else
    00179             p.drawText(0, 0, width(), height(),
    00180                        AlignCenter | SingleLine, titleStr);
    00181     }
    00182     p.setPen(Qt::black);
    00183     p.drawRect(r);
    00184     p.setPen(grLow);
    00185     p.drawLine(r.x()+1, r.y()+1, r.right()-1, r.y()+1);
    00186     p.drawLine(r.x()+1, r.y()+1, r.x()+1, r.bottom()-1);
    00187     p.setPen(grHigh);
    00188     p.drawLine(r.x()+1, r.bottom()-1, r.right()-1, r.bottom()-1);
    00189     p.drawLine(r.right()-1, r.y()+1, r.right()-1, r.bottom()-1);
    00190 }
    00191
    00192 QSize KPopupTitle::sizeHint() const
    00193 {
    00194     return(minimumSize());
    00195 }
    00196
    00197 class KPopupMenu::KPopupMenuPrivate
    00198 {
    00199 public:
    00200     KPopupMenuPrivate ()
    00201         : noMatches(false)
    00202         , shortcuts(false)
    00203         , autoExec(false)
    00204         , lastHitIndex(-1)
    00205     {}
    00206
    00207     QString m_lastTitle;
    00208
    00209     // variables for keyboard navigation
    00210     QTimer clearTimer;
    00211
    00212     bool noMatches : 1;
    00213     bool shortcuts : 1;
    00214     bool autoExec : 1;
    00215
    00216     QString keySeq;
    00217     QString originalText;
    00218
    00219     int lastHitIndex;
    00220 };
    00221
    00222
    00223 KPopupMenu::KPopupMenu(QWidget *parent, const char *name)
    00224     : QPopupMenu(parent, name)
    00225 {
    00226     d = new KPopupMenuPrivate;
    00227     resetKeyboardVars();
    00228     connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars()));
    00229 }
    00230
    00231 KPopupMenu::~KPopupMenu()
    00232 {
    00233     delete d;
    00234 }
    00235
    00236 int KPopupMenu::insertTitle(const QString &text, int id, int index)
    00237 {
    00238     KPopupTitle *titleItem = new KPopupTitle();
    00239     titleItem->setTitle(text);
    00240     int ret = insertItem(titleItem, id, index);
    00241     setItemEnabled(id, false);
    00242     return ret;
    00243 }
    00244
    00245 int KPopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id,
    00246                             int index)
    00247 {
    00248     KPopupTitle *titleItem = new KPopupTitle();
    00249     titleItem->setTitle(text, &icon);
    00250     int ret = insertItem(titleItem, id, index);
    00251     setItemEnabled(id, false);
    00252     return ret;
    00253 }
    00254
    00255 void KPopupMenu::changeTitle(int id, const QString &text)
    00256 {
    00257     QMenuItem *item = findItem(id);
    00258     if(item){
    00259         if(item->widget())
    00260             ((KPopupTitle *)item->widget())->setTitle(text);
    00261         else
    00262             qWarning("KPopupMenu: changeTitle() called with non-title id %d.", id);
    00263     }
    00264     else
    00265         qWarning("KPopupMenu: changeTitle() called with invalid id %d.", id);
    00266 }
    00267
    00268 void KPopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text)
    00269 {
    00270     QMenuItem *item = findItem(id);
    00271     if(item){
    00272         if(item->widget())
    00273             ((KPopupTitle *)item->widget())->setTitle(text, &icon);
    00274         else
    00275             qWarning("KPopupMenu: changeTitle() called with non-title id %d.", id);
    00276     }
    00277     else
    00278         qWarning("KPopupMenu: changeTitle() called with invalid id %d.", id);
    00279 }
    00280
    00281 QString KPopupMenu::title(int id) const
    00282 {
    00283     if(id == -1) // obsolete
    00284         return(d->m_lastTitle);
    00285     QMenuItem *item = findItem(id);
    00286     if(item){
    00287         if(item->widget())
    00288             return(((KPopupTitle *)item->widget())->title());
    00289         else
    00290             qWarning("KPopupMenu: title() called with non-title id %d.", id);
    00291     }
    00292     else
    00293         qWarning("KPopupMenu: title() called with invalid id %d.", id);
    00294     return(QString::null);
    00295 }
    00296
    00297 QPixmap KPopupMenu::titlePixmap(int id) const
    00298 {
    00299     QMenuItem *item = findItem(id);
    00300     if(item){
    00301         if(item->widget())
    00302             return(((KPopupTitle *)item->widget())->icon());
    00303         else
    00304             qWarning("KPopupMenu: titlePixmap() called with non-title id %d.", id);
    00305     }
    00306     else
    00307         qWarning("KPopupMenu: titlePixmap() called with invalid id %d.", id);
    00308     QPixmap tmp;
    00309     return(tmp);
    00310 }
    00311
    00315 void KPopupMenu::closeEvent(QCloseEvent*e)
    00316 {
    00317     if (d->shortcuts)
    00318         resetKeyboardVars();
    00319     QPopupMenu::closeEvent(e);
    00320 }
    00321
    00322 void KPopupMenu::keyPressEvent(QKeyEvent* e)
    00323 {
    00324     if (!d->shortcuts) {
    00325         // continue event processing by Qpopup
    00326         //e->ignore();
    00327         QPopupMenu::keyPressEvent(e);
    00328         return;
    00329     }
    00330
    00331     int i = 0;
    00332     bool firstpass = true;
    00333     QString keyString = e->text();
    00334
    00335     // check for common commands dealt with by QPopup
    00336     int key = e->key();
    00337     if (key == Key_Escape || key == Key_Return || key == Key_Enter
    00338             || key == Key_Up || key == Key_Down || key == Key_Left
    00339             || key == Key_Right || key == Key_F1) {
    00340
    00341         resetKeyboardVars();
    00342         // continue event processing by Qpopup
    00343         //e->ignore();
    00344         QPopupMenu::keyPressEvent(e);
    00345         return;
    00346     }
    00347
    00348     // check to see if the user wants to remove a key from the sequence (backspace)
    00349     // or clear the sequence (delete)
    00350     if (d->keySeq != QString::null) {
    00351
    00352         if (key == Key_Backspace) {
    00353
    00354             if (d->keySeq.length() == 1) {
    00355                 resetKeyboardVars();
    00356                 return;
    00357             }
    00358
    00359             // keep the last sequence in keyString
    00360             keyString = d->keySeq.left(d->keySeq.length() - 1);
    00361
    00362             // allow sequence matching to be tried again
    00363             resetKeyboardVars();
    00364
    00365         } else if (key == Key_Delete) {
    00366             resetKeyboardVars();
    00367
    00368             // clear active item
    00369             setActiveItem(0);
    00370             return;
    00371
    00372         } else if (d->noMatches) {
    00373             // clear if there are no matches
    00374             resetKeyboardVars();
    00375
    00376             // clear active item
    00377             setActiveItem(0);
    00378
    00379         } else {
    00380             // the key sequence is not a null string
    00381             // therefore the lastHitIndex is valid
    00382             i = d->lastHitIndex;
    00383         }
    00384     } else if (key == Key_Backspace && parentMenu) {
    00385         // backspace with no chars in the buffer... go back a menu.
    00386         hide();
    00387         resetKeyboardVars();
    00388         return;
    00389     }
    00390
    00391     d->keySeq += keyString;
    00392     int seqLen = d->keySeq.length();
    00393
    00394     for (; i < (int)count(); i++) {
    00395         // compare typed text with text of this entry
    00396         int j = idAt(i);
    00397
    00398         // don't search disabled entries
    00399         if (!isItemEnabled(j))
    00400             continue;
    00401
    00402         QString thisText;
    00403
    00404         // retrieve the right text
    00405         // (the last selected item one may have additional ampersands)
    00406         if (i == d->lastHitIndex)
    00407             thisText = d->originalText;
    00408         else
    00409             thisText = text(j);
    00410
    00411         // if there is an accelerator present, remove it
    00412         if ((int)accel(j) != 0)
    00413             thisText = thisText.replace(QRegExp("&"), "");
    00414
    00415         // chop text to the search length
    00416         thisText = thisText.left(seqLen);
    00417
    00418         // do the search
    00419         if (thisText.find(d->keySeq, 0, false) == 0) {
    00420
    00421             if (firstpass) {
    00422                 // match
    00423                 setActiveItem(i);
    00424
    00425                 // check to see if we're underlining a different item
    00426                 if (d->lastHitIndex != i)
    00427                     // yes; revert the underlining
    00428                     changeItem(idAt(d->lastHitIndex), d->originalText);
    00429
    00430                 // set the original text if it's a different item
    00431                 if (d->lastHitIndex != i || d->lastHitIndex == -1)
    00432                     d->originalText = text(j);
    00433
    00434                 // underline the currently selected item
    00435                 changeItem(j, underlineText(d->originalText, d->keySeq.length()));
    00436
    00437                 // remeber what's going on
    00438                 d->lastHitIndex = i;
    00439
    00440                 // start/restart the clear timer
    00441                 d->clearTimer.start(5000, true);
    00442
    00443                 // go around for another try, to see if we can execute
    00444                 firstpass = false;
    00445             } else {
    00446                 // don't allow execution
    00447                 return;
    00448             }
    00449         }
    00450
    00451         // fall through to allow execution
    00452     }
    00453
    00454     if (!firstpass) {
    00455         if (d->autoExec) {
    00456             // activate anything
    00457             activateItemAt(d->lastHitIndex);
    00458             resetKeyboardVars();
    00459
    00460         } else if (findItem(idAt(d->lastHitIndex)) &&
    00461                  findItem(idAt(d->lastHitIndex))->popup()) {
    00462             // only activate sub-menus
    00463             activateItemAt(d->lastHitIndex);
    00464             resetKeyboardVars();
    00465         }
    00466
    00467         return;
    00468     }
    00469
    00470     // no matches whatsoever, clean up
    00471     resetKeyboardVars(true);
    00472     //e->ignore();
    00473     QPopupMenu::keyPressEvent(e);
    00474 }
    00475
    00476 QString KPopupMenu::underlineText(const QString& text, uint length)
    00477 {
    00478     QString ret = text;
    00479     for (uint i = 0; i < length; i++) {
    00480         if (ret[2*i] != '&')
    00481             ret.insert(2*i, "&");
    00482     }
    00483     return ret;
    00484 }
    00485
    00486 void KPopupMenu::resetKeyboardVars(bool noMatches /* = false */)
    00487 {
    00488     // Clean up keyboard variables
    00489     if (d->lastHitIndex != -1) {
    00490         changeItem(idAt(d->lastHitIndex), d->originalText);
    00491         d->lastHitIndex = -1;
    00492     }
    00493
    00494     if (!noMatches) {
    00495         d->keySeq = QString::null;
    00496     }
    00497
    00498     d->noMatches = noMatches;
    00499 }
    00500
    00501 void KPopupMenu::setKeyboardShortcutsEnabled(bool enable)
    00502 {
    00503     d->shortcuts = enable;
    00504 }
    00505
    00506 void KPopupMenu::setKeyboardShortcutsExecute(bool enable)
    00507 {
    00508     d->autoExec = enable;
    00509 }
    00514 // Obsolete
    00515 KPopupMenu::KPopupMenu(const QString& title, QWidget *parent, const char *name)
    00516     : QPopupMenu(parent, name)
    00517 {
    00518     d = new KPopupMenuPrivate;
    00519     setTitle(title);
    00520 }
    00521
    00522 // Obsolete
    00523 void KPopupMenu::setTitle(const QString &title)
    00524 {
    00525     KPopupTitle *titleItem = new KPopupTitle();
    00526     titleItem->setTitle(title);
    00527     insertItem(titleItem);
    00528     d->m_lastTitle = title;
    00529 }
    00530
    00531 void KPopupTitle::virtual_hook( int, void* )
    00532 { /*BASE::virtual_hook( id, data );*/ }
    00533
    00534 void KPopupMenu::virtual_hook( int, void* )
    00535 { /*BASE::virtual_hook( id, data );*/ }
    00536
    00537 #include "kpopupmenu.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:57:33 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001