]> git.lyx.org Git - lyx.git/blob - src/insets/InsetNomencl.cpp
Remove profiling.py
[lyx.git] / src / insets / InsetNomencl.cpp
1 /**
2  * \file InsetNomencl.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  * \author O. U. Baran
8  * \author Uwe Stöhr
9  * \author Jürgen Spitzmüller
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13 #include <config.h>
14
15 #include "InsetNomencl.h"
16 #include "InsetNote.h"
17
18 #include "Buffer.h"
19 #include "Cursor.h"
20 #include "DispatchResult.h"
21 #include "Font.h"
22 #include "Encoding.h"
23 #include "FuncRequest.h"
24 #include "FuncStatus.h"
25 #include "InsetLayout.h"
26 #include "InsetList.h"
27 #include "Language.h"
28 #include "LaTeXFeatures.h"
29 #include "LyX.h"
30 #include "xml.h"
31 #include "texstream.h"
32 #include "TocBackend.h"
33
34 #include "frontends/FontMetrics.h"
35
36 #include "support/debug.h"
37 #include "support/docstream.h"
38 #include "support/gettext.h"
39 #include "support/Length.h"
40 #include "support/lstrings.h"
41
42 using namespace std;
43 using namespace lyx::support;
44
45 namespace lyx {
46
47
48 /////////////////////////////////////////////////////////////////////
49 //
50 // InsetNomencl
51 //
52 /////////////////////////////////////////////////////////////////////
53
54 InsetNomencl::InsetNomencl(Buffer * buf, InsetCommandParams const & p)
55         : InsetCommand(buf, p)
56 {}
57
58
59 ParamInfo const & InsetNomencl::findInfo(string const & /* cmdName */)
60 {
61         static ParamInfo param_info_;
62         if (param_info_.empty()) {
63                 param_info_.add("prefix", ParamInfo::LATEX_OPTIONAL);
64                 param_info_.add("symbol", ParamInfo::LATEX_REQUIRED,
65                                 ParamInfo::ParamHandling(ParamInfo::HANDLING_LATEXIFY
66                                                          | ParamInfo::HANDLING_INDEX_ESCAPE));
67                 param_info_.add("description", ParamInfo::LATEX_REQUIRED,
68                                 ParamInfo::ParamHandling(ParamInfo::HANDLING_LATEXIFY
69                                                          | ParamInfo::HANDLING_INDEX_ESCAPE));
70                 param_info_.add("literal", ParamInfo::LYX_INTERNAL);
71         }
72         return param_info_;
73 }
74
75
76 docstring InsetNomencl::screenLabel() const
77 {
78         size_t const maxLabelChars = 25;
79         docstring label = _("Nom: ") + getParam("symbol");
80         support::truncateWithEllipsis(label, maxLabelChars);
81         return label;
82 }
83
84
85 docstring InsetNomencl::toolTip(BufferView const & /*bv*/, int /*x*/, int /*y*/) const
86 {
87         docstring tip = _("Nomenclature Symbol: ") + getParam("symbol") + "\n";
88         tip += _("Description: ") + "\t"
89                 + subst(getParam("description"), from_ascii("\\\\"), from_ascii("\n\t"));
90         if (!getParam("prefix").empty())
91                 tip += "\n" + _("Sorting: ") + getParam("prefix");
92         return tip;
93 }
94
95
96 int InsetNomencl::plaintext(odocstringstream & os,
97         OutputParams const &, size_t) const
98 {
99         docstring s = "[" + getParam("symbol") + ": " + getParam("description") + "]";
100         os << s;
101         return s.size();
102 }
103
104
105 void InsetNomencl::docbook(XMLStream & xs, OutputParams const &) const
106 {
107         docstring attr = "linkend=\"" + xml::cleanID(from_ascii("nomen") + getParam("symbol")) + "\"";
108         xs << xml::StartTag("glossterm", attr);
109         xs << xml::escapeString(getParam("symbol"));
110         xs << xml::EndTag("glossterm");
111 }
112
113
114 docstring InsetNomencl::xhtml(XMLStream &, OutputParams const &) const
115 {
116         return docstring();
117 }
118
119
120 void InsetNomencl::validate(LaTeXFeatures & features) const
121 {
122         features.require("nomencl");
123         InsetCommand::validate(features);
124 }
125
126
127 void InsetNomencl::addToToc(DocIterator const & cpit, bool output_active,
128                                                         UpdateType, TocBackend & backend) const
129 {
130         docstring const str = getParam("symbol");
131         TocBuilder & b = backend.builder("nomencl");
132         b.pushItem(cpit, str, output_active);
133         b.pop();
134 }
135
136
137 /////////////////////////////////////////////////////////////////////
138 //
139 // InsetPrintNomencl
140 //
141 /////////////////////////////////////////////////////////////////////
142
143 InsetPrintNomencl::InsetPrintNomencl(Buffer * buf, InsetCommandParams const & p)
144         : InsetCommand(buf, p)
145 {}
146
147
148 ParamInfo const & InsetPrintNomencl::findInfo(string const & /* cmdName */)
149 {
150         // The symbol width is set via nomencl's \nomlabelwidth in
151         // InsetPrintNomencl::latex and not as optional parameter of
152         // \printnomenclature
153         static ParamInfo param_info_;
154         if (param_info_.empty()) {
155                 // how is the width set?
156                 // values: none|auto|custom
157                 param_info_.add("set_width", ParamInfo::LYX_INTERNAL);
158                 // custom width
159                 param_info_.add("width", ParamInfo::LYX_INTERNAL);
160         }
161         return param_info_;
162 }
163
164
165 docstring InsetPrintNomencl::screenLabel() const
166 {
167         return _("Nomenclature");
168 }
169
170
171 struct NomenclEntry {
172         NomenclEntry() : par(nullptr) {}
173         NomenclEntry(docstring s, docstring d, Paragraph const * p)
174           : symbol(s), desc(d), par(p)
175         {}
176
177         docstring symbol;
178         docstring desc;
179         Paragraph const * par;
180 };
181
182
183 typedef map<docstring, NomenclEntry > EntryMap;
184
185
186 docstring InsetPrintNomencl::xhtml(XMLStream &, OutputParams const & op) const
187 {
188         shared_ptr<Toc const> toc = buffer().tocBackend().toc("nomencl");
189
190         EntryMap entries;
191         Toc::const_iterator it = toc->begin();
192         Toc::const_iterator const en = toc->end();
193         for (; it != en; ++it) {
194                 DocIterator dit = it->dit();
195                 Paragraph const & par = dit.innerParagraph();
196                 Inset const * inset = par.getInset(dit.top().pos());
197                 if (!inset)
198                         return docstring();
199                 InsetCommand const * ic = inset->asInsetCommand();
200                 if (!ic)
201                         return docstring();
202
203                 // FIXME We need a link to the paragraph here, so we
204                 // need some kind of struct.
205                 docstring const symbol = ic->getParam("symbol");
206                 docstring const desc = ic->getParam("description");
207                 docstring const prefix = ic->getParam("prefix");
208                 docstring const sortas = prefix.empty() ? symbol : prefix;
209
210                 entries[sortas] = NomenclEntry(symbol, desc, &par);
211         }
212
213         if (entries.empty())
214                 return docstring();
215
216         // we'll use our own stream, because we are going to defer everything.
217         // that's how we deal with the fact that we're probably inside a standard
218         // paragraph, and we don't want to be.
219         odocstringstream ods;
220         XMLStream xs(ods);
221
222         InsetLayout const & il = getLayout();
223         string const & tag = il.htmltag();
224         docstring toclabel = translateIfPossible(from_ascii("Nomenclature"),
225                 getLocalOrDefaultLang(op)->lang());
226
227         xs << xml::StartTag("div", "class='nomencl'")
228            << xml::StartTag(tag, "class='nomencl'")
229                  << toclabel
230                  << xml::EndTag(tag)
231            << xml::CR()
232            << xml::StartTag("dl")
233            << xml::CR();
234
235         EntryMap::const_iterator eit = entries.begin();
236         EntryMap::const_iterator const een = entries.end();
237         for (; eit != een; ++eit) {
238                 NomenclEntry const & ne = eit->second;
239                 string const parid = ne.par->magicLabel();
240                 xs << xml::StartTag("dt")
241                    << xml::StartTag("a", "href='#" + parid + "' class='nomencl'")
242                    << ne.symbol
243                    << xml::EndTag("a")
244                    << xml::EndTag("dt")
245                    << xml::CR()
246                    << xml::StartTag("dd")
247                    << ne.desc
248                    << xml::EndTag("dd")
249                    << xml::CR();
250         }
251
252         xs << xml::EndTag("dl")
253            << xml::CR()
254            << xml::EndTag("div")
255            << xml::CR();
256
257         return ods.str();
258 }
259
260
261 void InsetPrintNomencl::doDispatch(Cursor & cur, FuncRequest & cmd)
262 {
263         switch (cmd.action()) {
264
265         case LFUN_INSET_MODIFY: {
266                 InsetCommandParams p(NOMENCL_PRINT_CODE);
267                 // FIXME UNICODE
268                 InsetCommand::string2params(to_utf8(cmd.argument()), p);
269                 if (p.getCmdName().empty()) {
270                         cur.noScreenUpdate();
271                         break;
272                 }
273
274                 cur.recordUndo();
275                 setParams(p);
276                 break;
277         }
278
279         default:
280                 InsetCommand::doDispatch(cur, cmd);
281                 break;
282         }
283 }
284
285
286 bool InsetPrintNomencl::getStatus(Cursor & cur, FuncRequest const & cmd,
287         FuncStatus & status) const
288 {
289         switch (cmd.action()) {
290
291         case LFUN_INSET_DIALOG_UPDATE:
292         case LFUN_INSET_MODIFY:
293                 status.setEnabled(true);
294                 return true;
295
296         default:
297                 return InsetCommand::getStatus(cur, cmd, status);
298         }
299 }
300
301
302 void InsetPrintNomencl::docbook(XMLStream & xs, OutputParams const & runparams) const
303 {
304         shared_ptr<Toc const> toc = buffer().tocBackend().toc("nomencl");
305
306         EntryMap entries;
307         Toc::const_iterator it = toc->begin();
308         Toc::const_iterator const en = toc->end();
309         for (; it != en; ++it) {
310                 DocIterator dit = it->dit();
311                 Paragraph const & par = dit.innerParagraph();
312                 Inset const * inset = par.getInset(dit.top().pos());
313                 if (!inset)
314                         return;
315                 InsetCommand const * ic = inset->asInsetCommand();
316                 if (!ic)
317                         return;
318
319                 // FIXME We need a link to the paragraph here, so we
320                 // need some kind of struct.
321                 docstring const symbol = ic->getParam("symbol");
322                 docstring const desc = ic->getParam("description");
323                 docstring const prefix = ic->getParam("prefix");
324                 docstring const sortas = prefix.empty() ? symbol : prefix;
325
326                 entries[sortas] = NomenclEntry(symbol, desc, &par);
327         }
328
329         if (entries.empty())
330                 return;
331
332         // As opposed to XHTML, no need to defer everything until the end of time, so write directly to xs.
333         // TODO: At least, that's what was done before...
334
335         docstring toclabel = translateIfPossible(from_ascii("Nomenclature"),
336                                                  getLocalOrDefaultLang(runparams)->lang());
337
338         xs << xml::StartTag("glossary");
339         xs << xml::CR();
340         xs << xml::StartTag("title");
341         xs << toclabel;
342         xs << xml::EndTag("title");
343         xs << xml::CR();
344
345         EntryMap::const_iterator eit = entries.begin();
346         EntryMap::const_iterator const een = entries.end();
347         for (; eit != een; ++eit) {
348                 NomenclEntry const & ne = eit->second;
349
350                 xs << xml::StartTag("glossentry", "xml:id=\"" + xml::cleanID(from_ascii("nomen") + ne.symbol) + "\"");
351                 xs << xml::CR();
352                 xs << xml::StartTag("glossterm");
353                 xs << ne.symbol;
354                 xs << xml::EndTag("glossterm");
355                 xs << xml::CR();
356                 xs << xml::StartTag("glossdef");
357                 xs << xml::CR();
358                 xs << xml::StartTag("para");
359                 xs << ne.desc;
360                 xs << xml::EndTag("para");
361                 xs << xml::CR();
362                 xs << xml::EndTag("glossdef");
363                 xs << xml::CR();
364                 xs << xml::EndTag("glossentry");
365                 xs << xml::CR();
366         }
367
368         xs << xml::EndTag("glossary");
369         xs << xml::CR();
370 }
371
372
373 namespace {
374 docstring nomenclWidest(Buffer const & buffer, OutputParams const & runparams)
375 {
376         // nomenclWidest() determines and returns the widest used
377         // nomenclature symbol in the document
378
379         int w = 0;
380         docstring symb;
381         InsetNomencl const * nomencl = nullptr;
382         ParagraphList::const_iterator it = buffer.paragraphs().begin();
383         ParagraphList::const_iterator end = buffer.paragraphs().end();
384
385         for (; it != end; ++it) {
386                 if (it->insetList().empty())
387                         continue;
388                 InsetList::const_iterator iit = it->insetList().begin();
389                 InsetList::const_iterator eend = it->insetList().end();
390                 for (; iit != eend; ++iit) {
391                         Inset * inset = iit->inset;
392                         if (inset->lyxCode() != NOMENCL_CODE)
393                                 continue;
394                         nomencl = static_cast<InsetNomencl const *>(inset);
395                         // Use proper formatting. We do not escape makeindex chars here
396                         docstring symbol = nomencl ?
397                                 nomencl->params().prepareCommand(runparams, nomencl->getParam("symbol"),
398                                                         ParamInfo::HANDLING_LATEXIFY)
399                                 : docstring();
400                         // strip out % characters which are used as escape in nomencl
401                         // but act as comment in our context here
402                         symbol = subst(symbol, from_ascii("%"), docstring());
403                         // This is only an approximation,
404                         // but the best we can get.
405                         int const wx = use_gui ?
406                                 theFontMetrics(Font()).width(symbol) :
407                                 symbol.size();
408                         if (wx > w) {
409                                 w = wx;
410                                 symb = symbol;
411                         }
412                 }
413         }
414         // return the widest (or an empty) string
415         return symb;
416 }
417 } // namespace
418
419
420 void InsetPrintNomencl::latex(otexstream & os, OutputParams const & runparams_in) const
421 {
422         OutputParams runparams = runparams_in;
423         if (getParam("set_width") == "auto") {
424                 docstring widest = nomenclWidest(buffer(), runparams);
425                 // Set the label width via nomencl's command \nomlabelwidth.
426                 // This must be output before the command \printnomenclature
427                 if (!widest.empty()) {
428                         os << "\\settowidth{\\nomlabelwidth}{"
429                            << widest
430                            << "}\n";
431                 }
432         } else if (getParam("set_width") == "custom") {
433                 // custom length as optional arg of \printnomenclature
434                 string const width =
435                         Length(to_ascii(getParam("width"))).asLatexString();
436                 os << '\\'
437                    << from_ascii(getCmdName())
438                    << '['
439                    << from_ascii(width)
440                    << "]"
441                    << termcmd;
442                 return;
443         }
444         // output the command \printnomenclature
445         os << getCommand(runparams);
446 }
447
448
449 void InsetPrintNomencl::validate(LaTeXFeatures & features) const
450 {
451         features.useInsetLayout(getLayout());
452         features.require("nomencl");
453 }
454
455
456 InsetCode InsetPrintNomencl::lyxCode() const
457 {
458         return NOMENCL_PRINT_CODE;
459 }
460
461
462 string InsetPrintNomencl::contextMenuName() const
463 {
464         return "context-nomenclprint";
465 }
466
467
468 } // namespace lyx