]> git.lyx.org Git - lyx.git/blob - src/TocBackend.C
Change tracking:
[lyx.git] / src / TocBackend.C
1 /**
2  * \file TocBackend.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jean-Marc Lasgouttes
7  * \author Angus Leeming
8  * \author Abdelrazak Younes
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "toc.h"
16
17 #include "buffer.h"
18 #include "bufferparams.h"
19 #include "FloatList.h"
20 #include "funcrequest.h"
21 #include "LyXAction.h"
22 #include "paragraph.h"
23 #include "cursor.h"
24 #include "debug.h"
25
26 #include "frontends/LyXView.h"
27
28 #include "insets/insetfloat.h"
29 #include "insets/insetoptarg.h"
30 #include "insets/insetwrap.h"
31
32 #include "support/convert.h"
33
34 #include <iostream>
35
36 using lyx::docstring;
37
38 using std::vector;
39 using std::max;
40 using std::ostream;
41 using std::string;
42 using std::cout;
43 using std::endl;
44
45 namespace lyx {
46
47 ///////////////////////////////////////////////////////////////////////////
48 // TocBackend::Item implementation
49
50 TocBackend::Item::Item(ParConstIterator const & par_it, int d,
51                 docstring const & s)
52                 : par_it_(par_it), depth_(d), str_(s)
53 {
54 /*
55         if (!uid_.empty())
56                 return;
57
58         size_t pos = s.find(" ");
59         if (pos == string::npos) {
60                 // Non labelled item
61                 uid_ = s;
62                 return;
63         }
64
65         string s2 = s.substr(0, pos);
66
67         if (s2 == "Chapter" || s2 == "Part") {
68                 size_t pos2 = s.find(" ", pos + 1);
69                 if (pos2 == string::npos) {
70                         // Unnumbered Chapter?? This should not happen.
71                         uid_ = s.substr(pos + 1);
72                         return;
73                 }
74                 // Chapter or Part
75                 uid_ = s.substr(pos2 + 1);
76                 return;
77         }
78         // Numbered Item.
79         uid_ = s.substr(pos + 1);
80         */
81 }
82
83 bool const TocBackend::Item::isValid() const
84 {
85         return depth_ != -1;
86 }
87
88
89 int const TocBackend::Item::id() const
90 {
91         return par_it_->id();
92 }
93
94
95 int const TocBackend::Item::depth() const
96 {
97         return depth_;
98 }
99
100
101 docstring const & TocBackend::Item::str() const
102 {
103         return str_;
104 }
105
106
107 docstring const TocBackend::Item::asString() const
108 {
109         return docstring(4 * depth_, ' ') + str_;
110 }
111
112
113 void TocBackend::Item::goTo(LyXView & lv_) const
114 {
115         string const tmp = convert<string>(id());
116         lv_.dispatch(FuncRequest(LFUN_PARAGRAPH_GOTO, tmp));
117 }
118
119 FuncRequest TocBackend::Item::action() const
120 {
121         return FuncRequest(LFUN_PARAGRAPH_GOTO, convert<string>(id()));
122 }
123
124
125
126
127
128 ///////////////////////////////////////////////////////////////////////////
129 // TocBackend implementation
130
131 TocBackend::Toc const & TocBackend::toc(std::string const & type)
132 {
133         // Is the type already supported?
134         TocList::const_iterator it = tocs_.find(type);
135         BOOST_ASSERT(it != tocs_.end());
136
137         return it->second;
138 }
139
140
141 bool TocBackend::addType(std::string const & type)
142 {
143         // Is the type already supported?
144         TocList::iterator toclist_it = tocs_.find(type);
145         if (toclist_it != tocs_.end())
146                 return false;
147
148         tocs_.insert(make_pair(type, Toc()));
149         types_.push_back(type);
150
151         return true;
152 }
153
154
155 void TocBackend::update()
156 {
157         tocs_.clear();
158         types_.clear();
159
160         BufferParams const & bufparams = buffer_->params();
161         const int min_toclevel = bufparams.getLyXTextClass().min_toclevel();
162
163         ParConstIterator pit = buffer_->par_iterator_begin();
164         ParConstIterator end = buffer_->par_iterator_end();
165         for (; pit != end; ++pit) {
166
167                 // the string that goes to the toc (could be the optarg)
168                 docstring tocstring;
169
170                 // For each paragraph, traverse its insets and look for
171                 // FLOAT_CODE or WRAP_CODE
172                 InsetList::const_iterator it = pit->insetlist.begin();
173                 InsetList::const_iterator end = pit->insetlist.end();
174                 for (; it != end; ++it) {
175                         switch (it->inset->lyxCode()) {
176                         case InsetBase::FLOAT_CODE:
177                                 static_cast<InsetFloat*>(it->inset)
178                                         ->addToToc(tocs_, *buffer_);
179                                 break;
180                         case InsetBase::WRAP_CODE:
181                                 static_cast<InsetWrap*>(it->inset)
182                                         ->addToToc(tocs_, *buffer_);
183                                 break;
184                         case InsetBase::OPTARG_CODE: {
185                                 if (!tocstring.empty())
186                                         break;
187                                 Paragraph const & par = *static_cast<InsetOptArg*>(it->inset)->paragraphs().begin();
188                                 if (!pit->getLabelstring().empty())
189                                         // FIXME UNICODE
190                                         tocstring = lyx::from_utf8(
191                                                 pit->getLabelstring() + ' ');
192                                 tocstring += par.asString(*buffer_, false);
193                                 break;
194                         }
195                         default:
196                                 break;
197                         }
198                 }
199
200                 /// now the toc entry for the paragraph
201                 int const toclevel = pit->layout()->toclevel;
202                 if (toclevel != LyXLayout::NOT_IN_TOC
203                     && toclevel >= min_toclevel
204                     && toclevel <= bufparams.tocdepth) {
205                         // insert this into the table of contents
206                         if (tocstring.empty())
207                                 tocstring = pit->asString(*buffer_, true);
208                         Item const item(pit, toclevel - min_toclevel, tocstring);
209                         tocs_["TOC"].push_back(item);
210                         //cout << "item inserted str " << item.str()
211                         //      << "  id " << item.id() << endl;
212                 }
213         }
214
215         TocList::iterator it = tocs_.begin();
216         for (; it != tocs_.end(); ++it)
217                 types_.push_back(it->first);
218 }
219
220
221 TocBackend::TocIterator const TocBackend::item(std::string const & type, ParConstIterator const & par_it)
222 {
223         TocList::iterator toclist_it = tocs_.find(type);
224         // Is the type supported?
225         BOOST_ASSERT(toclist_it != tocs_.end());
226
227         Toc const & toc_vector = toclist_it->second;
228         TocBackend::TocIterator last = toc_vector.begin();
229         TocBackend::TocIterator it = toc_vector.end();
230         --it;
231
232         for (; it != last; --it) {
233                 
234                 // A good solution for Items inside insets would be to do:
235                 //
236                 //if (std::distance(it->par_it_, current) <= 0)
237                 //      return it;
238                 //
239                 // But for an unknown reason, std::distance(current, it->par_it_) always
240                 // returns  a positive value and std::distance(it->par_it_, current) takes forever...
241                 // So for now, we do:
242                 if (it->par_it_.pit() <= par_it.pit())
243                         return it;
244         }
245
246         // We are before the first Toc Item:
247         return last;
248 }
249
250
251 void TocBackend::asciiTocList(string const & type, lyx::odocstream & os) const
252 {
253         TocList::const_iterator cit = tocs_.find(type);
254         if (cit != tocs_.end()) {
255                 Toc::const_iterator ccit = cit->second.begin();
256                 Toc::const_iterator end = cit->second.end();
257                 for (; ccit != end; ++ccit)
258                         os << ccit->asString() << '\n';
259         }
260 }
261
262
263 } // namespace lyx