]> git.lyx.org Git - lyx.git/blob - src/toc.C
c20c0b171d6c140d53c5cbf23da1807029b7fe35
[lyx.git] / src / toc.C
1 /**
2  * \file toc.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 using std::vector;
35 using std::max;
36 using std::ostream;
37 using std::string;
38
39 namespace lyx {
40 namespace toc {
41
42 string const TocItem::asString() const
43 {
44         return string(4 * depth, ' ') + str;
45 }
46
47
48 void TocItem::goTo(LyXView & lv_) const
49 {
50         string const tmp = convert<string>(id_);
51         lv_.dispatch(FuncRequest(LFUN_GOTO_PARAGRAPH, tmp));
52 }
53
54
55 FuncRequest TocItem::action() const
56 {
57         return FuncRequest(LFUN_GOTO_PARAGRAPH, convert<string>(id_));
58 }
59
60
61 string const getType(string const & cmdName)
62 {
63         // special case
64         if (cmdName == "tableofcontents")
65                 return "TOC";
66         else
67                 return cmdName;
68 }
69
70
71 string const getGuiName(string const & type, Buffer const & buffer)
72 {
73         FloatList const & floats =
74                 buffer.params().getLyXTextClass().floats();
75         if (floats.typeExist(type))
76                 return floats.getType(type).name();
77         else
78                 return type;
79 }
80
81
82 TocList const getTocList(Buffer const & buf)
83 {
84         TocList toclist;
85
86         BufferParams const & bufparams = buf.params();
87         const int min_toclevel = bufparams.getLyXTextClass().min_toclevel();
88
89         ParConstIterator pit = buf.par_iterator_begin();
90         ParConstIterator end = buf.par_iterator_end();
91         for (; pit != end; ++pit) {
92
93                 // the string that goes to the toc (could be the optarg)
94                 string tocstring;
95
96                 // For each paragraph, traverse its insets and look for
97                 // FLOAT_CODE or WRAP_CODE
98                 InsetList::const_iterator it = pit->insetlist.begin();
99                 InsetList::const_iterator end = pit->insetlist.end();
100                 for (; it != end; ++it) {
101                         switch (it->inset->lyxCode()) {
102                         case InsetBase::FLOAT_CODE:
103                                 static_cast<InsetFloat*>(it->inset)
104                                         ->addToToc(toclist, buf);
105                                 break;
106                         case InsetBase::WRAP_CODE:
107                                 static_cast<InsetWrap*>(it->inset)
108                                         ->addToToc(toclist, buf);
109                                 break;
110                         case InsetBase::OPTARG_CODE: {
111                                 if (!tocstring.empty())
112                                         break;
113                                 Paragraph const & par = *static_cast<InsetOptArg*>(it->inset)->paragraphs().begin();
114                                 if (!pit->getLabelstring().empty())
115                                         tocstring = pit->getLabelstring()
116                                                 + ' ';
117                                 tocstring += par.asString(buf, false);
118                                 break;
119                         }
120                         default:
121                                 break;
122                         }
123                 }
124
125                 /// now the toc entry for the paragraph
126                 int const toclevel = pit->layout()->toclevel;
127                 if (toclevel != LyXLayout::NOT_IN_TOC
128                     && toclevel >= min_toclevel
129                     && toclevel <= bufparams.tocdepth) {
130                         // insert this into the table of contents
131                         if (tocstring.empty())
132                                 tocstring = pit->asString(buf, true);
133                         TocItem const item(pit->id(), toclevel - min_toclevel,
134                                            tocstring);
135                         toclist["TOC"].push_back(item);
136                 }
137         }
138         return toclist;
139 }
140
141
142 TocItem const getCurrentTocItem(Buffer const & buf, LCursor const & cur,
143                                                                 std::string const & type)
144 {
145         // This should be cached:
146         TocList tmp = getTocList(buf);
147
148         // Is the type supported?
149         /// \todo TocItem() should create an invalid TocItem()
150         /// \todo create TocItem::isValid()
151         TocList::iterator toclist_it = tmp.find(type);
152         if (toclist_it == tmp.end())
153                 return TocItem(-1, -1, string());
154
155         Toc const toc_vector = toclist_it->second;
156         ParConstIterator const current(cur);
157         int start = toc_vector.size() - 1;
158
159         /// \todo cache the ParConstIterator values inside TocItem
160         for (int i = start; i >= 0; --i) {
161                 
162                 ParConstIterator const it 
163                         = buf.getParFromID(toc_vector[i].id_);
164
165                 // A good solution for TocItems inside insets would be to do:
166                 //
167                 //if (std::distance(it, current) <= 0)
168                 //      return toc_vector[i];
169                 //
170                 // But for an unknown reason, std::distance(current, it) always
171                 // returns  a positive value and std::distance(it, current) takes forever...
172                 // So for now, we do:
173                 if (it.pit() <= current.pit())
174                         return toc_vector[i];
175         }
176
177         // We are before the first TocItem:
178         return toc_vector[0];
179 }
180
181
182 vector<string> const getTypes(Buffer const & buffer)
183 {
184         vector<string> types;
185
186         TocList const tmp = getTocList(buffer);
187
188         TocList::const_iterator cit = tmp.begin();
189         TocList::const_iterator end = tmp.end();
190
191         for (; cit != end; ++cit) {
192                 types.push_back(cit->first);
193         }
194
195         return types;
196 }
197
198
199 void asciiTocList(string const & type, Buffer const & buffer, ostream & os)
200 {
201         TocList const toc_list = getTocList(buffer);
202         TocList::const_iterator cit = toc_list.find(type);
203         if (cit != toc_list.end()) {
204                 Toc::const_iterator ccit = cit->second.begin();
205                 Toc::const_iterator end = cit->second.end();
206                 for (; ccit != end; ++ccit)
207                         os << ccit->asString() << '\n';
208         }
209 }
210
211
212 void outline(OutlineOp mode, Buffer * buf, pit_type & pit)
213 {
214         ParagraphList & pars = buf->text().paragraphs();
215         ParagraphList::iterator bgn = pars.begin();
216         ParagraphList::iterator s = boost::next(bgn, pit);
217         ParagraphList::iterator p = s;
218         ParagraphList::iterator end = pars.end();
219
220         LyXTextClass::const_iterator lit =
221                 buf->params().getLyXTextClass().begin();
222         LyXTextClass::const_iterator const lend =
223                 buf->params().getLyXTextClass().end();
224
225         int const thistoclevel = s->layout()->toclevel;
226         int toclevel;
227         switch (mode) {
228                 case UP: {
229                         if (p != end)
230                                 ++p;
231                         for (; p != end; ++p) {
232                                 toclevel = p->layout()->toclevel;
233                                 if (toclevel != LyXLayout::NOT_IN_TOC
234                                     && toclevel <= thistoclevel) {
235                                         break;
236                                 }
237                         }
238                         ParagraphList::iterator q = s;
239                         if (q != bgn)
240                                 --q;
241                         else
242                                 break;
243                         for (; q != bgn; --q) {
244                                 toclevel = q->layout()->toclevel;
245                                 if (toclevel != LyXLayout::NOT_IN_TOC
246                                     && toclevel <= thistoclevel) {
247                                         break;
248                                 }
249                         }
250                         pit_type const newpit = std::distance(pars.begin(), q);
251                         pit_type const len = std::distance(s, p);
252                         pit += len;
253                         pars.insert(q, s, p);
254                         s = boost::next(pars.begin(), pit);
255                         ParagraphList::iterator t = boost::next(s, len);
256                         pit = newpit;
257                         pars.erase(s, t);
258                 break;
259                 }
260                 case DOWN: {
261                            if (p != end)
262                                 ++p;
263                         for (; p != end; ++p) {
264                                 toclevel = p->layout()->toclevel;
265                                 if (toclevel != LyXLayout::NOT_IN_TOC
266                                     && toclevel <= thistoclevel) {
267                                         break;
268                                 }
269                         }
270                         ParagraphList::iterator q = p;
271                         if (q != end)
272                                 ++q;
273                         else
274                                 break;
275                         for (; q != end; ++q) {
276                                 toclevel = q->layout()->toclevel;
277                                 if (toclevel != LyXLayout::NOT_IN_TOC
278                                     && toclevel <= thistoclevel) {
279                                         break;
280                                 }
281                         }
282                         pit_type const newpit = std::distance(pars.begin(), q);
283                         pit_type const len = std::distance(s, p);
284                         pars.insert(q, s, p);
285                         s = boost::next(pars.begin(), pit);
286                         ParagraphList::iterator t = boost::next(s, len);
287                         pit = newpit - len;
288                         pars.erase(s, t);
289                 break;
290                 }
291                 case IN:
292                         for (; lit != lend; ++lit) {
293                                 if ((*lit)->toclevel == thistoclevel + 1) {
294                                         s->layout((*lit));
295                                         break;
296                                 }
297                         }
298                 break;
299                 case OUT:
300                         for (; lit != lend; ++lit) {
301                                 if ((*lit)->toclevel == thistoclevel - 1) {
302                                         s->layout((*lit));
303                                         break;
304                                 }
305                         }
306                 break;
307                 default:
308                 break;
309         }
310 }
311
312
313 } // namespace toc
314 } // namespace lyx