]> git.lyx.org Git - lyx.git/blob - src/insets/InsetArgument.cpp
Update format in lyxrc.dist
[lyx.git] / src / insets / InsetArgument.cpp
1 /**
2  * \file InsetArgument.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Martin Vermeer
7  * \author Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "InsetArgument.h"
15
16 #include "Buffer.h"
17 #include "BufferParams.h"
18 #include "Cursor.h"
19 #include "FuncStatus.h"
20 #include "FuncRequest.h"
21 #include "InsetLayout.h"
22 #include "InsetList.h"
23 #include "Language.h"
24 #include "Layout.h"
25 #include "ParIterator.h"
26 #include "TexRow.h"
27 #include "texstream.h"
28 #include "TocBackend.h"
29 #include "xml.h"
30
31 #include "support/convert.h"
32 #include "support/debug.h"
33 #include "support/docstream.h"
34 #include "support/gettext.h"
35 #include "support/Lexer.h"
36 #include "support/lstrings.h"
37
38 using namespace std;
39
40 namespace lyx {
41
42 using support::Lexer;
43
44 InsetArgument::InsetArgument(Buffer * buf, string const & name)
45     : InsetCollapsible(buf), name_(name), labelstring_(docstring()),
46       font_(inherit_font), labelfont_(inherit_font), decoration_(string()),
47       pass_thru_context_(false), pass_thru_local_(false), pass_thru_(false),
48       free_spacing_(false), pass_thru_chars_(docstring()), is_toc_caption_(false),
49       newline_cmd_(string())
50 {}
51
52
53 void InsetArgument::write(ostream & os) const
54 {
55         os << "Argument " << name_ << "\n";
56         InsetCollapsible::write(os);
57 }
58
59
60 void InsetArgument::read(Lexer & lex)
61 {
62         lex >> name_;
63         InsetCollapsible::read(lex);
64 }
65
66
67 void InsetArgument::init(Paragraph const & par)
68 {
69         Inset const & ininset = par.inInset();
70         bool const insetlayout = !par.layout().hasArgs();
71         Layout::LaTeXArgMap const args = insetlayout ?
72                 ininset.getLayout().args() : par.layout().args();
73         pass_thru_context_ = insetlayout ?
74                 ininset.getLayout().isPassThru() : par.layout().pass_thru;
75         // Record PassThru status in order to act on changes.
76         bool const former_pass_thru = pass_thru_;
77
78         // Handle pre 2.1 ArgInsets (lyx2lyx cannot classify them)
79         // "999" is the conventional name given to those by lyx2lyx
80         if (name_ == "999") {
81                 int const req = insetlayout ? ininset.getLayout().requiredArgs()
82                                       : par.layout().requiredArgs();
83                 int const opts = insetlayout ? ininset.getLayout().optArgs()
84                                       : par.layout().optArgs();
85                 int nr = 0;
86                 int ours = 0;
87                 for (InsetList::Element const & elt : par.insetList()) {
88                         if (elt.inset->lyxCode() == ARG_CODE) {
89                                 ++nr;
90                                 if (elt.inset == this)
91                                         ours = nr;
92                         }
93                 }
94                 bool done = false;
95                 int realopts = 0;
96                 if (nr > req) {
97                         // We have optional arguments
98                         realopts = nr - req;
99                         if (ours <= realopts) {
100                                 name_ = convert<string>(ours);
101                                 done = true;
102                         }
103                 }
104                 if (!done) {
105                         // This is a mandatory argument. We have to consider
106                         // non-given optional arguments for the numbering
107                         int offset = opts - realopts;
108                         ours += offset;
109                         name_ = convert<string>(ours);
110                 }
111         }
112         Layout::LaTeXArgMap::const_iterator const lait = args.find(name_);
113         caption_of_toc_ = string();
114         if (lait != args.end()) {
115                 docstring label = translateIfPossible((*lait).second.labelstring);
116                 docstring striplabel;
117                 support::rsplit(label, striplabel, '|');
118                 labelstring_ = striplabel.empty() ? label: striplabel;
119                 tooltip_ = translateIfPossible((*lait).second.tooltip);
120                 font_ = (*lait).second.font;
121                 labelfont_ = (*lait).second.labelfont;
122                 decoration_ = (*lait).second.decoration;
123                 pass_thru_chars_ = (*lait).second.pass_thru_chars;
124                 newline_cmd_ = (*lait).second.newlinecmd;
125                 free_spacing_ = (*lait).second.free_spacing;
126                 docbooktag_ = (*lait).second.docbooktag;
127                 docbooktagtype_ = (*lait).second.docbooktagtype;
128                 docbookattr_ = (*lait).second.docbookattr;
129                 docbookargumentbeforemaintag_ = (*lait).second.docbookargumentbeforemaintag;
130                 docbookargumentaftermaintag_ = (*lait).second.docbookargumentaftermaintag;
131                 pass_thru_local_ = false;
132                 if (lait->second.is_toc_caption) {
133                         is_toc_caption_ = true;
134                         // empty if AddToToc is not set
135                         caption_of_toc_ = insetlayout
136                                 ? ininset.getLayout().tocType()
137                                 : par.layout().tocType();
138                 }
139
140                 switch ((*lait).second.passthru) {
141                         case PT_INHERITED:
142                                 pass_thru_ = pass_thru_context_;
143                                 break;
144                         case PT_TRUE:
145                                 pass_thru_ = true;
146                                 pass_thru_local_ = true;
147                                 break;
148                         case PT_FALSE:
149                                 pass_thru_ = false;
150                                 break;
151                 }
152         } else {
153                 labelstring_ = _("Unknown Argument");
154                 tooltip_ = _("Argument not known in this Layout. Will be suppressed in the output.");
155         }
156
157         if (former_pass_thru != pass_thru_) {
158                 // PassThru status changed. We might need to update
159                 // the language of the contents
160                 // Language const * l  = insetlayout
161                 //      ? it.inset().buffer().language()
162                 //      : it.buffer()->language();
163                 Language const * l  = ininset.buffer().language();
164                 fixParagraphLanguage(l);
165         }
166
167         setButtonLabel();
168 }
169
170 void InsetArgument::updateBuffer(ParIterator const & it, UpdateType utype, bool const deleted)
171 {
172         init(it.paragraph());
173         InsetCollapsible::updateBuffer(it, utype, deleted);
174 }
175
176
177 void InsetArgument::setButtonLabel()
178 {
179         setLabel(labelstring_);
180 }
181
182
183 docstring InsetArgument::toolTip(BufferView const & bv, int, int) const
184 {
185         if (isOpen(bv))
186                 return tooltip_;
187         return toolTipText(tooltip_ + from_ascii(":\n"));
188 }
189
190
191 void InsetArgument::doDispatch(Cursor & cur, FuncRequest & cmd)
192 {
193         switch (cmd.action()) {
194
195         case LFUN_INSET_MODIFY: {
196                 string const first_arg = cmd.getArg(0);
197                 bool const change_type = first_arg == "changetype";
198                 if (!change_type) {
199                         // not for us
200                         // this will not be handled higher up
201                         cur.undispatched();
202                         return;
203                 }
204                 cur.recordUndoInset(this);
205                 name_ = cmd.getArg(1);
206                 cur.forceBufferUpdate();
207                 break;
208         }
209
210         case LFUN_PASTE:
211         case LFUN_CLIPBOARD_PASTE:
212         case LFUN_SELECTION_PASTE:
213         case LFUN_PRIMARY_SELECTION_PASTE:
214         case LFUN_SELF_INSERT:
215                 // With (only) inherited pass_thru, call Text::dispatch()
216                 // directly to avoid call for fixParagraphsFont() and/or
217                 // forcing to latex_language in InsetText::dispatch(),
218                 // since this does not play nicely with inherited pass_thru
219                 // (see #8471).
220                 if (pass_thru_ && !pass_thru_local_) {
221                         text().dispatch(cur, cmd);
222                         // For the paste operations, check if we have
223                         // non-latex_language, and if so, fix.
224                         if (cmd.action() != LFUN_SELF_INSERT)
225                                 fixParagraphLanguage(buffer().params().language);
226                 }
227                 else
228                         InsetCollapsible::doDispatch(cur, cmd);
229                 break;
230
231         default:
232                 InsetCollapsible::doDispatch(cur, cmd);
233                 break;
234         }
235 }
236
237
238 bool InsetArgument::getStatus(Cursor & cur, FuncRequest const & cmd,
239                 FuncStatus & flag) const
240 {
241         switch (cmd.action()) {
242
243         case LFUN_INSET_MODIFY: {
244                 string const first_arg = cmd.getArg(0);
245                 if (first_arg == "changetype") {
246                         string const type = cmd.getArg(1);
247                         flag.setOnOff(type == name_);
248                         if (type == name_) {
249                                 flag.setEnabled(true);
250                                 return true;
251                         }
252                         Layout::LaTeXArgMap args;
253                         bool const insetlayout = cur.paragraph().layout().latexargs().empty();
254                         if (insetlayout)
255                                 args = cur.inset().getLayout().latexargs();
256                         else
257                                 args = cur.paragraph().layout().latexargs();
258                         Layout::LaTeXArgMap::const_iterator const lait = args.find(type);
259                         if (lait != args.end()) {
260                                 flag.setEnabled(true);
261                                 for (auto const & table : cur.paragraph().insetList())
262                                         if (InsetArgument const * ins = table.inset->asInsetArgument())
263                                                 if (ins->name() == type) {
264                                                         // we have this already
265                                                         flag.setEnabled(false);
266                                                         return true;
267                                                 }
268                         } else
269                                 flag.setEnabled(false);
270                         return true;
271                 }
272                 return InsetCollapsible::getStatus(cur, cmd, flag);
273         }
274
275         default:
276                 return InsetCollapsible::getStatus(cur, cmd, flag);
277         }
278 }
279
280
281 string InsetArgument::contextMenuName() const
282 {
283         if (decoration() == InsetDecoration::CONGLOMERATE)
284                 return "context-argument-conglomerate";
285         else
286                 return "context-argument";
287 }
288
289
290 FontInfo InsetArgument::getFont() const
291 {
292         if (font_ != inherit_font)
293                 return font_;
294         return InsetCollapsible::getFont();
295 }
296
297
298 FontInfo InsetArgument::getLabelfont() const
299 {
300         if (labelfont_ != inherit_font)
301                 return labelfont_;
302         return InsetCollapsible::getLabelfont();
303 }
304
305
306 ColorCode InsetArgument::labelColor() const {
307         if (labelfont_.color() != Color_inherit)
308                 return labelfont_.color();
309         return InsetCollapsible::labelColor();
310 }
311
312
313 InsetDecoration InsetArgument::decoration() const
314 {
315         InsetDecoration dec = getLayout().decoration();
316         if (!decoration_.empty())
317                 dec = translateDecoration(decoration_);
318         return dec == InsetDecoration::DEFAULT ? InsetDecoration::CLASSIC : dec;
319 }
320
321
322 void InsetArgument::docbook(XMLStream & xs, OutputParams const & rp) const {
323         // Ignore arguments that have already been output or are planned to be output elsewhere.
324         if (rp.docbook_prepended_arguments.find(this) != rp.docbook_prepended_arguments.end())
325                 return;
326         if (rp.docbook_appended_arguments.find(this) != rp.docbook_appended_arguments.end())
327                 return;
328
329         if (docbooktag_ != from_ascii("NONE") && docbooktag_ != from_ascii("IGNORE")) {
330                 // TODO: implement docbooktagtype_.
331                 xs << xml::StartTag(docbooktag_, docbookattr_);
332                 InsetText::docbook(xs, rp);
333                 xs << xml::EndTag(docbooktag_);
334                 xs << xml::CR();
335         }
336 }
337
338
339 void InsetArgument::latexArgument(otexstream & os,
340                 OutputParams const & runparams_in, docstring const & ldelim,
341                 docstring const & rdelim, docstring const & presetarg) const
342 {
343         otexstringstream ots;
344         OutputParams runparams = runparams_in;
345         if (!pass_thru_chars_.empty())
346                 runparams.pass_thru_chars += pass_thru_chars_;
347         if (!newline_cmd_.empty())
348                 runparams.newlinecmd = newline_cmd_;
349         runparams.pass_thru = isPassThru();
350         InsetText::latex(ots, runparams);
351         TexString ts = ots.release();
352         bool const add_braces = !ldelim.empty() && ldelim != "{"
353                         && support::contains(ts.str, rdelim);
354         os << ldelim;
355         if (add_braces)
356                 os << '{';
357         os << presetarg;
358         if (!presetarg.empty() && !ts.str.empty())
359                 os << ", ";
360         os << std::move(ts);
361         if (add_braces)
362                 os << '}';
363         os << rdelim;
364 }
365
366
367 void InsetArgument::addToToc(DocIterator const & dit, bool output_active,
368                              UpdateType utype, TocBackend & backend) const
369 {
370         if (!caption_of_toc_.empty()) {
371                 docstring str;
372                 text().forOutliner(str, TOC_ENTRY_LENGTH);
373                 backend.builder(caption_of_toc_).argumentItem(str);
374         }
375         // Proceed with the rest of the inset.
376         InsetText::addToToc(dit, output_active, utype, backend);
377 }
378
379
380 void InsetArgument::fixParagraphLanguage(Language const * l)
381 {
382         Font font(inherit_font, l);
383         if (pass_thru_)
384                 font.setLanguage(latex_language);
385         paragraphs().front().resetFonts(font);
386 }
387
388
389 } // namespace lyx