diff options
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqaccel.cpp')
-rw-r--r-- | tqtinterface/qt4/src/kernel/tqaccel.cpp | 2098 |
1 files changed, 2098 insertions, 0 deletions
diff --git a/tqtinterface/qt4/src/kernel/tqaccel.cpp b/tqtinterface/qt4/src/kernel/tqaccel.cpp new file mode 100644 index 0000000..fd47345 --- /dev/null +++ b/tqtinterface/qt4/src/kernel/tqaccel.cpp @@ -0,0 +1,2098 @@ +#include "tqtglobaldefines.h" + +#if 0 + +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3Support module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tqaccel.h" + +#include "tqsignal.h" +#include "Qt/qapplication.h" +#include "Qt/qwidget.h" +#include "tqptrlist.h" +#include "Qt/qwhatsthis.h" +#include "Qt/qpointer.h" +#include "Qt/qstatusbar.h" +#include "Qt/qdockwidget.h" +#include "Qt/qevent.h" +#include "Qt/qkeysequence.h" +// #include "private/qapplication_p.h" + +QT_BEGIN_NAMESPACE + +using namespace Qt; + +/*! + \class TQAccel + \brief The TQAccel class handles keyboard accelerator and shortcut keys. + + \compat + + A keyboard accelerator triggers an action when a certain key + combination is pressed. The accelerator handles all keyboard + activity for all the children of one top-level widget, so it is + not affected by the keyboard focus. + + In most cases, you will not need to use this class directly. Use + the QAction class to create actions with accelerators that can be + used in both menus and toolbars. If you're only interested in + menus use Q3MenuData::insertItem() or Q3MenuData::setAccel() to make + accelerators for operations that are also available on menus. Many + widgets automatically generate accelerators, such as QAbstractButton, + QGroupBox, QLabel (with QLabel::setBuddy()), QMenuBar, and QTabBar. + Example: + \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 0 + + A TQAccel tqcontains a list of accelerator items that can be + manipulated using insertItem(), removeItem(), clear(), key() and + findKey(). + + Each accelerator item consists of an identifier and a \l + QKeySequence. A single key sequence consists of a keyboard code + combined with modifiers (Qt::SHIFT, Qt::CTRL, Qt::ALT, or + Qt::UNICODE_ACCEL). For example, Qt::CTRL + Qt::Key_P could be a shortcut + for printing a document. As an alternative, use Qt::UNICODE_ACCEL with the + tqunicode code point of the character. For example, Qt::UNICODE_ACCEL + + 'A' gives the same accelerator as Qt::Key_A. + + When an accelerator key is pressed, the accelerator sends out the + signal activated() with a number that identifies this particular + accelerator item. Accelerator items can also be individually + connected, so that two different keys will activate two different + Q_SLOTS (see connectItem() and disconnectItem()). + + The activated() signal is \e not emitted when two or more + accelerators match the same key. Instead, the first matching + accelerator sends out the activatedAmbiguously() signal. By + pressing the key multiple times, users can navigate between all + matching accelerators. Some standard controls like QPushButton and + QCheckBox connect the activatedAmbiguously() signal to the + harmless setFocus() slot, whereas activated() is connected to a + slot invoking the button's action. Most controls, like QLabel and + QTabBar, treat activated() and activatedAmbiguously() as + equivalent. + + Use setEnabled() to enable or disable all the items in an + accelerator, or setItemEnabled() to enable or disable individual + items. An item is active only when both the TQAccel and the item + itself are enabled. + + The function setWhatsThis() specifies a help text that appears + when the user presses an accelerator key in What's This mode. + + The accelerator will be deleted when \e parent is deleted, + and will consume relevant key events until then. + + Please note that the accelerator + \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 1 + can be triggered with both the 'M' key, and with Shift+M, + unless a second accelerator is defined for the Shift+M + combination. + + + Example: + \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 2 + + \sa QKeyEvent QWidget::keyPressEvent() + QAbstractButton::setAccel() QLabel::setBuddy() QKeySequence +*/ + + +struct TQAccelItem { // internal accelerator item + TQAccelItem(const QKeySequence &k, int i) + { key=k; id=i; enabled=true; signal=0; } + ~TQAccelItem() { delete signal; } + int id; + QKeySequence key; + bool enabled; + TQSignal *signal; + QString whatsthis; +}; + + +typedef TQPtrList<TQAccelItem> TQAccelList; // internal accelerator list + +class TQAccelPrivate { +public: + TQAccelPrivate(TQAccel* p); + ~TQAccelPrivate(); + TQAccelList aitems; + bool enabled; + QPointer<QWidget> watch; + bool ignorewhatsthis; + TQAccel* parent; + + void activate(TQAccelItem* item); + void activateAmbiguously(TQAccelItem* item); +}; + +class TQAccelManager { +public: + static TQAccelManager* self() { return self_ptr ? self_ptr : new TQAccelManager; } + void registerAccel(TQAccelPrivate* a) { accels.append(a); } + void unregisterAccel(TQAccelPrivate* a) { accels.removeRef(a); if (accels.isEmpty()) delete this; } + bool tryAccelEvent(QWidget* w, QKeyEvent* e); + bool dispatchAccelEvent(QWidget* w, QKeyEvent* e); + bool tryComposeUnicode(QWidget* w, QKeyEvent* e); + +private: + TQAccelManager() + : currentState(QKeySequence::NoMatch), clash(-1), metaComposeUnicode(false),composedUnicode(0) + { setFuncPtr(); self_ptr = this; } + ~TQAccelManager() { self_ptr = 0; } + void setFuncPtr(); + + bool correctSubWindow(QWidget *w, TQAccelPrivate* d); + QKeySequence::SequenceMatch match(QKeyEvent* e, TQAccelItem* item, QKeySequence& temp); + int translateModifiers(ButtonState state); + + TQPtrList<TQAccelPrivate> accels; + static TQAccelManager* self_ptr; + QKeySequence::SequenceMatch currentState; + QKeySequence intermediate; + int clash; + bool metaComposeUnicode; + int composedUnicode; +}; +TQAccelManager* TQAccelManager::self_ptr = 0; + +bool Q_COMPAT_EXPORT qt_tryAccelEvent(QWidget* w, QKeyEvent* e){ + return TQAccelManager::self()->tryAccelEvent(w, e); +} + +bool Q_COMPAT_EXPORT qt_dispatchAccelEvent(QWidget* w, QKeyEvent* e){ + return TQAccelManager::self()->dispatchAccelEvent(w, e); +} + +bool Q_COMPAT_EXPORT qt_tryComposeUnicode(QWidget* w, QKeyEvent* e){ + return TQAccelManager::self()->tryComposeUnicode(w, e); +} + +void TQAccelManager::setFuncPtr() { + if (qApp->d_func()->qt_compat_used) + return; + QApplicationPrivate *data = static_cast<QApplicationPrivate*>(qApp->d_ptr.data()); + data->qt_tryAccelEvent = qt_tryAccelEvent; + data->qt_tryComposeUnicode = qt_tryComposeUnicode; + data->qt_dispatchAccelEvent = qt_dispatchAccelEvent; + data->qt_compat_used = true; +} + +#ifdef Q_WS_MAC +static bool qt_accel_no_shortcuts = true; +#else +static bool qt_accel_no_shortcuts = false; +#endif +void Q_COMPAT_EXPORT qt_set_accel_auto_shortcuts(bool b) { qt_accel_no_shortcuts = b; } + +/* + \internal + Returns true if the accel is in the current subwindow, else false. +*/ +bool TQAccelManager::correctSubWindow(QWidget* w, TQAccelPrivate* d) { +#if !defined (Q_OS_MACX) + if (!d->watch || !d->watch->isVisible() || !d->watch->isEnabled()) +#else + if (!d->watch || (!d->watch->isVisible() && !d->watch->inherits("QMenuBar")) || !d->watch->isEnabled()) +#endif + return false; + QWidget* tlw = w->window(); + QWidget* wtlw = d->watch->window(); + + /* if we live in a floating dock window, keep our parent's + * accelerators working */ +#ifndef QT_NO_MAINWINDOW + if ((tlw->windowType() == Qt::Dialog) && tlw->parentWidget() && qobject_cast<QDockWidget*>(tlw)) + return tlw->parentWidget()->window() == wtlw; + + if (wtlw != tlw) + return false; +#endif + /* if we live in a MDI subwindow, ignore the event if we are + not the active document window */ + QWidget* sw = d->watch; + while (sw && sw->windowType() != Qt::SubWindow) + sw = sw->parentWidget(true); + if (sw) { // we are in a subwindow indeed + QWidget* fw = w; + while (fw && fw != sw) + fw = fw->parentWidget(true); + if (fw != sw) // focus widget not in our subwindow + return false; + } + return true; +} + +inline int TQAccelManager::translateModifiers(ButtonState state) +{ + int result = 0; + if (state & ShiftButton) + result |= SHIFT; + if (state & ControlButton) + result |= CTRL; + if (state & MetaButton) + result |= META; + if (state & AltButton) + result |= ALT; + return result; +} + +/* + \internal + Matches the current intermediate key sequence + the latest + keyevent, with and AccelItem. Returns Identical, + PartialMatch or NoMatch, and fills \a temp with the + resulting key sequence. +*/ +QKeySequence::SequenceMatch TQAccelManager::match(QKeyEvent *e, TQAccelItem* item, QKeySequence& temp) +{ + QKeySequence::SequenceMatch result = QKeySequence::NoMatch; + int index = intermediate.count(); + temp = intermediate; + + int modifier = translateModifiers(e->state()); + + if (e->key() && e->key() != Key_unknown) { + int key = e->key() | modifier; + if (e->key() == Key_BackTab) { + /* + In QApplication, we map shift+tab to shift+backtab. + This code here reverts the mapping in a way that keeps + backtab and shift+tab accelerators working, in that + order, meaning backtab has priority.*/ + key &= ~SHIFT; + + temp.setKey(key, index); + if (QKeySequence::NoMatch != (result = temp.matches(item->key))) + return result; + if (e->state() & ShiftButton) + key |= SHIFT; + key = Key_Tab | (key & MODIFIER_MASK); + temp.setKey(key, index); + if (QKeySequence::NoMatch != (result = temp.matches(item->key))) + return result; + } else { + temp.setKey(key, index); + if (QKeySequence::NoMatch != (result = temp.matches(item->key))) + return result; + } + + if (key == Key_BackTab) { + if (e->state() & ShiftButton) + key |= SHIFT; + temp.setKey(key, index); + if (QKeySequence::NoMatch != (result = temp.matches(item->key))) + return result; + } + } + if (!e->text().isEmpty()) { + temp.setKey((int)e->text()[0].tqunicode() | UNICODE_ACCEL | modifier, index); + result = temp.matches(item->key); + } + return result; +} + +bool TQAccelManager::tryAccelEvent(QWidget* w, QKeyEvent* e) +{ + if (QKeySequence::NoMatch == currentState) { + e->t = QEvent::AccelOverride; + e->ignore(); + QApplication::sendSpontaneousEvent(w, e); + if (e->isAccepted()) + return false; + } + e->t = QEvent::Accel; + e->ignore(); + QApplication::sendSpontaneousEvent(w, e); + return e->isAccepted(); +} + +bool TQAccelManager::tryComposeUnicode(QWidget* w, QKeyEvent* e) +{ + if (metaComposeUnicode) { + int value = e->key() - Key_0; + // Ignore acceloverrides so we don't trigger + // accels on keypad when Meta compose is on + if ((e->type() == QEvent::AccelOverride) && + (e->state() == Qt::Keypad + Qt::MetaButton)) { + e->accept(); + // Meta compose start/continue + } else if ((e->type() == QEvent::KeyPress) && + (e->state() == Qt::Keypad + Qt::MetaButton)) { + if (value >= 0 && value <= 9) { + composedUnicode *= 10; + composedUnicode += value; + return true; + } else { + // Composing interrupted, dispatch! + if (composedUnicode) { + QChar ch(composedUnicode); + QString s(ch); + QKeyEvent kep(QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s); + QKeyEvent ker(QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s); + QApplication::sendEvent(w, &kep); + QApplication::sendEvent(w, &ker); + } + composedUnicode = 0; + return true; + } + // Meta compose end, dispatch + } else if ((e->type() == QEvent::KeyRelease) && + (e->key() == Key_Meta) && + (composedUnicode != 0)) { + if ((composedUnicode > 0) && + (composedUnicode < 0xFFFE)) { + QChar ch(composedUnicode); + QString s(ch); + QKeyEvent kep(QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s); + QKeyEvent ker(QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s); + QApplication::sendEvent(w, &kep); + QApplication::sendEvent(w, &ker); + } + composedUnicode = 0; + return true; + } + } + return false; +} + +/* + \internal + Checks for possible accelerators, if no widget + ate the keypres, or we are in the middle of a + partial key sequence. +*/ +bool TQAccelManager::dispatchAccelEvent(QWidget* w, QKeyEvent* e) +{ +#ifndef QT_NO_STATUSBAR + // Needs to be declared and used here because of "goto doclash" + QStatusBar* mainStatusBar = 0; +#endif + + // Modifiers can NOT be accelerators... + if (e->key() >= Key_Shift && + e->key() <= Key_Alt) + return false; + + QKeySequence::SequenceMatch result = QKeySequence::NoMatch; + QKeySequence tocheck, partial; + TQAccelPrivate* accel = 0; + TQAccelItem* item = 0; + TQAccelPrivate* firstaccel = 0; + TQAccelItem* firstitem = 0; + TQAccelPrivate* lastaccel = 0; + TQAccelItem* lastitem = 0; + + QKeyEvent pe = *e; + int n = -1; + int hasShift = (e->state()&Qt::ShiftButton)?1:0; + bool identicalDisabled = false; + bool matchFound = false; + do { + accel = accels.first(); + matchFound = false; + while (accel) { + if (correctSubWindow(w, accel)) { + if (accel->enabled) { + item = accel->aitems.last(); + while(item) { + if (QKeySequence::Identical == (result = match(&pe, item, tocheck))) { + if (item->enabled) { + if (!firstaccel) { + firstaccel = accel; + firstitem = item; + } + lastaccel = accel; + lastitem = item; + n++; + matchFound = true; + if (n > QMAX(clash,0)) + goto doclash; + } else { + identicalDisabled = true; + } + } + if (item->enabled && QKeySequence::PartialMatch == result) { + partial = tocheck; + matchFound = true; + } + item = accel->aitems.prev(); + } + } else { + item = accel->aitems.last(); + while(item) { + if (QKeySequence::Identical == match(&pe, item, tocheck)) + identicalDisabled = true; + item = accel->aitems.prev(); + } + } + } + accel = accels.next(); + } + pe = QKeyEvent(QEvent::Accel, pe.key(), pe.ascii(), pe.state()&~Qt::ShiftButton, pe.text()); + } while (hasShift-- && !matchFound && !identicalDisabled); + +#ifndef QT_NO_STATUSBAR + mainStatusBar = (QStatusBar*) w->window()->child(0, "QStatusBar"); +#endif + if (n < 0) { // no match found + currentState = partial.count() ? QKeySequence::PartialMatch : QKeySequence::NoMatch; +#ifndef QT_NO_STATUSBAR + // Only display message if we are, or were, in a partial match + if (mainStatusBar && (QKeySequence::PartialMatch == currentState || intermediate.count())) { + if (currentState == QKeySequence::PartialMatch) { + mainStatusBar->showMessage((QString)partial + QLatin1String(", ...")); + } else if (!identicalDisabled) { + QString message = TQAccel::tr("%1, %2 not defined"). + arg((QString)intermediate). + arg(QKeySequence::encodeString(e->key() | translateModifiers(e->state()))); + mainStatusBar->showMessage(message, 2000); + // Since we're a NoMatch, reset the clash count + clash = -1; + } else { + mainStatusBar->clearMessage(); + } + } +#endif + + bool eatKey = (QKeySequence::PartialMatch == currentState || intermediate.count()); + intermediate = partial; + if (eatKey) + e->accept(); + return eatKey; + } else if (n == 0) { // found exactly one match + clash = -1; // reset +#ifndef QT_NO_STATUSBAR + if (currentState == QKeySequence::PartialMatch && mainStatusBar) + mainStatusBar->clearMessage(); +#endif + currentState = QKeySequence::NoMatch; // Free sequence keylock + intermediate = QKeySequence(); + lastaccel->activate(lastitem); + e->accept(); + return true; + } + + doclash: // found more than one match +#ifndef QT_NO_STATUSBAR + if (!mainStatusBar) // if "goto doclash", we need to get status bar again. + mainStatusBar = (QStatusBar*) w->window()->child(0, "QStatusBar"); +#endif + + QString message = TQAccel::tr("Ambiguous %1 not handled").arg((QString)tocheck); + if (clash >= 0 && n > clash) { // pick next match + intermediate = QKeySequence(); + currentState = QKeySequence::NoMatch; // Free sequence keylock + clash++; +#ifndef QT_NO_STATUSBAR + if (mainStatusBar && + !lastitem->signal && + !(lastaccel->parent->tqreceivers(SIGNAL(activatedAmbiguously(int))))) + mainStatusBar->showMessage(message, 2000); +#endif + lastaccel->activateAmbiguously(lastitem); + } else { // start (or wrap) with the first matching + intermediate = QKeySequence(); + currentState = QKeySequence::NoMatch; // Free sequence keylock + clash = 0; +#ifndef QT_NO_STATUSBAR + if (mainStatusBar && + !firstitem->signal && + !(firstaccel->parent->tqreceivers(SIGNAL(activatedAmbiguously(int))))) + mainStatusBar->showMessage(message, 2000); +#endif + firstaccel->activateAmbiguously(firstitem); + } + e->accept(); + return true; +} + +TQAccelPrivate::TQAccelPrivate(TQAccel* p) + : parent(p) +{ + TQAccelManager::self()->registerAccel(this); + aitems.setAutoDelete(true); + ignorewhatsthis = false; +} + +TQAccelPrivate::~TQAccelPrivate() +{ + TQAccelManager::self()->unregisterAccel(this); +} + +static TQAccelItem *find_id(TQAccelList &list, int id) +{ + register TQAccelItem *item = list.first(); + while (item && item->id != id) + item = list.next(); + return item; +} + +static TQAccelItem *find_key(TQAccelList &list, const QKeySequence &key) +{ + register TQAccelItem *item = list.first(); + while (item && !(item->key == key)) + item = list.next(); + return item; +} + +/*! + Constructs a TQAccel object called \a name, with parent \a parent. + The accelerator operates on \a parent. +*/ + +TQAccel::TQAccel(QWidget *parent, const char *name) + : TQT_BASE_OBJECT_NAME(parent, name) +{ + d = new TQAccelPrivate(this); + d->enabled = true; + d->watch = parent; +#if defined(QT_CHECK_NULL) + if (!d->watch) + qWarning("TQAccel: An accelerator must have a parent or a watch widget"); +#endif +} + +/*! + Constructs a TQAccel object called \a name, that operates on \a + watch, and is a child of \a parent. + + This constructor is not needed for normal application programming. +*/ +TQAccel::TQAccel(QWidget* watch, TQT_BASE_OBJECT_NAME *parent, const char *name) + : TQT_BASE_OBJECT_NAME(parent, name) +{ + d = new TQAccelPrivate(this); + d->enabled = true; + d->watch = watch; +#if defined(QT_CHECK_NULL) + if (!d->watch) + qWarning("TQAccel: An accelerator must have a parent or a watch widget"); +#endif +} + +/*! + Destroys the accelerator object and frees all allocated resources. +*/ + +TQAccel::~TQAccel() +{ + delete d; +} + + +/*! + \fn void TQAccel::activated(int id) + + This signal is emitted when the user types the shortcut's key + sequence. \a id is a number that identifies this particular + accelerator item. + + \sa activatedAmbiguously() +*/ + +/*! + \fn void TQAccel::activatedAmbiguously(int id) + + This signal is emitted when the user types a shortcut key + sequence that is ambiguous. For example, if one key sequence is a + "prefix" for another and the user types these keys it isn't clear + if they want the shorter key sequence, or if they're about to + type more to complete the longer key sequence. \a id is a number + that identifies this particular accelerator item. + + \sa activated() +*/ + +/*! + Returns true if the accelerator is enabled; otherwise returns + false. + + \sa setEnabled(), isItemEnabled() +*/ + +bool TQAccel::isEnabled() const +{ + return d->enabled; +} + + +/*! + Enables the accelerator if \a enable is true, or disables it if \a + enable is false. + + Individual keys can also be enabled or disabled using + setItemEnabled(). To work, a key must be an enabled item in an + enabled TQAccel. + + \sa isEnabled(), setItemEnabled() +*/ + +void TQAccel::setEnabled(bool enable) +{ + d->enabled = enable; +} + + +/*! + Returns the number of accelerator items in this accelerator. +*/ + +uint TQAccel::count() const +{ + return d->aitems.count(); +} + + +static int get_seq_id() +{ + static int seq_no = -2; // -1 is used as return value in findKey() + return seq_no--; +} + +/*! + Inserts an accelerator item and returns the item's identifier. + + \a key is a key code and an optional combination of SHIFT, CTRL + and ALT. \a id is the accelerator item id. + + If \a id is negative, then the item will be assigned a unique + negative identifier less than -1. + + \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 3 +*/ + +int TQAccel::insertItem(const QKeySequence& key, int id) +{ + if (id == -1) + id = get_seq_id(); + d->aitems.insert(0, new TQAccelItem(key,id)); + return id; +} + +/*! + Removes the accelerator item with the identifier \a id. +*/ + +void TQAccel::removeItem(int id) +{ + if (find_id(d->aitems, id)) + d->aitems.remove(); +} + + +/*! + Removes all accelerator items. +*/ + +void TQAccel::clear() +{ + d->aitems.clear(); +} + + +/*! + Returns the key sequence of the accelerator item with identifier + \a id, or an invalid key sequence (0) if the id cannot be found. +*/ + +QKeySequence TQAccel::key(int id) +{ + TQAccelItem *item = find_id(d->aitems, id); + return item ? item->key : QKeySequence(0); +} + + +/*! + Returns the identifier of the accelerator item with the key code + \a key, or -1 if the item cannot be found. +*/ + +int TQAccel::findKey(const QKeySequence& key) const +{ + TQAccelItem *item = find_key(d->aitems, key); + return item ? item->id : -1; +} + + +/*! + Returns true if the accelerator item with the identifier \a id is + enabled. Returns false if the item is disabled or cannot be found. + + \sa setItemEnabled(), isEnabled() +*/ + +bool TQAccel::isItemEnabled(int id) const +{ + TQAccelItem *item = find_id(d->aitems, id); + return item ? item->enabled : false; +} + + +/*! + Enables the accelerator item with the identifier \a id if \a + enable is true, and disables item \a id if \a enable is false. + + To work, an item must be enabled and be in an enabled TQAccel. + + \sa isItemEnabled(), isEnabled() +*/ + +void TQAccel::setItemEnabled(int id, bool enable) +{ + TQAccelItem *item = find_id(d->aitems, id); + if (item) + item->enabled = enable; +} + + +/*! + Connects the accelerator item \a id to the slot \a member of \a + receiver. Returns true if the connection is successful. + + \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 4 + + Of course, you can also send a signal as \a member. + + Normally accelerators are connected to Q_SLOTS which then receive + the \c activated(int id) signal with the id of the accelerator + item that was activated. If you choose to connect a specific + accelerator item using this function, the \c activated() signal is + emitted if the associated key sequence is pressed but no \c + activated(int id) signal is emitted. + + \sa disconnectItem(), TQT_BASE_OBJECT_NAME::connect() +*/ + +bool TQAccel::connectItem(int id, const TQT_BASE_OBJECT_NAME *receiver, const char *member) +{ + TQAccelItem *item = find_id(d->aitems, id); + if (item) { + if (!item->signal) { + item->signal = new TQSignal; + Q_CHECK_PTR(item->signal); + } + return item->signal->connect(receiver, member); + } + return false; +} + +/*! + Disconnects the accelerator item identified by \a id from + the function called \a member in the \a receiver object. + Returns true if the connection existed and the disconnect + was successful. + + \sa connectItem(), TQT_BASE_OBJECT_NAME::disconnect() +*/ + +bool TQAccel::disconnectItem(int id, const TQT_BASE_OBJECT_NAME *receiver, + const char *member) +{ + TQAccelItem *item = find_id(d->aitems, id); + if (item && item->signal) + return item->signal->disconnect(receiver, member); + return false; +} + +void TQAccelPrivate::activate(TQAccelItem* item) +{ +#ifndef QT_NO_WHATSTHIS + if (QWhatsThis::inWhatsThisMode() && !ignorewhatsthis) { + QWhatsThis::showText(QCursor::pos(), item->whatsthis); + return; + } +#endif + if (item->signal) + item->signal->activate(); + else + emit parent->activated(item->id); +} + +void TQAccelPrivate::activateAmbiguously(TQAccelItem* item) +{ + if (item->signal) + item->signal->activate(); + else + emit parent->activatedAmbiguously(item->id); +} + + +/*! + Returns the shortcut key sequence for \a str, or an invalid key + sequence (0) if \a str has no shortcut sequence. + + For example, shortcutKey("E&xit") returns QKeySequence(Qt::ALT + + Qt::Key_X), shortcutKey("&Quit") returns QKeySequence(Qt::ALT + + Qt::Key_Q), and shortcutKey("Quit") returns QKeySequence(). +*/ + +QKeySequence TQAccel::shortcutKey(const QString &str) +{ + if(qt_accel_no_shortcuts) + return QKeySequence(); + + int p = 0; + while (p >= 0) { + p = str.find(QLatin1Char('&'), p) + 1; + if (p <= 0 || p >= (int)str.length()) + return 0; + if (str[p] != QLatin1Char('&')) { + QChar c = str[p]; + if (c.isPrint()) { + char ltr = c.upper().latin1(); + if (ltr >= (char)Key_A && ltr <= (char)Key_Z) + c = QLatin1Char(ltr); + else + c = c.lower(); + return QKeySequence(c.tqunicode() + ALT + UNICODE_ACCEL); + } + } + p++; + } + return QKeySequence(); +} + +/*! \obsolete + + Creates an accelerator string for the key \a k. + For instance CTRL+Key_O gives "Ctrl+O". The "Ctrl" etc. + are translated (using TQT_BASE_OBJECT_NAME::tr()) in the "TQAccel" context. + + The function is superfluous. Cast the QKeySequence \a k to a + QString for the same effect. +*/ +QString TQAccel::keyToString(QKeySequence k) +{ + return (QString) k; +} + +/*!\obsolete + + Returns an accelerator code for the string \a s. For example + "Ctrl+O" gives CTRL+UNICODE_ACCEL+'O'. The strings "Ctrl", + "Shift", "Alt" are recognized, as well as their translated + equivalents in the "TQAccel" context (using TQT_BASE_OBJECT_NAME::tr()). Returns 0 + if \a s is not recognized. + + This function is typically used with \link TQT_BASE_OBJECT_NAME::tr() tr + \endlink(), so that accelerator keys can be tqreplaced in + translations: + + \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 5 + + Notice the "File|Open" translator comment. It is by no means + necessary, but it provides some context for the human translator. + + The function is superfluous. Construct a QKeySequence from the + string \a s for the same effect. + + \sa TQT_BASE_OBJECT_NAME::tr(), {Internationalization with Qt} +*/ +QKeySequence TQAccel::stringToKey(const QString & s) +{ + return QKeySequence(s); +} + + +/*! + Sets a What's This help text for the accelerator item \a id to \a + text. + + The text will be shown when the application is in What's This mode + and the user hits the accelerator key. + + To set What's This help on a menu item (with or without an + accelerator key), use Q3MenuData::setWhatsThis(). + + \sa whatsThis(), QWhatsThis::inWhatsThisMode(), QAction::setWhatsThis() +*/ +void TQAccel::setWhatsThis(int id, const QString& text) +{ + TQAccelItem *item = find_id(d->aitems, id); + if (item) + item->whatsthis = text; +} + +/*! + Returns the What's This help text for the specified item \a id or + an empty string if no text has been specified. + + \sa setWhatsThis() +*/ +QString TQAccel::whatsThis(int id) const +{ + + TQAccelItem *item = find_id(d->aitems, id); + return item? item->whatsthis : QString(); +} + +/*!\internal */ +void TQAccel::setIgnoreWhatsThis(bool b) +{ + d->ignorewhatsthis = b; +} + +/*!\internal */ +bool TQAccel::ignoreWhatsThis() const +{ + return d->ignorewhatsthis; +} + +/*! + \fn void TQAccel::repairEventFilter() + \internal +*/ + +QT_END_NAMESPACE + +#else // USE_QT4 + +/**************************************************************************** +** +** Implementation of TQAccel class +** +** Created : 950419 +** +** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqaccel.h" + +#ifndef TQT_NO_ACCEL + +#include "tqsignal.h" +#include "tqapplication.h" +#include "tqwidget.h" +#include "tqptrlist.h" +#include "tqwhatsthis.h" +#include "tqguardedptr.h" +#include "tqstatusbar.h" +#include "tqdockwindow.h" +#include "tqsignalslotimp.h" +/*! + \class TQAccel tqaccel.h + \brief The TQAccel class handles keyboard accelerator and shortcut keys. + + \ingroup misc + + A keyboard accelerator triggers an action when a certain key + combination is pressed. The accelerator handles all keyboard + activity for all the tqchildren of one top-level widget, so it is + not affected by the keyboard focus. + + In most cases, you will not need to use this class directly. Use + the TQAction class to create actions with accelerators that can be + used in both menus and toolbars. If you're only interested in + menus use TQMenuData::insertItem() or TQMenuData::setAccel() to make + accelerators for operations that are also available on menus. Many + widgets automatically generate accelerators, such as TQButton, + TQGroupBox, TQLabel (with TQLabel::setBuddy()), TQMenuBar and TQTabBar. + Example: + \code + TQPushButton p( "&Exit", tqparent ); // automatic shortcut ALT+Key_E + TQPopupMenu *fileMenu = new fileMenu( tqparent ); + fileMenu->insertItem( "Undo", tqparent, TQT_SLOT(undo()), CTRL+Key_Z ); + \endcode + + A TQAccel tqcontains a list of accelerator items that can be + manipulated using insertItem(), removeItem(), clear(), key() and + tqfindKey(). + + Each accelerator item consists of an identifier and a \l + TQKeySequence. A single key sequence consists of a keyboard code + combined with modifiers (\c SHIFT, \c CTRL, \c ALT or \c + UNICODE_ACCEL). For example, \c{CTRL + Key_P} could be a shortcut + for printing a document. The key codes are listed in \c + tqnamespace.h. As an alternative, use \c UNICODE_ACCEL with the + tqunicode code point of the character. For example, \c{UNICODE_ACCEL + + 'A'} gives the same accelerator as \c Key_A. + + When an accelerator key is pressed, the accelerator sends out the + signal activated() with a number that identifies this particular + accelerator item. Accelerator items can also be individually + connected, so that two different keys will activate two different + Q_SLOTS (see connectItem() and disconnectItem()). + + The activated() signal is \e not emitted when two or more + accelerators match the same key. Instead, the first matching + accelerator sends out the activatedAmbiguously() signal. By + pressing the key multiple times, users can navigate between all + matching accelerators. Some standard controls like TQPushButton and + TQCheckBox connect the activatedAmbiguously() signal to the + harmless setFocus() slot, whereas activated() is connected to a + slot invoking the button's action. Most controls, like TQLabel and + TQTabBar, treat activated() and activatedAmbiguously() as + equivalent. + + Use setEnabled() to enable or disable all the items in an + accelerator, or setItemEnabled() to enable or disable individual + items. An item is active only when both the TQAccel and the item + itself are enabled. + + The function setWhatsThis() specifies a help text that appears + when the user presses an accelerator key in What's This mode. + + The accelerator will be deleted when \e tqparent is deleted, + and will consume relevant key events until then. + + Please note that the accelerator + \code + accelerator->insertItem( TQKeySequence("M") ); + \endcode + can be triggered with both the 'M' key, and with Shift+M, + unless a second accelerator is defined for the Shift+M + combination. + + + Example: + \code + TQAccel *a = new TQAccel( myWindow ); // create accels for myWindow + a->connectItem( a->insertItem(Key_P+CTRL), // adds Ctrl+P accelerator + myWindow, // connected to myWindow's + TQT_SLOT(printDoc()) ); // printDoc() slot + \endcode + + \sa TQKeyEvent TQWidget::keyPressEvent() TQMenuData::setAccel() + TQButton::setAccel() TQLabel::setBuddy() TQKeySequence + \link guibooks.html#fowler GUI Design Handbook: Keyboard Shortcuts \endlink. +*/ + + +struct TQAccelItem { // internal accelerator item + TQAccelItem( const TQKeySequence &k, int i ) + { key=k; id=i; enabled=TRUE; signal=0; } + ~TQAccelItem() { delete signal; } + int id; + TQKeySequence key; + bool enabled; + TQSignal *signal; + TQString whatsthis; +}; + + +typedef TQPtrList<TQAccelItem> TQAccelList; // internal accelerator list + +class TQAccelPrivate : public TQt { +public: + TQAccelPrivate( TQAccel* p ); + ~TQAccelPrivate(); + TQAccelList aitems; + bool enabled; + TQGuardedPtr<TQWidget> watch; + bool ignorewhatsthis; + TQAccel* tqparent; + + void activate( TQAccelItem* item ); + void activateAmbiguously( TQAccelItem* item ); +}; + +class TQAccelManager : public TQt { +public: + static TQAccelManager* self() { return self_ptr ? self_ptr : new TQAccelManager; } + void registerAccel( TQAccelPrivate* a ) { accels.append( a ); } + void unregisterAccel( TQAccelPrivate* a ) { accels.removeRef( a ); if ( accels.isEmpty() ) delete this; } + bool tryAccelEvent( TQWidget* w, TQKeyEvent* e ); + bool dispatchAccelEvent( TQWidget* w, TQKeyEvent* e ); + bool tryComposeUnicode( TQWidget* w, TQKeyEvent* e ); + +private: + TQAccelManager():currentState(TQt::NoMatch), clash(-1) { self_ptr = this; } + ~TQAccelManager() { self_ptr = 0; } + + bool correctSubWindow( TQWidget *w, TQAccelPrivate* d ); + SequenceMatch match( TQKeyEvent* e, TQAccelItem* item, TQKeySequence& temp ); + int translateModifiers( ButtonState state ); + + TQPtrList<TQAccelPrivate> accels; + static TQAccelManager* self_ptr; + TQt::SequenceMatch currentState; + TQKeySequence intermediate; + int clash; +}; +TQAccelManager* TQAccelManager::self_ptr = 0; + +bool TQ_EXPORT qt_tryAccelEvent( TQWidget* w, TQKeyEvent* e){ + return TQAccelManager::self()->tryAccelEvent( w, e ); +} + +bool TQ_EXPORT qt_dispatchAccelEvent( TQWidget* w, TQKeyEvent* e){ + return TQAccelManager::self()->dispatchAccelEvent( w, e ); +} + +bool TQ_EXPORT qt_tryComposeUnicode( TQWidget* w, TQKeyEvent* e){ + return TQAccelManager::self()->tryComposeUnicode( w, e ); +} + +#ifdef TQ_WS_MAC +static bool qt_accel_no_shortcuts = TRUE; +#else +static bool qt_accel_no_shortcuts = FALSE; +#endif +void TQ_EXPORT qt_setAccelAutoShortcuts(bool b) { qt_accel_no_shortcuts = b; } + +/* + \internal + Returns TRUE if the accel is in the current subwindow, else FALSE. +*/ +bool TQAccelManager::correctSubWindow( TQWidget* w, TQAccelPrivate* d ) { +#if !defined ( TQ_OS_MACX ) + if ( !d->watch || !d->watch->isVisible() || !d->watch->isEnabled() ) +#else + if ( !d->watch || (!d->watch->isVisible() && !d->watch->inherits( "TQMenuBar" )) || !d->watch->isEnabled() ) +#endif + return FALSE; + TQWidget* tlw = w->tqtopLevelWidget(); + TQWidget* wtlw = d->watch->tqtopLevelWidget(); + + /* if we live in a floating dock window, keep our tqparent's + * accelerators working */ +#ifndef TQT_NO_MAINWINDOW + if ( tlw->isDialog() && tlw->parentWidget() && ::tqqt_cast<TQDockWindow*>(tlw) ) // [FIXME] Can I safely use the TQT_TQOBJECT macro here? + return tlw->parentWidget()->tqtopLevelWidget() == wtlw; + + if ( wtlw != tlw ) + return FALSE; +#endif + /* if we live in a MDI subwindow, ignore the event if we are + not the active document window */ + TQWidget* sw = d->watch; + while ( sw && !sw->testWFlags( WSubWindow ) ) + sw = sw->parentWidget( TRUE ); + if ( sw ) { // we are in a subwindow indeed + TQWidget* fw = w; + while ( fw && fw != sw ) + fw = fw->parentWidget( TRUE ); + if ( fw != sw ) // focus widget not in our subwindow + return FALSE; + } + return TRUE; +} + +inline int TQAccelManager::translateModifiers( ButtonState state ) +{ + int result = 0; + if ( state & ShiftButton ) + result |= SHIFT; + if ( state & ControlButton ) + result |= CTRL; + if ( state & MetaButton ) + result |= META; + if ( state & AltButton ) + result |= ALT; + return result; +} + +/* + \internal + Matches the current intermediate key sequence + the latest + keyevent, with and AccelItem. Returns Identical, + PartialMatch or NoMatch, and fills \a temp with the + resulting key sequence. +*/ +TQt::SequenceMatch TQAccelManager::match( TQKeyEvent *e, TQAccelItem* item, TQKeySequence& temp ) +{ + SequenceMatch result = TQt::NoMatch; + int index = intermediate.count(); + temp = intermediate; + + int modifier = translateModifiers( e->state() ); + + if ( e->key() && e->key() != Key_unknown) { + int key = e->key() | modifier; + if ( e->key() == Key_BackTab ) { + /* + In TQApplication, we map shift+tab to shift+backtab. + This code here reverts the mapping in a way that keeps + backtab and shift+tab accelerators working, in that + order, meaning backtab has priority.*/ + key &= ~SHIFT; + + temp.setKey( key, index ); + if ( TQt::NoMatch != (result = temp.matches( item->key )) ) + return result; + if ( e->state() & ShiftButton ) + key |= SHIFT; + key = Key_Tab | ( key & MODIFIER_MASK ); + temp.setKey( key, index ); + if ( TQt::NoMatch != (result = temp.matches( item->key )) ) + return result; + } else { + temp.setKey( key, index ); + if ( TQt::NoMatch != (result = temp.matches( item->key )) ) + return result; + } + + if ( key == Key_BackTab ) { + if ( e->state() & ShiftButton ) + key |= SHIFT; + temp.setKey( key, index ); + if ( TQt::NoMatch != (result = temp.matches( item->key )) ) + return result; + } + } + if ( !e->text().isEmpty() ) { + temp.setKey( (int)e->text()[0].unicode() | UNICODE_ACCEL | modifier, index ); + result = temp.matches( item->key ); + } + return result; +} + +bool TQAccelManager::tryAccelEvent( TQWidget* w, TQKeyEvent* e ) +{ + if ( TQt::NoMatch == currentState ) { + e->t = TQEvent::AccelOverride; + e->ignore(); + TQAccel::sendSpontaneousKeyEvent( TQT_TQOBJECT(w), e ); + if ( e->isAccepted() ) + return FALSE; + } + e->t = TQEvent::Accel; + e->ignore(); + TQAccel::sendSpontaneousKeyEvent( TQT_TQOBJECT(w), e ); + return e->isAccepted(); +} + +bool TQAccelManager::tryComposeUnicode( TQWidget* w, TQKeyEvent* e ) +{ + if ( TQApplication::metaComposeUnicode ) { + int value = e->key() - Key_0; + // Ignore acceloverrides so we don't trigger + // accels on keypad when Meta compose is on + if ( (e->type() == TQEvent::AccelOverride) && + (e->state() == TQt::Keypad + TQt::MetaButton) ) { + e->accept(); + // Meta compose start/continue + } else if ( (e->type() == TQEvent::KeyPress) && + (e->state() == TQt::Keypad + TQt::MetaButton) ) { + if ( value >= 0 && value <= 9 ) { + TQApplication::composedUnicode *= 10; + TQApplication::composedUnicode += value; + return TRUE; + } else { + // Composing interrupted, dispatch! + if ( TQApplication::composedUnicode ) { + TQChar ch( TQApplication::composedUnicode ); + TQString s( ch ); + TQKeyEvent kep( TQEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s ); + TQKeyEvent ker( TQEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s ); + TQApplication::sendEvent( w, &kep ); + TQApplication::sendEvent( w, &ker ); + } + TQApplication::composedUnicode = 0; + return TRUE; + } + // Meta compose end, dispatch + } else if ( (e->type() == TQEvent::KeyRelease) && + (e->key() == Key_Meta) && + (TQApplication::composedUnicode != 0) ) { + if ( (TQApplication::composedUnicode > 0) && + (TQApplication::composedUnicode < 0xFFFE) ) { + TQChar ch( TQApplication::composedUnicode ); + TQString s( ch ); + TQKeyEvent kep( TQEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s ); + TQKeyEvent ker( TQEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s ); + TQApplication::sendEvent( w, &kep ); + TQApplication::sendEvent( w, &ker ); + } + TQApplication::composedUnicode = 0; + return TRUE; + } + } + return FALSE; +} + +/* + \internal + Checks for possible accelerators, if no widget + ate the keypres, or we are in the middle of a + partial key sequence. +*/ +bool TQAccelManager::dispatchAccelEvent( TQWidget* w, TQKeyEvent* e ) +{ +#ifndef TQT_NO_STATUSBAR + // Needs to be declared and used here because of "goto doclash" + TQStatusBar* maintqStatusBar = 0; +#endif + + // Modifiers can NOT be accelerators... + if ( e->key() >= Key_Shift && + e->key() <= Key_Alt ) + return FALSE; + + SequenceMatch result = TQt::NoMatch; + TQKeySequence tocheck, partial; + TQAccelPrivate* accel = 0; + TQAccelItem* item = 0; + TQAccelPrivate* firstaccel = 0; + TQAccelItem* firstitem = 0; + TQAccelPrivate* lastaccel = 0; + TQAccelItem* lastitem = 0; + + TQKeyEvent pe = *e; + int n = -1; + int hasShift = (e->state()&ShiftButton)?1:0; + bool identicalDisabled = FALSE; + bool matchFound = FALSE; + do { + accel = accels.first(); + matchFound = FALSE; + while ( accel ) { + if ( correctSubWindow( w, accel ) ) { + if ( accel->enabled ) { + item = accel->aitems.last(); + while( item ) { + if ( TQt::Identical == (result = match( &pe, item, tocheck )) ) { + if ( item->enabled ) { + if ( !firstaccel ) { + firstaccel = accel; + firstitem = item; + } + lastaccel = accel; + lastitem = item; + n++; + matchFound = TRUE; + if ( n > TQMAX(clash,0) ) + goto doclash; + } else { + identicalDisabled = TRUE; + } + } + if ( item->enabled && TQt::PartialMatch == result ) { + partial = tocheck; + matchFound = TRUE; + } + item = accel->aitems.prev(); + } + } else { + item = accel->aitems.last(); + while( item ) { + if ( TQt::Identical == match( &pe, item, tocheck ) ) + identicalDisabled = TRUE; + item = accel->aitems.prev(); + } + } + } + accel = accels.next(); + } + pe = TQKeyEvent( TQEvent::Accel, pe.key(), pe.ascii(), pe.state()&~ShiftButton, pe.text() ); + } while ( hasShift-- && !matchFound && !identicalDisabled ); + +#ifndef TQT_NO_STATUSBAR + maintqStatusBar = (TQStatusBar*) w->tqtopLevelWidget()->child( 0, "TQStatusBar" ); +#endif + if ( n < 0 ) { // no match found + currentState = partial.count() ? PartialMatch : NoMatch; +#ifndef TQT_NO_STATUSBAR + // Only display message if we are, or were, in a partial match + if ( maintqStatusBar && (PartialMatch == currentState || intermediate.count() ) ) { + if ( currentState == TQt::PartialMatch ) { + maintqStatusBar->message( (TQString)partial + ", ...", 0 ); + } else if (!identicalDisabled) { + TQString message = TQAccel::tr("%1, %2 not defined"). + arg( (TQString)intermediate ). + arg( TQKeySequence::encodeString( e->key() | translateModifiers(e->state()) ) ); + maintqStatusBar->message( message, 2000 ); + // Since we're a NoMatch, reset the clash count + clash = -1; + } else { + maintqStatusBar->clear(); + } + } +#endif + + bool eatKey = (PartialMatch == currentState || intermediate.count() ); + intermediate = partial; + if ( eatKey ) + e->accept(); + return eatKey; + } else if ( n == 0 ) { // found exactly one match + clash = -1; // reset +#ifndef TQT_NO_STATUSBAR + if ( currentState == TQt::PartialMatch && maintqStatusBar ) + maintqStatusBar->clear(); +#endif + currentState = TQt::NoMatch; // Free sequence keylock + intermediate = TQKeySequence(); + lastaccel->activate( lastitem ); + e->accept(); + return TRUE; + } + + doclash: // found more than one match +#ifndef TQT_NO_STATUSBAR + if ( !maintqStatusBar ) // if "goto doclash", we need to get statusbar again. + maintqStatusBar = (TQStatusBar*) w->tqtopLevelWidget()->child( 0, "TQStatusBar" ); +#endif + + TQString message = TQAccel::tr( "Ambiguous \"%1\" not handled" ).arg( (TQString)tocheck ); + if ( clash >= 0 && n > clash ) { // pick next match + intermediate = TQKeySequence(); + currentState = TQt::NoMatch; // Free sequence keylock + clash++; +#ifndef TQT_NO_STATUSBAR + if ( maintqStatusBar && + !lastitem->signal && + !(lastaccel->tqparent->tqreceivers( "activatedAmbiguously(int)" )) ) + maintqStatusBar->message( message, 2000 ); +#endif + lastaccel->activateAmbiguously( lastitem ); + } else { // start (or wrap) with the first matching + intermediate = TQKeySequence(); + currentState = TQt::NoMatch; // Free sequence keylock + clash = 0; +#ifndef TQT_NO_STATUSBAR + if ( maintqStatusBar && + !firstitem->signal && + !(firstaccel->tqparent->tqreceivers( "activatedAmbiguously(int)" )) ) + maintqStatusBar->message( message, 2000 ); +#endif + firstaccel->activateAmbiguously( firstitem ); + } + e->accept(); + return TRUE; +} + +TQAccelPrivate::TQAccelPrivate( TQAccel* p ) + : tqparent( p ) +{ + TQAccelManager::self()->registerAccel( this ); + aitems.setAutoDelete( TRUE ); + ignorewhatsthis = FALSE; +} + +TQAccelPrivate::~TQAccelPrivate() +{ + TQAccelManager::self()->unregisterAccel( this ); +} + +static TQAccelItem *tqfind_id( TQAccelList &list, int id ) +{ + register TQAccelItem *item = list.first(); + while ( item && item->id != id ) + item = list.next(); + return item; +} + +static TQAccelItem *tqfind_key( TQAccelList &list, const TQKeySequence &key ) +{ + register TQAccelItem *item = list.first(); + while ( item && !( item->key == key ) ) + item = list.next(); + return item; +} + +/*! + Constructs a TQAccel object called \a name, with tqparent \a tqparent. + The accelerator operates on \a tqparent. +*/ + +TQAccel::TQAccel( TQWidget *tqparent, const char *name ) + : TQObject( TQT_TQOBJECT(tqparent), name ) +{ + d = new TQAccelPrivate( this ); + d->enabled = TRUE; + d->watch = tqparent; +#if defined(TQT_CHECK_NULL) + if ( !d->watch ) + qWarning( "TQAccel: An accelerator must have a tqparent or a watch widget" ); +#endif +} + +/*! + Constructs a TQAccel object called \a name, that operates on \a + watch, and is a child of \a tqparent. + + This constructor is not needed for normal application programming. +*/ +TQAccel::TQAccel( TQWidget* watch, TQObject *tqparent, const char *name ) + : TQObject( tqparent, name ) +{ + d = new TQAccelPrivate( this ); + d->enabled = TRUE; + d->watch = watch; +#if defined(TQT_CHECK_NULL) + if ( !d->watch ) + qWarning( "TQAccel: An accelerator must have a tqparent or a watch widget" ); +#endif +} + +/*! + Constructs a TQAccel object called \a name, that operates on \a + watch, and is a child of \a tqparent. + + This constructor is not needed for normal application programming. +*/ +TQAccel::TQAccel( TQWidget* watch, TQWidget *tqparent, const char *name ) + : TQObject( TQT_TQOBJECT(tqparent), name ) +{ + d = new TQAccelPrivate( this ); + d->enabled = TRUE; + d->watch = watch; +#if defined(TQT_CHECK_NULL) + if ( !d->watch ) + qWarning( "TQAccel: An accelerator must have a tqparent or a watch widget" ); +#endif +} + +/*! + Destroys the accelerator object and frees all allocated resources. +*/ + +TQAccel::~TQAccel() +{ + delete d; +} + + +/*! + \fn void TQAccel::activated( int id ) + + This signal is emitted when an accelerator key is pressed. \a id + is a number that identifies this particular accelerator item. + + \sa activatedAmbiguously() +*/ + +/*! + \fn void TQAccel::activatedAmbiguously( int id ) + + This signal is emitted when an accelerator key is pressed. \a id + is a number that identifies this particular accelerator item. + + \sa activated() +*/ + + +/*! + Returns TRUE if the accelerator is enabled; otherwise returns + FALSE. + + \sa setEnabled(), isItemEnabled() +*/ + +bool TQAccel::isEnabled() const +{ + return d->enabled; +} + + +/*! + Enables the accelerator if \a enable is TRUE, or disables it if \a + enable is FALSE. + + Individual keys can also be enabled or disabled using + setItemEnabled(). To work, a key must be an enabled item in an + enabled TQAccel. + + \sa isEnabled(), setItemEnabled() +*/ + +void TQAccel::setEnabled( bool enable ) +{ + d->enabled = enable; +} + + +/*! + Returns the number of accelerator items in this accelerator. +*/ + +uint TQAccel::count() const +{ + return d->aitems.count(); +} + + +static int get_seq_id() +{ + static int seq_no = -2; // -1 is used as return value in tqfindKey() + return seq_no--; +} + +/*! + Inserts an accelerator item and returns the item's identifier. + + \a key is a key code and an optional combination of SHIFT, CTRL + and ALT. \a id is the accelerator item id. + + If \a id is negative, then the item will be assigned a unique + negative identifier less than -1. + + \code + TQAccel *a = new TQAccel( myWindow ); // create accels for myWindow + a->insertItem( CTRL + Key_P, 200 ); // Ctrl+P, e.g. to print document + a->insertItem( ALT + Key_X, 201 ); // Alt+X, e.g. to quit + a->insertItem( UNICODE_ACCEL + 'q', 202 ); // Unicode 'q', e.g. to quit + a->insertItem( Key_D ); // gets a unique negative id < -1 + a->insertItem( CTRL + SHIFT + Key_P ); // gets a unique negative id < -1 + \endcode +*/ + +int TQAccel::insertItem( const TQKeySequence& key, int id ) +{ + if ( id == -1 ) + id = get_seq_id(); + d->aitems.insert( 0, new TQAccelItem(key,id) ); + return id; +} + +/*! + Removes the accelerator item with the identifier \a id. +*/ + +void TQAccel::removeItem( int id ) +{ + if ( tqfind_id( d->aitems, id) ) + d->aitems.remove(); +} + + +/*! + Removes all accelerator items. +*/ + +void TQAccel::clear() +{ + d->aitems.clear(); +} + + +/*! + Returns the key sequence of the accelerator item with identifier + \a id, or an invalid key sequence (0) if the id cannot be found. +*/ + +TQKeySequence TQAccel::key( int id ) +{ + TQAccelItem *item = tqfind_id( d->aitems, id); + return item ? item->key : TQKeySequence( 0 ); +} + + +/*! + Returns the identifier of the accelerator item with the key code + \a key, or -1 if the item cannot be found. +*/ + +int TQAccel::tqfindKey( const TQKeySequence& key ) const +{ + TQAccelItem *item = tqfind_key( d->aitems, key ); + return item ? item->id : -1; +} + + +/*! + Returns TRUE if the accelerator item with the identifier \a id is + enabled. Returns FALSE if the item is disabled or cannot be found. + + \sa setItemEnabled(), isEnabled() +*/ + +bool TQAccel::isItemEnabled( int id ) const +{ + TQAccelItem *item = tqfind_id( d->aitems, id); + return item ? item->enabled : FALSE; +} + + +/*! + Enables the accelerator item with the identifier \a id if \a + enable is TRUE, and disables item \a id if \a enable is FALSE. + + To work, an item must be enabled and be in an enabled TQAccel. + + \sa isItemEnabled(), isEnabled() +*/ + +void TQAccel::setItemEnabled( int id, bool enable ) +{ + TQAccelItem *item = tqfind_id( d->aitems, id); + if ( item ) + item->enabled = enable; +} + + +/*! + Connects the accelerator item \a id to the slot \a member of \a + receiver. + + \code + a->connectItem( 201, mainView, TQT_SLOT(quit()) ); + \endcode + + Of course, you can also send a signal as \a member. + + Normally accelerators are connected to Q_SLOTS which then receive + the \c activated(int id) signal with the id of the accelerator + item that was activated. If you choose to connect a specific + accelerator item using this function, the \c activated() signal is + emitted if the associated key sequence is pressed but no \c + activated(int id) signal is emitted. + + \sa disconnectItem() +*/ + +bool TQAccel::connectItem( int id, const TQT_BASE_OBJECT_NAME *receiver, const char *member ) +{ + TQAccelItem *item = tqfind_id( d->aitems, id); + if ( item ) { + if ( !item->signal ) { + item->signal = new TQSignal; + TQ_CHECK_PTR( item->signal ); + } + return item->signal->connect( receiver, member ); + } + return FALSE; +} + +/*! + Disconnects an accelerator item with id \a id from the function + called \a member in the \a receiver object. + + \sa connectItem() +*/ + +bool TQAccel::disconnectItem( int id, const TQT_BASE_OBJECT_NAME *receiver, + const char *member ) +{ + TQAccelItem *item = tqfind_id( d->aitems, id); + if ( item && item->signal ) + return item->signal->disconnect( receiver, member ); + return FALSE; +} + +void TQAccelPrivate::activate( TQAccelItem* item ) +{ +#ifndef TQT_NO_WHATSTHIS + if ( TQWhatsThis::inWhatsThisMode() && !ignorewhatsthis ) { + TQWhatsThis::leaveWhatsThisMode( item->whatsthis ); + return; + } +#endif + if ( item->signal ) + item->signal->activate(); + else + emit tqparent->activated( item->id ); +} + +void TQAccelPrivate::activateAmbiguously( TQAccelItem* item ) +{ + if ( item->signal ) + item->signal->activate(); + else + emit tqparent->activatedAmbiguously( item->id ); +} + + +/*! + Returns the shortcut key sequence for \a str, or an invalid key + sequence (0) if \a str has no shortcut sequence. + + For example, shortcutKey("E&xit") returns ALT+Key_X, + shortcutKey("&Quit") returns ALT+Key_Q and shortcutKey("Quit") + returns 0. (In code that does not inherit the TQt namespace class, + you must write e.g. TQt::ALT+TQt::Key_Q.) + + We provide a \link accelerators.html list of common accelerators + \endlink in English. At the time of writing, Microsoft and Open + Group do not appear to have issued equivalent recommendations for + other languages. +*/ + +TQKeySequence TQAccel::shortcutKey( const TQString &str ) +{ + if(qt_accel_no_shortcuts) + return TQKeySequence(); + + int p = 0; + while ( p >= 0 ) { + p = str.tqfind( '&', p ) + 1; + if ( p <= 0 || p >= (int)str.length() ) + return 0; + if ( str[p] != '&' ) { + TQChar c = str[p]; + if ( c.isPrint() ) { + char ltr = c.upper().latin1(); + if ( ltr >= (char)Qt::Key_A && ltr <= (char)Qt::Key_Z ) + c = ltr; + else + c = c.lower(); + return TQKeySequence( c.tqunicode() + Qt::ALT + Qt::UNICODE_ACCEL ); + } + } + p++; + } + return TQKeySequence(); +} + +/*! \obsolete + + Creates an accelerator string for the key \a k. + For instance CTRL+Key_O gives "Ctrl+O". The "Ctrl" etc. + are translated (using TQObject::tr()) in the "TQAccel" context. + + The function is superfluous. Cast the TQKeySequence \a k to a + TQString for the same effect. +*/ +TQString TQAccel::keyToString( TQKeySequence k ) +{ + return (TQString) k; +} + +/*!\obsolete + + Returns an accelerator code for the string \a s. For example + "Ctrl+O" gives CTRL+UNICODE_ACCEL+'O'. The strings "Ctrl", + "Shift", "Alt" are recognized, as well as their translated + equivalents in the "TQAccel" context (using TQObject::tr()). Returns 0 + if \a s is not recognized. + + This function is typically used with \link TQObject::tr() tr + \endlink(), so that accelerator keys can be tqreplaced in + translations: + + \code + TQPopupMenu *file = new TQPopupMenu( this ); + file->insertItem( p1, tr("&Open..."), this, TQT_SLOT(open()), + TQAccel::stringToKey(tr("Ctrl+O", "File|Open")) ); + \endcode + + Notice the \c "File|Open" translator comment. It is by no means + necessary, but it provides some context for the human translator. + + + The function is superfluous. Construct a TQKeySequence from the + string \a s for the same effect. + + \sa TQObject::tr() + \link i18n.html Internationalization with TQt \endlink +*/ +TQKeySequence TQAccel::stringToKey( const TQString & s ) +{ + return TQKeySequence( s ); +} + + +/*! + Sets a What's This help text for the accelerator item \a id to \a + text. + + The text will be shown when the application is in What's This mode + and the user hits the accelerator key. + + To set What's This help on a menu item (with or without an + accelerator key), use TQMenuData::setWhatsThis(). + + \sa whatsThis(), TQWhatsThis::inWhatsThisMode(), + TQMenuData::setWhatsThis(), TQAction::setWhatsThis() +*/ +void TQAccel::setWhatsThis( int id, const TQString& text ) +{ + + TQAccelItem *item = tqfind_id( d->aitems, id); + if ( item ) + item->whatsthis = text; +} + +/*! + Returns the What's This help text for the specified item \a id or + TQString::null if no text has been specified. + + \sa setWhatsThis() +*/ +TQString TQAccel::whatsThis( int id ) const +{ + + TQAccelItem *item = tqfind_id( d->aitems, id); + return item? item->whatsthis : TQString::null; +} + +/*!\internal */ +void TQAccel::setIgnoreWhatsThis( bool b) +{ + d->ignorewhatsthis = b; +} + +/*!\internal */ +bool TQAccel::ignoreWhatsThis() const +{ + return d->ignorewhatsthis; +} + + +/*! + +\page accelerators.html + +\title Standard Accelerator Keys + +Applications invariably need to define accelerator keys for actions. +TQt fully supports accelerators, for example with \l TQAccel::shortcutKey(). + +Here are Microsoft's recommendations for accelerator keys, with +comments about the Open Group's recommendations where they exist +and differ. For most commands, the Open Group either has no advice or +agrees with Microsoft. + +The emboldened letter plus Alt is Microsoft's recommended choice, and +we recommend supporting it. For an Apply button, for example, we +recommend TQButton::setText( \link TQWidget::tr() tr \endlink("&Apply") ); + +If you have conflicting commands (e.g. About and Apply buttons in the +same dialog), you must decide for yourself. + +\list +\i <b><u>A</u></b>bout +\i Always on <b><u>T</u></b>op +\i <b><u>A</u></b>pply +\i <b><u>B</u></b>ack +\i <b><u>B</u></b>rowse +\i <b><u>C</u></b>lose (CDE: Alt+F4; Alt+F4 is "close window" in Windows) +\i <b><u>C</u></b>opy (CDE: Ctrl+C, Ctrl+Insert) +\i <b><u>C</u></b>opy Here +\i Create <b><u>S</u></b>hortcut +\i Create <b><u>S</u></b>hortcut Here +\i Cu<b><u>t</u></b> +\i <b><u>D</u></b>elete +\i <b><u>E</u></b>dit +\i <b><u>E</u></b>xit (CDE: E<b><u>x</u></b>it) +\i <b><u>E</u></b>xplore +\i <b><u>F</u></b>ile +\i <b><u>F</u></b>ind +\i <b><u>H</u></b>elp +\i Help <b><u>T</u></b>opics +\i <b><u>H</u></b>ide +\i <b><u>I</u></b>nsert +\i Insert <b><u>O</u></b>bject +\i <b><u>L</u></b>ink Here +\i Ma<b><u>x</u></b>imize +\i Mi<b><u>n</u></b>imize +\i <b><u>M</u></b>ove +\i <b><u>M</u></b>ove Here +\i <b><u>N</u></b>ew +\i <b><u>N</u></b>ext +\i <b><u>N</u></b>o +\i <b><u>O</u></b>pen +\i Open <b><u>W</u></b>ith +\i Page Set<b><u>u</u></b>p +\i <b><u>P</u></b>aste +\i Paste <b><u>L</u></b>ink +\i Paste <b><u>S</u></b>hortcut +\i Paste <b><u>S</u></b>pecial +\i <b><u>P</u></b>ause +\i <b><u>P</u></b>lay +\i <b><u>P</u></b>rint +\i <b><u>P</u></b>rint Here +\i P<b><u>r</u></b>operties +\i <b><u>Q</u></b>uick View +\i <b><u>R</u></b>edo (CDE: Ctrl+Y, Shift+Alt+Backspace) +\i <b><u>R</u></b>epeat +\i <b><u>R</u></b>estore +\i <b><u>R</u></b>esume +\i <b><u>R</u></b>etry +\i <b><u>R</u></b>un +\i <b><u>S</u></b>ave +\i Save <b><u>A</u></b>s +\i Select <b><u>A</u></b>ll +\i Se<b><u>n</u></b>d To +\i <b><u>S</u></b>how +\i <b><u>S</u></b>ize +\i S<b><u>p</u></b>lit +\i <b><u>S</u></b>top +\i <b><u>U</u></b>ndo (CDE: Ctrl+Z or Alt+Backspace) +\i <b><u>V</u></b>iew +\i <b><u>W</u></b>hat's This? +\i <b><u>W</u></b>indow +\i <b><u>Y</u></b>es +\endlist + +There are also a lot of other keys and actions (that use other +modifier keys than Alt). See the Microsoft and The Open Group +documentation for details. + +The \link http://www.amazon.com/exec/obidos/ASIN/0735605661/trolltech/t +Microsoft book \endlink has ISBN 0735605661. The corresponding Open Group +book is very hard to tqfind, rather expensive and we cannot recommend +it. However, if you really want it, OGPubs@opengroup.org might be able +to help. Ask them for ISBN 1859121047. + +*/ + +/*! \obsolete serves no purpose anymore */ +void TQAccel::repairEventFilter() {} +/*! \obsolete serves no purpose anymore */ +bool TQAccel::eventFilter( TQObject *, TQEvent * ) { return FALSE; } +#endif // TQT_NO_ACCEL + +#endif // USE_QT4
\ No newline at end of file |