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