2 /* This file is part of
3 * ======================================================
5 * LyX, The Document Processor
7 * Copyright 1998-2000 The LyX Team.
9 * ======================================================
20 #pragma implementation
23 #include "insettext.h"
24 #include "lyxparagraph.h"
28 #include "commandtags.h"
31 #include "BufferView.h"
33 #include "LaTeXFeatures.h"
35 #include "lyx_gui_misc.h"
37 #include "lyxcursor.h"
38 #include "CutAndPaste.h"
41 #include "support/textutils.h"
42 #include "support/LAssert.h"
46 #include "trans_mgr.h"
47 #include "lyxscreen.h"
57 extern unsigned char getCurrentTextClass(Buffer *);
58 extern bool math_insert_greek(BufferView *, char);
59 extern int greek_kb_flag;
61 InsetText::InsetText()
63 par = new LyXParagraph;
68 InsetText::InsetText(InsetText const & ins)
73 autoBreakRows = ins.autoBreakRows;
77 InsetText & InsetText::operator=(InsetText const & it)
80 autoBreakRows = it.autoBreakRows;
85 void InsetText::init(InsetText const * ins)
93 the_locking_inset = 0;
99 autoBreakRows = false;
103 SetParagraphData(ins->par);
104 autoBreakRows = ins->autoBreakRows;
105 drawFrame = ins->drawFrame;
107 par->SetInsetOwner(this);
108 frame_color = LColor::insetframe;
111 last_drawn_width = -1;
115 InsetText::~InsetText()
117 // delete all instances of LyXText before deleting the paragraps used
119 for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit) {
120 delete (*cit).second;
124 LyXParagraph * p = par->next_;
133 LyXParagraph * tmp = par->next();
141 void InsetText::clear()
143 // delete all instances of LyXText before deleting the paragraps used
145 for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit){
146 delete (*cit).second;
150 LyXParagraph * p = par->next_;
159 LyXParagraph * tmp = par->next();
164 par = new LyXParagraph;
168 Inset * InsetText::Clone(Buffer const &) const
170 InsetText * t = new InsetText(*this);
175 void InsetText::Write(Buffer const * buf, ostream & os) const
178 WriteParagraphData(buf, os);
182 void InsetText::WriteParagraphData(Buffer const * buf, ostream & os) const
184 par->writeFile(buf, os, buf->params, 0, 0);
188 void InsetText::Read(Buffer const * buf, LyXLex & lex)
192 LyXParagraph * return_par = 0;
193 char depth = 0; // signed or unsigned?
195 LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
196 LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
198 LyXFont font(LyXFont::ALL_INHERIT);
200 // delete all instances of LyXText before deleting the paragraps used
202 for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit) {
203 delete (*cit).second;
208 LyXParagraph * p = par->next_;
217 LyXParagraph * tmp = par->next();
222 par = new LyXParagraph;
225 token = lex.GetString();
228 if (token == "\\end_inset")
230 if (const_cast<Buffer*>(buf)->
231 parseSingleLyXformat2Token(lex, par, return_par,
232 token, pos, depth, font
234 , footnoteflag, footnotekind
238 // the_end read this should NEVER happen
239 lex.printError("\\the_end read in inset! Error in document!");
247 return_par->SetInsetOwner(this);
249 return_par = return_par->next_;
251 return_par = return_par->next();
255 if (token != "\\end_inset") {
256 lex.printError("Missing \\end_inset at this point. "
263 int InsetText::ascent(BufferView * bv, LyXFont const &) const
266 Row * row = TEXT(bv)->GetRowNearY(y_temp);
267 insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
272 int InsetText::descent(BufferView * bv, LyXFont const &) const
275 Row * row = TEXT(bv)->GetRowNearY(y_temp);
276 insetDescent = TEXT(bv)->height - row->ascent_of_text() +
277 TEXT_TO_INSET_OFFSET;
282 int InsetText::width(BufferView * bv, LyXFont const &) const
284 insetWidth = max(textWidth(bv),
285 (int)TEXT(bv)->width + (2 * TEXT_TO_INSET_OFFSET));
290 int InsetText::textWidth(BufferView * bv) const
292 int const w = getMaxWidth(bv, this);
297 void InsetText::draw(BufferView * bv, LyXFont const & f,
298 int baseline, float & x, bool cleared) const
300 Painter & pain = bv->painter();
302 // no draw is necessary !!!
303 if ((drawFrame == LOCKED) && !locked && !par->size()) {
304 if (!cleared && (need_update & CLEAR_FRAME)) {
305 pain.rectangle(top_x + 1, baseline - insetAscent + 1,
307 insetAscent + insetDescent - 1,
311 top_baseline = baseline;
318 UpdatableInset::draw(bv, f, baseline, x, cleared);
320 // update insetWidth and insetHeight with dummy calls
322 (void)descent(bv, f);
325 // if top_x differs we have a rule down and we don't have to clear anything
326 if (!cleared && (top_x == int(x)) &&
327 ((need_update == INIT) || (need_update == FULL) || (top_baseline != baseline) ||
328 (last_drawn_width!=insetWidth))) {
330 int h = insetAscent + insetDescent;
331 int ty = baseline - insetAscent;
337 if ((ty + h) > pain.paperHeight())
338 h = pain.paperHeight();
339 if ((top_x + drawTextXOffset + w) > pain.paperWidth())
340 w = pain.paperWidth();
341 pain.fillRectangle(top_x+drawTextXOffset, ty, w, h);
345 if (!cleared && (need_update == NONE))
348 if (top_x != int(x)) {
351 bv->text->status = LyXText::CHANGED_IN_DRAW;
354 if (cleared || (last_drawn_width != insetWidth)) {
356 last_drawn_width = insetWidth;
359 top_baseline = baseline;
360 top_y = baseline - ascent(bv, f);
361 last_width = width(bv, f);
362 last_height = ascent(bv, f) + descent(bv, f);
364 if (the_locking_inset && (cpar(bv) == inset_par) && (cpos(bv) == inset_pos)) {
365 inset_x = cx(bv) - top_x + drawTextXOffset;
366 inset_y = cy(bv) + drawTextYOffset;
368 if (!cleared && (need_update == CURSOR) && !TEXT(bv)->selection) {
373 x += TEXT_TO_INSET_OFFSET;
376 #warning Jürgen, why is this a block of its own? (Lgb)
377 #warning because you told me to define variables only in local context (Jug)!
378 #warning then make it a function/method of its own. (Lgb)
382 Row * row = TEXT(bv)->GetRowNearY(y);
383 int y_offset = baseline - row->ascent_of_text();
384 int ph = pain.paperHeight();
387 while ((row != 0) && ((y+row->height()) <= 0)) {
389 first += row->height();
394 TEXT(bv)->first = first;
395 if (cleared) { // (need_update&FULL) || (need_update&INIT)
398 while ((row != 0) && (yf < ph)) {
399 TEXT(bv)->GetVisibleRow(bv, y+y_offset, int(x), row,
405 } else if (!locked) {
406 if (need_update & CURSOR) {
407 bv->screen()->ToggleSelection(TEXT(bv), bv, true, y_offset,int(x));
408 TEXT(bv)->ClearSelection(bv);
409 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
411 bv->screen()->Update(TEXT(bv), bv, y_offset, int(x));
414 if (need_update & SELECTION)
415 bv->screen()->ToggleToggle(TEXT(bv), bv, y_offset, int(x));
416 else if (need_update & CURSOR) {
417 bv->screen()->ToggleSelection(TEXT(bv), bv, true, y_offset,int(x));
418 TEXT(bv)->ClearSelection(bv);
419 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
421 bv->screen()->Update(TEXT(bv), bv, y_offset, int(x));
425 TEXT(bv)->refresh_y = 0;
426 TEXT(bv)->status = LyXText::UNCHANGED;
427 if ((need_update != CURSOR_PAR) &&
428 ((drawFrame == ALWAYS) || ((drawFrame == LOCKED) && locked)))
430 pain.rectangle(top_x + 1, baseline - insetAscent + 1,
432 insetAscent + insetDescent - 1,
434 } else if (need_update & CLEAR_FRAME) {
435 pain.rectangle(top_x + 1, baseline - insetAscent + 1,
437 insetAscent + insetDescent - 1,
440 x += width(bv, f) - TEXT_TO_INSET_OFFSET;
441 if (bv->text->status==LyXText::CHANGED_IN_DRAW) {
443 } else if (need_update != INIT)
448 void InsetText::update(BufferView * bv, LyXFont const & font, bool reinit)
450 if (reinit) { // && (need_update != CURSOR)) {
454 owner()->update(bv, font, true);
457 if (the_locking_inset) {
458 inset_x = cx(bv) - top_x + drawTextXOffset;
459 inset_y = cy(bv) + drawTextYOffset;
460 the_locking_inset->update(bv, font, reinit);
462 if (need_update == INIT) {
466 int oldw = insetWidth;
468 insetWidth = TEXT(bv)->width + (2 * TEXT_TO_INSET_OFFSET);
469 // max(textWidth(bv->painter()),
470 // static_cast<int>(TEXT(bv)->width) + drawTextXOffset) +
471 // (2 * TEXT_TO_INSET_OFFSET);
473 insetWidth = textWidth(bv);
475 insetWidth = static_cast<int>(TEXT(bv)->width);
477 if (oldw != insetWidth) {
478 // printf("TW(%p): %d-%d-%d-%d\n",this,insetWidth, oldw,
479 // textWidth(bv->painter()),static_cast<int>(TEXT(bv)->width));
482 update(bv, font, reinit);
485 if ((need_update == CURSOR_PAR) && (TEXT(bv)->status == LyXText::UNCHANGED) &&
488 TEXT(bv)->UpdateInset(bv, the_locking_inset);
491 if (TEXT(bv)->status == LyXText::NEED_MORE_REFRESH)
495 Row * row = TEXT(bv)->GetRowNearY(y_temp);
496 insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
497 insetDescent = TEXT(bv)->height - row->ascent_of_text() +
498 TEXT_TO_INSET_OFFSET;
502 void InsetText::SetUpdateStatus(BufferView * bv, int what)
505 if (TEXT(bv)->status == LyXText::NEED_MORE_REFRESH)
507 else if (TEXT(bv)->status == LyXText::NEED_VERY_LITTLE_REFRESH)
508 need_update |= CURSOR_PAR;
510 // this to not draw a selection when we redraw all of it!
511 if ((need_update & (INIT|FULL)) && (need_update & CURSOR))
512 TEXT(bv)->ClearSelection(bv);
516 void InsetText::UpdateLocal(BufferView * bv, int what, bool mark_dirty)
518 TEXT(bv)->FullRebreak(bv);
519 SetUpdateStatus(bv, what);
520 if ((need_update != CURSOR) || (TEXT(bv)->status != LyXText::UNCHANGED) ||
522 bv->updateInset(this, mark_dirty);
523 bv->owner()->showState();
524 if (old_par != cpar(bv)) {
525 bv->owner()->setLayout(cpar(bv)->GetLayout());
531 string const InsetText::EditMessage() const
533 return _("Opened Text Inset");
537 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
539 // par->SetInsetOwner(this);
540 UpdatableInset::Edit(bv, x, y, button);
542 if (!bv->lockInset(this)) {
543 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
547 the_locking_inset = 0;
548 inset_pos = inset_x = inset_y = 0;
549 inset_boundary = false;
552 int tmp_y = (y < 0)?0:y;
553 if (!checkAndActivateInset(bv, x, tmp_y, button))
554 TEXT(bv)->SetCursorFromCoordinates(bv, x - drawTextXOffset,
556 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
557 bv->text->FinishUndo();
559 UpdateLocal(bv, FULL, false);
561 // If the inset is empty set the language of the current font to the
562 // language to the surronding text.
564 if (par->Last() == 0 && !par->next_)
566 if (par->size() == 0 && !par->next())
569 LyXFont font(LyXFont::ALL_IGNORE);
570 font.setLanguage(bv->getParentLanguage(this));
571 SetFont(bv, font, false);
576 void InsetText::InsetUnlock(BufferView * bv)
578 if (the_locking_inset) {
579 the_locking_inset->InsetUnlock(bv);
580 the_locking_inset = 0;
583 no_selection = false;
585 UpdateLocal(bv, CLEAR_FRAME|CURSOR, false);
587 bv->owner()->setLayout(owner()->getLyXText(bv)
588 ->cursor.par()->GetLayout());
590 bv->owner()->setLayout(bv->text->cursor.par()->GetLayout());
594 bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
596 lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset("
600 if (inset == cpar(bv)->GetInset(cpos(bv))) {
601 lyxerr[Debug::INSETS] << "OK" << endl;
602 the_locking_inset = inset;
603 inset_x = cx(bv) - top_x + drawTextXOffset;
604 inset_y = cy(bv) + drawTextYOffset;
605 inset_pos = cpos(bv);
606 inset_par = cpar(bv);
607 inset_boundary = cboundary(bv);
609 TEXT(bv)->ClearSelection(bv);
610 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
611 TEXT(bv)->UpdateInset(bv, the_locking_inset);
613 UpdateLocal(bv, CURSOR, false);
616 } else if (the_locking_inset && (the_locking_inset == inset)) {
617 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
618 lyxerr[Debug::INSETS] << "OK" << endl;
619 inset_x = cx(bv) - top_x + drawTextXOffset;
620 inset_y = cy(bv) + drawTextYOffset;
622 lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
624 } else if (the_locking_inset) {
625 lyxerr[Debug::INSETS] << "MAYBE" << endl;
626 return the_locking_inset->LockInsetInInset(bv, inset);
628 lyxerr[Debug::INSETS] << "NOT OK" << endl;
633 bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
636 if (!the_locking_inset)
638 if (the_locking_inset == inset) {
639 the_locking_inset->InsetUnlock(bv);
640 TEXT(bv)->UpdateInset(bv, inset);
641 the_locking_inset = 0;
643 moveRight(bv, false);
644 old_par = 0; // force layout setting
645 UpdateLocal(bv, CURSOR_PAR, false);
648 return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
652 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
654 if (!the_locking_inset)
656 if (the_locking_inset != inset) {
657 TEXT(bv)->UpdateInset(bv, the_locking_inset);
658 SetUpdateStatus(bv, CURSOR_PAR);
659 return the_locking_inset->UpdateInsetInInset(bv, inset);
661 // UpdateLocal(bv, FULL, false);
662 if (TEXT(bv)->UpdateInset(bv, inset))
663 UpdateLocal(bv, CURSOR_PAR, false);
664 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
665 inset_x = cx(bv) - top_x + drawTextXOffset;
666 inset_y = cy(bv) + drawTextYOffset;
672 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
676 int tmp_x = x - drawTextXOffset;
677 int tmp_y = y + insetAscent - TEXT(bv)->first;
678 Inset * inset = bv->checkInsetHit(TEXT(bv), tmp_x, tmp_y, button);
681 if (the_locking_inset) {
682 if (the_locking_inset == inset) {
683 the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
684 no_selection = false;
687 // otherwise unlock the_locking_inset and lock the new inset
688 the_locking_inset->InsetUnlock(bv);
689 inset_x = cx(bv) - top_x + drawTextXOffset;
690 inset_y = cy(bv) + drawTextYOffset;
691 the_locking_inset = static_cast<UpdatableInset*>(inset);
692 inset->InsetButtonPress(bv, x - inset_x, y - inset_y, button);
693 inset->Edit(bv, x - inset_x, y - inset_y, button);
694 if (the_locking_inset)
695 UpdateLocal(bv, CURSOR, false);
696 no_selection = false;
699 // otherwise only unlock the_locking_inset
700 the_locking_inset->InsetUnlock(bv);
701 the_locking_inset = 0;
703 if (bv->theLockingInset()) {
704 if (inset && inset->Editable() == Inset::HIGHLY_EDITABLE) {
705 UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
706 inset_x = cx(bv) - top_x + drawTextXOffset;
707 inset_y = cy(bv) + drawTextYOffset;
708 inset_pos = cpos(bv);
709 inset_par = cpar(bv);
710 inset_boundary = cboundary(bv);
711 the_locking_inset = uinset;
712 uinset->InsetButtonPress(bv, x - inset_x, y - inset_y,
714 uinset->Edit(bv, x - inset_x, y - inset_y, 0);
715 if (the_locking_inset)
716 UpdateLocal(bv, CURSOR, false);
717 no_selection = false;
721 if (!inset) { // && (button == 2)) {
722 bool paste_internally = false;
723 if ((button == 2) && TEXT(bv)->selection) {
724 LocalDispatch(bv, LFUN_COPY, "");
725 paste_internally = true;
727 TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset,
729 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
730 UpdateLocal(bv, CURSOR, false);
731 bv->owner()->setLayout(cpar(bv)->GetLayout());
733 // Insert primary selection with middle mouse
734 // if there is a local selection in the current buffer,
737 if (paste_internally)
738 LocalDispatch(bv, LFUN_PASTE, "");
740 LocalDispatch(bv, LFUN_PASTESELECTION,
745 no_selection = false;
749 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
751 UpdatableInset * inset = 0;
753 if (the_locking_inset) {
754 the_locking_inset->InsetButtonRelease(bv,
755 x - inset_x, y - inset_y,
758 if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
759 inset = static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
760 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
761 inset->InsetButtonRelease(bv,
763 y - inset_y, button);
765 inset_x = cx(bv) - top_x + drawTextXOffset;
766 inset_y = cy(bv) + drawTextYOffset;
767 inset->InsetButtonRelease(bv,
769 y - inset_y, button);
771 x - inset_x, y - inset_y, button);
773 UpdateLocal(bv, CURSOR_PAR, false);
776 no_selection = false;
780 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
784 if (the_locking_inset) {
785 the_locking_inset->InsetMotionNotify(bv, x - inset_x,
790 TEXT(bv)->SetCursorFromCoordinates(bv, x - drawTextXOffset,
792 TEXT(bv)->SetSelection(bv);
793 if (TEXT(bv)->toggle_cursor.par()!=TEXT(bv)->toggle_end_cursor.par() ||
794 TEXT(bv)->toggle_cursor.pos()!=TEXT(bv)->toggle_end_cursor.pos())
795 UpdateLocal(bv, SELECTION, false);
800 void InsetText::InsetKeyPress(XKeyEvent * xke)
802 if (the_locking_inset) {
803 the_locking_inset->InsetKeyPress(xke);
809 UpdatableInset::RESULT
810 InsetText::LocalDispatch(BufferView * bv,
811 kb_action action, string const & arg)
813 no_selection = false;
814 UpdatableInset::RESULT
815 result= UpdatableInset::LocalDispatch(bv, action, arg);
816 if (result != UNDISPATCHED) {
821 if ((action < 0) && arg.empty())
824 if (the_locking_inset) {
825 result = the_locking_inset->LocalDispatch(bv, action, arg);
826 if (result == DISPATCHED_NOUPDATE)
828 else if (result == DISPATCHED) {
829 UpdateLocal(bv, CURSOR_PAR, false);
831 } else if (result == FINISHED) {
832 bool dispatched = false;
834 case LFUN_UNKNOWN_ACTION:
835 case LFUN_BREAKPARAGRAPH:
837 moveRightIntern(bv, false, false);
840 if (!TEXT(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
841 moveRightIntern(bv, false, false);
845 if (TEXT(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
846 moveRightIntern(bv, false, false);
852 the_locking_inset = 0;
860 case LFUN_UNKNOWN_ACTION:
861 if (bv->buffer()->isReadonly()) {
862 // setErrorMessage(N_("Document is read only"));
866 /* Automatically delete the currently selected
867 * text and replace it with what is being
868 * typed in now. Depends on lyxrc settings
869 * "auto_region_delete", which defaults to
872 bv->text->SetUndo(bv->buffer(), Undo::INSERT,
874 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
875 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
877 bv->text->cursor.par()->previous(),
878 bv->text->cursor.par()->next()
882 if (lyxrc.auto_region_delete) {
883 if (TEXT(bv)->selection){
884 TEXT(bv)->CutSelection(bv, false);
887 TEXT(bv)->ClearSelection(bv);
888 for (string::size_type i = 0; i < arg.length(); ++i) {
890 if (!math_insert_greek(bv, arg[i])) {
891 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], TEXT(bv));
892 } else if (!the_locking_inset) {
893 (void)moveRight(bv, false);
896 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], TEXT(bv));
900 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
901 UpdateLocal(bv, CURSOR_PAR, true);
902 result=DISPATCHED_NOUPDATE;
904 // --- Cursor Movements -----------------------------------
906 bv->text->FinishUndo();
907 moveRight(bv, false, true);
908 TEXT(bv)->SetSelection(bv);
909 UpdateLocal(bv, SELECTION, false);
912 result = moveRight(bv);
913 bv->text->FinishUndo();
914 UpdateLocal(bv, CURSOR, false);
917 bv->text->FinishUndo();
918 moveLeft(bv, false, true);
919 TEXT(bv)->SetSelection(bv);
920 UpdateLocal(bv, SELECTION, false);
923 bv->text->FinishUndo();
924 result = moveLeft(bv);
925 UpdateLocal(bv, CURSOR, false);
928 bv->text->FinishUndo();
930 TEXT(bv)->SetSelection(bv);
931 UpdateLocal(bv, SELECTION, false);
934 bv->text->FinishUndo();
935 result = moveDown(bv);
936 UpdateLocal(bv, CURSOR, false);
939 bv->text->FinishUndo();
941 TEXT(bv)->SetSelection(bv);
942 UpdateLocal(bv, SELECTION, false);
945 bv->text->FinishUndo();
947 UpdateLocal(bv, CURSOR, false);
950 bv->text->FinishUndo();
951 TEXT(bv)->CursorHome(bv);
952 UpdateLocal(bv, CURSOR, false);
955 TEXT(bv)->CursorEnd(bv);
956 UpdateLocal(bv, CURSOR, false);
959 bv->text->SetUndo(bv->buffer(), Undo::DELETE,
961 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
962 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
964 bv->text->cursor.par()->previous(),
965 bv->text->cursor.par()->next()
968 if (TEXT(bv)->selection)
969 TEXT(bv)->CutSelection(bv);
971 TEXT(bv)->Backspace(bv);
972 UpdateLocal(bv, CURSOR_PAR, true);
975 bv->text->SetUndo(bv->buffer(), Undo::DELETE,
977 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
978 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
980 bv->text->cursor.par()->previous(),
981 bv->text->cursor.par()->next()
984 if (TEXT(bv)->selection)
985 TEXT(bv)->CutSelection(bv);
987 TEXT(bv)->Delete(bv);
988 UpdateLocal(bv, CURSOR_PAR, true);
991 bv->text->SetUndo(bv->buffer(), Undo::DELETE,
993 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
994 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
996 bv->text->cursor.par()->previous(),
997 bv->text->cursor.par()->next()
1000 TEXT(bv)->CutSelection(bv);
1001 UpdateLocal(bv, CURSOR_PAR, true);
1004 bv->text->FinishUndo();
1005 TEXT(bv)->CopySelection(bv);
1006 UpdateLocal(bv, CURSOR_PAR, false);
1008 case LFUN_PASTESELECTION:
1010 string clip(bv->workarea()->getClipboard());
1014 if (arg == "paragraph") {
1015 TEXT(bv)->InsertStringB(bv, clip);
1017 TEXT(bv)->InsertStringA(bv, clip);
1019 UpdateLocal(bv, CURSOR_PAR, true);
1023 if (!autoBreakRows) {
1026 if (cap.nrOfParagraphs() > 1) {
1027 WriteAlert(_("Impossible operation"),
1028 _("Cannot include more than one paragraph!"),
1033 bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1035 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1036 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1038 bv->text->cursor.par()->previous(),
1039 bv->text->cursor.par()->next()
1042 TEXT(bv)->PasteSelection(bv);
1043 UpdateLocal(bv, CURSOR_PAR, true);
1045 case LFUN_BREAKPARAGRAPH:
1048 TEXT(bv)->BreakParagraph(bv, 0);
1049 UpdateLocal(bv, FULL, true);
1051 case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
1054 TEXT(bv)->BreakParagraph(bv, 1);
1055 UpdateLocal(bv, FULL, true);
1057 case LFUN_BREAKLINE:
1060 bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1062 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1063 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1065 bv->text->cursor.par()->previous(),
1066 bv->text->cursor.par()->next()
1069 TEXT(bv)->InsertChar(bv, LyXParagraph::META_NEWLINE);
1070 UpdateLocal(bv, CURSOR_PAR, true);
1073 // do not set layouts on non breakable textinsets
1074 if (autoBreakRows) {
1075 LyXTextClass::size_type cur_layout = cpar(bv)->layout;
1077 // Derive layout number from given argument (string)
1078 // and current buffer's textclass (number). */
1079 LyXTextClassList::ClassList::size_type tclass =
1080 bv->buffer()->params.textclass;
1081 std::pair<bool, LyXTextClass::size_type> layout =
1082 textclasslist.NumberOfLayout(tclass, arg);
1084 // If the entry is obsolete, use the new one instead.
1086 string obs = textclasslist.Style(tclass,layout.second).
1089 layout = textclasslist.NumberOfLayout(tclass, obs);
1092 // see if we found the layout number:
1093 if (!layout.first) {
1094 string const msg = string(N_("Layout ")) + arg + N_(" not known");
1095 bv->owner()->message(msg);
1099 if (cur_layout != layout.second) {
1100 cur_layout = layout.second;
1101 TEXT(bv)->SetLayout(bv, layout.second);
1102 bv->owner()->setLayout(cpar(bv)->GetLayout());
1103 UpdateLocal(bv, CURSOR_PAR, true);
1106 // reset the layout box
1107 bv->owner()->setLayout(cpar(bv)->GetLayout());
1110 case LFUN_PARAGRAPH_SPACING:
1111 // This one is absolutely not working. When fiddling with this
1112 // it also seems to me that the paragraphs inside the insettext
1113 // inherit bufferparams/paragraphparams in a strange way. (Lgb)
1115 LyXParagraph * par = TEXT(bv)->cursor.par();
1116 Spacing::Space cur_spacing = par->params.spacing().getSpace();
1117 float cur_value = 1.0;
1118 if (cur_spacing == Spacing::Other) {
1119 cur_value = par->params.spacing().getValue();
1122 std::istringstream istr(arg.c_str());
1125 Spacing::Space new_spacing = cur_spacing;
1126 float new_value = cur_value;
1128 lyxerr << "Missing argument to `paragraph-spacing'"
1130 } else if (tmp == "single") {
1131 new_spacing = Spacing::Single;
1132 } else if (tmp == "onehalf") {
1133 new_spacing = Spacing::Onehalf;
1134 } else if (tmp == "double") {
1135 new_spacing = Spacing::Double;
1136 } else if (tmp == "other") {
1137 new_spacing = Spacing::Other;
1140 lyxerr << "new_value = " << tmpval << endl;
1143 } else if (tmp == "default") {
1144 new_spacing = Spacing::Default;
1146 lyxerr << _("Unknown spacing argument: ")
1149 if (cur_spacing != new_spacing || cur_value != new_value) {
1150 par->params.spacing(Spacing(new_spacing, new_value));
1151 //TEXT(bv)->RedoParagraph(owner->view());
1152 UpdateLocal(bv, CURSOR_PAR, true);
1153 //bv->update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1159 if (!bv->Dispatch(action, arg))
1160 result = UNDISPATCHED;
1164 /// If the action has deleted all text in the inset, we need to change the
1165 // language to the language to the surronding text.
1167 if (par->Last() == 0 && !par->next_)
1169 if (par->size() == 0 && !par->next())
1172 LyXFont font(LyXFont::ALL_IGNORE);
1173 font.setLanguage(bv->getParentLanguage(this));
1174 SetFont(bv, font, false);
1177 if (result != FINISHED) {
1178 ShowInsetCursor(bv);
1180 bv->unlockInset(this);
1185 int InsetText::Latex(Buffer const * buf, ostream & os, bool, bool) const
1188 buf->latexParagraphs(os, par, 0, texrow);
1189 return texrow.rows();
1193 int InsetText::Ascii(Buffer const * buf, ostream & os, int linelen) const
1195 LyXParagraph * p = par;
1196 unsigned int lines = 0;
1200 tmp = buf->asciiParagraph(p, linelen);
1201 lines += countChar(tmp, '\n');
1213 int InsetText::DocBook(Buffer const * buf, ostream & os) const
1215 LyXParagraph * p = par;
1216 unsigned int lines = 0;
1221 buf->SimpleDocBookOnePar(os,tmp,p,desc,0);
1233 void InsetText::Validate(LaTeXFeatures & features) const
1235 LyXParagraph * p = par;
1237 p->validate(features);
1247 int InsetText::BeginningOfMainBody(Buffer const * buf, LyXParagraph * p) const
1249 if (textclasslist.Style(buf->params.textclass,
1250 p->GetLayout()).labeltype != LABEL_MANUAL)
1253 return p->BeginningOfMainBody();
1257 void InsetText::GetCursorPos(BufferView * bv,
1258 int & x, int & y) const
1265 unsigned int InsetText::InsetInInsetY()
1267 if (!the_locking_inset)
1270 return (inset_y + the_locking_inset->InsetInInsetY());
1274 void InsetText::ToggleInsetCursor(BufferView * bv)
1276 if (the_locking_inset) {
1277 the_locking_inset->ToggleInsetCursor(bv);
1281 LyXFont const font(TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv)));
1283 int const asc = lyxfont::maxAscent(font);
1284 int const desc = lyxfont::maxDescent(font);
1286 if (isCursorVisible())
1287 bv->hideLockedInsetCursor();
1289 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1290 toggleCursorVisible();
1294 void InsetText::ShowInsetCursor(BufferView * bv, bool show)
1296 if (the_locking_inset) {
1297 the_locking_inset->ShowInsetCursor(bv);
1300 if (!isCursorVisible()) {
1301 LyXFont const font =
1302 TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1304 int const asc = lyxfont::maxAscent(font);
1305 int const desc = lyxfont::maxDescent(font);
1307 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1309 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1310 setCursorVisible(true);
1315 void InsetText::HideInsetCursor(BufferView * bv)
1317 if (isCursorVisible()) {
1318 bv->hideLockedInsetCursor();
1319 setCursorVisible(false);
1321 if (the_locking_inset)
1322 the_locking_inset->HideInsetCursor(bv);
1326 UpdatableInset::RESULT
1327 InsetText::moveRight(BufferView * bv, bool activate_inset, bool selecting)
1329 if (TEXT(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1330 return moveLeftIntern(bv, false, activate_inset, selecting);
1332 return moveRightIntern(bv, false, activate_inset, selecting);
1335 UpdatableInset::RESULT
1336 InsetText::moveLeft(BufferView * bv, bool activate_inset, bool selecting)
1338 if (TEXT(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1339 return moveRightIntern(bv, true, activate_inset, selecting);
1341 return moveLeftIntern(bv, true, activate_inset, selecting);
1345 UpdatableInset::RESULT
1346 InsetText::moveRightIntern(BufferView * bv, bool behind,
1347 bool activate_inset, bool selecting)
1350 if (!cpar(bv)->next_ && (cpos(bv) >= cpar(bv)->Last()))
1352 if (!cpar(bv)->next() && (cpos(bv) >= cpar(bv)->size()))
1355 if (activate_inset && checkAndActivateInset(bv, behind))
1357 TEXT(bv)->CursorRight(bv);
1359 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1360 return DISPATCHED_NOUPDATE;
1364 UpdatableInset::RESULT
1365 InsetText::moveLeftIntern(BufferView * bv, bool behind,
1366 bool activate_inset, bool selecting)
1369 if (!cpar(bv)->previous_ && (cpos(bv) <= 0))
1371 if (!cpar(bv)->previous() && (cpos(bv) <= 0))
1374 TEXT(bv)->CursorLeft(bv);
1376 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1377 if (activate_inset && checkAndActivateInset(bv, behind))
1379 return DISPATCHED_NOUPDATE;
1383 UpdatableInset::RESULT
1384 InsetText::moveUp(BufferView * bv)
1386 if (!crow(bv)->previous())
1388 TEXT(bv)->CursorUp(bv);
1389 return DISPATCHED_NOUPDATE;
1393 UpdatableInset::RESULT
1394 InsetText::moveDown(BufferView * bv)
1396 if (!crow(bv)->next())
1398 TEXT(bv)->CursorDown(bv);
1399 return DISPATCHED_NOUPDATE;
1403 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1405 if (the_locking_inset) {
1406 if (the_locking_inset->InsertInsetAllowed(inset))
1407 return the_locking_inset->InsertInset(bv, inset);
1410 bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1412 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1413 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1415 bv->text->cursor.par()->previous(),
1416 bv->text->cursor.par()->next()
1419 inset->setOwner(this);
1420 HideInsetCursor(bv);
1421 TEXT(bv)->InsertInset(bv, inset);
1423 if ((cpar(bv)->GetChar(cpos(bv)) != LyXParagraph::META_INSET) ||
1424 (cpar(bv)->GetInset(cpos(bv)) != inset))
1425 TEXT(bv)->CursorLeft(bv);
1427 bv->fitCursor(TEXT(bv));
1428 UpdateLocal(bv, CURSOR_PAR|CURSOR, true);
1429 ShowInsetCursor(bv);
1434 UpdatableInset * InsetText::GetLockingInset()
1436 return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1440 UpdatableInset * InsetText::GetFirstLockingInsetOfType(Inset::Code c)
1444 if (the_locking_inset)
1445 return the_locking_inset->GetFirstLockingInsetOfType(c);
1450 bool InsetText::ShowInsetDialog(BufferView * bv) const
1452 if (the_locking_inset)
1453 return the_locking_inset->ShowInsetDialog(bv);
1458 std::vector<string> const InsetText::getLabelList() const
1460 std::vector<string> label_list;
1462 LyXParagraph * tpar = par;
1464 LyXParagraph::inset_iterator beg = tpar->inset_iterator_begin();
1465 LyXParagraph::inset_iterator end = tpar->inset_iterator_end();
1466 for (; beg != end; ++beg) {
1467 std::vector<string> const l = (*beg)->getLabelList();
1468 label_list.insert(label_list.end(), l.begin(), l.end());
1470 tpar = tpar->next();
1476 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1478 if (TEXT(bv)->selection) {
1479 bv->text->SetUndo(bv->buffer(), Undo::EDIT,
1481 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1482 bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1484 bv->text->cursor.par()->previous(),
1485 bv->text->cursor.par()->next()
1489 TEXT(bv)->SetFont(bv, font, toggleall);
1490 bv->fitCursor(TEXT(bv));
1491 UpdateLocal(bv, CURSOR_PAR, true);
1495 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1497 if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
1501 static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
1502 if (!inset || inset->Editable() != Inset::HIGHLY_EDITABLE)
1504 LyXFont const font =
1505 TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1507 x = inset->width(bv, font);
1508 y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1511 y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1513 //inset_x = cx(bv) - top_x + drawTextXOffset;
1514 //inset_y = cy(bv) + drawTextYOffset;
1515 inset->Edit(bv, x, y, 0);
1516 if (!the_locking_inset)
1518 UpdateLocal(bv, CURSOR_PAR, false);
1525 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1528 int dummyx = x = x - drawTextXOffset;
1529 int dummyy = y + insetAscent;
1530 Inset * inset = bv->checkInsetHit(TEXT(bv), dummyx, dummyy, button);
1537 inset_x = cx(bv) - top_x + drawTextXOffset;
1538 inset_y = cy(bv) + drawTextYOffset;
1539 inset->Edit(bv, x - inset_x, y - inset_y, button);
1540 if (!the_locking_inset)
1542 UpdateLocal(bv, CURSOR_PAR, false);
1549 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1551 int w = UpdatableInset::getMaxWidth(bv, inset);
1556 w = w - top_x + owner()->x();
1559 w -= (2 * TEXT_TO_INSET_OFFSET);
1561 // return w - (2*TEXT_TO_INSET_OFFSET);
1565 void InsetText::SetParagraphData(LyXParagraph * p)
1567 // delete all instances of LyXText before deleting the paragraps used
1569 for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit){
1570 delete (*cit).second;
1586 par->SetInsetOwner(this);
1590 np->next(p->Clone());
1591 np->next_->previous(np);
1593 np->SetInsetOwner(this);
1597 LyXParagraph * tmp = par->next();
1603 par->SetInsetOwner(this);
1604 LyXParagraph * np = par;
1607 np->next(p->Clone());
1608 np->next()->previous(np);
1610 np->SetInsetOwner(this);
1617 void InsetText::SetText(string const & data)
1620 LyXFont font(LyXFont::ALL_SANE);
1621 for (unsigned int i=0; i < data.length(); ++i)
1622 par->InsertChar(i, data[i], font);
1626 void InsetText::SetAutoBreakRows(bool flag)
1628 if (flag != autoBreakRows) {
1629 autoBreakRows = flag;
1637 void InsetText::SetDrawFrame(BufferView * bv, DrawFrame how)
1639 if (how != drawFrame) {
1642 UpdateLocal(bv, DRAW_FRAME, false);
1647 void InsetText::SetFrameColor(BufferView * bv, LColor::color col)
1649 if (frame_color != col) {
1652 UpdateLocal(bv, DRAW_FRAME, false);
1657 int InsetText::cx(BufferView * bv) const
1659 LyXText * text = TEXT(bv);
1660 int x = text->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
1661 if (the_locking_inset) {
1662 LyXFont font = text->GetFont(bv->buffer(),
1664 text->cursor.pos());
1665 if (font.isVisibleRightToLeft())
1666 x -= the_locking_inset->width(bv, font);
1672 int InsetText::cy(BufferView * bv) const
1675 return TEXT(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
1679 LyXParagraph::size_type InsetText::cpos(BufferView * bv) const
1681 return TEXT(bv)->cursor.pos();
1685 LyXParagraph * InsetText::cpar(BufferView * bv) const
1687 return TEXT(bv)->cursor.par();
1690 bool InsetText::cboundary(BufferView * bv) const
1692 return TEXT(bv)->cursor.boundary();
1696 Row * InsetText::crow(BufferView * bv) const
1698 return TEXT(bv)->cursor.row();
1702 LyXText * InsetText::getLyXText(BufferView const * lbv,
1703 bool const recursive) const
1705 // Super UGLY! (Lgb)
1706 BufferView * bv = const_cast<BufferView *>(lbv);
1708 if ((cache.find(bv) != cache.end()) && cache[bv]) {
1709 if (recursive && the_locking_inset)
1710 return the_locking_inset->getLyXText(bv);
1713 LyXText * lt = new LyXText(const_cast<InsetText *>(this));
1716 if (the_locking_inset) {
1717 lt->SetCursor(bv, inset_par, inset_pos, true, inset_boundary);
1719 return the_locking_inset->getLyXText(bv);
1725 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
1727 if ((cache.find(bv) == cache.end()) || !cache[bv])
1732 /// then remove all LyXText in text-insets
1733 LyXParagraph * p = par;
1735 for (; p; p = p->next_) {
1736 p->deleteInsetsLyXText(bv);
1739 for (; p; p = p->next()) {
1740 p->deleteInsetsLyXText(bv);
1747 void InsetText::resizeLyXText(BufferView * bv) const
1750 if (!par->next_ && !par->size()) // resize not neccessary!
1752 if (!par->next() && !par->size()) // resize not neccessary!
1755 if ((cache.find(bv) == cache.end()) || !cache[bv])
1758 LyXParagraph * lpar = 0;
1759 LyXParagraph * selstartpar = 0;
1760 LyXParagraph * selendpar = 0;
1761 LyXParagraph::size_type pos = 0;
1762 LyXParagraph::size_type selstartpos = 0;
1763 LyXParagraph::size_type selendpos = 0;
1764 bool boundary = false;
1765 bool selstartboundary = false;
1766 bool selendboundary = false;
1770 // ProhibitInput(bv);
1773 lpar = TEXT(bv)->cursor.par();
1774 pos = TEXT(bv)->cursor.pos();
1775 boundary = TEXT(bv)->cursor.boundary();
1776 selstartpar = TEXT(bv)->sel_start_cursor.par();
1777 selstartpos = TEXT(bv)->sel_start_cursor.pos();
1778 selstartboundary = TEXT(bv)->sel_start_cursor.boundary();
1779 selendpar = TEXT(bv)->sel_end_cursor.par();
1780 selendpos = TEXT(bv)->sel_end_cursor.pos();
1781 selendboundary = TEXT(bv)->sel_end_cursor.boundary();
1782 selection = TEXT(bv)->selection;
1783 mark_set = TEXT(bv)->mark_set;
1785 deleteLyXText(bv, (the_locking_inset == 0));
1788 TEXT(bv)->selection = true;
1789 /* at this point just to avoid the Delete-Empty-Paragraph
1790 * Mechanism when setting the cursor */
1791 TEXT(bv)->mark_set = mark_set;
1793 TEXT(bv)->SetCursor(bv, selstartpar, selstartpos,
1794 true, selstartboundary);
1795 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1796 TEXT(bv)->SetCursor(bv, selendpar, selendpos,
1797 true, selendboundary);
1798 TEXT(bv)->SetSelection(bv);
1799 TEXT(bv)->SetCursor(bv, lpar, pos);
1801 TEXT(bv)->SetCursor(bv, lpar, pos, true, boundary);
1802 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1803 TEXT(bv)->selection = false;
1807 TEXT(bv)->first = bv->screen()->TopCursorVisible(TEXT(bv));
1808 // this will scroll the screen such that the cursor becomes visible
1809 bv->updateScrollbar();
1811 if (the_locking_inset) {
1812 /// then resize all LyXText in text-insets
1813 inset_x = cx(bv) - top_x + drawTextXOffset;
1814 inset_y = cy(bv) + drawTextYOffset;
1816 for (LyXParagraph * p = par; p; p = p->next_) {
1817 p->resizeInsetsLyXText(bv);
1820 for (LyXParagraph * p = par; p; p = p->next()) {
1821 p->resizeInsetsLyXText(bv);
1829 void InsetText::removeNewlines()
1832 for (LyXParagraph * p = par; p; p = p->next_) {
1833 for (int i = 0; i < p->Last(); ++i) {
1835 for (LyXParagraph * p = par; p; p = p->next()) {
1836 for (int i = 0; i < p->size(); ++i) {
1838 if (p->GetChar(i) == LyXParagraph::META_NEWLINE)