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