kdelibs/kdeui/widgets/kcharselect.cpp
2014-11-19 15:17:14 +00:00

895 lines
28 KiB
C++

/* This file is part of the KDE libraries
Copyright (C) 1999 Reginald Stadlbauer <reggie@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kcharselect.h"
#include "kcharselect_p.h"
#include <QtGui/QActionEvent>
#include <QtGui/QDoubleSpinBox>
#include <QtGui/QHeaderView>
#include <QtGui/QBoxLayout>
#include <QtGui/QShortcut>
#include <QtGui/QSplitter>
#include <QtGui/QPushButton>
#include <QtGui/QToolButton>
#include <kcombobox.h>
#include <kdebug.h>
#include <kdialog.h>
#include <klocale.h>
#include <klineedit.h>
#include <ktextbrowser.h>
#include <kfontcombobox.h>
#include <kactioncollection.h>
#include <kstandardaction.h>
K_GLOBAL_STATIC(KCharSelectData, s_data)
class KCharSelectTablePrivate
{
public:
KCharSelectTablePrivate(KCharSelectTable *q): q(q), model(0)
{}
KCharSelectTable *q;
QFont font;
KCharSelectItemModel *model;
QList<QChar> chars;
QChar chr;
void _k_resizeCells();
void _k_doubleClicked(const QModelIndex & index);
void _k_slotSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected);
};
class KCharSelect::KCharSelectPrivate
{
public:
struct HistoryItem
{
QChar c;
bool fromSearch;
QString searchString;
};
enum { MaxHistoryItems = 100 };
KCharSelectPrivate(KCharSelect *q)
: q(q)
,searchLine(0)
,searchMode(false)
,historyEnabled(false)
,inHistory(0)
,actions(NULL)
{
}
KCharSelect *q;
QToolButton *backButton;
QToolButton *forwardButton;
KLineEdit* searchLine;
KFontComboBox *fontCombo;
QSpinBox *fontSizeSpinBox;
QComboBox *sectionCombo;
QComboBox *blockCombo;
KCharSelectTable *charTable;
KTextBrowser *detailBrowser;
bool searchMode; //a search is active
bool historyEnabled;
int inHistory; //index of current char in history
QList<HistoryItem> history;
KActionCollection* actions;
QString createLinks(QString s);
void historyAdd(const QChar &c, bool fromSearch, const QString &searchString);
void showFromHistory(int index);
void updateBackForwardButtons();
void _k_activateSearchLine();
void _k_back();
void _k_forward();
void _k_fontSelected();
void _k_updateCurrentChar(const QChar &c);
void _k_slotUpdateUnicode(const QChar &c);
void _k_sectionSelected(int index);
void _k_blockSelected(int index);
void _k_searchEditChanged();
void _k_search();
void _k_linkClicked(QUrl url);
};
/******************************************************************/
/* Class: KCharSelectTable */
/******************************************************************/
KCharSelectTable::KCharSelectTable(QWidget *parent, const QFont &_font)
: QTableView(parent), d(new KCharSelectTablePrivate(this))
{
d->font = _font;
setTabKeyNavigation(false);
setSelectionMode(QAbstractItemView::SingleSelection);
QPalette _palette;
_palette.setColor(backgroundRole(), palette().color(QPalette::Base));
setPalette(_palette);
verticalHeader()->setVisible(false);
verticalHeader()->setResizeMode(QHeaderView::Custom);
horizontalHeader()->setVisible(false);
horizontalHeader()->setResizeMode(QHeaderView::Custom);
setFocusPolicy(Qt::StrongFocus);
setDragEnabled(true);
setAcceptDrops(true);
setDropIndicatorShown(false);
setDragDropMode(QAbstractItemView::DragDrop);
connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(_k_doubleClicked(QModelIndex)));
d->_k_resizeCells();
}
KCharSelectTable::~KCharSelectTable()
{
delete d;
}
void KCharSelectTable::setFont(const QFont &_font)
{
QTableView::setFont(_font);
d->font = _font;
if (d->model) d->model->setFont(_font);
d->_k_resizeCells();
}
QChar KCharSelectTable::chr()
{
return d->chr;
}
QFont KCharSelectTable::font() const
{
return d->font;
}
QList<QChar> KCharSelectTable::displayedChars() const
{
return d->chars;
}
void KCharSelectTable::setChar(const QChar &c)
{
int pos = d->chars.indexOf(c);
if (pos != -1) {
setCurrentIndex(model()->index(pos / model()->columnCount(), pos % model()->columnCount()));
}
}
void KCharSelectTable::setContents(QList<QChar> chars)
{
d->chars = chars;
KCharSelectItemModel *m = d->model;
d->model = new KCharSelectItemModel(chars, d->font, this);
setModel(d->model);
d->_k_resizeCells();
QItemSelectionModel *selectionModel = new QItemSelectionModel(d->model);
setSelectionModel(selectionModel);
setSelectionBehavior(QAbstractItemView::SelectItems);
setSelectionMode(QAbstractItemView::SingleSelection);
connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(_k_slotSelectionChanged(QItemSelection,QItemSelection)));
connect(d->model, SIGNAL(showCharRequested(QChar)), this, SIGNAL(showCharRequested(QChar)));
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)
}
void KCharSelectTable::scrollTo(const QModelIndex & index, ScrollHint hint)
{
// this prevents horizontal scrolling when selecting a character in the last column
if (index.isValid() && index.column() != 0) {
QTableView::scrollTo(d->model->index(index.row(), 0), hint);
} else {
QTableView::scrollTo(index, hint);
}
}
void KCharSelectTablePrivate::_k_slotSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected)
{
Q_UNUSED(deselected);
if (!model || selected.indexes().isEmpty())
return;
QVariant temp = model->data(selected.indexes().at(0), KCharSelectItemModel::CharacterRole);
if (temp.type() != QVariant::Char)
return;
QChar c = temp.toChar();
chr = c;
emit q->focusItemChanged(c);
}
void KCharSelectTable::resizeEvent(QResizeEvent * e)
{
QTableView::resizeEvent(e);
if (e->size().width() != e->oldSize().width()) {
d->_k_resizeCells();
}
}
void KCharSelectTablePrivate::_k_resizeCells()
{
if (!q->model()) return;
static_cast<KCharSelectItemModel*>(q->model())->updateColumnCount(q->viewport()->size().width());
QChar oldChar = q->chr();
const int new_w = q->viewport()->size().width() / q->model()->columnCount(QModelIndex());
const int columns = q->model()->columnCount(QModelIndex());
const int rows = q->model()->rowCount(QModelIndex());
q->setUpdatesEnabled(false);
QHeaderView* hv = q->horizontalHeader();
int spaceLeft = q->viewport()->size().width() % new_w + 1;
for (int i = 0;i <= columns;i++) {
if (i < spaceLeft) {
hv->resizeSection(i, new_w + 1);
} else {
hv->resizeSection(i, new_w);
}
}
hv = q->verticalHeader();
int new_h = QFontMetrics(font).xHeight() * 3;
if (new_h < 5 || new_h < 4 + QFontMetrics(font).height()) {
new_h = qMax(5, 4 + QFontMetrics(font).height());
}
for (int i = 0;i < rows;i++) {
hv->resizeSection(i, new_h);
}
q->setUpdatesEnabled(true);
q->setChar(oldChar);
}
void KCharSelectTablePrivate::_k_doubleClicked(const QModelIndex & index)
{
QChar c = model->data(index, KCharSelectItemModel::CharacterRole).toChar();
if (s_data->isPrint(c)) {
emit q->activated(c);
}
}
void KCharSelectTable::keyPressEvent(QKeyEvent *e)
{
if (d->model)
switch (e->key()) {
case Qt::Key_Space:
emit activated(' ');
return;
break;
case Qt::Key_Enter: case Qt::Key_Return: {
if (!currentIndex().isValid()) return;
QChar c = d->model->data(currentIndex(), KCharSelectItemModel::CharacterRole).toChar();
if (s_data->isPrint(c)) {
emit activated(c);
}
}
return;
break;
}
QTableView::keyPressEvent(e);
}
/******************************************************************/
/* Class: KCharSelect */
/******************************************************************/
#ifndef KDE_NO_DEPRECATED
KCharSelect::KCharSelect(QWidget *parent, const Controls controls)
: QWidget(parent), d(new KCharSelectPrivate(this))
{
init(controls, NULL);
}
#endif
KCharSelect::KCharSelect(
QWidget *parent
,KActionCollection *collection
,const Controls controls)
: QWidget(parent), d(new KCharSelectPrivate(this))
{
init(controls, collection);
}
void KCharSelect::init(const Controls controls, KActionCollection *collection)
{
if (collection==NULL) {
d->actions = new KActionCollection(this);
d->actions->addAssociatedWidget(this);
} else {
d->actions = collection;
}
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setMargin(0);
if (SearchLine & controls) {
QHBoxLayout *searchLayout = new QHBoxLayout();
mainLayout->addLayout(searchLayout);
d->searchLine = new KLineEdit(this);
searchLayout->addWidget(d->searchLine);
d->searchLine->setClickMessage(i18n("Enter a search term or character here"));
d->searchLine->setClearButtonShown(true);
d->searchLine->setToolTip(i18n("Enter a search term or character here"));
KStandardAction::find(this, SLOT(_k_activateSearchLine()), d->actions);
connect(d->searchLine, SIGNAL(textChanged(QString)), this, SLOT(_k_searchEditChanged()));
connect(d->searchLine, SIGNAL(returnPressed()), this, SLOT(_k_search()));
}
if ((SearchLine & controls) && ((FontCombo & controls) || (FontSize & controls) || (BlockCombos & controls))) {
QFrame* line = new QFrame(this);
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
mainLayout->addWidget(line);
}
QHBoxLayout *comboLayout = new QHBoxLayout();
d->backButton = new QToolButton(this);
comboLayout->addWidget(d->backButton);
d->backButton->setEnabled(false);
d->backButton->setText(i18nc("Goes to previous character", "Previous in History"));
d->backButton->setIcon(KIcon("go-previous"));
d->backButton->setToolTip(i18n("Previous Character in History"));
d->forwardButton = new QToolButton(this);
comboLayout->addWidget(d->forwardButton);
d->forwardButton->setEnabled(false);
d->forwardButton->setText(i18nc("Goes to next character", "Next in History"));
d->forwardButton->setIcon(KIcon("go-next"));
d->forwardButton->setToolTip(i18n("Next Character in History"));
KStandardAction::back(d->backButton, SLOT(animateClick()), d->actions);
KStandardAction::forward(d->forwardButton, SLOT(animateClick()), d->actions);
connect(d->backButton, SIGNAL(clicked()), this, SLOT(_k_back()));
connect(d->forwardButton, SIGNAL(clicked()), this, SLOT(_k_forward()));
d->sectionCombo = new KComboBox(this);
d->sectionCombo->setToolTip(i18n("Select a category"));
comboLayout->addWidget(d->sectionCombo);
d->blockCombo = new KComboBox(this);
d->blockCombo->setToolTip(i18n("Select a block to be displayed"));
d->blockCombo->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
comboLayout->addWidget(d->blockCombo, 1);
d->sectionCombo->addItems(s_data->sectionList());
d->blockCombo->setMinimumWidth(QFontMetrics(QWidget::font()).averageCharWidth() * 25);
connect(d->sectionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_k_sectionSelected(int)));
connect(d->blockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_k_blockSelected(int)));
d->fontCombo = new KFontComboBox(this);
comboLayout->addWidget(d->fontCombo);
d->fontCombo->setEditable(true);
d->fontCombo->resize(d->fontCombo->sizeHint());
d->fontCombo->setToolTip(i18n("Set font"));
d->fontSizeSpinBox = new QSpinBox(this);
comboLayout->addWidget(d->fontSizeSpinBox);
d->fontSizeSpinBox->setValue(QWidget::font().pointSize());
d->fontSizeSpinBox->setRange(1, 400);
d->fontSizeSpinBox->setSingleStep(1);
d->fontSizeSpinBox->setToolTip(i18n("Set font size"));
connect(d->fontCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(_k_fontSelected()));
connect(d->fontSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(_k_fontSelected()));
if ((HistoryButtons & controls) || (FontCombo & controls) || (FontSize & controls) || (BlockCombos & controls)) {
mainLayout->addLayout(comboLayout);
}
if (!(HistoryButtons & controls)) {
d->backButton->hide();
d->forwardButton->hide();
}
if (!(FontCombo & controls)) {
d->fontCombo->hide();
}
if (!(FontSize & controls)) {
d->fontSizeSpinBox->hide();
}
if (!(BlockCombos & controls)) {
d->sectionCombo->hide();
d->blockCombo->hide();
}
QSplitter *splitter = new QSplitter(this);
if ((CharacterTable & controls) || (DetailBrowser & controls)) {
mainLayout->addWidget(splitter);
} else {
splitter->hide();
}
d->charTable = new KCharSelectTable(this, QFont());
if (CharacterTable & controls) {
splitter->addWidget(d->charTable);
d->charTable->setFocus(Qt::OtherFocusReason);
} else {
d->charTable->hide();
}
const QSize sz(200, 200);
d->charTable->resize(sz);
d->charTable->setMinimumSize(sz);
d->charTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setCurrentFont(QFont());
connect(d->charTable, SIGNAL(focusItemChanged(QChar)), this, SLOT(_k_updateCurrentChar(QChar)));
connect(d->charTable, SIGNAL(activated(QChar)), this, SIGNAL(charSelected(QChar)));
connect(d->charTable, SIGNAL(focusItemChanged(QChar)),
this, SIGNAL(currentCharChanged(QChar)));
connect(d->charTable, SIGNAL(showCharRequested(QChar)), this, SLOT(setCurrentChar(QChar)));
d->detailBrowser = new KTextBrowser(this);
if (DetailBrowser & controls) {
splitter->addWidget(d->detailBrowser);
} else {
d->detailBrowser->hide();
}
d->detailBrowser->setOpenLinks(false);
connect(d->detailBrowser, SIGNAL(anchorClicked(QUrl)), this, SLOT(_k_linkClicked(QUrl)));
setFocusPolicy(Qt::StrongFocus);
setFocusProxy(d->charTable);
d->_k_sectionSelected(0);
d->_k_blockSelected(0);
setCurrentChar(0x0);
d->historyEnabled = true;
}
KCharSelect::~KCharSelect()
{
delete d;
}
QSize KCharSelect::sizeHint() const
{
return QWidget::sizeHint();
}
void KCharSelect::setCurrentFont(const QFont &_font)
{
d->fontCombo->setCurrentFont(_font);
d->fontSizeSpinBox->setValue(_font.pointSize());
d->_k_fontSelected();
}
QChar KCharSelect::currentChar() const
{
return d->charTable->chr();
}
QFont KCharSelect::currentFont() const
{
return d->charTable->font();
}
QList<QChar> KCharSelect::displayedChars() const
{
return d->charTable->displayedChars();
}
void KCharSelect::setCurrentChar(const QChar &c)
{
bool oldHistoryEnabled = d->historyEnabled;
d->historyEnabled = false;
int block = s_data->blockIndex(c);
int section = s_data->sectionIndex(block);
d->sectionCombo->setCurrentIndex(section);
int index = d->blockCombo->findData(block);
if (index != -1) {
d->blockCombo->setCurrentIndex(index);
}
d->historyEnabled = oldHistoryEnabled;
d->charTable->setChar(c);
}
void KCharSelect::KCharSelectPrivate::historyAdd(const QChar &c, bool fromSearch, const QString &searchString)
{
//kDebug() << "about to add char" << c << "fromSearch" << fromSearch << "searchString" << searchString;
if (!historyEnabled) {
return;
}
if (!history.isEmpty() && c == history.last().c) {
//avoid duplicates
return;
}
//behave like a web browser, i.e. if user goes back from B to A then clicks C, B is forgotten
while (!history.isEmpty() && inHistory != history.count() - 1) {
history.removeLast();
}
while (history.size() >= MaxHistoryItems) {
history.removeFirst();
}
HistoryItem item;
item.c = c;
item.fromSearch = fromSearch;
item.searchString = searchString;
history.append(item);
inHistory = history.count() - 1;
updateBackForwardButtons();
}
void KCharSelect::KCharSelectPrivate::showFromHistory(int index)
{
Q_ASSERT(index >= 0 && index < history.count());
Q_ASSERT(index != inHistory);
inHistory = index;
updateBackForwardButtons();
const HistoryItem &item = history[index];
//kDebug() << "index" << index << "char" << item.c << "fromSearch" << item.fromSearch
// << "searchString" << item.searchString;
//avoid adding an item from history into history again
bool oldHistoryEnabled = historyEnabled;
historyEnabled = false;
if (item.fromSearch) {
if (searchLine->text() != item.searchString) {
searchLine->setText(item.searchString);
_k_search();
}
charTable->setChar(item.c);
} else {
searchLine->clear();
q->setCurrentChar(item.c);
}
historyEnabled = oldHistoryEnabled;
}
void KCharSelect::KCharSelectPrivate::updateBackForwardButtons()
{
backButton->setEnabled(inHistory > 0);
forwardButton->setEnabled(inHistory < history.count() - 1);
}
void KCharSelect::KCharSelectPrivate::_k_activateSearchLine()
{
searchLine->setFocus();
searchLine->selectAll();
}
void KCharSelect::KCharSelectPrivate::_k_back()
{
Q_ASSERT(inHistory > 0);
showFromHistory(inHistory - 1);
}
void KCharSelect::KCharSelectPrivate::_k_forward()
{
Q_ASSERT(inHistory + 1 < history.count());
showFromHistory(inHistory + 1);
}
void KCharSelect::KCharSelectPrivate::_k_fontSelected()
{
QFont font = fontCombo->currentFont();
font.setPointSize(fontSizeSpinBox->value());
charTable->setFont(font);
emit q->currentFontChanged(font);
}
void KCharSelect::KCharSelectPrivate::_k_updateCurrentChar(const QChar &c)
{
if (searchMode) {
//we are in search mode. make the two comboboxes show the section & block for this character.
//(when we are not in search mode the current character always belongs to the current section & block.)
int block = s_data->blockIndex(c);
int section = s_data->sectionIndex(block);
sectionCombo->setCurrentIndex(section);
int index = blockCombo->findData(block);
if (index != -1) {
blockCombo->setCurrentIndex(index);
}
}
if( searchLine)
historyAdd(c, searchMode, searchLine->text());
_k_slotUpdateUnicode(c);
}
void KCharSelect::KCharSelectPrivate::_k_slotUpdateUnicode(const QChar &c)
{
QString html = "<p>" + i18n("Character:") + ' ' + s_data->display(c, charTable->font()) + ' ' +
s_data->formatCode(c.unicode()) + "<br />";
QString name = s_data->name(c);
if (!name.isEmpty()) {
//is name ever empty? </p> should always be there...
html += i18n("Name: ") + Qt::escape(name) + "</p>";
}
QStringList aliases = s_data->aliases(c);
QStringList notes = s_data->notes(c);
QList<QChar> seeAlso = s_data->seeAlso(c);
QStringList equivalents = s_data->equivalents(c);
QStringList approxEquivalents = s_data->approximateEquivalents(c);
if (!(aliases.isEmpty() && notes.isEmpty() && seeAlso.isEmpty() && equivalents.isEmpty() && approxEquivalents.isEmpty())) {
html += "<p><b>" + i18n("Annotations and Cross References") + "</b></p>";
}
if (!aliases.isEmpty()) {
html += "<p style=\"margin-bottom: 0px;\">" + i18n("Alias names:") + "</p><ul style=\"margin-top: 0px;\">";
foreach(const QString &alias, aliases) {
html += "<li>" + Qt::escape(alias) + "</li>";
}
html += "</ul>";
}
if (!notes.isEmpty()) {
html += "<p style=\"margin-bottom: 0px;\">" + i18n("Notes:") + "</p><ul style=\"margin-top: 0px;\">";
foreach(const QString &note, notes) {
html += "<li>" + createLinks(Qt::escape(note)) + "</li>";
}
html += "</ul>";
}
if (!seeAlso.isEmpty()) {
html += "<p style=\"margin-bottom: 0px;\">" + i18n("See also:") + "</p><ul style=\"margin-top: 0px;\">";
foreach(const QChar &c2, seeAlso) {
html += "<li><a href=\"" + QString::number(c2.unicode(), 16) + "\">";
if (s_data->isPrint(c2)) {
html += "&#" + QString::number(c2.unicode()) + "; ";
}
html += s_data->formatCode(c2.unicode()) + ' ' + Qt::escape(s_data->name(c2)) + "</a></li>";
}
html += "</ul>";
}
if (!equivalents.isEmpty()) {
html += "<p style=\"margin-bottom: 0px;\">" + i18n("Equivalents:") + "</p><ul style=\"margin-top: 0px;\">";
foreach(const QString &equivalent, equivalents) {
html += "<li>" + createLinks(Qt::escape(equivalent)) + "</li>";
}
html += "</ul>";
}
if (!approxEquivalents.isEmpty()) {
html += "<p style=\"margin-bottom: 0px;\">" + i18n("Approximate equivalents:") + "</p><ul style=\"margin-top: 0px;\">";
foreach(const QString &approxEquivalent, approxEquivalents) {
html += "<li>" + createLinks(Qt::escape(approxEquivalent)) + "</li>";
}
html += "</ul>";
}
QStringList unihan = s_data->unihanInfo(c);
if (unihan.count() == 7) {
html += "<p><b>" + i18n("CJK Ideograph Information") + "</b></p><p>";
bool newline = true;
if (!unihan[0].isEmpty()) {
html += i18n("Definition in English: ") + unihan[0];
newline = false;
}
if (!unihan[2].isEmpty()) {
if (!newline) html += "<br>";
html += i18n("Mandarin Pronunciation: ") + unihan[2];
newline = false;
}
if (!unihan[1].isEmpty()) {
if (!newline) html += "<br>";
html += i18n("Cantonese Pronunciation: ") + unihan[1];
newline = false;
}
if (!unihan[6].isEmpty()) {
if (!newline) html += "<br>";
html += i18n("Japanese On Pronunciation: ") + unihan[6];
newline = false;
}
if (!unihan[5].isEmpty()) {
if (!newline) html += "<br>";
html += i18n("Japanese Kun Pronunciation: ") + unihan[5];
newline = false;
}
if (!unihan[3].isEmpty()) {
if (!newline) html += "<br>";
html += i18n("Tang Pronunciation: ") + unihan[3];
newline = false;
}
if (!unihan[4].isEmpty()) {
if (!newline) html += "<br>";
html += i18n("Korean Pronunciation: ") + unihan[4];
newline = false;
}
html += "</p>";
}
html += "<p><b>" + i18n("General Character Properties") + "</b><br>";
html += i18n("Block: ") + s_data->block(c) + "<br>";
html += i18n("Unicode category: ") + s_data->categoryText(s_data->category(c)) + "</p>";
QByteArray utf8 = QString(c).toUtf8();
html += "<p><b>" + i18n("Various Useful Representations") + "</b><br>";
html += i18n("UTF-8:");
foreach(unsigned char c, utf8)
html += ' ' + s_data->formatCode(c, 2, "0x");
html += "<br>" + i18n("UTF-16: ") + s_data->formatCode(c.unicode(), 4, "0x") + "<br>";
html += i18n("C octal escaped UTF-8: ");
foreach(unsigned char c, utf8)
html += s_data->formatCode(c, 3, "\\", 8);
html += "<br>" + i18n("XML decimal entity:") + " &amp;#" + QString::number(c.unicode()) + ";</p>";
detailBrowser->setHtml(html);
}
QString KCharSelect::KCharSelectPrivate::createLinks(QString s)
{
QRegExp rx("\\b([\\dABCDEF]{4})\\b");
QStringList chars;
int pos = 0;
while ((pos = rx.indexIn(s, pos)) != -1) {
chars << rx.cap(1);
pos += rx.matchedLength();
}
QSet<QString> chars2 = QSet<QString>::fromList(chars);
foreach(const QString &c, chars2) {
int unicode = c.toInt(0, 16);
QString link = "<a href=\"" + c + "\">";
if (s_data->isPrint(QChar(unicode))) {
link += "&#" + QString::number(unicode) + ";&nbsp;";
}
link += "U+" + c + ' ';
link += Qt::escape(s_data->name(QChar(unicode))) + "</a>";
s.replace(c, link);
}
return s;
}
void KCharSelect::KCharSelectPrivate::_k_sectionSelected(int index)
{
blockCombo->clear();
QList<int> blocks = s_data->sectionContents(index);
foreach(int block, blocks) {
blockCombo->addItem(s_data->blockName(block), QVariant(block));
}
blockCombo->setCurrentIndex(0);
}
void KCharSelect::KCharSelectPrivate::_k_blockSelected(int index)
{
if (index == -1) {
//the combo box has been cleared and is about to be filled again (because the section has changed)
return;
}
if (searchMode) {
//we are in search mode, so don't fill the table with this block.
return;
}
int block = blockCombo->itemData(index).toInt();
const QList<QChar> contents = s_data->blockContents(block);
if(contents.count() <= index) {
return;
}
charTable->setContents(contents);
emit q->displayedCharsChanged();
charTable->setChar(contents[0]);
}
void KCharSelect::KCharSelectPrivate::_k_searchEditChanged()
{
if (searchLine->text().isEmpty()) {
sectionCombo->setEnabled(true);
blockCombo->setEnabled(true);
//upon leaving search mode, keep the same character selected
searchMode = false;
QChar c = charTable->chr();
bool oldHistoryEnabled = historyEnabled;
historyEnabled = false;
_k_blockSelected(blockCombo->currentIndex());
historyEnabled = oldHistoryEnabled;
q->setCurrentChar(c);
} else {
sectionCombo->setEnabled(false);
blockCombo->setEnabled(false);
int length = searchLine->text().length();
if (length >= 3) {
_k_search();
}
}
}
void KCharSelect::KCharSelectPrivate::_k_search()
{
if (searchLine->text().isEmpty()) {
return;
}
searchMode = true;
const QList<QChar> contents = s_data->find(searchLine->text());
charTable->setContents(contents);
emit q->displayedCharsChanged();
if (!contents.isEmpty()) {
charTable->setChar(contents[0]);
}
}
void KCharSelect::KCharSelectPrivate::_k_linkClicked(QUrl url)
{
QString hex = url.toString();
if (hex.size() > 4) {
return;
}
int unicode = hex.toInt(0, 16);
searchLine->clear();
q->setCurrentChar(QChar(unicode));
}
////
QVariant KCharSelectItemModel::data(const QModelIndex &index, int role) const
{
int pos = m_columns * (index.row()) + index.column();
if (!index.isValid() || pos < 0 || pos >= m_chars.size()
|| index.row() < 0 || index.column() < 0) {
if (role == Qt::BackgroundColorRole) {
return QVariant(qApp->palette().color(QPalette::Button));
}
return QVariant();
}
QChar c = m_chars[pos];
if (role == Qt::ToolTipRole) {
QString result = s_data->display(c, m_font) + "<br />" + Qt::escape(s_data->name(c)) + "<br />" +
i18n("Unicode code point:") + ' ' + s_data->formatCode(c.unicode()) + "<br />" +
i18nc("Character", "In decimal:") + ' ' + QString::number(c.unicode());
return QVariant(result);
} else if (role == Qt::TextAlignmentRole)
return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
else if (role == Qt::DisplayRole) {
if (s_data->isPrint(c))
return QVariant(c);
return QVariant();
} else if (role == Qt::BackgroundColorRole) {
QFontMetrics fm = QFontMetrics(m_font);
if (fm.inFont(c) && s_data->isPrint(c))
return QVariant(qApp->palette().color(QPalette::Base));
else
return QVariant(qApp->palette().color(QPalette::Button));
} else if (role == Qt::FontRole)
return QVariant(m_font);
else if (role == CharacterRole) {
return QVariant(c);
}
return QVariant();
}
#include "kcharselect.moc"
#include "kcharselect_p.moc"