23 #include "kcharselect_p.h"
25 #include <QtGui/QActionEvent>
26 #include <QtGui/QDoubleSpinBox>
27 #include <QtGui/QHeaderView>
28 #include <QtGui/QBoxLayout>
29 #include <QtGui/QShortcut>
30 #include <QtGui/QSplitter>
31 #include <QtGui/QPushButton>
32 #include <QtGui/QToolButton>
46 class KCharSelectTablePrivate
49 KCharSelectTablePrivate(KCharSelectTable *q): q(q), model(0)
55 KCharSelectItemModel *model;
59 void _k_resizeCells();
64 class KCharSelect::KCharSelectPrivate
74 enum { MaxHistoryItems = 100 };
80 ,historyEnabled(false)
95 KCharSelectTable *charTable;
105 void historyAdd(
const QChar &c,
bool fromSearch,
const QString &searchString);
106 void showFromHistory(
int index);
107 void updateBackForwardButtons();
108 void _k_activateSearchLine();
111 void _k_fontSelected();
112 void _k_updateCurrentChar(
const QChar &c);
113 void _k_slotUpdateUnicode(
const QChar &c);
114 void _k_sectionSelected(
int index);
115 void _k_blockSelected(
int index);
116 void _k_searchEditChanged();
118 void _k_linkClicked(
QUrl url);
125 KCharSelectTable::KCharSelectTable(
QWidget *parent,
const QFont &_font)
126 :
QTableView(parent), d(new KCharSelectTablePrivate(this))
130 setTabKeyNavigation(
false);
131 setSelectionMode(QAbstractItemView::SingleSelection);
133 _palette.
setColor(backgroundRole(), palette().color(QPalette::Base));
134 setPalette(_palette);
135 verticalHeader()->setVisible(
false);
136 verticalHeader()->setResizeMode(QHeaderView::Custom);
137 horizontalHeader()->setVisible(
false);
138 horizontalHeader()->setResizeMode(QHeaderView::Custom);
140 setFocusPolicy(Qt::StrongFocus);
141 setDragEnabled(
true);
142 setAcceptDrops(
true);
143 setDropIndicatorShown(
false);
144 setDragDropMode(QAbstractItemView::DragDrop);
151 KCharSelectTable::~KCharSelectTable()
156 void KCharSelectTable::setFont(
const QFont &_font)
160 if (d->model) d->model->setFont(_font);
164 QChar KCharSelectTable::chr()
169 QFont KCharSelectTable::font()
const
179 void KCharSelectTable::setChar(
const QChar &c)
183 const int columnCount = model()->columnCount();
184 setCurrentIndex(model()->index(pos / columnCount, pos % columnCount));
192 KCharSelectItemModel *m = d->model;
193 d->model =
new KCharSelectItemModel(chars, d->font,
this);
197 setSelectionModel(selectionModel);
198 setSelectionBehavior(QAbstractItemView::SelectItems);
199 setSelectionMode(QAbstractItemView::SingleSelection);
201 connect(d->model, SIGNAL(showCharRequested(
QChar)),
this, SIGNAL(showCharRequested(
QChar)));
205 void KCharSelectTable::scrollTo(
const QModelIndex & index, ScrollHint hint)
217 Q_UNUSED(deselected);
218 if (!model || selected.
indexes().isEmpty())
220 QVariant temp = model->data(selected.
indexes().at(0), KCharSelectItemModel::CharacterRole);
221 if (temp.
type() != QVariant::Char)
225 emit q->focusItemChanged(c);
236 void KCharSelectTablePrivate::_k_resizeCells()
238 KCharSelectItemModel *model =
static_cast<KCharSelectItemModel*
>(q->model());
241 const int viewportWidth = q->viewport()->size().width();
248 int maxCharWidth = 0;
250 for (
int i = 0 ; i < chars.
size(); ++i) {
251 maxCharWidth = qMax(maxCharWidth, fontMetrics.width(chars.
at(i)));
254 maxCharWidth = qMax(maxCharWidth, 2 * fontMetrics.xHeight());
255 maxCharWidth = qMax(maxCharWidth, fontMetrics.height());
257 const int textMargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, q) + 1;
258 maxCharWidth += 2 * textMargin;
260 const int columns = qMax(1, viewportWidth / maxCharWidth);
261 model->setColumnCount(columns);
263 const QChar oldChar = q->chr();
265 const int new_w = viewportWidth / columns;
266 const int rows = model->rowCount();
267 q->setUpdatesEnabled(
false);
269 const int spaceLeft = viewportWidth - new_w * columns;
270 for (
int i = 0 ; i <= columns; i++ ) {
280 int new_h = fontMetrics.lineSpacing() + 1;
282 int new_h = fontMetrics.xHeight() * 3;
284 const int fontHeight = fontMetrics.
height();
285 if (new_h < 5 || new_h < 4 + fontHeight) {
286 new_h = qMax(5, 4 + fontHeight);
288 for (
int i = 0;i < rows;i++) {
292 q->setUpdatesEnabled(
true);
296 void KCharSelectTablePrivate::_k_doubleClicked(
const QModelIndex & index)
298 QChar c = model->data(index, KCharSelectItemModel::CharacterRole).toChar();
299 if (s_data->isPrint(c)) {
300 emit q->activated(c);
304 void KCharSelectTable::keyPressEvent(
QKeyEvent *e)
312 case Qt::Key_Enter:
case Qt::Key_Return: {
313 if (!currentIndex().isValid())
return;
314 QChar c = d->model->data(currentIndex(), KCharSelectItemModel::CharacterRole).toChar();
315 if (s_data->isPrint(c)) {
330 #ifndef KDE_NO_DEPRECATED
332 :
QWidget(parent), d(new KCharSelectPrivate(this))
334 init(controls, NULL);
341 ,
const Controls controls)
342 :
QWidget(parent), d(new KCharSelectPrivate(this))
344 init(controls, collection);
349 if (collection==NULL) {
351 d->actions->addAssociatedWidget(
this);
353 d->actions = collection;
363 d->searchLine->setClickMessage(
i18n(
"Enter a search term or character here"));
364 d->searchLine->setClearButtonShown(
true);
365 d->searchLine->setToolTip(
i18n(
"Enter a search term or character here"));
367 connect(d->searchLine, SIGNAL(textChanged(
QString)),
this, SLOT(_k_searchEditChanged()));
368 connect(d->searchLine, SIGNAL(returnPressed()),
this, SLOT(_k_search()));
382 d->backButton->setEnabled(
false);
383 d->backButton->setText(
i18nc(
"Goes to previous character",
"Previous in History"));
384 d->backButton->setIcon(
KIcon(
"go-previous"));
385 d->backButton->setToolTip(
i18n(
"Previous Character in History"));
388 comboLayout->
addWidget(d->forwardButton);
389 d->forwardButton->setEnabled(
false);
390 d->forwardButton->setText(
i18nc(
"Goes to next character",
"Next in History"));
391 d->forwardButton->setIcon(
KIcon(
"go-next"));
392 d->forwardButton->setToolTip(
i18n(
"Next Character in History"));
396 connect(d->backButton, SIGNAL(clicked()),
this, SLOT(_k_back()));
397 connect(d->forwardButton, SIGNAL(clicked()),
this, SLOT(_k_forward()));
400 d->sectionCombo->setToolTip(
i18n(
"Select a category"));
403 d->blockCombo->setToolTip(
i18n(
"Select a block to be displayed"));
404 d->blockCombo->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
405 comboLayout->
addWidget(d->blockCombo, 1);
406 d->sectionCombo->addItems(s_data->sectionList());
409 connect(d->sectionCombo, SIGNAL(currentIndexChanged(
int)),
this, SLOT(_k_sectionSelected(
int)));
410 connect(d->blockCombo, SIGNAL(currentIndexChanged(
int)),
this, SLOT(_k_blockSelected(
int)));
414 d->fontCombo->setEditable(
true);
415 d->fontCombo->resize(d->fontCombo->sizeHint());
416 d->fontCombo->setToolTip(
i18n(
"Set font"));
418 d->fontSizeSpinBox =
new QSpinBox(
this);
419 comboLayout->
addWidget(d->fontSizeSpinBox);
421 d->fontSizeSpinBox->setRange(1, 400);
422 d->fontSizeSpinBox->setSingleStep(1);
423 d->fontSizeSpinBox->setToolTip(
i18n(
"Set font size"));
425 connect(d->fontCombo, SIGNAL(currentIndexChanged(
QString)),
this, SLOT(_k_fontSelected()));
426 connect(d->fontSizeSpinBox, SIGNAL(valueChanged(
int)),
this, SLOT(_k_fontSelected()));
432 d->backButton->hide();
433 d->forwardButton->hide();
436 d->fontCombo->hide();
439 d->fontSizeSpinBox->hide();
442 d->sectionCombo->hide();
443 d->blockCombo->hide();
452 d->charTable =
new KCharSelectTable(
this,
QFont());
455 d->charTable->setFocus(Qt::OtherFocusReason);
457 d->charTable->hide();
460 const QSize sz(200, 200);
461 d->charTable->resize(sz);
462 d->charTable->setMinimumSize(sz);
464 d->charTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
468 connect(d->charTable, SIGNAL(focusItemChanged(
QChar)),
this, SLOT(_k_updateCurrentChar(
QChar)));
479 d->detailBrowser->hide();
481 d->detailBrowser->setOpenLinks(
false);
482 connect(d->detailBrowser, SIGNAL(anchorClicked(
QUrl)),
this, SLOT(_k_linkClicked(
QUrl)));
486 d->_k_sectionSelected(0);
487 d->_k_blockSelected(0);
490 d->historyEnabled =
true;
505 d->fontCombo->setCurrentFont(_font);
506 d->fontSizeSpinBox->setValue(_font.
pointSize());
507 d->_k_fontSelected();
512 return d->charTable->chr();
517 return d->charTable->font();
522 return d->charTable->displayedChars();
527 bool oldHistoryEnabled = d->historyEnabled;
528 d->historyEnabled =
false;
529 int block = s_data->blockIndex(c);
530 int section = s_data->sectionIndex(block);
531 d->sectionCombo->setCurrentIndex(section);
532 int index = d->blockCombo->findData(block);
534 d->blockCombo->setCurrentIndex(index);
536 d->historyEnabled = oldHistoryEnabled;
537 d->charTable->setChar(c);
540 void KCharSelect::KCharSelectPrivate::historyAdd(
const QChar &c,
bool fromSearch,
const QString &searchString)
544 if (!historyEnabled) {
548 if (!history.isEmpty() && c == history.last().c) {
554 while (!history.isEmpty() && inHistory != history.count() - 1) {
555 history.removeLast();
558 while (history.size() >= MaxHistoryItems) {
559 history.removeFirst();
564 item.fromSearch = fromSearch;
565 item.searchString = searchString;
568 inHistory = history.
count() - 1;
569 updateBackForwardButtons();
572 void KCharSelect::KCharSelectPrivate::showFromHistory(
int index)
574 Q_ASSERT(index >= 0 && index < history.count());
575 Q_ASSERT(index != inHistory);
578 updateBackForwardButtons();
580 const HistoryItem &item = history[index];
585 bool oldHistoryEnabled = historyEnabled;
586 historyEnabled =
false;
587 if (item.fromSearch) {
588 if (searchLine->text() != item.searchString) {
589 searchLine->setText(item.searchString);
592 charTable->setChar(item.c);
595 q->setCurrentChar(item.c);
597 historyEnabled = oldHistoryEnabled;
600 void KCharSelect::KCharSelectPrivate::updateBackForwardButtons()
602 backButton->setEnabled(inHistory > 0);
603 forwardButton->setEnabled(inHistory < history.count() - 1);
606 void KCharSelect::KCharSelectPrivate::_k_activateSearchLine()
608 searchLine->setFocus();
609 searchLine->selectAll();
612 void KCharSelect::KCharSelectPrivate::_k_back()
614 Q_ASSERT(inHistory > 0);
615 showFromHistory(inHistory - 1);
618 void KCharSelect::KCharSelectPrivate::_k_forward()
620 Q_ASSERT(inHistory + 1 < history.count());
621 showFromHistory(inHistory + 1);
624 void KCharSelect::KCharSelectPrivate::_k_fontSelected()
626 QFont font = fontCombo->currentFont();
628 charTable->setFont(font);
629 emit q->currentFontChanged(font);
632 void KCharSelect::KCharSelectPrivate::_k_updateCurrentChar(
const QChar &c)
637 int block = s_data->blockIndex(c);
638 int section = s_data->sectionIndex(block);
639 sectionCombo->setCurrentIndex(section);
640 int index = blockCombo->findData(block);
642 blockCombo->setCurrentIndex(index);
647 historyAdd(c, searchMode, searchLine->text());
649 _k_slotUpdateUnicode(c);
652 void KCharSelect::KCharSelectPrivate::_k_slotUpdateUnicode(
const QChar &c)
654 QString html =
"<p>" +
i18n(
"Character:") +
' ' + s_data->display(c, charTable->font()) +
' ' +
655 s_data->formatCode(c.
unicode()) +
"<br />";
666 QStringList approxEquivalents = s_data->approximateEquivalents(c);
668 html +=
"<p><b>" +
i18n(
"Annotations and Cross References") +
"</b></p>";
672 html +=
"<p style=\"margin-bottom: 0px;\">" +
i18n(
"Alias names:") +
"</p><ul style=\"margin-top: 0px;\">";
673 foreach(
const QString &alias, aliases) {
680 html +=
"<p style=\"margin-bottom: 0px;\">" +
i18n(
"Notes:") +
"</p><ul style=\"margin-top: 0px;\">";
681 foreach(
const QString ¬e, notes) {
682 html +=
"<li>" + createLinks(
Qt::escape(note)) +
"</li>";
688 html +=
"<p style=\"margin-bottom: 0px;\">" +
i18n(
"See also:") +
"</p><ul style=\"margin-top: 0px;\">";
689 foreach(
const QChar &c2, seeAlso) {
691 if (s_data->isPrint(c2)) {
694 html += s_data->formatCode(c2.
unicode()) +
' ' +
Qt::escape(s_data->name(c2)) +
"</a></li>";
700 html +=
"<p style=\"margin-bottom: 0px;\">" +
i18n(
"Equivalents:") +
"</p><ul style=\"margin-top: 0px;\">";
701 foreach(
const QString &equivalent, equivalents) {
702 html +=
"<li>" + createLinks(
Qt::escape(equivalent)) +
"</li>";
707 if (!approxEquivalents.
isEmpty()) {
708 html +=
"<p style=\"margin-bottom: 0px;\">" +
i18n(
"Approximate equivalents:") +
"</p><ul style=\"margin-top: 0px;\">";
709 foreach(
const QString &approxEquivalent, approxEquivalents) {
710 html +=
"<li>" + createLinks(
Qt::escape(approxEquivalent)) +
"</li>";
716 if (unihan.
count() == 7) {
717 html +=
"<p><b>" +
i18n(
"CJK Ideograph Information") +
"</b></p><p>";
719 if (!unihan[0].isEmpty()) {
720 html +=
i18n(
"Definition in English: ") + unihan[0];
723 if (!unihan[2].isEmpty()) {
724 if (!newline) html +=
"<br>";
725 html +=
i18n(
"Mandarin Pronunciation: ") + unihan[2];
728 if (!unihan[1].isEmpty()) {
729 if (!newline) html +=
"<br>";
730 html +=
i18n(
"Cantonese Pronunciation: ") + unihan[1];
733 if (!unihan[6].isEmpty()) {
734 if (!newline) html +=
"<br>";
735 html +=
i18n(
"Japanese On Pronunciation: ") + unihan[6];
738 if (!unihan[5].isEmpty()) {
739 if (!newline) html +=
"<br>";
740 html +=
i18n(
"Japanese Kun Pronunciation: ") + unihan[5];
743 if (!unihan[3].isEmpty()) {
744 if (!newline) html +=
"<br>";
745 html +=
i18n(
"Tang Pronunciation: ") + unihan[3];
748 if (!unihan[4].isEmpty()) {
749 if (!newline) html +=
"<br>";
750 html +=
i18n(
"Korean Pronunciation: ") + unihan[4];
756 html +=
"<p><b>" +
i18n(
"General Character Properties") +
"</b><br>";
757 html +=
i18n(
"Block: ") + s_data->block(c) +
"<br>";
758 html +=
i18n(
"Unicode category: ") + s_data->categoryText(s_data->category(c)) +
"</p>";
762 html +=
"<p><b>" +
i18n(
"Various Useful Representations") +
"</b><br>";
763 html +=
i18n(
"UTF-8:");
764 foreach(
unsigned char c, utf8)
765 html +=
' ' + s_data->formatCode(c, 2,
"0x");
766 html +=
"<br>" +
i18n(
"UTF-16: ") + s_data->formatCode(c.unicode(), 4,
"0x") +
"<br>";
767 html +=
i18n(
"C octal escaped UTF-8: ");
768 foreach(
unsigned char c, utf8)
769 html += s_data->formatCode(c, 3,
"\\", 8);
770 html +=
"<br>" +
i18n(
"XML decimal entity:") +
" &#" +
QString::number(c.unicode()) +
";</p>";
772 detailBrowser->setHtml(html);
777 QRegExp rx(
"\\b([\\dABCDEF]{4})\\b");
782 while ((pos = rx.indexIn(s, pos)) != -1) {
784 pos += rx.matchedLength();
788 foreach(
const QString &c, chars2) {
789 int unicode = c.
toInt(0, 16);
790 QString link =
"<a href=\"" + c +
"\">";
791 if (s_data->isPrint(
QChar(unicode))) {
794 link +=
"U+" + c +
' ';
801 void KCharSelect::KCharSelectPrivate::_k_sectionSelected(
int index)
804 QList<int> blocks = s_data->sectionContents(index);
805 foreach(
int block, blocks) {
806 blockCombo->addItem(s_data->blockName(block),
QVariant(block));
808 blockCombo->setCurrentIndex(0);
811 void KCharSelect::KCharSelectPrivate::_k_blockSelected(
int index)
822 int block = blockCombo->itemData(index).toInt();
823 const QList<QChar> contents = s_data->blockContents(block);
824 if(contents.
count() <= index) {
827 charTable->setContents(contents);
828 emit q->displayedCharsChanged();
829 charTable->setChar(contents[0]);
832 void KCharSelect::KCharSelectPrivate::_k_searchEditChanged()
834 if (searchLine->text().isEmpty()) {
835 sectionCombo->setEnabled(
true);
836 blockCombo->setEnabled(
true);
840 QChar c = charTable->chr();
841 bool oldHistoryEnabled = historyEnabled;
842 historyEnabled =
false;
843 _k_blockSelected(blockCombo->currentIndex());
844 historyEnabled = oldHistoryEnabled;
845 q->setCurrentChar(c);
847 sectionCombo->setEnabled(
false);
848 blockCombo->setEnabled(
false);
850 int length = searchLine->text().length();
857 void KCharSelect::KCharSelectPrivate::_k_search()
859 if (searchLine->text().isEmpty()) {
864 charTable->setContents(contents);
865 emit q->displayedCharsChanged();
867 charTable->setChar(contents[0]);
871 void KCharSelect::KCharSelectPrivate::_k_linkClicked(
QUrl url)
874 if (hex.
size() > 4) {
877 int unicode = hex.
toInt(0, 16);
879 q->setCurrentChar(
QChar(unicode));
886 int pos = m_columns * (index.
row()) + index.
column();
887 if (!index.
isValid() || pos < 0 || pos >= m_chars.size()
888 || index.
row() < 0 || index.
column() < 0) {
889 if (role == Qt::BackgroundColorRole) {
890 return QVariant(qApp->palette().color(QPalette::Button));
895 QChar c = m_chars[pos];
896 if (role == Qt::ToolTipRole) {
897 QString result = s_data->display(c, m_font) +
"<br />" +
Qt::escape(s_data->name(c)) +
"<br />" +
898 i18n(
"Unicode code point:") +
' ' + s_data->formatCode(c.
unicode()) +
"<br />" +
901 }
else if (role == Qt::TextAlignmentRole)
902 return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
903 else if (role == Qt::DisplayRole) {
904 if (s_data->isPrint(c))
907 }
else if (role == Qt::BackgroundColorRole) {
909 if (fm.
inFont(c) && s_data->isPrint(c))
910 return QVariant(qApp->palette().color(QPalette::Base));
912 return QVariant(qApp->palette().color(QPalette::Button));
913 }
else if (role == Qt::FontRole)
915 else if (role == CharacterRole) {
921 bool KCharSelectItemModel::dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
const QModelIndex &parent)
925 if (action == Qt::IgnoreAction) {
940 emit showCharRequested(text[0]);
944 void KCharSelectItemModel::setColumnCount(
int columns)
946 emit layoutAboutToBeChanged();
948 emit layoutChanged();
957 #include "kcharselect.moc"
958 #include "kcharselect_p.moc"
QModelIndexList indexes() const
QString i18n(const char *text)
A container for a set of QAction objects.
void setPointSize(int pointSize)
QString & append(QChar ch)
KAction * back(const QObject *recvr, const char *slot, QObject *parent)
Move back (web style menu).
void setColor(ColorGroup group, ColorRole role, const QColor &color)
A lightweight font selection widget.
void setFrameShape(Shape)
#define K_GLOBAL_STATIC(TYPE, NAME)
Shows the font size spin box.
const T & at(int i) const
const char * name(StandardAction id)
This will return the internal name of a given standard action.
virtual void resizeEvent(QResizeEvent *event)
Shows the search widgets.
KAction * find(const QObject *recvr, const char *slot, QObject *parent)
Initiate a 'find' request in the current document.
Shows the detail browser.
QString toString(QFlags< QUrl::FormattingOption > options) const
QString i18nc(const char *ctxt, const char *text)
int indexOf(const T &value, int from) const
Shows the category/block selection combo boxes.
QString number(int n, int base)
int count(const T &value) const
QChar currentChar() const
Returns the currently selected character.
void charSelected(const QChar &c)
A character is selected to be inserted somewhere.
Shows the Back/Forward buttons.
const QSize & oldSize() const
int toInt(bool *ok, int base) const
QList< QChar > displayedChars() const
Returns a list of currently displayed characters.
bool inFont(QChar ch) const
A wrapper around QIcon that provides KDE icon features.
void setCurrentChar(const QChar &c)
Highlights the character c.
void setMargin(int margin)
Shows the font combo box.
void currentCharChanged(const QChar &c)
The current character is changed.
void setCurrentFont(const QFont &font)
Sets the font which is displayed to font.
const QSize & size() const
KAction * forward(const QObject *recvr, const char *slot, QObject *parent)
Move forward (web style menu).
void setFrameShadow(Shadow)
Character selection widget.
QString & replace(int position, int n, QChar after)
An enhanced QLineEdit widget for inputting text.
QString escape(const QString &plain)
KCharSelect(QWidget *parent, KActionCollection *collection, const Controls controls=AllGuiElements)
Constructor.
QSet< T > fromList(const QList< T > &list)
virtual void keyPressEvent(QKeyEvent *event)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
iterator find(const T &t)
QFont currentFont() const
Returns the currently displayed font.
void addLayout(QLayout *layout, int stretch)
virtual QSize sizeHint() const
Reimplemented.
QByteArray toUtf8() const