]> git.lyx.org Git - lyx.git/blob - src/insets/InsetCommandParams.cpp
Inset::addToToc(): change signature. Use DocIterator instead of ParConstIterator...
[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 #include <algorithm>
15
16 #include "InsetCommandParams.h"
17
18 #include "InsetBibitem.h"
19 #include "InsetBibtex.h"
20 #include "InsetCitation.h"
21 #include "InsetFloatList.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 "Lexer.h"
31
32 #include "support/debug.h"
33 #include "support/docstream.h"
34 #include "support/ExceptionMessage.h"
35 #include "support/gettext.h"
36 #include "support/lstrings.h"
37
38 #include "support/lassert.h"
39
40 using namespace std;
41 using namespace lyx::support;
42
43
44 namespace lyx {
45
46 /// Get information for \p code and command \p cmdName.
47 /// Returns 0 if the combination is not known.  [FIXME: 0?]
48 /// Don't call this without first making sure the command name is
49 /// acceptable to the inset.
50 static ParamInfo const & findInfo(InsetCode code, string const & cmdName)
51 {
52         switch (code) {
53         case BIBITEM_CODE:
54                 return InsetBibitem::findInfo(cmdName);
55         case BIBTEX_CODE:
56                 return InsetBibtex::findInfo(cmdName);
57         case CITE_CODE:
58                 return InsetCitation::findInfo(cmdName);        
59         case FLOAT_LIST_CODE:
60                 return InsetFloatList::findInfo(cmdName);
61         case HYPERLINK_CODE:
62                 return InsetHyperlink::findInfo(cmdName);
63         case INCLUDE_CODE:
64                 return InsetInclude::findInfo(cmdName);
65         case INDEX_PRINT_CODE:
66                 return InsetPrintIndex::findInfo(cmdName);
67         case LABEL_CODE:
68                 return InsetLabel::findInfo(cmdName);   
69         case NOMENCL_CODE:
70                 return InsetNomencl::findInfo(cmdName);
71         case NOMENCL_PRINT_CODE:
72                 return InsetPrintNomencl::findInfo(cmdName);
73         case REF_CODE:
74                 return InsetRef::findInfo(cmdName);
75         case TOC_CODE:
76                 return InsetTOC::findInfo(cmdName);
77         default:
78                 LASSERT(false, /**/);
79         }
80         static const ParamInfo pi;
81         return pi; // to silence the warning
82 }
83
84
85 /////////////////////////////////////////////////////////////////////
86 //
87 // ParamInfo::ParamData
88 //
89 /////////////////////////////////////////////////////////////////////
90
91 ParamInfo::ParamData::ParamData(std::string const & s, ParamType t)
92         : name_(s), type_(t)
93 {}
94
95
96 bool ParamInfo::ParamData::isOptional() const
97 {
98         return type_ == ParamInfo::LATEX_OPTIONAL;
99 }
100
101
102 bool ParamInfo::ParamData::operator==(ParamInfo::ParamData const & rhs) const
103 {
104         return name() == rhs.name() && type() == rhs.type();
105 }
106
107
108 bool ParamInfo::hasParam(std::string const & name) const
109 {
110         const_iterator it = begin();
111         const_iterator last = end();
112         for (; it != last; ++it) {
113                 if (it->name() == name)
114                         return true;
115         }
116         return false;
117 }
118
119
120 void ParamInfo::add(std::string const & name, ParamType type)
121
122         info_.push_back(ParamData(name, type)); 
123 }
124
125
126 bool ParamInfo::operator==(ParamInfo const & rhs) const
127 {
128         if (size() != rhs.size())
129                 return false;
130         return equal(begin(), end(), rhs.begin());
131 }
132
133
134 ParamInfo::ParamData const & 
135         ParamInfo::operator[](std::string const & name) const
136 {
137         LASSERT(hasParam(name), /**/);
138         const_iterator it = begin();
139         const_iterator last = end();
140         for (; it != last; ++it) {
141                 if (it->name() == name)
142                         return *it;
143         }
144         return *it; // silence warning
145 }
146
147
148 /////////////////////////////////////////////////////////////////////
149 //
150 // InsetCommandParams
151 //
152 /////////////////////////////////////////////////////////////////////
153
154
155 InsetCommandParams::InsetCommandParams(InsetCode code)
156         : insetCode_(code), preview_(false)
157 {
158         cmdName_ = getDefaultCmd(code);
159         info_ = findInfo(code, cmdName_);
160 }
161
162
163 InsetCommandParams::InsetCommandParams(InsetCode code,
164         string const & cmdName)
165         : insetCode_(code), cmdName_(cmdName), preview_(false)
166 {
167         info_ = findInfo(code, cmdName);
168 }
169
170
171 std::string InsetCommandParams::insetType() const
172 {
173         return insetName(insetCode_);
174 }
175
176
177 string InsetCommandParams::getDefaultCmd(InsetCode code)
178 {
179         switch (code) {
180                 case BIBITEM_CODE: 
181                         return InsetBibitem::defaultCommand();
182                 case BIBTEX_CODE:
183                         return InsetBibtex::defaultCommand();
184                 case CITE_CODE:
185                         return InsetCitation::defaultCommand();
186                 case FLOAT_LIST_CODE:
187                         return InsetFloatList::defaultCommand();
188                 case HYPERLINK_CODE:
189                         return InsetHyperlink::defaultCommand();
190                 case INCLUDE_CODE:
191                         return InsetInclude::defaultCommand();
192                 case INDEX_PRINT_CODE:
193                         return InsetPrintIndex::defaultCommand();
194                 case LABEL_CODE:
195                         return InsetLabel::defaultCommand();
196                 case NOMENCL_CODE:
197                         return InsetNomencl::defaultCommand();
198                 case NOMENCL_PRINT_CODE:
199                         return InsetPrintNomencl::defaultCommand();
200                 case REF_CODE:
201                         return InsetRef::defaultCommand();
202                 case TOC_CODE:
203                         return InsetTOC::defaultCommand();
204                 default:
205                         LASSERT(false, /**/);
206         }
207         return string(); // silence the warning
208 }
209
210
211 bool InsetCommandParams::isCompatibleCommand(InsetCode code, string const & s)
212 {
213         switch (code) {
214                 case BIBITEM_CODE: 
215                         return InsetBibitem::isCompatibleCommand(s);
216                 case BIBTEX_CODE:
217                         return InsetBibtex::isCompatibleCommand(s);
218                 case CITE_CODE:
219                         return InsetCitation::isCompatibleCommand(s);
220                 case FLOAT_LIST_CODE:
221                         return InsetFloatList::isCompatibleCommand(s);
222                 case HYPERLINK_CODE:
223                         return InsetHyperlink::isCompatibleCommand(s);
224                 case INCLUDE_CODE:
225                         return InsetInclude::isCompatibleCommand(s);
226                 case INDEX_PRINT_CODE:
227                         return InsetPrintIndex::isCompatibleCommand(s);
228                 case LABEL_CODE:
229                         return InsetLabel::isCompatibleCommand(s);
230                 case NOMENCL_CODE:
231                         return InsetNomencl::isCompatibleCommand(s);
232                 case NOMENCL_PRINT_CODE:
233                         return InsetPrintNomencl::isCompatibleCommand(s);
234                 case REF_CODE:
235                         return InsetRef::isCompatibleCommand(s);
236                 case TOC_CODE:
237                         return InsetTOC::isCompatibleCommand(s);
238                 default:
239                         LASSERT(false, /**/);
240         }
241         return false; // silence the warning
242 }
243
244
245 void InsetCommandParams::setCmdName(string const & name)
246 {
247         if (!isCompatibleCommand(insetCode_, cmdName_)) {
248                 LYXERR0("InsetCommand: Incompatible command name " << 
249                                 name << ".");
250                 throw ExceptionMessage(WarningException, _("InsetCommand Error: "),
251                                        _("Incompatible command name."));
252         }
253
254         cmdName_ = name;
255         info_ = findInfo(insetCode_, cmdName_);
256 }
257
258
259 void InsetCommandParams::read(Lexer & lex)
260 {
261         lex.setContext("InsetCommandParams::read");
262         lex >> insetName(insetCode_).c_str();
263         lex >> "LatexCommand";
264         lex >> cmdName_;
265         if (!isCompatibleCommand(insetCode_, cmdName_)) {
266                 lex.printError("Incompatible command name " + cmdName_ + ".");
267                 throw ExceptionMessage(WarningException, _("InsetCommandParams Error: "),
268                                        _("Incompatible command name."));
269         }
270
271         info_ = findInfo(insetCode_, cmdName_);
272         
273         string token;
274         while (lex.isOK()) {
275                 lex.next();
276                 token = lex.getString();
277                 if (token == "\\end_inset")
278                         break;
279                 if (token == "preview") {
280                         lex.next();
281                         preview_ = lex.getBool();
282                         continue;
283                 }
284                 if (info_.hasParam(token)) {
285                         lex.next(true);
286                         params_[token] = lex.getDocString();
287                 } else {
288                         lex.printError("Unknown parameter name `$$Token' for command " + cmdName_);
289                         throw ExceptionMessage(WarningException,
290                                 _("InsetCommandParams: ") + 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         ParamInfo::const_iterator it  = info_.begin();
311         ParamInfo::const_iterator end = info_.end();
312         for (; it != end; ++it) {
313                 std::string const & name = it->name();
314                 docstring const & data = (*this)[name];
315                 if (!data.empty()) {
316                         // FIXME UNICODE
317                         os << name << ' '
318                            << Lexer::quoteString(to_utf8(data))
319                            << '\n';
320                 }
321         }
322 }
323
324
325 bool InsetCommandParams::writeEmptyOptional(ParamInfo::const_iterator ci) const
326 {
327         if (!ci->isOptional())
328                 LASSERT(false, /**/);
329         ++ci; // we want to start with the next one
330         ParamInfo::const_iterator end = info_.end();
331         for (; ci != end; ++ci) {
332                 switch (ci->type()) {
333                 case ParamInfo::LYX_INTERNAL:
334                         break;
335
336                 case ParamInfo::LATEX_REQUIRED:
337                         return false;
338
339                 case ParamInfo::LATEX_OPTIONAL: {
340                         std::string const & name = ci->name();
341                         docstring const & data = (*this)[name];
342                         if (!data.empty())
343                                 return true;
344                         break;
345                 }
346
347                 } //end switch
348         }
349         return false;
350 }
351
352
353 docstring InsetCommandParams::getCommand() const
354 {
355         docstring s = '\\' + from_ascii(cmdName_);
356         bool noparam = true;
357         ParamInfo::const_iterator it  = info_.begin();
358         ParamInfo::const_iterator end = info_.end();
359         for (; it != end; ++it) {
360                 std::string const & name = it->name();
361                 switch (it->type()) {
362                 case ParamInfo::LYX_INTERNAL:
363                         break;
364
365                 case ParamInfo::LATEX_REQUIRED: {
366                         docstring const & data = (*this)[name];
367                         s += '{' + data + '}';
368                         noparam = false;
369                         break;
370                 }
371                 case ParamInfo::LATEX_OPTIONAL: {
372                         docstring const & data = (*this)[name];
373                         if (!data.empty()) {
374                                 s += '[' + data + ']';
375                                 noparam = false;
376                         } else if (writeEmptyOptional(it)) {
377                                         s += "[]";
378                                         noparam = false;
379                         }
380                         break;
381                 } 
382                 } //end switch
383         }
384         if (noparam)
385                 // Make sure that following stuff does not change the
386                 // command name.
387                 s += "{}";
388         return s;
389 }
390
391
392 docstring InsetCommandParams::getFirstNonOptParam() const
393 {
394         ParamInfo::const_iterator it = 
395                 find_if(info_.begin(), info_.end(), 
396                         not1(mem_fun_ref(&ParamInfo::ParamData::isOptional)));
397         if (it == info_.end())
398                 LASSERT(false, return docstring());
399         return (*this)[it->name()];
400 }
401
402
403 docstring const & InsetCommandParams::operator[](string const & name) const
404 {
405         static const docstring dummy; //so we don't return a ref to temporary
406         LASSERT(info_.hasParam(name), return dummy);
407         ParamMap::const_iterator data = params_.find(name);
408         if (data == params_.end() || data->second.empty())
409                 return dummy;
410         return data->second;
411 }
412
413
414 docstring & InsetCommandParams::operator[](string const & name)
415 {
416         LASSERT(info_.hasParam(name), /**/);
417         return params_[name];
418 }
419
420
421 void InsetCommandParams::clear()
422 {
423         params_.clear();
424 }
425
426
427 bool operator==(InsetCommandParams const & o1, InsetCommandParams const & o2)
428 {
429         return o1.insetCode_ == o2.insetCode_
430                 && o1.cmdName_ == o2.cmdName_
431                 && o1.info_ == o2.info_
432                 && o1.params_ == o2.params_
433                 && o1.preview_ == o2.preview_;
434 }
435
436
437 bool operator!=(InsetCommandParams const & o1, InsetCommandParams const & o2)
438 {
439         return !(o1 == o2);
440 }
441
442
443 } // namespace lyx