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