]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
setFont rework + some code simplification
[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(Inlined);
123                         } else if (tmp_token == "Collapsed") {
124                                 status(Collapsed);
125                         } else {
126                                 // leave this as default!
127                                 status(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(Open);
158                 else
159                         status(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::updateStatus(bool swap) const
228 {
229         if (status_ != Inlined) {
230                 if (isOpen())
231                         status(swap ? Collapsed : Open);
232                 else
233                         status(swap ? Open : Collapsed);
234         }
235 }
236
237
238 InsetOld::EDITABLE InsetERT::editable() const
239 {
240         return (status_ == Collapsed) ? IS_EDITABLE : HIGHLY_EDITABLE;
241 }
242
243
244 void InsetERT::lfunMousePress(FuncRequest const & cmd)
245 {
246         if (status_ == Inlined)
247                 inset.dispatch(cmd);
248         else {
249                 idx_type idx = 0;
250                 pos_type pos = 0;
251                 InsetCollapsable::priv_dispatch(cmd, idx, pos);
252         }
253 }
254
255
256 bool InsetERT::lfunMouseRelease(FuncRequest const & cmd)
257 {
258         BufferView * bv = cmd.view();
259
260         if (cmd.button() == mouse_button::button3) {
261                 showInsetDialog(bv);
262                 return true;
263         }
264
265         if (status_ != Inlined && hitButton(cmd)) {
266                 updateStatus(true);
267         } else {
268                 FuncRequest cmd1 = cmd;
269 #warning metrics?
270                 cmd1.y = ascent() + cmd.y - inset.ascent();
271
272                 // inlined is special - the text appears above
273                 if (status_ == Inlined)
274                         inset.dispatch(cmd1);
275                 else if (isOpen() && cmd.y > buttonDim().y2) {
276                         cmd1.y -= height_collapsed();
277                         inset.dispatch(cmd1);
278                 }
279         }
280         return false;
281 }
282
283
284 void InsetERT::lfunMouseMotion(FuncRequest const & cmd)
285 {
286         if (status_ == Inlined)
287                 inset.dispatch(cmd);
288         else {
289                 idx_type idx = 0;
290                 pos_type pos = 0;
291                 InsetCollapsable::priv_dispatch(cmd, idx, pos);
292         }
293 }
294
295
296 int InsetERT::latex(Buffer const &, ostream & os,
297                     OutputParams const &) const
298 {
299         ParagraphList::iterator par = inset.paragraphs.begin();
300         ParagraphList::iterator end = inset.paragraphs.end();
301
302         int lines = 0;
303         while (par != end) {
304                 pos_type siz = par->size();
305                 for (pos_type i = 0; i < siz; ++i) {
306                         // ignore all struck out text
307                         if (isDeletedText(*par, i))
308                                 continue;
309
310                         if (par->isNewline(i)) {
311                                 os << '\n';
312                                 ++lines;
313                         } else {
314                                 os << par->getChar(i);
315                         }
316                 }
317                 ++par;
318                 if (par != end) {
319                         os << "\n";
320                         ++lines;
321                 }
322         }
323
324         return lines;
325 }
326
327
328 int InsetERT::plaintext(Buffer const &, ostream &,
329                     OutputParams const & /*runparams*/) const
330 {
331         return 0;
332 }
333
334
335 int InsetERT::linuxdoc(Buffer const &, ostream & os,
336                        OutputParams const &)const
337 {
338         ParagraphList::iterator par = inset.paragraphs.begin();
339         ParagraphList::iterator end = inset.paragraphs.end();
340
341         int lines = 0;
342         while (par != end) {
343                 pos_type siz = par->size();
344                 for (pos_type i = 0; i < siz; ++i) {
345                         if (par->isNewline(i)) {
346                                 os << '\n';
347                                 ++lines;
348                         } else {
349                                 os << par->getChar(i);
350                         }
351                 }
352                 ++par;
353                 if (par != end) {
354                         os << "\n";
355                         lines ++;
356                 }
357         }
358
359         return lines;
360 }
361
362
363 int InsetERT::docbook(Buffer const &, ostream & os,
364                       OutputParams const &) 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 void InsetERT::edit(BufferView * bv, bool left)
392 {
393         if (status_ == Inlined) {
394                 inset.edit(bv, left);
395         } else {
396                 InsetCollapsable::edit(bv, left);
397         }
398         setLatexFont(bv);
399         updateStatus();
400 }
401
402
403 DispatchResult
404 InsetERT::priv_dispatch(FuncRequest const & cmd, idx_type & idx, pos_type & pos)
405 {
406         BufferView * bv = cmd.view();
407
408         if (inset.paragraphs.begin()->empty())
409                 setLatexFont(bv);
410
411         switch (cmd.action) {
412
413         case LFUN_INSET_MODIFY: {
414                 InsetERT::ERTStatus status_;
415                 InsetERTMailer::string2params(cmd.argument, status_);
416                 status(status_);
417                 bv->update();
418                 return DispatchResult(true, true);
419         }
420
421         case LFUN_MOUSE_PRESS:
422                 lfunMousePress(cmd);
423                 return DispatchResult(true, true);
424
425         case LFUN_MOUSE_MOTION:
426                 lfunMouseMotion(cmd);
427                 return DispatchResult(true, true);
428
429         case LFUN_MOUSE_RELEASE:
430                 lfunMouseRelease(cmd);
431                 return DispatchResult(true, true);
432
433         case LFUN_LAYOUT:
434                 bv->owner()->setLayout(inset.paragraphs.begin()->layout()->name());
435                 return DispatchResult(true);
436
437         case LFUN_BREAKPARAGRAPH:
438         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
439         case LFUN_BACKSPACE:
440         case LFUN_BACKSPACE_SKIP:
441         case LFUN_DELETE:
442         case LFUN_DELETE_SKIP:
443         case LFUN_DELETE_LINE_FORWARD:
444         case LFUN_CUT:
445                 setLatexFont(bv);
446                 return InsetCollapsable::priv_dispatch(cmd, idx, pos);
447
448         default:
449                 return InsetCollapsable::priv_dispatch(cmd, idx, pos);
450         }
451 }
452
453
454 string const InsetERT::getNewLabel() const
455 {
456         string la;
457         pos_type const max_length = 15;
458         pos_type const p_siz = inset.paragraphs.begin()->size();
459         pos_type const n = min(max_length, p_siz);
460         pos_type i = 0;
461         pos_type j = 0;
462         for( ; i < n && j < p_siz; ++j) {
463                 if (inset.paragraphs.begin()->isInset(j))
464                         continue;
465                 la += inset.paragraphs.begin()->getChar(j);
466                 ++i;
467         }
468         if (inset.paragraphs.size() > 1 || (i > 0 && j < p_siz)) {
469                 la += "...";
470         }
471         if (la.empty()) {
472                 la = _("ERT");
473         }
474         return la;
475 }
476
477
478 void InsetERT::setButtonLabel() const
479 {
480         setLabel(status_ == Collapsed ? getNewLabel() : _("ERT"));
481 }
482
483
484 bool InsetERT::checkInsertChar(LyXFont & /* font */)
485 {
486 #ifdef SET_HARD_FONT
487         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
488         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
489         font.setColor(LColor::latex);
490 #endif
491         return true;
492 }
493
494
495 void InsetERT::metrics(MetricsInfo & mi, Dimension & dim) const
496 {
497         setButtonLabel();
498         if (inlined())
499                 inset.metrics(mi, dim);
500         else
501                 InsetCollapsable::metrics(mi, dim);
502         // Make it stand out on its own as it is code, not part of running
503         // text:
504         if (isOpen() && !inlined())
505                 dim.wid = mi.base.textwidth;
506         dim_ = dim;
507 }
508
509
510 void InsetERT::draw(PainterInfo & pi, int x, int y) const
511 {
512         InsetCollapsable::draw(pi, x, y, inlined());
513 }
514
515
516 void InsetERT::setLatexFont(BufferView * /*bv*/)
517 {
518 #ifdef SET_HARD_FONT
519         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
520         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
521         font.setColor(LColor::latex);
522         inset.text_.setFont(bv, font, false);
523 #endif
524 }
525
526
527 void InsetERT::status(ERTStatus const st) const
528 {
529         if (st == status_)
530                 return;
531
532         status_ = st;
533
534         switch (st) {
535         case Inlined:
536                 break;
537         case Open:
538                 setCollapsed(false);
539                 setButtonLabel();
540                 break;
541         case Collapsed:
542                 setCollapsed(true);
543                 setButtonLabel();
544                 break;
545         }
546 }
547
548
549 bool InsetERT::showInsetDialog(BufferView * bv) const
550 {
551         InsetERTMailer(const_cast<InsetERT &>(*this)).showDialog(bv);
552         return true;
553 }
554
555
556 void InsetERT::open()
557 {
558         if (!isOpen())
559                 status(Open);
560 }
561
562
563 void InsetERT::close() const
564 {
565         if (status_ == Collapsed || status_ == Inlined)
566                 return;
567
568         status(Collapsed);
569 }
570
571
572 void InsetERT::getDrawFont(LyXFont & font) const
573 {
574         font = LyXFont(LyXFont::ALL_INHERIT, latex_language);
575         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
576         font.setColor(LColor::latex);
577 }
578
579
580 string const InsetERTMailer::name_("ert");
581
582 InsetERTMailer::InsetERTMailer(InsetERT & inset)
583         : inset_(inset)
584 {}
585
586
587 string const InsetERTMailer::inset2string(Buffer const &) const
588 {
589         return params2string(inset_.status());
590 }
591
592
593 void InsetERTMailer::string2params(string const & in,
594                                    InsetERT::ERTStatus & status)
595 {
596         status = InsetERT::Collapsed;
597
598         string name;
599         string body = split(in, name, ' ');
600
601         if (body.empty())
602                 return;
603
604         status = static_cast<InsetERT::ERTStatus>(strToInt(body));
605 }
606
607
608 string const InsetERTMailer::params2string(InsetERT::ERTStatus status)
609 {
610         return name_ + ' ' + tostr(status);
611 }