2 * \file InsetIndexMacro.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Jürgen Spitzmüller
8 * Full author contact details are available in file CREDITS.
13 #include "InsetIndexMacro.h"
16 #include "BufferParams.h"
18 #include "Dimension.h"
20 #include "ErrorList.h"
22 #include "FuncRequest.h"
23 #include "FuncStatus.h"
24 #include "InsetLayout.h"
25 #include "InsetList.h"
27 #include "LaTeXFeatures.h"
29 #include "MetricsInfo.h"
31 #include "texstream.h"
33 #include "frontends/alert.h"
35 #include "support/debug.h"
36 #include "support/docstream.h"
37 #include "support/gettext.h"
38 #include "support/lstrings.h"
39 #include "support/Translator.h"
42 using namespace lyx::support;
48 typedef Translator<string, InsetIndexMacroParams::Type> InsetIndexMacroTranslator;
49 typedef Translator<docstring, InsetIndexMacroParams::Type> InsetIndexMacroTranslatorLoc;
51 InsetIndexMacroTranslator const init_insetindexmacrotranslator()
53 InsetIndexMacroTranslator translator("see", InsetIndexMacroParams::See);
54 translator.addPair("seealso", InsetIndexMacroParams::Seealso);
55 translator.addPair("subentry", InsetIndexMacroParams::Subentry);
56 translator.addPair("sortkey", InsetIndexMacroParams::Sortkey);
61 InsetIndexMacroTranslatorLoc const init_insetindexmacrotranslator_loc()
63 InsetIndexMacroTranslatorLoc translator(_("See"), InsetIndexMacroParams::See);
64 translator.addPair(_("See also"), InsetIndexMacroParams::Seealso);
65 translator.addPair(_("Subentry"), InsetIndexMacroParams::Subentry);
66 translator.addPair(_("Sort as"), InsetIndexMacroParams::Sortkey);
71 InsetIndexMacroTranslator const & insetindexmacrotranslator()
73 static InsetIndexMacroTranslator const macrotranslator =
74 init_insetindexmacrotranslator();
75 return macrotranslator;
79 InsetIndexMacroTranslatorLoc const & insetindexmacrotranslator_loc()
81 static InsetIndexMacroTranslatorLoc const translator =
82 init_insetindexmacrotranslator_loc();
89 InsetIndexMacroParams::InsetIndexMacroParams()
94 void InsetIndexMacroParams::write(ostream & os) const
96 string const label = insetindexmacrotranslator().find(type);
97 os << "IndexMacro " << label << "\n";
101 void InsetIndexMacroParams::read(Lexer & lex)
106 type = insetindexmacrotranslator().find(label);
110 /////////////////////////////////////////////////////////////////////
114 /////////////////////////////////////////////////////////////////////
116 InsetIndexMacro::InsetIndexMacro(Buffer * buf, string const & label)
117 : InsetCollapsible(buf)
120 setFrameColor(Color_insetframe);
121 params_.type = insetindexmacrotranslator().find(label);
125 InsetIndexMacro::~InsetIndexMacro()
129 docstring InsetIndexMacro::layoutName() const
131 return from_ascii("IndexMacro:" + insetindexmacrotranslator().find(params_.type));
134 InsetCode InsetIndexMacro::lyxCode() const
136 return params_.type == InsetIndexMacroParams::Sortkey
137 ? INDEXMACRO_SORTKEY_CODE
142 void InsetIndexMacro::write(ostream & os) const
145 InsetCollapsible::write(os);
149 void InsetIndexMacro::read(Lexer & lex)
152 InsetCollapsible::read(lex);
156 void InsetIndexMacro::getLatex(otexstream & os, OutputParams const & runparams) const
158 if (params_.type == InsetIndexMacroParams::Subentry) {
160 getSortkey(os, runparams);
163 odocstringstream ourlatex;
164 otexstream ots(ourlatex);
165 InsetText::latex(ots, runparams);
166 odocstringstream ourplain;
167 InsetText::plaintext(ourplain, runparams);
168 // These are the LaTeX and plaintext representations
169 docstring latexstr = ourlatex.str();
170 docstring plainstr = ourplain.str();
171 processLatexSorting(os, runparams, latexstr, plainstr);
176 if (params_.type == InsetIndexMacroParams::See)
178 else if (params_.type == InsetIndexMacroParams::Seealso)
181 InsetCollapsible::latex(os, runparams);
183 if (params_.type == InsetIndexMacroParams::See
184 || params_.type == InsetIndexMacroParams::Seealso)
189 int InsetIndexMacro::getPlaintext(odocstringstream & os,
190 OutputParams const & runparams, size_t max_length) const
192 return InsetText::plaintext(os, runparams, max_length);
196 void InsetIndexMacro::getDocbook(XMLStream & xs, OutputParams const & runparams) const
198 InsetText::docbook(xs, runparams);
202 docstring InsetIndexMacro::getXhtml(XMLStream & xs, OutputParams const & runparams) const
204 return InsetText::xhtml(xs, runparams);
208 bool InsetIndexMacro::hasNoContent() const
210 return paragraphs().front().empty();
214 void InsetIndexMacro::doDispatch(Cursor & cur, FuncRequest & cmd)
216 switch (cmd.action()) {
218 case LFUN_INSET_MODIFY: {
219 if (cmd.getArg(0) == "changetype") {
220 cur.recordUndoInset(this);
221 params_.type = insetindexmacrotranslator().find(cmd.getArg(1));
224 InsetCollapsible::doDispatch(cur, cmd);
229 InsetCollapsible::doDispatch(cur, cmd);
235 bool InsetIndexMacro::getStatus(Cursor & cur, FuncRequest const & cmd,
236 FuncStatus & flag) const
238 switch (cmd.action()) {
240 case LFUN_INSET_MODIFY:
241 if (cmd.getArg(0) == "changetype") {
242 docstring const newtype = from_utf8(cmd.getArg(1));
243 bool const enabled = (params_.type == InsetIndexMacroParams::See
244 || params_.type == InsetIndexMacroParams::Seealso)
245 && (newtype == "see" || newtype == "seealso");
246 flag.setEnabled(enabled);
248 newtype == from_ascii(insetindexmacrotranslator().find(params_.type)));
251 return InsetCollapsible::getStatus(cur, cmd, flag);
254 return InsetCollapsible::getStatus(cur, cmd, flag);
259 void InsetIndexMacro::processLatexSorting(otexstream & os, OutputParams const & runparams,
260 docstring const latex, docstring const plain) const
262 if (contains(latex, '\\') && !contains(latex, '@')) {
263 // Plaintext might return nothing (e.g. for ERTs).
264 // In that case, we use LaTeX.
265 docstring const spart = (plain.empty()) ? latex : plain;
266 // Now we need to validate that all characters in
267 // the sorting part are representable in the current
268 // encoding. If not try the LaTeX macro which might
269 // or might not be a good choice, and issue a warning.
270 pair<docstring, docstring> spart_latexed =
271 runparams.encoding->latexString(spart, runparams.dryrun);
272 if (!spart_latexed.second.empty())
273 LYXERR0("Uncodable character in index entry. Sorting might be wrong!");
274 if (spart != spart_latexed.first && !runparams.dryrun) {
276 ErrorList & errorList = buffer().errorList("Export");
277 docstring const s = bformat(_("LyX's automatic index sorting algorithm faced "
278 "problems with the sub-entry '%1$s'.\n"
279 "Please specify the sorting of this entry manually, as "
280 "explained in the User Guide."), spart);
281 Paragraph const & par = buffer().paragraphs().front();
282 errorList.push_back(ErrorItem(_("Index sorting failed"), s,
283 {par.id(), 0}, {par.id(), -1}));
284 buffer().bufferErrors(terr, errorList);
286 // Remove remaining \'s from the sort key
287 docstring ppart = subst(spart_latexed.first, from_ascii("\\"), docstring());
288 // Plain quotes need to be escaped, however (#10649), as this
289 // is the default escape character
290 ppart = subst(ppart, from_ascii("\""), from_ascii("\\\""));
292 // Now insert the sortkey, separated by '@'.
296 // Insert the actual level text
301 docstring InsetIndexMacro::toolTip(BufferView const &, int, int) const
303 return insetindexmacrotranslator_loc().find(params_.type);
307 string InsetIndexMacro::params2string(InsetIndexMacroParams const & params)
310 data << "IndexMacro" << ' ';
316 void InsetIndexMacro::string2params(string const & in, InsetIndexMacroParams & params)
318 params = InsetIndexMacroParams();
323 istringstream data(in);
326 lex.setContext("InsetIndexMacro::string2params");
327 lex >> "IndexMacro" >> "see";
333 bool InsetIndexMacro::hasSortKey() const
335 Paragraph const & par = paragraphs().front();
336 InsetList::const_iterator it = par.insetList().begin();
337 for (; it != par.insetList().end(); ++it) {
338 Inset & inset = *it->inset;
339 if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE)
346 void InsetIndexMacro::getSortkey(otexstream & os, OutputParams const & runparams) const
348 Paragraph const & par = paragraphs().front();
349 InsetList::const_iterator it = par.insetList().begin();
350 for (; it != par.insetList().end(); ++it) {
351 Inset & inset = *it->inset;
352 if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE) {
353 InsetIndexMacro const & iim =
354 static_cast<InsetIndexMacro const &>(inset);
355 iim.getLatex(os, runparams);
362 string InsetIndexMacro::contextMenuName() const
364 return "context-indexmacro";
368 string InsetIndexMacro::contextMenu(BufferView const & bv, int x, int y) const
370 // We override the implementation of InsetCollapsible,
371 // because we have eytra entries.
372 string owncm = "context-edit-index;";
373 return owncm + InsetCollapsible::contextMenu(bv, x, y);
377 bool InsetIndexMacro::insetAllowed(InsetCode code) const
382 case INDEXMACRO_SORTKEY_CODE:
383 return (params_.type == InsetIndexMacroParams::Subentry
386 return InsetCollapsible::insetAllowed(code);