]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
Look for mathed xpms. Doesn't do anything yet due to lack of workable XPMs
[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 void InsetERT::lfunMousePress(FuncRequest const & cmd)
302 {
303         if (status_ == Inlined)
304                 inset.localDispatch(cmd);
305         else
306                 InsetCollapsable::localDispatch(cmd);
307 }
308
309
310 bool InsetERT::lfunMouseRelease(FuncRequest const & cmd)
311 {
312         BufferView * bv = cmd.view();
313
314         if (cmd.button() == mouse_button::button3) {
315                 showInsetDialog(bv);
316                 return true;
317         }
318
319         if (status_ != Inlined && (cmd.x >= 0) && (cmd.x < button_length) &&
320             (cmd.y >= button_top_y) && (cmd.y <= button_bottom_y)) {
321                 updateStatus(bv, true);
322         } else {
323                 LyXFont font(LyXFont::ALL_SANE);
324                 FuncRequest cmd1 = cmd;
325                 cmd1.y = ascent(bv, font) + cmd.y - inset.ascent(bv, font);
326
327                 // inlined is special - the text appears above
328                 // button_bottom_y
329                 if (status_ == Inlined)
330                         inset.localDispatch(cmd1);
331                 else if (!collapsed_ && (cmd.y > button_bottom_y)) {
332                         cmd1.y -= ascent_collapsed() + descent_collapsed();
333                         inset.localDispatch(cmd1);
334                 }
335         }
336         return false;
337 }
338
339
340 void InsetERT::lfunMouseMotion(FuncRequest const & cmd)
341 {
342         if (status_ == Inlined)
343                 inset.localDispatch(cmd);
344         else
345                 InsetCollapsable::localDispatch(cmd);
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 *, ostream &, int /*linelen*/) const
380 {
381         return 0;
382 }
383
384
385 int InsetERT::linuxdoc(Buffer const *, ostream & os) const
386 {
387         Paragraph * par = inset.paragraph();
388         int lines = 0;
389         while (par) {
390                 pos_type siz = par->size();
391                 for (pos_type i = 0; i < siz; ++i) {
392                         Paragraph::value_type c = par->getChar(i);
393                         switch (c) {
394                         case Paragraph::META_NEWLINE:
395                                 os << '\n';
396                                 ++lines;
397                                 break;
398                         default:
399                                 os << c;
400                                 break;
401                         }
402                 }
403                 par = par->next();
404                 if (par) {
405                         os << "\n";
406                         lines ++;
407                 }
408         }
409
410         return lines;
411 }
412
413
414 int InsetERT::docbook(Buffer const *, ostream & os, bool) const
415 {
416         Paragraph * par = inset.paragraph();
417         int lines = 0;
418         while (par) {
419                 pos_type siz = par->size();
420                 for (pos_type i = 0; i < siz; ++i) {
421                         Paragraph::value_type c = par->getChar(i);
422                         switch (c) {
423                         case Paragraph::META_NEWLINE:
424                                 os << '\n';
425                                 ++lines;
426                                 break;
427                         default:
428                                 os << c;
429                                 break;
430                         }
431                 }
432                 par = par->next();
433                 if (par) {
434                         os << "\n";
435                         lines ++;
436                 }
437         }
438
439         return lines;
440 }
441
442
443 Inset::RESULT InsetERT::localDispatch(FuncRequest const & cmd)
444 {
445         Inset::RESULT result = DISPATCHED_NOUPDATE;
446         BufferView * bv = cmd.view();
447
448         if (inset.paragraph()->empty()) {
449                 set_latex_font(bv);
450         }
451
452         switch (cmd.action) {
453                 case LFUN_MOUSE_PRESS:
454                         lfunMousePress(cmd);
455                         return DISPATCHED;
456
457                 case LFUN_MOUSE_MOTION:
458                         lfunMouseMotion(cmd);
459                         return DISPATCHED;
460
461                 case LFUN_MOUSE_RELEASE:
462                         lfunMouseRelease(cmd);
463                         return DISPATCHED;
464
465                 case LFUN_LAYOUT:
466                         bv->owner()->setLayout(inset.paragraph()->layout()->name());
467                         break;
468
469                 default:
470                         result = InsetCollapsable::localDispatch(cmd);
471         }
472
473         switch (cmd.action) {
474         case LFUN_BREAKPARAGRAPH:
475         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
476         case LFUN_BACKSPACE:
477         case LFUN_BACKSPACE_SKIP:
478         case LFUN_DELETE:
479         case LFUN_DELETE_SKIP:
480         case LFUN_DELETE_LINE_FORWARD:
481         case LFUN_CUT:
482                 set_latex_font(bv);
483                 break;
484
485         default:
486                 break;
487         }
488         return result;
489 }
490
491
492 string const InsetERT::get_new_label() const
493 {
494         string la;
495         pos_type const max_length = 15;
496         pos_type const p_siz = inset.paragraph()->size();
497         pos_type const n = min(max_length, p_siz);
498         int i = 0;
499         int j = 0;
500         for(; i < n && j < p_siz; ++j) {
501                 if (inset.paragraph()->isInset(j))
502                         continue;
503                 la += inset.paragraph()->getChar(j);
504                 ++i;
505         }
506         if (inset.paragraph()->next() || (i > 0 && j < p_siz)) {
507                 la += "...";
508         }
509         if (la.empty()) {
510                 la = _("ERT");
511         }
512         return la;
513 }
514
515
516 void InsetERT::setButtonLabel() const
517 {
518         if (status_ == Collapsed) {
519                 setLabel(get_new_label());
520         } else {
521                 setLabel(_("ERT"));
522         }
523 }
524
525
526 bool InsetERT::checkInsertChar(LyXFont & /* font */)
527 {
528 #ifdef SET_HARD_FONT
529 #ifndef INHERIT_LANG
530         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
531 #else
532         LyXFont f(LyXFont::ALL_INHERIT);
533 #endif
534         font = f;
535         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
536         font.setColor(LColor::latex);
537 #endif
538         return true;
539 }
540
541
542 int InsetERT::ascent(BufferView * bv, LyXFont const & font) const
543 {
544         if (!inlined())
545                 return InsetCollapsable::ascent(bv, font);
546
547         return inset.ascent(bv, font);
548 }
549
550
551 int InsetERT::descent(BufferView * bv, LyXFont const & font) const
552 {
553         if (!inlined())
554                 return InsetCollapsable::descent(bv, font);
555
556         return inset.descent(bv, font);
557 }
558
559
560 int InsetERT::width(BufferView * bv, LyXFont const & font) const
561 {
562         if (!inlined())
563                 return InsetCollapsable::width(bv, font);
564
565         return inset.width(bv, font);
566 }
567
568
569 void InsetERT::draw(BufferView * bv, LyXFont const & f,
570                     int baseline, float & x, bool cleared) const
571 {
572         Painter & pain = bv->painter();
573
574         button_length = width_collapsed();
575         button_top_y = -ascent(bv, f);
576         button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
577                 descent_collapsed();
578
579         if (!isOpen()) {
580                 draw_collapsed(pain, baseline, x);
581                 return;
582         }
583
584         float old_x = x;
585
586         if (!owner())
587                 x += static_cast<float>(scroll());
588
589         if (!cleared && (inset.need_update == InsetText::FULL ||
590                          inset.need_update == InsetText::INIT ||
591                          top_x != int(x) ||
592                          top_baseline != baseline))
593         {
594                 // we don't need anymore to clear here we just have to tell
595                 // the underlying LyXText that it should do the RowClear!
596                 inset.setUpdateStatus(bv, InsetText::FULL);
597                 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
598                 return;
599         }
600
601         top_x = int(x);
602         topx_set = true;
603         top_baseline = baseline;
604
605         int const bl = baseline - ascent(bv, f) + ascent_collapsed();
606
607         if (inlined()) {
608                 inset.draw(bv, f, baseline, x, cleared);
609         } else {
610                 draw_collapsed(pain, bl, old_x);
611                 inset.draw(bv, f,
612                                    bl + descent_collapsed() + inset.ascent(bv, f),
613                                    x, cleared);
614         }
615         need_update = NONE;
616 }
617
618
619 void InsetERT::set_latex_font(BufferView * /* bv */)
620 {
621 #ifdef SET_HARD_FONT
622 #ifndef INHERIT_LANG
623         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
624 #else
625         LyXFont font(LyXFont::ALL_INHERIT);
626 #endif
627
628         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
629         font.setColor(LColor::latex);
630
631         inset.getLyXText(bv)->setFont(bv, font, false);
632 #endif
633 }
634
635
636 // attention this function can be called with bv == 0
637 void InsetERT::status(BufferView * bv, ERTStatus const st) const
638 {
639         if (st != status_) {
640                 status_ = st;
641                 need_update = FULL;
642                 switch (st) {
643                 case Inlined:
644                         if (bv)
645                                 inset.setUpdateStatus(bv, InsetText::INIT);
646                         break;
647                 case Open:
648                         collapsed_ = false;
649                         setButtonLabel();
650                         break;
651                 case Collapsed:
652                         collapsed_ = true;
653                         setButtonLabel();
654                         if (bv)
655                                 bv->unlockInset(const_cast<InsetERT *>(this));
656                         break;
657                 }
658                 if (bv)
659                         bv->updateInset(const_cast<InsetERT *>(this), false);
660         }
661 }
662
663
664 bool InsetERT::showInsetDialog(BufferView * bv) const
665 {
666         bv->owner()->getDialogs().showERT(const_cast<InsetERT *>(this));
667         return true;
668 }
669
670
671 void InsetERT::open(BufferView * bv)
672 {
673         if (!collapsed_)
674                 return;
675         status(bv, Open);
676 }
677
678
679 void InsetERT::close(BufferView * bv) const
680 {
681         if (status_ == Collapsed || status_ == Inlined)
682                 return;
683
684         status(bv, Collapsed);
685 }
686
687
688 WordLangTuple const
689 InsetERT::selectNextWordToSpellcheck(BufferView * bv, float &) const
690 {
691         bv->unlockInset(const_cast<InsetERT *>(this));
692         return WordLangTuple();
693 }
694
695
696 void InsetERT::getDrawFont(LyXFont & font) const
697 {
698 #ifndef INHERIT_LANG
699         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
700 #else
701         LyXFont f(LyXFont::ALL_INHERIT);
702 #endif
703         font = f;
704         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
705         font.setColor(LColor::latex);
706 }
707
708
709 int InsetERT::getMaxWidth(BufferView * bv, UpdatableInset const * in) const
710 {
711         int w = InsetCollapsable::getMaxWidth(bv, in);
712         if (status_ != Inlined || w < 0)
713                 return w;
714         LyXText * text = inset.getLyXText(bv);
715         int rw = text->firstRow()->width();
716         if (!rw)
717                 rw = w;
718         rw += 40;
719         if (!text->firstRow()->next() && rw < w)
720                 return -1;
721         return w;
722 }
723
724
725 void InsetERT::update(BufferView * bv, LyXFont const & font,
726                       bool reinit)
727 {
728         if (inset.need_update & InsetText::INIT ||
729                 inset.need_update & InsetText::FULL)
730         {
731                 setButtonLabel();
732         }
733         InsetCollapsable::update(bv, font, reinit);
734 }