]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
Get rid of trailing whitespace 'noise' in future patches for the
[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
15 #include "buffer.h"
16 #include "bufferparams.h"
17 #include "BufferView.h"
18 #include "debug.h"
19 #include "funcrequest.h"
20 #include "gettext.h"
21 #include "language.h"
22 #include "lyxlex.h"
23 #include "metricsinfo.h"
24 #include "paragraph.h"
25 #include "WordLangTuple.h"
26
27 #include "frontends/Alert.h"
28 #include "frontends/LyXView.h"
29
30 #include "support/tostr.h"
31
32 using namespace lyx::support;
33
34 using lyx::pos_type;
35
36 using std::endl;
37 using std::min;
38
39 using std::auto_ptr;
40 using std::ostream;
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)
66         : InsetCollapsable(in), status_(in.status_)
67 {
68         init();
69 }
70
71
72 auto_ptr<InsetBase> InsetERT::clone() const
73 {
74         return auto_ptr<InsetBase>(new InsetERT(*this));
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.paragraphs.begin()->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         InsetERTMailer(*this).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
160         ParagraphList::iterator pit = inset.paragraphs.begin();
161         ParagraphList::iterator pend = inset.paragraphs.end();
162         for (; pit != pend; ++pit) {
163                 pos_type siz = pit->size();
164                 for (pos_type i = 0; i < siz; ++i) {
165                         pit->setFont(i, font);
166                 }
167         }
168 #endif
169
170         if (!token_found) {
171                 if (collapsed_) {
172                         status(0, Collapsed);
173                 } else {
174                         status(0, Open);
175                 }
176         }
177         setButtonLabel();
178 }
179
180
181 void InsetERT::write(Buffer const & buf, ostream & os) const
182 {
183         string st;
184
185         switch (status_) {
186         case Open:
187                 st = "Open";
188                 break;
189         case Collapsed:
190                 st = "Collapsed";
191                 break;
192         case Inlined:
193                 st = "Inlined";
194                 break;
195         }
196
197         os << getInsetName() << "\n"
198            << "status "<< st << "\n";
199
200         //inset.writeParagraphData(buf, os);
201         string const layout(buf.params().getLyXTextClass().defaultLayoutName());
202         ParagraphList::iterator par = inset.paragraphs.begin();
203         ParagraphList::iterator end = inset.paragraphs.end();
204         for (; par != end; ++par) {
205                 os << "\n\\begin_layout " << layout << "\n";
206                 pos_type siz = par->size();
207                 for (pos_type i = 0; i < siz; ++i) {
208                         Paragraph::value_type c = par->getChar(i);
209                         switch (c) {
210                         case Paragraph::META_INSET:
211                                 if (par->getInset(i)->lyxCode() != InsetOld::NEWLINE_CODE) {
212                                         lyxerr << "Element is not allowed in insertERT"
213                                                << endl;
214                                 } else {
215                                         par->getInset(i)->write(buf, os);
216                                 }
217                                 break;
218
219                         case '\\':
220                                 os << "\n\\backslash \n";
221                                 break;
222                         default:
223                                 os << c;
224                                 break;
225                         }
226                 }
227                 os << "\n\\end_layout\n";
228         }
229 }
230
231
232 string const InsetERT::editMessage() const
233 {
234         return _("Opened ERT Inset");
235 }
236
237
238 bool InsetERT::insertInset(BufferView *, InsetOld *)
239 {
240         return false;
241 }
242
243
244 void InsetERT::setFont(BufferView *, LyXFont const &, bool, bool selectall)
245 {
246 #ifdef WITH_WARNINGS
247 #warning FIXME. More UI stupidity...
248 #endif
249         // if selectall is activated then the fontchange was an outside general
250         // fontchange and this messages is not needed
251         if (!selectall)
252                 Alert::error(_("Cannot change font"),
253                            _("You cannot change font settings inside TeX code."));
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
269 InsetOld::EDITABLE InsetERT::editable() const
270 {
271         if (status_ == Collapsed)
272                 return IS_EDITABLE;
273         return HIGHLY_EDITABLE;
274 }
275
276
277 void InsetERT::lfunMousePress(FuncRequest const & cmd)
278 {
279         if (status_ == Inlined)
280                 inset.localDispatch(cmd);
281         else
282                 InsetCollapsable::localDispatch(cmd);
283 }
284
285
286 bool InsetERT::lfunMouseRelease(FuncRequest const & cmd)
287 {
288         BufferView * bv = cmd.view();
289
290         if (cmd.button() == mouse_button::button3) {
291                 showInsetDialog(bv);
292                 return true;
293         }
294
295         if (status_ != Inlined && hitButton(cmd)) {
296                 updateStatus(bv, true);
297         } else {
298                 FuncRequest cmd1 = cmd;
299 #warning metrics?
300                 cmd1.y = ascent() + cmd.y - inset.ascent();
301
302                 // inlined is special - the text appears above
303                 // button_dim.y2
304                 if (status_ == Inlined)
305                         inset.localDispatch(cmd1);
306                 else if (!collapsed_ && (cmd.y > button_dim.y2)) {
307                         cmd1.y -= height_collapsed();
308                         inset.localDispatch(cmd1);
309                 }
310         }
311         return false;
312 }
313
314
315 void InsetERT::lfunMouseMotion(FuncRequest const & cmd)
316 {
317         if (status_ == Inlined)
318                 inset.localDispatch(cmd);
319         else
320                 InsetCollapsable::localDispatch(cmd);
321 }
322
323
324 int InsetERT::latex(Buffer const &, ostream & os,
325                     LatexRunParams const &) const
326 {
327         ParagraphList::iterator par = inset.paragraphs.begin();
328         ParagraphList::iterator end = inset.paragraphs.end();
329
330         int lines = 0;
331         while (par != end) {
332                 pos_type siz = par->size();
333                 for (pos_type i = 0; i < siz; ++i) {
334                         // ignore all struck out text
335                         if (isDeletedText(*par, i))
336                                 continue;
337
338                         if (par->isNewline(i)) {
339                                 os << '\n';
340                                 ++lines;
341                         } else {
342                                 os << par->getChar(i);
343                         }
344                 }
345                 ++par;
346                 if (par != end) {
347                         os << "\n";
348                         ++lines;
349                 }
350         }
351
352         return lines;
353 }
354
355
356 int InsetERT::ascii(Buffer const &, ostream &, int /*linelen*/) const
357 {
358         return 0;
359 }
360
361
362 int InsetERT::linuxdoc(Buffer const &, ostream & os) const
363 {
364         ParagraphList::iterator par = inset.paragraphs.begin();
365         ParagraphList::iterator end = inset.paragraphs.end();
366
367         int lines = 0;
368         while (par != end) {
369                 pos_type siz = par->size();
370                 for (pos_type i = 0; i < siz; ++i) {
371                         if (par->isNewline(i)) {
372                                 os << '\n';
373                                 ++lines;
374                         } else {
375                                 os << par->getChar(i);
376                         }
377                 }
378                 ++par;
379                 if (par != end) {
380                         os << "\n";
381                         lines ++;
382                 }
383         }
384
385         return lines;
386 }
387
388
389 int InsetERT::docbook(Buffer const &, ostream & os, bool) const
390 {
391         ParagraphList::iterator par = inset.paragraphs.begin();
392         ParagraphList::iterator end = inset.paragraphs.end();
393
394         int lines = 0;
395         while (par != end) {
396                 pos_type siz = par->size();
397                 for (pos_type i = 0; i < siz; ++i) {
398                         if (par->isNewline(i)) {
399                                 os << '\n';
400                                 ++lines;
401                         } else {
402                                 os << par->getChar(i);
403                         }
404                 }
405                 ++par;
406                 if (par != end) {
407                         os << "\n";
408                         lines ++;
409                 }
410         }
411
412         return lines;
413 }
414
415
416 InsetOld::RESULT InsetERT::localDispatch(FuncRequest const & cmd)
417 {
418         InsetOld::RESULT result = UNDISPATCHED;
419         BufferView * bv = cmd.view();
420
421         if (inset.paragraphs.begin()->empty()) {
422                 set_latex_font(bv);
423         }
424
425         switch (cmd.action) {
426
427         case LFUN_INSET_EDIT:
428                 if (cmd.button() == mouse_button::button3)
429                         break;
430                 if (status_ == Inlined) {
431                         if (!bv->lockInset(this))
432                                 break;
433                         result = inset.localDispatch(cmd);
434                 } else {
435                         result = InsetCollapsable::localDispatch(cmd);
436                 }
437                 set_latex_font(bv);
438                 updateStatus(bv);
439                 break;
440
441         case LFUN_INSET_MODIFY: {
442                 InsetERT::ERTStatus status_;
443                 InsetERTMailer::string2params(cmd.argument, status_);
444
445                 status(bv, status_);
446
447                 /* FIXME: I refuse to believe we have to live
448                  * with ugliness like this ! Note that this
449                  * rebreak *is* needed. Consider a change from
450                  * Open (needfullrow) to Inlined (only the space
451                  * taken by the text).
452                  */
453                 inset.getLyXText(cmd.view())->fullRebreak();
454                 bv->updateInset(this);
455                 result = DISPATCHED;
456         }
457         break;
458
459         case LFUN_MOUSE_PRESS:
460                 lfunMousePress(cmd);
461                 result = DISPATCHED;
462                 break;
463
464         case LFUN_MOUSE_MOTION:
465                 lfunMouseMotion(cmd);
466                 result = DISPATCHED;
467                 break;
468
469         case LFUN_MOUSE_RELEASE:
470                 lfunMouseRelease(cmd);
471                 result = DISPATCHED;
472                 break;
473
474         case LFUN_LAYOUT:
475                 bv->owner()->setLayout(inset.paragraphs.begin()->layout()->name());
476                 result = DISPATCHED_NOUPDATE;
477                 break;
478
479         default:
480                 result = InsetCollapsable::localDispatch(cmd);
481         }
482
483         switch (cmd.action) {
484         case LFUN_BREAKPARAGRAPH:
485         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
486         case LFUN_BACKSPACE:
487         case LFUN_BACKSPACE_SKIP:
488         case LFUN_DELETE:
489         case LFUN_DELETE_SKIP:
490         case LFUN_DELETE_LINE_FORWARD:
491         case LFUN_CUT:
492                 set_latex_font(bv);
493                 break;
494
495         default:
496                 break;
497         }
498         return result;
499 }
500
501
502 string const InsetERT::get_new_label() const
503 {
504         string la;
505         pos_type const max_length = 15;
506         pos_type const p_siz = inset.paragraphs.begin()->size();
507         pos_type const n = min(max_length, p_siz);
508         pos_type i = 0;
509         pos_type j = 0;
510         for(; i < n && j < p_siz; ++j) {
511                 if (inset.paragraphs.begin()->isInset(j))
512                         continue;
513                 la += inset.paragraphs.begin()->getChar(j);
514                 ++i;
515         }
516         if (inset.paragraphs.size() > 1 || (i > 0 && j < p_siz)) {
517                 la += "...";
518         }
519         if (la.empty()) {
520                 la = _("ERT");
521         }
522         return la;
523 }
524
525
526 void InsetERT::setButtonLabel() const
527 {
528         if (status_ == Collapsed) {
529                 setLabel(get_new_label());
530         } else {
531                 setLabel(_("ERT"));
532         }
533 }
534
535
536 bool InsetERT::checkInsertChar(LyXFont & /* font */)
537 {
538 #ifdef SET_HARD_FONT
539         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
540         font = f;
541         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
542         font.setColor(LColor::latex);
543 #endif
544         return true;
545 }
546
547
548 void InsetERT::metrics(MetricsInfo & mi, Dimension & dim) const
549 {
550         setButtonLabel();
551         if (inlined())
552                 inset.metrics(mi, dim);
553         else
554                 InsetCollapsable::metrics(mi, dim);
555         // Make it stand out on its own as it is code, not part of running
556         // text:
557         if (isOpen() && !inlined())
558                 dim.wid = mi.base.textwidth;
559         dim_ = dim;
560 }
561
562
563 void InsetERT::draw(PainterInfo & pi, int x, int y) const
564 {
565         InsetCollapsable::draw(pi, x, y, inlined());
566 }
567
568
569 void InsetERT::set_latex_font(BufferView * /* bv */)
570 {
571 #ifdef SET_HARD_FONT
572         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
573
574         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
575         font.setColor(LColor::latex);
576
577         inset.getLyXText(bv)->setFont(bv, font, false);
578 #endif
579 }
580
581
582 // attention this function can be called with bv == 0
583 void InsetERT::status(BufferView * bv, ERTStatus const st) const
584 {
585         if (st != status_) {
586                 status_ = st;
587                 switch (st) {
588                 case Inlined:
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(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(Buffer const &) 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 }