]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
Place inset content on the button when collapsed
[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 void InsetERT::setButtonLabel() const
455 {
456         setLabel(status_ == Collapsed ? getNewLabel(_("ERT")) : _("ERT"));
457 }
458
459
460 void InsetERT::metrics(MetricsInfo & mi, Dimension & dim) const
461 {
462         setButtonLabel();
463         if (inlined())
464                 inset.metrics(mi, dim);
465         else
466                 InsetCollapsable::metrics(mi, dim);
467         // Make it stand out on its own as it is code, not part of running
468         // text:
469         if (isOpen() && !inlined())
470                 dim.wid = mi.base.textwidth;
471         dim_ = dim;
472 }
473
474
475 void InsetERT::draw(PainterInfo & pi, int x, int y) const
476 {
477         InsetCollapsable::draw(pi, x, y, inlined());
478 }
479
480
481 void InsetERT::setLatexFont(BufferView * /*bv*/)
482 {
483 #ifdef SET_HARD_FONT
484         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
485         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
486         font.setColor(LColor::latex);
487         inset.text_.setFont(bv, font, false);
488 #endif
489 }
490
491
492 void InsetERT::status(ERTStatus const st) const
493 {
494         if (st == status_)
495                 return;
496
497         status_ = st;
498
499         switch (st) {
500         case Inlined:
501                 break;
502         case Open:
503                 setCollapsed(false);
504                 setButtonLabel();
505                 break;
506         case Collapsed:
507                 setCollapsed(true);
508                 setButtonLabel();
509                 break;
510         }
511 }
512
513
514 bool InsetERT::showInsetDialog(BufferView * bv) const
515 {
516         InsetERTMailer(const_cast<InsetERT &>(*this)).showDialog(bv);
517         return true;
518 }
519
520
521 void InsetERT::open()
522 {
523         if (!isOpen())
524                 status(Open);
525 }
526
527
528 void InsetERT::close() const
529 {
530         if (status_ == Collapsed || status_ == Inlined)
531                 return;
532
533         status(Collapsed);
534 }
535
536
537 void InsetERT::getDrawFont(LyXFont & font) const
538 {
539         font = LyXFont(LyXFont::ALL_INHERIT, latex_language);
540         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
541         font.setColor(LColor::latex);
542 }
543
544
545 string const InsetERTMailer::name_("ert");
546
547 InsetERTMailer::InsetERTMailer(InsetERT & inset)
548         : inset_(inset)
549 {}
550
551
552 string const InsetERTMailer::inset2string(Buffer const &) const
553 {
554         return params2string(inset_.status());
555 }
556
557
558 void InsetERTMailer::string2params(string const & in,
559                                    InsetERT::ERTStatus & status)
560 {
561         status = InsetERT::Collapsed;
562
563         string name;
564         string body = split(in, name, ' ');
565
566         if (body.empty())
567                 return;
568
569         status = static_cast<InsetERT::ERTStatus>(strToInt(body));
570 }
571
572
573 string const InsetERTMailer::params2string(InsetERT::ERTStatus status)
574 {
575         return name_ + ' ' + tostr(status);
576 }