source: trunk/src/qt3support/other/q3accel.cpp@ 1056

Last change on this file since 1056 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 30.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the Qt3Support module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "q3accel.h"
43
44#include "q3signal.h"
45#include "qapplication.h"
46#include "qwidget.h"
47#include "q3ptrlist.h"
48#include "qwhatsthis.h"
49#include "qpointer.h"
50#include "qstatusbar.h"
51#include "qdockwidget.h"
52#include "qevent.h"
53#include "qkeysequence.h"
54#include "private/qapplication_p.h"
55
56QT_BEGIN_NAMESPACE
57
58using namespace Qt;
59
60/*!
61 \class Q3Accel
62 \brief The Q3Accel class handles keyboard accelerator and shortcut keys.
63
64 \compat
65
66 A keyboard accelerator triggers an action when a certain key
67 combination is pressed. The accelerator handles all keyboard
68 activity for all the children of one top-level widget, so it is
69 not affected by the keyboard focus.
70
71 In most cases, you will not need to use this class directly. Use
72 the QAction class to create actions with accelerators that can be
73 used in both menus and toolbars. If you're only interested in
74 menus use Q3MenuData::insertItem() or Q3MenuData::setAccel() to make
75 accelerators for operations that are also available on menus. Many
76 widgets automatically generate accelerators, such as QAbstractButton,
77 QGroupBox, QLabel (with QLabel::setBuddy()), QMenuBar, and QTabBar.
78 Example:
79 \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 0
80
81 A Q3Accel contains a list of accelerator items that can be
82 manipulated using insertItem(), removeItem(), clear(), key() and
83 findKey().
84
85 Each accelerator item consists of an identifier and a \l
86 QKeySequence. A single key sequence consists of a keyboard code
87 combined with modifiers (Qt::SHIFT, Qt::CTRL, Qt::ALT, or
88 Qt::UNICODE_ACCEL). For example, Qt::CTRL + Qt::Key_P could be a shortcut
89 for printing a document. As an alternative, use Qt::UNICODE_ACCEL with the
90 unicode code point of the character. For example, Qt::UNICODE_ACCEL
91 + 'A' gives the same accelerator as Qt::Key_A.
92
93 When an accelerator key is pressed, the accelerator sends out the
94 signal activated() with a number that identifies this particular
95 accelerator item. Accelerator items can also be individually
96 connected, so that two different keys will activate two different
97 slots (see connectItem() and disconnectItem()).
98
99 The activated() signal is \e not emitted when two or more
100 accelerators match the same key. Instead, the first matching
101 accelerator sends out the activatedAmbiguously() signal. By
102 pressing the key multiple times, users can navigate between all
103 matching accelerators. Some standard controls like QPushButton and
104 QCheckBox connect the activatedAmbiguously() signal to the
105 harmless setFocus() slot, whereas activated() is connected to a
106 slot invoking the button's action. Most controls, like QLabel and
107 QTabBar, treat activated() and activatedAmbiguously() as
108 equivalent.
109
110 Use setEnabled() to enable or disable all the items in an
111 accelerator, or setItemEnabled() to enable or disable individual
112 items. An item is active only when both the Q3Accel and the item
113 itself are enabled.
114
115 The function setWhatsThis() specifies a help text that appears
116 when the user presses an accelerator key in What's This mode.
117
118 The accelerator will be deleted when \e parent is deleted,
119 and will consume relevant key events until then.
120
121 Please note that the accelerator
122 \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 1
123 can be triggered with both the 'M' key, and with Shift+M,
124 unless a second accelerator is defined for the Shift+M
125 combination.
126
127
128 Example:
129 \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 2
130
131 \sa QKeyEvent QWidget::keyPressEvent()
132 QAbstractButton::setAccel() QLabel::setBuddy() QKeySequence
133*/
134
135
136struct Q3AccelItem { // internal accelerator item
137 Q3AccelItem(const QKeySequence &k, int i)
138 { key=k; id=i; enabled=true; signal=0; }
139 ~Q3AccelItem() { delete signal; }
140 int id;
141 QKeySequence key;
142 bool enabled;
143 Q3Signal *signal;
144 QString whatsthis;
145};
146
147
148typedef Q3PtrList<Q3AccelItem> Q3AccelList; // internal accelerator list
149
150class Q3AccelPrivate {
151public:
152 Q3AccelPrivate(Q3Accel* p);
153 ~Q3AccelPrivate();
154 Q3AccelList aitems;
155 bool enabled;
156 QPointer<QWidget> watch;
157 bool ignorewhatsthis;
158 Q3Accel* parent;
159
160 void activate(Q3AccelItem* item);
161 void activateAmbiguously(Q3AccelItem* item);
162};
163
164class Q3AccelManager {
165public:
166 static Q3AccelManager* self() { return self_ptr ? self_ptr : new Q3AccelManager; }
167 void registerAccel(Q3AccelPrivate* a) { accels.append(a); }
168 void unregisterAccel(Q3AccelPrivate* a) { accels.removeRef(a); if (accels.isEmpty()) delete this; }
169 bool tryAccelEvent(QWidget* w, QKeyEvent* e);
170 bool dispatchAccelEvent(QWidget* w, QKeyEvent* e);
171 bool tryComposeUnicode(QWidget* w, QKeyEvent* e);
172
173private:
174 Q3AccelManager()
175 : currentState(QKeySequence::NoMatch), clash(-1), metaComposeUnicode(false),composedUnicode(0)
176 { setFuncPtr(); self_ptr = this; }
177 ~Q3AccelManager() { self_ptr = 0; }
178 void setFuncPtr();
179
180 bool correctSubWindow(QWidget *w, Q3AccelPrivate* d);
181 QKeySequence::SequenceMatch match(QKeyEvent* e, Q3AccelItem* item, QKeySequence& temp);
182 int translateModifiers(ButtonState state);
183
184 Q3PtrList<Q3AccelPrivate> accels;
185 static Q3AccelManager* self_ptr;
186 QKeySequence::SequenceMatch currentState;
187 QKeySequence intermediate;
188 int clash;
189 bool metaComposeUnicode;
190 int composedUnicode;
191};
192Q3AccelManager* Q3AccelManager::self_ptr = 0;
193
194bool Q_COMPAT_EXPORT qt_tryAccelEvent(QWidget* w, QKeyEvent* e){
195 return Q3AccelManager::self()->tryAccelEvent(w, e);
196}
197
198bool Q_COMPAT_EXPORT qt_dispatchAccelEvent(QWidget* w, QKeyEvent* e){
199 return Q3AccelManager::self()->dispatchAccelEvent(w, e);
200}
201
202bool Q_COMPAT_EXPORT qt_tryComposeUnicode(QWidget* w, QKeyEvent* e){
203 return Q3AccelManager::self()->tryComposeUnicode(w, e);
204}
205
206void Q3AccelManager::setFuncPtr() {
207 if (qApp->d_func()->qt_compat_used)
208 return;
209 QApplicationPrivate *data = static_cast<QApplicationPrivate*>(qApp->d_ptr.data());
210 data->qt_tryAccelEvent = qt_tryAccelEvent;
211 data->qt_tryComposeUnicode = qt_tryComposeUnicode;
212 data->qt_dispatchAccelEvent = qt_dispatchAccelEvent;
213 data->qt_compat_used = true;
214}
215
216#ifdef Q_WS_MAC
217static bool qt_accel_no_shortcuts = true;
218#else
219static bool qt_accel_no_shortcuts = false;
220#endif
221void Q_COMPAT_EXPORT qt_set_accel_auto_shortcuts(bool b) { qt_accel_no_shortcuts = b; }
222
223/*
224 \internal
225 Returns true if the accel is in the current subwindow, else false.
226*/
227bool Q3AccelManager::correctSubWindow(QWidget* w, Q3AccelPrivate* d) {
228#if !defined (Q_OS_MACX)
229 if (!d->watch || !d->watch->isVisible() || !d->watch->isEnabled())
230#else
231 if (!d->watch || (!d->watch->isVisible() && !d->watch->inherits("QMenuBar")) || !d->watch->isEnabled())
232#endif
233 return false;
234 QWidget* tlw = w->window();
235 QWidget* wtlw = d->watch->window();
236
237 /* if we live in a floating dock window, keep our parent's
238 * accelerators working */
239#ifndef QT_NO_MAINWINDOW
240 if ((tlw->windowType() == Qt::Dialog) && tlw->parentWidget() && qobject_cast<QDockWidget*>(tlw))
241 return tlw->parentWidget()->window() == wtlw;
242
243 if (wtlw != tlw)
244 return false;
245#endif
246 /* if we live in a MDI subwindow, ignore the event if we are
247 not the active document window */
248 QWidget* sw = d->watch;
249 while (sw && sw->windowType() != Qt::SubWindow)
250 sw = sw->parentWidget(true);
251 if (sw) { // we are in a subwindow indeed
252 QWidget* fw = w;
253 while (fw && fw != sw)
254 fw = fw->parentWidget(true);
255 if (fw != sw) // focus widget not in our subwindow
256 return false;
257 }
258 return true;
259}
260
261inline int Q3AccelManager::translateModifiers(ButtonState state)
262{
263 int result = 0;
264 if (state & ShiftButton)
265 result |= SHIFT;
266 if (state & ControlButton)
267 result |= CTRL;
268 if (state & MetaButton)
269 result |= META;
270 if (state & AltButton)
271 result |= ALT;
272 return result;
273}
274
275/*
276 \internal
277 Matches the current intermediate key sequence + the latest
278 keyevent, with and AccelItem. Returns Identical,
279 PartialMatch or NoMatch, and fills \a temp with the
280 resulting key sequence.
281*/
282QKeySequence::SequenceMatch Q3AccelManager::match(QKeyEvent *e, Q3AccelItem* item, QKeySequence& temp)
283{
284 QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
285 int index = intermediate.count();
286 temp = intermediate;
287
288 int modifier = translateModifiers(e->state());
289
290 if (e->key() && e->key() != Key_unknown) {
291 int key = e->key() | modifier;
292 if (e->key() == Key_BackTab) {
293 /*
294 In QApplication, we map shift+tab to shift+backtab.
295 This code here reverts the mapping in a way that keeps
296 backtab and shift+tab accelerators working, in that
297 order, meaning backtab has priority.*/
298 key &= ~SHIFT;
299
300 temp.setKey(key, index);
301 if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
302 return result;
303 if (e->state() & ShiftButton)
304 key |= SHIFT;
305 key = Key_Tab | (key & MODIFIER_MASK);
306 temp.setKey(key, index);
307 if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
308 return result;
309 } else {
310 temp.setKey(key, index);
311 if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
312 return result;
313 }
314
315 if (key == Key_BackTab) {
316 if (e->state() & ShiftButton)
317 key |= SHIFT;
318 temp.setKey(key, index);
319 if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
320 return result;
321 }
322 }
323 if (!e->text().isEmpty()) {
324 temp.setKey((int)e->text()[0].unicode() | UNICODE_ACCEL | modifier, index);
325 result = temp.matches(item->key);
326 }
327 return result;
328}
329
330bool Q3AccelManager::tryAccelEvent(QWidget* w, QKeyEvent* e)
331{
332 if (QKeySequence::NoMatch == currentState) {
333 e->t = QEvent::AccelOverride;
334 e->ignore();
335 QApplication::sendSpontaneousEvent(w, e);
336 if (e->isAccepted())
337 return false;
338 }
339 e->t = QEvent::Accel;
340 e->ignore();
341 QApplication::sendSpontaneousEvent(w, e);
342 return e->isAccepted();
343}
344
345bool Q3AccelManager::tryComposeUnicode(QWidget* w, QKeyEvent* e)
346{
347 if (metaComposeUnicode) {
348 int value = e->key() - Key_0;
349 // Ignore acceloverrides so we don't trigger
350 // accels on keypad when Meta compose is on
351 if ((e->type() == QEvent::AccelOverride) &&
352 (e->state() == Qt::Keypad + Qt::MetaButton)) {
353 e->accept();
354 // Meta compose start/continue
355 } else if ((e->type() == QEvent::KeyPress) &&
356 (e->state() == Qt::Keypad + Qt::MetaButton)) {
357 if (value >= 0 && value <= 9) {
358 composedUnicode *= 10;
359 composedUnicode += value;
360 return true;
361 } else {
362 // Composing interrupted, dispatch!
363 if (composedUnicode) {
364 QChar ch(composedUnicode);
365 QString s(ch);
366 QKeyEvent kep(QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s);
367 QKeyEvent ker(QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s);
368 QApplication::sendEvent(w, &kep);
369 QApplication::sendEvent(w, &ker);
370 }
371 composedUnicode = 0;
372 return true;
373 }
374 // Meta compose end, dispatch
375 } else if ((e->type() == QEvent::KeyRelease) &&
376 (e->key() == Key_Meta) &&
377 (composedUnicode != 0)) {
378 if ((composedUnicode > 0) &&
379 (composedUnicode < 0xFFFE)) {
380 QChar ch(composedUnicode);
381 QString s(ch);
382 QKeyEvent kep(QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s);
383 QKeyEvent ker(QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s);
384 QApplication::sendEvent(w, &kep);
385 QApplication::sendEvent(w, &ker);
386 }
387 composedUnicode = 0;
388 return true;
389 }
390 }
391 return false;
392}
393
394/*
395 \internal
396 Checks for possible accelerators, if no widget
397 ate the keypres, or we are in the middle of a
398 partial key sequence.
399*/
400bool Q3AccelManager::dispatchAccelEvent(QWidget* w, QKeyEvent* e)
401{
402#ifndef QT_NO_STATUSBAR
403 // Needs to be declared and used here because of "goto doclash"
404 QStatusBar* mainStatusBar = 0;
405#endif
406
407 // Modifiers can NOT be accelerators...
408 if (e->key() >= Key_Shift &&
409 e->key() <= Key_Alt)
410 return false;
411
412 QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
413 QKeySequence tocheck, partial;
414 Q3AccelPrivate* accel = 0;
415 Q3AccelItem* item = 0;
416 Q3AccelPrivate* firstaccel = 0;
417 Q3AccelItem* firstitem = 0;
418 Q3AccelPrivate* lastaccel = 0;
419 Q3AccelItem* lastitem = 0;
420
421 QKeyEvent pe = *e;
422 int n = -1;
423 int hasShift = (e->state()&Qt::ShiftButton)?1:0;
424 bool identicalDisabled = false;
425 bool matchFound = false;
426 do {
427 accel = accels.first();
428 matchFound = false;
429 while (accel) {
430 if (correctSubWindow(w, accel)) {
431 if (accel->enabled) {
432 item = accel->aitems.last();
433 while(item) {
434 if (QKeySequence::Identical == (result = match(&pe, item, tocheck))) {
435 if (item->enabled) {
436 if (!firstaccel) {
437 firstaccel = accel;
438 firstitem = item;
439 }
440 lastaccel = accel;
441 lastitem = item;
442 n++;
443 matchFound = true;
444 if (n > QMAX(clash,0))
445 goto doclash;
446 } else {
447 identicalDisabled = true;
448 }
449 }
450 if (item->enabled && QKeySequence::PartialMatch == result) {
451 partial = tocheck;
452 matchFound = true;
453 }
454 item = accel->aitems.prev();
455 }
456 } else {
457 item = accel->aitems.last();
458 while(item) {
459 if (QKeySequence::Identical == match(&pe, item, tocheck))
460 identicalDisabled = true;
461 item = accel->aitems.prev();
462 }
463 }
464 }
465 accel = accels.next();
466 }
467 pe = QKeyEvent(QEvent::Accel, pe.key(), pe.ascii(), pe.state()&~Qt::ShiftButton, pe.text());
468 } while (hasShift-- && !matchFound && !identicalDisabled);
469
470#ifndef QT_NO_STATUSBAR
471 mainStatusBar = (QStatusBar*) w->window()->child(0, "QStatusBar");
472#endif
473 if (n < 0) { // no match found
474 currentState = partial.count() ? QKeySequence::PartialMatch : QKeySequence::NoMatch;
475#ifndef QT_NO_STATUSBAR
476 // Only display message if we are, or were, in a partial match
477 if (mainStatusBar && (QKeySequence::PartialMatch == currentState || intermediate.count())) {
478 if (currentState == QKeySequence::PartialMatch) {
479 mainStatusBar->showMessage((QString)partial + QLatin1String(", ..."));
480 } else if (!identicalDisabled) {
481 QString message = Q3Accel::tr("%1, %2 not defined").
482 arg((QString)intermediate).
483 arg(QKeySequence::encodeString(e->key() | translateModifiers(e->state())));
484 mainStatusBar->showMessage(message, 2000);
485 // Since we're a NoMatch, reset the clash count
486 clash = -1;
487 } else {
488 mainStatusBar->clearMessage();
489 }
490 }
491#endif
492
493 bool eatKey = (QKeySequence::PartialMatch == currentState || intermediate.count());
494 intermediate = partial;
495 if (eatKey)
496 e->accept();
497 return eatKey;
498 } else if (n == 0) { // found exactly one match
499 clash = -1; // reset
500#ifndef QT_NO_STATUSBAR
501 if (currentState == QKeySequence::PartialMatch && mainStatusBar)
502 mainStatusBar->clearMessage();
503#endif
504 currentState = QKeySequence::NoMatch; // Free sequence keylock
505 intermediate = QKeySequence();
506 lastaccel->activate(lastitem);
507 e->accept();
508 return true;
509 }
510
511 doclash: // found more than one match
512#ifndef QT_NO_STATUSBAR
513 if (!mainStatusBar) // if "goto doclash", we need to get status bar again.
514 mainStatusBar = (QStatusBar*) w->window()->child(0, "QStatusBar");
515#endif
516
517 QString message = Q3Accel::tr("Ambiguous %1 not handled").arg((QString)tocheck);
518 if (clash >= 0 && n > clash) { // pick next match
519 intermediate = QKeySequence();
520 currentState = QKeySequence::NoMatch; // Free sequence keylock
521 clash++;
522#ifndef QT_NO_STATUSBAR
523 if (mainStatusBar &&
524 !lastitem->signal &&
525 !(lastaccel->parent->receivers(SIGNAL(activatedAmbiguously(int)))))
526 mainStatusBar->showMessage(message, 2000);
527#endif
528 lastaccel->activateAmbiguously(lastitem);
529 } else { // start (or wrap) with the first matching
530 intermediate = QKeySequence();
531 currentState = QKeySequence::NoMatch; // Free sequence keylock
532 clash = 0;
533#ifndef QT_NO_STATUSBAR
534 if (mainStatusBar &&
535 !firstitem->signal &&
536 !(firstaccel->parent->receivers(SIGNAL(activatedAmbiguously(int)))))
537 mainStatusBar->showMessage(message, 2000);
538#endif
539 firstaccel->activateAmbiguously(firstitem);
540 }
541 e->accept();
542 return true;
543}
544
545Q3AccelPrivate::Q3AccelPrivate(Q3Accel* p)
546 : parent(p)
547{
548 Q3AccelManager::self()->registerAccel(this);
549 aitems.setAutoDelete(true);
550 ignorewhatsthis = false;
551}
552
553Q3AccelPrivate::~Q3AccelPrivate()
554{
555 Q3AccelManager::self()->unregisterAccel(this);
556}
557
558static Q3AccelItem *find_id(Q3AccelList &list, int id)
559{
560 register Q3AccelItem *item = list.first();
561 while (item && item->id != id)
562 item = list.next();
563 return item;
564}
565
566static Q3AccelItem *find_key(Q3AccelList &list, const QKeySequence &key)
567{
568 register Q3AccelItem *item = list.first();
569 while (item && !(item->key == key))
570 item = list.next();
571 return item;
572}
573
574/*!
575 Constructs a Q3Accel object called \a name, with parent \a parent.
576 The accelerator operates on \a parent.
577*/
578
579Q3Accel::Q3Accel(QWidget *parent, const char *name)
580 : QObject(parent, name)
581{
582 d = new Q3AccelPrivate(this);
583 d->enabled = true;
584 d->watch = parent;
585#if defined(QT_CHECK_NULL)
586 if (!d->watch)
587 qWarning("Q3Accel: An accelerator must have a parent or a watch widget");
588#endif
589}
590
591/*!
592 Constructs a Q3Accel object called \a name, that operates on \a
593 watch, and is a child of \a parent.
594
595 This constructor is not needed for normal application programming.
596*/
597Q3Accel::Q3Accel(QWidget* watch, QObject *parent, const char *name)
598 : QObject(parent, name)
599{
600 d = new Q3AccelPrivate(this);
601 d->enabled = true;
602 d->watch = watch;
603#if defined(QT_CHECK_NULL)
604 if (!d->watch)
605 qWarning("Q3Accel: An accelerator must have a parent or a watch widget");
606#endif
607}
608
609/*!
610 Destroys the accelerator object and frees all allocated resources.
611*/
612
613Q3Accel::~Q3Accel()
614{
615 delete d;
616}
617
618
619/*!
620 \fn void Q3Accel::activated(int id)
621
622 This signal is emitted when the user types the shortcut's key
623 sequence. \a id is a number that identifies this particular
624 accelerator item.
625
626 \sa activatedAmbiguously()
627*/
628
629/*!
630 \fn void Q3Accel::activatedAmbiguously(int id)
631
632 This signal is emitted when the user types a shortcut key
633 sequence that is ambiguous. For example, if one key sequence is a
634 "prefix" for another and the user types these keys it isn't clear
635 if they want the shorter key sequence, or if they're about to
636 type more to complete the longer key sequence. \a id is a number
637 that identifies this particular accelerator item.
638
639 \sa activated()
640*/
641
642/*!
643 Returns true if the accelerator is enabled; otherwise returns
644 false.
645
646 \sa setEnabled(), isItemEnabled()
647*/
648
649bool Q3Accel::isEnabled() const
650{
651 return d->enabled;
652}
653
654
655/*!
656 Enables the accelerator if \a enable is true, or disables it if \a
657 enable is false.
658
659 Individual keys can also be enabled or disabled using
660 setItemEnabled(). To work, a key must be an enabled item in an
661 enabled Q3Accel.
662
663 \sa isEnabled(), setItemEnabled()
664*/
665
666void Q3Accel::setEnabled(bool enable)
667{
668 d->enabled = enable;
669}
670
671
672/*!
673 Returns the number of accelerator items in this accelerator.
674*/
675
676uint Q3Accel::count() const
677{
678 return d->aitems.count();
679}
680
681
682static int get_seq_id()
683{
684 static int seq_no = -2; // -1 is used as return value in findKey()
685 return seq_no--;
686}
687
688/*!
689 Inserts an accelerator item and returns the item's identifier.
690
691 \a key is a key code and an optional combination of SHIFT, CTRL
692 and ALT. \a id is the accelerator item id.
693
694 If \a id is negative, then the item will be assigned a unique
695 negative identifier less than -1.
696
697 \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 3
698*/
699
700int Q3Accel::insertItem(const QKeySequence& key, int id)
701{
702 if (id == -1)
703 id = get_seq_id();
704 d->aitems.insert(0, new Q3AccelItem(key,id));
705 return id;
706}
707
708/*!
709 Removes the accelerator item with the identifier \a id.
710*/
711
712void Q3Accel::removeItem(int id)
713{
714 if (find_id(d->aitems, id))
715 d->aitems.remove();
716}
717
718
719/*!
720 Removes all accelerator items.
721*/
722
723void Q3Accel::clear()
724{
725 d->aitems.clear();
726}
727
728
729/*!
730 Returns the key sequence of the accelerator item with identifier
731 \a id, or an invalid key sequence (0) if the id cannot be found.
732*/
733
734QKeySequence Q3Accel::key(int id)
735{
736 Q3AccelItem *item = find_id(d->aitems, id);
737 return item ? item->key : QKeySequence(0);
738}
739
740
741/*!
742 Returns the identifier of the accelerator item with the key code
743 \a key, or -1 if the item cannot be found.
744*/
745
746int Q3Accel::findKey(const QKeySequence& key) const
747{
748 Q3AccelItem *item = find_key(d->aitems, key);
749 return item ? item->id : -1;
750}
751
752
753/*!
754 Returns true if the accelerator item with the identifier \a id is
755 enabled. Returns false if the item is disabled or cannot be found.
756
757 \sa setItemEnabled(), isEnabled()
758*/
759
760bool Q3Accel::isItemEnabled(int id) const
761{
762 Q3AccelItem *item = find_id(d->aitems, id);
763 return item ? item->enabled : false;
764}
765
766
767/*!
768 Enables the accelerator item with the identifier \a id if \a
769 enable is true, and disables item \a id if \a enable is false.
770
771 To work, an item must be enabled and be in an enabled Q3Accel.
772
773 \sa isItemEnabled(), isEnabled()
774*/
775
776void Q3Accel::setItemEnabled(int id, bool enable)
777{
778 Q3AccelItem *item = find_id(d->aitems, id);
779 if (item)
780 item->enabled = enable;
781}
782
783
784/*!
785 Connects the accelerator item \a id to the slot \a member of \a
786 receiver. Returns true if the connection is successful.
787
788 \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 4
789
790 Of course, you can also send a signal as \a member.
791
792 Normally accelerators are connected to slots which then receive
793 the \c activated(int id) signal with the id of the accelerator
794 item that was activated. If you choose to connect a specific
795 accelerator item using this function, the \c activated() signal is
796 emitted if the associated key sequence is pressed but no \c
797 activated(int id) signal is emitted.
798
799 \sa disconnectItem(), QObject::connect()
800*/
801
802bool Q3Accel::connectItem(int id, const QObject *receiver, const char *member)
803{
804 Q3AccelItem *item = find_id(d->aitems, id);
805 if (item) {
806 if (!item->signal) {
807 item->signal = new Q3Signal;
808 Q_CHECK_PTR(item->signal);
809 }
810 return item->signal->connect(receiver, member);
811 }
812 return false;
813}
814
815/*!
816 Disconnects the accelerator item identified by \a id from
817 the function called \a member in the \a receiver object.
818 Returns true if the connection existed and the disconnect
819 was successful.
820
821 \sa connectItem(), QObject::disconnect()
822*/
823
824bool Q3Accel::disconnectItem(int id, const QObject *receiver,
825 const char *member)
826{
827 Q3AccelItem *item = find_id(d->aitems, id);
828 if (item && item->signal)
829 return item->signal->disconnect(receiver, member);
830 return false;
831}
832
833void Q3AccelPrivate::activate(Q3AccelItem* item)
834{
835#ifndef QT_NO_WHATSTHIS
836 if (QWhatsThis::inWhatsThisMode() && !ignorewhatsthis) {
837 QWhatsThis::showText(QCursor::pos(), item->whatsthis);
838 return;
839 }
840#endif
841 if (item->signal)
842 item->signal->activate();
843 else
844 emit parent->activated(item->id);
845}
846
847void Q3AccelPrivate::activateAmbiguously(Q3AccelItem* item)
848{
849 if (item->signal)
850 item->signal->activate();
851 else
852 emit parent->activatedAmbiguously(item->id);
853}
854
855
856/*!
857 Returns the shortcut key sequence for \a str, or an invalid key
858 sequence (0) if \a str has no shortcut sequence.
859
860 For example, shortcutKey("E&xit") returns QKeySequence(Qt::ALT +
861 Qt::Key_X), shortcutKey("&Quit") returns QKeySequence(Qt::ALT +
862 Qt::Key_Q), and shortcutKey("Quit") returns QKeySequence().
863*/
864
865QKeySequence Q3Accel::shortcutKey(const QString &str)
866{
867 if(qt_accel_no_shortcuts)
868 return QKeySequence();
869
870 int p = 0;
871 while (p >= 0) {
872 p = str.find(QLatin1Char('&'), p) + 1;
873 if (p <= 0 || p >= (int)str.length())
874 return 0;
875 if (str[p] != QLatin1Char('&')) {
876 QChar c = str[p];
877 if (c.isPrint()) {
878 char ltr = c.upper().latin1();
879 if (ltr >= (char)Key_A && ltr <= (char)Key_Z)
880 c = QLatin1Char(ltr);
881 else
882 c = c.lower();
883 return QKeySequence(c.unicode() + ALT + UNICODE_ACCEL);
884 }
885 }
886 p++;
887 }
888 return QKeySequence();
889}
890
891/*! \obsolete
892
893 Creates an accelerator string for the key \a k.
894 For instance CTRL+Key_O gives "Ctrl+O". The "Ctrl" etc.
895 are translated (using QObject::tr()) in the "Q3Accel" context.
896
897 The function is superfluous. Cast the QKeySequence \a k to a
898 QString for the same effect.
899*/
900QString Q3Accel::keyToString(QKeySequence k)
901{
902 return (QString) k;
903}
904
905/*!\obsolete
906
907 Returns an accelerator code for the string \a s. For example
908 "Ctrl+O" gives CTRL+UNICODE_ACCEL+'O'. The strings "Ctrl",
909 "Shift", "Alt" are recognized, as well as their translated
910 equivalents in the "Q3Accel" context (using QObject::tr()). Returns 0
911 if \a s is not recognized.
912
913 This function is typically used with \link QObject::tr() tr
914 \endlink(), so that accelerator keys can be replaced in
915 translations:
916
917 \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 5
918
919 Notice the "File|Open" translator comment. It is by no means
920 necessary, but it provides some context for the human translator.
921
922 The function is superfluous. Construct a QKeySequence from the
923 string \a s for the same effect.
924
925 \sa QObject::tr(), {Internationalization with Qt}
926*/
927QKeySequence Q3Accel::stringToKey(const QString & s)
928{
929 return QKeySequence(s);
930}
931
932
933/*!
934 Sets a What's This help text for the accelerator item \a id to \a
935 text.
936
937 The text will be shown when the application is in What's This mode
938 and the user hits the accelerator key.
939
940 To set What's This help on a menu item (with or without an
941 accelerator key), use Q3MenuData::setWhatsThis().
942
943 \sa whatsThis(), QWhatsThis::inWhatsThisMode(), QAction::setWhatsThis()
944*/
945void Q3Accel::setWhatsThis(int id, const QString& text)
946{
947 Q3AccelItem *item = find_id(d->aitems, id);
948 if (item)
949 item->whatsthis = text;
950}
951
952/*!
953 Returns the What's This help text for the specified item \a id or
954 an empty string if no text has been specified.
955
956 \sa setWhatsThis()
957*/
958QString Q3Accel::whatsThis(int id) const
959{
960
961 Q3AccelItem *item = find_id(d->aitems, id);
962 return item? item->whatsthis : QString();
963}
964
965/*!\internal */
966void Q3Accel::setIgnoreWhatsThis(bool b)
967{
968 d->ignorewhatsthis = b;
969}
970
971/*!\internal */
972bool Q3Accel::ignoreWhatsThis() const
973{
974 return d->ignorewhatsthis;
975}
976
977/*!
978 \fn void Q3Accel::repairEventFilter()
979 \internal
980*/
981
982QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.