X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiSymbols.cpp;h=6bd5ba210a4bf1f9fcbed1c4751b482422dd8749;hb=425d092204118ea6c24c28e85fdf03fcf2bb51a4;hp=98229454ffc961e85e1efcc4c87701ea0e2b15d6;hpb=9bdca85f2602576d669bbf2b2e63a45e38292e30;p=lyx.git diff --git a/src/frontends/qt4/GuiSymbols.cpp b/src/frontends/qt4/GuiSymbols.cpp index 98229454ff..6bd5ba210a 100644 --- a/src/frontends/qt4/GuiSymbols.cpp +++ b/src/frontends/qt4/GuiSymbols.cpp @@ -3,7 +3,7 @@ * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * - * \author Jürgen Spitzmüller + * \author Jürgen Spitzmüller * * Full author contact details are available in file CREDITS. */ @@ -12,22 +12,26 @@ #include "GuiSymbols.h" -#include "Buffer.h" -#include "BufferView.h" - #include "GuiApplication.h" #include "GuiView.h" - #include "qt_helpers.h" +#include "Buffer.h" +#include "BufferParams.h" +#include "BufferView.h" +#include "Cursor.h" #include "Encoding.h" +#include "FuncRequest.h" + +#include "support/debug.h" #include "support/gettext.h" +#include #include #include +#include -// Set to zero if unicode symbols are preferred. -#define USE_PIXMAP 1 +#include using namespace std; @@ -73,6 +77,7 @@ UnicodeBlocks unicode_blocks[] = { { N_("Tibetan"), 0x0f00, 0x0fbf }, { N_("Georgian"), 0x10a0, 0x10ff }, { N_("Hangul Jamo"), 0x1100, 0x11ff }, + { N_("Phonetic Extensions"), 0x1d00, 0x1d7f }, { N_("Latin Extended Additional"), 0x1e00, 0x1eff }, { N_("Greek Extended"), 0x1f00, 0x1fff }, { N_("General Punctuation"), 0x2000, 0x206f }, @@ -92,6 +97,7 @@ UnicodeBlocks unicode_blocks[] = { { N_("Geometric Shapes"), 0x25a0, 0x25ff }, { N_("Miscellaneous Symbols"), 0x2600, 0x26ff }, { N_("Dingbats"), 0x2700, 0x27bf }, + { N_("Miscellaneous Mathematical Symbols-A"), 0x27c0, 0x27ef }, { N_("CJK Symbols and Punctuation"), 0x3000, 0x303f }, { N_("Hiragana"), 0x3040, 0x309f }, { N_("Katakana"), 0x30a0, 0x30ff }, @@ -137,17 +143,132 @@ UnicodeBlocks unicode_blocks[] = { { N_("CJK Compatibility Ideographs Supplement"), 0x2f800, 0x2fa1f }, { N_("Tags"), 0xe0000, 0xe007f }, { N_("Variation Selectors Supplement"), 0xe0100, 0xe01ef }, - { N_("Supplementary Private Use Area-A"), 0xf0000, 0xe01ef }, - { N_("Supplementary Private Use Area-B"), 0x100000, 0x10ffff } + { N_("Supplementary Private Use Area-A"), 0xf0000, 0xffffd }, + { N_("Supplementary Private Use Area-B"), 0x100000, 0x10fffd } }; const int no_blocks = sizeof(unicode_blocks) / sizeof(UnicodeBlocks); + +QString getBlock(char_type c) +{ + // store an educated guess for the next search + static int lastBlock = 0; + + // "clever reset" + if (c < 0x7f) + lastBlock = 0; + + // off the end already + if (lastBlock == no_blocks) + return QString(); + + // c falls into a covered area, and we can guess which + if (c >= unicode_blocks[lastBlock].start + && c <= unicode_blocks[lastBlock].end) + return qt_(unicode_blocks[lastBlock].name); + + // c falls into an uncovered area, but we can guess which + if (c > unicode_blocks[lastBlock].end + && c < unicode_blocks[lastBlock + 1].start) + return QString(); + + // guessing was wrong so far. do a real search. + int i = 0; + while (c > unicode_blocks[i].end && i < no_blocks) + ++i; + if (i == no_blocks) + return QString(); + lastBlock = i; + //LYXERR0("fail: " << int(c) << ' ' << lastBlock); + return qt_(unicode_blocks[lastBlock].name); +} + + } // namespace anon +///////////////////////////////////////////////////////////////////// +// +// GuiSymbols::Model +// +///////////////////////////////////////////////////////////////////// + +class GuiSymbols::Model : public QAbstractItemModel +{ +public: + Model(GuiSymbols * parent) + : QAbstractItemModel(parent), parent_(parent) + {} + + QModelIndex index(int row, int column, QModelIndex const &) const + { + return createIndex(row, column); + } + + QModelIndex parent(QModelIndex const &) const + { + return QModelIndex(); + } + + int rowCount(QModelIndex const &) const + { + return symbols_.count(); + } + + int columnCount(QModelIndex const &) const + { + return 1; + } + + QVariant data(QModelIndex const & index, int role) const + { + static QString const strCharacter = qt_("Character: "); + static QString const strCodePoint = qt_("Code Point: "); + + static char codeName[10]; + + char_type c = symbols_.at(index.row()); + + if (role == Qt::TextAlignmentRole) + return QVariant(Qt::AlignCenter); + + if (role == Qt::DisplayRole) + return toqstr(c); + + if (role == Qt::ToolTipRole) { + sprintf(codeName, "0x%04x", c); + return strCharacter + toqstr(c) + '\n' + + strCodePoint + QLatin1String(codeName); + } + + //LYXERR0("role: " << role << " row: " << index.row()); + return QVariant(); + } + + void setSymbols(QList const & symbols) + { + symbols_ = symbols; + QAbstractItemModel::reset(); + } + +private: + friend class GuiSymbols; + GuiSymbols * parent_; + + QList symbols_; +}; + + +///////////////////////////////////////////////////////////////////// +// +// GuiSymbols +// +///////////////////////////////////////////////////////////////////// + GuiSymbols::GuiSymbols(GuiView & lv) - : DialogView(lv, "symbols", qt_("Symbols")), encoding_("ascii") + : DialogView(lv, "symbols", qt_("Symbols")), encoding_("ascii"), + model_(new Model(this)) { setupUi(this); @@ -160,18 +281,36 @@ GuiSymbols::GuiSymbols(GuiView & lv) int size = font.pointSize() + 3; font.setPointSize(size); symbolsLW->setFont(font); - - okPB->setEnabled(!chosenLE->text().isEmpty() && - !bufferview()->buffer().isReadonly()); - applyPB->setEnabled(!chosenLE->text().isEmpty() && - !bufferview()->buffer().isReadonly()); + symbolsLW->setModel(model_); } void GuiSymbols::updateView() { chosenLE->clear(); - initialiseParams(bufferview()->cursor().getEncoding()->name()); + + string new_encoding = bufferview()->cursor().getEncoding()->name(); + if (buffer().params().inputenc != "auto" && + buffer().params().inputenc != "default") + new_encoding = buffer().params().encoding().name(); + if (new_encoding == encoding_) + // everything up to date + return; + if (!new_encoding.empty()) + encoding_ = new_encoding; + bool const utf8 = toqstr(encoding_).startsWith("utf8"); + if (utf8) + categoryFilterCB->setChecked(false); + //categoryFilterCB->setEnabled(!utf8); + updateSymbolList(); +} + + +void GuiSymbols::enableView(bool enable) +{ + chosenLE->setEnabled(enable); + okPB->setEnabled(enable); + applyPB->setEnabled(enable); } @@ -194,7 +333,7 @@ void GuiSymbols::on_closePB_clicked() } -void GuiSymbols::on_symbolsLW_itemActivated(QListWidgetItem *) +void GuiSymbols::on_symbolsLW_activated(QModelIndex const &) { on_okPB_clicked(); } @@ -202,8 +341,9 @@ void GuiSymbols::on_symbolsLW_itemActivated(QListWidgetItem *) void GuiSymbols::on_chosenLE_textChanged(QString const & text) { - okPB->setEnabled(!text.isEmpty() && !bufferview()->buffer().isReadonly()); - applyPB->setEnabled(!text.isEmpty() && !bufferview()->buffer().isReadonly()); + bool const empty_sel = text.isEmpty(); + okPB->setEnabled(!empty_sel); + applyPB->setEnabled(!empty_sel); } @@ -213,83 +353,120 @@ void GuiSymbols::on_chosenLE_returnPressed() } -void GuiSymbols::on_symbolsLW_itemClicked(QListWidgetItem * item) +void GuiSymbols::on_symbolsLW_clicked(QModelIndex const & index) { - QString const text = item->text(); + QString const text = model_->data(index, Qt::DisplayRole).toString(); if (text.isEmpty()) return; - chosenLE->insert(text); - QString const category = getBlock(text.data()->unicode()); - categoryCO->setCurrentIndex(categoryCO->findText(category)); + if (chosenLE->isEnabled()) + chosenLE->insert(text); + if (categoryFilterCB->isChecked()) { + QString const category = getBlock(text.data()->unicode()); + categoryCO->setCurrentIndex(categoryCO->findText(category)); + } } void GuiSymbols::on_categoryCO_activated(QString const & text) { - if (used_blocks.find(text) != used_blocks.end()) - symbolsLW->scrollToItem(used_blocks[text]); + if (!categoryFilterCB->isChecked()) + updateSymbolList(false); + else + scrollToItem(text); } -void GuiSymbols::updateSymbolList() +void GuiSymbols::on_categoryFilterCB_toggled(bool on) { - symbolsLW->clear(); - used_blocks.clear(); - categoryCO->clear(); - - typedef set SymbolsList; - Encoding enc = *(encodings.getFromLyXName(encoding_)); - SymbolsList symbols = enc.getSymbolsList(); - - SymbolsList::const_iterator const end = symbols.end(); - for (SymbolsList::const_iterator it = symbols.begin(); it != end; ++it) { - char_type c = *it; - // we do not want control or space characters - if (QChar(c).category() == QChar::Other_Control || - QChar(c).category() == QChar::Separator_Space) - continue; - QListWidgetItem * lwi = new QListWidgetItem(QChar(c)); - lwi->setTextAlignment(Qt::AlignCenter); - symbolsLW->addItem(lwi); - QString block = getBlock(c); - if (used_blocks.find(block) == used_blocks.end()) - used_blocks[block] = lwi; - } - - // update category combo - for (UsedBlocks::iterator it = used_blocks.begin(); it != used_blocks.end(); ++it) { - categoryCO->addItem(it->first); - } + updateSymbolList(on); + if (on) + scrollToItem(categoryCO->currentText()); } -QString const GuiSymbols::getBlock(char_type c) const +void GuiSymbols::scrollToItem(QString const & category) { - int i = 0; - while (c > unicode_blocks[i].end && i < no_blocks) - ++i; - if (unicode_blocks[i].name) - return toqstr(unicode_blocks[i].name); - return QString(); + if (used_blocks.find(category) == used_blocks.end()) + return; + int row = used_blocks[category]; + QModelIndex index = symbolsLW->model()->index(row, 0, QModelIndex()); + symbolsLW->scrollTo(index, QAbstractItemView::PositionAtTop); } - -bool GuiSymbols::initialiseParams(string const & data) +void GuiSymbols::updateSymbolList(bool update_combo) { - if (data == encoding_) - // everything up to date - return true; - if (!data.empty()) - encoding_ = data; - updateSymbolList(); - return true; + QString category = categoryCO->currentText(); + bool const nocategory = category.isEmpty(); + char_type range_start = 0x0000; + char_type range_end = 0x110000; + QList s; + if (update_combo) { + used_blocks.clear(); + categoryCO->clear(); + } + bool const show_all = categoryFilterCB->isChecked(); + + if (symbols_.empty() || update_combo) + symbols_ = encodings.fromLyXName(encoding_)->symbolsList(); + + if (!show_all) { + for (int i = 0 ; i < no_blocks; ++i) + if (qt_(unicode_blocks[i].name) == category) { + range_start = unicode_blocks[i].start; + range_end = unicode_blocks[i].end; + break; + } + } + + SymbolsList::const_iterator const end = symbols_.end(); + int numItem = 0; + for (SymbolsList::const_iterator it = symbols_.begin(); it != end; ++it) { + char_type c = *it; + if (!update_combo && !show_all && (c <= range_start || c >= range_end)) + continue; +#if QT_VERSION >= 0x040300 + QChar::Category const cat = QChar::category(uint(c)); +#else + QChar::Category const cat = QChar(uint(c)).category(); +#endif + // we do not want control or space characters + if (cat == QChar::Other_Control || cat == QChar::Separator_Space) + continue; + ++numItem; + if (show_all || (c >= range_start && c <= range_end)) + s.append(c); + if (update_combo) { + QString block = getBlock(c); + if (category.isEmpty()) + category = block; + if (used_blocks.find(block) == used_blocks.end()) + used_blocks[block] = numItem; + } + } + model_->setSymbols(s); + + if (update_combo) { + // update category combo + for (UsedBlocks::iterator it = used_blocks.begin(); + it != used_blocks.end(); ++it) { + categoryCO->addItem(it->first); + } + } + + int old = categoryCO->findText(category); + if (old != -1) + categoryCO->setCurrentIndex(old); + // update again in case the combo has not yet been filled + // on first cycle (at dialog initialization) + if (nocategory && !category.isEmpty()) + updateSymbolList(); } void GuiSymbols::dispatchParams() { - dispatch(FuncRequest(LFUN_SELF_INSERT, fromqstr(chosenLE->text()))); + dispatch(FuncRequest(getLfun(), fromqstr(chosenLE->text()))); } @@ -302,4 +479,4 @@ Dialog * createGuiSymbols(GuiView & lv) } // namespace frontend } // namespace lyx -#include "GuiSymbols_moc.cpp" +#include "moc_GuiSymbols.cpp"