]> git.lyx.org Git - lyx.git/blob - src/insets/InsetCommandParams.cpp
5a9ee9f7b95aa996d6b85e1ae98ef5bc0d64b06c
[lyx.git] / src / insets / InsetCommandParams.cpp
1 /**
2  * \file InsetCommandParams.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author Georg Baum
8  * \author Richard Heck
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "InsetCommandParams.h"
16
17 #include "InsetBibitem.h"
18 #include "InsetBibtex.h"
19 #include "InsetCitation.h"
20 #include "InsetFloatList.h"
21 #include "InsetHFill.h"
22 #include "InsetHyperlink.h"
23 #include "InsetInclude.h"
24 #include "InsetIndex.h"
25 #include "InsetLabel.h"
26 #include "InsetNomencl.h"
27 #include "InsetRef.h"
28 #include "InsetTOC.h"
29
30 #include "debug.h"
31 #include "gettext.h"
32 #include "Lexer.h"
33
34 #include "support/ExceptionMessage.h"
35 #include "support/lstrings.h"
36
37 #include <boost/assert.hpp>
38
39
40 namespace lyx {
41
42 using support::findToken;
43
44 using std::string;
45 using std::endl;
46 using std::ostream;
47
48 using support::ExceptionMessage;
49 using support::WarningException;
50
51 InsetCommandParams::InsetCommandParams(InsetCode code)
52         : insetCode_(code), preview_(false)
53 {
54         cmdName_ = getDefaultCmd(code);
55         info_ = findInfo(code, cmdName_);
56         BOOST_ASSERT(info_);
57         params_.resize(info_->n);
58 }
59
60
61 InsetCommandParams::InsetCommandParams(InsetCode code,
62         string const & cmdName)
63         : insetCode_(code), cmdName_(cmdName), preview_(false)
64 {
65         info_ = findInfo(code, cmdName);
66         BOOST_ASSERT(info_);
67         params_.resize(info_->n);
68 }
69
70
71 CommandInfo const * InsetCommandParams::findInfo(
72         InsetCode code, std::string const & cmdName)
73 {
74         switch (code) {
75         case BIBITEM_CODE:
76                 return InsetBibitem::findInfo(cmdName);
77         case BIBTEX_CODE:
78                 return InsetBibtex::findInfo(cmdName);
79         case CITE_CODE:
80                 return InsetCitation::findInfo(cmdName);        
81         case FLOAT_LIST_CODE:
82                 return InsetFloatList::findInfo(cmdName);
83         case HFILL_CODE:
84                 return InsetHFill::findInfo(cmdName);
85         case HYPERLINK_CODE:
86                 return InsetHyperlink::findInfo(cmdName);
87         case INCLUDE_CODE:
88                 return InsetInclude::findInfo(cmdName);
89         case INDEX_PRINT_CODE:
90                 return InsetPrintIndex::findInfo(cmdName);
91         case LABEL_CODE:
92                 return InsetLabel::findInfo(cmdName);   
93         case NOMENCL_CODE:
94                 return InsetNomencl::findInfo(cmdName);
95         case NOMENCL_PRINT_CODE:
96                 return InsetPrintNomencl::findInfo(cmdName);
97         case REF_CODE:
98                 return InsetRef::findInfo(cmdName);
99         case TOC_CODE:
100                 return InsetTOC::findInfo(cmdName);
101         default:
102                 BOOST_ASSERT(false);
103         }
104         return 0;
105 }
106
107
108 std::string InsetCommandParams::getDefaultCmd(InsetCode code) {
109         switch (code) {
110                 case BIBITEM_CODE: 
111                         return InsetBibitem::defaultCommand();
112                 case BIBTEX_CODE:
113                         return InsetBibtex::defaultCommand();
114                 case CITE_CODE:
115                         return InsetCitation::defaultCommand();
116                 case FLOAT_LIST_CODE:
117                         return InsetFloatList::defaultCommand();
118                 case HFILL_CODE:
119                         return InsetHFill::defaultCommand();
120                 case HYPERLINK_CODE:
121                         return InsetHyperlink::defaultCommand();
122                 case INCLUDE_CODE:
123                         return InsetInclude::defaultCommand();
124                 case INDEX_PRINT_CODE:
125                         return InsetPrintIndex::defaultCommand();
126                 case LABEL_CODE:
127                         return InsetLabel::defaultCommand();
128                 case NOMENCL_CODE:
129                         return InsetNomencl::defaultCommand();
130                 case NOMENCL_PRINT_CODE:
131                         return InsetPrintNomencl::defaultCommand();
132                 case REF_CODE:
133                         return InsetRef::defaultCommand();
134                 case TOC_CODE:
135                         return InsetTOC::defaultCommand();
136                 default:
137                         BOOST_ASSERT(false);
138         }
139         return string(); //silence the warning
140 }
141
142
143 bool InsetCommandParams::isCompatibleCommand(
144                 InsetCode code, std::string const & s)
145 {
146         switch (code) {
147                 case BIBITEM_CODE: 
148                         return InsetBibitem::isCompatibleCommand(s);
149                 case BIBTEX_CODE:
150                         return InsetBibtex::isCompatibleCommand(s);
151                 case CITE_CODE:
152                         return InsetCitation::isCompatibleCommand(s);
153                 case FLOAT_LIST_CODE:
154                         return InsetFloatList::isCompatibleCommand(s);
155                 case HFILL_CODE:
156                         return InsetHFill::isCompatibleCommand(s);
157                 case HYPERLINK_CODE:
158                         return InsetHyperlink::isCompatibleCommand(s);
159                 case INCLUDE_CODE:
160                         return InsetInclude::isCompatibleCommand(s);
161                 case INDEX_PRINT_CODE:
162                         return InsetPrintIndex::isCompatibleCommand(s);
163                 case LABEL_CODE:
164                         return InsetLabel::isCompatibleCommand(s);
165                 case NOMENCL_CODE:
166                         return InsetNomencl::isCompatibleCommand(s);
167                 case NOMENCL_PRINT_CODE:
168                         return InsetPrintNomencl::isCompatibleCommand(s);
169                 case REF_CODE:
170                         return InsetRef::isCompatibleCommand(s);
171                 case TOC_CODE:
172                         return InsetTOC::isCompatibleCommand(s);
173                 default:
174                         BOOST_ASSERT(false);
175         }
176         return false; //silence the warning
177 }
178
179
180 void InsetCommandParams::setCmdName(string const & name)
181 {
182         if (!isCompatibleCommand(insetCode_, cmdName_)){
183                 lyxerr << "InsetCommand: Incompatible command name " << 
184                                 name << "." << std::endl;
185                 throw ExceptionMessage(WarningException, _("InsetCommand Error: "),
186                                        from_utf8("Incompatible command name."));
187         }
188
189         cmdName_ = name;
190         CommandInfo const * const info = findInfo(insetCode_, cmdName_);
191         if (!info) {
192                 lyxerr << "Command '" << name << "' is not compatible with a '" <<
193                         insetType() << "' inset." << std::endl;
194                 return;
195         }
196         ParamVector params(info->n);
197         // Overtake parameters with the same name
198         for (size_t i = 0; i < info_->n; ++i) {
199                 int j = findToken(info->paramnames, info_->paramnames[i]);
200                 if (j >= 0)
201                         params[j] = params_[i];
202         }
203         info_ = info;
204         std::swap(params, params_);
205 }
206
207
208 void InsetCommandParams::read(Lexer & lex)
209 {
210         if (lex.isOK()) {
211                 lex.next();
212                 string const insetType = lex.getString();
213                 InsetCode const code = insetCode(insetType);
214                 if (code != insetCode_) {
215                         lex.printError("InsetCommand: Attempt to change type of parameters.");
216                         throw ExceptionMessage(WarningException, _("InsetCommand Error: "),
217                                 from_utf8("Attempt to change type of parameters."));
218                 }
219         }
220
221         if (lex.isOK()) {
222                 lex.next();
223                 string const test = lex.getString();
224                 if (test != "LatexCommand") {
225                         lex.printError("InsetCommand: no LatexCommand line found.");
226                         throw ExceptionMessage(WarningException, _("InsetCommand error:"),
227                                 from_utf8("Can't find LatexCommand line."));
228                 }
229         }
230         lex.next();
231         cmdName_ = lex.getString();
232         if (!isCompatibleCommand(insetCode_, cmdName_)){
233                 lex.printError("InsetCommand: Incompatible command name " + cmdName_ + ".");
234                 throw ExceptionMessage(WarningException, _("InsetCommand Error: "),
235                                        from_utf8("Incompatible command name."));
236         }
237
238         info_ = findInfo(insetCode_, cmdName_);
239         if (!info_) {
240                 lex.printError("InsetCommand: Unknown inset name `$$Token'");
241                 throw ExceptionMessage(WarningException,
242                         _("Unknown inset name: "), from_utf8(insetType()));
243         }
244         
245         string token;
246         while (lex.isOK()) {
247                 lex.next();
248                 token = lex.getString();
249                 if (token == "\\end_inset")
250                         break;
251                 if (token == "preview") {
252                         lex.next();
253                         preview_ = lex.getBool();
254                         continue;
255                 }
256                 int const i = findToken(info_->paramnames, token);
257                 if (i >= 0) {
258                         lex.next(true);
259                         params_[i] = lex.getDocString();
260                 } else {
261                         lex.printError("Unknown parameter name `$$Token' for command " + cmdName_);
262                         throw ExceptionMessage(WarningException,
263                                 _("Inset Command: ") + from_ascii(cmdName_),
264                                 _("Unknown parameter name: ") + from_utf8(token));
265                 }
266         }
267         if (token != "\\end_inset") {
268                 lex.printError("Missing \\end_inset at this point. "
269                                "Read: `$$Token'");
270                 throw ExceptionMessage(WarningException,
271                         _("Missing \\end_inset at this point."),
272                         from_utf8(token));
273         }
274 }
275
276
277 void InsetCommandParams::write(ostream & os) const
278 {
279         os << "CommandInset " << insetType() << '\n';
280         os << "LatexCommand " << cmdName_ << '\n';
281         if (preview_)
282                 os << "preview true\n";
283         for (size_t i = 0; i < info_->n; ++i)
284                 if (!params_[i].empty())
285                         // FIXME UNICODE
286                         os << info_->paramnames[i] << ' '
287                            << Lexer::quoteString(to_utf8(params_[i]))
288                            << '\n';
289 }
290
291
292 docstring const InsetCommandParams::getCommand() const
293 {
294         docstring s = '\\' + from_ascii(cmdName_);
295         bool noparam = true;
296         for (size_t i = 0; i < info_->n; ++i) {
297                 if (info_->optional[i]) {
298                         if (params_[i].empty()) {
299                                 // We need to write this parameter even if
300                                 // it is empty if nonempty optional parameters
301                                 // follow before the next required parameter.
302                                 for (size_t j = i + 1; j < info_->n; ++j) {
303                                         if (!info_->optional[j])
304                                                 break;
305                                         if (!params_[j].empty()) {
306                                                 s += "[]";
307                                                 noparam = false;
308                                                 break;
309                                         }
310                                 }
311                         } else {
312                                 s += '[' + params_[i] + ']';
313                                 noparam = false;
314                         }
315                 } else {
316                         s += '{' + params_[i] + '}';
317                         noparam = false;
318                 }
319         }
320         if (noparam)
321                 // Make sure that following stuff does not change the
322                 // command name.
323                 s += "{}";
324         return s;
325 }
326
327
328 docstring const InsetCommandParams::getFirstNonOptParam() const
329 {
330         for (size_t i = 0; i < info_->n; ++i)
331                 if (!info_->optional[i])
332                         return params_[i];
333         BOOST_ASSERT(false);
334         return docstring();
335 }
336
337
338 docstring const & InsetCommandParams::operator[](string const & name) const
339 {
340         int const i = findToken(info_->paramnames, name);
341         BOOST_ASSERT(i >= 0);
342         return params_[i];
343 }
344
345
346 docstring & InsetCommandParams::operator[](string const & name)
347 {
348         int const i = findToken(info_->paramnames, name);
349         BOOST_ASSERT(i >= 0);
350         return params_[i];
351 }
352
353
354 void InsetCommandParams::clear()
355 {
356         for (size_t i = 0; i < info_->n; ++i)
357                 params_[i].clear();
358 }
359
360
361 bool operator==(InsetCommandParams const & o1,
362                 InsetCommandParams const & o2)
363 {
364         return o1.insetCode_ == o2.insetCode_ &&
365                o1.cmdName_ == o2.cmdName_ &&
366                o1.info_ == o2.info_ &&
367                o1.params_ == o2.params_ &&
368                o1.preview_ == o2.preview_;
369 }
370
371
372 bool operator!=(InsetCommandParams const & o1,
373                 InsetCommandParams const & o2)
374 {
375         return !(o1 == o2);
376 }
377
378
379 } // namespace lyx