X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FTocModel.cpp;h=51365311aa9eba703bfeda79a7243a7e114f8db2;hb=b6eacd8d4f86734e8abef3335b190ce12a6a11b5;hp=adc580bc99f4785aa26fe71221ef8284b5663491;hpb=e1ce2f92db49d50c688414a32944be8e718faa2e;p=lyx.git diff --git a/src/frontends/qt4/TocModel.cpp b/src/frontends/qt4/TocModel.cpp index adc580bc99..51365311aa 100644 --- a/src/frontends/qt4/TocModel.cpp +++ b/src/frontends/qt4/TocModel.cpp @@ -13,154 +13,389 @@ #include "TocModel.h" -#include "debug.h" +#include "Buffer.h" +#include "BufferView.h" +#include "Cursor.h" +#include "DocIterator.h" +#include "FuncRequest.h" +#include "LyX.h" +#include "qt_helpers.h" +#include "TocBackend.h" -#include +#include "support/debug.h" +#include "support/lassert.h" -using std::endl; -using std::map; -using std::max; -using std::min; +#include +#include + + +#include + +using namespace std; namespace lyx { namespace frontend { +/// A QStandardItemModel that gives access to the reset methods. +/// This is needed in order to fix http://www.lyx.org/trac/ticket/3740 +// FIXME: Better appropriately subclass QStandardItemModel and implement +// the toc-specific reset methods there. +class TocTypeModel : public QStandardItemModel +{ +public: + /// + TocTypeModel(QObject * parent) : QStandardItemModel(parent) + {} + /// + void reset() + { + QStandardItemModel::beginResetModel(); + QStandardItemModel::endResetModel(); + } + /// + void beginResetModel() + { + QStandardItemModel::beginResetModel(); + } + /// + void endResetModel() + { + QStandardItemModel::endResetModel(); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// +// TocModel +// +/////////////////////////////////////////////////////////////////////////////// + +TocModel::TocModel(QObject * parent) + : model_(new TocTypeModel(parent)), + sorted_model_(new QSortFilterProxyModel(parent)), + is_sorted_(false), toc_(new Toc()), + maxdepth_(0), mindepth_(0) +{ + sorted_model_->setSortLocaleAware(true); + sorted_model_->setSourceModel(model_); +} + + +QAbstractItemModel * TocModel::model() +{ + if (is_sorted_) + return sorted_model_; + return model_; +} + -TocModel::TocModel(Toc const & toc) +QAbstractItemModel const * TocModel::model() const { - populate(toc); + if (is_sorted_) + return sorted_model_; + return model_; } -TocModel const & TocModel::operator=(Toc const & toc) +void TocModel::clear() { - populate(toc); - return *this; + model_->blockSignals(true); + model_->clear(); + toc_ = make_shared(); + model_->blockSignals(false); } -TocIterator const TocModel::tocIterator(QModelIndex const & index) const +void TocModel::sort(bool sort_it) { - TocMap::const_iterator map_it = toc_map_.find(index); - BOOST_ASSERT(map_it != toc_map_.end()); - return map_it->second; + is_sorted_ = sort_it; + if (is_sorted_) + sorted_model_->sort(0); } -QModelIndex const TocModel::modelIndex(TocIterator const & it) const +TocItem const & TocModel::tocItem(QModelIndex const & index) const { - ModelMap::const_iterator map_it = model_map_.find(it); - //BOOST_ASSERT(it != model_map_.end()); + return (*toc_)[model()->data(index, Qt::UserRole).toUInt()]; +} + - if (map_it == model_map_.end()) +QModelIndex TocModel::modelIndex(DocIterator const & dit) const +{ + if (toc_->empty()) return QModelIndex(); - return map_it->second; + unsigned int const toc_index = TocBackend::findItem(*toc_, dit) - + toc_->begin(); + + QModelIndexList list = model()->match(model()->index(0, 0), Qt::UserRole, + QVariant(toc_index), 1, + Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive)); + + LASSERT(!list.isEmpty(), return QModelIndex()); + return list[0]; } -void TocModel::clear() +void TocModel::reset() { - QStandardItemModel::clear(); - toc_map_.clear(); - model_map_.clear(); - removeRows(0, rowCount()); - removeColumns(0, columnCount()); + model_->reset(); } -void TocModel::populate(Toc const & toc) +void TocModel::setString(TocItem const & item, QModelIndex index) { - clear(); + // Use implicit sharing of QStrings + QString str = toqstr(item.asString()); + model_->setData(index, str, Qt::DisplayRole); + model_->setData(index, str, Qt::ToolTipRole); +} - if (toc.empty()) - return; - int current_row; - QModelIndex top_level_item; - TocIterator iter = toc.begin(); - TocIterator end = toc.end(); +void TocModel::updateItem(DocIterator const & dit) +{ + QModelIndex const index = modelIndex(dit); + setString(tocItem(index), index); +} + - insertColumns(0, 1); +void TocModel::reset(shared_ptr toc) +{ + toc_ = toc; + if (toc_->empty()) { + maxdepth_ = 0; + mindepth_ = 0; + reset(); + return; + } + + model_->blockSignals(true); + model_->beginResetModel(); + model_->insertColumns(0, 1); maxdepth_ = 0; mindepth_ = INT_MAX; - while (iter != end) { - maxdepth_ = max(maxdepth_, iter->depth()); - mindepth_ = min(mindepth_, iter->depth()); - current_row = rowCount(); - insertRows(current_row, 1); - top_level_item = QStandardItemModel::index(current_row, 0); - //setData(top_level_item, toqstr(iter->str())); - setData(top_level_item, toqstr(iter->str()), Qt::DisplayRole); + size_t end = toc_->size(); + for (unsigned int index = 0; index != end; ++index) { + TocItem const & item = (*toc_)[index]; + maxdepth_ = max(maxdepth_, item.depth()); + mindepth_ = min(mindepth_, item.depth()); + int current_row = model_->rowCount(); + model_->insertRows(current_row, 1); + QModelIndex top_level_item = model_->index(current_row, 0); + setString(item, top_level_item); + model_->setData(top_level_item, index, Qt::UserRole); + + LYXERR(Debug::GUI, "Toc: at depth " << item.depth() + << ", added item " << item.asString()); + + populate(index, top_level_item); + if (index >= end) + break; + } - // This looks like a gcc bug, in principle this should work: - //toc_map_[top_level_item] = iter; - // but it crashes with gcc-4.1 and 4.0.2 - toc_map_.insert( TocPair(top_level_item, iter) ); - model_map_[iter] = top_level_item; + model_->setHeaderData(0, Qt::Horizontal, QVariant("title"), Qt::DisplayRole); + sorted_model_->setSourceModel(model_); + if (is_sorted_) + sorted_model_->sort(0); + model_->blockSignals(false); + model_->endResetModel(); +} - LYXERR(Debug::GUI, "Toc: at depth " << iter->depth() - << ", added item " << to_utf8(iter->str())); - populate(iter, end, top_level_item); +void TocModel::populate(unsigned int & index, QModelIndex const & parent) +{ + int curdepth = (*toc_)[index].depth() + 1; - if (iter == end) + QModelIndex child_item; + model_->insertColumns(0, 1, parent); + + size_t end = toc_->size(); + ++index; + for (; index != end; ++index) { + TocItem const & item = (*toc_)[index]; + if (item.depth() < curdepth) { + --index; + return; + } + maxdepth_ = max(maxdepth_, item.depth()); + mindepth_ = min(mindepth_, item.depth()); + int current_row = model_->rowCount(parent); + model_->insertRows(current_row, 1, parent); + child_item = model_->index(current_row, 0, parent); + setString(item, child_item); + model_->setData(child_item, index, Qt::UserRole); + populate(index, child_item); + if (index >= end) break; - - ++iter; } +} + - setHeaderData(0, Qt::Horizontal, QVariant("title"), Qt::DisplayRole); -// emit headerDataChanged(); +int TocModel::modelDepth() const +{ + int const d = maxdepth_ - mindepth_; + LASSERT(d >= 0 && d <= 100, return 0); + return d; } -void TocModel::populate(TocIterator & iter, TocIterator const & end, - QModelIndex const & parent) +/////////////////////////////////////////////////////////////////////////////// +// +// TocModels +// +/////////////////////////////////////////////////////////////////////////////// + +TocModels::TocModels() { - int curdepth = iter->depth() + 1; + names_ = new TocTypeModel(this); + names_sorted_ = new TocModelSortProxyModel(this); + names_sorted_->setSourceModel(names_); + names_sorted_->setSortLocaleAware(true); + names_sorted_->sort(0); +} - int current_row; - QModelIndex child_item; - insertColumns(0, 1, parent); - while (iter != end) { +void TocModels::clear() +{ + names_->blockSignals(true); + names_->clear(); + names_->blockSignals(false); + iterator end = models_.end(); + for (iterator it = models_.begin(); it != end; ++it) + it.value()->clear(); +} - ++iter; - if (iter == end) - break; +int TocModels::depth(QString const & type) +{ + const_iterator it = models_.find(type); + if (it == models_.end()) + return 0; + return it.value()->modelDepth(); +} + + +QAbstractItemModel * TocModels::model(QString const & type) +{ + iterator it = models_.find(type); + if (it != models_.end()) + return it.value()->model(); + LYXERR0("type not found: " << type); + return 0; +} - if (iter->depth() < curdepth) { - --iter; - return; - } - maxdepth_ = max(maxdepth_, iter->depth()); - mindepth_ = min(mindepth_, iter->depth()); - current_row = rowCount(parent); - insertRows(current_row, 1, parent); - child_item = QStandardItemModel::index(current_row, 0, parent); - //setData(child_item, toqstr(iter->str())); - setData(child_item, toqstr(iter->str()), Qt::DisplayRole); - - // This looks like a gcc bug, in principle this should work: - //toc_map_[child_item] = iter; - // but it crashes with gcc-4.1 and 4.0.2 - toc_map_.insert( TocPair(child_item, iter) ); - model_map_[iter] = child_item; - populate(iter, end, child_item); +QAbstractItemModel * TocModels::nameModel() +{ + return names_sorted_; +} + + +QModelIndex TocModels::currentIndex(QString const & type, + DocIterator const & dit) const +{ + const_iterator it = models_.find(type); + if (it == models_.end()) + return QModelIndex(); + return it.value()->modelIndex(dit); +} + + +FuncRequest TocModels::goTo(QString const & type, QModelIndex const & index) const +{ + const_iterator it = models_.find(type); + if (it == models_.end() || !index.isValid()) { + LYXERR(Debug::GUI, "TocModels::goTo(): QModelIndex is invalid!"); + return FuncRequest(LFUN_NOACTION); } + LASSERT(index.model() == it.value()->model(), return FuncRequest(LFUN_NOACTION)); + TocItem const item = it.value()->tocItem(index); + LYXERR(Debug::GUI, "TocModels::goTo " << item.asString()); + return item.action(); } -int TocModel::modelDepth() const +TocItem const TocModels::currentItem(QString const & type, + QModelIndex const & index) const +{ + const_iterator it = models_.find(type); + if (it == models_.end() || !index.isValid()) { + LYXERR(Debug::GUI, "TocModels::currentItem(): QModelIndex is invalid!"); + return TocItem(); + } + LASSERT(index.model() == it.value()->model(), return TocItem()); + + return it.value()->tocItem(index); +} + + +void TocModels::updateItem(QString const & type, DocIterator const & dit) +{ + models_[type]->updateItem(dit); +} + + +void TocModels::reset(BufferView const * bv) +{ + clear(); + if (!bv) { + iterator end = models_.end(); + for (iterator it = models_.begin(); it != end; ++it) + it.value()->reset(); + names_->reset(); + return; + } + + names_->blockSignals(true); + names_->beginResetModel(); + names_->insertColumns(0, 1); + // In the outliner, add Tocs from the master document + TocBackend const & backend = bv->buffer().masterBuffer()->tocBackend(); + for (pair> const & toc : backend.tocs()) { + QString const type = toqstr(toc.first); + + // First, fill in the toc models. + iterator mod_it = models_.find(type); + if (mod_it == models_.end()) + mod_it = models_.insert(type, new TocModel(this)); + mod_it.value()->reset(toc.second); + + // Fill in the names_ model. + QString const gui_name = toqstr(backend.outlinerName(toc.first)); + int const current_row = names_->rowCount(); + names_->insertRows(current_row, 1); + QModelIndex const index = names_->index(current_row, 0); + names_->setData(index, gui_name, Qt::DisplayRole); + names_->setData(index, type, Qt::UserRole); + } + names_->blockSignals(false); + names_->endResetModel(); +} + + +bool TocModels::isSorted(QString const & type) const +{ + const_iterator it = models_.find(type); + if (it == models_.end()) { + LYXERR0("type not found: " << type); + return false; + } + return it.value()->isSorted(); +} + + +void TocModels::sort(QString const & type, bool sort_it) { - return maxdepth_ - mindepth_; + iterator it = models_.find(type); + if (it == models_.end()) + LYXERR0("type not found: " << type); + else + it.value()->sort(sort_it); } } // namespace frontend } // namespace lyx -#include "TocModel_moc.cpp" +#include "moc_TocModel.cpp"