]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
Make it compile when USE_BOOST_FORMAT is unset
[lyx.git] / src / insets / insetert.C
1 /**
2  * \file insetert.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Vigna
7  * \author Lars Gullik Bjønnes
8  *
9  * Full author contact details are available in file CREDITS
10  */
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include "insetert.h"
18 #include "insettext.h"
19
20 #include "buffer.h"
21 #include "BufferView.h"
22 #include "debug.h"
23 #include "funcrequest.h"
24 #include "gettext.h"
25 #include "language.h"
26 #include "lyxfont.h"
27 #include "lyxlex.h"
28 #include "lyxrow.h"
29 #include "lyxtext.h"
30 #include "WordLangTuple.h"
31
32 #include "frontends/Alert.h"
33 #include "frontends/Dialogs.h"
34 #include "frontends/LyXView.h"
35
36 #include "support/LOstream.h"
37
38
39 using std::ostream;
40 using std::min;
41 using std::endl;
42
43 using lyx::pos_type;
44
45
46 void InsetERT::init()
47 {
48         setButtonLabel();
49         labelfont = LyXFont(LyXFont::ALL_SANE);
50         labelfont.decSize();
51         labelfont.decSize();
52         labelfont.setColor(LColor::latex);
53         setInsetName("ERT");
54 }
55
56
57 InsetERT::InsetERT(BufferParams const & bp, bool collapsed)
58         : InsetCollapsable(bp, collapsed)
59 {
60         if (collapsed)
61                 status_ = Collapsed;
62         else
63                 status_ = Open;
64         init();
65 }
66
67
68 InsetERT::InsetERT(InsetERT const & in, bool same_id)
69         : InsetCollapsable(in, same_id), status_(in.status_)
70 {
71         init();
72 }
73
74
75 Inset * InsetERT::clone(Buffer const &, bool same_id) const
76 {
77         return new InsetERT(*const_cast<InsetERT *>(this), same_id);
78 }
79
80
81 InsetERT::InsetERT(BufferParams const & bp,
82                    Language const * l, string const & contents, bool collapsed)
83         : InsetCollapsable(bp, collapsed)
84 {
85         if (collapsed)
86                 status_ = Collapsed;
87         else
88                 status_ = Open;
89
90         LyXFont font(LyXFont::ALL_INHERIT, l);
91 #ifdef SET_HARD_FONT
92         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
93         font.setColor(LColor::latex);
94 #endif
95
96         string::const_iterator cit = contents.begin();
97         string::const_iterator end = contents.end();
98         pos_type pos = 0;
99         for (; cit != end; ++cit) {
100                 inset.paragraph()->insertChar(pos++, *cit, font);
101         }
102         // the init has to be after the initialization of the paragraph
103         // because of the label settings (draw_label for ert insets).
104         init();
105 }
106
107
108 InsetERT::~InsetERT()
109 {
110         hideDialog();
111 }
112
113
114 void InsetERT::read(Buffer const * buf, LyXLex & lex)
115 {
116         bool token_found = false;
117         if (lex.isOK()) {
118                 lex.next();
119                 string const token = lex.getString();
120                 if (token == "status") {
121                         lex.next();
122                         string const tmp_token = lex.getString();
123
124                         if (tmp_token == "Inlined") {
125                                 status(0, Inlined);
126                         } else if (tmp_token == "Collapsed") {
127                                 status(0, Collapsed);
128                         } else {
129                                 // leave this as default!
130                                 status(0, Open);
131                         }
132
133                         token_found = true;
134                 } else {
135                         lyxerr << "InsetERT::Read: Missing 'status'-tag!"
136                                    << endl;
137                         // take countermeasures
138                         lex.pushToken(token);
139                 }
140         }
141 #if 0
142 #warning this should be really short lived only for compatibility to
143 #warning files written 07/08/2001 so this has to go before 1.2.0! (Jug)
144         if (lex.isOK()) {
145                 lex.next();
146                 string const token = lex.getString();
147                 if (token == "collapsed") {
148                         lex.next();
149                         collapsed_ = lex.getBool();
150                 } else {
151                         // Take countermeasures
152                         lex.pushToken(token);
153                 }
154         }
155 #endif
156         inset.read(buf, lex);
157
158 #ifdef SET_HARD_FONT
159         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
160         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
161         font.setColor(LColor::latex);
162         Paragraph * par = inset.paragraph();
163         while (par) {
164                 pos_type siz = par->size();
165                 for (pos_type i = 0; i < siz; ++i) {
166                         par->setFont(i, font);
167                 }
168                 par = par->next();
169         }
170 #endif
171
172         if (!token_found) {
173                 if (collapsed_) {
174                         status(0, Collapsed);
175                 } else {
176                         status(0, Open);
177                 }
178         }
179         setButtonLabel();
180 }
181
182
183 void InsetERT::write(Buffer const * buf, ostream & os) const
184 {
185         string st;
186
187         switch (status_) {
188         case Open:
189                 st = "Open";
190                 break;
191         case Collapsed:
192                 st = "Collapsed";
193                 break;
194         case Inlined:
195                 st = "Inlined";
196                 break;
197         }
198
199         os << getInsetName() << "\n"
200            << "status "<< st << "\n";
201
202         //inset.writeParagraphData(buf, os);
203         string const layout(buf->params.getLyXTextClass().defaultLayoutName());
204         Paragraph * par = inset.paragraph();
205         while (par) {
206                 os << "\n\\layout " << layout << "\n";
207                 pos_type siz = par->size();
208                 for (pos_type i = 0; i < siz; ++i) {
209                         Paragraph::value_type c = par->getChar(i);
210                         switch (c) {
211                         case Paragraph::META_INSET:
212                         case Paragraph::META_HFILL:
213                                 lyxerr << "Element is not allowed in insertERT"
214                                        << endl;
215                         case Paragraph::META_NEWLINE:
216                                 os << "\n\\newline \n";
217                                 break;
218                         case '\\':
219                                 os << "\n\\backslash \n";
220                                 break;
221                         default:
222                                 os << c;
223                                 break;
224                         }
225                 }
226                 par = par->next();
227         }
228 }
229
230
231 string const InsetERT::editMessage() const
232 {
233         return _("Opened ERT Inset");
234 }
235
236
237 bool InsetERT::insertInset(BufferView *, Inset *)
238 {
239         return false;
240 }
241
242
243 void InsetERT::setFont(BufferView *, LyXFont const &, bool, bool selectall)
244 {
245         // if selectall is activated then the fontchange was an outside general
246         // fontchange and this messages is not needed
247         if (!selectall)
248                 Alert::alert(_("Impossible Operation!"),
249                            _("Not permitted to change font-types inside ERT-insets!"),
250                            _("Sorry."));
251 }
252
253
254 void InsetERT::updateStatus(BufferView * bv, bool swap) const
255 {
256         if (status_ != Inlined) {
257                 if (collapsed_) {
258                         status(bv, swap ? Open : Collapsed);
259                 } else {
260                         status(bv, swap ? Collapsed : Open);
261                 }
262         }
263 }
264
265 void InsetERT::edit(BufferView * bv, int x, int y, mouse_button::state button)
266 {
267         if (button == mouse_button::button3)
268                 return;
269
270         if (status_ == Inlined) {
271                 if (!bv->lockInset(this))
272                         return;
273                 inset.edit(bv, x, y, button);
274         } else {
275                 InsetCollapsable::edit(bv, x, y, button);
276         }
277         set_latex_font(bv);
278         updateStatus(bv);
279 }
280
281
282 Inset::EDITABLE InsetERT::editable() const
283 {
284         if (status_ == Collapsed)
285                 return IS_EDITABLE;
286         return HIGHLY_EDITABLE;
287 }
288
289
290 void InsetERT::edit(BufferView * bv, bool front)
291 {
292         InsetCollapsable::edit(bv, front);
293         updateStatus(0);
294         set_latex_font(bv);
295 }
296
297
298 void InsetERT::lfunMousePress(FuncRequest const & cmd)
299 {
300         if (status_ == Inlined)
301                 inset.localDispatch(cmd);
302         else
303                 InsetCollapsable::localDispatch(cmd);
304 }
305
306
307 bool InsetERT::lfunMouseRelease(FuncRequest const & cmd)
308 {
309         BufferView * bv = cmd.view();
310
311         if (cmd.button() == mouse_button::button3) {
312                 showInsetDialog(bv);
313                 return true;
314         }
315
316         if (status_ != Inlined && (cmd.x >= 0) && (cmd.x < button_length) &&
317             (cmd.y >= button_top_y) && (cmd.y <= button_bottom_y)) {
318                 updateStatus(bv, true);
319         } else {
320                 LyXFont font(LyXFont::ALL_SANE);
321                 FuncRequest cmd1 = cmd;
322                 cmd1.y = ascent(bv, font) + cmd.y - inset.ascent(bv, font);
323
324                 // inlined is special - the text appears above
325                 // button_bottom_y
326                 if (status_ == Inlined)
327                         inset.localDispatch(cmd1);
328                 else if (!collapsed_ && (cmd.y > button_bottom_y)) {
329                         cmd1.y -= ascent_collapsed() + descent_collapsed();
330                         inset.localDispatch(cmd1);
331                 }
332         }
333         return false;
334 }
335
336
337 void InsetERT::lfunMouseMotion(FuncRequest const & cmd)
338 {
339         if (status_ == Inlined)
340                 inset.localDispatch(cmd);
341         else
342                 InsetCollapsable::localDispatch(cmd);
343 }
344
345
346 int InsetERT::latex(Buffer const *, ostream & os, bool /*fragile*/,
347                     bool /*free_spc*/) const
348 {
349         Paragraph * par = inset.paragraph();
350         int lines = 0;
351         while (par) {
352                 pos_type siz = par->size();
353                 for (pos_type i = 0; i < siz; ++i) {
354                         Paragraph::value_type c = par->getChar(i);
355                         switch (c) {
356                         case Paragraph::META_NEWLINE:
357                                 os << '\n';
358                                 ++lines;
359                                 break;
360                         default:
361                                 os << c;
362                                 break;
363                         }
364                 }
365                 par = par->next();
366                 if (par) {
367                         os << "\n\n";
368                         lines += 2;
369                 }
370         }
371
372         return lines;
373 }
374
375
376 int InsetERT::ascii(Buffer const *, ostream &, int /*linelen*/) const
377 {
378         return 0;
379 }
380
381
382 int InsetERT::linuxdoc(Buffer const *, ostream & os) const
383 {
384         Paragraph * par = inset.paragraph();
385         int lines = 0;
386         while (par) {
387                 pos_type siz = par->size();
388                 for (pos_type i = 0; i < siz; ++i) {
389                         Paragraph::value_type c = par->getChar(i);
390                         switch (c) {
391                         case Paragraph::META_NEWLINE:
392                                 os << '\n';
393                                 ++lines;
394                                 break;
395                         default:
396                                 os << c;
397                                 break;
398                         }
399                 }
400                 par = par->next();
401                 if (par) {
402                         os << "\n";
403                         lines ++;
404                 }
405         }
406
407         return lines;
408 }
409
410
411 int InsetERT::docbook(Buffer const *, ostream & os, bool) const
412 {
413         Paragraph * par = inset.paragraph();
414         int lines = 0;
415         while (par) {
416                 pos_type siz = par->size();
417                 for (pos_type i = 0; i < siz; ++i) {
418                         Paragraph::value_type c = par->getChar(i);
419                         switch (c) {
420                         case Paragraph::META_NEWLINE:
421                                 os << '\n';
422                                 ++lines;
423                                 break;
424                         default:
425                                 os << c;
426                                 break;
427                         }
428                 }
429                 par = par->next();
430                 if (par) {
431                         os << "\n";
432                         lines ++;
433                 }
434         }
435
436         return lines;
437 }
438
439
440 Inset::RESULT InsetERT::localDispatch(FuncRequest const & cmd)
441 {
442         Inset::RESULT result = DISPATCHED_NOUPDATE;
443         BufferView * bv = cmd.view();
444
445         if (inset.paragraph()->empty()) {
446                 set_latex_font(bv);
447         }
448
449         switch (cmd.action) {
450                 case LFUN_MOUSE_PRESS:
451                         lfunMousePress(cmd);
452                         return DISPATCHED;
453
454                 case LFUN_MOUSE_MOTION:
455                         lfunMouseMotion(cmd);
456                         return DISPATCHED;
457
458                 case LFUN_MOUSE_RELEASE:
459                         lfunMouseRelease(cmd);
460                         return DISPATCHED;
461
462                 case LFUN_LAYOUT:
463                         bv->owner()->setLayout(inset.paragraph()->layout()->name());
464                         break;
465
466                 default:
467                         result = InsetCollapsable::localDispatch(cmd);
468         }
469
470         switch (cmd.action) {
471         case LFUN_BREAKPARAGRAPH:
472         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
473         case LFUN_BACKSPACE:
474         case LFUN_BACKSPACE_SKIP:
475         case LFUN_DELETE:
476         case LFUN_DELETE_SKIP:
477         case LFUN_DELETE_LINE_FORWARD:
478         case LFUN_CUT:
479                 set_latex_font(bv);
480                 break;
481
482         default:
483                 break;
484         }
485         return result;
486 }
487
488
489 string const InsetERT::get_new_label() const
490 {
491         string la;
492         pos_type const max_length = 15;
493         pos_type const p_siz = inset.paragraph()->size();
494         pos_type const n = min(max_length, p_siz);
495         int i = 0;
496         int j = 0;
497         for(; i < n && j < p_siz; ++j) {
498                 if (inset.paragraph()->isInset(j))
499                         continue;
500                 la += inset.paragraph()->getChar(j);
501                 ++i;
502         }
503         if (inset.paragraph()->next() || (i > 0 && j < p_siz)) {
504                 la += "...";
505         }
506         if (la.empty()) {
507                 la = _("ERT");
508         }
509         return la;
510 }
511
512
513 void InsetERT::setButtonLabel() const
514 {
515         if (status_ == Collapsed) {
516                 setLabel(get_new_label());
517         } else {
518                 setLabel(_("ERT"));
519         }
520 }
521
522
523 bool InsetERT::checkInsertChar(LyXFont & /* font */)
524 {
525 #ifdef SET_HARD_FONT
526         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
527         font = f;
528         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
529         font.setColor(LColor::latex);
530 #endif
531         return true;
532 }
533
534
535 int InsetERT::ascent(BufferView * bv, LyXFont const & font) const
536 {
537         if (!inlined())
538                 return InsetCollapsable::ascent(bv, font);
539
540         return inset.ascent(bv, font);
541 }
542
543
544 int InsetERT::descent(BufferView * bv, LyXFont const & font) const
545 {
546         if (!inlined())
547                 return InsetCollapsable::descent(bv, font);
548
549         return inset.descent(bv, font);
550 }
551
552
553 int InsetERT::width(BufferView * bv, LyXFont const & font) const
554 {
555         if (!inlined())
556                 return InsetCollapsable::width(bv, font);
557
558         return inset.width(bv, font);
559 }
560
561
562 void InsetERT::draw(BufferView * bv, LyXFont const & f,
563                     int baseline, float & x, bool cleared) const
564 {
565         Painter & pain = bv->painter();
566
567         button_length = width_collapsed();
568         button_top_y = -ascent(bv, f);
569         button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
570                 descent_collapsed();
571
572         if (!isOpen()) {
573                 draw_collapsed(pain, baseline, x);
574                 return;
575         }
576
577         float old_x = x;
578
579         if (!owner())
580                 x += static_cast<float>(scroll());
581
582         if (!cleared && (inset.need_update == InsetText::FULL ||
583                          inset.need_update == InsetText::INIT ||
584                          top_x != int(x) ||
585                          top_baseline != baseline))
586         {
587                 // we don't need anymore to clear here we just have to tell
588                 // the underlying LyXText that it should do the RowClear!
589                 inset.setUpdateStatus(bv, InsetText::FULL);
590                 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
591                 return;
592         }
593
594         top_x = int(x);
595         topx_set = true;
596         top_baseline = baseline;
597
598         int const bl = baseline - ascent(bv, f) + ascent_collapsed();
599
600         if (inlined()) {
601                 inset.draw(bv, f, baseline, x, cleared);
602         } else {
603                 draw_collapsed(pain, bl, old_x);
604                 inset.draw(bv, f,
605                                    bl + descent_collapsed() + inset.ascent(bv, f),
606                                    x, cleared);
607         }
608         need_update = NONE;
609 }
610
611
612 void InsetERT::set_latex_font(BufferView * /* bv */)
613 {
614 #ifdef SET_HARD_FONT
615         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
616
617         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
618         font.setColor(LColor::latex);
619
620         inset.getLyXText(bv)->setFont(bv, font, false);
621 #endif
622 }
623
624
625 // attention this function can be called with bv == 0
626 void InsetERT::status(BufferView * bv, ERTStatus const st) const
627 {
628         if (st != status_) {
629                 status_ = st;
630                 need_update = FULL;
631                 switch (st) {
632                 case Inlined:
633                         if (bv)
634                                 inset.setUpdateStatus(bv, InsetText::INIT);
635                         break;
636                 case Open:
637                         collapsed_ = false;
638                         setButtonLabel();
639                         break;
640                 case Collapsed:
641                         collapsed_ = true;
642                         setButtonLabel();
643                         if (bv)
644                                 bv->unlockInset(const_cast<InsetERT *>(this));
645                         break;
646                 }
647                 if (bv)
648                         bv->updateInset(const_cast<InsetERT *>(this), false);
649         }
650 }
651
652
653 bool InsetERT::showInsetDialog(BufferView * bv) const
654 {
655         bv->owner()->getDialogs().showERT(const_cast<InsetERT *>(this));
656         return true;
657 }
658
659
660 void InsetERT::open(BufferView * bv)
661 {
662         if (!collapsed_)
663                 return;
664         status(bv, Open);
665 }
666
667
668 void InsetERT::close(BufferView * bv) const
669 {
670         if (status_ == Collapsed || status_ == Inlined)
671                 return;
672
673         status(bv, Collapsed);
674 }
675
676
677 WordLangTuple const
678 InsetERT::selectNextWordToSpellcheck(BufferView * bv, float &) const
679 {
680         bv->unlockInset(const_cast<InsetERT *>(this));
681         return WordLangTuple();
682 }
683
684
685 void InsetERT::getDrawFont(LyXFont & font) const
686 {
687         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
688         font = f;
689         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
690         font.setColor(LColor::latex);
691 }
692
693
694 int InsetERT::getMaxWidth(BufferView * bv, UpdatableInset const * in) const
695 {
696         int w = InsetCollapsable::getMaxWidth(bv, in);
697         if (status_ != Inlined || w < 0)
698                 return w;
699         LyXText * text = inset.getLyXText(bv);
700         int rw = text->firstRow()->width();
701         if (!rw)
702                 rw = w;
703         rw += 40;
704         if (!text->firstRow()->next() && rw < w)
705                 return -1;
706         return w;
707 }
708
709
710 void InsetERT::update(BufferView * bv, LyXFont const & font,
711                       bool reinit)
712 {
713         if (inset.need_update & InsetText::INIT ||
714                 inset.need_update & InsetText::FULL)
715         {
716                 setButtonLabel();
717         }
718         InsetCollapsable::update(bv, font, reinit);
719 }