KDEUI
kcharselect.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 00003 Copyright (C) 1999 Reginald Stadlbauer <reggie@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kcharselect.h" 00022 00023 #include "kcharselect_p.h" 00024 00025 #include <QtGui/QActionEvent> 00026 #include <QtGui/QDoubleSpinBox> 00027 #include <QtGui/QHeaderView> 00028 #include <QtGui/QBoxLayout> 00029 #include <QtGui/QShortcut> 00030 #include <QtGui/QSplitter> 00031 #include <QtGui/QPushButton> 00032 #include <QtGui/QToolButton> 00033 00034 #include <kcombobox.h> 00035 #include <kdebug.h> 00036 #include <kdialog.h> 00037 #include <klocale.h> 00038 #include <klineedit.h> 00039 #include <ktextbrowser.h> 00040 #include <kfontcombobox.h> 00041 #include <kactioncollection.h> 00042 #include <kstandardaction.h> 00043 00044 K_GLOBAL_STATIC(KCharSelectData, s_data) 00045 00046 class KCharSelectTablePrivate 00047 { 00048 public: 00049 KCharSelectTablePrivate(KCharSelectTable *q): q(q), model() 00050 {} 00051 00052 KCharSelectTable *q; 00053 00054 QFont font; 00055 KCharSelectItemModel *model; 00056 QList<QChar> chars; 00057 QChar chr; 00058 00059 void _k_resizeCells(); 00060 void _k_doubleClicked(const QModelIndex & index); 00061 void _k_slotCurrentChanged(const QModelIndex & current, const QModelIndex & previous); 00062 }; 00063 00064 class KCharSelect::KCharSelectPrivate 00065 { 00066 public: 00067 struct HistoryItem 00068 { 00069 QChar c; 00070 bool fromSearch; 00071 QString searchString; 00072 }; 00073 00074 enum { MaxHistoryItems = 100 }; 00075 00076 KCharSelectPrivate(KCharSelect *q) 00077 : q(q) 00078 ,searchLine(0) 00079 ,searchMode(false) 00080 ,historyEnabled(false) 00081 ,inHistory(0) 00082 ,actions(NULL) 00083 { 00084 } 00085 00086 KCharSelect *q; 00087 00088 QToolButton *backButton; 00089 QToolButton *forwardButton; 00090 KLineEdit* searchLine; 00091 KFontComboBox *fontCombo; 00092 QSpinBox *fontSizeSpinBox; 00093 QComboBox *sectionCombo; 00094 QComboBox *blockCombo; 00095 KCharSelectTable *charTable; 00096 KTextBrowser *detailBrowser; 00097 00098 bool searchMode; //a search is active 00099 bool historyEnabled; 00100 int inHistory; //index of current char in history 00101 QList<HistoryItem> history; 00102 KActionCollection* actions; 00103 00104 QString createLinks(QString s); 00105 void historyAdd(const QChar &c, bool fromSearch, const QString &searchString); 00106 void showFromHistory(int index); 00107 void updateBackForwardButtons(); 00108 void _k_activateSearchLine(); 00109 void _k_back(); 00110 void _k_forward(); 00111 void _k_fontSelected(); 00112 void _k_updateCurrentChar(const QChar &c); 00113 void _k_slotUpdateUnicode(const QChar &c); 00114 void _k_sectionSelected(int index); 00115 void _k_blockSelected(int index); 00116 void _k_searchEditChanged(); 00117 void _k_search(); 00118 void _k_linkClicked(QUrl url); 00119 }; 00120 00121 /******************************************************************/ 00122 /* Class: KCharSelectTable */ 00123 /******************************************************************/ 00124 00125 KCharSelectTable::KCharSelectTable(QWidget *parent, const QFont &_font) 00126 : QTableView(parent), d(new KCharSelectTablePrivate(this)) 00127 { 00128 d->font = _font; 00129 00130 setTabKeyNavigation(false); 00131 setSelectionMode(QAbstractItemView::SingleSelection); 00132 QPalette _palette; 00133 _palette.setColor(backgroundRole(), palette().color(QPalette::Base)); 00134 setPalette(_palette); 00135 verticalHeader()->setVisible(false); 00136 verticalHeader()->setResizeMode(QHeaderView::Custom); 00137 horizontalHeader()->setVisible(false); 00138 horizontalHeader()->setResizeMode(QHeaderView::Custom); 00139 00140 setFocusPolicy(Qt::StrongFocus); 00141 setDragEnabled(true); 00142 setAcceptDrops(true); 00143 setDropIndicatorShown(false); 00144 setDragDropMode(QAbstractItemView::DragDrop); 00145 00146 connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(_k_doubleClicked(QModelIndex))); 00147 00148 d->_k_resizeCells(); 00149 } 00150 00151 KCharSelectTable::~KCharSelectTable() 00152 { 00153 delete d; 00154 } 00155 00156 void KCharSelectTable::setFont(const QFont &_font) 00157 { 00158 QTableView::setFont(_font); 00159 d->font = _font; 00160 if (d->model) d->model->setFont(_font); 00161 d->_k_resizeCells(); 00162 } 00163 00164 QChar KCharSelectTable::chr() 00165 { 00166 return d->chr; 00167 } 00168 00169 QFont KCharSelectTable::font() const 00170 { 00171 return d->font; 00172 } 00173 00174 QList<QChar> KCharSelectTable::displayedChars() const 00175 { 00176 return d->chars; 00177 } 00178 00179 void KCharSelectTable::setChar(const QChar &c) 00180 { 00181 int pos = d->chars.indexOf(c); 00182 if (pos != -1) { 00183 setCurrentIndex(model()->index(pos / model()->columnCount(), pos % model()->columnCount())); 00184 } 00185 } 00186 00187 void KCharSelectTable::setContents(QList<QChar> chars) 00188 { 00189 d->chars = chars; 00190 00191 KCharSelectItemModel *m = d->model; 00192 d->model = new KCharSelectItemModel(chars, d->font, this); 00193 setModel(d->model); 00194 d->_k_resizeCells(); 00195 QItemSelectionModel *selectionModel = new QItemSelectionModel(d->model); 00196 setSelectionModel(selectionModel); 00197 setSelectionBehavior(QAbstractItemView::SelectItems); 00198 setSelectionMode(QAbstractItemView::SingleSelection); 00199 connect(selectionModel, SIGNAL(currentChanged(const QModelIndex & , const QModelIndex &)), this, SLOT(_k_slotCurrentChanged(const QModelIndex &, const QModelIndex &))); 00200 connect(d->model, SIGNAL(showCharRequested(QChar)), this, SIGNAL(showCharRequested(QChar))); 00201 delete m; // this should hopefully delete aold selection models too, since it is the parent of them (didn't track, if there are setParent calls somewhere. Check that (jowenn) 00202 } 00203 00204 void KCharSelectTable::scrollTo(const QModelIndex & index, ScrollHint hint) 00205 { 00206 // this prevents horizontal scrolling when selecting a character in the last column 00207 if (index.isValid() && index.column() != 0) { 00208 QTableView::scrollTo(d->model->index(index.row(), 0), hint); 00209 } else { 00210 QTableView::scrollTo(index, hint); 00211 } 00212 } 00213 00214 void KCharSelectTablePrivate::_k_slotCurrentChanged(const QModelIndex & current, const QModelIndex & previous) 00215 { 00216 Q_UNUSED(previous); 00217 if (!model) return; 00218 QVariant temp = model->data(current, KCharSelectItemModel::CharacterRole); 00219 if (temp.type() != QVariant::Char) 00220 return; 00221 QChar c = temp.toChar(); 00222 chr = c; 00223 emit q->focusItemChanged(c); 00224 } 00225 00226 void KCharSelectTable::resizeEvent(QResizeEvent * e) 00227 { 00228 QTableView::resizeEvent(e); 00229 if (e->size().width() != e->oldSize().width()) { 00230 d->_k_resizeCells(); 00231 } 00232 } 00233 00234 void KCharSelectTablePrivate::_k_resizeCells() 00235 { 00236 if (!q->model()) return; 00237 static_cast<KCharSelectItemModel*>(q->model())->updateColumnCount(q->viewport()->size().width()); 00238 00239 QChar oldChar = q->chr(); 00240 00241 const int new_w = q->viewport()->size().width() / q->model()->columnCount(QModelIndex()); 00242 const int columns = q->model()->columnCount(QModelIndex()); 00243 const int rows = q->model()->rowCount(QModelIndex()); 00244 q->setUpdatesEnabled(false); 00245 QHeaderView* hv = q->horizontalHeader(); 00246 int spaceLeft = q->viewport()->size().width() % new_w + 1; 00247 for (int i = 0;i <= columns;i++) { 00248 if (i < spaceLeft) { 00249 hv->resizeSection(i, new_w + 1); 00250 } else { 00251 hv->resizeSection(i, new_w); 00252 } 00253 } 00254 00255 hv = q->verticalHeader(); 00256 #ifdef Q_WS_WIN 00257 const int new_h = QFontMetrics(font).lineSpacing() + 1; 00258 #else 00259 const int new_h = QFontMetrics(font).xHeight() * 3; 00260 #endif 00261 for (int i = 0;i < rows;i++) { 00262 hv->resizeSection(i, new_h); 00263 } 00264 00265 q->setUpdatesEnabled(true); 00266 q->setChar(oldChar); 00267 } 00268 00269 void KCharSelectTablePrivate::_k_doubleClicked(const QModelIndex & index) 00270 { 00271 QChar c = model->data(index, KCharSelectItemModel::CharacterRole).toChar(); 00272 if (c.isPrint()) { 00273 emit q->activated(c); 00274 } 00275 } 00276 00277 void KCharSelectTable::keyPressEvent(QKeyEvent *e) 00278 { 00279 if (d->model) 00280 switch (e->key()) { 00281 case Qt::Key_Space: 00282 emit activated(' '); 00283 return; 00284 break; 00285 case Qt::Key_Enter: case Qt::Key_Return: { 00286 if (!currentIndex().isValid()) return; 00287 QChar c = d->model->data(currentIndex(), KCharSelectItemModel::CharacterRole).toChar(); 00288 if (c.isPrint()) { 00289 emit activated(c); 00290 } 00291 } 00292 return; 00293 break; 00294 } 00295 QTableView::keyPressEvent(e); 00296 } 00297 00298 00299 /******************************************************************/ 00300 /* Class: KCharSelect */ 00301 /******************************************************************/ 00302 00303 #ifndef KDE_NO_DEPRECATED 00304 KCharSelect::KCharSelect(QWidget *parent, const Controls controls) 00305 : QWidget(parent), d(new KCharSelectPrivate(this)) 00306 { 00307 init(controls, NULL); 00308 } 00309 #endif 00310 00311 KCharSelect::KCharSelect( 00312 QWidget *parent 00313 ,KActionCollection *collection 00314 ,const Controls controls) 00315 : QWidget(parent), d(new KCharSelectPrivate(this)) 00316 { 00317 init(controls, collection); 00318 } 00319 00320 void KCharSelect::init(const Controls controls, KActionCollection *collection) 00321 { 00322 if (collection==NULL) { 00323 d->actions = new KActionCollection(this); 00324 d->actions->addAssociatedWidget(this); 00325 } else { 00326 d->actions = collection; 00327 } 00328 00329 QVBoxLayout *mainLayout = new QVBoxLayout(this); 00330 mainLayout->setMargin(0); 00331 if (SearchLine & controls) { 00332 QHBoxLayout *searchLayout = new QHBoxLayout(); 00333 mainLayout->addLayout(searchLayout); 00334 d->searchLine = new KLineEdit(this); 00335 searchLayout->addWidget(d->searchLine); 00336 d->searchLine->setClickMessage(i18n("Enter a search term or character here")); 00337 d->searchLine->setClearButtonShown(true); 00338 d->searchLine->setToolTip(i18n("Enter a search term or character here")); 00339 KStandardAction::find(this, SLOT(_k_activateSearchLine()), d->actions); 00340 connect(d->searchLine, SIGNAL(textChanged(QString)), this, SLOT(_k_searchEditChanged())); 00341 connect(d->searchLine, SIGNAL(returnPressed()), this, SLOT(_k_search())); 00342 } 00343 00344 if ((SearchLine & controls) && ((FontCombo & controls) || (FontSize & controls) || (BlockCombos & controls))) { 00345 QFrame* line = new QFrame(this); 00346 line->setFrameShape(QFrame::HLine); 00347 line->setFrameShadow(QFrame::Sunken); 00348 mainLayout->addWidget(line); 00349 } 00350 00351 QHBoxLayout *comboLayout = new QHBoxLayout(); 00352 00353 d->backButton = new QToolButton(this); 00354 comboLayout->addWidget(d->backButton); 00355 d->backButton->setEnabled(false); 00356 d->backButton->setText(i18nc("Goes to previous character", "Previous in History")); 00357 d->backButton->setIcon(KIcon("go-previous")); 00358 d->backButton->setToolTip(i18n("Previous Character in History")); 00359 00360 d->forwardButton = new QToolButton(this); 00361 comboLayout->addWidget(d->forwardButton); 00362 d->forwardButton->setEnabled(false); 00363 d->forwardButton->setText(i18nc("Goes to next character", "Next in History")); 00364 d->forwardButton->setIcon(KIcon("go-next")); 00365 d->forwardButton->setToolTip(i18n("Next Character in History")); 00366 00367 KStandardAction::back(d->backButton, SLOT(animateClick()), d->actions); 00368 KStandardAction::forward(d->forwardButton, SLOT(animateClick()), d->actions); 00369 connect(d->backButton, SIGNAL(clicked()), this, SLOT(_k_back())); 00370 connect(d->forwardButton, SIGNAL(clicked()), this, SLOT(_k_forward())); 00371 00372 d->sectionCombo = new KComboBox(this); 00373 d->sectionCombo->setToolTip(i18n("Select a category")); 00374 comboLayout->addWidget(d->sectionCombo); 00375 d->blockCombo = new KComboBox(this); 00376 d->blockCombo->setToolTip(i18n("Select a block to be displayed")); 00377 d->blockCombo->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); 00378 comboLayout->addWidget(d->blockCombo, 1); 00379 d->sectionCombo->addItems(s_data->sectionList()); 00380 d->blockCombo->setMinimumWidth(QFontMetrics(QWidget::font()).averageCharWidth() * 25); 00381 00382 connect(d->sectionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_k_sectionSelected(int))); 00383 connect(d->blockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_k_blockSelected(int))); 00384 00385 d->fontCombo = new KFontComboBox(this); 00386 comboLayout->addWidget(d->fontCombo); 00387 d->fontCombo->setEditable(true); 00388 d->fontCombo->resize(d->fontCombo->sizeHint()); 00389 d->fontCombo->setToolTip(i18n("Set font")); 00390 00391 d->fontSizeSpinBox = new QSpinBox(this); 00392 comboLayout->addWidget(d->fontSizeSpinBox); 00393 d->fontSizeSpinBox->setValue(QWidget::font().pointSize()); 00394 d->fontSizeSpinBox->setRange(1, 400); 00395 d->fontSizeSpinBox->setSingleStep(1); 00396 d->fontSizeSpinBox->setToolTip(i18n("Set font size")); 00397 00398 connect(d->fontCombo, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(_k_fontSelected())); 00399 connect(d->fontSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(_k_fontSelected())); 00400 00401 if ((HistoryButtons & controls) || (FontCombo & controls) || (FontSize & controls) || (BlockCombos & controls)) { 00402 mainLayout->addLayout(comboLayout); 00403 } 00404 if (!(HistoryButtons & controls)) { 00405 d->backButton->hide(); 00406 d->forwardButton->hide(); 00407 } 00408 if (!(FontCombo & controls)) { 00409 d->fontCombo->hide(); 00410 } 00411 if (!(FontSize & controls)) { 00412 d->fontSizeSpinBox->hide(); 00413 } 00414 if (!(BlockCombos & controls)) { 00415 d->sectionCombo->hide(); 00416 d->blockCombo->hide(); 00417 } 00418 00419 QSplitter *splitter = new QSplitter(this); 00420 if ((CharacterTable & controls) || (DetailBrowser & controls)) { 00421 mainLayout->addWidget(splitter); 00422 } else { 00423 splitter->hide(); 00424 } 00425 d->charTable = new KCharSelectTable(this, QFont()); 00426 if (CharacterTable & controls) { 00427 splitter->addWidget(d->charTable); 00428 d->charTable->setFocus(Qt::OtherFocusReason); 00429 } else { 00430 d->charTable->hide(); 00431 } 00432 00433 const QSize sz(200, 200); 00434 d->charTable->resize(sz); 00435 d->charTable->setMinimumSize(sz); 00436 00437 d->charTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 00438 00439 setCurrentFont(QFont()); 00440 00441 connect(d->charTable, SIGNAL(focusItemChanged(const QChar &)), this, SLOT(_k_updateCurrentChar(const QChar &))); 00442 connect(d->charTable, SIGNAL(activated(const QChar &)), this, SIGNAL(charSelected(const QChar &))); 00443 connect(d->charTable, SIGNAL(focusItemChanged(const QChar &)), 00444 this, SIGNAL(currentCharChanged(const QChar &))); 00445 00446 connect(d->charTable, SIGNAL(showCharRequested(QChar)), this, SLOT(setCurrentChar(QChar))); 00447 00448 d->detailBrowser = new KTextBrowser(this); 00449 if (DetailBrowser & controls) { 00450 splitter->addWidget(d->detailBrowser); 00451 } else { 00452 d->detailBrowser->hide(); 00453 } 00454 d->detailBrowser->setOpenLinks(false); 00455 connect(d->detailBrowser, SIGNAL(anchorClicked(QUrl)), this, SLOT(_k_linkClicked(QUrl))); 00456 00457 setFocusPolicy(Qt::StrongFocus); 00458 setFocusProxy(d->charTable); 00459 d->_k_sectionSelected(0); 00460 d->_k_blockSelected(0); 00461 setCurrentChar(0x0); 00462 00463 d->historyEnabled = true; 00464 } 00465 00466 KCharSelect::~KCharSelect() 00467 { 00468 delete d; 00469 } 00470 00471 QSize KCharSelect::sizeHint() const 00472 { 00473 return QWidget::sizeHint(); 00474 } 00475 00476 void KCharSelect::setCurrentFont(const QFont &_font) 00477 { 00478 d->fontCombo->setCurrentFont(_font); 00479 d->fontSizeSpinBox->setValue(_font.pointSize()); 00480 d->_k_fontSelected(); 00481 } 00482 00483 QChar KCharSelect::currentChar() const 00484 { 00485 return d->charTable->chr(); 00486 } 00487 00488 QFont KCharSelect::currentFont() const 00489 { 00490 return d->charTable->font(); 00491 } 00492 00493 QList<QChar> KCharSelect::displayedChars() const 00494 { 00495 return d->charTable->displayedChars(); 00496 } 00497 00498 void KCharSelect::setCurrentChar(const QChar &c) 00499 { 00500 bool oldHistoryEnabled = d->historyEnabled; 00501 d->historyEnabled = false; 00502 int block = s_data->blockIndex(c); 00503 int section = s_data->sectionIndex(block); 00504 d->sectionCombo->setCurrentIndex(section); 00505 int index = d->blockCombo->findData(block); 00506 if (index != -1) { 00507 d->blockCombo->setCurrentIndex(index); 00508 } 00509 d->historyEnabled = oldHistoryEnabled; 00510 d->charTable->setChar(c); 00511 } 00512 00513 void KCharSelect::KCharSelectPrivate::historyAdd(const QChar &c, bool fromSearch, const QString &searchString) 00514 { 00515 //kDebug() << "about to add char" << c << "fromSearch" << fromSearch << "searchString" << searchString; 00516 00517 if (!historyEnabled) { 00518 return; 00519 } 00520 00521 if (!history.isEmpty() && c == history.last().c) { 00522 //avoid duplicates 00523 return; 00524 } 00525 00526 //behave like a web browser, i.e. if user goes back from B to A then clicks C, B is forgotten 00527 while (!history.isEmpty() && inHistory != history.count() - 1) { 00528 history.removeLast(); 00529 } 00530 00531 while (history.size() >= MaxHistoryItems) { 00532 history.removeFirst(); 00533 } 00534 00535 HistoryItem item; 00536 item.c = c; 00537 item.fromSearch = fromSearch; 00538 item.searchString = searchString; 00539 history.append(item); 00540 00541 inHistory = history.count() - 1; 00542 updateBackForwardButtons(); 00543 } 00544 00545 void KCharSelect::KCharSelectPrivate::showFromHistory(int index) 00546 { 00547 Q_ASSERT(index >= 0 && index < history.count()); 00548 Q_ASSERT(index != inHistory); 00549 00550 inHistory = index; 00551 updateBackForwardButtons(); 00552 00553 const HistoryItem &item = history[index]; 00554 //kDebug() << "index" << index << "char" << item.c << "fromSearch" << item.fromSearch 00555 // << "searchString" << item.searchString; 00556 00557 //avoid adding an item from history into history again 00558 bool oldHistoryEnabled = historyEnabled; 00559 historyEnabled = false; 00560 if (item.fromSearch) { 00561 if (searchLine->text() != item.searchString) { 00562 searchLine->setText(item.searchString); 00563 _k_search(); 00564 } 00565 charTable->setChar(item.c); 00566 } else { 00567 searchLine->clear(); 00568 q->setCurrentChar(item.c); 00569 } 00570 historyEnabled = oldHistoryEnabled; 00571 } 00572 00573 void KCharSelect::KCharSelectPrivate::updateBackForwardButtons() 00574 { 00575 backButton->setEnabled(inHistory > 0); 00576 forwardButton->setEnabled(inHistory < history.count() - 1); 00577 } 00578 00579 void KCharSelect::KCharSelectPrivate::_k_activateSearchLine() 00580 { 00581 searchLine->setFocus(); 00582 searchLine->selectAll(); 00583 } 00584 00585 void KCharSelect::KCharSelectPrivate::_k_back() 00586 { 00587 Q_ASSERT(inHistory > 0); 00588 showFromHistory(inHistory - 1); 00589 } 00590 00591 void KCharSelect::KCharSelectPrivate::_k_forward() 00592 { 00593 Q_ASSERT(inHistory + 1 < history.count()); 00594 showFromHistory(inHistory + 1); 00595 } 00596 00597 void KCharSelect::KCharSelectPrivate::_k_fontSelected() 00598 { 00599 QFont font = fontCombo->currentFont(); 00600 font.setPointSize(fontSizeSpinBox->value()); 00601 charTable->setFont(font); 00602 emit q->currentFontChanged(font); 00603 } 00604 00605 void KCharSelect::KCharSelectPrivate::_k_updateCurrentChar(const QChar &c) 00606 { 00607 if (searchMode) { 00608 //we are in search mode. make the two comboboxes show the section & block for this character. 00609 //(when we are not in search mode the current character always belongs to the current section & block.) 00610 int block = s_data->blockIndex(c); 00611 int section = s_data->sectionIndex(block); 00612 sectionCombo->setCurrentIndex(section); 00613 int index = blockCombo->findData(block); 00614 if (index != -1) { 00615 blockCombo->setCurrentIndex(index); 00616 } 00617 } 00618 00619 if( searchLine) 00620 historyAdd(c, searchMode, searchLine->text()); 00621 00622 _k_slotUpdateUnicode(c); 00623 } 00624 00625 void KCharSelect::KCharSelectPrivate::_k_slotUpdateUnicode(const QChar &c) 00626 { 00627 QString html = "<p>" + i18n("Character:") + ' ' + s_data->display(c, charTable->font()) + ' ' + 00628 s_data->formatCode(c.unicode()) + "<br />"; 00629 00630 QString name = s_data->name(c); 00631 if (!name.isEmpty()) { 00632 //is name ever empty? </p> should always be there... 00633 html += i18n("Name: ") + Qt::escape(name) + "</p>"; 00634 } 00635 QStringList aliases = s_data->aliases(c); 00636 QStringList notes = s_data->notes(c); 00637 QList<QChar> seeAlso = s_data->seeAlso(c); 00638 QStringList equivalents = s_data->equivalents(c); 00639 QStringList approxEquivalents = s_data->approximateEquivalents(c); 00640 if (!(aliases.isEmpty() && notes.isEmpty() && seeAlso.isEmpty() && equivalents.isEmpty() && approxEquivalents.isEmpty())) { 00641 html += "<p><b>" + i18n("Annotations and Cross References") + "</b></p>"; 00642 } 00643 00644 if (!aliases.isEmpty()) { 00645 html += "<p style=\"margin-bottom: 0px;\">" + i18n("Alias names:") + "</p><ul style=\"margin-top: 0px;\">"; 00646 foreach(const QString &alias, aliases) { 00647 html += "<li>" + Qt::escape(alias) + "</li>"; 00648 } 00649 html += "</ul>"; 00650 } 00651 00652 if (!notes.isEmpty()) { 00653 html += "<p style=\"margin-bottom: 0px;\">" + i18n("Notes:") + "</p><ul style=\"margin-top: 0px;\">"; 00654 foreach(const QString ¬e, notes) { 00655 html += "<li>" + createLinks(Qt::escape(note)) + "</li>"; 00656 } 00657 html += "</ul>"; 00658 } 00659 00660 if (!seeAlso.isEmpty()) { 00661 html += "<p style=\"margin-bottom: 0px;\">" + i18n("See also:") + "</p><ul style=\"margin-top: 0px;\">"; 00662 foreach(const QChar &c2, seeAlso) { 00663 html += "<li><a href=\"" + QString::number(c2.unicode(), 16) + "\">"; 00664 if (c2.isPrint()) { 00665 html += "&#" + QString::number(c2.unicode()) + "; "; 00666 } 00667 html += s_data->formatCode(c2.unicode()) + ' ' + Qt::escape(s_data->name(c2)) + "</a></li>"; 00668 } 00669 html += "</ul>"; 00670 } 00671 00672 if (!equivalents.isEmpty()) { 00673 html += "<p style=\"margin-bottom: 0px;\">" + i18n("Equivalents:") + "</p><ul style=\"margin-top: 0px;\">"; 00674 foreach(const QString &equivalent, equivalents) { 00675 html += "<li>" + createLinks(Qt::escape(equivalent)) + "</li>"; 00676 } 00677 html += "</ul>"; 00678 } 00679 00680 if (!approxEquivalents.isEmpty()) { 00681 html += "<p style=\"margin-bottom: 0px;\">" + i18n("Approximate equivalents:") + "</p><ul style=\"margin-top: 0px;\">"; 00682 foreach(const QString &approxEquivalent, approxEquivalents) { 00683 html += "<li>" + createLinks(Qt::escape(approxEquivalent)) + "</li>"; 00684 } 00685 html += "</ul>"; 00686 } 00687 00688 QStringList unihan = s_data->unihanInfo(c); 00689 if (unihan.count() == 7) { 00690 html += "<p><b>" + i18n("CJK Ideograph Information") + "</b></p><p>"; 00691 bool newline = true; 00692 if (!unihan[0].isEmpty()) { 00693 html += i18n("Definition in English: ") + unihan[0]; 00694 newline = false; 00695 } 00696 if (!unihan[2].isEmpty()) { 00697 if (!newline) html += "<br>"; 00698 html += i18n("Mandarin Pronunciation: ") + unihan[2]; 00699 newline = false; 00700 } 00701 if (!unihan[1].isEmpty()) { 00702 if (!newline) html += "<br>"; 00703 html += i18n("Cantonese Pronunciation: ") + unihan[1]; 00704 newline = false; 00705 } 00706 if (!unihan[6].isEmpty()) { 00707 if (!newline) html += "<br>"; 00708 html += i18n("Japanese On Pronunciation: ") + unihan[6]; 00709 newline = false; 00710 } 00711 if (!unihan[5].isEmpty()) { 00712 if (!newline) html += "<br>"; 00713 html += i18n("Japanese Kun Pronunciation: ") + unihan[5]; 00714 newline = false; 00715 } 00716 if (!unihan[3].isEmpty()) { 00717 if (!newline) html += "<br>"; 00718 html += i18n("Tang Pronunciation: ") + unihan[3]; 00719 newline = false; 00720 } 00721 if (!unihan[4].isEmpty()) { 00722 if (!newline) html += "<br>"; 00723 html += i18n("Korean Pronunciation: ") + unihan[4]; 00724 newline = false; 00725 } 00726 html += "</p>"; 00727 } 00728 00729 html += "<p><b>" + i18n("General Character Properties") + "</b><br>"; 00730 html += i18n("Block: ") + s_data->block(c) + "<br>"; 00731 html += i18n("Unicode category: ") + s_data->categoryText(c.category()) + "</p>"; 00732 00733 QByteArray utf8 = QString(c).toUtf8(); 00734 00735 html += "<p><b>" + i18n("Various Useful Representations") + "</b><br>"; 00736 html += i18n("UTF-8:"); 00737 foreach(unsigned char c, utf8) 00738 html += ' ' + s_data->formatCode(c, 2, "0x"); 00739 html += "<br>" + i18n("UTF-16: ") + s_data->formatCode(c.unicode(), 4, "0x") + "<br>"; 00740 html += i18n("C octal escaped UTF-8: "); 00741 foreach(unsigned char c, utf8) 00742 html += s_data->formatCode(c, 3, "\\", 8); 00743 html += "<br>" + i18n("XML decimal entity:") + " &#" + QString::number(c.unicode()) + ";</p>"; 00744 00745 detailBrowser->setHtml(html); 00746 } 00747 00748 QString KCharSelect::KCharSelectPrivate::createLinks(QString s) 00749 { 00750 QRegExp rx("\\b([\\dABCDEF]{4})\\b"); 00751 00752 QStringList chars; 00753 int pos = 0; 00754 00755 while ((pos = rx.indexIn(s, pos)) != -1) { 00756 chars << rx.cap(1); 00757 pos += rx.matchedLength(); 00758 } 00759 00760 QSet<QString> chars2 = QSet<QString>::fromList(chars); 00761 foreach(const QString &c, chars2) { 00762 int unicode = c.toInt(0, 16); 00763 QString link = "<a href=\"" + c + "\">"; 00764 if (QChar(unicode).isPrint()) { 00765 link += "&#" + QString::number(unicode) + "; "; 00766 } 00767 link += "U+" + c + ' '; 00768 link += Qt::escape(s_data->name(QChar(unicode))) + "</a>"; 00769 s.replace(c, link); 00770 } 00771 return s; 00772 } 00773 00774 void KCharSelect::KCharSelectPrivate::_k_sectionSelected(int index) 00775 { 00776 blockCombo->clear(); 00777 QList<int> blocks = s_data->sectionContents(index); 00778 foreach(int block, blocks) { 00779 blockCombo->addItem(s_data->blockName(block), QVariant(block)); 00780 } 00781 blockCombo->setCurrentIndex(0); 00782 } 00783 00784 void KCharSelect::KCharSelectPrivate::_k_blockSelected(int index) 00785 { 00786 if (index == -1) { 00787 //the combo box has been cleared and is about to be filled again (because the section has changed) 00788 return; 00789 } 00790 if (searchMode) { 00791 //we are in search mode, so don't fill the table with this block. 00792 return; 00793 } 00794 00795 int block = blockCombo->itemData(index).toInt(); 00796 const QList<QChar> contents = s_data->blockContents(block); 00797 if(contents.count() <= index) { 00798 return; 00799 } 00800 charTable->setContents(contents); 00801 emit q->displayedCharsChanged(); 00802 charTable->setChar(contents[0]); 00803 } 00804 00805 void KCharSelect::KCharSelectPrivate::_k_searchEditChanged() 00806 { 00807 if (searchLine->text().isEmpty()) { 00808 sectionCombo->setEnabled(true); 00809 blockCombo->setEnabled(true); 00810 00811 //upon leaving search mode, keep the same character selected 00812 searchMode = false; 00813 QChar c = charTable->chr(); 00814 bool oldHistoryEnabled = historyEnabled; 00815 historyEnabled = false; 00816 _k_blockSelected(blockCombo->currentIndex()); 00817 historyEnabled = oldHistoryEnabled; 00818 q->setCurrentChar(c); 00819 } else { 00820 sectionCombo->setEnabled(false); 00821 blockCombo->setEnabled(false); 00822 00823 int length = searchLine->text().length(); 00824 if (length >= 3) { 00825 _k_search(); 00826 } 00827 } 00828 } 00829 00830 void KCharSelect::KCharSelectPrivate::_k_search() 00831 { 00832 if (searchLine->text().isEmpty()) { 00833 return; 00834 } 00835 searchMode = true; 00836 const QList<QChar> contents = s_data->find(searchLine->text()); 00837 charTable->setContents(contents); 00838 emit q->displayedCharsChanged(); 00839 if (!contents.isEmpty()) { 00840 charTable->setChar(contents[0]); 00841 } 00842 } 00843 00844 void KCharSelect::KCharSelectPrivate::_k_linkClicked(QUrl url) 00845 { 00846 QString hex = url.toString(); 00847 if (hex.size() > 4) { 00848 return; 00849 } 00850 int unicode = hex.toInt(0, 16); 00851 searchLine->clear(); 00852 q->setCurrentChar(QChar(unicode)); 00853 } 00854 00856 00857 QVariant KCharSelectItemModel::data(const QModelIndex &index, int role) const 00858 { 00859 int pos = m_columns * (index.row()) + index.column(); 00860 if (pos >= m_chars.size() || index.row() < 0 || index.column() < 0) { 00861 if (role == Qt::BackgroundColorRole) { 00862 return QVariant(qApp->palette().color(QPalette::Button)); 00863 } 00864 return QVariant(); 00865 } 00866 00867 QChar c = m_chars[pos]; 00868 if (!index.isValid()) 00869 return QVariant(); 00870 else if (role == Qt::ToolTipRole) { 00871 QString result = s_data->display(c, m_font) + "<br />" + Qt::escape(s_data->name(c)) + "<br />" + 00872 i18n("Unicode code point:") + ' ' + s_data->formatCode(c.unicode()) + "<br />" + 00873 i18nc("Character", "In decimal:") + ' ' + QString::number(c.unicode()); 00874 return QVariant(result); 00875 } else if (role == Qt::TextAlignmentRole) 00876 return QVariant(Qt::AlignHCenter | Qt::AlignVCenter); 00877 else if (role == Qt::DisplayRole) { 00878 if (c.isPrint()) 00879 return QVariant(c); 00880 return QVariant(); 00881 } else if (role == Qt::BackgroundColorRole) { 00882 QFontMetrics fm = QFontMetrics(m_font); 00883 if (fm.inFont(c) && c.isPrint()) 00884 return QVariant(qApp->palette().color(QPalette::Base)); 00885 else 00886 return QVariant(qApp->palette().color(QPalette::Button)); 00887 } else if (role == Qt::FontRole) 00888 return QVariant(m_font); 00889 else if (role == CharacterRole) { 00890 return QVariant(c); 00891 } 00892 return QVariant(); 00893 } 00894 00895 #include "kcharselect.moc" 00896 #include "kcharselect_p.moc"
KDE 4.6 API Reference