]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiSymbols.cpp
* fix spelling in comments to please John.
[lyx.git] / src / frontends / qt4 / GuiSymbols.cpp
index 443a968629f78c424dea89c1108724a08ef01722..6bd5ba210a4bf1f9fcbed1c4751b482422dd8749 100644 (file)
@@ -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.
  */
 #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 <QChar>
 #include <QPixmap>
 #include <QListWidgetItem>
+#include <QString>
+
+#include <cstdio>
 
 using namespace std;
 
@@ -135,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<char_type> const & symbols)
+       {
+               symbols_ = symbols;
+               QAbstractItemModel::reset();
+       }
+
+private:
+       friend class GuiSymbols;
+       GuiSymbols * parent_;
+       
+       QList<char_type> 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);
 
@@ -158,6 +281,7 @@ GuiSymbols::GuiSymbols(GuiView & lv)
        int size = font.pointSize() + 3;
        font.setPointSize(size);
        symbolsLW->setFont(font);
+       symbolsLW->setModel(model_);
 }
 
 
@@ -165,12 +289,19 @@ void GuiSymbols::updateView()
 {
        chosenLE->clear();
 
-       string const & new_encoding = 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();
 }
 
@@ -202,7 +333,7 @@ void GuiSymbols::on_closePB_clicked()
 }
 
 
-void GuiSymbols::on_symbolsLW_itemActivated(QListWidgetItem *)
+void GuiSymbols::on_symbolsLW_activated(QModelIndex const &)
 {
        on_okPB_clicked();
 }
@@ -222,88 +353,107 @@ 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;
        if (chosenLE->isEnabled())
                chosenLE->insert(text);
-       QString const category = getBlock(text.data()->unicode());
-       categoryCO->setCurrentIndex(categoryCO->findText(category));
+       if (categoryFilterCB->isChecked()) {
+               QString const category = getBlock(text.data()->unicode());
+               categoryCO->setCurrentIndex(categoryCO->findText(category));
+       }
 }
 
 
 void GuiSymbols::on_categoryCO_activated(QString const & text)
 {
        if (!categoryFilterCB->isChecked())
-               updateSymbolList();
-       if (used_blocks.find(text) != used_blocks.end())
-               symbolsLW->scrollToItem(used_blocks[text],
-                       QAbstractItemView::PositionAtTop);
+               updateSymbolList(false);
+       else
+               scrollToItem(text);
 }
 
 
 void GuiSymbols::on_categoryFilterCB_toggled(bool on)
 {
-       updateSymbolList();
-       if (on) {
-               QString const category = categoryCO->currentText();
-               if (used_blocks.find(category) != used_blocks.end())
-                       symbolsLW->scrollToItem(used_blocks[category],
-                               QAbstractItemView::PositionAtTop);
-       }
+       updateSymbolList(on);
+       if (on)
+               scrollToItem(categoryCO->currentText());        
 }
 
 
-void GuiSymbols::updateSymbolList()
+void GuiSymbols::scrollToItem(QString const & category)
+{
+       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);
+}
+
+
+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();
-       used_blocks.clear();
-       categoryCO->clear();
+       QList<char_type> s;
+       if (update_combo) {
+               used_blocks.clear();
+               categoryCO->clear();
+       }
        bool const show_all = categoryFilterCB->isChecked();
 
-       typedef set<char_type> SymbolsList;
-       Encoding enc = *(encodings.getFromLyXName(encoding_));
-       SymbolsList symbols = enc.getSymbolsList();
+       if (symbols_.empty() || update_combo)
+               symbols_ = encodings.fromLyXName(encoding_)->symbolsList();
 
        if (!show_all) {
                for (int i = 0 ; i < no_blocks; ++i)
-                       if (unicode_blocks[i].name == fromqstr(category)) {
+                       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();
-       for (SymbolsList::const_iterator it = symbols.begin(); it != end; ++it) {
+       SymbolsList::const_iterator const end = symbols_.end();
+       int numItem = 0;
+       for (SymbolsList::const_iterator it = symbols_.begin(); it != end; ++it) {
                char_type c = *it;
-               QChar::Category cat = QChar::category((uint) c);
+               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;
-               QListWidgetItem * lwi = new QListWidgetItem(
-                       QString::fromUcs4((uint const *) &c, 1));
-               if (show_all || c >= range_start && c <= range_end) {
-                       lwi->setTextAlignment(Qt::AlignCenter);
-                       symbolsLW->addItem(lwi);
+               ++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;
                }
-               QString block = getBlock(c);
-               if (category.isEmpty())
-                       category = block;
-               if (used_blocks.find(block) == used_blocks.end())
-                       used_blocks[block] = lwi;
        }
+       model_->setSymbols(s);
 
-       // update category combo
-       for (UsedBlocks::iterator it = used_blocks.begin(); it != used_blocks.end(); ++it) {
-               categoryCO->addItem(it->first);
+       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);
@@ -314,17 +464,6 @@ void GuiSymbols::updateSymbolList()
 }
 
 
-QString const GuiSymbols::getBlock(char_type c) const
-{
-       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();
-}
-
-
 void GuiSymbols::dispatchParams()
 {
        dispatch(FuncRequest(getLfun(), fromqstr(chosenLE->text())));
@@ -340,4 +479,4 @@ Dialog * createGuiSymbols(GuiView & lv)
 } // namespace frontend
 } // namespace lyx
 
-#include "GuiSymbols_moc.cpp"
+#include "moc_GuiSymbols.cpp"