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