]> git.lyx.org Git - features.git/blob - src/insets/InsetBox.cpp
'using namespace std' instead of 'using std::xxx'
[features.git] / src / insets / InsetBox.cpp
1 /**
2  * \file InsetBox.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 Martin Vermeer
8  * \author Jürgen Spitzmüller
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "InsetBox.h"
16
17 #include "Buffer.h"
18 #include "BufferView.h"
19 #include "Cursor.h"
20 #include "DispatchResult.h"
21 #include "support/debug.h"
22 #include "FuncStatus.h"
23 #include "FuncRequest.h"
24 #include "support/gettext.h"
25 #include "LaTeXFeatures.h"
26 #include "Lexer.h"
27 #include "MetricsInfo.h"
28
29 #include "support/Translator.h"
30
31 #include <sstream>
32
33 using namespace std;
34
35 namespace lyx {
36
37 namespace {
38
39 typedef Translator<std::string, InsetBox::BoxType> BoxTranslator;
40 typedef Translator<docstring, InsetBox::BoxType> BoxTranslatorLoc;
41
42 BoxTranslator const init_boxtranslator()
43 {
44         BoxTranslator translator("Boxed", InsetBox::Boxed);
45         translator.addPair("Frameless", InsetBox::Frameless);
46         translator.addPair("Framed", InsetBox::Framed);
47         translator.addPair("ovalbox", InsetBox::ovalbox);
48         translator.addPair("Ovalbox", InsetBox::Ovalbox);
49         translator.addPair("Shadowbox", InsetBox::Shadowbox);
50         translator.addPair("Shaded", InsetBox::Shaded);
51         translator.addPair("Doublebox",InsetBox::Doublebox);
52         return translator;
53 }
54
55
56 BoxTranslatorLoc const init_boxtranslator_loc()
57 {
58         BoxTranslatorLoc translator(_("simple frame"), InsetBox::Boxed);
59         translator.addPair(_("frameless"), InsetBox::Frameless);
60         translator.addPair(_("simple frame, page breaks"), InsetBox::Framed);
61         translator.addPair(_("oval, thin"), InsetBox::ovalbox);
62         translator.addPair(_("oval, thick"), InsetBox::Ovalbox);
63         translator.addPair(_("drop shadow"), InsetBox::Shadowbox);
64         translator.addPair(_("shaded background"), InsetBox::Shaded);
65         translator.addPair(_("double frame"), InsetBox::Doublebox);
66         return translator;
67 }
68
69
70 BoxTranslator const & boxtranslator()
71 {
72         static BoxTranslator translator = init_boxtranslator();
73         return translator;
74 }
75
76
77 BoxTranslatorLoc const & boxtranslator_loc()
78 {
79         static BoxTranslatorLoc translator = init_boxtranslator_loc();
80         return translator;
81 }
82
83 } // anon
84
85
86 InsetBox::InsetBox(BufferParams const & bp, string const & label)
87         : InsetCollapsable(bp), params_(label)
88 {}
89
90
91 InsetBox::InsetBox(InsetBox const & in)
92         : InsetCollapsable(in), params_(in.params_)
93 {}
94
95
96 InsetBox::~InsetBox()
97 {
98         InsetBoxMailer(*this).hideDialog();
99 }
100
101
102 Inset * InsetBox::clone() const
103 {
104         return new InsetBox(*this);
105 }
106
107
108 docstring const InsetBox::editMessage() const
109 {
110         return _("Opened Box Inset");
111 }
112
113
114 docstring InsetBox::name() const 
115 {
116         // FIXME: UNICODE
117         string name = string("Box");
118         if (boxtranslator().find(params_.type) == Shaded)
119                 name += string(":Shaded");
120         return from_ascii(name);
121 }
122
123
124 void InsetBox::write(Buffer const & buf, ostream & os) const
125 {
126         params_.write(os);
127         InsetCollapsable::write(buf, os);
128 }
129
130
131 void InsetBox::read(Buffer const & buf, Lexer & lex)
132 {
133         params_.read(lex);
134         InsetCollapsable::read(buf, lex);
135 }
136
137
138 void InsetBox::setButtonLabel()
139 {
140         BoxType btype = boxtranslator().find(params_.type);
141
142         docstring label;
143         label += _("Box");
144         label += " (";
145         if (btype == Frameless) {
146                 if (params_.use_parbox)
147                         label += _("Parbox");
148                 else
149                         label += _("Minipage");
150         } else
151                 label += boxtranslator_loc().find(btype);
152         label += ")";
153
154         setLabel(label);
155 }
156
157
158 bool InsetBox::hasFixedWidth() const
159 {
160       return params_.inner_box || params_.special != "width";
161 }
162
163
164 void InsetBox::metrics(MetricsInfo & m, Dimension & dim) const
165 {
166         // back up textwidth.
167         int textwidth_backup = m.base.textwidth;
168         if (hasFixedWidth())
169                 m.base.textwidth = params_.width.inPixels(m.base.textwidth);
170         InsetCollapsable::metrics(m, dim);
171         // retore textwidth.
172         m.base.textwidth = textwidth_backup;
173 }
174
175
176 bool InsetBox::forceDefaultParagraphs(idx_type) const
177 {
178         return !params_.inner_box;
179 }
180
181
182 bool InsetBox::showInsetDialog(BufferView * bv) const
183 {
184         InsetBoxMailer(const_cast<InsetBox &>(*this)).showDialog(bv);
185         return true;
186 }
187
188
189 void InsetBox::doDispatch(Cursor & cur, FuncRequest & cmd)
190 {
191         switch (cmd.action) {
192
193         case LFUN_INSET_MODIFY: {
194                 //lyxerr << "InsetBox::dispatch MODIFY" << endl;
195                 InsetBoxMailer::string2params(to_utf8(cmd.argument()), params_);
196                 setLayout(cur.buffer().params());
197                 break;
198         }
199
200         case LFUN_INSET_DIALOG_UPDATE:
201                 InsetBoxMailer(*this).updateDialog(&cur.bv());
202                 break;
203
204         case LFUN_MOUSE_RELEASE:
205                 if (cmd.button() == mouse_button::button3 && hitButton(cmd)) {
206                         InsetBoxMailer(*this).showDialog(&cur.bv());
207                         break;
208                 }
209                 InsetCollapsable::doDispatch(cur, cmd);
210                 break;
211
212         default:
213                 InsetCollapsable::doDispatch(cur, cmd);
214                 break;
215         }
216 }
217
218
219 bool InsetBox::getStatus(Cursor & cur, FuncRequest const & cmd,
220                 FuncStatus & flag) const
221 {
222         switch (cmd.action) {
223
224         case LFUN_INSET_MODIFY:
225         case LFUN_INSET_DIALOG_UPDATE:
226                 flag.enabled(true);
227                 return true;
228         case LFUN_BREAK_PARAGRAPH:
229                 if (params_.inner_box) {
230                         return InsetCollapsable::getStatus(cur, cmd, flag);
231                 } else {
232                         flag.enabled(false);
233                         return true;
234                 }
235
236         default:
237                 return InsetCollapsable::getStatus(cur, cmd, flag);
238         }
239 }
240
241
242 int InsetBox::latex(Buffer const & buf, odocstream & os,
243                     OutputParams const & runparams) const
244 {
245         BoxType btype = boxtranslator().find(params_.type);
246
247         string width_string = params_.width.asLatexString();
248         bool stdwidth(false);
249         if (params_.inner_box &&
250                         (width_string.find("1.0\\columnwidth") != string::npos
251                         || width_string.find("1.0\\textwidth") != string::npos)) {
252                 stdwidth = true;
253                 switch (btype) {
254                 case Frameless:
255                 case Framed:
256                         break;
257                 case Boxed:
258                 case Shaded:
259                         width_string += " - 2\\fboxsep - 2\\fboxrule";
260                         break;
261                 case ovalbox:
262                         width_string += " - 2\\fboxsep - 0.8pt";
263                         break;
264                 case Ovalbox:
265                         width_string += " - 2\\fboxsep - 1.6pt";
266                         break;
267                 case Shadowbox:
268                         // Shadow falls outside right margin... opinions?
269                         width_string += " - 2\\fboxsep - 2\\fboxrule"/* "-\\shadowsize"*/;
270                         break;
271                 case Doublebox:
272                         width_string += " - 2\\fboxsep - 7.5\\fboxrule - 1.0pt";
273                         break;
274                 }
275         }
276
277         int i = 0;
278         os << "%\n";
279         // Adapt to column/text width correctly also if paragraphs indented:
280         if (stdwidth)
281                 os << "\\noindent";
282
283         switch (btype) {
284         case Frameless:
285                 break;
286         case Framed:
287                 os << "\\begin{framed}%\n";
288                 i += 1;
289                 break;
290         case Boxed:
291                 os << "\\framebox";
292                 if (!params_.inner_box) {
293                         os << "{\\makebox";
294                         // Special widths, see usrguide §3.5
295                         // FIXME UNICODE
296                         if (params_.special != "none") {
297                                 os << "[" << params_.width.value()
298                                    << '\\' << from_utf8(params_.special)
299                                    << ']';
300                         } else
301                                 os << '[' << from_ascii(width_string)
302                                    << ']';
303                         if (params_.hor_pos != 'c')
304                                 os << "[" << params_.hor_pos << "]";
305                 }
306
307                 os << "{";
308                 break;
309         case ovalbox:
310                 os << "\\ovalbox{";
311                 break;
312         case Ovalbox:
313                 os << "\\Ovalbox{";
314                 break;
315         case Shadowbox:
316                 os << "\\shadowbox{";
317                 break;
318         case Shaded:
319                 // later
320                 break;
321         case Doublebox:
322                 os << "\\doublebox{";
323                 break;
324         }
325
326         if (params_.inner_box) {
327                 if (params_.use_parbox)
328                         os << "\\parbox";
329                 else
330                         os << "\\begin{minipage}";
331
332                 os << "[" << params_.pos << "]";
333                 if (params_.height_special == "none") {
334                         // FIXME UNICODE
335                         os << "[" << from_ascii(params_.height.asLatexString()) << "]";
336                 } else {
337                         // Special heights
338                         // set no optional argument when the value is the default "1\height"
339                         // (special units like \height are handled as "in")
340                         // but when the user has chosen a non-default inner_pos, the height
341                         // must be given: \minipage[pos][height][inner-pos]{width}
342                         if ((params_.height != Length("1in") ||
343                                  params_.height_special != "totalheight") ||
344                                 params_.inner_pos != params_.pos) {
345                                 // FIXME UNICODE
346                                 os << "[" << params_.height.value()
347                                         << "\\" << from_utf8(params_.height_special) << "]";
348                         }
349                 }
350                 if (params_.inner_pos != params_.pos)
351                         os << "[" << params_.inner_pos << "]";
352
353                 // FIXME UNICODE
354                 os << '{' << from_ascii(width_string) << '}';
355
356                 if (params_.use_parbox)
357                         os << "{";
358                 os << "%\n";
359                 i += 1;
360         }
361         if (btype == Shaded)
362                 os << "\\begin{shaded}%\n";
363                 i += 1;
364
365         i += InsetText::latex(buf, os, runparams);
366
367         if (btype == Shaded)
368                 os << "\\end{shaded}";
369
370         if (params_.inner_box) {
371                 if (params_.use_parbox)
372                         os << "%\n}";
373                 else
374                         os << "%\n\\end{minipage}";
375         }
376
377         switch (btype) {
378         case Frameless:
379                 break;
380         case Framed:
381                 os << "\\end{framed}";
382                 break;
383         case Boxed:
384                 if (!params_.inner_box)
385                         os << "}"; // for makebox
386                 os << "}";
387                 break;
388         case ovalbox:
389         case Ovalbox:
390         case Doublebox:
391         case Shadowbox:
392                 os << "}";
393                 break;
394         case Shaded:
395                 // already done
396                 break;
397         }
398         os << "%\n";
399
400         i += 3;
401
402         return i;
403 }
404
405
406 int InsetBox::plaintext(Buffer const & buf, odocstream & os,
407                         OutputParams const & runparams) const
408 {
409         BoxType const btype = boxtranslator().find(params_.type);
410
411         switch (btype) {
412                 case Frameless:
413                         break;
414                 case Framed:
415                 case Boxed:
416                         os << "[\n";
417                         break;
418                 case ovalbox:
419                         os << "(\n";
420                         break;
421                 case Ovalbox:
422                         os << "((\n";
423                         break;
424                 case Shadowbox:
425                 case Shaded:
426                         os << "[/\n";
427                         break;
428                 case Doublebox:
429                         os << "[[\n";
430                         break;
431         }
432
433         InsetText::plaintext(buf, os, runparams);
434
435         int len = 0;
436         switch (btype) {
437                 case Frameless:
438                         os << "\n";
439                         break;
440                 case Framed:
441                 case Boxed:
442                         os << "\n]";
443                         len = 1;
444                         break;
445                 case ovalbox:
446                         os << "\n)";
447                         len = 1;
448                         break;
449                 case Ovalbox:
450                         os << "\n))";
451                         len = 2;
452                         break;
453                 case Shadowbox:
454                 case Shaded:
455                         os << "\n/]";
456                         len = 2;
457                         break;
458                 case Doublebox:
459                         os << "\n]]";
460                         len = 2;
461                         break;
462         }
463
464         return PLAINTEXT_NEWLINE + len; // len chars on a separate line
465 }
466
467
468 int InsetBox::docbook(Buffer const & buf, odocstream & os,
469                       OutputParams const & runparams) const
470 {
471         return InsetText::docbook(buf, os, runparams);
472 }
473
474
475 void InsetBox::validate(LaTeXFeatures & features) const
476 {
477         BoxType btype = boxtranslator().find(params_.type);
478         switch (btype) {
479         case Frameless:
480                 break;
481         case Framed:
482                 features.require("framed");
483                 break;
484         case Boxed:
485                 features.require("calc");
486                 break;
487         case ovalbox:
488         case Ovalbox:
489         case Shadowbox:
490         case Doublebox:
491                 features.require("calc");
492                 features.require("fancybox");
493                 break;
494         case Shaded:
495                 features.require("color");
496                 features.require("framed");
497                 break;
498         }
499         InsetText::validate(features);
500 }
501
502
503 InsetBoxMailer::InsetBoxMailer(InsetBox & inset)
504         : inset_(inset)
505 {}
506
507
508 string const InsetBoxMailer::name_ = "box";
509
510
511 string const InsetBoxMailer::inset2string(Buffer const &) const
512 {
513         return params2string(inset_.params());
514 }
515
516
517 string const InsetBoxMailer::params2string(InsetBoxParams const & params)
518 {
519         ostringstream data;
520         data << "box" << ' ';
521         params.write(data);
522         return data.str();
523 }
524
525
526 void InsetBoxMailer::string2params(string const & in,
527                                    InsetBoxParams & params)
528 {
529         params = InsetBoxParams(string());
530         if (in.empty())
531                 return;
532
533         istringstream data(in);
534         Lexer lex(0,0);
535         lex.setStream(data);
536
537         string name;
538         lex >> name;
539         if (!lex || name != name_)
540                 return print_mailer_error("InsetBoxMailer", in, 1, name_);
541
542         // This is part of the inset proper that is usually swallowed
543         // by Text::readInset
544         string id;
545         lex >> id;
546         if (!lex || id != "Box")
547                 return print_mailer_error("InsetBoxMailer", in, 2, "Box");
548
549         params.read(lex);
550 }
551
552
553 InsetBoxParams::InsetBoxParams(string const & label)
554         : type(label),
555           use_parbox(false),
556           inner_box(true),
557           width(Length("100col%")),
558           special("none"),
559           pos('t'),
560           hor_pos('c'),
561           inner_pos('t'),
562           height(Length("1in")),
563           height_special("totalheight") // default is 1\\totalheight
564 {}
565
566
567 void InsetBoxParams::write(ostream & os) const
568 {
569         os << "Box " << type << "\n";
570         os << "position \"" << pos << "\"\n";
571         os << "hor_pos \"" << hor_pos << "\"\n";
572         os << "has_inner_box " << inner_box << "\n";
573         os << "inner_pos \"" << inner_pos << "\"\n";
574         os << "use_parbox " << use_parbox << "\n";
575         os << "width \"" << width.asString() << "\"\n";
576         os << "special \"" << special << "\"\n";
577         os << "height \"" << height.asString() << "\"\n";
578         os << "height_special \"" << height_special << "\"\n";
579 }
580
581
582 void InsetBoxParams::read(Lexer & lex)
583 {
584         if (!lex.isOK())
585                 return;
586
587         lex.next();
588         type = lex.getString();
589
590         if (!lex)
591                 return;
592
593         lex.next();
594         string token;
595         token = lex.getString();
596         if (!lex)
597                 return;
598         if (token == "position") {
599                 lex.next();
600                 // The [0] is needed. We need the first and only char in
601                 // this string -- MV
602                 pos = lex.getString()[0];
603         } else {
604                 lyxerr << "InsetBox::Read: Missing 'position'-tag!" << token << endl;
605                 lex.pushToken(token);
606         }
607
608         lex.next();
609         token = lex.getString();
610         if (!lex)
611                 return;
612         if (token == "hor_pos") {
613                 lex.next();
614                 hor_pos = lex.getString()[0];
615         } else {
616                 lyxerr << "InsetBox::Read: Missing 'hor_pos'-tag!" << token << endl;
617                 lex.pushToken(token);
618         }
619
620         lex.next();
621         token = lex.getString();
622         if (!lex)
623                 return;
624         if (token == "has_inner_box") {
625                 lex.next();
626                 inner_box = lex.getInteger();
627         } else {
628                 lyxerr << "InsetBox::Read: Missing 'has_inner_box'-tag!" << endl;
629                 lex.pushToken(token);
630         }
631
632         lex.next();
633         token = lex.getString();
634         if (!lex)
635                 return;
636         if (token == "inner_pos") {
637                 lex.next();
638                 inner_pos = lex.getString()[0];
639         } else {
640                 lyxerr << "InsetBox::Read: Missing 'inner_pos'-tag!"
641                         << token << endl;
642                 lex.pushToken(token);
643         }
644
645         lex.next();
646         token = lex.getString();
647         if (!lex)
648                 return;
649         if (token == "use_parbox") {
650                 lex.next();
651                 use_parbox = lex.getInteger();
652         } else {
653                 lyxerr << "InsetBox::Read: Missing 'use_parbox'-tag!" << endl;
654                 lex.pushToken(token);
655         }
656
657         lex.next();
658         token = lex.getString();
659         if (!lex)
660                 return;
661         if (token == "width") {
662                 lex.next();
663                 width = Length(lex.getString());
664         } else {
665                 lyxerr << "InsetBox::Read: Missing 'width'-tag!" << endl;
666                 lex.pushToken(token);
667         }
668
669         lex.next();
670         token = lex.getString();
671         if (!lex)
672                 return;
673         if (token == "special") {
674                 lex.next();
675                 special = lex.getString();
676         } else {
677                 lyxerr << "InsetBox::Read: Missing 'special'-tag!" << endl;
678                 lex.pushToken(token);
679         }
680
681         lex.next();
682         token = lex.getString();
683         if (!lex)
684                 return;
685         if (token == "height") {
686                 lex.next();
687                 height = Length(lex.getString());
688         } else {
689                 lyxerr << "InsetBox::Read: Missing 'height'-tag!" << endl;
690                 lex.pushToken(token);
691         }
692
693         lex.next();
694         token = lex.getString();
695         if (!lex)
696                 return;
697         if (token == "height_special") {
698                 lex.next();
699                 height_special = lex.getString();
700         } else {
701                 lyxerr << "InsetBox::Read: Missing 'height_special'-tag!" << endl;
702                 lex.pushToken(token);
703         }
704 }
705
706
707 } // namespace lyx