1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1998-2001 The LyX Team.
8 * ======================================================
19 #pragma implementation
22 #include "insettext.h"
23 #include "paragraph.h"
27 #include "commandtags.h"
30 #include "BufferView.h"
32 #include "LaTeXFeatures.h"
34 #include "lyx_gui_misc.h"
36 #include "lyxcursor.h"
37 #include "CutAndPaste.h"
40 #include "support/textutils.h"
41 #include "support/LAssert.h"
45 #include "trans_mgr.h"
46 #include "lyxscreen.h"
50 #include "ParagraphParameters.h"
59 extern unsigned char getCurrentTextClass(Buffer *);
60 extern bool math_insert_greek(BufferView *, char);
61 extern int greek_kb_flag;
63 InsetText::InsetText()
70 InsetText::InsetText(InsetText const & ins)
75 autoBreakRows = ins.autoBreakRows;
79 InsetText & InsetText::operator=(InsetText const & it)
82 autoBreakRows = it.autoBreakRows;
87 void InsetText::init(InsetText const * ins)
95 the_locking_inset = 0;
101 autoBreakRows = false;
105 setParagraphData(ins->par);
106 autoBreakRows = ins->autoBreakRows;
107 drawFrame_ = ins->drawFrame_;
109 par->setInsetOwner(this);
110 frame_color = LColor::insetframe;
113 last_drawn_width = -1;
114 frame_is_visible = false;
119 InsetText::~InsetText()
126 Paragraph * tmp = par->next();
133 void InsetText::clear()
137 // now also delete all caches this should be safe, hopefully
141 Paragraph * tmp = par->next();
149 Inset * InsetText::clone(Buffer const &) const
151 InsetText * t = new InsetText(*this);
156 void InsetText::write(Buffer const * buf, ostream & os) const
159 writeParagraphData(buf, os);
163 void InsetText::writeParagraphData(Buffer const * buf, ostream & os) const
165 par->writeFile(buf, os, buf->params, 0);
169 void InsetText::read(Buffer const * buf, LyXLex & lex)
173 Paragraph * return_par = 0;
174 Paragraph::depth_type depth = 0;
175 LyXFont font(LyXFont::ALL_INHERIT);
181 token = lex.GetString();
184 if (token == "\\end_inset")
186 if (const_cast<Buffer*>(buf)->
187 parseSingleLyXformat2Token(lex, par, return_par,
188 token, pos, depth, font)) {
189 // the_end read this should NEVER happen
190 lex.printError("\\the_end read in inset! Error in document!");
198 return_par->setInsetOwner(this);
199 return_par = return_par->next();
202 if (token != "\\end_inset") {
203 lex.printError("Missing \\end_inset at this point. "
210 int InsetText::ascent(BufferView * bv, LyXFont const &) const
213 Row * row = getLyXText(bv)->getRowNearY(y_temp);
214 insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
219 int InsetText::descent(BufferView * bv, LyXFont const &) const
221 LyXText * t = getLyXText(bv);
223 Row * row = t->getRowNearY(y_temp);
224 insetDescent = t->height - row->ascent_of_text() +
225 TEXT_TO_INSET_OFFSET;
230 int InsetText::width(BufferView * bv, LyXFont const &) const
232 insetWidth = max(textWidth(bv),
233 (int)getLyXText(bv)->width + (2 * TEXT_TO_INSET_OFFSET));
238 int InsetText::textWidth(BufferView * bv) const
240 int const w = getMaxWidth(bv, this);
245 void InsetText::draw(BufferView * bv, LyXFont const & f,
246 int baseline, float & x, bool cleared) const
251 Painter & pain = bv->painter();
253 // no draw is necessary !!!
254 if ((drawFrame_ == LOCKED) && !locked && !par->size()) {
256 top_baseline = baseline;
258 if (!cleared && (need_update & CLEAR_FRAME))
259 clearFrame(pain, cleared);
261 frame_is_visible = false;
268 UpdatableInset::draw(bv, f, baseline, x, cleared);
271 x += static_cast<float>(scroll());
274 // update insetWidth and insetHeight with dummy calls
276 (void)descent(bv, f);
280 // if top_x differs we have a rule down and we don't have to clear anything
281 if (!cleared && (top_x == int(x)) &&
282 ((need_update&(INIT|FULL)) || (top_baseline!=baseline) ||
283 (last_drawn_width!=insetWidth))) {
284 clearInset(pain, baseline, cleared);
287 frame_is_visible = false;
289 if (!cleared && (need_update == NONE))
292 if (top_x != int(x)) {
293 if ((getMaxWidth(bv, this) > 0) &&
294 (getLyXText(bv)->width != old_max_width)) {
297 old_max_width = getLyXText(bv)->width;
298 bv->text->status = LyXText::CHANGED_IN_DRAW;
302 clearInset(pain, baseline, cleared);
308 // lyxerr << "InsetText::draw[" << this << "](" << need_update << ":" << int(x) << ":" << top_x << ")\n";
310 if (cleared || (last_drawn_width != insetWidth)) {
312 last_drawn_width = insetWidth;
315 top_baseline = baseline;
316 top_y = baseline - ascent(bv, f);
317 last_width = width(bv, f);
318 last_height = ascent(bv, f) + descent(bv, f);
320 if (the_locking_inset && (cpar(bv) == inset_par)
321 && (cpos(bv) == inset_pos)) {
322 inset_x = cx(bv) - top_x + drawTextXOffset;
323 inset_y = cy(bv) + drawTextYOffset;
325 if (!cleared && (need_update == CURSOR)
326 && !getLyXText(bv)->selection.set()) {
327 drawFrame(pain, cleared);
328 x += last_width; // was width(bv, f);
332 x += TEXT_TO_INSET_OFFSET;
335 Row * row = getLyXText(bv)->getRowNearY(y);
336 int y_offset = baseline - row->ascent_of_text();
337 int ph = pain.paperHeight();
340 while ((row != 0) && ((y+row->height()) <= 0)) {
342 first += row->height();
347 getLyXText(bv)->first = first;
351 while ((row != 0) && (yf < ph)) {
352 getLyXText(bv)->getVisibleRow(bv, y+y_offset, int(x), row,
358 } else if (!locked) {
359 if (need_update & CURSOR) {
360 bv->screen()->toggleSelection(getLyXText(bv), bv, true, y_offset,int(x));
361 getLyXText(bv)->clearSelection(bv);
362 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
364 bv->screen()->update(getLyXText(bv), bv, y_offset, int(x));
367 if (need_update & SELECTION)
368 bv->screen()->toggleToggle(getLyXText(bv), bv, y_offset, int(x));
369 else if (need_update & CURSOR) {
370 bv->screen()->toggleSelection(getLyXText(bv), bv, true, y_offset,int(x));
371 getLyXText(bv)->clearSelection(bv);
372 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
374 bv->screen()->update(getLyXText(bv), bv, y_offset, int(x));
378 getLyXText(bv)->refresh_y = 0;
379 getLyXText(bv)->status = LyXText::UNCHANGED;
380 if ((need_update != CURSOR_PAR) &&
381 ((drawFrame_ == ALWAYS) || ((drawFrame_ == LOCKED) && locked)))
382 drawFrame(pain, cleared);
383 else if (need_update & CLEAR_FRAME)
384 clearFrame(pain, cleared);
385 x += last_width /* was width(bv, f) */ - TEXT_TO_INSET_OFFSET;
386 if (bv->text->status==LyXText::CHANGED_IN_DRAW) {
388 } else if (need_update != INIT)
393 void InsetText::drawFrame(Painter & pain, bool cleared) const
395 if (!frame_is_visible || cleared) {
396 pain.rectangle(top_x + 1, top_baseline - insetAscent + 1,
397 insetWidth - 1, insetAscent + insetDescent - 1,
399 frame_is_visible = true;
404 void InsetText::clearFrame(Painter & pain, bool cleared) const
406 if (frame_is_visible) {
408 pain.rectangle(top_x + 1, top_baseline - insetAscent + 1,
409 insetWidth - 1, insetAscent + insetDescent - 1,
412 frame_is_visible = false;
417 void InsetText::update(BufferView * bv, LyXFont const & font, bool reinit)
419 LyXText * t = getLyXText(bv);
423 t->BreakParagraph(bv);
431 owner()->update(bv, font, true);
434 if (the_locking_inset) {
435 inset_x = cx(bv) - top_x + drawTextXOffset;
436 inset_y = cy(bv) + drawTextYOffset;
437 the_locking_inset->update(bv, font, reinit);
440 if (need_update == INIT) {
445 int oldw = insetWidth;
446 insetWidth = t->width + (2 * TEXT_TO_INSET_OFFSET);
447 if (oldw != insetWidth) {
450 // update(bv, font, reinit);
453 if ((need_update & CURSOR_PAR) && t->status == LyXText::UNCHANGED &&
455 t->updateInset(bv, the_locking_inset);
458 if (t->status == LyXText::NEED_MORE_REFRESH)
462 Row * row = t->GetRowNearY(y_temp);
463 insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
464 insetDescent = t->height - row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
469 void InsetText::setUpdateStatus(BufferView * bv, int what) const
471 LyXText * t = getLyXText(bv);
473 if (t->status == LyXText::NEED_MORE_REFRESH)
475 else if (t->status == LyXText::NEED_VERY_LITTLE_REFRESH)
476 need_update |= CURSOR_PAR;
478 // this to not draw a selection when we redraw all of it!
479 if ((need_update & (INIT|FULL)) && (need_update & CURSOR))
480 t->clearSelection(bv);
484 void InsetText::updateLocal(BufferView * bv, int what, bool mark_dirty)
486 LyXText * t = getLyXText(bv);
488 setUpdateStatus(bv, what);
489 if (need_update != CURSOR || t->status != LyXText::UNCHANGED ||
491 bv->updateInset(this, mark_dirty);
492 bv->owner()->showState();
493 if (old_par != cpar(bv)) {
494 bv->owner()->setLayout(cpar(bv)->getLayout());
500 string const InsetText::editMessage() const
502 return _("Opened Text Inset");
506 void InsetText::edit(BufferView * bv, int x, int y, unsigned int button)
508 // par->SetInsetOwner(this);
509 UpdatableInset::edit(bv, x, y, button);
511 if (!bv->lockInset(this)) {
512 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
516 the_locking_inset = 0;
517 inset_pos = inset_x = inset_y = 0;
518 inset_boundary = false;
521 int tmp_y = (y < 0) ? 0 : y;
522 LyXText * t = getLyXText(bv);
524 if (!checkAndActivateInset(bv, x, tmp_y, button)) {
525 t->setCursorFromCoordinates(bv, x - drawTextXOffset,
529 t->selection.cursor = t->cursor;
530 bv->text->finishUndo();
532 updateLocal(bv, CURSOR, false);
534 // If the inset is empty set the language of the current font to the
535 // language to the surronding text (if different).
536 if (par->size() == 0 && !par->next() &&
537 bv->getParentLanguage(this) != t->current_font.language()) {
538 LyXFont font(LyXFont::ALL_IGNORE);
539 font.setLanguage(bv->getParentLanguage(this));
540 setFont(bv, font, false);
545 void InsetText::insetUnlock(BufferView * bv)
547 if (the_locking_inset) {
548 the_locking_inset->insetUnlock(bv);
549 the_locking_inset = 0;
552 no_selection = false;
554 int code = CURSOR|CLEAR_FRAME;
555 LyXText * t = getLyXText(bv);
556 if (t->selection.set()) {
557 t->clearSelection(bv);
559 } else if (owner()) {
560 bv->owner()->setLayout(owner()->getLyXText(bv)
561 ->cursor.par()->getLayout());
563 bv->owner()->setLayout(bv->text->cursor.par()->getLayout());
564 updateLocal(bv, code, false);
568 bool InsetText::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
570 lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset("
574 if (inset == cpar(bv)->getInset(cpos(bv))) {
575 lyxerr[Debug::INSETS] << "OK" << endl;
576 the_locking_inset = inset;
577 inset_x = cx(bv) - top_x + drawTextXOffset;
578 inset_y = cy(bv) + drawTextYOffset;
579 inset_pos = cpos(bv);
580 inset_par = cpar(bv);
581 inset_boundary = cboundary(bv);
583 getLyXText(bv)->clearSelection(bv);
584 getLyXText(bv)->sel_cursor = getLyXText(bv)->cursor;
585 getLyXText(bv)->UpdateInset(bv, the_locking_inset);
587 updateLocal(bv, CURSOR, false);
590 } else if (the_locking_inset && (the_locking_inset == inset)) {
591 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
592 lyxerr[Debug::INSETS] << "OK" << endl;
593 inset_x = cx(bv) - top_x + drawTextXOffset;
594 inset_y = cy(bv) + drawTextYOffset;
596 lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
598 } else if (the_locking_inset) {
599 lyxerr[Debug::INSETS] << "MAYBE" << endl;
600 return the_locking_inset->lockInsetInInset(bv, inset);
602 lyxerr[Debug::INSETS] << "NOT OK" << endl;
607 bool InsetText::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
610 if (!the_locking_inset)
612 if (the_locking_inset == inset) {
613 the_locking_inset->insetUnlock(bv);
614 getLyXText(bv)->updateInset(bv, inset);
615 the_locking_inset = 0;
617 moveRight(bv, false);
618 old_par = 0; // force layout setting
622 updateLocal(bv, CURSOR, false);
625 return the_locking_inset->unlockInsetInInset(bv, inset, lr);
629 bool InsetText::updateInsetInInset(BufferView * bv, Inset * inset)
631 if (!the_locking_inset)
633 if (the_locking_inset != inset) {
634 getLyXText(bv)->updateInset(bv, the_locking_inset);
635 setUpdateStatus(bv, CURSOR_PAR);
636 return the_locking_inset->updateInsetInInset(bv, inset);
638 // updateLocal(bv, FULL, false);
639 if (getLyXText(bv)->updateInset(bv, inset))
640 updateLocal(bv, CURSOR_PAR, false);
641 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
642 inset_x = cx(bv) - top_x + drawTextXOffset;
643 inset_y = cy(bv) + drawTextYOffset;
649 void InsetText::insetButtonPress(BufferView * bv, int x, int y, int button)
653 int tmp_x = x - drawTextXOffset;
654 int tmp_y = y + insetAscent - getLyXText(bv)->first;
655 Inset * inset = bv->checkInsetHit(getLyXText(bv), tmp_x, tmp_y, button);
658 if (the_locking_inset) {
659 if (the_locking_inset == inset) {
660 the_locking_inset->insetButtonPress(bv,x-inset_x,y-inset_y,button);
661 no_selection = false;
664 // otherwise unlock the_locking_inset and lock the new inset
665 the_locking_inset->insetUnlock(bv);
666 inset_x = cx(bv) - top_x + drawTextXOffset;
667 inset_y = cy(bv) + drawTextYOffset;
668 the_locking_inset = static_cast<UpdatableInset*>(inset);
669 inset->insetButtonPress(bv, x - inset_x, y - inset_y, button);
670 inset->edit(bv, x - inset_x, y - inset_y, button);
671 if (the_locking_inset)
672 updateLocal(bv, CURSOR, false);
673 no_selection = false;
676 // otherwise only unlock the_locking_inset
677 the_locking_inset->insetUnlock(bv);
678 the_locking_inset = 0;
680 if (bv->theLockingInset()) {
681 if (inset && inset->editable() == Inset::HIGHLY_EDITABLE) {
682 UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
683 inset_x = cx(bv) - top_x + drawTextXOffset;
684 inset_y = cy(bv) + drawTextYOffset;
685 inset_pos = cpos(bv);
686 inset_par = cpar(bv);
687 inset_boundary = cboundary(bv);
688 the_locking_inset = uinset;
689 uinset->insetButtonPress(bv, x - inset_x, y - inset_y,
691 uinset->edit(bv, x - inset_x, y - inset_y, 0);
692 if (the_locking_inset)
693 updateLocal(bv, CURSOR, false);
694 no_selection = false;
698 if (!inset) { // && (button == 2)) {
699 bool paste_internally = false;
700 if ((button == 2) && getLyXText(bv)->selection.set()) {
701 localDispatch(bv, LFUN_COPY, "");
702 paste_internally = true;
704 getLyXText(bv)->setCursorFromCoordinates(bv, x-drawTextXOffset,
706 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
707 updateLocal(bv, CURSOR, false);
708 bv->owner()->setLayout(cpar(bv)->getLayout());
710 // Insert primary selection with middle mouse
711 // if there is a local selection in the current buffer,
714 if (paste_internally)
715 localDispatch(bv, LFUN_PASTE, "");
717 localDispatch(bv, LFUN_PASTESELECTION,
722 no_selection = false;
726 void InsetText::insetButtonRelease(BufferView * bv, int x, int y, int button)
728 UpdatableInset * inset = 0;
730 if (the_locking_inset) {
731 the_locking_inset->insetButtonRelease(bv,
732 x - inset_x, y - inset_y,
735 if (cpar(bv)->getChar(cpos(bv)) == Paragraph::META_INSET) {
736 inset = static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
737 if (inset->editable() == Inset::HIGHLY_EDITABLE) {
738 inset->insetButtonRelease(bv,
740 y - inset_y, button);
742 inset_x = cx(bv) - top_x + drawTextXOffset;
743 inset_y = cy(bv) + drawTextYOffset;
744 inset->insetButtonRelease(bv,
746 y - inset_y, button);
748 x - inset_x, y - inset_y, button);
750 updateLocal(bv, CURSOR_PAR, false);
753 no_selection = false;
757 void InsetText::insetMotionNotify(BufferView * bv, int x, int y, int state)
761 if (the_locking_inset) {
762 the_locking_inset->insetMotionNotify(bv, x - inset_x,
766 LyXText * t = getLyXText(bv);
768 t->setCursorFromCoordinates(bv, x - drawTextXOffset, y + insetAscent);
770 if (t->toggle_cursor.par() != t->toggle_end_cursor.par() ||
771 t->toggle_cursor.pos() != t->toggle_end_cursor.pos())
772 updateLocal(bv, SELECTION, false);
777 void InsetText::insetKeyPress(XKeyEvent * xke)
779 if (the_locking_inset) {
780 the_locking_inset->insetKeyPress(xke);
786 UpdatableInset::RESULT
787 InsetText::localDispatch(BufferView * bv,
788 kb_action action, string const & arg)
790 no_selection = false;
791 UpdatableInset::RESULT
792 result= UpdatableInset::localDispatch(bv, action, arg);
793 if (result != UNDISPATCHED) {
798 if ((action < 0) && arg.empty())
801 if (the_locking_inset) {
802 result = the_locking_inset->localDispatch(bv, action, arg);
803 if (result == DISPATCHED_NOUPDATE)
805 else if (result == DISPATCHED) {
806 updateLocal(bv, CURSOR_PAR, false);
808 } else if (result == FINISHED) {
809 bool dispatched = false;
811 case LFUN_UNKNOWN_ACTION:
812 case LFUN_BREAKPARAGRAPH:
814 moveRightIntern(bv, false, false);
817 if (!getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
818 moveRightIntern(bv, false, false);
822 if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
823 moveRightIntern(bv, false, false);
829 the_locking_inset = 0;
837 case LFUN_SELFINSERT:
838 if (bv->buffer()->isReadonly()) {
839 // setErrorMessage(N_("Document is read only"));
843 /* Automatically delete the currently selected
844 * text and replace it with what is being
845 * typed in now. Depends on lyxrc settings
846 * "auto_region_delete", which defaults to
849 bv->text->setUndo(bv->buffer(), Undo::INSERT,
850 bv->text->cursor.par()->previous(),
851 bv->text->cursor.par()->next());
853 if (lyxrc.auto_region_delete) {
854 if (getLyXText(bv)->selection.set()) {
855 getLyXText(bv)->cutSelection(bv, false);
858 getLyXText(bv)->clearSelection(bv);
859 for (string::size_type i = 0; i < arg.length(); ++i) {
861 if (!math_insert_greek(bv, arg[i])) {
862 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], getLyXText(bv));
863 } else if (!the_locking_inset) {
864 (void)moveRight(bv, false);
867 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], getLyXText(bv));
871 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
872 updateLocal(bv, CURSOR_PAR, true);
873 result = DISPATCHED_NOUPDATE;
875 // --- Cursor Movements -----------------------------------
877 bv->text->finishUndo();
878 moveRight(bv, false, true);
879 getLyXText(bv)->setSelection(bv);
880 updateLocal(bv, SELECTION, false);
883 result = moveRight(bv);
884 bv->text->finishUndo();
885 updateLocal(bv, CURSOR, false);
888 bv->text->finishUndo();
889 moveLeft(bv, false, true);
890 getLyXText(bv)->setSelection(bv);
891 updateLocal(bv, SELECTION, false);
894 bv->text->finishUndo();
895 result = moveLeft(bv);
896 updateLocal(bv, CURSOR, false);
899 bv->text->finishUndo();
901 getLyXText(bv)->setSelection(bv);
902 updateLocal(bv, SELECTION, false);
905 bv->text->finishUndo();
906 result = moveDown(bv);
907 updateLocal(bv, CURSOR, false);
910 bv->text->finishUndo();
912 getLyXText(bv)->setSelection(bv);
913 updateLocal(bv, SELECTION, false);
916 bv->text->finishUndo();
918 updateLocal(bv, CURSOR, false);
921 bv->text->finishUndo();
922 getLyXText(bv)->cursorHome(bv);
923 updateLocal(bv, CURSOR, false);
926 getLyXText(bv)->cursorEnd(bv);
927 updateLocal(bv, CURSOR, false);
929 case LFUN_BACKSPACE: {
930 bv->text->setUndo(bv->buffer(), Undo::DELETE,
931 bv->text->cursor.par()->previous(),
932 bv->text->cursor.par()->next());
933 LyXText * t = getLyXText(bv);
935 if (t->selection.set()) {
941 updateLocal(bv, CURSOR_PAR, true);
947 bv->text->setUndo(bv->buffer(), Undo::DELETE,
948 bv->text->cursor.par()->previous(),
949 bv->text->cursor.par()->next());
950 LyXText * t = getLyXText(bv);
952 if (t->selection.set()) {
957 updateLocal(bv, CURSOR_PAR, true);
962 bv->text->setUndo(bv->buffer(), Undo::DELETE,
963 bv->text->cursor.par()->previous(),
964 bv->text->cursor.par()->next());
965 getLyXText(bv)->cutSelection(bv);
966 updateLocal(bv, CURSOR_PAR, true);
969 bv->text->finishUndo();
970 getLyXText(bv)->copySelection(bv);
971 updateLocal(bv, CURSOR_PAR, false);
973 case LFUN_PASTESELECTION:
975 string const clip(bv->getClipboard());
979 if (arg == "paragraph") {
980 getLyXText(bv)->insertStringAsParagraphs(bv, clip);
982 getLyXText(bv)->insertStringAsLines(bv, clip);
984 updateLocal(bv, CURSOR_PAR, true);
988 if (!autoBreakRows) {
990 if (CutAndPaste::nrOfParagraphs() > 1) {
991 WriteAlert(_("Impossible operation"),
992 _("Cannot include more than one paragraph!"),
997 bv->text->setUndo(bv->buffer(), Undo::INSERT,
998 bv->text->cursor.par()->previous(),
999 bv->text->cursor.par()->next());
1000 getLyXText(bv)->pasteSelection(bv);
1001 updateLocal(bv, CURSOR_PAR, true);
1003 case LFUN_BREAKPARAGRAPH:
1006 getLyXText(bv)->breakParagraph(bv, 0);
1007 updateLocal(bv, FULL, true);
1009 case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
1012 getLyXText(bv)->breakParagraph(bv, 1);
1013 updateLocal(bv, FULL, true);
1015 case LFUN_BREAKLINE:
1018 bv->text->setUndo(bv->buffer(), Undo::INSERT,
1019 bv->text->cursor.par()->previous(),
1020 bv->text->cursor.par()->next());
1021 getLyXText(bv)->insertChar(bv, Paragraph::META_NEWLINE);
1022 updateLocal(bv, CURSOR_PAR, true);
1025 // do not set layouts on non breakable textinsets
1026 if (autoBreakRows) {
1027 LyXTextClass::size_type cur_layout = cpar(bv)->layout;
1029 // Derive layout number from given argument (string)
1030 // and current buffer's textclass (number). */
1031 LyXTextClassList::ClassList::size_type tclass =
1032 bv->buffer()->params.textclass;
1033 std::pair <bool, LyXTextClass::size_type> layout =
1034 textclasslist.NumberOfLayout(tclass, arg);
1036 // If the entry is obsolete, use the new one instead.
1038 string obs = textclasslist.Style(tclass,layout.second).
1041 layout = textclasslist.NumberOfLayout(tclass, obs);
1044 // see if we found the layout number:
1045 if (!layout.first) {
1046 string const msg = string(N_("Layout ")) + arg + N_(" not known");
1047 bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, msg);
1051 if (cur_layout != layout.second) {
1052 cur_layout = layout.second;
1053 getLyXText(bv)->setLayout(bv, layout.second);
1054 bv->owner()->setLayout(cpar(bv)->getLayout());
1055 updateLocal(bv, CURSOR_PAR, true);
1058 // reset the layout box
1059 bv->owner()->setLayout(cpar(bv)->getLayout());
1062 case LFUN_PARAGRAPH_SPACING:
1063 // This one is absolutely not working. When fiddling with this
1064 // it also seems to me that the paragraphs inside the insettext
1065 // inherit bufferparams/paragraphparams in a strange way. (Lgb)
1067 Paragraph * par = getLyXText(bv)->cursor.par();
1068 Spacing::Space cur_spacing = par->params().spacing().getSpace();
1069 float cur_value = 1.0;
1070 if (cur_spacing == Spacing::Other) {
1071 cur_value = par->params().spacing().getValue();
1074 std::istringstream istr(arg.c_str());
1077 Spacing::Space new_spacing = cur_spacing;
1078 float new_value = cur_value;
1080 lyxerr << "Missing argument to `paragraph-spacing'"
1082 } else if (tmp == "single") {
1083 new_spacing = Spacing::Single;
1084 } else if (tmp == "onehalf") {
1085 new_spacing = Spacing::Onehalf;
1086 } else if (tmp == "double") {
1087 new_spacing = Spacing::Double;
1088 } else if (tmp == "other") {
1089 new_spacing = Spacing::Other;
1092 lyxerr << "new_value = " << tmpval << endl;
1095 } else if (tmp == "default") {
1096 new_spacing = Spacing::Default;
1098 lyxerr << _("Unknown spacing argument: ")
1101 if (cur_spacing != new_spacing || cur_value != new_value) {
1102 par->params().spacing(Spacing(new_spacing, new_value));
1103 //getLyXText(bv)->RedoParagraph(owner->view());
1104 updateLocal(bv, CURSOR_PAR, true);
1105 //bv->update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1111 if (!bv->Dispatch(action, arg))
1112 result = UNDISPATCHED;
1116 /// If the action has deleted all text in the inset, we need to change the
1117 // language to the language to the surronding text.
1118 if (par->size() == 0 && !par->next()) {
1119 LyXFont font(LyXFont::ALL_IGNORE);
1120 font.setLanguage(bv->getParentLanguage(this));
1121 setFont(bv, font, false);
1124 if (result != FINISHED) {
1125 showInsetCursor(bv);
1127 bv->unlockInset(this);
1132 int InsetText::latex(Buffer const * buf, ostream & os, bool, bool) const
1135 buf->latexParagraphs(os, par, 0, texrow);
1136 return texrow.rows();
1140 int InsetText::ascii(Buffer const * buf, ostream & os, int linelen) const
1142 Paragraph * p = par;
1143 unsigned int lines = 0;
1146 string const tmp = buf->asciiParagraph(p, linelen);
1147 lines += countChar(tmp, '\n');
1155 int InsetText::docBook(Buffer const * buf, ostream & os) const
1157 Paragraph * p = par;
1158 unsigned int lines = 0;
1163 buf->simpleDocBookOnePar(os, tmp, p, desc, 0);
1171 void InsetText::validate(LaTeXFeatures & features) const
1173 Paragraph * p = par;
1175 p->validate(features);
1181 int InsetText::beginningOfMainBody(Buffer const * buf, Paragraph * p) const
1183 if (textclasslist.Style(buf->params.textclass,
1184 p->getLayout()).labeltype != LABEL_MANUAL)
1187 return p->beginningOfMainBody();
1191 void InsetText::getCursorPos(BufferView * bv,
1192 int & x, int & y) const
1199 unsigned int InsetText::insetInInsetY()
1201 if (!the_locking_inset)
1204 return (inset_y + the_locking_inset->insetInInsetY());
1208 void InsetText::toggleInsetCursor(BufferView * bv)
1210 if (the_locking_inset) {
1211 the_locking_inset->toggleInsetCursor(bv);
1215 LyXFont const font(getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv)));
1217 int const asc = lyxfont::maxAscent(font);
1218 int const desc = lyxfont::maxDescent(font);
1220 if (isCursorVisible())
1221 bv->hideLockedInsetCursor();
1223 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1224 toggleCursorVisible();
1228 void InsetText::showInsetCursor(BufferView * bv, bool show)
1230 if (the_locking_inset) {
1231 the_locking_inset->showInsetCursor(bv);
1234 if (!isCursorVisible()) {
1235 LyXFont const font =
1236 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1238 int const asc = lyxfont::maxAscent(font);
1239 int const desc = lyxfont::maxDescent(font);
1241 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1243 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1244 setCursorVisible(true);
1249 void InsetText::hideInsetCursor(BufferView * bv)
1251 if (isCursorVisible()) {
1252 bv->hideLockedInsetCursor();
1253 setCursorVisible(false);
1255 if (the_locking_inset)
1256 the_locking_inset->hideInsetCursor(bv);
1260 UpdatableInset::RESULT
1261 InsetText::moveRight(BufferView * bv, bool activate_inset, bool selecting)
1263 if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1264 return moveLeftIntern(bv, false, activate_inset, selecting);
1266 return moveRightIntern(bv, false, activate_inset, selecting);
1270 UpdatableInset::RESULT
1271 InsetText::moveLeft(BufferView * bv, bool activate_inset, bool selecting)
1273 if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1274 return moveRightIntern(bv, true, activate_inset, selecting);
1276 return moveLeftIntern(bv, true, activate_inset, selecting);
1280 UpdatableInset::RESULT
1281 InsetText::moveRightIntern(BufferView * bv, bool behind,
1282 bool activate_inset, bool selecting)
1284 if (!cpar(bv)->next() && (cpos(bv) >= cpar(bv)->size()))
1286 if (activate_inset && checkAndActivateInset(bv, behind))
1288 getLyXText(bv)->cursorRight(bv);
1290 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1291 return DISPATCHED_NOUPDATE;
1295 UpdatableInset::RESULT
1296 InsetText::moveLeftIntern(BufferView * bv, bool behind,
1297 bool activate_inset, bool selecting)
1299 if (!cpar(bv)->previous() && (cpos(bv) <= 0))
1301 getLyXText(bv)->cursorLeft(bv);
1303 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1304 if (activate_inset && checkAndActivateInset(bv, behind))
1306 return DISPATCHED_NOUPDATE;
1310 UpdatableInset::RESULT
1311 InsetText::moveUp(BufferView * bv)
1313 if (!crow(bv)->previous())
1315 getLyXText(bv)->cursorUp(bv);
1316 return DISPATCHED_NOUPDATE;
1320 UpdatableInset::RESULT
1321 InsetText::moveDown(BufferView * bv)
1323 if (!crow(bv)->next())
1325 getLyXText(bv)->cursorDown(bv);
1326 return DISPATCHED_NOUPDATE;
1330 bool InsetText::insertInset(BufferView * bv, Inset * inset)
1332 if (the_locking_inset) {
1333 if (the_locking_inset->insertInsetAllowed(inset))
1334 return the_locking_inset->insertInset(bv, inset);
1337 bv->text->setUndo(bv->buffer(), Undo::INSERT,
1338 bv->text->cursor.par()->previous(),
1339 bv->text->cursor.par()->next());
1340 inset->setOwner(this);
1341 hideInsetCursor(bv);
1342 getLyXText(bv)->insertInset(bv, inset);
1344 if ((cpar(bv)->GetChar(cpos(bv)) != Paragraph::META_INSET) ||
1345 (cpar(bv)->GetInset(cpos(bv)) != inset))
1346 getLyXText(bv)->CursorLeft(bv);
1348 bv->fitCursor(getLyXText(bv));
1349 updateLocal(bv, CURSOR_PAR|CURSOR, true);
1350 showInsetCursor(bv);
1355 UpdatableInset * InsetText::getLockingInset()
1357 return the_locking_inset ? the_locking_inset->getLockingInset() : this;
1361 UpdatableInset * InsetText::getFirstLockingInsetOfType(Inset::Code c)
1365 if (the_locking_inset)
1366 return the_locking_inset->getFirstLockingInsetOfType(c);
1371 bool InsetText::showInsetDialog(BufferView * bv) const
1373 if (the_locking_inset)
1374 return the_locking_inset->showInsetDialog(bv);
1379 std::vector<string> const InsetText::getLabelList() const
1381 std::vector<string> label_list;
1383 Paragraph * tpar = par;
1385 Paragraph::inset_iterator beg = tpar->inset_iterator_begin();
1386 Paragraph::inset_iterator end = tpar->inset_iterator_end();
1387 for (; beg != end; ++beg) {
1388 std::vector<string> const l = (*beg)->getLabelList();
1389 label_list.insert(label_list.end(), l.begin(), l.end());
1391 tpar = tpar->next();
1397 void InsetText::setFont(BufferView * bv, LyXFont const & font, bool toggleall,
1400 if (the_locking_inset) {
1401 the_locking_inset->setFont(bv, font, toggleall, selectall);
1404 if (getLyXText(bv)->selection.set()) {
1405 bv->text->setUndo(bv->buffer(), Undo::EDIT,
1406 bv->text->cursor.par()->previous(),
1407 bv->text->cursor.par()->next());
1411 getLyXText(bv)->setFont(bv, font, toggleall);
1413 getLyXText(bv)->clearSelection(bv);
1414 bv->fitCursor(getLyXText(bv));
1415 if (selectall || getLyXText(bv)->selection.set())
1416 updateLocal(bv, FULL, true);
1418 updateLocal(bv, CURSOR_PAR, true);
1422 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1424 if (cpar(bv)->getChar(cpos(bv)) == Paragraph::META_INSET) {
1428 static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
1429 if (!inset || inset->editable() != Inset::HIGHLY_EDITABLE)
1431 LyXFont const font =
1432 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1434 x = inset->width(bv, font);
1435 y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1438 y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1440 //inset_x = cx(bv) - top_x + drawTextXOffset;
1441 //inset_y = cy(bv) + drawTextYOffset;
1442 inset->edit(bv, x, y, 0);
1443 if (!the_locking_inset)
1445 updateLocal(bv, CURSOR, false);
1452 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1455 x -= drawTextXOffset;
1457 int dummyy = y + insetAscent;
1458 Inset * inset = bv->checkInsetHit(getLyXText(bv), dummyx, dummyy, button);
1465 inset_x = cx(bv) - top_x + drawTextXOffset;
1466 inset_y = cy(bv) + drawTextYOffset;
1467 inset->edit(bv, x - inset_x, y - inset_y, button);
1468 if (!the_locking_inset)
1470 updateLocal(bv, CURSOR, false);
1477 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1479 int w = UpdatableInset::getMaxWidth(bv, inset);
1484 w = w - top_x + owner()->x();
1487 w -= (2 * TEXT_TO_INSET_OFFSET);
1489 // return w - (2*TEXT_TO_INSET_OFFSET);
1493 void InsetText::setParagraphData(Paragraph * p)
1497 // now also delete all caches this should be safe, hopefully
1501 Paragraph * tmp = par->next();
1506 par = new Paragraph(*p);
1507 par->setInsetOwner(this);
1508 Paragraph * np = par;
1511 np->next(new Paragraph(*p));
1512 np->next()->previous(np);
1514 np->setInsetOwner(this);
1521 void InsetText::setText(string const & data)
1524 LyXFont font(LyXFont::ALL_SANE);
1525 for (unsigned int i=0; i < data.length(); ++i)
1526 par->insertChar(i, data[i], font);
1530 void InsetText::setAutoBreakRows(bool flag)
1532 if (flag != autoBreakRows) {
1533 autoBreakRows = flag;
1541 void InsetText::setDrawFrame(BufferView * bv, DrawFrame how)
1543 if (how != drawFrame_) {
1546 updateLocal(bv, DRAW_FRAME, false);
1551 void InsetText::setFrameColor(BufferView * bv, LColor::color col)
1553 if (frame_color != col) {
1556 updateLocal(bv, DRAW_FRAME, false);
1561 int InsetText::cx(BufferView * bv) const
1563 LyXText * text = getLyXText(bv);
1564 int x = text->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
1565 if (the_locking_inset) {
1566 LyXFont font = text->getFont(bv->buffer(),
1568 text->cursor.pos());
1569 if (font.isVisibleRightToLeft())
1570 x -= the_locking_inset->width(bv, font);
1576 int InsetText::cy(BufferView * bv) const
1579 return getLyXText(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
1583 Paragraph::size_type InsetText::cpos(BufferView * bv) const
1585 return getLyXText(bv)->cursor.pos();
1589 Paragraph * InsetText::cpar(BufferView * bv) const
1591 return getLyXText(bv)->cursor.par();
1595 bool InsetText::cboundary(BufferView * bv) const
1597 return getLyXText(bv)->cursor.boundary();
1601 Row * InsetText::crow(BufferView * bv) const
1603 return getLyXText(bv)->cursor.row();
1607 LyXText * InsetText::getLyXText(BufferView const * lbv,
1608 bool const recursive) const
1610 if (!recursive && (cached_bview == lbv))
1611 return cached_text.get();
1613 // Super UGLY! (Lgb)
1614 BufferView * bv = const_cast<BufferView *>(lbv);
1617 Cache::iterator it = cache.find(bv);
1619 if (it != cache.end()) {
1620 lyx::Assert(it->second.get());
1622 cached_text = it->second;
1623 if (recursive && the_locking_inset) {
1624 return the_locking_inset->getLyXText(bv);
1626 return cached_text.get();
1628 cached_text.reset(new LyXText(const_cast<InsetText *>(this)));
1629 cached_text->init(bv);
1631 cache.insert(make_pair(bv, cached_text));
1633 if (the_locking_inset) {
1634 cached_text->setCursor(bv, inset_par, inset_pos,
1635 true, inset_boundary);
1637 return the_locking_inset->getLyXText(bv);
1640 return cached_text.get();
1644 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
1648 Cache::iterator it = cache.find(bv);
1650 if (it == cache.end()) {
1654 lyx::Assert(it->second.get());
1658 /// then remove all LyXText in text-insets
1659 Paragraph * p = par;
1660 for (; p; p = p->next()) {
1661 p->deleteInsetsLyXText(bv);
1667 void InsetText::resizeLyXText(BufferView * bv, bool force) const
1669 if (!par->next() && !par->size()) // no data, resize not neccessary!
1671 // one endless line, resize normally not necessary
1672 if (!force && getMaxWidth(bv, this) < 0)
1675 Cache::iterator it = cache.find(bv);
1676 if (it == cache.end()) {
1679 lyx::Assert(it->second.get());
1681 Paragraph * lpar = 0;
1682 Paragraph * selstartpar = 0;
1683 Paragraph * selendpar = 0;
1684 Paragraph::size_type pos = 0;
1685 Paragraph::size_type selstartpos = 0;
1686 Paragraph::size_type selendpos = 0;
1687 bool boundary = false;
1688 bool selstartboundary = false;
1689 bool selendboundary = false;
1690 bool selection = false;
1691 bool mark_set = false;
1693 // bv->owner()->prohibitInput();
1696 LyXText * t = getLyXText(bv);
1697 lpar = t->cursor.par();
1698 pos = t->cursor.pos();
1699 boundary = t->cursor.boundary();
1700 selstartpar = t->selection.start.par();
1701 selstartpos = t->selection.start.pos();
1702 selstartboundary = t->selection.start.boundary();
1703 selendpar = t->selection.end.par();
1704 selendpos = t->selection.end.pos();
1705 selendboundary = t->selection.end.boundary();
1706 selection = t->selection.set();
1707 mark_set = t->selection.mark();
1709 deleteLyXText(bv, (the_locking_inset == 0) || force);
1712 LyXText * t = getLyXText(bv);
1714 t->selection.set(true);
1715 /* at this point just to avoid the Delete-Empty-Paragraph
1716 * Mechanism when setting the cursor */
1717 t->selection.mark(mark_set);
1719 t->setCursor(bv, selstartpar, selstartpos, true, selstartboundary);
1720 t->selection.cursor = t->cursor;
1721 t->setCursor(bv, selendpar, selendpos, true, selendboundary);
1722 t->setSelection(bv);
1723 t->setCursor(bv, lpar, pos);
1725 t->setCursor(bv, lpar, pos, true, boundary);
1726 t->selection.cursor = t->cursor;
1727 t->selection.set(false);
1731 LyXText * t = getLyXText(bv);
1732 t->first = bv->screen()->topCursorVisible(t);
1735 // this will scroll the screen such that the cursor becomes visible
1736 bv->updateScrollbar();
1737 // bv->owner()->allowInput();
1738 if (the_locking_inset) {
1739 /// then resize all LyXText in text-insets
1740 inset_x = cx(bv) - top_x + drawTextXOffset;
1741 inset_y = cy(bv) + drawTextYOffset;
1742 for (Paragraph * p = par; p; p = p->next()) {
1743 p->resizeInsetsLyXText(bv);
1750 void InsetText::removeNewlines()
1752 for (Paragraph * p = par; p; p = p->next()) {
1753 for (int i = 0; i < p->size(); ++i) {
1754 if (p->getChar(i) == Paragraph::META_NEWLINE)
1761 bool InsetText::nodraw() const
1763 if (the_locking_inset)
1764 return the_locking_inset->nodraw();
1765 return UpdatableInset::nodraw();
1769 int InsetText::scroll(bool recursive) const
1771 int sx = UpdatableInset::scroll(false);
1773 if (recursive && the_locking_inset)
1774 sx += the_locking_inset->scroll(recursive);
1780 bool InsetText::doClearArea() const
1782 return !locked || (need_update & (FULL|INIT));
1786 void InsetText::selectAll(BufferView * bv)
1788 getLyXText(bv)->cursorTop(bv);
1789 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1790 getLyXText(bv)->cursorBottom(bv);
1791 getLyXText(bv)->setSelection(bv);
1795 void InsetText::clearSelection(BufferView * bv)
1797 getLyXText(bv)->clearSelection(bv);
1801 void InsetText::clearInset(Painter & pain, int baseline, bool & cleared) const
1804 int h = insetAscent + insetDescent;
1805 int ty = baseline - insetAscent;
1811 if ((ty + h) > pain.paperHeight())
1812 h = pain.paperHeight();
1813 if ((top_x + drawTextXOffset + w) > pain.paperWidth())
1814 w = pain.paperWidth();
1815 pain.fillRectangle(top_x+drawTextXOffset, ty, w, h);