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