1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1998-2001 The LyX Team.
8 * ======================================================
14 #pragma implementation
17 #include "insettext.h"
18 #include "paragraph.h"
22 #include "commandtags.h"
25 #include "BufferView.h"
26 #include "lyxtextclasslist.h"
27 #include "LaTeXFeatures.h"
30 #include "lyxcursor.h"
31 #include "CutAndPaste.h"
37 #include "trans_mgr.h"
38 #include "lyxscreen.h"
42 #include "ParagraphParameters.h"
43 #include "undo_funcs.h"
46 #include "frontends/Alert.h"
48 #include "support/textutils.h"
49 #include "support/LAssert.h"
50 #include "support/lstrings.h"
51 #include "support/lyxalgo.h" // lyx::count
68 using lyx::layout_type;
69 using lyx::textclass_type;
71 extern unsigned char getCurrentTextClass(Buffer *);
72 extern bool math_insert_greek(BufferView *, char);
73 extern int greek_kb_flag;
76 // These functions should probably go into bufferview_funcs somehow (Jug)
78 void InsetText::saveLyXTextState(LyXText * t) const
80 // check if my paragraphs are still valid
83 if (p == t->cursor.par())
88 if (p && t->cursor.pos() <= p->size()) {
89 sstate.lpar = t->cursor.par();
90 sstate.pos = t->cursor.pos();
91 sstate.boundary = t->cursor.boundary();
92 sstate.selstartpar = t->selection.start.par();
93 sstate.selstartpos = t->selection.start.pos();
94 sstate.selstartboundary = t->selection.start.boundary();
95 sstate.selendpar = t->selection.end.par();
96 sstate.selendpos = t->selection.end.pos();
97 sstate.selendboundary = t->selection.end.boundary();
98 sstate.selection = t->selection.set();
99 sstate.mark_set = t->selection.mark();
100 sstate.refresh = t->refresh_row != 0;
106 void InsetText::restoreLyXTextState(BufferView * bv, LyXText * t) const
109 t->selection.set(true);
110 /* at this point just to avoid the Delete-Empty-Paragraph
111 * Mechanism when setting the cursor */
112 t->selection.mark(sstate.mark_set);
113 if (sstate.selection) {
114 t->setCursor(bv, sstate.selstartpar, sstate.selstartpos,
115 true, sstate.selstartboundary);
116 t->selection.cursor = t->cursor;
117 t->setCursor(bv, sstate.selendpar, sstate.selendpos,
118 true, sstate.selendboundary);
120 t->setCursor(bv, sstate.lpar, sstate.pos);
122 t->setCursor(bv, sstate.lpar, sstate.pos, true, sstate.boundary);
123 t->selection.cursor = t->cursor;
124 t->selection.set(false);
126 if (sstate.refresh) {
132 InsetText::InnerCache::InnerCache(boost::shared_ptr<LyXText> t)
139 InsetText::InsetText()
140 : UpdatableInset(), lt(0), in_update(false), do_resize(0),
148 InsetText::InsetText(InsetText const & in, bool same_id)
149 : UpdatableInset(in, same_id), lt(0), in_update(false), do_resize(0),
157 InsetText & InsetText::operator=(InsetText const & it)
164 void InsetText::init(InsetText const * ins, bool same_id)
167 setParagraphData(ins->par, same_id);
168 autoBreakRows = ins->autoBreakRows;
169 drawFrame_ = ins->drawFrame_;
170 frame_color = ins->frame_color;
176 p->setInsetOwner(this);
179 the_locking_inset = 0;
181 frame_color = LColor::insetframe;
182 autoBreakRows = false;
189 no_selection = false;
196 last_drawn_width = -1;
197 frame_is_visible = false;
200 in_insetAllowed = false;
204 InsetText::~InsetText()
211 Paragraph * tmp = par->next();
218 void InsetText::clear()
221 Paragraph * tmp = par->next();
231 Inset * InsetText::clone(Buffer const &, bool same_id) const
233 return new InsetText(*this, same_id);
237 void InsetText::write(Buffer const * buf, ostream & os) const
240 writeParagraphData(buf, os);
244 void InsetText::writeParagraphData(Buffer const * buf, ostream & os) const
246 par->writeFile(buf, os, buf->params, 0);
250 void InsetText::read(Buffer const * buf, LyXLex & lex)
254 Paragraph * return_par = 0;
255 Paragraph::depth_type depth = 0;
256 LyXFont font(LyXFont::ALL_INHERIT);
262 token = lex.getString();
265 if (token == "\\end_inset") {
266 #ifndef NO_COMPABILITY
267 const_cast<Buffer*>(buf)->insertErtContents(par, pos, false);
272 if (const_cast<Buffer*>(buf)->
273 parseSingleLyXformat2Token(lex, par, return_par,
274 token, pos, depth, font)) {
275 // the_end read this should NEVER happen
276 lex.printError("\\the_end read in inset! Error in document!");
284 return_par->setInsetOwner(this);
285 return_par = return_par->next();
288 if (token != "\\end_inset") {
289 lex.printError("Missing \\end_inset at this point. "
296 int InsetText::ascent(BufferView * bv, LyXFont const &) const
298 insetAscent = getLyXText(bv)->firstRow()->ascent_of_text() +
299 TEXT_TO_INSET_OFFSET;
304 int InsetText::descent(BufferView * bv, LyXFont const &) const
306 LyXText * llt = getLyXText(bv);
307 insetDescent = llt->height - llt->firstRow()->ascent_of_text() +
308 TEXT_TO_INSET_OFFSET;
313 int InsetText::width(BufferView * bv, LyXFont const &) const
315 insetWidth = max(textWidth(bv), (int)getLyXText(bv)->width) +
316 (2 * TEXT_TO_INSET_OFFSET);
317 insetWidth = max(insetWidth, 10);
322 int InsetText::textWidth(BufferView * bv, bool fordraw) const
325 if (!autoBreakRows) {
328 w = getMaxWidth(bv, this);
331 return max(w - (2 * TEXT_TO_INSET_OFFSET),
332 (int)getLyXText(bv)->width);
336 return w - (2 * TEXT_TO_INSET_OFFSET);
340 void InsetText::draw(BufferView * bv, LyXFont const & f,
341 int baseline, float & x, bool cleared) const
346 Painter & pain = bv->painter();
348 // this is the first thing we have to ask because if the x pos
349 // changed we have to do a complete rebreak of the text as we
350 // may have few space to draw in. Well we should check on this too
352 if (top_x != int(x)) {
355 int nw = getMaxWidth(bv, this);
356 if (nw > 0 && old_max_width != nw) {
359 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
364 // call these methods so that insetWidth, insetAscent and
365 // insetDescent have the right values.
370 // repaint the background if needed
371 if (cleared && backgroundColor() != LColor::background) {
372 clearInset(bv, baseline, cleared);
375 // no draw is necessary !!!
376 if ((drawFrame_ == LOCKED) && !locked && !par->size()) {
377 top_baseline = baseline;
379 if (need_update & CLEAR_FRAME)
380 clearFrame(pain, cleared);
387 x += static_cast<float>(scroll());
389 // if top_x differs we did it already
390 if (!cleared && (old_x == int(x))
391 && ((need_update&(INIT|FULL)) || (top_baseline != baseline)
392 ||(last_drawn_width != insetWidth)))
394 // Condition necessary to eliminate bug 59 attachment 37
396 clearInset(bv, baseline, cleared);
400 frame_is_visible = false;
402 if (!cleared && (need_update == NONE)) {
404 drawFrame(pain, cleared);
408 top_baseline = baseline;
409 top_y = baseline - insetAscent;
411 if (last_drawn_width != insetWidth) {
413 clearInset(bv, baseline, cleared);
415 last_drawn_width = insetWidth;
418 if (the_locking_inset && (cpar(bv) == inset_par)
419 && (cpos(bv) == inset_pos)) {
420 inset_x = cx(bv) - top_x + drawTextXOffset;
421 inset_y = cy(bv) + drawTextYOffset;
423 if (!cleared && (need_update == CURSOR)
424 && !getLyXText(bv)->selection.set()) {
425 drawFrame(pain, cleared);
435 x += TEXT_TO_INSET_OFFSET;
437 Row * row = lt->firstRow();
438 int y_offset = baseline - row->ascent_of_text();
439 int ph = pain.paperHeight();
442 while ((row != 0) && ((y+row->height()) <= 0)) {
444 first += row->height();
450 if (cleared || (need_update&(INIT|FULL))) {
453 while ((row != 0) && (yf < ph)) {
454 lt->getVisibleRow(bv, y+y_offset, int(x), row,
460 } else if (!locked) {
461 if (need_update & CURSOR) {
462 bv->screen()->toggleSelection(lt, bv, true, y_offset,int(x));
463 lt->clearSelection();
464 lt->selection.cursor = lt->cursor;
466 bv->screen()->update(lt, bv, y_offset, int(x));
469 if (need_update & SELECTION) {
470 bv->screen()->toggleToggle(lt, bv, y_offset, int(x));
471 } else if (need_update & CURSOR) {
472 bv->screen()->toggleSelection(lt, bv, true, y_offset,int(x));
473 lt->clearSelection();
474 lt->selection.cursor = lt->cursor;
476 bv->screen()->update(lt, bv, y_offset, int(x));
481 lt->status(bv, LyXText::UNCHANGED);
482 if ((need_update != CURSOR_PAR) &&
483 ((drawFrame_ == ALWAYS) || ((drawFrame_ == LOCKED) && locked))) {
484 drawFrame(pain, cleared);
485 } else if (need_update & CLEAR_FRAME) {
486 clearFrame(pain, cleared);
489 x += insetWidth - TEXT_TO_INSET_OFFSET;
491 if (bv->text->status() == LyXText::CHANGED_IN_DRAW) {
493 } else if (need_update != INIT) {
501 void InsetText::drawFrame(Painter & pain, bool cleared) const
503 static int const ttoD2 = TEXT_TO_INSET_OFFSET / 2;
504 if (!frame_is_visible || cleared) {
505 frame_x = top_x + ttoD2;
506 frame_y = top_baseline - insetAscent + ttoD2;
507 frame_w = insetWidth - TEXT_TO_INSET_OFFSET;
508 frame_h = insetAscent + insetDescent - TEXT_TO_INSET_OFFSET;
509 pain.rectangle(frame_x, frame_y, frame_w, frame_h,
511 frame_is_visible = true;
516 void InsetText::clearFrame(Painter & pain, bool cleared) const
518 if (frame_is_visible) {
520 pain.rectangle(frame_x, frame_y, frame_w, frame_h,
523 frame_is_visible = false;
528 void InsetText::update(BufferView * bv, LyXFont const & font, bool reinit)
531 if (reinit && owner()) {
533 owner()->update(bv, font, true);
538 if (reinit || need_update == INIT) {
540 // we should put this call where we set need_update to INIT!
543 owner()->update(bv, font, true);
547 if (the_locking_inset) {
548 inset_x = cx(bv) - top_x + drawTextXOffset;
549 inset_y = cy(bv) + drawTextYOffset;
550 the_locking_inset->update(bv, font, reinit);
558 if ((need_update & CURSOR_PAR) && (lt->status() == LyXText::UNCHANGED) &&
561 lt->updateInset(bv, the_locking_inset);
563 if (lt->status() == LyXText::NEED_MORE_REFRESH)
571 void InsetText::setUpdateStatus(BufferView * bv, int what) const
573 // this does nothing dangerous so use only a localized buffer
574 LyXText * llt = getLyXText(bv);
577 // we have to redraw us full if our LyXText NEEDS_MORE_REFRES or
578 // if we don't break row so that we only have one row to update!
579 if ((llt->status() == LyXText::NEED_MORE_REFRESH) ||
581 (llt->status() == LyXText::NEED_VERY_LITTLE_REFRESH)))
584 } else if (llt->status() == LyXText::NEED_VERY_LITTLE_REFRESH) {
585 need_update |= CURSOR_PAR;
588 // this to not draw a selection when we redraw all of it!
589 if (need_update & CURSOR && !(need_update & SELECTION)) {
590 if (llt->selection.set())
592 llt->clearSelection();
597 void InsetText::updateLocal(BufferView * bv, int what, bool mark_dirty) const
599 if (!autoBreakRows && par->next())
600 collapseParagraphs(bv->buffer()->params);
607 setUpdateStatus(bv, what);
608 bool flag = (((need_update != CURSOR) && (need_update != NONE)) ||
609 (lt->status() != LyXText::UNCHANGED) || lt->selection.set());
613 bv->updateInset(const_cast<InsetText *>(this), mark_dirty);
617 if (need_update == CURSOR)
619 bv->owner()->showState();
620 bv->owner()->updateMenubar();
621 bv->owner()->updateToolbar();
622 if (old_par != cpar(bv)) {
623 bv->owner()->setLayout(cpar(bv)->getLayout());
629 string const InsetText::editMessage() const
631 return _("Opened Text Inset");
635 void InsetText::edit(BufferView * bv, int x, int y, unsigned int button)
637 UpdatableInset::edit(bv, x, y, button);
639 if (!bv->lockInset(this)) {
640 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
644 the_locking_inset = 0;
645 inset_pos = inset_x = inset_y = 0;
646 inset_boundary = false;
649 int tmp_y = (y < 0) ? 0 : y;
655 if (!checkAndActivateInset(bv, x, tmp_y, button))
656 lt->setCursorFromCoordinates(bv, x - drawTextXOffset,
658 lt->clearSelection();
660 // If the inset is empty set the language of the current font to the
661 // language to the surronding text (if different).
662 if (par->size() == 0 && !par->next() &&
663 bv->getParentLanguage(this) != lt->current_font.language())
665 LyXFont font(LyXFont::ALL_IGNORE);
666 font.setLanguage(bv->getParentLanguage(this));
667 setFont(bv, font, false);
674 if (drawFrame_ == LOCKED)
675 code = CURSOR|DRAW_FRAME;
676 updateLocal(bv, code, false);
680 void InsetText::edit(BufferView * bv, bool front)
682 UpdatableInset::edit(bv, front);
684 if (!bv->lockInset(this)) {
685 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
689 the_locking_inset = 0;
690 inset_pos = inset_x = inset_y = 0;
691 inset_boundary = false;
700 lt->setCursor(bv, par, 0);
705 // int const pos = (p->size() ? p->size()-1 : p->size());
706 lt->setCursor(bv, p, p->size());
708 lt->clearSelection();
710 // If the inset is empty set the language of the current font to the
711 // language to the surronding text (if different).
712 if (par->size() == 0 && !par->next() &&
713 bv->getParentLanguage(this) != lt->current_font.language()) {
714 LyXFont font(LyXFont::ALL_IGNORE);
715 font.setLanguage(bv->getParentLanguage(this));
716 setFont(bv, font, false);
722 if (drawFrame_ == LOCKED)
723 code = CURSOR|DRAW_FRAME;
724 updateLocal(bv, code, false);
728 void InsetText::insetUnlock(BufferView * bv)
730 if (the_locking_inset) {
731 the_locking_inset->insetUnlock(bv);
732 the_locking_inset = 0;
735 no_selection = false;
738 if (drawFrame_ == LOCKED)
739 code = CURSOR|CLEAR_FRAME;
747 if (lt->selection.set()) {
748 lt->clearSelection();
750 } else if (owner()) {
751 bv->owner()->setLayout(owner()->getLyXText(bv)
752 ->cursor.par()->getLayout());
754 bv->owner()->setLayout(bv->text->cursor.par()->getLayout());
755 // hack for deleteEmptyParMech
756 lt->setCursor(bv, par, 0);
759 updateLocal(bv, code, false);
762 void InsetText::lockInset(BufferView * bv, UpdatableInset * inset)
764 the_locking_inset = inset;
765 inset_x = cx(bv) - top_x + drawTextXOffset;
766 inset_y = cy(bv) + drawTextYOffset;
767 inset_pos = cpos(bv);
768 inset_par = cpar(bv);
769 inset_boundary = cboundary(bv);
770 updateLocal(bv, CURSOR, false);
774 bool InsetText::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
776 lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset("
780 if (!the_locking_inset) {
782 int const id = inset->id();
784 Paragraph::inset_iterator it =
785 p->inset_iterator_begin();
786 Paragraph::inset_iterator const end =
787 p->inset_iterator_end();
788 for (; it != end; ++it) {
789 if ((*it) == inset) {
790 getLyXText(bv)->setCursorIntern(bv, p, it.getPos());
791 lockInset(bv, inset);
794 if ((*it)->getInsetFromID(id)) {
795 getLyXText(bv)->setCursorIntern(bv, p, it.getPos());
797 return the_locking_inset->lockInsetInInset(bv, inset);
804 if (inset == cpar(bv)->getInset(cpos(bv))) {
805 lyxerr[Debug::INSETS] << "OK" << endl;
806 lockInset(bv, inset);
808 } else if (the_locking_inset && (the_locking_inset == inset)) {
809 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
810 lyxerr[Debug::INSETS] << "OK" << endl;
811 inset_x = cx(bv) - top_x + drawTextXOffset;
812 inset_y = cy(bv) + drawTextYOffset;
814 lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
816 } else if (the_locking_inset) {
817 lyxerr[Debug::INSETS] << "MAYBE" << endl;
818 return the_locking_inset->lockInsetInInset(bv, inset);
820 lyxerr[Debug::INSETS] << "NOT OK" << endl;
825 bool InsetText::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
828 if (!the_locking_inset)
830 if (the_locking_inset == inset) {
831 the_locking_inset->insetUnlock(bv);
832 getLyXText(bv)->updateInset(bv, inset);
833 the_locking_inset = 0;
835 moveRight(bv, false);
836 old_par = 0; // force layout setting
840 updateLocal(bv, CURSOR, false);
843 return the_locking_inset->unlockInsetInInset(bv, inset, lr);
847 bool InsetText::updateInsetInInset(BufferView * bv, Inset * inset)
849 if (!autoBreakRows && par->next())
850 collapseParagraphs(bv->buffer()->params);
858 if (!the_locking_inset) {
859 bool found = lt->updateInset(bv, inset);
863 setUpdateStatus(bv, NONE);
866 if (the_locking_inset != inset) {
867 bool found = the_locking_inset->updateInsetInInset(bv, inset);
871 setUpdateStatus(bv, CURSOR_PAR);
874 bool found = lt->updateInset(bv, inset);
878 setUpdateStatus(bv, CURSOR_PAR);
879 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
880 inset_x = cx(bv) - top_x + drawTextXOffset;
881 inset_y = cy(bv) + drawTextYOffset;
888 void InsetText::insetButtonPress(BufferView * bv, int x, int y, int button)
892 // use this to check mouse motion for selection!
896 int tmp_x = x - drawTextXOffset;
897 int tmp_y = y + insetAscent - getLyXText(bv)->first;
898 Inset * inset = bv->checkInsetHit(getLyXText(bv), tmp_x, tmp_y);
901 if (the_locking_inset) {
902 if (the_locking_inset == inset) {
903 the_locking_inset->insetButtonPress(bv,
907 no_selection = false;
910 // otherwise unlock the_locking_inset and lock the new inset
911 the_locking_inset->insetUnlock(bv);
912 inset_x = cx(bv) - top_x + drawTextXOffset;
913 inset_y = cy(bv) + drawTextYOffset;
914 the_locking_inset = 0;
915 inset->insetButtonPress(bv, x - inset_x,
916 y - inset_y, button);
917 inset->edit(bv, x - inset_x, y - inset_y, button);
918 if (the_locking_inset)
919 updateLocal(bv, CURSOR, false);
920 no_selection = false;
923 // otherwise only unlock the_locking_inset
924 the_locking_inset->insetUnlock(bv);
925 the_locking_inset = 0;
927 if (bv->theLockingInset()) {
928 if (isHighlyEditableInset(inset)) {
929 UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
930 inset_x = cx(bv) - top_x + drawTextXOffset;
931 inset_y = cy(bv) + drawTextYOffset;
932 inset_pos = cpos(bv);
933 inset_par = cpar(bv);
934 inset_boundary = cboundary(bv);
935 the_locking_inset = uinset;
936 uinset->insetButtonPress(bv, x - inset_x, y - inset_y,
938 uinset->edit(bv, x - inset_x, y - inset_y, 0);
939 if (the_locking_inset)
940 updateLocal(bv, CURSOR, false);
941 no_selection = false;
945 if (!inset) { // && (button == 2)) {
946 bool paste_internally = false;
947 if ((button == 2) && getLyXText(bv)->selection.set()) {
948 localDispatch(bv, LFUN_COPY, "");
949 paste_internally = true;
957 lt->setCursorFromCoordinates(bv, x - drawTextXOffset,
959 // set the selection cursor!
960 lt->selection.cursor = lt->cursor;
961 lt->cursor.x_fix(lt->cursor.x());
963 if (lt->selection.set()) {
964 lt->clearSelection();
967 updateLocal(bv, FULL, false);
969 lt->clearSelection();
972 updateLocal(bv, CURSOR, false);
974 bv->owner()->setLayout(cpar(bv)->getLayout());
976 // Insert primary selection with middle mouse
977 // if there is a local selection in the current buffer,
980 if (paste_internally)
981 localDispatch(bv, LFUN_PASTE, "");
983 localDispatch(bv, LFUN_PASTESELECTION,
987 getLyXText(bv)->clearSelection();
990 no_selection = false;
994 bool InsetText::insetButtonRelease(BufferView * bv, int x, int y, int button)
996 if (the_locking_inset) {
997 return the_locking_inset->insetButtonRelease(bv,
998 x - inset_x, y - inset_y,
1001 int tmp_x = x - drawTextXOffset;
1002 int tmp_y = y + insetAscent - getLyXText(bv)->first;
1003 Inset * inset = bv->checkInsetHit(getLyXText(bv), tmp_x, tmp_y);
1006 if (isHighlyEditableInset(inset)) {
1007 ret = inset->insetButtonRelease(bv, x - inset_x,
1008 y - inset_y, button);
1010 inset_x = cx(bv) - top_x + drawTextXOffset;
1011 inset_y = cy(bv) + drawTextYOffset;
1012 ret = inset->insetButtonRelease(bv, x - inset_x,
1013 y - inset_y, button);
1014 inset->edit(bv, x - inset_x,
1015 y - inset_y, button);
1017 updateLocal(bv, CURSOR_PAR, false);
1023 void InsetText::insetMotionNotify(BufferView * bv, int x, int y, int state)
1025 if (no_selection || ((mouse_x == x) && (mouse_y == y)))
1027 if (the_locking_inset) {
1028 the_locking_inset->insetMotionNotify(bv, x - inset_x,
1034 lt = getLyXText(bv);
1037 hideInsetCursor(bv);
1038 LyXCursor cur = lt->cursor;
1039 lt->setCursorFromCoordinates(bv, x - drawTextXOffset, y + insetAscent);
1040 if (cur == lt->cursor) {
1045 lt->setSelection(bv);
1046 bool flag = (lt->toggle_cursor.par() != lt->toggle_end_cursor.par() ||
1047 lt->toggle_cursor.pos() != lt->toggle_end_cursor.pos());
1051 updateLocal(bv, SELECTION, false);
1053 showInsetCursor(bv);
1057 void InsetText::insetKeyPress(XKeyEvent * xke)
1059 if (the_locking_inset) {
1060 the_locking_inset->insetKeyPress(xke);
1066 UpdatableInset::RESULT
1067 InsetText::localDispatch(BufferView * bv,
1068 kb_action action, string const & arg)
1070 bool was_empty = par->size() == 0 && !par->next();
1071 no_selection = false;
1072 UpdatableInset::RESULT
1073 result= UpdatableInset::localDispatch(bv, action, arg);
1074 if (result != UNDISPATCHED) {
1078 result = DISPATCHED;
1079 if ((action < 0) && arg.empty())
1082 if (the_locking_inset) {
1083 result = the_locking_inset->localDispatch(bv, action, arg);
1084 if (result == DISPATCHED_NOUPDATE)
1086 else if (result == DISPATCHED) {
1087 updateLocal(bv, CURSOR_PAR, false);
1089 } else if (result >= FINISHED) {
1091 case FINISHED_RIGHT:
1092 moveRightIntern(bv, false, false);
1093 result = DISPATCHED;
1096 if ((result = moveUp(bv)) >= FINISHED) {
1097 updateLocal(bv, CURSOR, false);
1098 bv->unlockInset(this);
1102 if ((result = moveDown(bv)) >= FINISHED) {
1103 updateLocal(bv, CURSOR, false);
1104 bv->unlockInset(this);
1108 result = DISPATCHED;
1111 the_locking_inset = 0;
1112 #ifdef WITH_WARNINGS
1113 #warning I changed this to always return Dispatched maybe it is wrong (20011001 Jug)
1118 hideInsetCursor(bv);
1121 lt = getLyXText(bv);
1125 int updflag = false;
1128 case LFUN_SELFINSERT:
1129 if (bv->buffer()->isReadonly()) {
1130 // setErrorMessage(N_("Document is read only"));
1134 /* Automatically delete the currently selected
1135 * text and replace it with what is being
1136 * typed in now. Depends on lyxrc settings
1137 * "auto_region_delete", which defaults to
1140 setUndo(bv, Undo::INSERT,
1141 lt->cursor.par(), lt->cursor.par()->next());
1143 if (lyxrc.auto_region_delete) {
1144 if (lt->selection.set()) {
1145 lt->cutSelection(bv, false);
1148 lt->clearSelection();
1149 for (string::size_type i = 0; i < arg.length(); ++i) {
1150 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], lt);
1153 lt->selection.cursor = lt->cursor;
1154 updwhat = CURSOR_PAR;
1156 result = DISPATCHED_NOUPDATE;
1158 // --- Cursor Movements -----------------------------------
1161 moveRight(bv, false, true);
1162 lt->setSelection(bv);
1163 updwhat = SELECTION;
1166 result = moveRight(bv);
1172 moveLeft(bv, false, true);
1173 lt->setSelection(bv);
1174 updwhat = SELECTION;
1178 result = moveLeft(bv);
1184 lt->setSelection(bv);
1185 updwhat = SELECTION;
1189 result = moveDown(bv);
1195 lt->setSelection(bv);
1196 updwhat = SELECTION;
1200 result = moveUp(bv);
1212 case LFUN_BACKSPACE: {
1213 setUndo(bv, Undo::DELETE,
1214 lt->cursor.par(), lt->cursor.par()->next());
1215 if (lt->selection.set())
1216 lt->cutSelection(bv);
1219 updwhat = CURSOR_PAR;
1225 setUndo(bv, Undo::DELETE,
1226 lt->cursor.par(), lt->cursor.par()->next());
1227 if (lt->selection.set()) {
1228 lt->cutSelection(bv);
1232 updwhat = CURSOR_PAR;
1238 setUndo(bv, Undo::DELETE,
1239 lt->cursor.par(), lt->cursor.par()->next());
1240 lt->cutSelection(bv);
1241 updwhat = CURSOR_PAR;
1248 lt->copySelection(bv);
1249 updwhat = CURSOR_PAR;
1251 case LFUN_PASTESELECTION:
1253 string const clip(bv->getClipboard());
1257 if (arg == "paragraph") {
1258 lt->insertStringAsParagraphs(bv, clip);
1260 lt->insertStringAsLines(bv, clip);
1262 updwhat = CURSOR_PAR;
1267 if (!autoBreakRows) {
1269 if (CutAndPaste::nrOfParagraphs() > 1) {
1270 Alert::alert(_("Impossible operation"),
1271 _("Cannot include more than one paragraph!"),
1276 setUndo(bv, Undo::INSERT,
1277 lt->cursor.par(), lt->cursor.par()->next());
1278 lt->pasteSelection(bv);
1279 updwhat = CURSOR_PAR;
1284 case LFUN_BREAKPARAGRAPH:
1285 if (!autoBreakRows) {
1286 result = DISPATCHED;
1289 lt->breakParagraph(bv, 0);
1293 case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
1294 if (!autoBreakRows) {
1295 result = DISPATCHED;
1298 lt->breakParagraph(bv, 1);
1303 case LFUN_BREAKLINE: {
1304 if (!autoBreakRows) {
1305 result = DISPATCHED;
1308 setUndo(bv, Undo::INSERT,
1309 lt->cursor.par(), lt->cursor.par()->next());
1310 lt->insertChar(bv, Paragraph::META_NEWLINE);
1311 updwhat = CURSOR_PAR;
1317 // do not set layouts on non breakable textinsets
1318 if (autoBreakRows) {
1319 layout_type cur_layout = cpar(bv)->layout;
1321 // Derive layout number from given argument (string)
1322 // and current buffer's textclass (number). */
1323 textclass_type tclass = bv->buffer()->params.textclass;
1324 pair<bool, layout_type> layout =
1325 textclasslist.NumberOfLayout(tclass, arg);
1327 // If the entry is obsolete, use the new one instead.
1329 string obs = textclasslist.Style(tclass,layout.second).
1332 layout = textclasslist.NumberOfLayout(tclass, obs);
1335 // see if we found the layout number:
1336 if (!layout.first) {
1337 string const msg = string(N_("Layout ")) + arg + N_(" not known");
1338 bv->owner()->getLyXFunc()->dispatch(LFUN_MESSAGE, msg);
1342 if (cur_layout != layout.second) {
1343 cur_layout = layout.second;
1344 lt->setLayout(bv, layout.second);
1345 bv->owner()->setLayout(cpar(bv)->getLayout());
1346 updwhat = CURSOR_PAR;
1350 // reset the layout box
1351 bv->owner()->setLayout(cpar(bv)->getLayout());
1354 case LFUN_PARAGRAPH_SPACING:
1355 // This one is absolutely not working. When fiddling with this
1356 // it also seems to me that the paragraphs inside the insettext
1357 // inherit bufferparams/paragraphparams in a strange way. (Lgb)
1359 Paragraph * par = lt->cursor.par();
1360 Spacing::Space cur_spacing = par->params().spacing().getSpace();
1361 float cur_value = 1.0;
1362 if (cur_spacing == Spacing::Other) {
1363 cur_value = par->params().spacing().getValue();
1366 istringstream istr(arg.c_str());
1369 Spacing::Space new_spacing = cur_spacing;
1370 float new_value = cur_value;
1372 lyxerr << "Missing argument to `paragraph-spacing'"
1374 } else if (tmp == "single") {
1375 new_spacing = Spacing::Single;
1376 } else if (tmp == "onehalf") {
1377 new_spacing = Spacing::Onehalf;
1378 } else if (tmp == "double") {
1379 new_spacing = Spacing::Double;
1380 } else if (tmp == "other") {
1381 new_spacing = Spacing::Other;
1384 lyxerr << "new_value = " << tmpval << endl;
1387 } else if (tmp == "default") {
1388 new_spacing = Spacing::Default;
1390 lyxerr << _("Unknown spacing argument: ")
1393 if (cur_spacing != new_spacing || cur_value != new_value) {
1394 par->params().spacing(Spacing(new_spacing, new_value));
1395 updwhat = CURSOR_PAR;
1402 if (!bv->Dispatch(action, arg))
1403 result = UNDISPATCHED;
1410 updateLocal(bv, updwhat, updflag);
1411 /// If the action has deleted all text in the inset, we need to change the
1412 // language to the language of the surronding text.
1413 if (!was_empty && par->size() == 0 && !par->next()) {
1414 LyXFont font(LyXFont::ALL_IGNORE);
1415 font.setLanguage(bv->getParentLanguage(this));
1416 setFont(bv, font, false);
1419 if (result < FINISHED) {
1420 showInsetCursor(bv);
1422 bv->unlockInset(this);
1427 int InsetText::latex(Buffer const * buf, ostream & os, bool, bool) const
1430 buf->latexParagraphs(os, par, 0, texrow);
1431 return texrow.rows();
1435 int InsetText::ascii(Buffer const * buf, ostream & os, int linelen) const
1437 Paragraph * p = par;
1438 unsigned int lines = 0;
1441 string const tmp = buf->asciiParagraph(p, linelen, p->previous()==0);
1442 lines += lyx::count(tmp.begin(), tmp.end(), '\n');
1450 int InsetText::docbook(Buffer const * buf, ostream & os) const
1452 Paragraph * p = par;
1453 unsigned int lines = 0;
1455 vector<string> environment_stack(10);
1456 vector<string> environment_inner(10);
1458 int const command_depth = 0;
1461 Paragraph::depth_type depth = 0; // paragraph depth
1465 int desc_on = 0; // description mode
1467 LyXLayout const & style =
1468 textclasslist.Style(buf->params.textclass,
1471 // environment tag closing
1472 for (; depth > p->params().depth(); --depth) {
1473 if (environment_inner[depth] != "!-- --") {
1474 item_name = "listitem";
1475 buf->sgmlCloseTag(os, command_depth + depth,
1477 if (environment_inner[depth] == "varlistentry")
1478 buf->sgmlCloseTag(os, depth+command_depth,
1479 environment_inner[depth]);
1481 buf->sgmlCloseTag(os, depth + command_depth,
1482 environment_stack[depth]);
1483 environment_stack[depth].erase();
1484 environment_inner[depth].erase();
1487 if (depth == p->params().depth()
1488 && environment_stack[depth] != style.latexname()
1489 && !environment_stack[depth].empty()) {
1490 if (environment_inner[depth] != "!-- --") {
1491 item_name= "listitem";
1492 buf->sgmlCloseTag(os, command_depth+depth,
1494 if (environment_inner[depth] == "varlistentry")
1495 buf->sgmlCloseTag(os,
1496 depth + command_depth,
1497 environment_inner[depth]);
1500 buf->sgmlCloseTag(os, depth + command_depth,
1501 environment_stack[depth]);
1503 environment_stack[depth].erase();
1504 environment_inner[depth].erase();
1507 // Write opening SGML tags.
1508 switch (style.latextype) {
1509 case LATEX_PARAGRAPH:
1510 buf->sgmlOpenTag(os, depth + command_depth,
1515 buf->sgmlError(p, 0,
1516 _("Error : LatexType Command not allowed here.\n"));
1520 case LATEX_ENVIRONMENT:
1521 case LATEX_ITEM_ENVIRONMENT:
1522 if (depth < p->params().depth()) {
1523 depth = p->params().depth();
1524 environment_stack[depth].erase();
1527 if (environment_stack[depth] != style.latexname()) {
1528 if (environment_stack.size() == depth + 1) {
1529 environment_stack.push_back("!-- --");
1530 environment_inner.push_back("!-- --");
1532 environment_stack[depth] = style.latexname();
1533 environment_inner[depth] = "!-- --";
1534 buf->sgmlOpenTag(os, depth + command_depth,
1535 environment_stack[depth]);
1537 if (environment_inner[depth] != "!-- --") {
1538 item_name= "listitem";
1539 buf->sgmlCloseTag(os,
1540 command_depth + depth,
1542 if (environment_inner[depth] == "varlistentry")
1543 buf->sgmlCloseTag(os,
1544 depth + command_depth,
1545 environment_inner[depth]);
1549 if (style.latextype == LATEX_ENVIRONMENT) {
1550 if (!style.latexparam().empty()) {
1551 if (style.latexparam() == "CDATA")
1554 buf->sgmlOpenTag(os, depth + command_depth,
1555 style.latexparam());
1560 desc_on = (style.labeltype == LABEL_MANUAL);
1563 environment_inner[depth]= "varlistentry";
1565 environment_inner[depth]= "listitem";
1567 buf->sgmlOpenTag(os, depth + 1 + command_depth,
1568 environment_inner[depth]);
1572 buf->sgmlOpenTag(os, depth + 1 + command_depth,
1576 buf->sgmlOpenTag(os, depth + 1 + command_depth,
1581 buf->sgmlOpenTag(os, depth + command_depth,
1586 buf->simpleDocBookOnePar(os, p, desc_on,
1587 depth + 1 + command_depth);
1591 // write closing SGML tags
1592 switch (style.latextype) {
1593 case LATEX_ENVIRONMENT:
1594 if (!style.latexparam().empty()) {
1595 if (style.latexparam() == "CDATA")
1598 buf->sgmlCloseTag(os, depth + command_depth,
1599 style.latexparam());
1602 case LATEX_ITEM_ENVIRONMENT:
1603 if (desc_on == 1) break;
1605 buf->sgmlCloseTag(os, depth + 1 + command_depth, end_tag);
1607 case LATEX_PARAGRAPH:
1608 buf->sgmlCloseTag(os, depth + command_depth, style.latexname());
1611 buf->sgmlCloseTag(os, depth + command_depth, style.latexname());
1617 for (int d = depth; d >= 0; --d) {
1618 if (!environment_stack[depth].empty()) {
1619 if (environment_inner[depth] != "!-- --") {
1620 item_name = "listitem";
1621 buf->sgmlCloseTag(os, command_depth + depth,
1623 if (environment_inner[depth] == "varlistentry")
1624 buf->sgmlCloseTag(os, depth + command_depth,
1625 environment_inner[depth]);
1628 buf->sgmlCloseTag(os, depth + command_depth,
1629 environment_stack[depth]);
1637 void InsetText::validate(LaTeXFeatures & features) const
1639 Paragraph * p = par;
1641 p->validate(features);
1647 int InsetText::beginningOfMainBody(Buffer const * buf, Paragraph * p) const
1649 if (textclasslist.Style(buf->params.textclass,
1650 p->getLayout()).labeltype != LABEL_MANUAL)
1653 return p->beginningOfMainBody();
1657 void InsetText::getCursorPos(BufferView * bv,
1658 int & x, int & y) const
1660 if (the_locking_inset) {
1661 the_locking_inset->getCursorPos(bv, x, y);
1669 unsigned int InsetText::insetInInsetY()
1671 if (!the_locking_inset)
1674 return (inset_y + the_locking_inset->insetInInsetY());
1678 void InsetText::toggleInsetCursor(BufferView * bv)
1680 if (the_locking_inset) {
1681 the_locking_inset->toggleInsetCursor(bv);
1685 LyXFont const font(getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv)));
1687 int const asc = lyxfont::maxAscent(font);
1688 int const desc = lyxfont::maxDescent(font);
1690 if (isCursorVisible())
1691 bv->hideLockedInsetCursor();
1693 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1694 toggleCursorVisible();
1698 void InsetText::showInsetCursor(BufferView * bv, bool show)
1700 if (the_locking_inset) {
1701 the_locking_inset->showInsetCursor(bv, show);
1704 if (!isCursorVisible()) {
1705 LyXFont const font =
1706 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1708 int const asc = lyxfont::maxAscent(font);
1709 int const desc = lyxfont::maxDescent(font);
1711 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1713 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1714 setCursorVisible(true);
1719 void InsetText::hideInsetCursor(BufferView * bv)
1721 if (isCursorVisible()) {
1722 bv->hideLockedInsetCursor();
1723 setCursorVisible(false);
1725 if (the_locking_inset)
1726 the_locking_inset->hideInsetCursor(bv);
1730 void InsetText::fitInsetCursor(BufferView * bv) const
1732 if (the_locking_inset) {
1733 the_locking_inset->fitInsetCursor(bv);
1736 LyXFont const font =
1737 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1739 int const asc = lyxfont::maxAscent(font);
1740 int const desc = lyxfont::maxDescent(font);
1742 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1746 UpdatableInset::RESULT
1747 InsetText::moveRight(BufferView * bv, bool activate_inset, bool selecting)
1749 if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1750 return moveLeftIntern(bv, false, activate_inset, selecting);
1752 return moveRightIntern(bv, false, activate_inset, selecting);
1756 UpdatableInset::RESULT
1757 InsetText::moveLeft(BufferView * bv, bool activate_inset, bool selecting)
1759 if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1760 return moveRightIntern(bv, true, activate_inset, selecting);
1762 return moveLeftIntern(bv, true, activate_inset, selecting);
1766 UpdatableInset::RESULT
1767 InsetText::moveRightIntern(BufferView * bv, bool behind,
1768 bool activate_inset, bool selecting)
1770 if (!cpar(bv)->next() && (cpos(bv) >= cpar(bv)->size()))
1771 return FINISHED_RIGHT;
1772 if (activate_inset && checkAndActivateInset(bv, behind))
1774 getLyXText(bv)->cursorRight(bv);
1776 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1777 return DISPATCHED_NOUPDATE;
1781 UpdatableInset::RESULT
1782 InsetText::moveLeftIntern(BufferView * bv, bool behind,
1783 bool activate_inset, bool selecting)
1785 if (!cpar(bv)->previous() && (cpos(bv) <= 0))
1787 getLyXText(bv)->cursorLeft(bv);
1789 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1790 if (activate_inset && checkAndActivateInset(bv, behind))
1792 return DISPATCHED_NOUPDATE;
1796 UpdatableInset::RESULT
1797 InsetText::moveUp(BufferView * bv)
1799 if (!crow(bv)->previous())
1801 getLyXText(bv)->cursorUp(bv);
1802 return DISPATCHED_NOUPDATE;
1806 UpdatableInset::RESULT
1807 InsetText::moveDown(BufferView * bv)
1809 if (!crow(bv)->next())
1810 return FINISHED_DOWN;
1811 getLyXText(bv)->cursorDown(bv);
1812 return DISPATCHED_NOUPDATE;
1816 bool InsetText::insertInset(BufferView * bv, Inset * inset)
1818 if (the_locking_inset) {
1819 if (the_locking_inset->insetAllowed(inset))
1820 return the_locking_inset->insertInset(bv, inset);
1825 lt = getLyXText(bv);
1828 setUndo(bv, Undo::FINISH, lt->cursor.par(), lt->cursor.par()->next());
1830 inset->setOwner(this);
1831 hideInsetCursor(bv);
1832 lt->insertInset(bv, inset);
1836 updateLocal(bv, CURSOR_PAR|CURSOR, true);
1842 bool InsetText::insetAllowed(Inset::Code code) const
1844 // in_insetAllowed is a really gross hack,
1845 // to allow us to call the owner's insetAllowed
1846 // without stack overflow, which can happen
1847 // when the owner uses InsetCollapsable::insetAllowed()
1849 if (in_insetAllowed)
1851 in_insetAllowed = true;
1852 if (the_locking_inset)
1853 ret = the_locking_inset->insetAllowed(code);
1855 ret = owner()->insetAllowed(code);
1856 in_insetAllowed = false;
1861 UpdatableInset * InsetText::getLockingInset() const
1863 return the_locking_inset ? the_locking_inset->getLockingInset() :
1864 const_cast<InsetText *>(this);
1868 UpdatableInset * InsetText::getFirstLockingInsetOfType(Inset::Code c)
1872 if (the_locking_inset)
1873 return the_locking_inset->getFirstLockingInsetOfType(c);
1878 bool InsetText::showInsetDialog(BufferView * bv) const
1880 if (the_locking_inset)
1881 return the_locking_inset->showInsetDialog(bv);
1886 vector<string> const InsetText::getLabelList() const
1888 vector<string> label_list;
1890 Paragraph * tpar = par;
1892 Paragraph::inset_iterator beg = tpar->inset_iterator_begin();
1893 Paragraph::inset_iterator end = tpar->inset_iterator_end();
1894 for (; beg != end; ++beg) {
1895 vector<string> const l = (*beg)->getLabelList();
1896 label_list.insert(label_list.end(), l.begin(), l.end());
1898 tpar = tpar->next();
1904 void InsetText::setFont(BufferView * bv, LyXFont const & font, bool toggleall,
1907 if (the_locking_inset) {
1908 the_locking_inset->setFont(bv, font, toggleall, selectall);
1911 if ((!par->next() && !par->size()) || !cpar(bv)->size()) {
1912 getLyXText(bv)->setFont(bv, font, toggleall);
1917 lt = getLyXText(bv);
1920 if (lt->selection.set()) {
1921 setUndo(bv, Undo::EDIT, lt->cursor.par(), lt->cursor.par()->next());
1925 lt->toggleFree(bv, font, toggleall);
1927 lt->clearSelection();
1929 bool flag = (selectall || lt->selection.set());
1933 updateLocal(bv, FULL, true);
1935 updateLocal(bv, CURSOR_PAR, true);
1939 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1941 if (cpar(bv)->isInset(cpos(bv))) {
1945 static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
1946 if (!isHighlyEditableInset(inset))
1948 LyXFont const font =
1949 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1951 x = inset->width(bv, font);
1952 y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1955 y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1957 //inset_x = cx(bv) - top_x + drawTextXOffset;
1958 //inset_y = cy(bv) + drawTextYOffset;
1959 inset->edit(bv, x, y, 0);
1960 if (!the_locking_inset)
1962 updateLocal(bv, CURSOR, false);
1969 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1972 x -= drawTextXOffset;
1974 int dummyy = y + insetAscent;
1975 Inset * inset = bv->checkInsetHit(getLyXText(bv), dummyx, dummyy);
1982 inset_x = cx(bv) - top_x + drawTextXOffset;
1983 inset_y = cy(bv) + drawTextYOffset;
1984 inset->edit(bv, x - inset_x, y - inset_y, button);
1985 if (!the_locking_inset)
1987 updateLocal(bv, CURSOR, false);
1994 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1997 int w = UpdatableInset::getMaxWidth(bv, inset);
2002 w = w - top_x + owner()->x();
2005 w -= (2 * TEXT_TO_INSET_OFFSET);
2008 return UpdatableInset::getMaxWidth(bv, inset);
2013 void InsetText::setParagraphData(Paragraph * p, bool same_id)
2015 // we have to unlock any locked inset otherwise we're in troubles
2016 the_locking_inset = 0;
2018 Paragraph * tmp = par->next();
2023 par = new Paragraph(*p, same_id);
2024 par->setInsetOwner(this);
2025 Paragraph * np = par;
2028 np->next(new Paragraph(*p, same_id));
2029 np->next()->previous(np);
2031 np->setInsetOwner(this);
2038 void InsetText::setText(string const & data)
2041 LyXFont font(LyXFont::ALL_SANE);
2042 for (unsigned int i=0; i < data.length(); ++i)
2043 par->insertChar(i, data[i], font);
2047 void InsetText::setAutoBreakRows(bool flag)
2049 if (flag != autoBreakRows) {
2050 autoBreakRows = flag;
2058 void InsetText::setDrawFrame(BufferView * bv, DrawFrame how)
2060 if (how != drawFrame_) {
2063 updateLocal(bv, DRAW_FRAME, false);
2068 void InsetText::setFrameColor(BufferView * bv, LColor::color col)
2070 if (frame_color != col) {
2073 updateLocal(bv, DRAW_FRAME, false);
2078 int InsetText::cx(BufferView * bv) const
2080 // we do nothing dangerous so we use a local cache
2081 LyXText * llt = getLyXText(bv);
2082 int x = llt->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
2083 if (the_locking_inset) {
2084 LyXFont font = llt->getFont(bv->buffer(), llt->cursor.par(),
2086 if (font.isVisibleRightToLeft())
2087 x -= the_locking_inset->width(bv, font);
2093 int InsetText::cy(BufferView * bv) const
2096 return getLyXText(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
2100 pos_type InsetText::cpos(BufferView * bv) const
2102 return getLyXText(bv)->cursor.pos();
2106 Paragraph * InsetText::cpar(BufferView * bv) const
2108 return getLyXText(bv)->cursor.par();
2112 bool InsetText::cboundary(BufferView * bv) const
2114 return getLyXText(bv)->cursor.boundary();
2118 Row * InsetText::crow(BufferView * bv) const
2120 return getLyXText(bv)->cursor.row();
2124 LyXText * InsetText::getLyXText(BufferView const * lbv,
2125 bool const recursive) const
2127 if (!recursive && (cached_bview == lbv)) {
2128 LyXText * lt = cached_text.get();
2129 lyx::Assert(lt && lt->firstRow()->par() == par);
2133 // Super UGLY! (Lgb)
2134 BufferView * bv = const_cast<BufferView *>(lbv);
2137 Cache::iterator it = cache.find(bv);
2139 if (it != cache.end()) {
2142 } else if (do_resize) {
2143 resizeLyXText(do_resize);
2145 if (lt || !it->second.remove) {
2146 lyx::Assert(it->second.text.get());
2147 cached_text = it->second.text;
2148 if (recursive && the_locking_inset) {
2149 return the_locking_inset->getLyXText(bv, true);
2151 return cached_text.get();
2152 } else if (it->second.remove) {
2154 saveLyXTextState(it->second.text.get());
2160 // when we have to reinit the existing LyXText!
2162 it->second.text->init(bv);
2163 restoreLyXTextState(bv, it->second.text.get());
2164 it->second.remove = false;
2166 cached_text = it->second.text;
2167 if (the_locking_inset && recursive) {
2168 return the_locking_inset->getLyXText(bv);
2170 return cached_text.get();
2173 // we are here only if we don't have a BufferView * in the cache!!!
2175 cached_text.reset(new LyXText(const_cast<InsetText *>(this)));
2176 cached_text->init(bv);
2177 restoreLyXTextState(bv, cached_text.get());
2179 cache.insert(make_pair(bv, cached_text));
2181 if (the_locking_inset && recursive) {
2182 return the_locking_inset->getLyXText(bv);
2184 return cached_text.get();
2188 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
2192 Cache::iterator it = cache.find(bv);
2194 if (it == cache.end()) {
2198 lyx::Assert(it->second.text.get());
2200 it->second.remove = true;
2202 /// then remove all LyXText in text-insets
2203 Paragraph * p = par;
2204 for (; p; p = p->next()) {
2205 p->deleteInsetsLyXText(bv);
2211 void InsetText::resizeLyXText(BufferView * bv, bool force) const
2214 // we cannot resize this because we are in use!
2215 // so do this on the next possible getLyXText()
2220 // lyxerr << "InsetText::resizeLyXText\n";
2221 if (!par->next() && !par->size()) { // no data, resize not neccessary!
2222 // we have to do this as a fixed width may have changed!
2223 LyXText * t = getLyXText(bv);
2224 saveLyXTextState(t);
2226 restoreLyXTextState(bv, t);
2229 // one endless line, resize normally not necessary
2230 if (!force && getMaxWidth(bv, this) < 0)
2233 Cache::iterator it = cache.find(bv);
2234 if (it == cache.end()) {
2237 lyx::Assert(it->second.text.get());
2239 LyXText * t = it->second.text.get();
2240 saveLyXTextState(t);
2241 for (Paragraph * p = par; p; p = p->next()) {
2242 p->resizeInsetsLyXText(bv);
2245 restoreLyXTextState(bv, t);
2246 if (the_locking_inset) {
2247 inset_x = cx(bv) - top_x + drawTextXOffset;
2248 inset_y = cy(bv) + drawTextYOffset;
2252 t->first = bv->screen()->topCursorVisible(t);
2255 updateLocal(bv, FULL, false);
2256 // this will scroll the screen such that the cursor becomes visible
2257 bv->updateScrollbar();
2259 need_update |= FULL;
2264 void InsetText::reinitLyXText() const
2267 // we cannot resize this because we are in use!
2268 // so do this on the next possible getLyXText()
2274 // lyxerr << "InsetText::reinitLyXText\n";
2275 for(Cache::iterator it = cache.begin(); it != cache.end(); ++it) {
2276 lyx::Assert(it->second.text.get());
2278 LyXText * t = it->second.text.get();
2279 BufferView * bv = it->first;
2281 saveLyXTextState(t);
2282 for (Paragraph * p = par; p; p = p->next()) {
2283 p->resizeInsetsLyXText(bv);
2286 restoreLyXTextState(bv, t);
2287 if (the_locking_inset) {
2288 inset_x = cx(bv) - top_x + drawTextXOffset;
2289 inset_y = cy(bv) + drawTextYOffset;
2292 t->first = bv->screen()->topCursorVisible(t);
2295 updateLocal(bv, FULL, false);
2296 // this will scroll the screen such that the cursor becomes visible
2297 bv->updateScrollbar();
2305 void InsetText::removeNewlines()
2307 bool changed = false;
2309 for (Paragraph * p = par; p; p = p->next()) {
2310 for (int i = 0; i < p->size(); ++i) {
2311 if (p->getChar(i) == Paragraph::META_NEWLINE) {
2322 bool InsetText::nodraw() const
2324 if (the_locking_inset)
2325 return the_locking_inset->nodraw();
2326 return UpdatableInset::nodraw();
2330 int InsetText::scroll(bool recursive) const
2332 int sx = UpdatableInset::scroll(false);
2334 if (recursive && the_locking_inset)
2335 sx += the_locking_inset->scroll(recursive);
2341 bool InsetText::doClearArea() const
2343 return !locked || (need_update & (FULL|INIT));
2347 void InsetText::selectAll(BufferView * bv)
2349 getLyXText(bv)->cursorTop(bv);
2350 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
2351 getLyXText(bv)->cursorBottom(bv);
2352 getLyXText(bv)->setSelection(bv);
2356 void InsetText::clearSelection(BufferView * bv)
2358 getLyXText(bv)->clearSelection();
2362 void InsetText::clearInset(BufferView * bv, int baseline, bool & cleared) const
2364 Painter & pain = bv->painter();
2366 int h = insetAscent + insetDescent;
2367 int ty = baseline - insetAscent;
2373 if ((ty + h) > pain.paperHeight())
2374 h = pain.paperHeight();
2375 if ((top_x + drawTextXOffset + w) > pain.paperWidth())
2376 w = pain.paperWidth();
2377 // w -= TEXT_TO_INSET_OFFSET;
2378 pain.fillRectangle(top_x, ty, w+1, h+1, backgroundColor());
2381 frame_is_visible = false;
2385 Paragraph * InsetText::getParFromID(int id) const
2388 Paragraph * result = par;
2389 Paragraph * ires = 0;
2390 while (result && result->id() != id) {
2391 if ((ires = result->getParFromID(id)))
2393 result = result->next();
2397 Paragraph * tmp = par;
2399 if (tmp->id() == id) {
2402 Paragraph * tmp2 = tmp->getParFromID(id);
2413 Paragraph * InsetText::firstParagraph() const
2416 if (the_locking_inset)
2417 if ((result = the_locking_inset->firstParagraph()))
2423 Paragraph * InsetText::getFirstParagraph(int i) const
2425 return (i == 0) ? par : 0;
2429 LyXCursor const & InsetText::cursor(BufferView * bv) const
2431 if (the_locking_inset)
2432 return the_locking_inset->cursor(bv);
2433 return getLyXText(bv)->cursor;
2437 Paragraph * InsetText::paragraph() const
2443 void InsetText::paragraph(Paragraph * p)
2445 // GENERAL COMMENT: We don't have to free the old paragraphs as the
2446 // caller of this function has to take care of it. This IS important
2447 // as we could have to insert a paragraph before this one and just
2448 // link the actual to a new ones next and set it with this function
2451 // set ourself as owner for all the paragraphs inserted!
2452 Paragraph * np = par;
2454 np->setInsetOwner(this);
2458 // redraw myself when asked for
2463 Inset * InsetText::getInsetFromID(int id_arg) const
2466 return const_cast<InsetText *>(this);
2468 Paragraph * lp = par;
2471 for (Paragraph::inset_iterator it = lp->inset_iterator_begin(),
2472 en = lp->inset_iterator_end();
2475 if ((*it)->id() == id_arg)
2477 Inset * in = (*it)->getInsetFromID(id_arg);
2487 string const InsetText::selectNextWordToSpellcheck(BufferView * bv, float & value) const
2493 lt = getLyXText(bv);
2496 if (the_locking_inset) {
2497 str = the_locking_inset->selectNextWordToSpellcheck(bv, value);
2504 // we have to go on checking so move cusor to the next char
2505 lt->cursor.pos(lt->cursor.pos() + 1);
2507 str = lt->selectNextWordToSpellcheck(bv, value);
2509 bv->unlockInset(const_cast<InsetText *>(this));
2518 void InsetText::selectSelectedWord(BufferView * bv)
2520 if (the_locking_inset) {
2521 the_locking_inset->selectSelectedWord(bv);
2524 getLyXText(bv)->selectSelectedWord(bv);
2525 updateLocal(bv, SELECTION, false);
2529 void InsetText::toggleSelection(BufferView * bv, bool kill_selection)
2531 if (the_locking_inset) {
2532 the_locking_inset->toggleSelection(bv, kill_selection);
2536 lt = getLyXText(bv);
2540 int x = top_x + TEXT_TO_INSET_OFFSET;
2542 Row * row = lt->firstRow();
2543 int y_offset = top_baseline - row->ascent_of_text();
2545 while ((row != 0) && ((y+row->height()) <= 0)) {
2552 if (need_update & SELECTION)
2554 bv->screen()->toggleSelection(lt, bv, kill_selection, y_offset, x);
2560 bool InsetText::searchForward(BufferView * bv, string const & str,
2563 if (the_locking_inset) {
2564 if (the_locking_inset->searchForward(bv, str, cs, mw))
2568 lt = getLyXText(bv);
2571 Paragraph * lpar = lt->cursor.par();
2572 pos_type pos = lt->cursor.pos();
2573 if (pos < lpar->size() - 1)
2577 lpar = lpar->next();
2582 // we have to unlock ourself in this function by default!
2583 bv->unlockInset(const_cast<InsetText *>(this));
2586 lt->setCursor(bv, lpar, pos);
2590 if (LyXFind(bv, str, true, true, cs , mw)) {
2593 // we have to unlock ourself in this function by default!
2594 bv->unlockInset(const_cast<InsetText *>(this));
2598 bool InsetText::searchBackward(BufferView * bv, string const & str,
2601 if (the_locking_inset)
2602 if (the_locking_inset->searchBackward(bv, str, cs, mw))
2604 if (LyXFind(bv, str, false, true, cs, mw)) {
2607 // we have to unlock ourself in this function by default!
2608 bv->unlockInset(const_cast<InsetText *>(this));
2613 bool InsetText::checkInsertChar(LyXFont & font)
2616 return owner()->checkInsertChar(font);
2621 void InsetText::collapseParagraphs(BufferParams const & bparams) const
2623 while(par->next()) {
2624 if (!par->isSeparator(par->size()-1))
2625 par->insertChar(par->size()-1, ' ');
2626 par->pasteParagraph(bparams);