00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include <qwidget.h>
00022
#include <qobjectlist.h>
00023
#include <qapplication.h>
00024
#include <qpopupmenu.h>
00025
#include <qmenubar.h>
00026
#include <qmemarray.h>
00027
#include <qmainwindow.h>
00028
#include <qtabbar.h>
00029
#include <qwidgetstack.h>
00030
#include <qlabel.h>
00031
#include <qptrlist.h>
00032
#include <qmetaobject.h>
00033
#include <kstdaction.h>
00034
#include <kstaticdeleter.h>
00035
#include <kdebug.h>
00036
00037
00038
#include "kaccelmanager_private.h"
00039
#include "../kdeui/kstdaction_p.h"
00040
00041
#include "kaccelmanager.h"
00042
00043
00044
const int KAccelManagerAlgorithm::DEFAULT_WEIGHT = 50;
00045
00046
const int KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT = 50;
00047
00048
const int KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT = 50;
00049
00050
const int KAccelManagerAlgorithm::DIALOG_BUTTON_EXTRA_WEIGHT = 300;
00051
00052
const int KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT = 150;
00053
00054
const int KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT = 50;
00055
00056
const int KAccelManagerAlgorithm::GROUP_BOX_WEIGHT = 0;
00057
00058
const int KAccelManagerAlgorithm::MENU_TITLE_WEIGHT = 250;
00059
00060
const int KAccelManagerAlgorithm::STANDARD_ACCEL = 300;
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
class KAcceleratorManagerPrivate
00084 {
00085
public:
00086
00087
static void manage(
QWidget *widget);
00088
static bool programmers_mode;
00089
static bool standardName(
const QString &str);
00090
00091
static bool checkChange(
const KAccelString &as) {
00092
QString t2 = as.
accelerated();
00093
QString t1 = as.
originalText();
00094
if (t1 != t2)
00095 {
00096
if (as.
accel() == -1) {
00097 removed_string +=
"<tr><td>" + t1 +
"</td></tr>";
00098 }
else if (as.
originalAccel() == -1) {
00099 added_string +=
"<tr><td>" + t2 +
"</td></tr>";
00100 }
else {
00101 changed_string +=
"<tr><td>" + t1 +
"</td>";
00102 changed_string +=
"<td>" + t2 +
"</td></tr>";
00103 }
00104
return true;
00105 }
00106
return false;
00107 }
00108
static QString changed_string;
00109
static QString added_string;
00110
static QString removed_string;
00111
00112
private:
00113
class Item;
00114
typedef QPtrList<Item> ItemList;
00115
00116
00117
static void traverseChildren(
QWidget *widget, Item *item);
00118
00119
static void manageWidget(
QWidget *widget, Item *item);
00120
static void manageMenuBar(
QMenuBar *mbar, Item *item);
00121
static void manageTabBar(
QTabBar *bar, Item *item);
00122
00123
static void calculateAccelerators(Item *item,
QString &used);
00124
00125
class Item
00126 {
00127
public:
00128
00129 Item() : m_widget(0), m_children(0), m_index(-1) {};
00130 ~Item();
00131
00132
void addChild(Item *item);
00133
00134
QWidget *m_widget;
00135
KAccelString m_content;
00136 ItemList *m_children;
00137
int m_index;
00138
00139 };
00140 };
00141
00142
00143
bool KAcceleratorManagerPrivate::programmers_mode =
false;
00144
QString KAcceleratorManagerPrivate::changed_string;
00145
QString KAcceleratorManagerPrivate::added_string;
00146
QString KAcceleratorManagerPrivate::removed_string;
00147
static QStringList *kaccmp_sns = 0;
00148
static KStaticDeleter<QStringList> kaccmp_sns_d;
00149
00150
bool KAcceleratorManagerPrivate::standardName(
const QString &str)
00151 {
00152
if (!kaccmp_sns)
00153 kaccmp_sns_d.setObject(kaccmp_sns,
new QStringList(KStdAction::internal_stdNames()));
00154
return kaccmp_sns->contains(str);
00155 }
00156
00157 KAcceleratorManagerPrivate::Item::~Item()
00158 {
00159
delete m_children;
00160 }
00161
00162
00163
void KAcceleratorManagerPrivate::Item::addChild(Item *item)
00164 {
00165
if (!m_children) {
00166 m_children =
new ItemList;
00167 m_children->setAutoDelete(
true);
00168 }
00169
00170 m_children->append(item);
00171 }
00172
00173
void KAcceleratorManagerPrivate::manage(
QWidget *widget)
00174 {
00175
if (widget->inherits(
"QPopupMenu"))
00176 {
00177
00178 KPopupAccelManager::manage(static_cast<QPopupMenu*>(widget));
00179
return;
00180 }
00181
00182 Item *root =
new Item;
00183
00184 manageWidget(widget, root);
00185
00186
QString used;
00187 calculateAccelerators(root, used);
00188
delete root;
00189 }
00190
00191
00192
void KAcceleratorManagerPrivate::calculateAccelerators(Item *item,
QString &used)
00193 {
00194
if (!item->m_children)
00195
return;
00196
00197
00198
KAccelStringList contents;
00199
for (Item *it = item->m_children->first(); it != 0;
00200 it = item->m_children->next())
00201 {
00202 contents << it->m_content;
00203 }
00204
00205
00206 KAccelManagerAlgorithm::findAccelerators(contents, used);
00207
00208
00209
int cnt = -1;
00210
for (Item *it = item->m_children->first(); it != 0;
00211 it = item->m_children->next())
00212 {
00213 cnt++;
00214
00215
if (it->m_widget->inherits(
"QTabBar"))
00216 {
00217
QTabBar *bar = static_cast<QTabBar*>(it->m_widget);
00218
if (checkChange(contents[cnt]))
00219 bar->
tabAt(it->m_index)->setText(contents[cnt].accelerated());
00220
continue;
00221 }
00222
if (it->m_widget->inherits(
"QMenuBar"))
00223 {
00224
QMenuBar *bar = static_cast<QMenuBar*>(it->m_widget);
00225
if (it->m_index >= 0)
00226 {
00227 QMenuItem *mitem = bar->findItem(bar->idAt(it->m_index));
00228
if (mitem)
00229 {
00230 checkChange(contents[cnt]);
00231 mitem->setText(contents[cnt].accelerated());
00232 }
00233
continue;
00234 }
00235 }
00236
int tprop = it->m_widget->metaObject()->findProperty(
"text",
true);
00237
if (tprop != -1) {
00238
if (checkChange(contents[cnt]))
00239 it->m_widget->setProperty(
"text", contents[cnt].accelerated());
00240 }
else {
00241 tprop = it->m_widget->metaObject()->findProperty(
"title",
true);
00242
if (tprop != -1 && checkChange(contents[cnt]))
00243 it->m_widget->setProperty(
"title", contents[cnt].accelerated());
00244 }
00245 }
00246
00247
00248
for (Item *it = item->m_children->first(); it != 0;
00249 it = item->m_children->next())
00250 {
00251
if (it->m_widget && it->m_widget->isVisibleTo( item->m_widget ))
00252 calculateAccelerators(it, used);
00253 }
00254 }
00255
00256
00257
void KAcceleratorManagerPrivate::traverseChildren(
QWidget *widget, Item *item)
00258 {
00259
QObjectList *childList = widget->queryList(
"QWidget", 0,
false,
false);
00260
for (
QObject *it = childList->first(); it; it = childList->next() )
00261 {
00262
QWidget *w = static_cast<QWidget*>(it);
00263
00264
if ( !w->
isVisibleTo( widget ) )
00265
continue;
00266
00267 manageWidget(w, item);
00268 }
00269
delete childList;
00270 }
00271
00272
void KAcceleratorManagerPrivate::manageWidget(
QWidget *w, Item *item)
00273 {
00274
00275
00276
if (w->inherits(
"QTabBar"))
00277 {
00278 manageTabBar(static_cast<QTabBar*>(w), item);
00279
return;
00280 }
00281
00282
if (w->inherits(
"QPopupMenu"))
00283 {
00284
00285 KPopupAccelManager::manage(static_cast<QPopupMenu*>(w));
00286
return;
00287 }
00288
00289
if (w->inherits(
"QMenuBar"))
00290 {
00291 manageMenuBar(static_cast<QMenuBar*>(w), item);
00292
return;
00293 }
00294
00295
if (w->inherits(
"QComboBox") || w->inherits(
"QLineEdit") ||
00296 w->inherits(
"QTextEdit") || w->inherits(
"QTextView") ||
00297 w->inherits(
"QSpinBox"))
00298
return;
00299
00300
00301
if (w->
isFocusEnabled() || (w->inherits(
"QLabel") && static_cast<QLabel*>(w)->buddy()) || w->inherits(
"QGroupBox"))
00302 {
00303
QString content;
00304
QVariant variant;
00305
int tprop = w->metaObject()->findProperty(
"text",
true);
00306
if (tprop != -1) {
00307
const QMetaProperty* p = w->metaObject()->property( tprop,
true );
00308
if ( p && p->isValid() )
00309 w->qt_property( tprop, 1, &variant );
00310
else
00311 tprop = -1;
00312 }
00313
00314
if (tprop == -1) {
00315 tprop = w->metaObject()->findProperty(
"title",
true);
00316
if (tprop != -1) {
00317
const QMetaProperty* p = w->metaObject()->property( tprop,
true );
00318
if ( p && p->isValid() )
00319 w->qt_property( tprop, 1, &variant );
00320 }
00321 }
00322
00323
if (variant.
isValid())
00324 content = variant.
toString();
00325
00326
if (!content.
isEmpty())
00327 {
00328 Item *i =
new Item;
00329 i->m_widget = w;
00330
00331
00332
int weight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
00333
if (w->inherits(
"QPushButton") || w->inherits(
"QCheckBox") || w->inherits(
"QRadioButton") || w->inherits(
"QLabel"))
00334 weight = KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT;
00335
00336
00337
if (w->inherits(
"QGroupBox"))
00338 weight = KAccelManagerAlgorithm::GROUP_BOX_WEIGHT;
00339
00340
00341
if (w->inherits(
"KDialogBaseButton"))
00342 weight += KAccelManagerAlgorithm::DIALOG_BUTTON_EXTRA_WEIGHT;
00343
00344 i->m_content =
KAccelString(content, weight);
00345 item->addChild(i);
00346 }
00347 }
00348 traverseChildren(w, item);
00349 }
00350
00351
void KAcceleratorManagerPrivate::manageTabBar(
QTabBar *bar, Item *item)
00352 {
00353
for (
int i=0; i<bar->
count(); i++)
00354 {
00355
QString content = bar->
tabAt(i)->text();
00356
if (content.
isEmpty())
00357
continue;
00358
00359 Item *it =
new Item;
00360 item->addChild(it);
00361 it->m_widget = bar;
00362 it->m_index = i;
00363 it->m_content =
KAccelString(content);
00364 }
00365 }
00366
00367
00368
void KAcceleratorManagerPrivate::manageMenuBar(
QMenuBar *mbar, Item *item)
00369 {
00370 QMenuItem *mitem;
00371
QString s;
00372
00373
for (uint i=0; i<mbar->count(); ++i)
00374 {
00375 mitem = mbar->findItem(mbar->idAt(i));
00376
if (!mitem)
00377
continue;
00378
00379
00380
if (mitem->isSeparator())
00381
continue;
00382
00383 s = mitem->text();
00384
if (!s.
isEmpty())
00385 {
00386 Item *it =
new Item;
00387 item->addChild(it);
00388 it->m_content =
00389
KAccelString(s,
00390
00391 KAccelManagerAlgorithm::MENU_TITLE_WEIGHT);
00392
00393 it->m_widget = mbar;
00394 it->m_index = i;
00395 }
00396
00397
00398
if (mitem->popup())
00399 KPopupAccelManager::manage(mitem->popup());
00400 }
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 void KAcceleratorManager::manage(
QWidget *widget)
00413 {
00414
KAcceleratorManager::manage(widget,
false);
00415 }
00416
00417 void KAcceleratorManager::manage(
QWidget *widget,
bool programmers_mode)
00418 {
00419 KAcceleratorManagerPrivate::changed_string = QString::null;
00420 KAcceleratorManagerPrivate::added_string = QString::null;
00421 KAcceleratorManagerPrivate::removed_string = QString::null;
00422 KAcceleratorManagerPrivate::programmers_mode = programmers_mode;
00423 KAcceleratorManagerPrivate::manage(widget);
00424 }
00425
00426
void KAcceleratorManager::last_manage(
QString &added,
QString &changed,
QString &removed)
00427 {
00428 added = KAcceleratorManagerPrivate::added_string;
00429 changed = KAcceleratorManagerPrivate::changed_string;
00430 removed = KAcceleratorManagerPrivate::removed_string;
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440 KAccelString::KAccelString(
const QString &input,
int initialWeight)
00441 : m_pureText(input), m_weight()
00442 {
00443
if (m_pureText.contains(
'\t'))
00444 m_pureText = m_pureText.left(m_pureText.find(
'\t'));
00445 m_origText = m_pureText;
00446 m_orig_accel = m_pureText.find(
"(!)&");
00447 m_pureText.replace(m_orig_accel, 4,
"");
00448 m_orig_accel = m_pureText.find(
"(&&)");
00449
if (m_orig_accel != -1)
00450 m_pureText.replace(m_orig_accel, 4,
"&");
00451 m_orig_accel = m_accel = stripAccelerator(m_pureText);
00452
00453 kdDebug(125) << input <<
" " << m_orig_accel <<
" " << m_accel <<
" " << m_pureText <<
endl;
00454
if (initialWeight == -1)
00455 initialWeight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
00456
00457 calculateWeights(initialWeight);
00458
00459
00460 }
00461
00462
00463
QString KAccelString::accelerated()
const
00464
{
00465
QString result = m_pureText;
00466
if (result.
isEmpty())
00467
return result;
00468
00469
if (KAcceleratorManagerPrivate::programmers_mode)
00470 {
00471
int oa = m_orig_accel;
00472
00473
if (m_accel >= 0) {
00474
if (m_accel != m_orig_accel) {
00475 result.
insert(m_accel,
"(!)&");
00476
if (m_accel < m_orig_accel)
00477 oa += 4;
00478 }
else {
00479 result.
insert(m_accel,
"&");
00480
if (m_accel < m_orig_accel)
00481 oa++;
00482 }
00483 }
00484
00485
if (m_accel != m_orig_accel && m_orig_accel >= 0)
00486 result.
insert(oa,
"(&&)");
00487 }
else {
00488
if (m_accel >= 0)
00489 result.
insert(m_accel,
"&");
00490 }
00491
return result;
00492 }
00493
00494
00495
QChar KAccelString::accelerator()
const
00496
{
00497
if ((m_accel < 0) || (m_accel > (
int)m_pureText.
length()))
00498
return QChar();
00499
00500
return m_pureText[m_accel].
lower();
00501 }
00502
00503
00504
void KAccelString::calculateWeights(
int initialWeight)
00505 {
00506 m_weight.
resize(m_pureText.
length());
00507
00508 uint pos = 0;
00509
bool start_character =
true;
00510
00511
while (pos<m_pureText.
length())
00512 {
00513
QChar c = m_pureText[pos];
00514
00515
int weight = initialWeight+1;
00516
00517
00518
if (pos == 0)
00519 weight += KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT;
00520
00521
00522
if (start_character)
00523 {
00524 weight += KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT;
00525 start_character =
false;
00526 }
00527
00528
00529
if (pos < 50)
00530 weight += (50-pos);
00531
00532
00533
if ((
int)pos == accel()) {
00534 weight += KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT;
00535
00536
if (KAcceleratorManagerPrivate::standardName(m_origText)) {
00537 weight += KAccelManagerAlgorithm::STANDARD_ACCEL;
00538 }
00539 }
00540
00541
00542
if (!c.
isLetterOrNumber())
00543 {
00544 weight = 0;
00545 start_character =
true;
00546 }
00547
00548 m_weight[pos] = weight;
00549
00550 ++pos;
00551 }
00552 }
00553
00554
00555
int KAccelString::stripAccelerator(
QString &text)
00556 {
00557
00558
int p = 0;
00559
00560
while (p >= 0)
00561 {
00562 p = text.
find(
'&', p)+1;
00563
00564
if (p <= 0 || p >= (
int)text.
length())
00565
return -1;
00566
00567
if (text[p] !=
'&')
00568 {
00569
QChar c = text[p];
00570
if (c.
isPrint())
00571 {
00572 text.remove(p-1,1);
00573
return p-1;
00574 }
00575 }
00576
00577 p++;
00578 }
00579
00580
return -1;
00581 }
00582
00583
00584
int KAccelString::maxWeight(
int &index,
const QString &used)
00585 {
00586
int max = 0;
00587 index = -1;
00588
00589
for (uint pos=0; pos<m_pureText.
length(); ++pos)
00590
if (used.
find(m_pureText[pos], 0, FALSE) == -1 && m_pureText[pos].
latin1() != 0)
00591
if (m_weight[pos] > max)
00592 {
00593 max = m_weight[pos];
00594 index = pos;
00595 }
00596
00597
return max;
00598 }
00599
00600
00601
void KAccelString::dump()
00602 {
00603
QString s;
00604
for (uint i=0; i<m_weight.
count(); ++i)
00605 s +=
QString(
"%1(%2) ").
arg(pure()[i]).arg(m_weight[i]);
00606 kdDebug() <<
"s " << s <<
endl;
00607 }
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
void KAccelManagerAlgorithm::findAccelerators(
KAccelStringList &result, QString &used)
00644 {
00645
KAccelStringList accel_strings = result;
00646
00647
00648
for (KAccelStringList::Iterator it = result.
begin(); it != result.
end(); ++it)
00649 (*it).setAccel(-1);
00650
00651
00652
for (uint cnt=0; cnt<accel_strings.
count(); ++cnt)
00653 {
00654
int max = 0, index = -1, accel = -1;
00655
00656
00657
for (uint i=0; i<accel_strings.
count(); ++i)
00658 {
00659
int a;
00660
int m = accel_strings[i].maxWeight(a, used);
00661
if (m>max)
00662 {
00663 max = m;
00664 index = i;
00665 accel = a;
00666 }
00667 }
00668
00669
00670
if (index < 0)
00671
return;
00672
00673
00674
if (accel >= 0)
00675 {
00676 result[index].setAccel(accel);
00677 used.
append(result[index].accelerator());
00678 }
00679
00680
00681 accel_strings[index] =
KAccelString();
00682 }
00683 }
00684
00685
00686
00687
00688
00689
00690
00691
00692 KPopupAccelManager::KPopupAccelManager(
QPopupMenu *popup)
00693 :
QObject(popup), m_popup(popup), m_count(-1)
00694 {
00695 aboutToShow();
00696 connect(popup, SIGNAL(aboutToShow()), SLOT(aboutToShow()));
00697 }
00698
00699
00700
void KPopupAccelManager::aboutToShow()
00701 {
00702
00703
00704
00705
00706
00707
if (m_count != (
int)m_popup->count())
00708 {
00709 findMenuEntries(m_entries);
00710 calculateAccelerators();
00711 m_count = m_popup->count();
00712 }
00713
else
00714 {
00715
KAccelStringList entries;
00716 findMenuEntries(entries);
00717
if (entries != m_entries)
00718 {
00719 m_entries = entries;
00720 calculateAccelerators();
00721 }
00722 }
00723 }
00724
00725
00726
void KPopupAccelManager::calculateAccelerators()
00727 {
00728
00729 QString used;
00730 KAccelManagerAlgorithm::findAccelerators(m_entries, used);
00731
00732
00733 setMenuEntries(m_entries);
00734 }
00735
00736
00737
void KPopupAccelManager::findMenuEntries(
KAccelStringList &list)
00738 {
00739 QMenuItem *mitem;
00740 QString s;
00741
00742 list.
clear();
00743
00744
00745
for (uint i=0; i<m_popup->count(); i++)
00746 {
00747 mitem = m_popup->findItem(m_popup->
idAt(i));
00748
if (mitem->isSeparator())
00749
continue;
00750
00751 s = mitem->text();
00752
00753
00754
int weight = 50;
00755
if (s.
contains(
'\t'))
00756 weight = 0;
00757
00758 list.
append(
KAccelString(s, weight));
00759
00760
00761
if (mitem->popup())
00762 KPopupAccelManager::manage(mitem->popup());
00763 }
00764 }
00765
00766
00767
void KPopupAccelManager::setMenuEntries(
const KAccelStringList &list)
00768 {
00769 QMenuItem *mitem;
00770
00771 uint cnt = 0;
00772
for (uint i=0; i<m_popup->count(); i++)
00773 {
00774 mitem = m_popup->findItem(m_popup->
idAt(i));
00775
if (mitem->isSeparator())
00776
continue;
00777
00778
if (KAcceleratorManagerPrivate::checkChange(list[cnt]))
00779 mitem->setText(list[cnt].accelerated());
00780 cnt++;
00781 }
00782 }
00783
00784
00785
void KPopupAccelManager::manage(
QPopupMenu *popup)
00786 {
00787
00788
if (popup->child(0,
"KPopupAccelManager",
false) == 0 )
00789
new KPopupAccelManager(popup);
00790 }
00791
00792
00793
#include "kaccelmanager_private.moc"