]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
tab-sel patch
[lyx.git] / src / insets / insetert.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *       
6  *          Copyright 1998 The LyX Team.
7  *
8  *======================================================*/
9
10 #include <config.h>
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 #include "insetert.h"
17 #include "gettext.h"
18 #include "lyxfont.h"
19 #include "language.h"
20 #include "buffer.h"
21 #include "insets/insettext.h"
22 #include "support/LOstream.h"
23 #include "lyx_gui_misc.h"
24 #include "BufferView.h"
25 #include "LyXView.h"
26 #include "lyxtext.h"
27 #include "frontends/Dialogs.h"
28 #include "frontends/Alert.h"
29 #include "debug.h"
30
31 using std::ostream;
32 using lyx::pos_type;
33
34
35 void InsetERT::init()
36 {
37         setButtonLabel();
38         labelfont = LyXFont(LyXFont::ALL_SANE);
39         labelfont.decSize();
40         labelfont.decSize();
41         labelfont.setColor(LColor::latex);
42         setInsetName("ERT");
43 }
44
45
46 InsetERT::InsetERT(bool collapsed)
47         : InsetCollapsable(collapsed)
48 {
49         if (collapsed)
50                 status_ = Collapsed;
51         else
52                 status_ = Open;
53         init();
54 }
55
56
57 InsetERT::InsetERT(InsetERT const & in, bool same_id)
58         : InsetCollapsable(in, same_id), status_(in.status_)
59 {
60         init();
61 }
62
63
64 Inset * InsetERT::clone(Buffer const &, bool same_id) const
65 {
66         return new InsetERT(*const_cast<InsetERT *>(this), same_id);
67 }
68
69
70 InsetERT::InsetERT(string const & contents, bool collapsed)
71         : InsetCollapsable(collapsed)
72 {
73         if (collapsed)
74                 status_ = Collapsed;
75         else
76                 status_ = Open;
77 #ifndef INHERIT_LANG
78         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
79 #else 
80         LyXFont font(LyXFont::ALL_INHERIT);
81 #endif
82         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
83         font.setColor(LColor::latex);
84         string::const_iterator cit = contents.begin();
85         string::const_iterator end = contents.end();
86         pos_type pos = 0;
87         for (; cit != end; ++cit) {
88                 inset.paragraph()->insertChar(pos++, *cit, font);
89         }
90         // the init has to be after the initialization of the paragraph
91         // because of the label settings (draw_label for ert insets).
92         init();
93 }
94
95
96 InsetERT::~InsetERT()
97 {
98         hideDialog();
99 }
100
101
102 void InsetERT::read(Buffer const * buf, LyXLex & lex)
103 {
104         bool token_found = false;
105         if (lex.isOK()) {
106                 lex.next();
107                 string const token = lex.getString();
108                 if (token == "status") {
109                         lex.next();
110                         string const tmp_token = lex.getString();
111                         
112                         if (tmp_token == "Inlined") {
113                                 status(0, Inlined);
114                         } else if (tmp_token == "Collapsed") {
115                                 status(0, Collapsed);
116                         } else {
117                                 // leave this as default!
118                                 status(0, Open);
119                         }
120                         
121                         token_found = true;
122                 } else {
123                         lyxerr << "InsetERT::Read: Missing 'status'-tag!"
124                                    << std::endl;
125                         // take countermeasures
126                         lex.pushToken(token);
127                 }
128         }
129 #warning this should be really short lived only for compatibility to
130 #warning files written 07/08/2001 so this has to go before 1.2.0! (Jug)
131         if (lex.isOK()) {
132                 lex.next();
133                 string const token = lex.getString();
134                 if (token == "collapsed") {
135                         lex.next();
136                         collapsed_ = lex.getBool();
137                 } else {
138                         // Take countermeasures
139                         lex.pushToken(token);
140                 }
141         }
142         inset.read(buf, lex);
143
144 #ifndef INHERIT_LANG
145         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
146 #else 
147         LyXFont font(LyXFont::ALL_INHERIT);
148 #endif
149
150         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
151         font.setColor(LColor::latex);
152         Paragraph * par = inset.paragraph();
153         while (par) {
154                 pos_type siz = par->size();
155                 for (pos_type i = 0; i < siz; ++i) {
156                         par->setFont(i, font);
157                 }
158                 par = par->next();
159         }
160
161         if (!token_found) {
162                 if (collapsed_) {
163                         status(0, Collapsed);
164                 } else {
165                         status(0, Open);
166                 }
167         }
168         setButtonLabel();
169 }
170
171
172 void InsetERT::write(Buffer const * buf, ostream & os) const 
173 {
174         string st;
175
176         switch(status_) {
177         case Open: 
178                 st = "Open";
179                 break;
180         case Collapsed:
181                 st = "Collapsed";
182                 break;
183         case Inlined:
184                 st = "Inlined";
185                 break;
186         }
187
188         os << getInsetName() << "\n"
189            << "status "<< st << "\n";
190
191         //inset.writeParagraphData(buf, os);
192         string const layout =
193                 textclasslist.NameOfLayout(buf->params.textclass, 0);
194         Paragraph * par = inset.paragraph();
195         while (par) {
196                 os << "\n\\layout " << layout << "\n";
197                 pos_type siz = par->size();
198                 for (pos_type i = 0; i < siz; ++i) {
199                         Paragraph::value_type c = par->getChar(i);
200                         switch (c) {
201                         case Paragraph::META_INSET:
202                         case Paragraph::META_HFILL:
203                                 lyxerr << "Element is not allowed in insertERT"
204                                        << std::endl;
205                         case Paragraph::META_NEWLINE:
206                                 os << "\n\\newline \n";
207                                 break;
208                         case '\\':
209                                 os << "\n\\backslash \n";
210                                 break;
211                         default:
212                                 os << c;
213                                 break;
214                         }
215                 }
216                 par = par->next();
217         }
218 }
219
220
221 string const InsetERT::editMessage() const 
222 {
223         return _("Opened ERT Inset");
224 }
225
226
227 bool InsetERT::insertInset(BufferView *, Inset *)
228 {
229         return false;
230 }
231
232
233 void InsetERT::setFont(BufferView *, LyXFont const &, bool, bool selectall)
234 {
235         // if selectall is activated then the fontchange was an outside general
236         // fontchange and this messages is not needed
237         if (!selectall)
238                 Alert::alert(_("Impossible Operation!"),
239                            _("Not permitted to change font-types inside ERT-insets!"),
240                            _("Sorry."));
241 }
242
243
244 void InsetERT::updateStatus(BufferView * bv, bool swap) const
245 {
246         if (status_ != Inlined) {
247                 if (collapsed_) {
248                         status(bv, swap ? Open : Collapsed);
249                 } else {
250                         status(bv, swap ? Collapsed : Open);
251                 }
252         }
253 }
254
255  
256 void InsetERT::edit(BufferView * bv, int x, int y, unsigned int button)
257 {
258         if (button == 3)
259                 return;
260  
261         InsetCollapsable::edit(bv, x, y, button);
262         updateStatus(0);
263         set_latex_font(bv);
264 }
265
266
267 Inset::EDITABLE InsetERT::editable() const
268 {
269         if (status_ == Collapsed)
270                 return IS_EDITABLE;
271         return HIGHLY_EDITABLE;
272 }
273
274
275 void InsetERT::edit(BufferView * bv, bool front)
276 {
277         InsetCollapsable::edit(bv, front);
278         updateStatus(0);
279         set_latex_font(bv);
280 }
281
282
283 void InsetERT::insetButtonRelease(BufferView * bv, int x, int y, int button)
284 {
285         if (button == 3) {
286                 showInsetDialog(bv);
287                 return;
288         }
289  
290         if (status_ != Inlined && (x >= 0)  && (x < button_length) &&
291             (y >= button_top_y) &&  (y <= button_bottom_y)) {
292                 updateStatus(bv, true);
293         } else {
294                 LyXFont font(LyXFont::ALL_SANE);
295                 int yy = ascent(bv, font) + y - inset.ascent(bv, font);
296  
297                 // inlined is special - the text appears above 
298                 // button_bottom_y
299                 if (status_ == Inlined) {
300                         inset.insetButtonRelease(bv, x, yy, button);
301                 } else if (!collapsed_ && (y > button_bottom_y)) {
302                         yy -= (ascent_collapsed() + descent_collapsed());
303                         inset.insetButtonRelease(bv, x, yy, button);
304                 }
305         }
306 }
307
308
309 int InsetERT::latex(Buffer const *, std::ostream & os, bool /*fragile*/,
310                     bool /*free_spc*/) const
311 {
312         Paragraph * par = inset.paragraph();
313         int lines = 0;
314         while (par) {
315                 pos_type siz = par->size();
316                 for (pos_type i = 0; i < siz; ++i) {
317                         Paragraph::value_type c = par->getChar(i);
318                         switch (c) {
319                         case Paragraph::META_NEWLINE:
320                                 os << '\n';
321                                 ++lines;
322                                 break;
323                         default:
324                                 os << c;
325                                 break;
326                         }
327                 }
328                 par = par->next();
329                 if (par) {
330                         os << "\n\n";
331                         lines += 2;
332                 }
333         }
334         
335         return lines;
336 }
337
338
339 int InsetERT::ascii(Buffer const *,
340                     std::ostream &, int /*linelen*/) const 
341 {
342         return 0;
343 }
344
345
346 int InsetERT::linuxdoc(Buffer const *, std::ostream & os) const
347 {
348         Paragraph * par = inset.paragraph();
349         int lines = 0;
350         while (par) {
351                 pos_type siz = par->size();
352                 for (pos_type i = 0; i < siz; ++i) {
353                         Paragraph::value_type c = par->getChar(i);
354                         switch (c) {
355                         case Paragraph::META_NEWLINE:
356                                 os << '\n';
357                                 ++lines;
358                                 break;
359                         default:
360                                 os << c;
361                                 break;
362                         }
363                 }
364                 par = par->next();
365                 if (par) {
366                         os << "\n";
367                         lines ++;
368                 }
369         }
370         
371         return lines;
372 }
373
374
375 int InsetERT::docbook(Buffer const *, std::ostream & os) const
376 {
377         Paragraph * par = inset.paragraph();
378         int lines = 0;
379         while (par) {
380                 pos_type siz = par->size();
381                 for (pos_type i = 0; i < siz; ++i) {
382                         Paragraph::value_type c = par->getChar(i);
383                         switch (c) {
384                         case Paragraph::META_NEWLINE:
385                                 os << '\n';
386                                 ++lines;
387                                 break;
388                         default:
389                                 os << c;
390                                 break;
391                         }
392                 }
393                 par = par->next();
394                 if (par) {
395                         os << "\n";
396                         lines ++;
397                 }
398         }
399         
400         return lines;
401 }
402
403
404 UpdatableInset::RESULT
405 InsetERT::localDispatch(BufferView * bv, kb_action action, string const & arg)
406 {
407         UpdatableInset::RESULT result = DISPATCHED_NOUPDATE;
408
409         if (!inset.paragraph()->size()) {
410                 set_latex_font(bv);
411         }
412
413         switch(action) {
414         case LFUN_LAYOUT:
415                 bv->owner()->setLayout(inset.paragraph()->getLayout());
416                 break;
417         default:
418                 result = InsetCollapsable::localDispatch(bv, action, arg);
419         }
420         switch(action) {
421         case LFUN_BREAKPARAGRAPH:
422         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
423         case LFUN_BACKSPACE:
424         case LFUN_BACKSPACE_SKIP:
425         case LFUN_DELETE:
426         case LFUN_DELETE_SKIP:
427         case LFUN_DELETE_LINE_FORWARD:
428         case LFUN_CUT:
429                 set_latex_font(bv);
430                 break;
431         
432         default:
433                 break;
434         }
435         return result;
436 }
437
438
439 string const InsetERT::get_new_label() const
440 {
441         string la;
442         pos_type const max_length = 15;
443         pos_type const p_siz = inset.paragraph()->size();
444         pos_type const n = std::min(max_length, p_siz);
445         int i = 0;
446         int j = 0;
447         for(; i < n && j < p_siz; ++j) {
448                 if (inset.paragraph()->isInset(j))
449                         continue;
450                 la += inset.paragraph()->getChar(j);
451                 ++i;
452         }
453         if (i > 0 && j < p_siz) {
454                 la += "...";
455         }
456         if (la.empty()) {
457                 la = _("ERT");
458         }
459         return la;
460 }
461
462
463 void InsetERT::setButtonLabel() const
464 {
465         if (status_ == Collapsed) {
466                 setLabel(get_new_label());
467         } else {
468                 setLabel(_("ERT"));
469         }
470 }
471
472
473 bool InsetERT::checkInsertChar(LyXFont & font)
474 {
475 #ifndef INHERIT_LANG
476         LyXFont f(LyXFont::ALL_INHERIT, latex_language);
477 #else 
478         LyXFont f(LyXFont::ALL_INHERIT);
479 #endif
480         font = f;
481         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
482         font.setColor(LColor::latex);
483         return true;
484 }
485
486
487 int InsetERT::ascent(BufferView * bv, LyXFont const & font) const
488 {
489         if (!inlined())
490                 return InsetCollapsable::ascent(bv, font);
491
492         return inset.ascent(bv, font);
493 }
494
495
496 int InsetERT::descent(BufferView * bv, LyXFont const & font) const
497 {
498         if (!inlined())
499                 return InsetCollapsable::descent(bv, font);
500
501         return inset.descent(bv, font);
502 }
503
504
505 int InsetERT::width(BufferView * bv, LyXFont const & font) const
506 {
507         if (!inlined())
508                 return InsetCollapsable::width(bv, font);
509
510         return inset.width(bv, font);
511 }
512
513
514 void InsetERT::draw(BufferView * bv, LyXFont const & f, 
515                     int baseline, float & x, bool cleared) const
516 {
517         Painter & pain = bv->painter();
518
519         button_length = width_collapsed();
520         button_top_y = -ascent(bv, f);
521         button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
522                 descent_collapsed();
523
524         if (!isOpen()) {
525                 draw_collapsed(pain, baseline, x);
526                 x += TEXT_TO_INSET_OFFSET;
527                 return;
528         }
529
530         float old_x = x;
531
532         if (!owner())
533                 x += static_cast<float>(scroll());
534
535         if (!cleared && (inset.need_update == InsetText::FULL ||
536                          inset.need_update == InsetText::INIT ||
537                          top_x != int(x) ||
538                          top_baseline != baseline))
539         {
540                 // we don't need anymore to clear here we just have to tell
541                 // the underlying LyXText that it should do the RowClear!
542                 inset.setUpdateStatus(bv, InsetText::FULL);
543                 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
544                 return;
545         }
546
547         top_x = int(x);
548         topx_set = true;
549         top_baseline = baseline;
550
551         int const bl = baseline - ascent(bv, f) + ascent_collapsed();
552
553         if (inlined()) {
554                 inset.draw(bv, f, baseline, x, cleared);
555         } else {
556                 draw_collapsed(pain, bl, old_x);
557                 inset.draw(bv, f, 
558                                    bl + descent_collapsed() + inset.ascent(bv, f),
559                                    x, cleared);
560         }
561         need_update = NONE;
562 }
563
564
565 void InsetERT::set_latex_font(BufferView * bv)
566 {
567 #ifndef INHERIT_LANG
568         LyXFont font(LyXFont::ALL_INHERIT, latex_language);
569 #else 
570         LyXFont font(LyXFont::ALL_INHERIT);
571 #endif
572
573         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
574         font.setColor(LColor::latex);
575         inset.getLyXText(bv)->setFont(bv, font, false);
576 }
577
578
579 void InsetERT::status(BufferView * bv, ERTStatus const st) const
580 {
581         if (st != status_) {
582                 status_ = st;
583                 switch(st) {
584                 case Inlined:
585                         inset.setAutoBreakRows(false);
586                         break;
587                 case Open:
588                         inset.setAutoBreakRows(true);
589                         collapsed_ = false;
590                         need_update = FULL;
591                         setButtonLabel();
592                         break;
593                 case Collapsed:
594                         inset.setAutoBreakRows(true);
595                         collapsed_ = true;
596                         need_update = FULL;
597                         setButtonLabel();
598                         if (bv)
599                                 bv->unlockInset(const_cast<InsetERT *>(this));
600                         break;
601                 }
602                 if (bv)
603                         bv->updateInset(const_cast<InsetERT *>(this), false);
604         }
605 }
606
607
608 bool InsetERT::showInsetDialog(BufferView * bv) const
609 {
610         bv->owner()->getDialogs()->showERT(const_cast<InsetERT *>(this));
611         return true;
612 }
613
614
615 void InsetERT::open(BufferView * bv)
616 {
617         if (!collapsed_)
618                 return;
619         status(bv, Open);
620 }
621
622
623 void InsetERT::close(BufferView * bv) const
624 {
625         if (collapsed_)
626                 return;
627         status(bv, Collapsed);
628 }
629
630
631 string const InsetERT::selectNextWordToSpellcheck(BufferView * bv,float &) const
632 {
633         bv->unlockInset(const_cast<InsetERT *>(this));
634         return string();
635 }