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