2 /* This file is part of
3 * ======================================================
5 * LyX, The Document Processor
7 * Copyright 1995 Matthias Ettrich
8 * Copyright 1995-2001 The LyX Team.
10 * ====================================================== */
17 #include "BufferView.h"
19 #include "lyxcursor.h"
21 #include "insets/inseterror.h"
22 #include "insets/insetinfo.h"
24 #include "bufferlist.h"
25 #include "support/FileInfo.h"
26 #include "lyxscreen.h"
27 #include "support/filetools.h"
28 #include "lyx_gui_misc.h"
30 #include "BufferView_pimpl.h"
31 #include "insets/insetcommand.h" //ChangeRefs
32 #include "support/lyxfunctional.h" //equal_1st_in_pair
36 extern BufferList bufferlist;
47 // Inserts a file into current document
48 bool BufferView::insertLyXFile(string const & filen)
50 // Copyright CHT Software Service GmbH
53 // Insert a Lyxformat - file into current buffer
55 // Moved from lyx_cb.C (Lgb)
57 if (filen.empty()) return false;
59 string const fname = MakeAbsPath(filen);
61 // check if file exist
62 FileInfo const fi(fname);
65 WriteAlert(_("Error!"),
66 _("Specified file is unreadable: "),
67 MakeDisplayPath(fname, 50));
73 ifstream ifs(fname.c_str());
75 WriteAlert(_("Error!"),
76 _("Cannot open specified file: "),
77 MakeDisplayPath(fname, 50));
81 char const c = ifs.peek();
89 lyxerr.debug() << "Will insert file with header" << endl;
90 res = buffer()->readFile(lex, text->cursor.par());
92 lyxerr.debug() << "Will insert file without header" << endl;
93 res = buffer()->readLyXformat2(lex, text->cursor.par());
101 bool BufferView::removeAutoInsets()
103 LyXParagraph * par = buffer()->paragraph;
105 LyXCursor tmpcursor = text->cursor;
111 // this has to be done before the delete
112 text->SetCursor(this, cursor, par, 0);
113 if (par->AutoDeleteInsets()){
115 text->RedoParagraphs(this, cursor,
116 cursor.par()->next());
117 text->FullRebreak(this);
122 // avoid forbidden cursor positions caused by error removing
123 if (tmpcursor.pos() > tmpcursor.par()->size())
124 tmpcursor.pos(tmpcursor.par()->size());
126 text->SetCursorIntern(this, tmpcursor.par(), tmpcursor.pos());
132 void BufferView::insertErrors(TeXErrors & terr)
134 // Save the cursor position
135 LyXCursor cursor = text->cursor;
137 for (TeXErrors::Errors::const_iterator cit = terr.begin();
140 string const desctext((*cit).error_desc);
141 string const errortext((*cit).error_text);
142 string const msgtxt = desctext + '\n' + errortext;
143 int const errorrow = (*cit).error_in_line;
145 // Insert error string for row number
149 if (buffer()->texrow.getIdFromRow(errorrow, tmpid, tmppos)) {
150 buffer()->texrow.increasePos(tmpid, tmppos);
153 LyXParagraph * texrowpar = 0;
156 texrowpar = text->FirstParagraph();
159 texrowpar = text->GetParFromID(tmpid);
165 InsetError * new_inset = new InsetError(msgtxt);
166 text->SetCursorIntern(this, texrowpar, tmppos);
167 text->InsertInset(this, new_inset);
168 text->FullRebreak(this);
170 // Restore the cursor position
171 text->SetCursorIntern(this, cursor.par(), cursor.pos());
175 void BufferView::setCursorFromRow(int row)
180 buffer()->texrow.getIdFromRow(row, tmpid, tmppos);
182 LyXParagraph * texrowpar;
185 texrowpar = text->FirstParagraph();
188 texrowpar = text->GetParFromID(tmpid);
190 text->SetCursor(this, texrowpar, tmppos);
194 bool BufferView::insertInset(Inset * inset, string const & lout,
197 // if we are in a locking inset we should try to insert the
198 // inset there otherwise this is a illegal function now
199 if (theLockingInset()) {
200 if (theLockingInset()->InsertInsetAllowed(inset))
201 return theLockingInset()->InsertInset(this, inset);
205 // not quite sure if we want this...
206 text->SetCursorParUndo(buffer());
211 update(text, BufferView::SELECT|BufferView::FITCUR);
212 text->BreakParagraph(this);
213 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
215 if (text->cursor.par()->size()) {
216 text->CursorLeft(this);
218 text->BreakParagraph(this);
219 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
222 pair<bool, LyXTextClass::size_type> lres =
223 textclasslist.NumberOfLayout(buffer()->params
225 LyXTextClass::size_type lay;
226 if (lres.first != false) {
230 // layout not fount using default "Standard" (0)
234 text->SetLayout(this, lay);
236 text->SetParagraph(this, 0, 0,
238 VSpace(VSpace::NONE), VSpace(VSpace::NONE),
242 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
244 text->current_font.setLatex(LyXFont::OFF);
247 text->InsertInset(this, inset);
248 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
250 text->UnFreezeUndo();
255 /* This is also a buffer property (ale) */
256 // Not so sure about that. a goto Label function can not be buffer local, just
257 // think how this will work in a multiwindo/buffer environment, all the
258 // cursors in all the views showing this buffer will move. (Lgb)
259 // OK, then no cursor action should be allowed in buffer. (ale)
260 bool BufferView::gotoLabel(string const & label)
263 for (Buffer::inset_iterator it = buffer()->inset_iterator_begin();
264 it != buffer()->inset_iterator_end(); ++it) {
265 vector<string> labels = (*it)->getLabelList();
266 if (find(labels.begin(),labels.end(),label)
269 text->SetCursor(this, it.getPar(), it.getPos());
270 text->selection.cursor = text->cursor;
271 update(text, BufferView::SELECT|BufferView::FITCUR);
279 void BufferView::menuUndo()
282 owner()->message(_("Undo"));
285 update(text, BufferView::SELECT|BufferView::FITCUR);
286 if (!text->TextUndo(this))
287 owner()->message(_("No forther undo information"));
289 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
295 void BufferView::menuRedo()
297 if (theLockingInset()) {
298 owner()->message(_("Redo not yet supported in math mode"));
303 owner()->message(_("Redo"));
306 update(text, BufferView::SELECT|BufferView::FITCUR);
307 if (!text->TextRedo(this))
308 owner()->message(_("No further redo information"));
310 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
316 void BufferView::copyEnvironment()
319 text->copyEnvironmentType();
320 // clear the selection, even if mark_set
322 text->ClearSelection(this);
323 update(text, BufferView::SELECT|BufferView::FITCUR);
324 owner()->message(_("Paragraph environment type copied"));
329 void BufferView::pasteEnvironment()
332 text->pasteEnvironmentType(this);
333 owner()->message(_("Paragraph environment type set"));
334 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
339 void BufferView::copy()
342 text->CopySelection(this);
343 // clear the selection, even if mark_set
345 text->ClearSelection(this);
346 update(text, BufferView::SELECT|BufferView::FITCUR);
347 owner()->message(_("Copy"));
352 void BufferView::cut()
356 update(text, BufferView::SELECT|BufferView::FITCUR);
357 text->CutSelection(this);
358 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
359 owner()->message(_("Cut"));
364 void BufferView::paste()
366 if (!available()) return;
368 owner()->message(_("Paste"));
371 // clear the selection
373 text->ClearSelection(this);
374 update(text, BufferView::SELECT|BufferView::FITCUR);
377 text->PasteSelection(this);
378 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
380 // clear the selection
382 text->ClearSelection(this);
383 update(text, BufferView::SELECT|BufferView::FITCUR);
387 void BufferView::gotoInset(std::vector<Inset::Code> const & codes,
390 if (!available()) return;
394 update(text, BufferView::SELECT|BufferView::FITCUR);
398 text->cursor.par()->GetChar(text->cursor.pos()) == LyXParagraph::META_INSET) {
399 Inset const * inset = text->cursor.par()->GetInset(text->cursor.pos());
400 if (find(codes.begin(), codes.end(), inset->LyxCode())
403 static_cast<InsetCommand const *>(inset)->getContents();
406 if (!text->GotoNextInset(this, codes, contents)) {
407 if (text->cursor.pos()
408 || text->cursor.par() != text->FirstParagraph()) {
409 LyXCursor tmp = text->cursor;
410 text->cursor.par(text->FirstParagraph());
412 if (!text->GotoNextInset(this, codes, contents)) {
414 owner()->message(_("No more insets"));
417 owner()->message(_("No more insets"));
420 update(text, BufferView::SELECT|BufferView::FITCUR);
421 text->selection.cursor = text->cursor;
425 void BufferView::gotoInset(Inset::Code code, bool same_content)
427 gotoInset(vector<Inset::Code>(1, code), same_content);
431 void BufferView::insertCorrectQuote()
435 if (text->cursor.pos())
436 c = text->cursor.par()->GetChar(text->cursor.pos() - 1);
440 insertInset(new InsetQuotes(c, buffer()->params));
444 /* these functions are for the spellchecker */
445 string const BufferView::nextWord(float & value)
452 return text->SelectNextWord(this, value);
456 void BufferView::selectLastWord()
458 if (!available()) return;
462 text->SelectSelectedWord(this);
463 toggleSelection(false);
464 update(text, BufferView::SELECT|BufferView::FITCUR);
468 void BufferView::endOfSpellCheck()
470 if (!available()) return;
474 text->SelectSelectedWord(this);
475 text->ClearSelection(this);
476 update(text, BufferView::SELECT|BufferView::FITCUR);
480 void BufferView::replaceWord(string const & replacestring)
482 if (!available()) return;
485 update(text, BufferView::SELECT|BufferView::FITCUR);
487 /* clear the selection (if there is any) */
488 toggleSelection(false);
489 update(text, BufferView::SELECT|BufferView::FITCUR);
491 /* clear the selection (if there is any) */
492 toggleSelection(false);
493 text->ReplaceSelectionWithString(this, replacestring);
495 text->SetSelectionOverString(this, replacestring);
497 // Go back so that replacement string is also spellchecked
498 for (string::size_type i = 0; i < replacestring.length() + 1; ++i) {
499 text->CursorLeft(this);
501 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
503 // End of spellchecker stuff
506 bool BufferView::lockInset(UpdatableInset * inset)
508 if (!theLockingInset() && inset) {
509 theLockingInset(inset);
512 return theLockingInset()->LockInsetInInset(this, inset);
518 void BufferView::showLockedInsetCursor(int x, int y, int asc, int desc)
520 if (theLockingInset() && available()) {
521 LyXCursor cursor = text->cursor;
522 if ((cursor.pos() - 1 >= 0) &&
523 (cursor.par()->GetChar(cursor.pos() - 1) ==
524 LyXParagraph::META_INSET) &&
525 (cursor.par()->GetInset(cursor.pos() - 1) ==
526 theLockingInset()->GetLockingInset()))
527 text->SetCursor(this, cursor,
528 cursor.par(), cursor.pos() - 1);
529 LyXScreen::Cursor_Shape shape = LyXScreen::BAR_SHAPE;
530 LyXText * txt = getLyXText();
531 if (theLockingInset()->GetLockingInset()->LyxCode() ==
533 (txt->real_current_font.language() !=
534 buffer()->params.language
535 || txt->real_current_font.isVisibleRightToLeft()
536 != buffer()->params.language->RightToLeft()))
537 shape = (txt->real_current_font.isVisibleRightToLeft())
538 ? LyXScreen::REVERSED_L_SHAPE
539 : LyXScreen::L_SHAPE;
540 y += cursor.y() + theLockingInset()->InsetInInsetY();
541 pimpl_->screen_->ShowManualCursor(text, x, y, asc, desc,
547 void BufferView::hideLockedInsetCursor()
549 if (theLockingInset() && available()) {
550 pimpl_->screen_->HideCursor();
555 void BufferView::fitLockedInsetCursor(int x, int y, int asc, int desc)
557 if (theLockingInset() && available()) {
558 y += text->cursor.y() + theLockingInset()->InsetInInsetY();
559 if (pimpl_->screen_->FitManualCursor(text, this, x, y, asc, desc))
565 int BufferView::unlockInset(UpdatableInset * inset)
567 if (inset && theLockingInset() == inset) {
568 inset->InsetUnlock(this);
572 } else if (inset && theLockingInset() &&
573 theLockingInset()->UnlockInsetInInset(this, inset)) {
577 return bufferlist.unlockInset(inset);
581 void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind)
583 if (!theLockingInset())
584 return; // shouldn't happen
585 if (kind == Undo::EDIT) // in this case insets would not be stored!
587 text->SetUndo(buffer(), kind,
588 text->cursor.par()->previous(),
589 text->cursor.par()->next());
593 void BufferView::updateInset(Inset * inset, bool mark_dirty)
598 // first check for locking insets
599 if (theLockingInset()) {
600 if (theLockingInset() == inset) {
601 if (text->UpdateInset(this, inset)) {
604 buffer()->markDirty();
609 } else if (theLockingInset()->UpdateInsetInInset(this,inset)) {
610 if (text->UpdateInset(this, theLockingInset())) {
613 buffer()->markDirty();
621 // then check the current buffer
624 update(text, BufferView::UPDATE);
625 if (text->UpdateInset(this, inset)) {
627 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
629 update(text, SELECT);
636 bool BufferView::ChangeInsets(Inset::Code code,
637 string const & from, string const & to)
640 LyXParagraph * par = buffer()->paragraph;
641 LyXCursor cursor = text->cursor;
642 LyXCursor tmpcursor = cursor;
643 cursor.par(tmpcursor.par());
644 cursor.pos(tmpcursor.pos());
648 for (LyXParagraph::inset_iterator it = par->inset_iterator_begin();
649 it != par->inset_iterator_end(); ++it) {
650 if ((*it)->LyxCode() == code) {
651 InsetCommand * inset = static_cast<InsetCommand *>(*it);
652 if (inset->getContents() == from) {
653 inset->setContents(to);
660 // this is possible now, since SetCursor takes
661 // care about footnotes
662 text->SetCursorIntern(this, par, 0);
663 text->RedoParagraphs(this, text->cursor,
664 text->cursor.par()->next());
665 text->FullRebreak(this);
669 text->SetCursorIntern(this, cursor.par(), cursor.pos());
674 bool BufferView::ChangeRefsIfUnique(string const & from, string const & to)
676 // Check if the label 'from' appears more than once
677 vector<string> labels = buffer()->getLabelList();
678 if (count(labels.begin(), labels.end(), from) > 1)
681 return ChangeInsets(Inset::REF_CODE, from, to);
685 bool BufferView::ChangeCitationsIfUnique(string const & from, string const & to)
688 vector<pair<string,string> > keys = buffer()->getBibkeyList();
689 if (count_if(keys.begin(), keys.end(),
690 lyx::equal_1st_in_pair<string,string>(from))
694 return ChangeInsets(Inset::CITE_CODE, from, to);
697 UpdatableInset * BufferView::theLockingInset() const
699 // If NULL is not allowed we should put an Assert here. (Lgb)
701 return text->the_locking_inset;
706 void BufferView::theLockingInset(UpdatableInset * inset)
708 text->the_locking_inset = inset;
712 LyXText * BufferView::getLyXText() const
714 if (theLockingInset()) {
715 LyXText * txt = theLockingInset()->getLyXText(this, true);
723 LyXText * BufferView::getParentText(Inset * inset) const
725 if (inset->owner()) {
726 LyXText * txt = inset->getLyXText(this);
727 inset = inset->owner();
728 while (inset && inset->getLyXText(this) == txt)
729 inset = inset->owner();
731 return inset->getLyXText(this);
737 Language const * BufferView::getParentLanguage(Inset * inset) const
739 LyXText * text = getParentText(inset);
740 return text->cursor.par()->GetFontSettings(buffer()->params,
741 text->cursor.pos()).language();