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