On Wed, Mar 19, 2008 at 07:54:35PM +0100, Pavel Sanda wrote: > > > > some 30s here. btw Display all is disabled on utf-8. thats bug or > > > > intention? > > > > > > Intention (because it's currently unusably slow). > > > > What do I have to do to reproduce this "unusably slow" behaviour? > > set utf-8 document encoding and try insert some symbol.
With the attached patch it should be quite a bit faster. I am sure I broke the logic somewhere, so feel free to fix & apply or leave it ;-) Juergen, maybe you want to have a look, too? Andre'
Index: GuiSymbols.h =================================================================== --- GuiSymbols.h (revision 23858) +++ GuiSymbols.h (working copy) @@ -15,11 +15,7 @@ #include "DialogView.h" #include "ui_SymbolsUi.h" -#include <map> -#include <set> -class QListWidgetItem; - namespace lyx { namespace frontend { @@ -43,31 +39,20 @@ void on_applyPB_clicked(); void on_okPB_clicked(); void on_closePB_clicked(); - void on_symbolsLW_itemActivated(QListWidgetItem *); - void on_symbolsLW_itemClicked(QListWidgetItem * item); + void on_symbolsLW_activated(QModelIndex const & index); + void on_symbolsLW_clicked(QModelIndex const & index); void on_categoryCO_activated(QString const & text); - void on_categoryFilterCB_toggled(bool); void on_chosenLE_returnPressed(); void on_chosenLE_textChanged(QString const &); private: - /** update the widgets (symbol browser, category combo) - * \p combo indicates if the combo box has to be refreshed - * as well (which is rather expensive) - **/ - void updateSymbolList(bool update_combo = true); - /// get the unicode block associated with \p c - QString getBlock(char_type c) const; - /// the encoding at cursor position - std::string encoding_; - /// which blocks do we actually include? - typedef std::map<QString, QListWidgetItem *> UsedBlocks; - /// - UsedBlocks used_blocks; - /// list of all symbols - typedef std::set<char_type> SymbolsList; - /// - SymbolsList symbols_; + // update the symbol list + void updateSymbolList(); + // update the category combo + void updateComboBox(); + // the model used in the symbol list view + class Model; + Model * model_; }; } // namespace frontend Index: ui/SymbolsUi.ui =================================================================== --- ui/SymbolsUi.ui (revision 23858) +++ ui/SymbolsUi.ui (working copy) @@ -71,18 +71,8 @@ </property> </spacer> </item> - <item row="0" column="2" > - <widget class="QCheckBox" name="categoryFilterCB" > - <property name="toolTip" > - <string>Select this to display all available characters at once</string> - </property> - <property name="text" > - <string>&Display all</string> - </property> - </widget> - </item> <item row="1" column="0" colspan="3" > - <widget class="QListWidget" name="symbolsLW" > + <widget class="QListView" name="symbolsLW" > <property name="sizePolicy" > <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > <horstretch>0</horstretch> @@ -116,9 +106,6 @@ <property name="spacing" > <number>0</number> </property> - <property name="currentRow" > - <number>-1</number> - </property> </widget> </item> <item row="2" column="0" colspan="3" > Index: GuiSymbols.cpp =================================================================== --- GuiSymbols.cpp (revision 23858) +++ GuiSymbols.cpp (working copy) @@ -22,13 +22,17 @@ #include "Encoding.h" #include "FuncRequest.h" +#include "support/debug.h" #include "support/gettext.h" +#include <QAbstractItemModel> +#include <QModelIndex> #include <QChar> #include <QPixmap> -#include <QListWidgetItem> #include <QString> +#include <set> + using namespace std; namespace lyx { @@ -146,11 +150,117 @@ const int no_blocks = sizeof(unicode_blocks) / sizeof(UnicodeBlocks); +bool isIgnored(char_type c) +{ +#if QT_VERSION >= 0x040300 + QChar::Category const cat = QChar::category(uint(c)); +#else + QChar const qc = uint(c); + QChar::Category const cat = qc.category(); +#endif + // we do not want control or space characters + return cat == QChar::Other_Control || cat == QChar::Separator_Space; +} + +/// get the unicode block associated with \p c +QString getBlock(char_type c) +{ + int i = 1; // Skip "All Symbols" + while (c > unicode_blocks[i].end && i < no_blocks) + ++i; + if (!unicode_blocks[i].name.isEmpty()) + return unicode_blocks[i].name; + return QString(); +} + + } // namespace anon +///////////////////////////////////////////////////////////////////// +// +// GuiSymbols::Model +// +/////////////////////////////////////////////////////////////////////// + +class GuiSymbols::Model : public QAbstractItemModel +{ +public: + Model(GuiSymbols * parent) + : QAbstractItemModel(parent), parent_(parent), + range_start_(0), range_end_(0x7f) + {} + + 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 range_end_ - range_start_; + } + + 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 = range_start_ + index.row(); + + if (role == Qt::TextAlignmentRole) + return QVariant(Qt::AlignCenter); + + if (role == Qt::DisplayRole) + return isIgnored(c) ? QString::number(c) : toqstr(c); + + if (role == Qt::ToolTipRole) { + if (isIgnored(c)) + return QString(); + sprintf(codeName, "0x%04x", c); + return strCharacter + toqstr(c) + '\n' + + strCodePoint + QLatin1String(codeName); + } + + //LYXERR0("role: " << role << " row: " << index.row()); + return QVariant(); + } + + void reset(char_type start, char_type end) + { + range_start_ = start; + range_end_ = end; + QAbstractItemModel::reset(); + } + +private: + GuiSymbols * parent_; + char_type range_start_; + char_type range_end_; +}; + + + +///////////////////////////////////////////////////////////////////// +// +// GuiSymbols +// +/////////////////////////////////////////////////////////////////////// + GuiSymbols::GuiSymbols(GuiView & lv) - : DialogView(lv, "symbols", qt_("Symbols")), encoding_("ascii") + : DialogView(lv, "symbols", qt_("Symbols")), model_(new Model(this)) { setupUi(this); @@ -159,30 +269,20 @@ symbolsLW->setViewMode(QListView::IconMode); symbolsLW->setUniformItemSizes(true); // increase the display size of the symbols a bit - QFont font= symbolsLW->font(); - int size = font.pointSize() + 3; - font.setPointSize(size); + QFont font = symbolsLW->font(); + font.setPointSize(font.pointSize() + 3); symbolsLW->setFont(font); + symbolsLW->setModel(model_); + + updateComboBox(); + updateSymbolList(); } void GuiSymbols::updateView() { chosenLE->clear(); - - 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); + updateComboBox(); updateSymbolList(); } @@ -214,7 +314,7 @@ } -void GuiSymbols::on_symbolsLW_itemActivated(QListWidgetItem *) +void GuiSymbols::on_symbolsLW_activated(QModelIndex const &) { on_okPB_clicked(); } @@ -234,128 +334,84 @@ } -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; 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) +void GuiSymbols::on_categoryCO_activated(QString const &) { - if (!categoryFilterCB->isChecked()) - updateSymbolList(false); - else if (used_blocks.find(text) != used_blocks.end()) - symbolsLW->scrollToItem(used_blocks[text], - QAbstractItemView::PositionAtTop); + updateSymbolList(); } -void GuiSymbols::on_categoryFilterCB_toggled(bool on) +void GuiSymbols::updateComboBox() { - updateSymbolList(on); - if (on) { - QString const category = categoryCO->currentText(); - if (used_blocks.find(category) != used_blocks.end()) - symbolsLW->scrollToItem(used_blocks[category], - QAbstractItemView::PositionAtTop); - } -} + // get encoding at cursor position + std::string encoding = bufferview()->cursor().getEncoding()->name(); + if (buffer().params().inputenc != "auto" && + buffer().params().inputenc != "default") + encoding = buffer().params().encoding().name(); + LYXERR0("ENCODING: " << encoding); + typedef std::set<char_type> SymbolsList; + SymbolsList symbols_ = encodings.getFromLyXName(encoding)->getSymbolsList(); + LYXERR0("SYMBOLS size: " << symbols_.size()); -void GuiSymbols::updateSymbolList(bool update_combo) -{ - QString category = categoryCO->currentText(); - bool const nocategory = category.isEmpty(); - char_type range_start = 0x0000; - char_type range_end = 0x110000; - symbolsLW->clear(); - if (update_combo) { - used_blocks.clear(); - categoryCO->clear(); - } - bool const show_all = categoryFilterCB->isChecked(); + typedef std::set<QString> UsedBlocks; + UsedBlocks used_blocks; + used_blocks.insert(unicode_blocks[0].name); // ASCII - if (symbols_.empty() || update_combo) - symbols_ = encodings.getFromLyXName(encoding_)->getSymbolsList(); - - if (!show_all) { - for (int i = 0 ; i < no_blocks; ++i) - if (unicode_blocks[i].name == category) { - range_start = unicode_blocks[i].start; - range_end = unicode_blocks[i].end; - break; - } - } - - static char codeName[10]; - static QString const strCharacter = qt_("Character: "); - static QString const strCodePoint = qt_("Code Point: "); - SymbolsList::const_iterator const end = symbols_.end(); 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)) + if (isIgnored(c)) continue; -#if QT_VERSION >= 0x040300 - QChar::Category const cat = QChar::category(uint(c)); -#else - QChar const qc = uint(c); - QChar::Category const cat = qc.category(); -#endif - // we do not want control or space characters - if (cat == QChar::Other_Control || cat == QChar::Separator_Space) - continue; - QListWidgetItem * lwi = new QListWidgetItem(toqstr(c)); - if (show_all || c >= range_start && c <= range_end) { - sprintf(codeName, "0x%04x", c); - lwi->setTextAlignment(Qt::AlignCenter); - lwi->setToolTip(strCharacter + toqstr(c) + '\n' - + strCodePoint + QLatin1String(codeName)); - symbolsLW->addItem(lwi); - } - if (update_combo) { - QString block = getBlock(c); - if (category.isEmpty()) - category = block; - if (used_blocks.find(block) == used_blocks.end()) - used_blocks[block] = lwi; - } + QString block = getBlock(c); + used_blocks.insert(block); } - if (update_combo) { - // update category combo - for (UsedBlocks::iterator it = used_blocks.begin(); - it != used_blocks.end(); ++it) { - categoryCO->addItem(it->first); - } + // update category combo box + categoryCO->clear(); + categoryCO->addItem(qt_("All Symbols")); + int startIndex = 1; + int i = 0; + for (UsedBlocks::iterator it = used_blocks.begin(); + it != used_blocks.end(); ++it, ++i) { + categoryCO->addItem(*it); + if (*it == unicode_blocks[0].name) + startIndex = i; } - 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(); + categoryCO->setCurrentIndex(startIndex); } -QString GuiSymbols::getBlock(char_type c) const +void GuiSymbols::updateSymbolList() { - int i = 0; - while (c > unicode_blocks[i].end && i < no_blocks) - ++i; - if (!unicode_blocks[i].name.isEmpty()) - return unicode_blocks[i].name; - return QString(); + QString category = categoryCO->currentText(); + int start = 0x0000; + int end = 0x110000; + + for (int i = 0; i < no_blocks; ++i) { + if (unicode_blocks[i].name == category) { + start = unicode_blocks[i].start; + end = unicode_blocks[i].end; + break; + } + } + model_->reset(start, end); }