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