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);
162 InsetText::latex(os, runparams);
164 odocstringstream ourlatex;
165 otexstream ots(ourlatex);
166 InsetText::latex(ots, runparams);
167 odocstringstream ourplain;
168 InsetText::plaintext(ourplain, runparams);
169 // These are the LaTeX and plaintext representations
170 docstring latexstr = ourlatex.str();
171 docstring plainstr = ourplain.str();
172 processLatexSorting(os, runparams, latexstr, plainstr);
177 if (params_.type == InsetIndexMacroParams::See)
179 else if (params_.type == InsetIndexMacroParams::Seealso)
182 InsetCollapsible::latex(os, runparams);
184 if (params_.type == InsetIndexMacroParams::See
185 || params_.type == InsetIndexMacroParams::Seealso)
190 int InsetIndexMacro::getPlaintext(odocstringstream & os,
191 OutputParams const & runparams, size_t max_length) const
193 return InsetText::plaintext(os, runparams, max_length);
197 void InsetIndexMacro::getDocbook(XMLStream & xs, OutputParams const & runparams) const
199 InsetText::docbook(xs, runparams);
203 docstring InsetIndexMacro::getXhtml(XMLStream & xs, OutputParams const & runparams) const
205 return InsetText::xhtml(xs, runparams);
209 bool InsetIndexMacro::hasNoContent() const
211 return paragraphs().front().empty();
215 void InsetIndexMacro::doDispatch(Cursor & cur, FuncRequest & cmd)
217 switch (cmd.action()) {
219 case LFUN_INSET_MODIFY: {
220 if (cmd.getArg(0) == "changetype") {
221 cur.recordUndoInset(this);
222 params_.type = insetindexmacrotranslator().find(cmd.getArg(1));
225 InsetCollapsible::doDispatch(cur, cmd);
230 InsetCollapsible::doDispatch(cur, cmd);
236 bool InsetIndexMacro::getStatus(Cursor & cur, FuncRequest const & cmd,
237 FuncStatus & flag) const
239 switch (cmd.action()) {
241 case LFUN_INSET_MODIFY:
242 if (cmd.getArg(0) == "changetype") {
243 docstring const newtype = from_utf8(cmd.getArg(1));
244 bool const enabled = (params_.type == InsetIndexMacroParams::See
245 || params_.type == InsetIndexMacroParams::Seealso)
246 && (newtype == "see" || newtype == "seealso");
247 flag.setEnabled(enabled);
249 newtype == from_ascii(insetindexmacrotranslator().find(params_.type)));
252 return InsetCollapsible::getStatus(cur, cmd, flag);
255 return InsetCollapsible::getStatus(cur, cmd, flag);
260 void InsetIndexMacro::processLatexSorting(otexstream & os, OutputParams const & runparams,
261 docstring const latex, docstring const plain) const
263 if (contains(latex, '\\') && !contains(latex, '@')) {
264 // Plaintext might return nothing (e.g. for ERTs).
265 // In that case, we use LaTeX.
266 docstring const spart = (plain.empty()) ? latex : plain;
267 // Now we need to validate that all characters in
268 // the sorting part are representable in the current
269 // encoding. If not try the LaTeX macro which might
270 // or might not be a good choice, and issue a warning.
271 pair<docstring, docstring> spart_latexed =
272 runparams.encoding->latexString(spart, runparams.dryrun);
273 if (!spart_latexed.second.empty())
274 LYXERR0("Uncodable character in index entry. Sorting might be wrong!");
275 if (spart != spart_latexed.first && !runparams.dryrun) {
277 ErrorList & errorList = buffer().errorList("Export");
278 docstring const s = bformat(_("LyX's automatic index sorting algorithm faced "
279 "problems with the sub-entry '%1$s'.\n"
280 "Please specify the sorting of this entry manually, as "
281 "explained in the User Guide."), spart);
282 Paragraph const & par = buffer().paragraphs().front();
283 errorList.push_back(ErrorItem(_("Index sorting failed"), s,
284 {par.id(), 0}, {par.id(), -1}));
285 buffer().bufferErrors(terr, errorList);
287 // Remove remaining \'s from the sort key
288 docstring ppart = subst(spart_latexed.first, from_ascii("\\"), docstring());
289 // Plain quotes need to be escaped, however (#10649), as this
290 // is the default escape character
291 ppart = subst(ppart, from_ascii("\""), from_ascii("\\\""));
293 // Now insert the sortkey, separated by '@'.
297 // Insert the actual level text
302 docstring InsetIndexMacro::toolTip(BufferView const &, int, int) const
304 return insetindexmacrotranslator_loc().find(params_.type);
308 string InsetIndexMacro::params2string(InsetIndexMacroParams const & params)
311 data << "IndexMacro" << ' ';
317 void InsetIndexMacro::string2params(string const & in, InsetIndexMacroParams & params)
319 params = InsetIndexMacroParams();
324 istringstream data(in);
327 lex.setContext("InsetIndexMacro::string2params");
328 lex >> "IndexMacro" >> "see";
334 bool InsetIndexMacro::hasSortKey() const
336 Paragraph const & par = paragraphs().front();
337 InsetList::const_iterator it = par.insetList().begin();
338 for (; it != par.insetList().end(); ++it) {
339 Inset & inset = *it->inset;
340 if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE)
347 void InsetIndexMacro::getSortkey(otexstream & os, OutputParams const & runparams) const
349 Paragraph const & par = paragraphs().front();
350 InsetList::const_iterator it = par.insetList().begin();
351 for (; it != par.insetList().end(); ++it) {
352 Inset & inset = *it->inset;
353 if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE) {
354 InsetIndexMacro const & iim =
355 static_cast<InsetIndexMacro const &>(inset);
356 iim.getLatex(os, runparams);
363 string InsetIndexMacro::contextMenuName() const
365 return "context-indexmacro";
369 string InsetIndexMacro::contextMenu(BufferView const & bv, int x, int y) const
371 // We override the implementation of InsetCollapsible,
372 // because we have eytra entries.
373 string owncm = "context-edit-index;";
374 return owncm + InsetCollapsible::contextMenu(bv, x, y);
378 bool InsetIndexMacro::insetAllowed(InsetCode code) const
383 case INDEXMACRO_SORTKEY_CODE:
384 return (params_.type == InsetIndexMacroParams::Subentry
387 return InsetCollapsible::insetAllowed(code);