]> git.lyx.org Git - features.git/blob - src/insets/InsetNomencl.cpp
Add Nomenclature to the TOC.
[features.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 "LaTeXFeatures.h"
28 #include "Length.h"
29 #include "LyX.h"
30 #include "OutputParams.h"
31 #include "output_xhtml.h"
32 #include "sgml.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/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           nomenclature_entry_id(sgml::uniqueID(from_ascii("nomen")))
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::HANDLING_LATEXIFY);
67                 param_info_.add("description", ParamInfo::LATEX_REQUIRED,
68                                 ParamInfo::HANDLING_LATEXIFY);
69         }
70         return param_info_;
71 }
72
73
74 docstring InsetNomencl::screenLabel() const
75 {
76         size_t const maxLabelChars = 25;
77
78         docstring label = _("Nom: ") + getParam("symbol");
79         if (label.size() > maxLabelChars) {
80                 label.erase(maxLabelChars - 3);
81                 label += "...";
82         }
83         return label;
84 }
85
86
87 docstring InsetNomencl::toolTip(BufferView const & /*bv*/, int /*x*/, int /*y*/) const
88 {
89         docstring tip = _("Nomenclature Symbol: ") + getParam("symbol") + "\n";
90         tip += _("Description: ") + "\t"
91                 + subst(getParam("description"), from_ascii("\\\\"), from_ascii("\n\t"));
92         if (!getParam("prefix").empty())
93                 tip += "\n" + _("Sorting: ") + getParam("prefix");
94         return tip;
95 }
96
97
98
99 int InsetNomencl::docbook(odocstream & os, OutputParams const &) const
100 {
101         os << "<glossterm linkend=\"" << nomenclature_entry_id << "\">"
102            << sgml::escapeString(getParam("symbol"))
103            << "</glossterm>";
104         return 0;
105 }
106
107
108 docstring InsetNomencl::xhtml(XHTMLStream &, OutputParams const &) const
109 {
110         return docstring();
111 }
112
113
114 int InsetNomencl::docbookGlossary(odocstream & os) const
115 {
116         os << "<glossentry id=\"" << nomenclature_entry_id << "\">\n"
117            << "<glossterm>"
118            << sgml::escapeString(getParam("symbol"))
119            << "</glossterm>\n"
120            << "<glossdef><para>"
121            << sgml::escapeString(getParam("description"))
122            << "</para></glossdef>\n"
123            <<"</glossentry>\n";
124         return 4;
125 }
126
127
128 void InsetNomencl::validate(LaTeXFeatures & features) const
129 {
130         features.require("nomencl");
131 }
132
133
134 void InsetNomencl::addToToc(DocIterator const & cpit, bool output_active) const
135 {
136         docstring const str = getParam("symbol");
137         buffer().tocBackend().toc("nomencl").push_back(TocItem(cpit, 0, str, output_active));
138 }
139
140
141 /////////////////////////////////////////////////////////////////////
142 //
143 // InsetPrintNomencl
144 //
145 /////////////////////////////////////////////////////////////////////
146
147 InsetPrintNomencl::InsetPrintNomencl(Buffer * buf, InsetCommandParams const & p)
148         : InsetCommand(buf, p)
149 {}
150
151
152 ParamInfo const & InsetPrintNomencl::findInfo(string const & /* cmdName */)
153 {
154         // The symbol width is set via nomencl's \nomlabelwidth in 
155         // InsetPrintNomencl::latex and not as optional parameter of
156         // \printnomenclature
157         static ParamInfo param_info_;
158         if (param_info_.empty()) {
159                 // how is the width set?
160                 // values: none|auto|custom
161                 param_info_.add("set_width", ParamInfo::LYX_INTERNAL);
162                 // custom width
163                 param_info_.add("width", ParamInfo::LYX_INTERNAL);
164         }
165         return param_info_;
166 }
167
168
169 docstring InsetPrintNomencl::screenLabel() const
170 {
171         return _("Nomenclature");
172 }
173
174
175 void InsetPrintNomencl::doDispatch(Cursor & cur, FuncRequest & cmd)
176 {
177         switch (cmd.action()) {
178
179         case LFUN_INSET_MODIFY: {
180                 InsetCommandParams p(NOMENCL_PRINT_CODE);
181                 // FIXME UNICODE
182                 InsetCommand::string2params(to_utf8(cmd.argument()), p);
183                 if (p.getCmdName().empty()) {
184                         cur.noScreenUpdate();
185                         break;
186                 }
187
188                 cur.recordUndo();
189                 setParams(p);
190                 break;
191         }
192
193         default:
194                 InsetCommand::doDispatch(cur, cmd);
195                 break;
196         }
197 }
198
199
200 bool InsetPrintNomencl::getStatus(Cursor & cur, FuncRequest const & cmd,
201         FuncStatus & status) const
202 {
203         switch (cmd.action()) {
204
205         case LFUN_INSET_DIALOG_UPDATE:
206         case LFUN_INSET_MODIFY:
207                 status.setEnabled(true);
208                 return true;
209
210         default:
211                 return InsetCommand::getStatus(cur, cmd, status);
212         }
213 }
214
215
216 docstring InsetPrintNomencl::xhtml(XHTMLStream &, OutputParams const &) const
217 {
218         return docstring();
219 }
220
221
222 // FIXME This should be changed to use the TOC. Perhaps
223 // that could be done when XHTML output is added.
224 int InsetPrintNomencl::docbook(odocstream & os, OutputParams const &) const
225 {
226         os << "<glossary>\n";
227         int newlines = 2;
228         InsetIterator it = inset_iterator_begin(buffer().inset());
229         while (it) {
230                 if (it->lyxCode() == NOMENCL_CODE) {
231                         newlines += static_cast<InsetNomencl const &>(*it).docbookGlossary(os);
232                         ++it;
233                 } else if (!it->producesOutput()) {
234                         // Ignore contents of insets that are not in output
235                         size_t const depth = it.depth();
236                         ++it;
237                         while (it.depth() > depth)
238                                 ++it;
239                 } else {
240                         ++it;
241                 }
242         }
243         os << "</glossary>\n";
244         return newlines;
245 }
246
247
248 namespace {
249 docstring nomenclWidest(Buffer const & buffer, OutputParams const & runparams)
250 {
251         // nomenclWidest() determines and returns the widest used
252         // nomenclature symbol in the document
253
254         int w = 0;
255         docstring symb;
256         InsetNomencl const * nomencl = 0;
257         ParagraphList::const_iterator it = buffer.paragraphs().begin();
258         ParagraphList::const_iterator end = buffer.paragraphs().end();
259
260         for (; it != end; ++it) {
261                 if (it->insetList().empty())
262                         continue;
263                 InsetList::const_iterator iit = it->insetList().begin();
264                 InsetList::const_iterator eend = it->insetList().end();
265                 for (; iit != eend; ++iit) {
266                         Inset * inset = iit->inset;
267                         if (inset->lyxCode() != NOMENCL_CODE)
268                                 continue;
269                         nomencl = static_cast<InsetNomencl const *>(inset);
270                         docstring const symbol =
271                                 nomencl->getParam("symbol");
272                         // This is only an approximation,
273                         // but the best we can get.
274                         int const wx = use_gui ?
275                                 theFontMetrics(Font()).width(symbol) :
276                                 symbol.size();
277                         if (wx > w) {
278                                 w = wx;
279                                 symb = symbol;
280                         }
281                 }
282         }
283         // return the widest (or an empty) string
284         if (symb.empty())
285                 return symb;
286
287         // we have to encode the string properly
288         pair<docstring, docstring> latex_symb =
289                 runparams.encoding->latexString(symb, runparams.dryrun);
290         if (!latex_symb.second.empty())
291                 LYXERR0("Omitting uncodable characters '"
292                         << latex_symb.second
293                         << "' in nomencl widest string!");
294         return latex_symb.first;
295 }
296 } // namespace anon
297
298
299 void InsetPrintNomencl::latex(otexstream & os, OutputParams const & runparams_in) const
300 {
301         OutputParams runparams = runparams_in;
302         if (getParam("set_width") == "auto") {
303                 docstring widest = nomenclWidest(buffer(), runparams);
304                 // Set the label width via nomencl's command \nomlabelwidth.
305                 // This must be output before the command \printnomenclature
306                 if (!widest.empty()) {
307                         os << "\\settowidth{\\nomlabelwidth}{"
308                            << widest
309                            << "}\n";
310                 }
311         } else if (getParam("set_width") == "custom") {
312                 // custom length as optional arg of \printnomenclature
313                 string const width =
314                         Length(to_ascii(getParam("width"))).asLatexString();
315                 os << '\\'
316                    << from_ascii(getCmdName())
317                    << '['
318                    << from_ascii(width)
319                    << "]{}";
320                 return;
321         }
322         // output the command \printnomenclature
323         os << getCommand(runparams);
324 }
325
326
327 void InsetPrintNomencl::validate(LaTeXFeatures & features) const
328 {
329         features.require("nomencl");
330 }
331
332
333 InsetCode InsetPrintNomencl::lyxCode() const
334 {
335         return NOMENCL_PRINT_CODE;
336 }
337
338
339 string InsetPrintNomencl::contextMenuName() const
340 {
341         return "context-nomenclprint";
342 }
343
344
345 } // namespace lyx