]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
remove unneeded Inset::getMaxWidth(
[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 #include "insetert.h"
14 #include "insettext.h"
15
16 #include "buffer.h"
17 #include "BufferView.h"
18 #include "debug.h"
19 #include "funcrequest.h"
20 #include "gettext.h"
21 #include "language.h"
22 #include "lyxfont.h"
23 #include "lyxlex.h"
24 #include "lyxrow.h"
25 #include "lyxtext.h"
26 #include "WordLangTuple.h"
27
28 #include "frontends/Alert.h"
29 #include "frontends/Dialogs.h"
30 #include "frontends/LyXView.h"
31
32 #include "support/LOstream.h"
33 #include "support/LAssert.h"
34 #include "support/tostr.h"
35
36 using namespace lyx::support;
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)
68         : InsetCollapsable(in), status_(in.status_)
69 {
70         init();
71 }
72
73
74 InsetBase * InsetERT::clone() const
75 {
76         return new InsetERT(*this);
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.paragraphs.begin()->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         InsetERTMailer(*this).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         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
159         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
160         font.setColor(LColor::latex);
161
162         ParagraphList::iterator pit = inset.paragraphs.begin();
163         ParagraphList::iterator pend = inset.paragraphs.end();
164         for (; pit != pend; ++pit) {
165                 pos_type siz = pit->size();
166                 for (pos_type i = 0; i < siz; ++i) {
167                         pit->setFont(i, font);
168                 }
169         }
170 #endif
171
172         if (!token_found) {
173                 if (collapsed_) {
174                         status(0, Collapsed);
175                 } else {
176                         status(0, Open);
177                 }
178         }
179         setButtonLabel();
180 }
181
182
183 void InsetERT::write(Buffer const * buf, ostream & os) const
184 {
185         string st;
186
187         switch (status_) {
188         case Open:
189                 st = "Open";
190                 break;
191         case Collapsed:
192                 st = "Collapsed";
193                 break;
194         case Inlined:
195                 st = "Inlined";
196                 break;
197         }
198
199         os << getInsetName() << "\n"
200            << "status "<< st << "\n";
201
202         //inset.writeParagraphData(buf, os);
203         string const layout(buf->params.getLyXTextClass().defaultLayoutName());
204         ParagraphList::iterator par = inset.paragraphs.begin();
205         ParagraphList::iterator end = inset.paragraphs.end();
206         for (; par != end; ++par) {
207                 os << "\n\\layout " << layout << "\n";
208                 pos_type siz = par->size();
209                 for (pos_type i = 0; i < siz; ++i) {
210                         Paragraph::value_type c = par->getChar(i);
211                         switch (c) {
212                         case Paragraph::META_INSET:
213                                 if (par->getInset(i)->lyxCode() != Inset::NEWLINE_CODE) {
214                                         lyxerr << "Element is not allowed in insertERT"
215                                                << endl;
216                                 } else {
217                                         par->getInset(i)->write(buf, os);
218                                 }
219                                 break;
220
221                         case '\\':
222                                 os << "\n\\backslash \n";
223                                 break;
224                         default:
225                                 os << c;
226                                 break;
227                         }
228                 }
229         }
230 }
231
232
233 string const InsetERT::editMessage() const
234 {
235         return _("Opened ERT Inset");
236 }
237
238
239 bool InsetERT::insertInset(BufferView *, Inset *)
240 {
241         return false;
242 }
243
244
245 void InsetERT::setFont(BufferView *, LyXFont const &, bool, bool selectall)
246 {
247 #ifdef WITH_WARNINGS
248 #warning FIXME. More UI stupidity...
249 #endif
250         // if selectall is activated then the fontchange was an outside general
251         // fontchange and this messages is not needed
252         if (!selectall)
253                 Alert::error(_("Cannot change font"),
254                            _("You cannot change font settings inside TeX code."));
255 }
256
257
258 void InsetERT::updateStatus(BufferView * bv, bool swap) const
259 {
260         if (status_ != Inlined) {
261                 if (collapsed_) {
262                         status(bv, swap ? Open : Collapsed);
263                 } else {
264                         status(bv, swap ? Collapsed : Open);
265                 }
266         }
267 }
268
269
270 Inset::EDITABLE InsetERT::editable() const
271 {
272         if (status_ == Collapsed)
273                 return IS_EDITABLE;
274         return HIGHLY_EDITABLE;
275 }
276
277
278 void InsetERT::lfunMousePress(FuncRequest const & cmd)
279 {
280         if (status_ == Inlined)
281                 inset.localDispatch(cmd);
282         else
283                 InsetCollapsable::localDispatch(cmd);
284 }
285
286
287 bool InsetERT::lfunMouseRelease(FuncRequest const & cmd)
288 {
289         BufferView * bv = cmd.view();
290
291         if (cmd.button() == mouse_button::button3) {
292                 showInsetDialog(bv);
293                 return true;
294         }
295
296         if (status_ != Inlined && (cmd.x >= 0) && (cmd.x < button_length) &&
297             (cmd.y >= button_top_y) && (cmd.y <= button_bottom_y)) {
298                 updateStatus(bv, true);
299         } else {
300                 FuncRequest cmd1 = cmd;
301 #warning metrics?
302                 cmd1.y = ascent() + cmd.y - inset.ascent();
303
304                 // inlined is special - the text appears above
305                 // button_bottom_y
306                 if (status_ == Inlined)
307                         inset.localDispatch(cmd1);
308                 else if (!collapsed_ && (cmd.y > button_bottom_y)) {
309                         cmd1.y -= height_collapsed();
310                         inset.localDispatch(cmd1);
311                 }
312         }
313         return false;
314 }
315
316
317 void InsetERT::lfunMouseMotion(FuncRequest const & cmd)
318 {
319         if (status_ == Inlined)
320                 inset.localDispatch(cmd);
321         else
322                 InsetCollapsable::localDispatch(cmd);
323 }
324
325
326 int InsetERT::latex(Buffer const *, ostream & os,
327                     LatexRunParams const &) const
328 {
329         ParagraphList::iterator par = inset.paragraphs.begin();
330         ParagraphList::iterator end = inset.paragraphs.end();
331
332         int lines = 0;
333         while (par != end) {
334                 pos_type siz = par->size();
335                 for (pos_type i = 0; i < siz; ++i) {
336                         // ignore all struck out text
337                         if (isDeletedText(*par, i))
338                                 continue;
339
340                         if (par->isNewline(i)) {
341                                 os << '\n';
342                                 ++lines;
343                         } else {
344                                 os << par->getChar(i);
345                         }
346                 }
347                 ++par;
348                 if (par != end) {
349                         os << "\n";
350                         ++lines;
351                 }
352         }
353
354         return lines;
355 }
356
357
358 int InsetERT::ascii(Buffer const *, ostream &, int /*linelen*/) const
359 {
360         return 0;
361 }
362
363
364 int InsetERT::linuxdoc(Buffer const *, ostream & os) const
365 {
366         ParagraphList::iterator par = inset.paragraphs.begin();
367         ParagraphList::iterator end = inset.paragraphs.end();
368
369         int lines = 0;
370         while (par != end) {
371                 pos_type siz = par->size();
372                 for (pos_type i = 0; i < siz; ++i) {
373                         if (par->isNewline(i)) {
374                                 os << '\n';
375                                 ++lines;
376                         } else {
377                                 os << par->getChar(i);
378                         }
379                 }
380                 ++par;
381                 if (par != end) {
382                         os << "\n";
383                         lines ++;
384                 }
385         }
386
387         return lines;
388 }
389
390
391 int InsetERT::docbook(Buffer const *, ostream & os, bool) const
392 {
393         ParagraphList::iterator par = inset.paragraphs.begin();
394         ParagraphList::iterator end = inset.paragraphs.end();
395
396         int lines = 0;
397         while (par != end) {
398                 pos_type siz = par->size();
399                 for (pos_type i = 0; i < siz; ++i) {
400                         if (par->isNewline(i)) {
401                                 os << '\n';
402                                 ++lines;
403                         } else {
404                                 os << par->getChar(i);
405                         }
406                 }
407                 ++par;
408                 if (par != end) {
409                         os << "\n";
410                         lines ++;
411                 }
412         }
413
414         return lines;
415 }
416
417
418 Inset::RESULT InsetERT::localDispatch(FuncRequest const & cmd)
419 {
420         Inset::RESULT result = UNDISPATCHED;
421         BufferView * bv = cmd.view();
422
423         if (inset.paragraphs.begin()->empty()) {
424                 set_latex_font(bv);
425         }
426
427         switch (cmd.action) {
428
429         case LFUN_INSET_EDIT:
430                 if (cmd.button() == mouse_button::button3)
431                         break;
432                 if (status_ == Inlined) {
433                         if (!bv->lockInset(this))
434                                 break;
435                         result = inset.localDispatch(cmd);
436                 } else {
437                         result = InsetCollapsable::localDispatch(cmd);
438                 }
439                 set_latex_font(bv);
440                 updateStatus(bv);
441                 break;
442
443         case LFUN_INSET_MODIFY: {
444                 InsetERT::ERTStatus status_;
445                 InsetERTMailer::string2params(cmd.argument, status_);
446
447                 status(bv, status_);
448
449                 /* FIXME: I refuse to believe we have to live
450                  * with ugliness like this ! Note that this
451                  * rebreak *is* needed. Consider a change from
452                  * Open (needfullrow) to Inlined (only the space
453                  * taken by the text).
454                  */
455                 inset.getLyXText(cmd.view())->fullRebreak();
456                 bv->updateInset(this);
457                 result = DISPATCHED;
458         }
459         break;
460
461         case LFUN_MOUSE_PRESS:
462                 lfunMousePress(cmd);
463                 result = DISPATCHED;
464                 break;
465
466         case LFUN_MOUSE_MOTION:
467                 lfunMouseMotion(cmd);
468                 result = DISPATCHED;
469                 break;
470
471         case LFUN_MOUSE_RELEASE:
472                 lfunMouseRelease(cmd);
473                 result = DISPATCHED;
474                 break;
475
476         case LFUN_LAYOUT:
477                 bv->owner()->setLayout(inset.paragraphs.begin()->layout()->name());
478                 result = DISPATCHED_NOUPDATE;
479                 break;
480
481         default:
482                 result = InsetCollapsable::localDispatch(cmd);
483         }
484
485         switch (cmd.action) {
486         case LFUN_BREAKPARAGRAPH:
487         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
488         case LFUN_BACKSPACE:
489         case LFUN_BACKSPACE_SKIP:
490         case LFUN_DELETE:
491         case LFUN_DELETE_SKIP:
492         case LFUN_DELETE_LINE_FORWARD:
493         case LFUN_CUT:
494                 set_latex_font(bv);
495                 break;
496
497         default:
498                 break;
499         }
500         return result;
501 }
502
503
504 string const InsetERT::get_new_label() const
505 {
506         string la;
507         pos_type const max_length = 15;
508         pos_type const p_siz = inset.paragraphs.begin()->size();
509         pos_type const n = min(max_length, p_siz);
510         pos_type i = 0;
511         pos_type j = 0;
512         for(; i < n && j < p_siz; ++j) {
513                 if (inset.paragraphs.begin()->isInset(j))
514                         continue;
515                 la += inset.paragraphs.begin()->getChar(j);
516                 ++i;
517         }
518         if (p_siz > 1 || (i > 0 && j < p_siz)) {
519                 la += "...";
520         }
521         if (la.empty()) {
522                 la = _("ERT");
523         }
524         return la;
525 }
526
527
528 void InsetERT::setButtonLabel() const
529 {
530         if (status_ == Collapsed) {
531                 setLabel(get_new_label());
532         } else {
533                 setLabel(_("ERT"));
534         }
535 }
536
537
538 bool InsetERT::checkInsertChar(LyXFont & /* font */)
539 {
540 #ifdef SET_HARD_FONT
541         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
542         font = f;
543         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
544         font.setColor(LColor::latex);
545 #endif
546         return true;
547 }
548
549
550 void InsetERT::metrics(MetricsInfo & mi, Dimension & dim) const
551 {
552         setButtonLabel();
553         if (inlined())
554                 inset.metrics(mi, dim);
555         else
556                 InsetCollapsable::metrics(mi, dim);
557         dim_ = dim;
558 }
559
560
561 void InsetERT::draw(PainterInfo & pi, int x, int y) const
562 {
563         InsetCollapsable::draw(pi, x, y, inlined());
564 }
565
566
567 void InsetERT::set_latex_font(BufferView * /* bv */)
568 {
569 #ifdef SET_HARD_FONT
570         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
571
572         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
573         font.setColor(LColor::latex);
574
575         inset.getLyXText(bv)->setFont(bv, font, false);
576 #endif
577 }
578
579
580 // attention this function can be called with bv == 0
581 void InsetERT::status(BufferView * bv, ERTStatus const st) const
582 {
583         if (st != status_) {
584                 status_ = st;
585                 switch (st) {
586                 case Inlined:
587                         if (bv)
588                                 inset.setUpdateStatus(InsetText::INIT);
589                         break;
590                 case Open:
591                         collapsed_ = false;
592                         setButtonLabel();
593                         break;
594                 case Collapsed:
595                         collapsed_ = true;
596                         setButtonLabel();
597                         if (bv)
598                                 bv->unlockInset(const_cast<InsetERT *>(this));
599                         break;
600                 }
601                 if (bv) {
602                         bv->updateInset(const_cast<InsetERT *>(this));
603                         bv->buffer()->markDirty();
604                 }
605         }
606 }
607
608
609 bool InsetERT::showInsetDialog(BufferView * bv) const
610 {
611         InsetERTMailer(const_cast<InsetERT &>(*this)).showDialog(bv);
612         return true;
613 }
614
615
616 void InsetERT::open(BufferView * bv)
617 {
618         if (!collapsed_)
619                 return;
620         status(bv, Open);
621 }
622
623
624 void InsetERT::close(BufferView * bv) const
625 {
626         if (status_ == Collapsed || status_ == Inlined)
627                 return;
628
629         status(bv, Collapsed);
630 }
631
632
633 WordLangTuple const
634 InsetERT::selectNextWordToSpellcheck(BufferView * bv, float &) const
635 {
636         bv->unlockInset(const_cast<InsetERT *>(this));
637         return WordLangTuple();
638 }
639
640
641 void InsetERT::getDrawFont(LyXFont & font) const
642 {
643         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
644         font = f;
645         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
646         font.setColor(LColor::latex);
647 }
648
649
650 string const InsetERTMailer::name_("ert");
651
652 InsetERTMailer::InsetERTMailer(InsetERT & inset)
653         : inset_(inset)
654 {}
655
656
657 string const InsetERTMailer::inset2string() const
658 {
659         return params2string(inset_.status());
660 }
661
662
663 void InsetERTMailer::string2params(string const & in,
664                                    InsetERT::ERTStatus & status)
665 {
666         status = InsetERT::Collapsed;
667
668         string name;
669         string body = split(in, name, ' ');
670
671         if (body.empty())
672                 return;
673
674         status = static_cast<InsetERT::ERTStatus>(strToInt(body));
675 }
676
677
678 string const
679 InsetERTMailer::params2string(InsetERT::ERTStatus status)
680 {
681         return name_ + ' ' + tostr(status);
682 }