]> git.lyx.org Git - lyx.git/blob - src/insets/InsetIndex.cpp
This optional argument to the InsetCollapsable constructor
[lyx.git] / src / insets / InsetIndex.cpp
1 /**
2  * \file InsetIndex.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10 #include <config.h>
11
12 #include "InsetIndex.h"
13
14 #include "Buffer.h"
15 #include "DispatchResult.h"
16 #include "Encoding.h"
17 #include "FuncRequest.h"
18 #include "FuncStatus.h"
19 #include "LaTeXFeatures.h"
20 #include "MetricsInfo.h"
21 #include "sgml.h"
22 #include "TocBackend.h"
23
24 #include "support/debug.h"
25 #include "support/docstream.h"
26 #include "support/gettext.h"
27 #include "support/lstrings.h"
28
29 #include "frontends/alert.h"
30
31 #include <ostream>
32
33 using namespace std;
34 using namespace lyx::support;
35
36 namespace lyx {
37
38 /////////////////////////////////////////////////////////////////////
39 //
40 // InsetIndex
41 //
42 ///////////////////////////////////////////////////////////////////////
43
44
45 InsetIndex::InsetIndex(Buffer const & buf)
46         : InsetCollapsable(buf)
47 {}
48
49
50 int InsetIndex::latex(odocstream & os,
51                       OutputParams const & runparams) const
52 {
53         os << "\\index";
54         os << '{';
55         int i = 0;
56
57         // get contents of InsetText as LaTeX and plaintext
58         odocstringstream ourlatex;
59         InsetText::latex(ourlatex, runparams);
60         odocstringstream ourplain;
61         InsetText::plaintext(ourplain, runparams);
62         docstring latexstr = ourlatex.str();
63         docstring plainstr = ourplain.str();
64
65         // this will get what follows | if anything does
66         docstring cmd;
67
68         // check for the | separator
69         // FIXME This would go wrong on an escaped "|", but
70         // how far do we want to go here?
71         size_t pos = latexstr.find(from_ascii("|"));
72         if (pos != docstring::npos) {
73                 // put the bit after "|" into cmd...
74                 cmd = latexstr.substr(pos + 1);
75                 // ...and erase that stuff from latexstr
76                 latexstr = latexstr.erase(pos);
77                 // ...and similarly from plainstr
78                 size_t ppos = plainstr.find(from_ascii("|"));
79                 if (ppos < plainstr.size())
80                         plainstr.erase(ppos);
81                 else
82                         LYXERR0("The `|' separator was not found in the plaintext version!");
83         }
84
85         // Separate the entires and subentries, i.e., split on "!"
86         // FIXME This would do the wrong thing with escaped ! characters
87         std::vector<docstring> const levels =
88                 getVectorFromString(latexstr, from_ascii("!"), true);
89         std::vector<docstring> const levels_plain =
90                 getVectorFromString(plainstr, from_ascii("!"), true);
91
92         vector<docstring>::const_iterator it = levels.begin();
93         vector<docstring>::const_iterator end = levels.end();
94         vector<docstring>::const_iterator it2 = levels_plain.begin();
95         bool first = true;
96         for (; it != end; ++it) {
97                 // write the separator except the first time
98                 if (!first)
99                         os << '!';
100                 else
101                         first = false;
102
103                 // correctly sort macros and formatted strings
104                 // if we do find a command, prepend a plain text
105                 // version of the content to get sorting right,
106                 // e.g. \index{LyX@\LyX}, \index{text@\textbf{text}}
107                 // Don't do that if the user entered '@' himself, though.
108                 if (contains(*it, '\\') && !contains(*it, '@')) {
109                         // Plaintext might return nothing (e.g. for ERTs)
110                         docstring const spart = 
111                                 (it2 < levels_plain.end() && !(*it2).empty())
112                                 ? *it2 : *it;
113                         // Now we need to validate that all characters in
114                         // the sorting part are representable in the current
115                         // encoding. If not try the LaTeX macro which might
116                         // or might not be a good choice, and issue a warning.
117                         docstring spart2;
118                         for (size_t n = 0; n < spart.size(); ++n) {
119                                 try {
120                                         spart2 += runparams.encoding->latexChar(spart[n]);
121                                 } catch (EncodingException & /* e */) {
122                                         LYXERR0("Uncodable character in index entry. Sorting might be wrong!");
123                                 }
124                         }
125                         if (spart != spart2 && !runparams.dryrun) {
126                                 // FIXME: warning should be passed to the error dialog
127                                 frontend::Alert::warning(_("Index sorting failed"),
128                                 bformat(_("LyX's automatic index sorting algorithm faced\n"
129                                   "problems with the entry '%1$s'.\n"
130                                   "Please specify the sorting of this entry manually, as\n"
131                                   "explained in the User Guide."), spart));
132                         }
133                         // remove remaining \'s for the sorting part
134                         docstring const ppart =
135                                 subst(spart2, from_ascii("\\"), docstring());
136                         os << ppart;
137                         os << '@';
138                 }
139                 docstring const tpart = *it;
140                 os << tpart;
141                 if (it2 < levels_plain.end())
142                         ++it2;
143         }
144         // write the bit that followed "|"
145         if (!cmd.empty())
146                 os << "|" << cmd;
147         os << '}';
148         return i;
149 }
150
151
152 int InsetIndex::docbook(odocstream & os, OutputParams const & runparams) const
153 {
154         os << "<indexterm><primary>";
155         int const i = InsetText::docbook(os, runparams);
156         os << "</primary></indexterm>";
157         return i;
158 }
159
160
161 void InsetIndex::write(ostream & os) const
162 {
163         os << to_utf8(name()) << "\n";
164         InsetCollapsable::write(os);
165 }
166
167
168 void InsetIndex::textString(odocstream & os) const
169 {
170         os << text().asString(0, 1, AS_STR_LABEL | AS_STR_INSETS);
171 }
172
173
174 void InsetIndex::addToToc(DocIterator const & cpit)
175 {
176         DocIterator pit = cpit;
177         pit.push_back(CursorSlice(*this));
178         odocstringstream ods;
179         textString(ods);
180         buffer().tocBackend().toc("index").push_back(TocItem(pit, 0, ods.str()));
181         // Proceed with the rest of the inset.
182         InsetCollapsable::addToToc(cpit);
183 }
184
185
186 /////////////////////////////////////////////////////////////////////
187 //
188 // InsetPrintIndex
189 //
190 ///////////////////////////////////////////////////////////////////////
191
192 InsetPrintIndex::InsetPrintIndex(InsetCommandParams const & p)
193         : InsetCommand(p, string())
194 {}
195
196
197 ParamInfo const & InsetPrintIndex::findInfo(string const & /* cmdName */)
198 {
199         static ParamInfo param_info_;
200         if (param_info_.empty())
201                 param_info_.add("name", ParamInfo::LATEX_REQUIRED);
202         return param_info_;
203 }
204
205
206 docstring InsetPrintIndex::screenLabel() const
207 {
208         return _("Index");
209 }
210
211
212 void InsetPrintIndex::validate(LaTeXFeatures & features) const
213 {
214         features.require("makeidx");
215 }
216
217
218 InsetCode InsetPrintIndex::lyxCode() const
219 {
220         return INDEX_PRINT_CODE;
221 }
222
223 } // namespace lyx