]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
03cd6fee2465a1725b70144f96bf391b40ca92bc
[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
12 #include <config.h>
13
14 #include "insetert.h"
15
16 #include "buffer.h"
17 #include "bufferparams.h"
18 #include "BufferView.h"
19 #include "debug.h"
20 #include "dispatchresult.h"
21 #include "funcrequest.h"
22 #include "gettext.h"
23 #include "language.h"
24 #include "LColor.h"
25 #include "lyxlex.h"
26 #include "metricsinfo.h"
27 #include "paragraph.h"
28
29 #include "frontends/Alert.h"
30 #include "frontends/LyXView.h"
31
32 #include "support/tostr.h"
33
34 using lyx::pos_type;
35
36 using lyx::support::split;
37 using lyx::support::strToInt;
38
39 using std::endl;
40 using std::min;
41 using std::string;
42 using std::auto_ptr;
43 using std::ostream;
44
45
46 void InsetERT::init()
47 {
48         setButtonLabel();
49
50         LyXFont font(LyXFont::ALL_SANE);
51         font.decSize();
52         font.decSize();
53         font.setColor(LColor::latex);
54         setLabelFont(font);
55
56         setInsetName("ERT");
57 }
58
59
60 InsetERT::InsetERT(BufferParams const & bp, bool collapsed)
61         : InsetCollapsable(bp, collapsed)
62 {
63         status_ = collapsed ? Collapsed : Open;
64         init();
65 }
66
67
68 InsetERT::InsetERT(InsetERT const & in)
69         : InsetCollapsable(in), status_(in.status_)
70 {
71         init();
72 }
73
74
75 auto_ptr<InsetBase> InsetERT::clone() const
76 {
77         return auto_ptr<InsetBase>(new InsetERT(*this));
78 }
79
80
81 InsetERT::InsetERT(BufferParams const & bp,
82                    Language const * l, string const & contents, bool collapsed)
83         : InsetCollapsable(bp, collapsed)
84 {
85         status_ = collapsed ? Collapsed : 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         inset.read(buf, lex);
139
140 #ifdef SET_HARD_FONT
141         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
142         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
143         font.setColor(LColor::latex);
144
145         ParagraphList::iterator pit = inset.paragraphs.begin();
146         ParagraphList::iterator pend = inset.paragraphs.end();
147         for (; pit != pend; ++pit) {
148                 pos_type siz = pit->size();
149                 for (pos_type i = 0; i < siz; ++i) {
150                         pit->setFont(i, font);
151                 }
152         }
153 #endif
154
155         if (!token_found) {
156                 if (isOpen())
157                         status(0, Open);
158                 else
159                         status(0, Collapsed);
160         }
161         setButtonLabel();
162 }
163
164
165 void InsetERT::write(Buffer const & buf, ostream & os) const
166 {
167         string st;
168
169         switch (status_) {
170         case Open:
171                 st = "Open";
172                 break;
173         case Collapsed:
174                 st = "Collapsed";
175                 break;
176         case Inlined:
177                 st = "Inlined";
178                 break;
179         }
180
181         os << getInsetName() << "\n" << "status "<< st << "\n";
182
183         //inset.writeParagraphData(buf, os);
184         string const layout(buf.params().getLyXTextClass().defaultLayoutName());
185         ParagraphList::iterator par = inset.paragraphs.begin();
186         ParagraphList::iterator end = inset.paragraphs.end();
187         for (; par != end; ++par) {
188                 os << "\n\\begin_layout " << layout << "\n";
189                 pos_type siz = par->size();
190                 for (pos_type i = 0; i < siz; ++i) {
191                         Paragraph::value_type c = par->getChar(i);
192                         switch (c) {
193                         case Paragraph::META_INSET:
194                                 if (par->getInset(i)->lyxCode() != InsetOld::NEWLINE_CODE) {
195                                         lyxerr << "Element is not allowed in insertERT"
196                                                << endl;
197                                 } else {
198                                         par->getInset(i)->write(buf, os);
199                                 }
200                                 break;
201
202                         case '\\':
203                                 os << "\n\\backslash \n";
204                                 break;
205                         default:
206                                 os << c;
207                                 break;
208                         }
209                 }
210                 os << "\n\\end_layout\n";
211         }
212 }
213
214
215 string const InsetERT::editMessage() const
216 {
217         return _("Opened ERT Inset");
218 }
219
220
221 bool InsetERT::insertInset(BufferView *, InsetOld *)
222 {
223         return false;
224 }
225
226
227 void InsetERT::setFont(BufferView *, LyXFont const &, bool, bool selectall)
228 {
229 #ifdef WITH_WARNINGS
230 #warning FIXME. More UI stupidity...
231 #endif
232         // if selectall is activated then the fontchange was an outside general
233         // fontchange and this messages is not needed
234         if (!selectall)
235                 Alert::error(_("Cannot change font"),
236                            _("You cannot change font settings inside TeX code."));
237 }
238
239
240 void InsetERT::updateStatus(BufferView * bv, bool swap) const
241 {
242         if (status_ != Inlined) {
243                 if (isOpen())
244                         status(bv, swap ? Collapsed : Open);
245                 else
246                         status(bv, swap ? Open : Collapsed);
247         }
248 }
249
250
251 InsetOld::EDITABLE InsetERT::editable() const
252 {
253         return (status_ == Collapsed) ? IS_EDITABLE : HIGHLY_EDITABLE;
254 }
255
256
257 void InsetERT::lfunMousePress(FuncRequest const & cmd)
258 {
259         if (status_ == Inlined)
260                 inset.dispatch(cmd);
261         else {
262                 idx_type idx = 0;
263                 pos_type pos = 0;
264                 InsetCollapsable::priv_dispatch(cmd, idx, pos);
265         }
266 }
267
268
269 bool InsetERT::lfunMouseRelease(FuncRequest const & cmd)
270 {
271         BufferView * bv = cmd.view();
272
273         if (cmd.button() == mouse_button::button3) {
274                 showInsetDialog(bv);
275                 return true;
276         }
277
278         if (status_ != Inlined && hitButton(cmd)) {
279                 updateStatus(bv, true);
280         } else {
281                 FuncRequest cmd1 = cmd;
282 #warning metrics?
283                 cmd1.y = ascent() + cmd.y - inset.ascent();
284
285                 // inlined is special - the text appears above
286                 if (status_ == Inlined)
287                         inset.dispatch(cmd1);
288                 else if (isOpen() && cmd.y > buttonDim().y2) {
289                         cmd1.y -= height_collapsed();
290                         inset.dispatch(cmd1);
291                 }
292         }
293         return false;
294 }
295
296
297 void InsetERT::lfunMouseMotion(FuncRequest const & cmd)
298 {
299         if (status_ == Inlined)
300                 inset.dispatch(cmd);
301         else {
302                 idx_type idx = 0;
303                 pos_type pos = 0;
304                 InsetCollapsable::priv_dispatch(cmd, idx, pos);
305         }
306 }
307
308
309 int InsetERT::latex(Buffer const &, ostream & os,
310                     OutputParams const &) const
311 {
312         ParagraphList::iterator par = inset.paragraphs.begin();
313         ParagraphList::iterator end = inset.paragraphs.end();
314
315         int lines = 0;
316         while (par != end) {
317                 pos_type siz = par->size();
318                 for (pos_type i = 0; i < siz; ++i) {
319                         // ignore all struck out text
320                         if (isDeletedText(*par, i))
321                                 continue;
322
323                         if (par->isNewline(i)) {
324                                 os << '\n';
325                                 ++lines;
326                         } else {
327                                 os << par->getChar(i);
328                         }
329                 }
330                 ++par;
331                 if (par != end) {
332                         os << "\n";
333                         ++lines;
334                 }
335         }
336
337         return lines;
338 }
339
340
341 int InsetERT::plaintext(Buffer const &, ostream &,
342                     OutputParams const & /*runparams*/) const
343 {
344         return 0;
345 }
346
347
348 int InsetERT::linuxdoc(Buffer const &, ostream & os,
349                        OutputParams const &)const
350 {
351         ParagraphList::iterator par = inset.paragraphs.begin();
352         ParagraphList::iterator end = inset.paragraphs.end();
353
354         int lines = 0;
355         while (par != end) {
356                 pos_type siz = par->size();
357                 for (pos_type i = 0; i < siz; ++i) {
358                         if (par->isNewline(i)) {
359                                 os << '\n';
360                                 ++lines;
361                         } else {
362                                 os << par->getChar(i);
363                         }
364                 }
365                 ++par;
366                 if (par != end) {
367                         os << "\n";
368                         lines ++;
369                 }
370         }
371
372         return lines;
373 }
374
375
376 int InsetERT::docbook(Buffer const &, ostream & os,
377                       OutputParams const &) const
378 {
379         ParagraphList::iterator par = inset.paragraphs.begin();
380         ParagraphList::iterator end = inset.paragraphs.end();
381
382         int lines = 0;
383         while (par != end) {
384                 pos_type siz = par->size();
385                 for (pos_type i = 0; i < siz; ++i) {
386                         if (par->isNewline(i)) {
387                                 os << '\n';
388                                 ++lines;
389                         } else {
390                                 os << par->getChar(i);
391                         }
392                 }
393                 ++par;
394                 if (par != end) {
395                         os << "\n";
396                         lines ++;
397                 }
398         }
399
400         return lines;
401 }
402
403
404 void InsetERT::edit(BufferView * bv, bool left)
405 {
406         if (status_ == Inlined) {
407                 inset.edit(bv, left);
408         } else {
409                 InsetCollapsable::edit(bv, left);
410         }
411         set_latex_font(bv);
412         updateStatus(bv);
413 }
414
415
416 DispatchResult
417 InsetERT::priv_dispatch(FuncRequest const & cmd, idx_type & idx, pos_type & pos)
418 {
419         BufferView * bv = cmd.view();
420
421         if (inset.paragraphs.begin()->empty())
422                 set_latex_font(bv);
423
424         switch (cmd.action) {
425
426         case LFUN_INSET_MODIFY: {
427                 InsetERT::ERTStatus status_;
428                 InsetERTMailer::string2params(cmd.argument, status_);
429                 status(bv, status_);
430                 bv->updateInset(this);
431                 return DispatchResult(true, true);
432         }
433
434         case LFUN_MOUSE_PRESS:
435                 lfunMousePress(cmd);
436                 return DispatchResult(true, true);
437
438         case LFUN_MOUSE_MOTION:
439                 lfunMouseMotion(cmd);
440                 return DispatchResult(true, true);
441
442         case LFUN_MOUSE_RELEASE:
443                 lfunMouseRelease(cmd);
444                 return DispatchResult(true, true);
445
446         case LFUN_LAYOUT:
447                 bv->owner()->setLayout(inset.paragraphs.begin()->layout()->name());
448                 return DispatchResult(true);
449
450         case LFUN_BREAKPARAGRAPH:
451         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
452         case LFUN_BACKSPACE:
453         case LFUN_BACKSPACE_SKIP:
454         case LFUN_DELETE:
455         case LFUN_DELETE_SKIP:
456         case LFUN_DELETE_LINE_FORWARD:
457         case LFUN_CUT:
458                 set_latex_font(bv);
459                 return InsetCollapsable::priv_dispatch(cmd, idx, pos);
460
461         default:
462                 return InsetCollapsable::priv_dispatch(cmd, idx, pos);
463         }
464 }
465
466
467 string const InsetERT::get_new_label() const
468 {
469         string la;
470         pos_type const max_length = 15;
471         pos_type const p_siz = inset.paragraphs.begin()->size();
472         pos_type const n = min(max_length, p_siz);
473         pos_type i = 0;
474         pos_type j = 0;
475         for( ; i < n && j < p_siz; ++j) {
476                 if (inset.paragraphs.begin()->isInset(j))
477                         continue;
478                 la += inset.paragraphs.begin()->getChar(j);
479                 ++i;
480         }
481         if (inset.paragraphs.size() > 1 || (i > 0 && j < p_siz)) {
482                 la += "...";
483         }
484         if (la.empty()) {
485                 la = _("ERT");
486         }
487         return la;
488 }
489
490
491 void InsetERT::setButtonLabel() const
492 {
493         setLabel(status_ == Collapsed ? get_new_label() : _("ERT"));
494 }
495
496
497 bool InsetERT::checkInsertChar(LyXFont & /* font */)
498 {
499 #ifdef SET_HARD_FONT
500         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
501         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
502         font.setColor(LColor::latex);
503 #endif
504         return true;
505 }
506
507
508 void InsetERT::metrics(MetricsInfo & mi, Dimension & dim) const
509 {
510         setButtonLabel();
511         if (inlined())
512                 inset.metrics(mi, dim);
513         else
514                 InsetCollapsable::metrics(mi, dim);
515         // Make it stand out on its own as it is code, not part of running
516         // text:
517         if (isOpen() && !inlined())
518                 dim.wid = mi.base.textwidth;
519         dim_ = dim;
520 }
521
522
523 void InsetERT::draw(PainterInfo & pi, int x, int y) const
524 {
525         InsetCollapsable::draw(pi, x, y, inlined());
526 }
527
528
529 void InsetERT::set_latex_font(BufferView * /*bv*/)
530 {
531 #ifdef SET_HARD_FONT
532         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
533         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
534         font.setColor(LColor::latex);
535         inset.text_.setFont(bv, font, false);
536 #endif
537 }
538
539
540 // attention this function can be called with bv == 0
541 void InsetERT::status(BufferView * bv, ERTStatus const st) const
542 {
543         if (st == status_)
544                 return;
545
546         status_ = st;
547         switch (st) {
548         case Inlined:
549                 break;
550         case Open:
551                 setCollapsed(false);
552                 setButtonLabel();
553                 break;
554         case Collapsed:
555                 setCollapsed(true);
556                 setButtonLabel();
557 #ifdef LOCK
558                 if (bv)
559                         bv->unlockInset();
560 #endif
561                 break;
562         }
563         if (bv) {
564                 bv->updateInset(this);
565                 bv->buffer()->markDirty();
566         }
567 }
568
569
570 bool InsetERT::showInsetDialog(BufferView * bv) const
571 {
572         InsetERTMailer(const_cast<InsetERT &>(*this)).showDialog(bv);
573         return true;
574 }
575
576
577 void InsetERT::open(BufferView * bv)
578 {
579         if (!isOpen())
580                 status(bv, Open);
581 }
582
583
584 void InsetERT::close(BufferView * bv) const
585 {
586         if (status_ == Collapsed || status_ == Inlined)
587                 return;
588
589         status(bv, Collapsed);
590 }
591
592
593 void InsetERT::getDrawFont(LyXFont & font) const
594 {
595         font = LyXFont(LyXFont::ALL_INHERIT, latex_language);
596         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
597         font.setColor(LColor::latex);
598 }
599
600
601 string const InsetERTMailer::name_("ert");
602
603 InsetERTMailer::InsetERTMailer(InsetERT & inset)
604         : inset_(inset)
605 {}
606
607
608 string const InsetERTMailer::inset2string(Buffer const &) const
609 {
610         return params2string(inset_.status());
611 }
612
613
614 void InsetERTMailer::string2params(string const & in,
615                                    InsetERT::ERTStatus & status)
616 {
617         status = InsetERT::Collapsed;
618
619         string name;
620         string body = split(in, name, ' ');
621
622         if (body.empty())
623                 return;
624
625         status = static_cast<InsetERT::ERTStatus>(strToInt(body));
626 }
627
628
629 string const InsetERTMailer::params2string(InsetERT::ERTStatus status)
630 {
631         return name_ + ' ' + tostr(status);
632 }