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
67 using lyx::layout_type;
68 using lyx::textclass_type;
70 extern unsigned char getCurrentTextClass(Buffer *);
71 extern bool math_insert_greek(BufferView *, char);
72 extern int greek_kb_flag;
75 // These functions should probably go into bufferview_funcs somehow (Jug)
77 void InsetText::saveLyXTextState(LyXText * t) const
79 // check if my paragraphs are still valid
82 if (p == t->cursor.par())
87 if (p && t->cursor.pos() <= p->size()) {
88 sstate.lpar = t->cursor.par();
89 sstate.pos = t->cursor.pos();
90 sstate.boundary = t->cursor.boundary();
91 sstate.selstartpar = t->selection.start.par();
92 sstate.selstartpos = t->selection.start.pos();
93 sstate.selstartboundary = t->selection.start.boundary();
94 sstate.selendpar = t->selection.end.par();
95 sstate.selendpos = t->selection.end.pos();
96 sstate.selendboundary = t->selection.end.boundary();
97 sstate.selection = t->selection.set();
98 sstate.mark_set = t->selection.mark();
99 sstate.refresh = t->refresh_row != 0;
105 void InsetText::restoreLyXTextState(BufferView * bv, LyXText * t) const
108 t->selection.set(true);
109 /* at this point just to avoid the Delete-Empty-Paragraph
110 * Mechanism when setting the cursor */
111 t->selection.mark(sstate.mark_set);
112 if (sstate.selection) {
113 t->setCursor(bv, sstate.selstartpar, sstate.selstartpos,
114 true, sstate.selstartboundary);
115 t->selection.cursor = t->cursor;
116 t->setCursor(bv, sstate.selendpar, sstate.selendpos,
117 true, sstate.selendboundary);
119 t->setCursor(bv, sstate.lpar, sstate.pos);
121 t->setCursor(bv, sstate.lpar, sstate.pos, true, sstate.boundary);
122 t->selection.cursor = t->cursor;
123 t->selection.set(false);
125 if (sstate.refresh) {
131 InsetText::InnerCache::InnerCache(boost::shared_ptr<LyXText> t)
138 InsetText::InsetText()
139 : UpdatableInset(), lt(0), in_update(false), do_resize(0),
147 InsetText::InsetText(InsetText const & in, bool same_id)
148 : UpdatableInset(in, same_id), lt(0), in_update(false), do_resize(0),
156 InsetText & InsetText::operator=(InsetText const & it)
163 void InsetText::init(InsetText const * ins, bool same_id)
166 setParagraphData(ins->par, same_id);
167 autoBreakRows = ins->autoBreakRows;
168 drawFrame_ = ins->drawFrame_;
169 frame_color = ins->frame_color;
175 p->setInsetOwner(this);
178 the_locking_inset = 0;
180 frame_color = LColor::insetframe;
181 autoBreakRows = false;
188 no_selection = false;
195 last_drawn_width = -1;
196 frame_is_visible = false;
199 in_insetAllowed = false;
203 InsetText::~InsetText()
210 Paragraph * tmp = par->next();
217 void InsetText::clear()
220 Paragraph * tmp = par->next();
230 Inset * InsetText::clone(Buffer const &, bool same_id) const
232 return new InsetText(*this, same_id);
236 void InsetText::write(Buffer const * buf, ostream & os) const
239 writeParagraphData(buf, os);
243 void InsetText::writeParagraphData(Buffer const * buf, ostream & os) const
245 par->writeFile(buf, os, buf->params, 0);
249 void InsetText::read(Buffer const * buf, LyXLex & lex)
253 Paragraph * return_par = 0;
254 Paragraph::depth_type depth = 0;
255 LyXFont font(LyXFont::ALL_INHERIT);
261 token = lex.getString();
264 if (token == "\\end_inset") {
265 #ifndef NO_COMPABILITY
266 const_cast<Buffer*>(buf)->insertErtContents(par, pos, false);
271 if (const_cast<Buffer*>(buf)->
272 parseSingleLyXformat2Token(lex, par, return_par,
273 token, pos, depth, font)) {
274 // the_end read this should NEVER happen
275 lex.printError("\\the_end read in inset! Error in document!");
283 return_par->setInsetOwner(this);
284 return_par = return_par->next();
287 if (token != "\\end_inset") {
288 lex.printError("Missing \\end_inset at this point. "
295 int InsetText::ascent(BufferView * bv, LyXFont const &) const
297 insetAscent = getLyXText(bv)->firstRow()->ascent_of_text() +
298 TEXT_TO_INSET_OFFSET;
303 int InsetText::descent(BufferView * bv, LyXFont const &) const
305 LyXText * llt = getLyXText(bv);
306 insetDescent = llt->height - llt->firstRow()->ascent_of_text() +
307 TEXT_TO_INSET_OFFSET;
312 int InsetText::width(BufferView * bv, LyXFont const &) const
314 insetWidth = max(textWidth(bv), (int)getLyXText(bv)->width) +
315 (2 * TEXT_TO_INSET_OFFSET);
316 insetWidth = max(insetWidth, 10);
321 int InsetText::textWidth(BufferView * bv, bool fordraw) const
324 if (!autoBreakRows) {
327 w = getMaxWidth(bv, this);
330 return max(w - (2 * TEXT_TO_INSET_OFFSET),
331 (int)getLyXText(bv)->width);
335 return w - (2 * TEXT_TO_INSET_OFFSET);
339 void InsetText::draw(BufferView * bv, LyXFont const & f,
340 int baseline, float & x, bool cleared) const
345 Painter & pain = bv->painter();
347 // this is the first thing we have to ask because if the x pos
348 // changed we have to do a complete rebreak of the text as we
349 // may have few space to draw in. Well we should check on this too
351 if (top_x != int(x)) {
353 int nw = getMaxWidth(bv, this);
354 if (nw > 0 && old_max_width != nw) {
357 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
365 // call these methods so that insetWidth, insetAscent and
366 // insetDescent have the right values.
371 // repaint the background if needed
372 if (cleared && backgroundColor() != LColor::background) {
374 clearInset(bv, baseline, cleared);
378 // no draw is necessary !!!
379 if ((drawFrame_ == LOCKED) && !locked && !par->size()) {
382 top_baseline = baseline;
384 if (need_update & CLEAR_FRAME)
385 clearFrame(pain, cleared);
392 x += static_cast<float>(scroll());
394 // if top_x differs we did it already
395 if (!cleared && (top_x == int(x))
396 && ((need_update&(INIT|FULL)) || (top_baseline != baseline)
397 ||(last_drawn_width != insetWidth))) {
398 // Condition necessary to eliminate bug 59 attachment 37
399 if (baseline > 0) clearInset(bv, baseline, cleared);
405 frame_is_visible = false;
407 if (!cleared && (need_update == NONE)) {
409 drawFrame(pain, cleared);
413 top_baseline = baseline;
414 top_y = baseline - insetAscent;
416 if (last_drawn_width != insetWidth) {
418 clearInset(bv, baseline, cleared);
420 last_drawn_width = insetWidth;
423 if (the_locking_inset && (cpar(bv) == inset_par)
424 && (cpos(bv) == inset_pos)) {
425 inset_x = cx(bv) - top_x + drawTextXOffset;
426 inset_y = cy(bv) + drawTextYOffset;
428 if (!cleared && (need_update == CURSOR)
429 && !getLyXText(bv)->selection.set()) {
430 drawFrame(pain, cleared);
440 x += TEXT_TO_INSET_OFFSET;
442 Row * row = lt->firstRow();
443 int y_offset = baseline - row->ascent_of_text();
444 int ph = pain.paperHeight();
447 while ((row != 0) && ((y+row->height()) <= 0)) {
449 first += row->height();
455 if (cleared || (need_update&(INIT|FULL))) {
458 while ((row != 0) && (yf < ph)) {
459 lt->getVisibleRow(bv, y+y_offset, int(x), row,
465 } else if (!locked) {
466 if (need_update & CURSOR) {
467 bv->screen()->toggleSelection(lt, bv, true, y_offset,int(x));
468 lt->clearSelection();
469 lt->selection.cursor = lt->cursor;
471 bv->screen()->update(lt, bv, y_offset, int(x));
474 if (need_update & SELECTION) {
475 bv->screen()->toggleToggle(lt, bv, y_offset, int(x));
476 } else if (need_update & CURSOR) {
477 bv->screen()->toggleSelection(lt, bv, true, y_offset,int(x));
478 lt->clearSelection();
479 lt->selection.cursor = lt->cursor;
481 bv->screen()->update(lt, bv, y_offset, int(x));
486 lt->status(bv, LyXText::UNCHANGED);
487 if ((need_update != CURSOR_PAR) &&
488 ((drawFrame_ == ALWAYS) || ((drawFrame_ == LOCKED) && locked))) {
489 drawFrame(pain, cleared);
490 } else if (need_update & CLEAR_FRAME) {
491 clearFrame(pain, cleared);
494 x += insetWidth - TEXT_TO_INSET_OFFSET;
496 if (bv->text->status() == LyXText::CHANGED_IN_DRAW) {
498 } else if (need_update != INIT) {
506 void InsetText::drawFrame(Painter & pain, bool cleared) const
508 static int const ttoD2 = TEXT_TO_INSET_OFFSET / 2;
509 if (!frame_is_visible || cleared) {
510 frame_x = top_x + ttoD2;
511 frame_y = top_baseline - insetAscent + ttoD2;
512 frame_w = insetWidth - TEXT_TO_INSET_OFFSET;
513 frame_h = insetAscent + insetDescent - TEXT_TO_INSET_OFFSET;
514 pain.rectangle(frame_x, frame_y, frame_w, frame_h,
516 frame_is_visible = true;
521 void InsetText::clearFrame(Painter & pain, bool cleared) const
523 if (frame_is_visible) {
525 pain.rectangle(frame_x, frame_y, frame_w, frame_h,
528 frame_is_visible = false;
533 void InsetText::update(BufferView * bv, LyXFont const & font, bool reinit)
536 if (reinit && owner()) {
538 owner()->update(bv, font, true);
543 if (reinit || need_update == INIT) {
545 // we should put this call where we set need_update to INIT!
548 owner()->update(bv, font, true);
552 if (the_locking_inset) {
553 inset_x = cx(bv) - top_x + drawTextXOffset;
554 inset_y = cy(bv) + drawTextYOffset;
555 the_locking_inset->update(bv, font, reinit);
563 if ((need_update & CURSOR_PAR) && (lt->status() == LyXText::UNCHANGED) &&
566 lt->updateInset(bv, the_locking_inset);
568 if (lt->status() == LyXText::NEED_MORE_REFRESH)
576 void InsetText::setUpdateStatus(BufferView * bv, int what) const
578 // this does nothing dangerous so use only a localized buffer
579 LyXText * llt = getLyXText(bv);
582 // we have to redraw us full if our LyXText NEEDS_MORE_REFRES or
583 // if we don't break row so that we only have one row to update!
584 if ((llt->status() == LyXText::NEED_MORE_REFRESH) ||
586 (llt->status() == LyXText::NEED_VERY_LITTLE_REFRESH)))
589 } else if (llt->status() == LyXText::NEED_VERY_LITTLE_REFRESH) {
590 need_update |= CURSOR_PAR;
593 // this to not draw a selection when we redraw all of it!
594 if (need_update & CURSOR && !(need_update & SELECTION)) {
595 if (llt->selection.set())
597 llt->clearSelection();
602 void InsetText::updateLocal(BufferView * bv, int what, bool mark_dirty) const
604 if (!autoBreakRows && par->next())
605 collapseParagraphs(bv->buffer()->params);
612 setUpdateStatus(bv, what);
613 bool flag = (((need_update != CURSOR) && (need_update != NONE)) ||
614 (lt->status() != LyXText::UNCHANGED) || lt->selection.set());
618 bv->updateInset(const_cast<InsetText *>(this), mark_dirty);
622 if (need_update == CURSOR)
624 bv->owner()->showState();
625 bv->owner()->updateMenubar();
626 bv->owner()->updateToolbar();
627 if (old_par != cpar(bv)) {
628 bv->owner()->setLayout(cpar(bv)->getLayout());
634 string const InsetText::editMessage() const
636 return _("Opened Text Inset");
640 void InsetText::edit(BufferView * bv, int x, int y, unsigned int button)
642 UpdatableInset::edit(bv, x, y, button);
644 if (!bv->lockInset(this)) {
645 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
649 the_locking_inset = 0;
650 inset_pos = inset_x = inset_y = 0;
651 inset_boundary = false;
654 int tmp_y = (y < 0) ? 0 : y;
660 if (!checkAndActivateInset(bv, x, tmp_y, button))
661 lt->setCursorFromCoordinates(bv, x - drawTextXOffset,
663 lt->clearSelection();
665 // If the inset is empty set the language of the current font to the
666 // language to the surronding text (if different).
667 if (par->size() == 0 && !par->next() &&
668 bv->getParentLanguage(this) != lt->current_font.language())
670 LyXFont font(LyXFont::ALL_IGNORE);
671 font.setLanguage(bv->getParentLanguage(this));
672 setFont(bv, font, false);
677 updateLocal(bv, CURSOR, false);
681 void InsetText::edit(BufferView * bv, bool front)
683 UpdatableInset::edit(bv, front);
685 if (!bv->lockInset(this)) {
686 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
690 the_locking_inset = 0;
691 inset_pos = inset_x = inset_y = 0;
692 inset_boundary = false;
701 lt->setCursor(bv, par, 0);
706 // int const pos = (p->size() ? p->size()-1 : p->size());
707 lt->setCursor(bv, p, p->size());
709 lt->clearSelection();
711 // If the inset is empty set the language of the current font to the
712 // language to the surronding text (if different).
713 if (par->size() == 0 && !par->next() &&
714 bv->getParentLanguage(this) != lt->current_font.language()) {
715 LyXFont font(LyXFont::ALL_IGNORE);
716 font.setLanguage(bv->getParentLanguage(this));
717 setFont(bv, font, false);
722 updateLocal(bv, CURSOR, false);
726 void InsetText::insetUnlock(BufferView * bv)
728 if (the_locking_inset) {
729 the_locking_inset->insetUnlock(bv);
730 the_locking_inset = 0;
733 no_selection = false;
736 if (drawFrame_ == LOCKED)
737 code = CURSOR|CLEAR_FRAME;
745 if (lt->selection.set()) {
746 lt->clearSelection();
748 } else if (owner()) {
749 bv->owner()->setLayout(owner()->getLyXText(bv)
750 ->cursor.par()->getLayout());
752 bv->owner()->setLayout(bv->text->cursor.par()->getLayout());
753 // hack for deleteEmptyParMech
754 lt->setCursor(bv, par, 0);
757 updateLocal(bv, code, false);
760 void InsetText::lockInset(BufferView * bv, UpdatableInset * inset)
762 the_locking_inset = inset;
763 inset_x = cx(bv) - top_x + drawTextXOffset;
764 inset_y = cy(bv) + drawTextYOffset;
765 inset_pos = cpos(bv);
766 inset_par = cpar(bv);
767 inset_boundary = cboundary(bv);
768 updateLocal(bv, CURSOR, false);
772 bool InsetText::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
774 lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset("
778 if (!the_locking_inset) {
780 int const id = inset->id();
782 Paragraph::inset_iterator it =
783 p->inset_iterator_begin();
784 Paragraph::inset_iterator const end =
785 p->inset_iterator_end();
786 for (; it != end; ++it) {
787 if ((*it) == inset) {
788 getLyXText(bv)->setCursorIntern(bv, p, it.getPos());
789 lockInset(bv, inset);
792 if ((*it)->getInsetFromID(id)) {
793 getLyXText(bv)->setCursorIntern(bv, p, it.getPos());
794 lockInset(bv, static_cast<UpdatableInset *>(*it));
795 return the_locking_inset->lockInsetInInset(bv, inset);
802 if (inset == cpar(bv)->getInset(cpos(bv))) {
803 lyxerr[Debug::INSETS] << "OK" << endl;
804 lockInset(bv, inset);
806 } else if (the_locking_inset && (the_locking_inset == inset)) {
807 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
808 lyxerr[Debug::INSETS] << "OK" << endl;
809 inset_x = cx(bv) - top_x + drawTextXOffset;
810 inset_y = cy(bv) + drawTextYOffset;
812 lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
814 } else if (the_locking_inset) {
815 lyxerr[Debug::INSETS] << "MAYBE" << endl;
816 return the_locking_inset->lockInsetInInset(bv, inset);
818 lyxerr[Debug::INSETS] << "NOT OK" << endl;
823 bool InsetText::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
826 if (!the_locking_inset)
828 if (the_locking_inset == inset) {
829 the_locking_inset->insetUnlock(bv);
830 getLyXText(bv)->updateInset(bv, inset);
831 the_locking_inset = 0;
833 moveRight(bv, false);
834 old_par = 0; // force layout setting
838 updateLocal(bv, CURSOR, false);
841 return the_locking_inset->unlockInsetInInset(bv, inset, lr);
845 bool InsetText::updateInsetInInset(BufferView * bv, Inset * inset)
847 if (!autoBreakRows && par->next())
848 collapseParagraphs(bv->buffer()->params);
856 if (!the_locking_inset) {
857 bool found = lt->updateInset(bv, inset);
861 setUpdateStatus(bv, NONE);
864 if (the_locking_inset != inset) {
865 bool found = the_locking_inset->updateInsetInInset(bv, inset);
869 setUpdateStatus(bv, CURSOR_PAR);
872 bool found = lt->updateInset(bv, inset);
876 setUpdateStatus(bv, CURSOR_PAR);
877 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
878 inset_x = cx(bv) - top_x + drawTextXOffset;
879 inset_y = cy(bv) + drawTextYOffset;
886 void InsetText::insetButtonPress(BufferView * bv, int x, int y, int button)
890 // use this to check mouse motion for selection!
894 int tmp_x = x - drawTextXOffset;
895 int tmp_y = y + insetAscent - getLyXText(bv)->first;
896 Inset * inset = bv->checkInsetHit(getLyXText(bv), tmp_x, tmp_y);
899 if (the_locking_inset) {
900 if (the_locking_inset == inset) {
901 the_locking_inset->insetButtonPress(bv,
905 no_selection = false;
908 // otherwise unlock the_locking_inset and lock the new inset
909 the_locking_inset->insetUnlock(bv);
910 inset_x = cx(bv) - top_x + drawTextXOffset;
911 inset_y = cy(bv) + drawTextYOffset;
912 the_locking_inset = 0;
913 inset->insetButtonPress(bv, x - inset_x,
914 y - inset_y, button);
915 inset->edit(bv, x - inset_x, y - inset_y, button);
916 if (the_locking_inset)
917 updateLocal(bv, CURSOR, false);
918 no_selection = false;
921 // otherwise only unlock the_locking_inset
922 the_locking_inset->insetUnlock(bv);
923 the_locking_inset = 0;
925 if (bv->theLockingInset()) {
926 if (isHighlyEditableInset(inset)) {
927 UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
928 inset_x = cx(bv) - top_x + drawTextXOffset;
929 inset_y = cy(bv) + drawTextYOffset;
930 inset_pos = cpos(bv);
931 inset_par = cpar(bv);
932 inset_boundary = cboundary(bv);
933 the_locking_inset = uinset;
934 uinset->insetButtonPress(bv, x - inset_x, y - inset_y,
936 uinset->edit(bv, x - inset_x, y - inset_y, 0);
937 if (the_locking_inset)
938 updateLocal(bv, CURSOR, false);
939 no_selection = false;
943 if (!inset) { // && (button == 2)) {
944 bool paste_internally = false;
945 if ((button == 2) && getLyXText(bv)->selection.set()) {
946 localDispatch(bv, LFUN_COPY, "");
947 paste_internally = true;
955 lt->setCursorFromCoordinates(bv, x - drawTextXOffset,
957 // set the selection cursor!
958 lt->selection.cursor = lt->cursor;
959 lt->cursor.x_fix(lt->cursor.x());
961 if (lt->selection.set()) {
962 lt->clearSelection();
965 updateLocal(bv, FULL, false);
967 lt->clearSelection();
970 updateLocal(bv, CURSOR, false);
972 bv->owner()->setLayout(cpar(bv)->getLayout());
974 // Insert primary selection with middle mouse
975 // if there is a local selection in the current buffer,
978 if (paste_internally)
979 localDispatch(bv, LFUN_PASTE, "");
981 localDispatch(bv, LFUN_PASTESELECTION,
985 getLyXText(bv)->clearSelection();
988 no_selection = false;
992 bool InsetText::insetButtonRelease(BufferView * bv, int x, int y, int button)
994 if (the_locking_inset) {
995 return the_locking_inset->insetButtonRelease(bv,
996 x - inset_x, y - inset_y,
999 int tmp_x = x - drawTextXOffset;
1000 int tmp_y = y + insetAscent - getLyXText(bv)->first;
1001 Inset * inset = bv->checkInsetHit(getLyXText(bv), tmp_x, tmp_y);
1004 if (isHighlyEditableInset(inset)) {
1005 ret = inset->insetButtonRelease(bv, x - inset_x,
1006 y - inset_y, button);
1008 inset_x = cx(bv) - top_x + drawTextXOffset;
1009 inset_y = cy(bv) + drawTextYOffset;
1010 ret = inset->insetButtonRelease(bv, x - inset_x,
1011 y - inset_y, button);
1012 inset->edit(bv, x - inset_x,
1013 y - inset_y, button);
1015 updateLocal(bv, CURSOR_PAR, false);
1021 void InsetText::insetMotionNotify(BufferView * bv, int x, int y, int state)
1023 if (no_selection || ((mouse_x == x) && (mouse_y == y)))
1025 if (the_locking_inset) {
1026 the_locking_inset->insetMotionNotify(bv, x - inset_x,
1032 lt = getLyXText(bv);
1035 hideInsetCursor(bv);
1036 LyXCursor cur = lt->cursor;
1037 lt->setCursorFromCoordinates(bv, x - drawTextXOffset, y + insetAscent);
1038 if (cur == lt->cursor) {
1043 lt->setSelection(bv);
1044 bool flag = (lt->toggle_cursor.par() != lt->toggle_end_cursor.par() ||
1045 lt->toggle_cursor.pos() != lt->toggle_end_cursor.pos());
1049 updateLocal(bv, SELECTION, false);
1051 showInsetCursor(bv);
1055 void InsetText::insetKeyPress(XKeyEvent * xke)
1057 if (the_locking_inset) {
1058 the_locking_inset->insetKeyPress(xke);
1064 UpdatableInset::RESULT
1065 InsetText::localDispatch(BufferView * bv,
1066 kb_action action, string const & arg)
1068 bool was_empty = par->size() == 0 && !par->next();
1069 no_selection = false;
1070 UpdatableInset::RESULT
1071 result= UpdatableInset::localDispatch(bv, action, arg);
1072 if (result != UNDISPATCHED) {
1076 result = DISPATCHED;
1077 if ((action < 0) && arg.empty())
1080 if (the_locking_inset) {
1081 result = the_locking_inset->localDispatch(bv, action, arg);
1082 if (result == DISPATCHED_NOUPDATE)
1084 else if (result == DISPATCHED) {
1085 updateLocal(bv, CURSOR_PAR, false);
1087 } else if (result >= FINISHED) {
1089 case FINISHED_RIGHT:
1090 moveRightIntern(bv, false, false);
1091 result = DISPATCHED;
1094 if ((result = moveUp(bv)) >= FINISHED) {
1095 updateLocal(bv, CURSOR, false);
1096 bv->unlockInset(this);
1100 if ((result = moveDown(bv)) >= FINISHED) {
1101 updateLocal(bv, CURSOR, false);
1102 bv->unlockInset(this);
1106 result = DISPATCHED;
1109 the_locking_inset = 0;
1110 #ifdef WITH_WARNINGS
1111 #warning I changed this to always return Dispatched maybe it is wrong (20011001 Jug)
1116 hideInsetCursor(bv);
1119 lt = getLyXText(bv);
1123 int updflag = false;
1126 case LFUN_SELFINSERT:
1127 if (bv->buffer()->isReadonly()) {
1128 // setErrorMessage(N_("Document is read only"));
1132 /* Automatically delete the currently selected
1133 * text and replace it with what is being
1134 * typed in now. Depends on lyxrc settings
1135 * "auto_region_delete", which defaults to
1138 setUndo(bv, Undo::INSERT,
1139 lt->cursor.par(), lt->cursor.par()->next());
1141 if (lyxrc.auto_region_delete) {
1142 if (lt->selection.set()) {
1143 lt->cutSelection(bv, false);
1146 lt->clearSelection();
1147 for (string::size_type i = 0; i < arg.length(); ++i) {
1148 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], lt);
1151 lt->selection.cursor = lt->cursor;
1152 updwhat = CURSOR_PAR;
1154 result = DISPATCHED_NOUPDATE;
1156 // --- Cursor Movements -----------------------------------
1159 moveRight(bv, false, true);
1160 lt->setSelection(bv);
1161 updwhat = SELECTION;
1164 result = moveRight(bv);
1170 moveLeft(bv, false, true);
1171 lt->setSelection(bv);
1172 updwhat = SELECTION;
1176 result = moveLeft(bv);
1182 lt->setSelection(bv);
1183 updwhat = SELECTION;
1187 result = moveDown(bv);
1193 lt->setSelection(bv);
1194 updwhat = SELECTION;
1198 result = moveUp(bv);
1210 case LFUN_BACKSPACE: {
1211 setUndo(bv, Undo::DELETE,
1212 lt->cursor.par(), lt->cursor.par()->next());
1213 if (lt->selection.set())
1214 lt->cutSelection(bv);
1217 updwhat = CURSOR_PAR;
1223 setUndo(bv, Undo::DELETE,
1224 lt->cursor.par(), lt->cursor.par()->next());
1225 if (lt->selection.set()) {
1226 lt->cutSelection(bv);
1230 updwhat = CURSOR_PAR;
1236 setUndo(bv, Undo::DELETE,
1237 lt->cursor.par(), lt->cursor.par()->next());
1238 lt->cutSelection(bv);
1239 updwhat = CURSOR_PAR;
1246 lt->copySelection(bv);
1247 updwhat = CURSOR_PAR;
1249 case LFUN_PASTESELECTION:
1251 string const clip(bv->getClipboard());
1255 if (arg == "paragraph") {
1256 lt->insertStringAsParagraphs(bv, clip);
1258 lt->insertStringAsLines(bv, clip);
1260 updwhat = CURSOR_PAR;
1265 if (!autoBreakRows) {
1267 if (CutAndPaste::nrOfParagraphs() > 1) {
1268 Alert::alert(_("Impossible operation"),
1269 _("Cannot include more than one paragraph!"),
1274 setUndo(bv, Undo::INSERT,
1275 lt->cursor.par(), lt->cursor.par()->next());
1276 lt->pasteSelection(bv);
1277 updwhat = CURSOR_PAR;
1282 case LFUN_BREAKPARAGRAPH:
1283 if (!autoBreakRows) {
1284 result = DISPATCHED;
1287 lt->breakParagraph(bv, 0);
1291 case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
1292 if (!autoBreakRows) {
1293 result = DISPATCHED;
1296 lt->breakParagraph(bv, 1);
1301 case LFUN_BREAKLINE: {
1302 if (!autoBreakRows) {
1303 result = DISPATCHED;
1306 setUndo(bv, Undo::INSERT,
1307 lt->cursor.par(), lt->cursor.par()->next());
1308 lt->insertChar(bv, Paragraph::META_NEWLINE);
1309 updwhat = CURSOR_PAR;
1315 // do not set layouts on non breakable textinsets
1316 if (autoBreakRows) {
1317 layout_type cur_layout = cpar(bv)->layout;
1319 // Derive layout number from given argument (string)
1320 // and current buffer's textclass (number). */
1321 textclass_type tclass = bv->buffer()->params.textclass;
1322 std::pair <bool, layout_type> layout =
1323 textclasslist.NumberOfLayout(tclass, arg);
1325 // If the entry is obsolete, use the new one instead.
1327 string obs = textclasslist.Style(tclass,layout.second).
1330 layout = textclasslist.NumberOfLayout(tclass, obs);
1333 // see if we found the layout number:
1334 if (!layout.first) {
1335 string const msg = string(N_("Layout ")) + arg + N_(" not known");
1336 bv->owner()->getLyXFunc()->dispatch(LFUN_MESSAGE, msg);
1340 if (cur_layout != layout.second) {
1341 cur_layout = layout.second;
1342 lt->setLayout(bv, layout.second);
1343 bv->owner()->setLayout(cpar(bv)->getLayout());
1344 updwhat = CURSOR_PAR;
1348 // reset the layout box
1349 bv->owner()->setLayout(cpar(bv)->getLayout());
1352 case LFUN_PARAGRAPH_SPACING:
1353 // This one is absolutely not working. When fiddling with this
1354 // it also seems to me that the paragraphs inside the insettext
1355 // inherit bufferparams/paragraphparams in a strange way. (Lgb)
1357 Paragraph * par = lt->cursor.par();
1358 Spacing::Space cur_spacing = par->params().spacing().getSpace();
1359 float cur_value = 1.0;
1360 if (cur_spacing == Spacing::Other) {
1361 cur_value = par->params().spacing().getValue();
1364 istringstream istr(arg.c_str());
1367 Spacing::Space new_spacing = cur_spacing;
1368 float new_value = cur_value;
1370 lyxerr << "Missing argument to `paragraph-spacing'"
1372 } else if (tmp == "single") {
1373 new_spacing = Spacing::Single;
1374 } else if (tmp == "onehalf") {
1375 new_spacing = Spacing::Onehalf;
1376 } else if (tmp == "double") {
1377 new_spacing = Spacing::Double;
1378 } else if (tmp == "other") {
1379 new_spacing = Spacing::Other;
1382 lyxerr << "new_value = " << tmpval << endl;
1385 } else if (tmp == "default") {
1386 new_spacing = Spacing::Default;
1388 lyxerr << _("Unknown spacing argument: ")
1391 if (cur_spacing != new_spacing || cur_value != new_value) {
1392 par->params().spacing(Spacing(new_spacing, new_value));
1393 updwhat = CURSOR_PAR;
1400 if (!bv->Dispatch(action, arg))
1401 result = UNDISPATCHED;
1408 updateLocal(bv, updwhat, updflag);
1409 /// If the action has deleted all text in the inset, we need to change the
1410 // language to the language of the surronding text.
1411 if (!was_empty && par->size() == 0 && !par->next()) {
1412 LyXFont font(LyXFont::ALL_IGNORE);
1413 font.setLanguage(bv->getParentLanguage(this));
1414 setFont(bv, font, false);
1417 if (result < FINISHED) {
1418 showInsetCursor(bv);
1420 bv->unlockInset(this);
1425 int InsetText::latex(Buffer const * buf, ostream & os, bool, bool) const
1428 buf->latexParagraphs(os, par, 0, texrow);
1429 return texrow.rows();
1433 int InsetText::ascii(Buffer const * buf, ostream & os, int linelen) const
1435 Paragraph * p = par;
1436 unsigned int lines = 0;
1439 string const tmp = buf->asciiParagraph(p, linelen, p->previous()==0);
1440 lines += lyx::count(tmp.begin(), tmp.end(), '\n');
1448 int InsetText::docbook(Buffer const * buf, ostream & os) const
1450 Paragraph * p = par;
1451 unsigned int lines = 0;
1453 vector<string> environment_stack(10);
1454 vector<string> environment_inner(10);
1456 int const command_depth = 0;
1459 Paragraph::depth_type depth = 0; // paragraph depth
1463 int desc_on = 0; // description mode
1465 LyXLayout const & style =
1466 textclasslist.Style(buf->params.textclass,
1469 // environment tag closing
1470 for (; depth > p->params().depth(); --depth) {
1471 if (environment_inner[depth] != "!-- --") {
1472 item_name = "listitem";
1473 buf->sgmlCloseTag(os, command_depth + depth,
1475 if (environment_inner[depth] == "varlistentry")
1476 buf->sgmlCloseTag(os, depth+command_depth,
1477 environment_inner[depth]);
1479 buf->sgmlCloseTag(os, depth + command_depth,
1480 environment_stack[depth]);
1481 environment_stack[depth].erase();
1482 environment_inner[depth].erase();
1485 if (depth == p->params().depth()
1486 && environment_stack[depth] != style.latexname()
1487 && !environment_stack[depth].empty()) {
1488 if (environment_inner[depth] != "!-- --") {
1489 item_name= "listitem";
1490 buf->sgmlCloseTag(os, command_depth+depth,
1492 if (environment_inner[depth] == "varlistentry")
1493 buf->sgmlCloseTag(os,
1494 depth + command_depth,
1495 environment_inner[depth]);
1498 buf->sgmlCloseTag(os, depth + command_depth,
1499 environment_stack[depth]);
1501 environment_stack[depth].erase();
1502 environment_inner[depth].erase();
1505 // Write opening SGML tags.
1506 switch (style.latextype) {
1507 case LATEX_PARAGRAPH:
1508 buf->sgmlOpenTag(os, depth + command_depth,
1513 buf->sgmlError(p, 0,
1514 _("Error : LatexType Command not allowed here.\n"));
1518 case LATEX_ENVIRONMENT:
1519 case LATEX_ITEM_ENVIRONMENT:
1520 if (depth < p->params().depth()) {
1521 depth = p->params().depth();
1522 environment_stack[depth].erase();
1525 if (environment_stack[depth] != style.latexname()) {
1526 if(environment_stack.size() == depth + 1) {
1527 environment_stack.push_back("!-- --");
1528 environment_inner.push_back("!-- --");
1530 environment_stack[depth] = style.latexname();
1531 environment_inner[depth] = "!-- --";
1532 buf->sgmlOpenTag(os, depth + command_depth,
1533 environment_stack[depth]);
1535 if (environment_inner[depth] != "!-- --") {
1536 item_name= "listitem";
1537 buf->sgmlCloseTag(os,
1538 command_depth + depth,
1540 if (environment_inner[depth] == "varlistentry")
1541 buf->sgmlCloseTag(os,
1542 depth + command_depth,
1543 environment_inner[depth]);
1547 if (style.latextype == LATEX_ENVIRONMENT) {
1548 if (!style.latexparam().empty()) {
1549 if(style.latexparam() == "CDATA")
1552 buf->sgmlOpenTag(os, depth + command_depth,
1553 style.latexparam());
1558 desc_on = (style.labeltype == LABEL_MANUAL);
1561 environment_inner[depth]= "varlistentry";
1563 environment_inner[depth]= "listitem";
1565 buf->sgmlOpenTag(os, depth + 1 + command_depth,
1566 environment_inner[depth]);
1570 buf->sgmlOpenTag(os, depth + 1 + command_depth,
1574 buf->sgmlOpenTag(os, depth + 1 + command_depth,
1579 buf->sgmlOpenTag(os, depth + command_depth,
1584 buf->simpleDocBookOnePar(os, p, desc_on,
1585 depth + 1 + command_depth);
1589 // write closing SGML tags
1590 switch (style.latextype) {
1591 case LATEX_ENVIRONMENT:
1592 if (!style.latexparam().empty()) {
1593 if(style.latexparam() == "CDATA")
1596 buf->sgmlCloseTag(os, depth + command_depth,
1597 style.latexparam());
1600 case LATEX_ITEM_ENVIRONMENT:
1601 if (desc_on == 1) break;
1603 buf->sgmlCloseTag(os, depth + 1 + command_depth, end_tag);
1605 case LATEX_PARAGRAPH:
1606 buf->sgmlCloseTag(os, depth + command_depth, style.latexname());
1609 buf->sgmlCloseTag(os, depth + command_depth, style.latexname());
1615 for (int d = depth; d >= 0; --d) {
1616 if (!environment_stack[depth].empty()) {
1617 if (environment_inner[depth] != "!-- --") {
1618 item_name = "listitem";
1619 buf->sgmlCloseTag(os, command_depth + depth,
1621 if (environment_inner[depth] == "varlistentry")
1622 buf->sgmlCloseTag(os, depth + command_depth,
1623 environment_inner[depth]);
1626 buf->sgmlCloseTag(os, depth + command_depth,
1627 environment_stack[depth]);
1635 void InsetText::validate(LaTeXFeatures & features) const
1637 Paragraph * p = par;
1639 p->validate(features);
1645 int InsetText::beginningOfMainBody(Buffer const * buf, Paragraph * p) const
1647 if (textclasslist.Style(buf->params.textclass,
1648 p->getLayout()).labeltype != LABEL_MANUAL)
1651 return p->beginningOfMainBody();
1655 void InsetText::getCursorPos(BufferView * bv,
1656 int & x, int & y) const
1658 if (the_locking_inset) {
1659 the_locking_inset->getCursorPos(bv, x, y);
1667 unsigned int InsetText::insetInInsetY()
1669 if (!the_locking_inset)
1672 return (inset_y + the_locking_inset->insetInInsetY());
1676 void InsetText::toggleInsetCursor(BufferView * bv)
1678 if (the_locking_inset) {
1679 the_locking_inset->toggleInsetCursor(bv);
1683 LyXFont const font(getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv)));
1685 int const asc = lyxfont::maxAscent(font);
1686 int const desc = lyxfont::maxDescent(font);
1688 if (isCursorVisible())
1689 bv->hideLockedInsetCursor();
1691 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1692 toggleCursorVisible();
1696 void InsetText::showInsetCursor(BufferView * bv, bool show)
1698 if (the_locking_inset) {
1699 the_locking_inset->showInsetCursor(bv, show);
1702 if (!isCursorVisible()) {
1703 LyXFont const font =
1704 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1706 int const asc = lyxfont::maxAscent(font);
1707 int const desc = lyxfont::maxDescent(font);
1709 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1711 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1712 setCursorVisible(true);
1717 void InsetText::hideInsetCursor(BufferView * bv)
1719 if (isCursorVisible()) {
1720 bv->hideLockedInsetCursor();
1721 setCursorVisible(false);
1723 if (the_locking_inset)
1724 the_locking_inset->hideInsetCursor(bv);
1728 void InsetText::fitInsetCursor(BufferView * bv) const
1730 if (the_locking_inset) {
1731 the_locking_inset->fitInsetCursor(bv);
1734 LyXFont const font =
1735 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1737 int const asc = lyxfont::maxAscent(font);
1738 int const desc = lyxfont::maxDescent(font);
1740 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1744 UpdatableInset::RESULT
1745 InsetText::moveRight(BufferView * bv, bool activate_inset, bool selecting)
1747 if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1748 return moveLeftIntern(bv, false, activate_inset, selecting);
1750 return moveRightIntern(bv, false, activate_inset, selecting);
1754 UpdatableInset::RESULT
1755 InsetText::moveLeft(BufferView * bv, bool activate_inset, bool selecting)
1757 if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1758 return moveRightIntern(bv, true, activate_inset, selecting);
1760 return moveLeftIntern(bv, true, activate_inset, selecting);
1764 UpdatableInset::RESULT
1765 InsetText::moveRightIntern(BufferView * bv, bool behind,
1766 bool activate_inset, bool selecting)
1768 if (!cpar(bv)->next() && (cpos(bv) >= cpar(bv)->size()))
1769 return FINISHED_RIGHT;
1770 if (activate_inset && checkAndActivateInset(bv, behind))
1772 getLyXText(bv)->cursorRight(bv);
1774 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1775 return DISPATCHED_NOUPDATE;
1779 UpdatableInset::RESULT
1780 InsetText::moveLeftIntern(BufferView * bv, bool behind,
1781 bool activate_inset, bool selecting)
1783 if (!cpar(bv)->previous() && (cpos(bv) <= 0))
1785 getLyXText(bv)->cursorLeft(bv);
1787 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1788 if (activate_inset && checkAndActivateInset(bv, behind))
1790 return DISPATCHED_NOUPDATE;
1794 UpdatableInset::RESULT
1795 InsetText::moveUp(BufferView * bv)
1797 if (!crow(bv)->previous())
1799 getLyXText(bv)->cursorUp(bv);
1800 return DISPATCHED_NOUPDATE;
1804 UpdatableInset::RESULT
1805 InsetText::moveDown(BufferView * bv)
1807 if (!crow(bv)->next())
1808 return FINISHED_DOWN;
1809 getLyXText(bv)->cursorDown(bv);
1810 return DISPATCHED_NOUPDATE;
1814 bool InsetText::insertInset(BufferView * bv, Inset * inset)
1816 if (the_locking_inset) {
1817 if (the_locking_inset->insetAllowed(inset))
1818 return the_locking_inset->insertInset(bv, inset);
1823 lt = getLyXText(bv);
1826 setUndo(bv, Undo::FINISH, lt->cursor.par(), lt->cursor.par()->next());
1828 inset->setOwner(this);
1829 hideInsetCursor(bv);
1830 lt->insertInset(bv, inset);
1834 updateLocal(bv, CURSOR_PAR|CURSOR, true);
1840 bool InsetText::insetAllowed(Inset::Code code) const
1842 // in_insetAllowed is a really gross hack,
1843 // to allow us to call the owner's insetAllowed
1844 // without stack overflow, which can happen
1845 // when the owner uses InsetCollapsable::insetAllowed()
1847 if (in_insetAllowed)
1849 in_insetAllowed = true;
1850 if (the_locking_inset)
1851 ret = the_locking_inset->insetAllowed(code);
1853 ret = owner()->insetAllowed(code);
1854 in_insetAllowed = false;
1859 UpdatableInset * InsetText::getLockingInset() const
1861 return the_locking_inset ? the_locking_inset->getLockingInset() :
1862 const_cast<InsetText *>(this);
1866 UpdatableInset * InsetText::getFirstLockingInsetOfType(Inset::Code c)
1870 if (the_locking_inset)
1871 return the_locking_inset->getFirstLockingInsetOfType(c);
1876 bool InsetText::showInsetDialog(BufferView * bv) const
1878 if (the_locking_inset)
1879 return the_locking_inset->showInsetDialog(bv);
1884 std::vector<string> const InsetText::getLabelList() const
1886 std::vector<string> label_list;
1888 Paragraph * tpar = par;
1890 Paragraph::inset_iterator beg = tpar->inset_iterator_begin();
1891 Paragraph::inset_iterator end = tpar->inset_iterator_end();
1892 for (; beg != end; ++beg) {
1893 std::vector<string> const l = (*beg)->getLabelList();
1894 label_list.insert(label_list.end(), l.begin(), l.end());
1896 tpar = tpar->next();
1902 void InsetText::setFont(BufferView * bv, LyXFont const & font, bool toggleall,
1905 if (the_locking_inset) {
1906 the_locking_inset->setFont(bv, font, toggleall, selectall);
1909 if ((!par->next() && !par->size()) || !cpar(bv)->size()) {
1910 getLyXText(bv)->setFont(bv, font, toggleall);
1915 lt = getLyXText(bv);
1918 if (lt->selection.set()) {
1919 setUndo(bv, Undo::EDIT, lt->cursor.par(), lt->cursor.par()->next());
1923 lt->toggleFree(bv, font, toggleall);
1925 lt->clearSelection();
1927 bool flag = (selectall || lt->selection.set());
1931 updateLocal(bv, FULL, true);
1933 updateLocal(bv, CURSOR_PAR, true);
1937 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1939 if (cpar(bv)->isInset(cpos(bv))) {
1943 static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
1944 if (!isHighlyEditableInset(inset))
1946 LyXFont const font =
1947 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1949 x = inset->width(bv, font);
1950 y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1953 y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1955 //inset_x = cx(bv) - top_x + drawTextXOffset;
1956 //inset_y = cy(bv) + drawTextYOffset;
1957 inset->edit(bv, x, y, 0);
1958 if (!the_locking_inset)
1960 updateLocal(bv, CURSOR, false);
1967 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1970 x -= drawTextXOffset;
1972 int dummyy = y + insetAscent;
1973 Inset * inset = bv->checkInsetHit(getLyXText(bv), dummyx, dummyy);
1980 inset_x = cx(bv) - top_x + drawTextXOffset;
1981 inset_y = cy(bv) + drawTextYOffset;
1982 inset->edit(bv, x - inset_x, y - inset_y, button);
1983 if (!the_locking_inset)
1985 updateLocal(bv, CURSOR, false);
1992 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1995 int w = UpdatableInset::getMaxWidth(bv, inset);
2000 w = w - top_x + owner()->x();
2003 w -= (2 * TEXT_TO_INSET_OFFSET);
2006 return UpdatableInset::getMaxWidth(bv, inset);
2011 void InsetText::setParagraphData(Paragraph * p, bool same_id)
2013 // we have to unlock any locked inset otherwise we're in troubles
2014 the_locking_inset = 0;
2016 Paragraph * tmp = par->next();
2021 par = new Paragraph(*p, same_id);
2022 par->setInsetOwner(this);
2023 Paragraph * np = par;
2026 np->next(new Paragraph(*p, same_id));
2027 np->next()->previous(np);
2029 np->setInsetOwner(this);
2036 void InsetText::setText(string const & data)
2039 LyXFont font(LyXFont::ALL_SANE);
2040 for (unsigned int i=0; i < data.length(); ++i)
2041 par->insertChar(i, data[i], font);
2045 void InsetText::setAutoBreakRows(bool flag)
2047 if (flag != autoBreakRows) {
2048 autoBreakRows = flag;
2056 void InsetText::setDrawFrame(BufferView * bv, DrawFrame how)
2058 if (how != drawFrame_) {
2061 updateLocal(bv, DRAW_FRAME, false);
2066 void InsetText::setFrameColor(BufferView * bv, LColor::color col)
2068 if (frame_color != col) {
2071 updateLocal(bv, DRAW_FRAME, false);
2076 int InsetText::cx(BufferView * bv) const
2078 // we do nothing dangerous so we use a local cache
2079 LyXText * llt = getLyXText(bv);
2080 int x = llt->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
2081 if (the_locking_inset) {
2082 LyXFont font = llt->getFont(bv->buffer(), llt->cursor.par(),
2084 if (font.isVisibleRightToLeft())
2085 x -= the_locking_inset->width(bv, font);
2091 int InsetText::cy(BufferView * bv) const
2094 return getLyXText(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
2098 pos_type InsetText::cpos(BufferView * bv) const
2100 return getLyXText(bv)->cursor.pos();
2104 Paragraph * InsetText::cpar(BufferView * bv) const
2106 return getLyXText(bv)->cursor.par();
2110 bool InsetText::cboundary(BufferView * bv) const
2112 return getLyXText(bv)->cursor.boundary();
2116 Row * InsetText::crow(BufferView * bv) const
2118 return getLyXText(bv)->cursor.row();
2122 LyXText * InsetText::getLyXText(BufferView const * lbv,
2123 bool const recursive) const
2125 if (!recursive && (cached_bview == lbv)) {
2126 LyXText * lt = cached_text.get();
2127 lyx::Assert(lt && lt->firstRow()->par() == par);
2131 // Super UGLY! (Lgb)
2132 BufferView * bv = const_cast<BufferView *>(lbv);
2135 Cache::iterator it = cache.find(bv);
2137 if (it != cache.end()) {
2140 } else if (do_resize) {
2141 resizeLyXText(do_resize);
2143 if (lt || !it->second.remove) {
2144 lyx::Assert(it->second.text.get());
2145 cached_text = it->second.text;
2146 if (recursive && the_locking_inset) {
2147 return the_locking_inset->getLyXText(bv, true);
2149 return cached_text.get();
2150 } else if (it->second.remove) {
2152 saveLyXTextState(it->second.text.get());
2158 // when we have to reinit the existing LyXText!
2160 it->second.text->init(bv);
2161 restoreLyXTextState(bv, it->second.text.get());
2162 it->second.remove = false;
2164 cached_text = it->second.text;
2165 if (the_locking_inset && recursive) {
2166 return the_locking_inset->getLyXText(bv);
2168 return cached_text.get();
2171 // we are here only if we don't have a BufferView * in the cache!!!
2173 cached_text.reset(new LyXText(const_cast<InsetText *>(this)));
2174 cached_text->init(bv);
2175 restoreLyXTextState(bv, cached_text.get());
2177 cache.insert(make_pair(bv, cached_text));
2179 if (the_locking_inset && recursive) {
2180 return the_locking_inset->getLyXText(bv);
2182 return cached_text.get();
2186 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
2190 Cache::iterator it = cache.find(bv);
2192 if (it == cache.end()) {
2196 lyx::Assert(it->second.text.get());
2198 it->second.remove = true;
2200 /// then remove all LyXText in text-insets
2201 Paragraph * p = par;
2202 for (; p; p = p->next()) {
2203 p->deleteInsetsLyXText(bv);
2209 void InsetText::resizeLyXText(BufferView * bv, bool force) const
2212 // we cannot resize this because we are in use!
2213 // so do this on the next possible getLyXText()
2218 // lyxerr << "InsetText::resizeLyXText\n";
2219 if (!par->next() && !par->size()) { // no data, resize not neccessary!
2220 // we have to do this as a fixed width may have changed!
2221 LyXText * t = getLyXText(bv);
2222 saveLyXTextState(t);
2224 restoreLyXTextState(bv, t);
2227 // one endless line, resize normally not necessary
2228 if (!force && getMaxWidth(bv, this) < 0)
2231 Cache::iterator it = cache.find(bv);
2232 if (it == cache.end()) {
2235 lyx::Assert(it->second.text.get());
2237 LyXText * t = it->second.text.get();
2238 saveLyXTextState(t);
2239 for (Paragraph * p = par; p; p = p->next()) {
2240 p->resizeInsetsLyXText(bv);
2243 restoreLyXTextState(bv, t);
2244 if (the_locking_inset) {
2245 inset_x = cx(bv) - top_x + drawTextXOffset;
2246 inset_y = cy(bv) + drawTextYOffset;
2250 t->first = bv->screen()->topCursorVisible(t);
2253 updateLocal(bv, FULL, false);
2254 // this will scroll the screen such that the cursor becomes visible
2255 bv->updateScrollbar();
2257 need_update |= FULL;
2262 void InsetText::reinitLyXText() const
2265 // we cannot resize this because we are in use!
2266 // so do this on the next possible getLyXText()
2272 // lyxerr << "InsetText::reinitLyXText\n";
2273 for(Cache::iterator it = cache.begin(); it != cache.end(); ++it) {
2274 lyx::Assert(it->second.text.get());
2276 LyXText * t = it->second.text.get();
2277 BufferView * bv = it->first;
2279 saveLyXTextState(t);
2280 for (Paragraph * p = par; p; p = p->next()) {
2281 p->resizeInsetsLyXText(bv);
2284 restoreLyXTextState(bv, t);
2285 if (the_locking_inset) {
2286 inset_x = cx(bv) - top_x + drawTextXOffset;
2287 inset_y = cy(bv) + drawTextYOffset;
2290 t->first = bv->screen()->topCursorVisible(t);
2293 updateLocal(bv, FULL, false);
2294 // this will scroll the screen such that the cursor becomes visible
2295 bv->updateScrollbar();
2303 void InsetText::removeNewlines()
2305 bool changed = false;
2307 for (Paragraph * p = par; p; p = p->next()) {
2308 for (int i = 0; i < p->size(); ++i) {
2309 if (p->getChar(i) == Paragraph::META_NEWLINE) {
2320 bool InsetText::nodraw() const
2322 if (the_locking_inset)
2323 return the_locking_inset->nodraw();
2324 return UpdatableInset::nodraw();
2328 int InsetText::scroll(bool recursive) const
2330 int sx = UpdatableInset::scroll(false);
2332 if (recursive && the_locking_inset)
2333 sx += the_locking_inset->scroll(recursive);
2339 bool InsetText::doClearArea() const
2341 return !locked || (need_update & (FULL|INIT));
2345 void InsetText::selectAll(BufferView * bv)
2347 getLyXText(bv)->cursorTop(bv);
2348 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
2349 getLyXText(bv)->cursorBottom(bv);
2350 getLyXText(bv)->setSelection(bv);
2354 void InsetText::clearSelection(BufferView * bv)
2356 getLyXText(bv)->clearSelection();
2360 void InsetText::clearInset(BufferView * bv, int baseline, bool & cleared) const
2362 Painter & pain = bv->painter();
2364 int h = insetAscent + insetDescent;
2365 int ty = baseline - insetAscent;
2371 if ((ty + h) > pain.paperHeight())
2372 h = pain.paperHeight();
2373 if ((top_x + drawTextXOffset + w) > pain.paperWidth())
2374 w = pain.paperWidth();
2375 // w -= TEXT_TO_INSET_OFFSET;
2376 pain.fillRectangle(top_x, ty, w+1, h+1, backgroundColor());
2379 frame_is_visible = false;
2383 Paragraph * InsetText::getParFromID(int id) const
2386 Paragraph * result = par;
2387 Paragraph * ires = 0;
2388 while (result && result->id() != id) {
2389 if ((ires = result->getParFromID(id)))
2391 result = result->next();
2395 Paragraph * tmp = par;
2397 if (tmp->id() == id) {
2400 Paragraph * tmp2 = tmp->getParFromID(id);
2411 Paragraph * InsetText::firstParagraph() const
2414 if (the_locking_inset)
2415 if ((result = the_locking_inset->firstParagraph()))
2421 Paragraph * InsetText::getFirstParagraph(int i) const
2423 return (i == 0) ? par : 0;
2427 LyXCursor const & InsetText::cursor(BufferView * bv) const
2429 if (the_locking_inset)
2430 return the_locking_inset->cursor(bv);
2431 return getLyXText(bv)->cursor;
2435 Paragraph * InsetText::paragraph() const
2441 void InsetText::paragraph(Paragraph * p)
2443 // GENERAL COMMENT: We don't have to free the old paragraphs as the
2444 // caller of this function has to take care of it. This IS important
2445 // as we could have to insert a paragraph before this one and just
2446 // link the actual to a new ones next and set it with this function
2449 // set ourself as owner for all the paragraphs inserted!
2450 Paragraph * np = par;
2452 np->setInsetOwner(this);
2456 // redraw myself when asked for
2461 Inset * InsetText::getInsetFromID(int id_arg) const
2464 return const_cast<InsetText *>(this);
2466 Paragraph * lp = par;
2469 for (Paragraph::inset_iterator it = lp->inset_iterator_begin(),
2470 en = lp->inset_iterator_end();
2473 if ((*it)->id() == id_arg)
2475 Inset * in = (*it)->getInsetFromID(id_arg);
2485 string const InsetText::selectNextWordToSpellcheck(BufferView * bv, float & value) const
2491 lt = getLyXText(bv);
2494 if (the_locking_inset) {
2495 str = the_locking_inset->selectNextWordToSpellcheck(bv, value);
2502 // we have to go on checking so move cusor to the next char
2503 lt->cursor.pos(lt->cursor.pos() + 1);
2505 str = lt->selectNextWordToSpellcheck(bv, value);
2507 bv->unlockInset(const_cast<InsetText *>(this));
2516 void InsetText::selectSelectedWord(BufferView * bv)
2518 if (the_locking_inset) {
2519 the_locking_inset->selectSelectedWord(bv);
2522 getLyXText(bv)->selectSelectedWord(bv);
2523 updateLocal(bv, SELECTION, false);
2527 void InsetText::toggleSelection(BufferView * bv, bool kill_selection)
2529 if (the_locking_inset) {
2530 the_locking_inset->toggleSelection(bv, kill_selection);
2534 lt = getLyXText(bv);
2538 int x = top_x + TEXT_TO_INSET_OFFSET;
2540 Row * row = lt->firstRow();
2541 int y_offset = top_baseline - row->ascent_of_text();
2543 while ((row != 0) && ((y+row->height()) <= 0)) {
2550 if (need_update & SELECTION)
2552 bv->screen()->toggleSelection(lt, bv, kill_selection, y_offset, x);
2558 bool InsetText::searchForward(BufferView * bv, string const & str,
2561 if (the_locking_inset) {
2562 if (the_locking_inset->searchForward(bv, str, cs, mw))
2566 lt = getLyXText(bv);
2569 Paragraph * lpar = lt->cursor.par();
2570 pos_type pos = lt->cursor.pos();
2571 if (pos < lpar->size() - 1)
2575 lpar = lpar->next();
2580 // we have to unlock ourself in this function by default!
2581 bv->unlockInset(const_cast<InsetText *>(this));
2584 lt->setCursor(bv, lpar, pos);
2588 if (LyXFind(bv, str, true, true, cs , mw)) {
2591 // we have to unlock ourself in this function by default!
2592 bv->unlockInset(const_cast<InsetText *>(this));
2596 bool InsetText::searchBackward(BufferView * bv, string const & str,
2599 if (the_locking_inset)
2600 if (the_locking_inset->searchBackward(bv, str, cs, mw))
2602 if (LyXFind(bv, str, false, true, cs, mw)) {
2605 // we have to unlock ourself in this function by default!
2606 bv->unlockInset(const_cast<InsetText *>(this));
2611 bool InsetText::checkInsertChar(LyXFont & font)
2614 return owner()->checkInsertChar(font);
2619 void InsetText::collapseParagraphs(BufferParams const & bparams) const
2621 while(par->next()) {
2622 if (!par->isSeparator(par->size()-1))
2623 par->insertChar(par->size()-1, ' ');
2624 par->pasteParagraph(bparams);