]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
Enable convertDefault.sh to run even if its executable bit is not set.
[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 #include "metricsinfo.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 #include "support/LAssert.h"
35 #include "support/tostr.h"
36
37 using namespace lyx::support;
38
39 using lyx::pos_type;
40
41 using std::ostream;
42 using std::min;
43 using std::endl;
44 using std::auto_ptr;
45
46
47 void InsetERT::init()
48 {
49         setButtonLabel();
50         labelfont = LyXFont(LyXFont::ALL_SANE);
51         labelfont.decSize();
52         labelfont.decSize();
53         labelfont.setColor(LColor::latex);
54         setInsetName("ERT");
55 }
56
57
58 InsetERT::InsetERT(BufferParams const & bp, bool collapsed)
59         : InsetCollapsable(bp, collapsed)
60 {
61         if (collapsed)
62                 status_ = Collapsed;
63         else
64                 status_ = Open;
65         init();
66 }
67
68
69 InsetERT::InsetERT(InsetERT const & in)
70         : InsetCollapsable(in), status_(in.status_)
71 {
72         init();
73 }
74
75
76 auto_ptr<InsetBase> InsetERT::clone() const
77 {
78         return auto_ptr<InsetBase>(new InsetERT(*this));
79 }
80
81
82 InsetERT::InsetERT(BufferParams const & bp,
83                    Language const * l, string const & contents, bool collapsed)
84         : InsetCollapsable(bp, collapsed)
85 {
86         if (collapsed)
87                 status_ = Collapsed;
88         else
89                 status_ = Open;
90
91         LyXFont font(LyXFont::ALL_INHERIT, l);
92 #ifdef SET_HARD_FONT
93         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
94         font.setColor(LColor::latex);
95 #endif
96
97         string::const_iterator cit = contents.begin();
98         string::const_iterator end = contents.end();
99         pos_type pos = 0;
100         for (; cit != end; ++cit) {
101                 inset.paragraphs.begin()->insertChar(pos++, *cit, font);
102         }
103         // the init has to be after the initialization of the paragraph
104         // because of the label settings (draw_label for ert insets).
105         init();
106 }
107
108
109 InsetERT::~InsetERT()
110 {
111         InsetERTMailer(*this).hideDialog();
112 }
113
114
115 void InsetERT::read(Buffer const & buf, LyXLex & lex)
116 {
117         bool token_found = false;
118         if (lex.isOK()) {
119                 lex.next();
120                 string const token = lex.getString();
121                 if (token == "status") {
122                         lex.next();
123                         string const tmp_token = lex.getString();
124
125                         if (tmp_token == "Inlined") {
126                                 status(0, Inlined);
127                         } else if (tmp_token == "Collapsed") {
128                                 status(0, Collapsed);
129                         } else {
130                                 // leave this as default!
131                                 status(0, Open);
132                         }
133
134                         token_found = true;
135                 } else {
136                         lyxerr << "InsetERT::Read: Missing 'status'-tag!"
137                                    << endl;
138                         // take countermeasures
139                         lex.pushToken(token);
140                 }
141         }
142 #if 0
143 #warning this should be really short lived only for compatibility to
144 #warning files written 07/08/2001 so this has to go before 1.2.0! (Jug)
145         if (lex.isOK()) {
146                 lex.next();
147                 string const token = lex.getString();
148                 if (token == "collapsed") {
149                         lex.next();
150                         collapsed_ = lex.getBool();
151                 } else {
152                         // Take countermeasures
153                         lex.pushToken(token);
154                 }
155         }
156 #endif
157         inset.read(buf, lex);
158
159 #ifdef SET_HARD_FONT
160         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
161         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
162         font.setColor(LColor::latex);
163
164         ParagraphList::iterator pit = inset.paragraphs.begin();
165         ParagraphList::iterator pend = inset.paragraphs.end();
166         for (; pit != pend; ++pit) {
167                 pos_type siz = pit->size();
168                 for (pos_type i = 0; i < siz; ++i) {
169                         pit->setFont(i, font);
170                 }
171         }
172 #endif
173
174         if (!token_found) {
175                 if (collapsed_) {
176                         status(0, Collapsed);
177                 } else {
178                         status(0, Open);
179                 }
180         }
181         setButtonLabel();
182 }
183
184
185 void InsetERT::write(Buffer const & buf, ostream & os) const
186 {
187         string st;
188
189         switch (status_) {
190         case Open:
191                 st = "Open";
192                 break;
193         case Collapsed:
194                 st = "Collapsed";
195                 break;
196         case Inlined:
197                 st = "Inlined";
198                 break;
199         }
200
201         os << getInsetName() << "\n"
202            << "status "<< st << "\n";
203
204         //inset.writeParagraphData(buf, os);
205         string const layout(buf.params.getLyXTextClass().defaultLayoutName());
206         ParagraphList::iterator par = inset.paragraphs.begin();
207         ParagraphList::iterator end = inset.paragraphs.end();
208         for (; par != end; ++par) {
209                 os << "\n\\begin_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                                 if (par->getInset(i)->lyxCode() != InsetOld::NEWLINE_CODE) {
216                                         lyxerr << "Element is not allowed in insertERT"
217                                                << endl;
218                                 } else {
219                                         par->getInset(i)->write(buf, os);
220                                 }
221                                 break;
222
223                         case '\\':
224                                 os << "\n\\backslash \n";
225                                 break;
226                         default:
227                                 os << c;
228                                 break;
229                         }
230                 }
231                 os << "\n\\end_layout\n";
232         }
233 }
234
235
236 string const InsetERT::editMessage() const
237 {
238         return _("Opened ERT Inset");
239 }
240
241
242 bool InsetERT::insertInset(BufferView *, InsetOld *)
243 {
244         return false;
245 }
246
247
248 void InsetERT::setFont(BufferView *, LyXFont const &, bool, bool selectall)
249 {
250 #ifdef WITH_WARNINGS
251 #warning FIXME. More UI stupidity...
252 #endif
253         // if selectall is activated then the fontchange was an outside general
254         // fontchange and this messages is not needed
255         if (!selectall)
256                 Alert::error(_("Cannot change font"),
257                            _("You cannot change font settings inside TeX code."));
258 }
259
260
261 void InsetERT::updateStatus(BufferView * bv, bool swap) const
262 {
263         if (status_ != Inlined) {
264                 if (collapsed_) {
265                         status(bv, swap ? Open : Collapsed);
266                 } else {
267                         status(bv, swap ? Collapsed : Open);
268                 }
269         }
270 }
271
272
273 InsetOld::EDITABLE InsetERT::editable() const
274 {
275         if (status_ == Collapsed)
276                 return IS_EDITABLE;
277         return HIGHLY_EDITABLE;
278 }
279
280
281 void InsetERT::lfunMousePress(FuncRequest const & cmd)
282 {
283         if (status_ == Inlined)
284                 inset.localDispatch(cmd);
285         else
286                 InsetCollapsable::localDispatch(cmd);
287 }
288
289
290 bool InsetERT::lfunMouseRelease(FuncRequest const & cmd)
291 {
292         BufferView * bv = cmd.view();
293
294         if (cmd.button() == mouse_button::button3) {
295                 showInsetDialog(bv);
296                 return true;
297         }
298
299         if (status_ != Inlined && hitButton(cmd)) {
300                 updateStatus(bv, true);
301         } else {
302                 FuncRequest cmd1 = cmd;
303 #warning metrics?
304                 cmd1.y = ascent() + cmd.y - inset.ascent();
305
306                 // inlined is special - the text appears above
307                 // button_dim.y2
308                 if (status_ == Inlined)
309                         inset.localDispatch(cmd1);
310                 else if (!collapsed_ && (cmd.y > button_dim.y2)) {
311                         cmd1.y -= height_collapsed();
312                         inset.localDispatch(cmd1);
313                 }
314         }
315         return false;
316 }
317
318
319 void InsetERT::lfunMouseMotion(FuncRequest const & cmd)
320 {
321         if (status_ == Inlined)
322                 inset.localDispatch(cmd);
323         else
324                 InsetCollapsable::localDispatch(cmd);
325 }
326
327
328 int InsetERT::latex(Buffer const &, ostream & os,
329                     LatexRunParams const &) const
330 {
331         ParagraphList::iterator par = inset.paragraphs.begin();
332         ParagraphList::iterator end = inset.paragraphs.end();
333
334         int lines = 0;
335         while (par != end) {
336                 pos_type siz = par->size();
337                 for (pos_type i = 0; i < siz; ++i) {
338                         // ignore all struck out text
339                         if (isDeletedText(*par, i))
340                                 continue;
341
342                         if (par->isNewline(i)) {
343                                 os << '\n';
344                                 ++lines;
345                         } else {
346                                 os << par->getChar(i);
347                         }
348                 }
349                 ++par;
350                 if (par != end) {
351                         os << "\n";
352                         ++lines;
353                 }
354         }
355
356         return lines;
357 }
358
359
360 int InsetERT::ascii(Buffer const &, ostream &, int /*linelen*/) const
361 {
362         return 0;
363 }
364
365
366 int InsetERT::linuxdoc(Buffer const &, ostream & os) const
367 {
368         ParagraphList::iterator par = inset.paragraphs.begin();
369         ParagraphList::iterator end = inset.paragraphs.end();
370
371         int lines = 0;
372         while (par != end) {
373                 pos_type siz = par->size();
374                 for (pos_type i = 0; i < siz; ++i) {
375                         if (par->isNewline(i)) {
376                                 os << '\n';
377                                 ++lines;
378                         } else {
379                                 os << par->getChar(i);
380                         }
381                 }
382                 ++par;
383                 if (par != end) {
384                         os << "\n";
385                         lines ++;
386                 }
387         }
388
389         return lines;
390 }
391
392
393 int InsetERT::docbook(Buffer const &, ostream & os, bool) const
394 {
395         ParagraphList::iterator par = inset.paragraphs.begin();
396         ParagraphList::iterator end = inset.paragraphs.end();
397
398         int lines = 0;
399         while (par != end) {
400                 pos_type siz = par->size();
401                 for (pos_type i = 0; i < siz; ++i) {
402                         if (par->isNewline(i)) {
403                                 os << '\n';
404                                 ++lines;
405                         } else {
406                                 os << par->getChar(i);
407                         }
408                 }
409                 ++par;
410                 if (par != end) {
411                         os << "\n";
412                         lines ++;
413                 }
414         }
415
416         return lines;
417 }
418
419
420 InsetOld::RESULT InsetERT::localDispatch(FuncRequest const & cmd)
421 {
422         InsetOld::RESULT result = UNDISPATCHED;
423         BufferView * bv = cmd.view();
424
425         if (inset.paragraphs.begin()->empty()) {
426                 set_latex_font(bv);
427         }
428
429         switch (cmd.action) {
430
431         case LFUN_INSET_EDIT:
432                 if (cmd.button() == mouse_button::button3)
433                         break;
434                 if (status_ == Inlined) {
435                         if (!bv->lockInset(this))
436                                 break;
437                         result = inset.localDispatch(cmd);
438                 } else {
439                         result = InsetCollapsable::localDispatch(cmd);
440                 }
441                 set_latex_font(bv);
442                 updateStatus(bv);
443                 break;
444
445         case LFUN_INSET_MODIFY: {
446                 InsetERT::ERTStatus status_;
447                 InsetERTMailer::string2params(cmd.argument, status_);
448
449                 status(bv, status_);
450
451                 /* FIXME: I refuse to believe we have to live
452                  * with ugliness like this ! Note that this
453                  * rebreak *is* needed. Consider a change from
454                  * Open (needfullrow) to Inlined (only the space
455                  * taken by the text).
456                  */
457                 inset.getLyXText(cmd.view())->fullRebreak();
458                 bv->updateInset(this);
459                 result = DISPATCHED;
460         }
461         break;
462
463         case LFUN_MOUSE_PRESS:
464                 lfunMousePress(cmd);
465                 result = DISPATCHED;
466                 break;
467
468         case LFUN_MOUSE_MOTION:
469                 lfunMouseMotion(cmd);
470                 result = DISPATCHED;
471                 break;
472
473         case LFUN_MOUSE_RELEASE:
474                 lfunMouseRelease(cmd);
475                 result = DISPATCHED;
476                 break;
477
478         case LFUN_LAYOUT:
479                 bv->owner()->setLayout(inset.paragraphs.begin()->layout()->name());
480                 result = DISPATCHED_NOUPDATE;
481                 break;
482
483         default:
484                 result = InsetCollapsable::localDispatch(cmd);
485         }
486
487         switch (cmd.action) {
488         case LFUN_BREAKPARAGRAPH:
489         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
490         case LFUN_BACKSPACE:
491         case LFUN_BACKSPACE_SKIP:
492         case LFUN_DELETE:
493         case LFUN_DELETE_SKIP:
494         case LFUN_DELETE_LINE_FORWARD:
495         case LFUN_CUT:
496                 set_latex_font(bv);
497                 break;
498
499         default:
500                 break;
501         }
502         return result;
503 }
504
505
506 string const InsetERT::get_new_label() const
507 {
508         string la;
509         pos_type const max_length = 15;
510         pos_type const p_siz = inset.paragraphs.begin()->size();
511         pos_type const n = min(max_length, p_siz);
512         pos_type i = 0;
513         pos_type j = 0;
514         for(; i < n && j < p_siz; ++j) {
515                 if (inset.paragraphs.begin()->isInset(j))
516                         continue;
517                 la += inset.paragraphs.begin()->getChar(j);
518                 ++i;
519         }
520         if (inset.paragraphs.size() > 1 || (i > 0 && j < p_siz)) {
521                 la += "...";
522         }
523         if (la.empty()) {
524                 la = _("ERT");
525         }
526         return la;
527 }
528
529
530 void InsetERT::setButtonLabel() const
531 {
532         if (status_ == Collapsed) {
533                 setLabel(get_new_label());
534         } else {
535                 setLabel(_("ERT"));
536         }
537 }
538
539
540 bool InsetERT::checkInsertChar(LyXFont & /* font */)
541 {
542 #ifdef SET_HARD_FONT
543         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
544         font = f;
545         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
546         font.setColor(LColor::latex);
547 #endif
548         return true;
549 }
550
551
552 void InsetERT::metrics(MetricsInfo & mi, Dimension & dim) const
553 {
554         setButtonLabel();
555         if (inlined())
556                 inset.metrics(mi, dim);
557         else
558                 InsetCollapsable::metrics(mi, dim);
559         // Make it stand out on its own as it is code, not part of running
560         // text:
561         if (isOpen() && !inlined())
562                 dim.wid = mi.base.textwidth;
563         dim_ = dim;
564 }
565
566
567 void InsetERT::draw(PainterInfo & pi, int x, int y) const
568 {
569         InsetCollapsable::draw(pi, x, y, inlined());
570 }
571
572
573 void InsetERT::set_latex_font(BufferView * /* bv */)
574 {
575 #ifdef SET_HARD_FONT
576         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
577
578         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
579         font.setColor(LColor::latex);
580
581         inset.getLyXText(bv)->setFont(bv, font, false);
582 #endif
583 }
584
585
586 // attention this function can be called with bv == 0
587 void InsetERT::status(BufferView * bv, ERTStatus const st) const
588 {
589         if (st != status_) {
590                 status_ = st;
591                 switch (st) {
592                 case Inlined:
593                         break;
594                 case Open:
595                         collapsed_ = false;
596                         setButtonLabel();
597                         break;
598                 case Collapsed:
599                         collapsed_ = true;
600                         setButtonLabel();
601                         if (bv)
602                                 bv->unlockInset(const_cast<InsetERT *>(this));
603                         break;
604                 }
605                 if (bv) {
606                         bv->updateInset(this);
607                         bv->buffer()->markDirty();
608                 }
609         }
610 }
611
612
613 bool InsetERT::showInsetDialog(BufferView * bv) const
614 {
615         InsetERTMailer(const_cast<InsetERT &>(*this)).showDialog(bv);
616         return true;
617 }
618
619
620 void InsetERT::open(BufferView * bv)
621 {
622         if (!collapsed_)
623                 return;
624         status(bv, Open);
625 }
626
627
628 void InsetERT::close(BufferView * bv) const
629 {
630         if (status_ == Collapsed || status_ == Inlined)
631                 return;
632
633         status(bv, Collapsed);
634 }
635
636
637 WordLangTuple const
638 InsetERT::selectNextWordToSpellcheck(BufferView * bv, float &) const
639 {
640         bv->unlockInset(const_cast<InsetERT *>(this));
641         return WordLangTuple();
642 }
643
644
645 void InsetERT::getDrawFont(LyXFont & font) const
646 {
647         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
648         font = f;
649         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
650         font.setColor(LColor::latex);
651 }
652
653
654 string const InsetERTMailer::name_("ert");
655
656 InsetERTMailer::InsetERTMailer(InsetERT & inset)
657         : inset_(inset)
658 {}
659
660
661 string const InsetERTMailer::inset2string(Buffer const &) const
662 {
663         return params2string(inset_.status());
664 }
665
666
667 void InsetERTMailer::string2params(string const & in,
668                                    InsetERT::ERTStatus & status)
669 {
670         status = InsetERT::Collapsed;
671
672         string name;
673         string body = split(in, name, ' ');
674
675         if (body.empty())
676                 return;
677
678         status = static_cast<InsetERT::ERTStatus>(strToInt(body));
679 }
680
681
682 string const
683 InsetERTMailer::params2string(InsetERT::ERTStatus status)
684 {
685         return name_ + ' ' + tostr(status);
686 }