1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2001 The LyX Team.
9 * ====================================================== */
16 #include "BufferView.h"
18 #include "lyxcursor.h"
20 #include "insets/inseterror.h"
22 #include "bufferlist.h"
23 #include "support/FileInfo.h"
24 #include "lyxscreen.h"
25 #include "support/filetools.h"
26 #include "lyx_gui_misc.h"
28 #include "BufferView_pimpl.h"
29 #include "insets/insetcommand.h" //ChangeRefs
30 #include "support/lyxfunctional.h" //equal_1st_in_pair
34 extern BufferList bufferlist;
45 // Inserts a file into current document
46 bool BufferView::insertLyXFile(string const & filen)
48 // Copyright CHT Software Service GmbH
51 // Insert a Lyxformat - file into current buffer
53 // Moved from lyx_cb.C (Lgb)
55 if (filen.empty()) return false;
57 string const fname = MakeAbsPath(filen);
59 // check if file exist
60 FileInfo const fi(fname);
63 WriteAlert(_("Error!"),
64 _("Specified file is unreadable: "),
65 MakeDisplayPath(fname, 50));
71 ifstream ifs(fname.c_str());
73 WriteAlert(_("Error!"),
74 _("Cannot open specified file: "),
75 MakeDisplayPath(fname, 50));
79 char const c = ifs.peek();
87 lyxerr.debug() << "Will insert file with header" << endl;
88 res = buffer()->readFile(lex, text->cursor.par());
90 lyxerr.debug() << "Will insert file without header" << endl;
91 res = buffer()->readLyXformat2(lex, text->cursor.par());
99 bool BufferView::removeAutoInsets()
101 LyXParagraph * par = buffer()->paragraph;
103 LyXCursor tmpcursor = text->cursor;
109 // this has to be done before the delete
110 text->SetCursor(this, cursor, par, 0);
111 if (par->AutoDeleteInsets()){
113 text->RedoParagraphs(this, cursor,
114 cursor.par()->next());
115 text->FullRebreak(this);
120 // avoid forbidden cursor positions caused by error removing
121 if (tmpcursor.pos() > tmpcursor.par()->size())
122 tmpcursor.pos(tmpcursor.par()->size());
124 text->SetCursorIntern(this, tmpcursor.par(), tmpcursor.pos());
130 void BufferView::insertErrors(TeXErrors & terr)
132 // Save the cursor position
133 LyXCursor cursor = text->cursor;
135 for (TeXErrors::Errors::const_iterator cit = terr.begin();
138 string const desctext((*cit).error_desc);
139 string const errortext((*cit).error_text);
140 string const msgtxt = desctext + '\n' + errortext;
141 int const errorrow = (*cit).error_in_line;
143 // Insert error string for row number
147 if (buffer()->texrow.getIdFromRow(errorrow, tmpid, tmppos)) {
148 buffer()->texrow.increasePos(tmpid, tmppos);
151 LyXParagraph * texrowpar = 0;
154 texrowpar = text->FirstParagraph();
157 texrowpar = text->GetParFromID(tmpid);
163 InsetError * new_inset = new InsetError(msgtxt);
164 text->SetCursorIntern(this, texrowpar, tmppos);
165 text->InsertInset(this, new_inset);
166 text->FullRebreak(this);
168 // Restore the cursor position
169 text->SetCursorIntern(this, cursor.par(), cursor.pos());
173 void BufferView::setCursorFromRow(int row)
178 buffer()->texrow.getIdFromRow(row, tmpid, tmppos);
180 LyXParagraph * texrowpar;
183 texrowpar = text->FirstParagraph();
186 texrowpar = text->GetParFromID(tmpid);
188 text->SetCursor(this, texrowpar, tmppos);
192 bool BufferView::insertInset(Inset * inset, string const & lout)
194 return pimpl_->insertInset(inset, lout);
198 /* This is also a buffer property (ale) */
199 // Not so sure about that. a goto Label function can not be buffer local, just
200 // think how this will work in a multiwindo/buffer environment, all the
201 // cursors in all the views showing this buffer will move. (Lgb)
202 // OK, then no cursor action should be allowed in buffer. (ale)
203 bool BufferView::gotoLabel(string const & label)
206 for (Buffer::inset_iterator it = buffer()->inset_iterator_begin();
207 it != buffer()->inset_iterator_end(); ++it) {
208 vector<string> labels = (*it)->getLabelList();
209 if (find(labels.begin(),labels.end(),label)
212 text->SetCursor(this, it.getPar(), it.getPos());
213 text->selection.cursor = text->cursor;
214 update(text, BufferView::SELECT|BufferView::FITCUR);
222 void BufferView::menuUndo()
225 owner()->message(_("Undo"));
228 update(text, BufferView::SELECT|BufferView::FITCUR);
229 if (!text->TextUndo(this))
230 owner()->message(_("No forther undo information"));
232 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
238 void BufferView::menuRedo()
240 if (theLockingInset()) {
241 owner()->message(_("Redo not yet supported in math mode"));
246 owner()->message(_("Redo"));
249 update(text, BufferView::SELECT|BufferView::FITCUR);
250 if (!text->TextRedo(this))
251 owner()->message(_("No further redo information"));
253 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
259 void BufferView::copyEnvironment()
262 text->copyEnvironmentType();
263 // clear the selection, even if mark_set
265 text->ClearSelection(this);
266 update(text, BufferView::SELECT|BufferView::FITCUR);
267 owner()->message(_("Paragraph environment type copied"));
272 void BufferView::pasteEnvironment()
275 text->pasteEnvironmentType(this);
276 owner()->message(_("Paragraph environment type set"));
277 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
282 void BufferView::copy()
285 text->CopySelection(this);
286 // clear the selection, even if mark_set
288 text->ClearSelection(this);
289 update(text, BufferView::SELECT|BufferView::FITCUR);
290 owner()->message(_("Copy"));
295 void BufferView::cut()
299 update(text, BufferView::SELECT|BufferView::FITCUR);
300 text->CutSelection(this);
301 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
302 owner()->message(_("Cut"));
307 void BufferView::paste()
309 if (!available()) return;
311 owner()->message(_("Paste"));
314 // clear the selection
316 text->ClearSelection(this);
317 update(text, BufferView::SELECT|BufferView::FITCUR);
320 text->PasteSelection(this);
321 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
323 // clear the selection
325 text->ClearSelection(this);
326 update(text, BufferView::SELECT|BufferView::FITCUR);
332 void BufferView::insertCorrectQuote()
336 if (text->cursor.pos())
337 c = text->cursor.par()->GetChar(text->cursor.pos() - 1);
341 insertInset(new InsetQuotes(c, buffer()->params));
345 /* these functions are for the spellchecker */
346 string const BufferView::nextWord(float & value)
353 return text->SelectNextWord(this, value);
357 void BufferView::selectLastWord()
359 if (!available()) return;
363 text->SelectSelectedWord(this);
364 toggleSelection(false);
365 update(text, BufferView::SELECT|BufferView::FITCUR);
369 void BufferView::endOfSpellCheck()
371 if (!available()) return;
375 text->SelectSelectedWord(this);
376 text->ClearSelection(this);
377 update(text, BufferView::SELECT|BufferView::FITCUR);
381 void BufferView::replaceWord(string const & replacestring)
383 if (!available()) return;
386 update(text, BufferView::SELECT|BufferView::FITCUR);
388 /* clear the selection (if there is any) */
389 toggleSelection(false);
390 update(text, BufferView::SELECT|BufferView::FITCUR);
392 /* clear the selection (if there is any) */
393 toggleSelection(false);
394 text->ReplaceSelectionWithString(this, replacestring);
396 text->SetSelectionOverString(this, replacestring);
398 // Go back so that replacement string is also spellchecked
399 for (string::size_type i = 0; i < replacestring.length() + 1; ++i) {
400 text->CursorLeft(this);
402 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
404 // End of spellchecker stuff
407 bool BufferView::lockInset(UpdatableInset * inset)
409 if (!theLockingInset() && inset) {
410 theLockingInset(inset);
413 return theLockingInset()->LockInsetInInset(this, inset);
419 void BufferView::showLockedInsetCursor(int x, int y, int asc, int desc)
421 if (theLockingInset() && available()) {
422 LyXCursor cursor = text->cursor;
423 if ((cursor.pos() - 1 >= 0) &&
424 (cursor.par()->GetChar(cursor.pos() - 1) ==
425 LyXParagraph::META_INSET) &&
426 (cursor.par()->GetInset(cursor.pos() - 1) ==
427 theLockingInset()->GetLockingInset()))
428 text->SetCursor(this, cursor,
429 cursor.par(), cursor.pos() - 1);
430 LyXScreen::Cursor_Shape shape = LyXScreen::BAR_SHAPE;
431 LyXText * txt = getLyXText();
432 if (theLockingInset()->GetLockingInset()->LyxCode() ==
434 (txt->real_current_font.language() !=
435 buffer()->params.language
436 || txt->real_current_font.isVisibleRightToLeft()
437 != buffer()->params.language->RightToLeft()))
438 shape = (txt->real_current_font.isVisibleRightToLeft())
439 ? LyXScreen::REVERSED_L_SHAPE
440 : LyXScreen::L_SHAPE;
441 y += cursor.y() + theLockingInset()->InsetInInsetY();
442 pimpl_->screen_->ShowManualCursor(text, x, y, asc, desc,
448 void BufferView::hideLockedInsetCursor()
450 if (theLockingInset() && available()) {
451 pimpl_->screen_->HideCursor();
456 void BufferView::fitLockedInsetCursor(int x, int y, int asc, int desc)
458 if (theLockingInset() && available()) {
459 y += text->cursor.y() + theLockingInset()->InsetInInsetY();
460 if (pimpl_->screen_->FitManualCursor(text, this, x, y, asc, desc))
466 int BufferView::unlockInset(UpdatableInset * inset)
468 if (inset && theLockingInset() == inset) {
469 inset->InsetUnlock(this);
473 } else if (inset && theLockingInset() &&
474 theLockingInset()->UnlockInsetInInset(this, inset)) {
478 return bufferlist.unlockInset(inset);
482 void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind)
484 if (!theLockingInset())
485 return; // shouldn't happen
486 if (kind == Undo::EDIT) // in this case insets would not be stored!
488 text->SetUndo(buffer(), kind,
489 text->cursor.par()->previous(),
490 text->cursor.par()->next());
494 void BufferView::updateInset(Inset * inset, bool mark_dirty)
496 pimpl_->updateInset(inset, mark_dirty);
500 bool BufferView::ChangeInsets(Inset::Code code,
501 string const & from, string const & to)
504 LyXParagraph * par = buffer()->paragraph;
505 LyXCursor cursor = text->cursor;
506 LyXCursor tmpcursor = cursor;
507 cursor.par(tmpcursor.par());
508 cursor.pos(tmpcursor.pos());
512 for (LyXParagraph::inset_iterator it = par->inset_iterator_begin();
513 it != par->inset_iterator_end(); ++it) {
514 if ((*it)->LyxCode() == code) {
515 InsetCommand * inset = static_cast<InsetCommand *>(*it);
516 if (inset->getContents() == from) {
517 inset->setContents(to);
524 // this is possible now, since SetCursor takes
525 // care about footnotes
526 text->SetCursorIntern(this, par, 0);
527 text->RedoParagraphs(this, text->cursor,
528 text->cursor.par()->next());
529 text->FullRebreak(this);
533 text->SetCursorIntern(this, cursor.par(), cursor.pos());
538 bool BufferView::ChangeRefsIfUnique(string const & from, string const & to)
540 // Check if the label 'from' appears more than once
541 vector<string> labels = buffer()->getLabelList();
542 if (count(labels.begin(), labels.end(), from) > 1)
545 return ChangeInsets(Inset::REF_CODE, from, to);
549 bool BufferView::ChangeCitationsIfUnique(string const & from, string const & to)
552 vector<pair<string,string> > keys = buffer()->getBibkeyList();
553 if (count_if(keys.begin(), keys.end(),
554 lyx::equal_1st_in_pair<string,string>(from))
558 return ChangeInsets(Inset::CITE_CODE, from, to);
562 UpdatableInset * BufferView::theLockingInset() const
564 // If NULL is not allowed we should put an Assert here. (Lgb)
566 return text->the_locking_inset;
571 void BufferView::theLockingInset(UpdatableInset * inset)
573 text->the_locking_inset = inset;
577 LyXText * BufferView::getLyXText() const
579 if (theLockingInset()) {
580 LyXText * txt = theLockingInset()->getLyXText(this, true);
588 LyXText * BufferView::getParentText(Inset * inset) const
590 if (inset->owner()) {
591 LyXText * txt = inset->getLyXText(this);
592 inset = inset->owner();
593 while (inset && inset->getLyXText(this) == txt)
594 inset = inset->owner();
596 return inset->getLyXText(this);
602 Language const * BufferView::getParentLanguage(Inset * inset) const
604 LyXText * text = getParentText(inset);
605 return text->cursor.par()->GetFontSettings(buffer()->params,
606 text->cursor.pos()).language();