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