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