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