Abdelrazak Younes a écrit :
Abdelrazak Younes a écrit :
I found myself using more and more the two ways toc navigation but,
eventually I got annoyed by the slowness of it. So I fixed it :-)
This patch implements a Toc backend (TocBackend.[Ch]) that is used in
toc.h. The speed improvement is _very_ very nice on windows.
I guess it should be sensible under mac and linux also. Try to open the
navigate menu on a user guide or any big highly hierarchical
document). Maybe this was the cause of the slowness on Mac because of
the special menu handling.
This patch impact minimally current code (except for toc.[Ch] and
ControlToc.[Ch] of course). The toc cache is implemented as a static
variable (static map<Buffer const *, lyx::TocBackend> toc_backend_; in
toc.C), this is not very nice but this seems to be the
only way with current code structure. Eventually, this toc_backend_
should become a member of the kernel.
I use the paragraph text as an universal ID for the Toc item. This
could/should eventually change once we have something stable.
Please test and comment. Test especially on other frontends to see if it
doesn't break anything. Tested only with qt4.
Just finished compiling with qt3 (always a penitence :-( ); I am happy
to report that the navigate menu and the Toc Dialog work as expected.
There is no reason why it should not be the same for xform and gtk so my
plan is to:
1) replace item::uid() with item::id() that contains the paragraph id.
It turned out that I didn't need this id. This new version use
Toc::const_iterator as a unique identifier. Also, I have simplified
TocItem construction and cleaned up its interface.
2) send the updated patch
Attached. This new version has been tested for qt2 and qt4 frontends and
I've checked that my changes doesn't impact the other frontend (xforms
and gtk).
3) commit :-)
Objections?
In the mean time any testing would be welcome.
Still...
Abdel.
Log:
* TocBackend.[Ch]: new files defining class TocBackend. This class
contains adapted code from former toc.C
* toc.[Ch]:
- rewritten to take advantage of new TocBackend class. The toc
cache is implemented as a static variable:
static map<Buffer const *, lyx::TocBackend> toc_backend_;
* buffer_funcs.C:
updateLabels(Buffer const & buf) now calls
"lyx::toc::updateToc(buf);"
* pariterator.h: added default constructor
ParConstIterator(): DocIterator() {}
* insetfloat.C: added pit parameter to TocItem construction
* insetwrap.C: added pit parameter to TocItem construction
* MenuBackend.C: use a const ref instead of a copy of TocList
* ControlToc.[Ch]: optimisation of the API by using const reference
instead of copy.
* qt4/TocPanel.[Ch]:
- optimisation of the API by using const reference instead of
copy
- directly use of TocBackend::TocIterator instead of identification
by paragraph contents.
* qt4/QToc.C:
- optimisation of the API by using const reference instead of
copy
- makes use of TocBackend::Item::uid()
* qt2/QToc.C:
- use TocItem::depth() and TocItem::str() instead of public member
access.
Index: src/buffer_funcs.C
===================================================================
--- src/buffer_funcs.C (revision 13695)
+++ src/buffer_funcs.C (working copy)
@@ -33,6 +33,7 @@
#include "lyxvc.h"
#include "texrow.h"
#include "vc-backend.h"
+#include "toc.h"
#include "frontends/Alert.h"
@@ -513,8 +514,11 @@
ParIterator & it)
{
if (it == par_iterator_end(buf.inset()))
- return true;
-
+ return false;
+
+// if (it.lastpit == 0 && LyXText::isMainText())
+// return false;
+
switch (it->layout()->labeltype) {
case LABEL_NO_LABEL:
@@ -582,6 +586,8 @@
// set the counter for this paragraph
setLabel(buf, it);
}
+
+ lyx::toc::updateToc(buf);
}
Index: src/frontends/controllers/ControlToc.C
===================================================================
--- src/frontends/controllers/ControlToc.C (revision 13695)
+++ src/frontends/controllers/ControlToc.C (working copy)
@@ -16,6 +16,7 @@
#include "funcrequest.h"
#include "gettext.h"
#include "BufferView.h"
+#include "debug.h"
using std::vector;
using std::string;
@@ -52,20 +53,19 @@
}
-vector<string> const ControlToc::getTypes() const
+vector<string> const & ControlToc::getTypes() const
{
return toc::getTypes(kernel().buffer());
}
-toc::TocItem const ControlToc::getCurrentTocItem(
+toc::TocIterator const ControlToc::getCurrentTocItem(
string const & type) const
{
- BufferView const * const bv = kernel().bufferview();
- if (!bv)
- return toc::TocItem(-1, -1, "");
+ BOOST_ASSERT(kernel().bufferview());
- return toc::getCurrentTocItem(kernel().buffer(), bv->cursor(), type);
+ return toc::getCurrentTocItem(kernel().buffer(),
+ kernel().bufferview()->cursor(), type);
}
@@ -78,22 +78,16 @@
}
-toc::Toc const ControlToc::getContents(string const & type) const
-{
- toc::Toc empty_list;
+toc::Toc const empty_list;
+toc::Toc const & ControlToc::getContents(string const & type) const
+{
// This shouldn't be possible...
if (!kernel().isBufferAvailable()) {
return empty_list;
}
- toc::TocList tmp = toc::getTocList(kernel().buffer());
- toc::TocList::iterator it = tmp.find(type);
- if (it == tmp.end()) {
- return empty_list;
- }
-
- return it->second;
+ return toc::getToc(kernel().buffer(), type);
}
} // namespace frontend
Index: src/frontends/controllers/ControlToc.h
===================================================================
--- src/frontends/controllers/ControlToc.h (revision 13695)
+++ src/frontends/controllers/ControlToc.h (working copy)
@@ -31,17 +31,17 @@
void goTo(toc::TocItem const &);
/// Return the list of types available
- std::vector<std::string> const getTypes() const;
+ std::vector<std::string> const & getTypes() const;
/// Return the guiname from a given cmdName of the TOC param
std::string const getGuiName(std::string const & type) const;
/// Return the first TocItem before the cursor
- toc::TocItem const getCurrentTocItem(
+ toc::TocIterator const getCurrentTocItem(
std::string const & type) const;
/// Given a type, returns the contents
- toc::Toc const getContents(std::string const & type) const;
+ toc::Toc const & getContents(std::string const & type) const;
/// Apply the selected outlining operation
void outline(toc::OutlineOp op);
Index: src/frontends/qt2/QToc.C
===================================================================
--- src/frontends/qt2/QToc.C (revision 13707)
+++ src/frontends/qt2/QToc.C (working copy)
@@ -116,21 +116,21 @@
for (toc::Toc::const_iterator iter = toclist.begin();
iter != toclist.end(); ++iter) {
- if (iter->depth == curdepth) {
+ if (iter->depth() == curdepth) {
// insert it after the last one we processed
if (!parent)
item = (last ? new
QListViewItem(dialog_->tocLV,last) : new QListViewItem(dialog_->tocLV));
else
item = (last ? new QListViewItem(parent,last) :
new QListViewItem(parent));
- } else if (iter->depth > curdepth) {
- int diff = iter->depth - curdepth;
+ } else if (iter->depth() > curdepth) {
+ int diff = iter->depth() - curdepth;
// first save old parent and last
while (diff--)
istack.push(pair< QListViewItem *,
QListViewItem * >(parent,last));
item = (last ? new QListViewItem(last) : new
QListViewItem(dialog_->tocLV));
parent = last;
} else {
- int diff = curdepth - iter->depth;
+ int diff = curdepth - iter->depth();
pair<QListViewItem *, QListViewItem * > top;
// restore context
while (diff--) {
@@ -148,20 +148,20 @@
lyxerr[Debug::GUI]
<< "Table of contents\n"
- << "Added item " << iter->str
- << " at depth " << iter->depth
+ << "Added item " << iter->str()
+ << " at depth " << iter->depth()
<< ", previous sibling \""
<< (last ? fromqstr(last->text(0)) : "0")
<< "\", parent \""
<< (parent ? fromqstr(parent->text(0)) : "0") << '"'
<< endl;
- item->setText(0, toqstr(iter->str));
- item->setOpen(iter->depth < depth_);
- curdepth = iter->depth;
+ item->setText(0, toqstr(iter->str()));
+ item->setOpen(iter->depth() < depth_);
+ curdepth = iter->depth();
last = item;
// Recognise part past the counter
- if (iter->str.substr(iter->str.find(' ') + 1) == text_) {
+ if (iter->str().substr(iter->str().find(' ') + 1) == text_) {
if (selected_item == 0)
selected_item = item;
else
@@ -186,7 +186,7 @@
toc::Toc::const_iterator iter = toclist.begin();
for (; iter != toclist.end(); ++iter) {
- if (iter->str == text)
+ if (iter->str() == text)
break;
}
Index: src/frontends/qt4/QToc.C
===================================================================
--- src/frontends/qt4/QToc.C (revision 13695)
+++ src/frontends/qt4/QToc.C (working copy)
@@ -31,6 +31,7 @@
namespace lyx {
namespace frontend {
+
QToc::QToc(Dialog & parent)
: ControlToc(parent)
{
@@ -76,17 +77,13 @@
QModelIndex const QToc::getCurrentIndex()
{
vector<string> const & types = getTypes();
- toc::TocItem const item = getCurrentTocItem(types[type_]);
- if (item.id_ == -1) {
- lyxerr[Debug::GUI]
- << "QToc::getCurrentIndex(): TocItem is invalid!" <<
endl;
+ TocIterator const it = getCurrentTocItem(types[type_]);
+ if (!it->isValid()) {
+ lyxerr[Debug::GUI] << "QToc::getCurrentIndex(): TocItem is
invalid!" << endl;
return QModelIndex();
}
- string toc_str = item.str;
- toc_str.erase(0, toc_str.find(' ') + 1);
-
- return toc_models_[type_]->index(toc_str);
+ return toc_models_[type_]->modelIndex(it);
}
@@ -98,12 +95,14 @@
<< endl;
return;
}
+
+ TocIterator const it = toc_models_[type_]->tocIterator(index);
lyxerr[Debug::GUI]
- << "QToc::goTo " << toc_models_[type_]->item(index).str
+ << "QToc::goTo " << it->str()
<< endl;
- ControlToc::goTo(toc_models_[type_]->item(index));
+ it->goTo(kernel().lyxview());
}
@@ -139,27 +138,15 @@
void QToc::updateToc(int type)
{
- vector<string> const & choice = getTypes();
-
- toc_models_[type] = new TocModel(getContents(choice[type]));
+ toc_models_[type] = new TocModel(getContents(getTypes()[type]));
}
-void QToc::move(toc::OutlineOp const operation, QModelIndex & index)
+void QToc::move(toc::OutlineOp const operation)
{
- int toc_id = toc_models_[type_]->item(index).id_;
- string toc_str = toc_models_[type_]->item(index).str;
- toc_str.erase(0, toc_str.find(' ') + 1);
-
outline(operation);
- updateToc(type_);
-
- lyxerr[Debug::GUI]
- << "Toc id " << toc_id
- << " Toc str " << toc_str
- << endl;
-
- index = toc_models_[type_]->index(toc_str);
+// updateToc(type_);
+ update();
}
} // namespace frontend
Index: src/frontends/qt4/QToc.h
===================================================================
--- src/frontends/qt4/QToc.h (revision 13695)
+++ src/frontends/qt4/QToc.h (working copy)
@@ -48,7 +48,7 @@
///
void goTo(QModelIndex const & index);
- void move(toc::OutlineOp const operation, QModelIndex & index);
+ void move(toc::OutlineOp const operation);
private:
Index: src/frontends/qt4/QTocDialog.C
===================================================================
--- src/frontends/qt4/QTocDialog.C (revision 13695)
+++ src/frontends/qt4/QTocDialog.C (working copy)
@@ -103,9 +103,9 @@
/*
while (
tocTv->setExpanded();
- if (iter->depth > depth_)
+ if (iter->depth() > depth_)
tocTV->collapseItem(topLevelItem);
- else if (iter->depth <= depth_)
+ else if (iter->depth() <= depth_)
tocTV->expandItem(topLevelItem);
*/
}
@@ -147,9 +147,10 @@
enableButtons(false);
QModelIndex index = tocTV->selectionModel()->selectedIndexes()[0];
form_->goTo(index);
- form_->move(operation, index);
- select(index);
- enableButtons();
+ form_->move(operation);
+ update();
+// select(index);
+// enableButtons();
}
void QTocDialog::select(QModelIndex const & index)
Index: src/frontends/qt4/TocModel.C
===================================================================
--- src/frontends/qt4/TocModel.C (revision 13695)
+++ src/frontends/qt4/TocModel.C (working copy)
@@ -25,80 +25,81 @@
namespace lyx {
namespace frontend {
+
-
-TocModel::TocModel(toc::Toc const & toc_list)
+TocModel::TocModel(TocBackend::Toc const & toc)
{
- populate(toc_list);
+ populate(toc);
}
-TocModel const & TocModel::operator=(toc::Toc const & toc_list)
+TocModel const & TocModel::operator=(TocBackend::Toc const & toc)
{
- populate(toc_list);
+ populate(toc);
return *this;
}
+
-toc::TocItem const TocModel::item(QModelIndex const & index) const
+TocIterator const TocModel::tocIterator(QModelIndex const & index) const
{
- ItemMap::const_iterator it = item_map_.find(index);
- BOOST_ASSERT(it != item_map_.end());
-
- return it->second;
+ TocMap::const_iterator map_it = toc_map_.find(index);
+ BOOST_ASSERT(map_it != toc_map_.end());
+ return map_it->second;
}
+
-QModelIndex const TocModel::index(string const & toc_str) const
+QModelIndex const TocModel::modelIndex(TocIterator const & it) const
{
- IndexMap::const_iterator it = index_map_.find(toc_str);
- //BOOST_ASSERT(it != index_map_.end());
+ ModelMap::const_iterator map_it = model_map_.find(it);
+ //BOOST_ASSERT(it != model_map_.end());
- if (it == index_map_.end())
+ if (map_it == model_map_.end())
return QModelIndex();
- return it->second;
+ return map_it->second;
}
+
void TocModel::clear()
{
QStandardItemModel::clear();
- item_map_.clear();
- index_map_.clear();
+ toc_map_.clear();
+ model_map_.clear();
removeRows(0, rowCount());
removeColumns(0, columnCount());
}
-void TocModel::populate(toc::Toc const & toc_list)
+void TocModel::populate(TocBackend::Toc const & toc)
{
clear();
- if (toc_list.empty())
+ if (toc.empty())
return;
int current_row;
QModelIndex top_level_item;
- toc::Toc::const_iterator iter = toc_list.begin();
- toc::Toc::const_iterator end = toc_list.end();
+ TocIterator iter = toc.begin();
+ TocIterator end = toc.end();
insertColumns(0, 1);
while (iter != end) {
- if (iter->depth == 1) {
+ if (iter->depth() >= 1) {
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);
- item_map_.insert(make_pair(top_level_item, *iter));
- index_map_.insert(make_pair(
- iter->str.substr(iter->str.find(' ') + 1),
top_level_item));
+ //setData(top_level_item, toqstr(iter->str()));
+ setData(top_level_item, toqstr(iter->str()),
Qt::DisplayRole);
+ toc_map_.insert(make_pair(top_level_item, iter));
+ model_map_.insert(make_pair(iter, top_level_item));
lyxerr[Debug::GUI]
- << "Toc: at depth " << iter->depth
- << ", added item " << iter->str
+ << "Toc: at depth " << iter->depth()
+ << ", added item " << iter->str()
<< endl;
populate(iter, end, top_level_item);
@@ -115,11 +116,11 @@
}
-void TocModel::populate(toc::Toc::const_iterator & iter,
- toc::Toc::const_iterator const
& end,
+void TocModel::populate(TocIterator & iter,
+ TocIterator const & end,
QModelIndex const & parent)
{
- int curdepth = iter->depth + 1;
+ int curdepth = iter->depth() + 1;
int current_row;
QModelIndex child_item;
@@ -131,31 +132,31 @@
if (iter == end)
break;
- if (iter->depth < curdepth) {
+ if (iter->depth() < curdepth) {
--iter;
return;
}
- if (iter->depth > curdepth) {
+ if (iter->depth() > curdepth) {
return;
}
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);
- item_map_.insert(make_pair(child_item, *iter));
- index_map_.insert(make_pair(
- iter->str.substr(iter->str.find(' ') + 1), child_item));
+ //setData(child_item, toqstr(iter->str()));
+ setData(child_item, toqstr(iter->str()), Qt::DisplayRole);
+ toc_map_.insert(make_pair(child_item, iter));
+ model_map_.insert(make_pair(iter, child_item));
// lyxerr[Debug::GUI]
-// << "Toc: at depth " << iter->depth
-// << ", added item " << iter->str
+// << "Toc: at depth " << iter->depth()
+// << ", added item " << iter->str()
// << endl;
populate(iter, end, child_item);
}
}
+
} // namespace frontend
} // namespace lyx
Index: src/frontends/qt4/TocModel.h
===================================================================
--- src/frontends/qt4/TocModel.h (revision 13695)
+++ src/frontends/qt4/TocModel.h (working copy)
@@ -12,7 +12,7 @@
#ifndef TOCMODEL_H
#define TOCMODEL_H
-#include "toc.h"
+#include "TocBackend.h"
#include "qt_helpers.h"
@@ -24,38 +24,42 @@
namespace lyx {
namespace frontend {
+typedef TocBackend::Toc::const_iterator TocIterator;
+
class TocModel: public QStandardItemModel {
Q_OBJECT
+
public:
///
TocModel() {}
///
- TocModel(toc::Toc const & toc_list);
+ TocModel(TocBackend::Toc const & toc);
///
~TocModel() {}
///
- TocModel const & operator=(toc::Toc const & toc_list);
+ TocModel const & operator=(TocBackend::Toc const & toc);
///
void clear();
///
- void populate(toc::Toc const & toc_list);
+ void populate(TocBackend::Toc const & toc);
///
- toc::TocItem const item(QModelIndex const & index) const;
+ TocIterator const tocIterator(QModelIndex const & index) const;
///
- QModelIndex const index(std::string const & toc_str) const;
+ QModelIndex const modelIndex(TocIterator const & it) const;
private:
///
- void populate(toc::Toc::const_iterator & iter,
- toc::Toc::const_iterator const & end,
- QModelIndex const & parent);
-
- typedef std::map<QModelIndex, toc::TocItem> ItemMap;
+ void populate(TocIterator & it,
+ TocIterator const & end,
+ QModelIndex const & parent);
///
- typedef std::map<std::string, QModelIndex> IndexMap;
+ typedef std::map<QModelIndex, TocIterator> TocMap;
///
- ItemMap item_map_;
- IndexMap index_map_;
+ typedef std::map<TocIterator, QModelIndex> ModelMap;
+ ///
+ TocMap toc_map_;
+ ///
+ ModelMap model_map_;
};
} // namespace frontend
Index: src/insets/insetfloat.C
===================================================================
--- src/insets/insetfloat.C (revision 13695)
+++ src/insets/insetfloat.C (working copy)
@@ -438,7 +438,7 @@
string const str =
convert<string>(toclist[type].size() + 1)
+ ". " + pit->asString(buf, false);
- lyx::toc::TocItem const item(pit->id(), 0 , str);
+ lyx::toc::TocItem const item(pit, 0 , str);
toclist[type].push_back(item);
}
}
Index: src/insets/insetwrap.C
===================================================================
--- src/insets/insetwrap.C (revision 13695)
+++ src/insets/insetwrap.C (working copy)
@@ -246,7 +246,7 @@
string const str =
convert<string>(toclist[type].size() + 1)
+ ". " + pit->asString(buf, false);
- lyx::toc::TocItem const item(pit->id(), 0 , str);
+ lyx::toc::TocItem const item(pit, 0 , str);
toclist[type].push_back(item);
}
}
Index: src/Makefile.am
===================================================================
--- src/Makefile.am (revision 13695)
+++ src/Makefile.am (working copy)
@@ -280,6 +280,8 @@
text.C \
text2.C \
text3.C \
+ TocBackend.C \
+ TocBackend.h \
toc.C \
toc.h \
trans.C \
Index: src/MenuBackend.C
===================================================================
--- src/MenuBackend.C (revision 13695)
+++ src/MenuBackend.C (working copy)
@@ -615,16 +615,16 @@
// check whether depth is smaller than the smallest depth in toc.
int min_depth = 1000;
for (lyx::toc::Toc::size_type i = from; i < to; ++i)
- min_depth = std::min(min_depth, toc_list[i].depth);
+ min_depth = std::min(min_depth, toc_list[i].depth());
if (min_depth > depth)
depth = min_depth;
if (to - from <= max_number_of_items) {
for (lyx::toc::Toc::size_type i = from; i < to; ++i) {
- string label(4 * max(0, toc_list[i].depth - depth),' ');
- label += limit_string_length(toc_list[i].str);
- if (toc_list[i].depth == depth
+ string label(4 * max(0, toc_list[i].depth() - depth),'
');
+ label += limit_string_length(toc_list[i].str());
+ if (toc_list[i].depth() == depth
&& shortcut_count < 9) {
if (label.find(convert<string>(shortcut_count +
1)) != string::npos)
label += '|' +
convert<string>(++shortcut_count);
@@ -637,12 +637,12 @@
while (pos < to) {
lyx::toc::Toc::size_type new_pos = pos + 1;
while (new_pos < to &&
- toc_list[new_pos].depth > depth)
+ toc_list[new_pos].depth() > depth)
++new_pos;
- string label(4 * max(0, toc_list[pos].depth - depth), '
');
- label += limit_string_length(toc_list[pos].str);
- if (toc_list[pos].depth == depth &&
+ string label(4 * max(0, toc_list[pos].depth() - depth),
' ');
+ label += limit_string_length(toc_list[pos].str());
+ if (toc_list[pos].depth() == depth &&
shortcut_count < 9) {
if (label.find(convert<string>(shortcut_count +
1)) != string::npos)
label += '|' +
convert<string>(++shortcut_count);
@@ -681,7 +681,7 @@
}
FloatList const & floatlist = buf->params().getLyXTextClass().floats();
- lyx::toc::TocList toc_list = lyx::toc::getTocList(*buf);
+ lyx::toc::TocList const & toc_list = lyx::toc::getTocList(*buf);
lyx::toc::TocList::const_iterator cit = toc_list.begin();
lyx::toc::TocList::const_iterator end = toc_list.end();
for (; cit != end; ++cit) {
@@ -694,7 +694,7 @@
lyx::toc::Toc::const_iterator ccit = cit->second.begin();
lyx::toc::Toc::const_iterator eend = cit->second.end();
for (; ccit != eend; ++ccit) {
- string const label = limit_string_length(ccit->str);
+ string const label = limit_string_length(ccit->str());
menu->add(MenuItem(MenuItem::Command,
label,
FuncRequest(ccit->action())));
Index: src/pariterator.h
===================================================================
--- src/pariterator.h (revision 13695)
+++ src/pariterator.h (working copy)
@@ -93,6 +93,8 @@
{
public:
///
+ ParConstIterator(): DocIterator() {}
+ ///
ParConstIterator(ParConstIterator const &);
///
ParConstIterator(DocIterator const &);
Index: src/toc.C
===================================================================
--- src/toc.C (revision 13695)
+++ src/toc.C (working copy)
@@ -31,181 +31,95 @@
#include "support/convert.h"
+#include <iostream>
+#include <map>
+
+using std::map;
+using std::pair;
+using std::make_pair;
using std::vector;
using std::max;
using std::ostream;
using std::string;
+using std::cout;
+using std::endl;
namespace lyx {
namespace toc {
-string const TocItem::asString() const
-{
- return string(4 * depth, ' ') + str;
-}
+typedef map<Buffer const *, lyx::TocBackend> TocMap;
+static TocMap toc_backend_;
+///////////////////////////////////////////////////////////////////////////
+// Interface to toc_backend_
-void TocItem::goTo(LyXView & lv_) const
+void updateToc(Buffer const & buf)
{
- string const tmp = convert<string>(id_);
- lv_.dispatch(FuncRequest(LFUN_GOTO_PARAGRAPH, tmp));
-}
+ TocMap::iterator it = toc_backend_.find(&buf);
+ if (it == toc_backend_.end()) {
+ pair<TocMap::iterator, bool> result
+ = toc_backend_.insert(make_pair(&buf,
TocBackend(&buf)));
+ if (!result.second)
+ return;
+ it = result.first;
+ }
-FuncRequest TocItem::action() const
-{
- return FuncRequest(LFUN_GOTO_PARAGRAPH, convert<string>(id_));
+ it->second.update();
}
-string const getType(string const & cmdName)
+TocList const & getTocList(Buffer const & buf)
{
- // special case
- if (cmdName == "tableofcontents")
- return "TOC";
- else
- return cmdName;
+ return toc_backend_[&buf].tocs();
}
-string const getGuiName(string const & type, Buffer const & buffer)
+Toc const & getToc(Buffer const & buf, std::string const & type)
{
- FloatList const & floats =
- buffer.params().getLyXTextClass().floats();
- if (floats.typeExist(type))
- return floats.getType(type).name();
- else
- return type;
+ return toc_backend_[&buf].toc(type);
}
-TocList const getTocList(Buffer const & buf)
+TocIterator const getCurrentTocItem(Buffer const & buf, LCursor const & cur,
+ std::string
const & type)
{
- TocList toclist;
-
- BufferParams const & bufparams = buf.params();
- const int min_toclevel = bufparams.getLyXTextClass().min_toclevel();
-
- ParConstIterator pit = buf.par_iterator_begin();
- ParConstIterator end = buf.par_iterator_end();
- for (; pit != end; ++pit) {
-
- // the string that goes to the toc (could be the optarg)
- string tocstring;
-
- // For each paragraph, traverse its insets and look for
- // FLOAT_CODE or WRAP_CODE
- InsetList::const_iterator it = pit->insetlist.begin();
- InsetList::const_iterator end = pit->insetlist.end();
- for (; it != end; ++it) {
- switch (it->inset->lyxCode()) {
- case InsetBase::FLOAT_CODE:
- static_cast<InsetFloat*>(it->inset)
- ->addToToc(toclist, buf);
- break;
- case InsetBase::WRAP_CODE:
- static_cast<InsetWrap*>(it->inset)
- ->addToToc(toclist, buf);
- break;
- case InsetBase::OPTARG_CODE: {
- if (!tocstring.empty())
- break;
- Paragraph const & par =
*static_cast<InsetOptArg*>(it->inset)->paragraphs().begin();
- if (!pit->getLabelstring().empty())
- tocstring = pit->getLabelstring()
- + ' ';
- tocstring += par.asString(buf, false);
- break;
- }
- default:
- break;
- }
- }
-
- /// now the toc entry for the paragraph
- int const toclevel = pit->layout()->toclevel;
- if (toclevel != LyXLayout::NOT_IN_TOC
- && toclevel >= min_toclevel
- && toclevel <= bufparams.tocdepth) {
- // insert this into the table of contents
- if (tocstring.empty())
- tocstring = pit->asString(buf, true);
- TocItem const item(pit->id(), toclevel - min_toclevel,
- tocstring);
- toclist["TOC"].push_back(item);
- }
- }
- return toclist;
+ return toc_backend_[&buf].item(type, ParConstIterator(cur));
}
-TocItem const getCurrentTocItem(Buffer const & buf, LCursor const & cur,
- std::string
const & type)
+vector<string> const & getTypes(Buffer const & buf)
{
- // This should be cached:
- TocList tmp = getTocList(buf);
-
- // Is the type supported?
- /// \todo TocItem() should create an invalid TocItem()
- /// \todo create TocItem::isValid()
- TocList::iterator toclist_it = tmp.find(type);
- if (toclist_it == tmp.end())
- return TocItem(-1, -1, string());
-
- Toc const toc_vector = toclist_it->second;
- ParConstIterator const current(cur);
- int start = toc_vector.size() - 1;
-
- /// \todo cache the ParConstIterator values inside TocItem
- for (int i = start; i >= 0; --i) {
-
- ParConstIterator const it
- = buf.getParFromID(toc_vector[i].id_);
-
- // A good solution for TocItems inside insets would be to do:
- //
- //if (std::distance(it, current) <= 0)
- // return toc_vector[i];
- //
- // But for an unknown reason, std::distance(current, it) always
- // returns a positive value and std::distance(it, current)
takes forever...
- // So for now, we do:
- if (it.pit() <= current.pit())
- return toc_vector[i];
- }
-
- // We are before the first TocItem:
- return toc_vector[0];
+ return toc_backend_[&buf].types();
}
-vector<string> const getTypes(Buffer const & buffer)
+void asciiTocList(string const & type, Buffer const & buf, ostream & os)
{
- vector<string> types;
+ toc_backend_[&buf].asciiTocList(type, os);
+}
- TocList const tmp = getTocList(buffer);
+///////////////////////////////////////////////////////////////////////////
+// Other functions
- TocList::const_iterator cit = tmp.begin();
- TocList::const_iterator end = tmp.end();
-
- for (; cit != end; ++cit) {
- types.push_back(cit->first);
- }
-
- return types;
+string const getType(string const & cmdName)
+{
+ // special case
+ if (cmdName == "tableofcontents")
+ return "TOC";
+ else
+ return cmdName;
}
-void asciiTocList(string const & type, Buffer const & buffer, ostream & os)
+string const getGuiName(string const & type, Buffer const & buffer)
{
- TocList const toc_list = getTocList(buffer);
- TocList::const_iterator cit = toc_list.find(type);
- if (cit != toc_list.end()) {
- Toc::const_iterator ccit = cit->second.begin();
- Toc::const_iterator end = cit->second.end();
- for (; ccit != end; ++ccit)
- os << ccit->asString() << '\n';
- }
+ FloatList const & floats =
+ buffer.params().getLyXTextClass().floats();
+ if (floats.typeExist(type))
+ return floats.getType(type).name();
+ else
+ return type;
}
Index: src/toc.h
===================================================================
--- src/toc.h (revision 13695)
+++ src/toc.h (working copy)
@@ -15,55 +15,33 @@
#ifndef TOC_H
#define TOC_H
-#include <map>
-#include <iosfwd>
-#include <vector>
-#include <string>
+#include "TocBackend.h"
-#include "pariterator.h"
-
-class Buffer;
-class LyXView;
-class Paragraph;
-class FuncRequest;
class LCursor;
namespace lyx {
namespace toc {
+typedef TocBackend::Item TocItem;
+typedef TocBackend::Toc::const_iterator TocIterator;
+typedef TocBackend::Toc Toc;
+typedef TocBackend::TocList TocList;
+
///
-class TocItem {
-public:
- TocItem(int par_id, int d, std::string const & s)
- : id_(par_id), depth(d), str(s) {}
- ///
- std::string const asString() const;
- /// set cursor in LyXView to this TocItem
- void goTo(LyXView & lv_) const;
- /// the action corresponding to the goTo above
- FuncRequest action() const;
- /// Paragraph ID containing this item
- int id_;
- /// nesting depth
- int depth;
- ///
- std::string str;
-};
+void updateToc(Buffer const &);
///
-typedef std::vector<TocItem> Toc;
-///
-typedef std::map<std::string, Toc> TocList;
+TocList const & getTocList(Buffer const &);
///
-TocList const getTocList(Buffer const &);
+Toc const & getToc(Buffer const & buf, std::string const & type);
///
-std::vector<std::string> const getTypes(Buffer const &);
+std::vector<std::string> const & getTypes(Buffer const &);
/// Return the first TocItem before the cursor
-TocItem const getCurrentTocItem(Buffer const &, LCursor const &,
- std::string
const & type);
+TocIterator const getCurrentTocItem(Buffer const &, LCursor const &,
+
std::string const & type);
///
void asciiTocList(std::string const &, Buffer const &, std::ostream &);
@@ -76,21 +54,6 @@
The localization of the names will be done in the frontends */
std::string const getGuiName(std::string const & type, Buffer const &);
-inline
-bool operator==(TocItem const & a, TocItem const & b)
-{
- return a.id_ == b.id_ && a.str == b.str;
- // No need to compare depth.
-}
-
-
-inline
-bool operator!=(TocItem const & a, TocItem const & b)
-{
- return !(a == b);
-}
-
-
/// the type of outline operation
enum OutlineOp {
UP, // Move this header with text down
Index: src/TocBackend.C
===================================================================
--- src/TocBackend.C (revision 0)
+++ src/TocBackend.C (revision 0)
@@ -0,0 +1,261 @@
+/**
+ * \file TocBackend.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Jean-Marc Lasgouttes
+ * \author Angus Leeming
+ * \author Abdelrazak Younes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "toc.h"
+
+#include "buffer.h"
+#include "bufferparams.h"
+#include "FloatList.h"
+#include "funcrequest.h"
+#include "LyXAction.h"
+#include "paragraph.h"
+#include "cursor.h"
+#include "debug.h"
+
+#include "frontends/LyXView.h"
+
+#include "insets/insetfloat.h"
+#include "insets/insetoptarg.h"
+#include "insets/insetwrap.h"
+
+#include "support/convert.h"
+
+#include <iostream>
+
+using std::vector;
+using std::max;
+using std::ostream;
+using std::string;
+using std::cout;
+using std::endl;
+
+namespace lyx {
+
+///////////////////////////////////////////////////////////////////////////
+// TocBackend::Item implementation
+
+TocBackend::Item::Item(ParConstIterator const & par_it, int d,
+ std::string const & s)
+ : par_it_(par_it), depth_(d), str_(s)
+{
+/*
+ if (!uid_.empty())
+ return;
+
+ size_t pos = s.find(" ");
+ if (pos == string::npos) {
+ // Non labelled item
+ uid_ = s;
+ return;
+ }
+
+ string s2 = s.substr(0, pos);
+
+ if (s2 == "Chapter" || s2 == "Part") {
+ size_t pos2 = s.find(" ", pos + 1);
+ if (pos2 == string::npos) {
+ // Unnumbered Chapter?? This should not happen.
+ uid_ = s.substr(pos + 1);
+ return;
+ }
+ // Chapter or Part
+ uid_ = s.substr(pos2 + 1);
+ return;
+ }
+ // Numbered Item.
+ uid_ = s.substr(pos + 1);
+ */
+}
+
+bool const TocBackend::Item::isValid() const
+{
+ return depth_ != -1;
+}
+
+
+int const TocBackend::Item::id() const
+{
+ return par_it_->id();
+}
+
+
+int const TocBackend::Item::depth() const
+{
+ return depth_;
+}
+
+
+std::string const & TocBackend::Item::str() const
+{
+ return str_;
+}
+
+
+string const TocBackend::Item::asString() const
+{
+ return string(4 * depth_, ' ') + str_;
+}
+
+
+void TocBackend::Item::goTo(LyXView & lv_) const
+{
+ string const tmp = convert<string>(id());
+ lv_.dispatch(FuncRequest(LFUN_GOTO_PARAGRAPH, tmp));
+}
+
+FuncRequest TocBackend::Item::action() const
+{
+ return FuncRequest(LFUN_GOTO_PARAGRAPH, convert<string>(id()));
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////
+// TocBackend implementation
+
+TocBackend::Toc const & TocBackend::toc(std::string const & type)
+{
+ // Is the type already supported?
+ TocList::const_iterator it = tocs_.find(type);
+ if (it == tocs_.end())
+ return empty_toc_;
+
+ return it->second;
+}
+
+
+bool TocBackend::addType(std::string const & type)
+{
+ // Is the type already supported?
+ TocList::iterator toclist_it = tocs_.find(type);
+ if (toclist_it != tocs_.end())
+ return false;
+
+ tocs_.insert(make_pair(type, Toc()));
+ types_.push_back(type);
+
+ return true;
+}
+
+
+void TocBackend::update()
+{
+ tocs_.clear();
+ types_.clear();
+
+ BufferParams const & bufparams = buffer_->params();
+ const int min_toclevel = bufparams.getLyXTextClass().min_toclevel();
+
+ ParConstIterator pit = buffer_->par_iterator_begin();
+ ParConstIterator end = buffer_->par_iterator_end();
+ for (; pit != end; ++pit) {
+
+ // the string that goes to the toc (could be the optarg)
+ string tocstring;
+
+ // For each paragraph, traverse its insets and look for
+ // FLOAT_CODE or WRAP_CODE
+ InsetList::const_iterator it = pit->insetlist.begin();
+ InsetList::const_iterator end = pit->insetlist.end();
+ for (; it != end; ++it) {
+ switch (it->inset->lyxCode()) {
+ case InsetBase::FLOAT_CODE:
+ static_cast<InsetFloat*>(it->inset)
+ ->addToToc(tocs_, *buffer_);
+ break;
+ case InsetBase::WRAP_CODE:
+ static_cast<InsetWrap*>(it->inset)
+ ->addToToc(tocs_, *buffer_);
+ break;
+ case InsetBase::OPTARG_CODE: {
+ if (!tocstring.empty())
+ break;
+ Paragraph const & par =
*static_cast<InsetOptArg*>(it->inset)->paragraphs().begin();
+ if (!pit->getLabelstring().empty())
+ tocstring = pit->getLabelstring()
+ + ' ';
+ tocstring += par.asString(*buffer_, false);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /// now the toc entry for the paragraph
+ int const toclevel = pit->layout()->toclevel;
+ if (toclevel != LyXLayout::NOT_IN_TOC
+ && toclevel >= min_toclevel
+ && toclevel <= bufparams.tocdepth) {
+ // insert this into the table of contents
+ if (tocstring.empty())
+ tocstring = pit->asString(*buffer_, true);
+ Item const item(pit, toclevel - min_toclevel,
tocstring);
+ tocs_["TOC"].push_back(item);
+ //cout << "item inserted str " << item.str()
+ // << " id " << item.id() << endl;
+ }
+ }
+
+ TocList::iterator it = tocs_.begin();
+ for (; it != tocs_.end(); ++it)
+ types_.push_back(it->first);
+}
+
+
+TocBackend::TocIterator const TocBackend::item(std::string const & type,
ParConstIterator const & par_it)
+{
+ TocList::iterator toclist_it = tocs_.find(type);
+ // Is the type supported?
+ BOOST_ASSERT(toclist_it != tocs_.end());
+
+ Toc const & toc_vector = toclist_it->second;
+ TocBackend::TocIterator last = toc_vector.begin();
+ TocBackend::TocIterator it = toc_vector.end();
+ --it;
+
+ for (; it != last; --it) {
+
+ // A good solution for Items inside insets would be to do:
+ //
+ //if (std::distance(it->par_it_, current) <= 0)
+ // return it;
+ //
+ // But for an unknown reason, std::distance(current,
it->par_it_) always
+ // returns a positive value and std::distance(it->par_it_,
current) takes forever...
+ // So for now, we do:
+ if (it->par_it_.pit() <= par_it.pit())
+ return it;
+ }
+
+ // We are before the first Toc Item:
+ return last;
+}
+
+
+void TocBackend::asciiTocList(string const & type, ostream & os) const
+{
+ TocList::const_iterator cit = tocs_.find(type);
+ if (cit != tocs_.end()) {
+ Toc::const_iterator ccit = cit->second.begin();
+ Toc::const_iterator end = cit->second.end();
+ for (; ccit != end; ++ccit)
+ os << ccit->asString() << '\n';
+ }
+}
+
+
+} // namespace lyx
Index: src/TocBackend.h
===================================================================
--- src/TocBackend.h (revision 0)
+++ src/TocBackend.h (revision 0)
@@ -0,0 +1,145 @@
+// -*- C++ -*-
+/**
+ * \file TocBackend.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Jean-Marc Lasgouttes
+ * \author Angus Leeming
+ * \author Abdelrazak Younes
+ *
+ * Full author contact details are available in file CREDITS.
+ *
+ * TocBackend mainly used in toc.[Ch]
+ */
+
+#ifndef TOC_BACKEND_H
+#define TOC_BACKEND_H
+
+#include <map>
+#include <iosfwd>
+#include <vector>
+#include <string>
+
+#include "pariterator.h"
+
+class Buffer;
+class LyXView;
+class Paragraph;
+class FuncRequest;
+class LCursor;
+
+namespace lyx {
+
+///
+/**
+*/
+class TocBackend
+{
+public:
+
+ ///
+ /**
+ */
+ class Item
+ {
+ friend class TocBackend;
+ friend bool operator==(Item const & a, Item const & b);
+
+ public:
+ ///
+ Item(
+ ParConstIterator const & par_it = ParConstIterator(),
+ int d = -1,
+ std::string const & s = std::string());
+ ///
+ ~Item() {}
+ ///
+ bool const isValid() const;
+ ///
+ int const id() const;
+ ///
+ int const depth() const;
+ ///
+ std::string const & str() const;
+ ///
+ std::string const asString() const;
+ /// set cursor in LyXView to this Item
+ void goTo(LyXView & lv_) const;
+ /// the action corresponding to the goTo above
+ FuncRequest action() const;
+
+ protected:
+ /// Current position of item.
+ ParConstIterator par_it_;
+
+ /// nesting depth
+ int depth_;
+
+ /// Full item string
+ std::string str_;
+ };
+
+ ///
+ typedef std::vector<Item> Toc;
+ typedef std::vector<Item>::const_iterator TocIterator;
+ ///
+ typedef std::map<std::string, Toc> TocList;
+
+public:
+ ///
+ TocBackend(Buffer const * buffer = NULL): buffer_(buffer) {}
+ ///
+ ~TocBackend() {}
+ ///
+ void setBuffer(Buffer const * buffer)
+ { buffer_ = buffer; }
+ ///
+ bool addType(std::string const & type);
+ ///
+ void update();
+ ///
+ TocList const & tocs()
+ { return tocs_; }
+ ///
+ std::vector<std::string> const & types()
+ { return types_; }
+ ///
+ Toc const & toc(std::string const & type);
+ /// Return the first Toc Item before the cursor
+ TocIterator const item(std::string const & type, ParConstIterator const
&);
+
+ void asciiTocList(std::string const & type, std::ostream & os) const;
+
+private:
+ ///
+ TocList tocs_;
+ ///
+ std::vector<std::string> types_;
+ ///
+ Item const invalid_item_;
+ ///
+ Toc const empty_toc_;
+ ///
+ Buffer const * buffer_;
+
+}; // TocBackend
+
+inline
+bool operator==(TocBackend::Item const & a, TocBackend::Item const & b)
+{
+ return a.id() == b.id() && a.str() == b.str();
+ // No need to compare depth.
+}
+
+
+inline
+bool operator!=(TocBackend::Item const & a, TocBackend::Item const & b)
+{
+ return !(a == b);
+}
+
+
+} // namespace lyx
+
+#endif // TOC_BACKEND_H