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 void InsetIndexMacro::doDispatch(Cursor & cur, FuncRequest & cmd)
210 switch (cmd.action()) {
212 case LFUN_INSET_MODIFY: {
213 if (cmd.getArg(0) == "changetype") {
214 cur.recordUndoInset(this);
215 params_.type = insetindexmacrotranslator().find(cmd.getArg(1));
218 InsetCollapsible::doDispatch(cur, cmd);
223 InsetCollapsible::doDispatch(cur, cmd);
229 bool InsetIndexMacro::getStatus(Cursor & cur, FuncRequest const & cmd,
230 FuncStatus & flag) const
232 switch (cmd.action()) {
234 case LFUN_INSET_MODIFY:
235 if (cmd.getArg(0) == "changetype") {
236 docstring const newtype = from_utf8(cmd.getArg(1));
237 bool const enabled = (params_.type == InsetIndexMacroParams::See
238 || params_.type == InsetIndexMacroParams::Seealso)
239 && (newtype == "see" || newtype == "seealso");
240 flag.setEnabled(enabled);
242 newtype == from_ascii(insetindexmacrotranslator().find(params_.type)));
245 return InsetCollapsible::getStatus(cur, cmd, flag);
248 return InsetCollapsible::getStatus(cur, cmd, flag);
253 void InsetIndexMacro::processLatexSorting(otexstream & os, OutputParams const & runparams,
254 docstring const latex, docstring const plain) const
256 if (contains(latex, '\\') && !contains(latex, '@')) {
257 // Plaintext might return nothing (e.g. for ERTs).
258 // In that case, we use LaTeX.
259 docstring const spart = (plain.empty()) ? latex : plain;
260 // Now we need to validate that all characters in
261 // the sorting part are representable in the current
262 // encoding. If not try the LaTeX macro which might
263 // or might not be a good choice, and issue a warning.
264 pair<docstring, docstring> spart_latexed =
265 runparams.encoding->latexString(spart, runparams.dryrun);
266 if (!spart_latexed.second.empty())
267 LYXERR0("Uncodable character in index entry. Sorting might be wrong!");
268 if (spart != spart_latexed.first && !runparams.dryrun) {
270 ErrorList & errorList = buffer().errorList("Export");
271 docstring const s = bformat(_("LyX's automatic index sorting algorithm faced "
272 "problems with the sub-entry '%1$s'.\n"
273 "Please specify the sorting of this entry manually, as "
274 "explained in the User Guide."), spart);
275 Paragraph const & par = buffer().paragraphs().front();
276 errorList.push_back(ErrorItem(_("Index sorting failed"), s,
277 {par.id(), 0}, {par.id(), -1}));
278 buffer().bufferErrors(terr, errorList);
280 // Remove remaining \'s from the sort key
281 docstring ppart = subst(spart_latexed.first, from_ascii("\\"), docstring());
282 // Plain quotes need to be escaped, however (#10649), as this
283 // is the default escape character
284 ppart = subst(ppart, from_ascii("\""), from_ascii("\\\""));
286 // Now insert the sortkey, separated by '@'.
290 // Insert the actual level text
295 docstring InsetIndexMacro::toolTip(BufferView const &, int, int) const
297 return insetindexmacrotranslator_loc().find(params_.type);
301 string InsetIndexMacro::params2string(InsetIndexMacroParams const & params)
304 data << "IndexMacro" << ' ';
310 void InsetIndexMacro::string2params(string const & in, InsetIndexMacroParams & params)
312 params = InsetIndexMacroParams();
317 istringstream data(in);
320 lex.setContext("InsetIndexMacro::string2params");
321 lex >> "IndexMacro" >> "see";
327 bool InsetIndexMacro::hasSortKey() const
329 Paragraph const & par = paragraphs().front();
330 InsetList::const_iterator it = par.insetList().begin();
331 for (; it != par.insetList().end(); ++it) {
332 Inset & inset = *it->inset;
333 if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE)
340 void InsetIndexMacro::getSortkey(otexstream & os, OutputParams const & runparams) const
342 Paragraph const & par = paragraphs().front();
343 InsetList::const_iterator it = par.insetList().begin();
344 for (; it != par.insetList().end(); ++it) {
345 Inset & inset = *it->inset;
346 if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE) {
347 InsetIndexMacro const & iim =
348 static_cast<InsetIndexMacro const &>(inset);
349 iim.getLatex(os, runparams);
356 string InsetIndexMacro::contextMenuName() const
358 return "context-indexmacro";
362 string InsetIndexMacro::contextMenu(BufferView const & bv, int x, int y) const
364 // We override the implementation of InsetCollapsible,
365 // because we have eytra entries.
366 string owncm = "context-edit-index;";
367 return owncm + InsetCollapsible::contextMenu(bv, x, y);
371 bool InsetIndexMacro::insetAllowed(InsetCode code) const
376 case INDEXMACRO_SORTKEY_CODE:
377 return (params_.type == InsetIndexMacroParams::Subentry
380 return InsetCollapsible::insetAllowed(code);