]> git.lyx.org Git - lyx.git/blob - src/insets/InsetArgument.cpp
Merge branch 'master' of git.lyx.org:lyx
[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 "InsetList.h"
22 #include "Language.h"
23 #include "Layout.h"
24 #include "Lexer.h"
25 #include "OutputParams.h"
26 #include "ParIterator.h"
27
28 #include "support/convert.h"
29 #include "support/debug.h"
30 #include "support/docstream.h"
31 #include "support/gettext.h"
32 #include "support/lstrings.h"
33
34 using namespace std;
35
36 namespace lyx {
37
38
39 InsetArgument::InsetArgument(Buffer * buf, string const & name)
40     : InsetCollapsable(buf), name_(name), labelstring_(docstring()),
41       font_(inherit_font), labelfont_(inherit_font), decoration_(string()),
42       pass_thru_(false), pass_thru_chars_(docstring())
43 {}
44
45
46 void InsetArgument::write(ostream & os) const
47 {
48         os << "Argument " << name_ << "\n";
49         InsetCollapsable::write(os);
50 }
51
52
53 void InsetArgument::read(Lexer & lex)
54 {
55         lex >> name_;
56         InsetCollapsable::read(lex);
57 }
58
59
60 void InsetArgument::updateBuffer(ParIterator const & it, UpdateType utype)
61 {
62         Layout::LaTeXArgMap args = it.paragraph().layout().args();
63         pass_thru_ = it.paragraph().layout().pass_thru;
64         bool const insetlayout = args.empty();
65         if (insetlayout) {
66                 args = it.inset().getLayout().args();
67                 pass_thru_ = it.inset().getLayout().isPassThru();
68         }
69
70         // Handle pre 2.1 ArgInsets (lyx2lyx cannot classify them)
71         if (name_ == "999") {
72                 unsigned int const req = insetlayout ? it.inset().getLayout().requiredArgs()
73                                       : it.paragraph().layout().requiredArgs();
74                 unsigned int const opts = insetlayout ? it.inset().getLayout().optArgs()
75                                       : it.paragraph().layout().optArgs();
76                 unsigned int nr = 0;
77                 unsigned int ours = 0;
78                 InsetList::const_iterator parit = it.paragraph().insetList().begin();
79                 InsetList::const_iterator parend = it.paragraph().insetList().end();
80                 for (; parit != parend; ++parit) {
81                         if (parit->inset->lyxCode() == ARG_CODE) {
82                                 ++nr;
83                                 if (parit->inset == this)
84                                         ours = nr;
85                         }
86                 }
87                 bool done = false;
88                 unsigned int realopts = 0;
89                 if (nr > req) {
90                         // We have optional arguments
91                         realopts = nr - req;
92                         if (ours <= realopts) {
93                                 name_ = convert<string>(ours);
94                                 done = true;
95                         }
96                 }
97                 if (!done) {
98                         // This is a mandatory argument. We have to consider
99                         // non-given optional arguments for the numbering
100                         int offset = opts - realopts;
101                         ours += offset;
102                         name_ = convert<string>(ours);
103                 }
104         }
105         Layout::LaTeXArgMap::const_iterator const lait = args.find(name_);
106         if (lait != args.end()) {
107                 docstring label = translateIfPossible((*lait).second.labelstring);
108                 docstring striplabel;
109                 support::rsplit(label, striplabel, '|');
110                 labelstring_ = striplabel.empty() ? label: striplabel;
111                 tooltip_ = translateIfPossible((*lait).second.tooltip);
112                 font_ = (*lait).second.font;
113                 labelfont_ = (*lait).second.labelfont;
114                 decoration_ = (*lait).second.decoration;
115                 pass_thru_chars_ = (*lait).second.pass_thru_chars;
116         } else {
117                 labelstring_ = _("Unknown Argument");
118                 tooltip_ = _("Argument not known in this Layout. Will be supressed in the output.");
119         }
120         setButtonLabel();
121         InsetCollapsable::updateBuffer(it, utype);
122 }
123
124
125 void InsetArgument::setButtonLabel()
126 {
127         setLabel(labelstring_);
128 }
129
130
131 docstring InsetArgument::toolTip(BufferView const & bv, int, int) const
132 {
133         if (isOpen(bv))
134                 return tooltip_;
135         return toolTipText(tooltip_ + from_ascii(":\n"));
136 }
137
138
139 void InsetArgument::doDispatch(Cursor & cur, FuncRequest & cmd)
140 {
141         switch (cmd.action()) {
142
143         case LFUN_INSET_MODIFY: {
144                 string const first_arg = cmd.getArg(0);
145                 bool const change_type = first_arg == "changetype";
146                 if (!change_type) {
147                         // not for us
148                         // this will not be handled higher up
149                         cur.undispatched();
150                         return;
151                 }
152                 cur.recordUndoInset(this);
153                 name_ = cmd.getArg(1);
154                 cur.forceBufferUpdate();
155                 break;
156         }
157
158         case LFUN_PASTE:
159         case LFUN_CLIPBOARD_PASTE:
160         case LFUN_SELECTION_PASTE:
161         case LFUN_PRIMARY_SELECTION_PASTE:
162                 // Do not call InsetCollapsable::doDispatch(cur, cmd)
163                 // with (inherited) pass_thru to avoid call for
164                 // fixParagraphsFont(), which does not play nicely with
165                 // inherited pass_thru (see #8471).
166                 // FIXME: Once we have implemented genuine pass_thru
167                 // option for InsetArgument (not inherited pass_thru),
168                 // we should probably directly call
169                 // InsetCollapsable::doDispatch(cur, cmd) for that
170                 // case as well
171                 if (pass_thru_)
172                         text().dispatch(cur, cmd);
173                 else
174                         InsetCollapsable::doDispatch(cur, cmd);
175                 break;
176
177         default:
178                 InsetCollapsable::doDispatch(cur, cmd);
179                 break;
180         }
181 }
182
183
184 bool InsetArgument::getStatus(Cursor & cur, FuncRequest const & cmd,
185                 FuncStatus & flag) const
186 {
187         switch (cmd.action()) {
188
189         case LFUN_INSET_MODIFY: {
190                 string const first_arg = cmd.getArg(0);
191                 if (first_arg == "changetype") {
192                         string const type = cmd.getArg(1);
193                         flag.setOnOff(type == name_);
194                         if (type == name_) {
195                                 flag.setEnabled(true);
196                                 return true;
197                         }
198                         Layout::LaTeXArgMap args;
199                         bool const insetlayout = cur.paragraph().layout().latexargs().empty();
200                         if (insetlayout)
201                                 args = cur.inset().getLayout().latexargs();
202                         else
203                                 args = cur.paragraph().layout().latexargs();
204                         Layout::LaTeXArgMap::const_iterator const lait = args.find(type);
205                         if (lait != args.end()) {
206                                 flag.setEnabled(true);
207                                 InsetList::const_iterator it = cur.paragraph().insetList().begin();
208                                 InsetList::const_iterator end = cur.paragraph().insetList().end();
209                                 for (; it != end; ++it) {
210                                         if (it->inset->lyxCode() == ARG_CODE) {
211                                                 InsetArgument const * ins =
212                                                         static_cast<InsetArgument const *>(it->inset);
213                                                 if (ins->name() == type) {
214                                                         // we have this already
215                                                         flag.setEnabled(false);
216                                                         return true;
217                                                 }
218                                         }
219                                 }
220                         } else
221                                 flag.setEnabled(false);
222                         return true;
223                 }
224                 return InsetCollapsable::getStatus(cur, cmd, flag);
225         }
226
227         default:
228                 return InsetCollapsable::getStatus(cur, cmd, flag);
229         }
230 }
231
232
233 string InsetArgument::contextMenuName() const
234 {
235         if (decoration() == InsetLayout::CONGLOMERATE)
236                 return "context-argument-conglomerate";
237         else
238                 return "context-argument";
239 }
240
241
242 FontInfo InsetArgument::getFont() const
243 {
244         if (font_ != inherit_font)
245                 return font_;
246         return getLayout().font();
247 }
248
249
250 FontInfo InsetArgument::getLabelfont() const
251 {
252         if (labelfont_ != inherit_font)
253                 return labelfont_;
254         return getLayout().labelfont();
255 }
256
257
258 InsetLayout::InsetDecoration InsetArgument::decoration() const
259 {
260         InsetLayout::InsetDecoration dec = getLayout().decoration();
261         if (!decoration_.empty())
262                 dec = translateDecoration(decoration_);
263         return dec == InsetLayout::DEFAULT ? InsetLayout::CLASSIC : dec;
264 }
265
266
267 void InsetArgument::latexArgument(otexstream & os,
268                 OutputParams const & runparams_in, docstring const & ldelim,
269                 docstring const & rdelim, docstring const & presetarg) const
270 {
271         TexRow texrow;
272         odocstringstream ss;
273         otexstream ots(ss, texrow);
274         OutputParams runparams = runparams_in;
275         if (!pass_thru_chars_.empty())
276                 runparams.pass_thru_chars += pass_thru_chars_;
277         InsetText::latex(ots, runparams);
278         docstring str = ss.str();
279         docstring const sep = str.empty() ? docstring() : from_ascii(", ");
280         if (!presetarg.empty())
281                 str = presetarg + sep + str;
282         if (ldelim != "{" && support::contains(str, rdelim))
283                 str = '{' + str + '}';
284         os << ldelim << str << rdelim;
285 }
286
287
288 } // namespace lyx