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"
23 #include "bufferlist.h"
24 #include "support/FileInfo.h"
25 #include "lyxscreen.h"
26 #include "support/filetools.h"
27 #include "lyx_gui_misc.h"
29 #include "BufferView_pimpl.h"
30 #include "insets/insetcommand.h" //ChangeRefs
31 #include "support/lyxfunctional.h" //equal_1st_in_pair
35 extern BufferList bufferlist;
46 // Inserts a file into current document
47 bool BufferView::insertLyXFile(string const & filen)
49 // Copyright CHT Software Service GmbH
52 // Insert a Lyxformat - file into current buffer
54 // Moved from lyx_cb.C (Lgb)
56 if (filen.empty()) return false;
58 string const fname = MakeAbsPath(filen);
60 // check if file exist
61 FileInfo const fi(fname);
64 WriteAlert(_("Error!"),
65 _("Specified file is unreadable: "),
66 MakeDisplayPath(fname, 50));
72 ifstream ifs(fname.c_str());
74 WriteAlert(_("Error!"),
75 _("Cannot open specified file: "),
76 MakeDisplayPath(fname, 50));
80 char const c = ifs.peek();
88 lyxerr.debug() << "Will insert file with header" << endl;
89 res = buffer()->readFile(lex, text->cursor.par());
91 lyxerr.debug() << "Will insert file without header" << endl;
92 res = buffer()->readLyXformat2(lex, text->cursor.par());
100 bool BufferView::removeAutoInsets()
102 LyXParagraph * par = buffer()->paragraph;
104 LyXCursor tmpcursor = text->cursor;
110 // this has to be done before the delete
111 text->SetCursor(this, cursor, par, 0);
112 if (par->AutoDeleteInsets()){
114 text->RedoParagraphs(this, cursor,
115 cursor.par()->next());
116 text->FullRebreak(this);
121 // avoid forbidden cursor positions caused by error removing
122 if (tmpcursor.pos() > tmpcursor.par()->size())
123 tmpcursor.pos(tmpcursor.par()->size());
125 text->SetCursorIntern(this, tmpcursor.par(), tmpcursor.pos());
131 void BufferView::insertErrors(TeXErrors & terr)
133 // Save the cursor position
134 LyXCursor cursor = text->cursor;
136 for (TeXErrors::Errors::const_iterator cit = terr.begin();
139 string const desctext((*cit).error_desc);
140 string const errortext((*cit).error_text);
141 string const msgtxt = desctext + '\n' + errortext;
142 int const errorrow = (*cit).error_in_line;
144 // Insert error string for row number
148 if (buffer()->texrow.getIdFromRow(errorrow, tmpid, tmppos)) {
149 buffer()->texrow.increasePos(tmpid, tmppos);
152 LyXParagraph * texrowpar = 0;
155 texrowpar = text->FirstParagraph();
158 texrowpar = text->GetParFromID(tmpid);
164 InsetError * new_inset = new InsetError(msgtxt);
165 text->SetCursorIntern(this, texrowpar, tmppos);
166 text->InsertInset(this, new_inset);
167 text->FullRebreak(this);
169 // Restore the cursor position
170 text->SetCursorIntern(this, cursor.par(), cursor.pos());
174 void BufferView::setCursorFromRow(int row)
179 buffer()->texrow.getIdFromRow(row, tmpid, tmppos);
181 LyXParagraph * texrowpar;
184 texrowpar = text->FirstParagraph();
187 texrowpar = text->GetParFromID(tmpid);
189 text->SetCursor(this, texrowpar, tmppos);
193 bool BufferView::insertInset(Inset * inset, string const & lout)
195 return pimpl_->insertInset(inset, lout);
199 /* This is also a buffer property (ale) */
200 // Not so sure about that. a goto Label function can not be buffer local, just
201 // think how this will work in a multiwindo/buffer environment, all the
202 // cursors in all the views showing this buffer will move. (Lgb)
203 // OK, then no cursor action should be allowed in buffer. (ale)
204 bool BufferView::gotoLabel(string const & label)
207 for (Buffer::inset_iterator it = buffer()->inset_iterator_begin();
208 it != buffer()->inset_iterator_end(); ++it) {
209 vector<string> labels = (*it)->getLabelList();
210 if (find(labels.begin(),labels.end(),label)
213 text->SetCursor(this, it.getPar(), it.getPos());
214 text->selection.cursor = text->cursor;
215 update(text, BufferView::SELECT|BufferView::FITCUR);
223 void BufferView::menuUndo()
226 owner()->message(_("Undo"));
229 update(text, BufferView::SELECT|BufferView::FITCUR);
230 if (!text->TextUndo(this))
231 owner()->message(_("No forther undo information"));
233 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
239 void BufferView::menuRedo()
241 if (theLockingInset()) {
242 owner()->message(_("Redo not yet supported in math mode"));
247 owner()->message(_("Redo"));
250 update(text, BufferView::SELECT|BufferView::FITCUR);
251 if (!text->TextRedo(this))
252 owner()->message(_("No further redo information"));
254 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
260 void BufferView::copyEnvironment()
263 text->copyEnvironmentType();
264 // clear the selection, even if mark_set
266 text->ClearSelection(this);
267 update(text, BufferView::SELECT|BufferView::FITCUR);
268 owner()->message(_("Paragraph environment type copied"));
273 void BufferView::pasteEnvironment()
276 text->pasteEnvironmentType(this);
277 owner()->message(_("Paragraph environment type set"));
278 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
283 void BufferView::copy()
286 text->CopySelection(this);
287 // clear the selection, even if mark_set
289 text->ClearSelection(this);
290 update(text, BufferView::SELECT|BufferView::FITCUR);
291 owner()->message(_("Copy"));
296 void BufferView::cut()
300 update(text, BufferView::SELECT|BufferView::FITCUR);
301 text->CutSelection(this);
302 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
303 owner()->message(_("Cut"));
308 void BufferView::paste()
310 if (!available()) return;
312 owner()->message(_("Paste"));
315 // clear the selection
317 text->ClearSelection(this);
318 update(text, BufferView::SELECT|BufferView::FITCUR);
321 text->PasteSelection(this);
322 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
324 // clear the selection
326 text->ClearSelection(this);
327 update(text, BufferView::SELECT|BufferView::FITCUR);
333 void BufferView::insertCorrectQuote()
337 if (text->cursor.pos())
338 c = text->cursor.par()->GetChar(text->cursor.pos() - 1);
342 insertInset(new InsetQuotes(c, buffer()->params));
346 /* these functions are for the spellchecker */
347 string const BufferView::nextWord(float & value)
354 return text->SelectNextWord(this, value);
358 void BufferView::selectLastWord()
360 if (!available()) return;
364 text->SelectSelectedWord(this);
365 toggleSelection(false);
366 update(text, BufferView::SELECT|BufferView::FITCUR);
370 void BufferView::endOfSpellCheck()
372 if (!available()) return;
376 text->SelectSelectedWord(this);
377 text->ClearSelection(this);
378 update(text, BufferView::SELECT|BufferView::FITCUR);
382 void BufferView::replaceWord(string const & replacestring)
384 if (!available()) return;
387 update(text, BufferView::SELECT|BufferView::FITCUR);
389 /* clear the selection (if there is any) */
390 toggleSelection(false);
391 update(text, BufferView::SELECT|BufferView::FITCUR);
393 /* clear the selection (if there is any) */
394 toggleSelection(false);
395 text->ReplaceSelectionWithString(this, replacestring);
397 text->SetSelectionOverString(this, replacestring);
399 // Go back so that replacement string is also spellchecked
400 for (string::size_type i = 0; i < replacestring.length() + 1; ++i) {
401 text->CursorLeft(this);
403 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
405 // End of spellchecker stuff
408 bool BufferView::lockInset(UpdatableInset * inset)
410 if (!theLockingInset() && inset) {
411 theLockingInset(inset);
414 return theLockingInset()->LockInsetInInset(this, inset);
420 void BufferView::showLockedInsetCursor(int x, int y, int asc, int desc)
422 if (theLockingInset() && available()) {
423 LyXCursor cursor = text->cursor;
424 if ((cursor.pos() - 1 >= 0) &&
425 (cursor.par()->GetChar(cursor.pos() - 1) ==
426 LyXParagraph::META_INSET) &&
427 (cursor.par()->GetInset(cursor.pos() - 1) ==
428 theLockingInset()->GetLockingInset()))
429 text->SetCursor(this, cursor,
430 cursor.par(), cursor.pos() - 1);
431 LyXScreen::Cursor_Shape shape = LyXScreen::BAR_SHAPE;
432 LyXText * txt = getLyXText();
433 if (theLockingInset()->GetLockingInset()->LyxCode() ==
435 (txt->real_current_font.language() !=
436 buffer()->params.language
437 || txt->real_current_font.isVisibleRightToLeft()
438 != buffer()->params.language->RightToLeft()))
439 shape = (txt->real_current_font.isVisibleRightToLeft())
440 ? LyXScreen::REVERSED_L_SHAPE
441 : LyXScreen::L_SHAPE;
442 y += cursor.y() + theLockingInset()->InsetInInsetY();
443 pimpl_->screen_->ShowManualCursor(text, x, y, asc, desc,
449 void BufferView::hideLockedInsetCursor()
451 if (theLockingInset() && available()) {
452 pimpl_->screen_->HideCursor();
457 void BufferView::fitLockedInsetCursor(int x, int y, int asc, int desc)
459 if (theLockingInset() && available()) {
460 y += text->cursor.y() + theLockingInset()->InsetInInsetY();
461 if (pimpl_->screen_->FitManualCursor(text, this, x, y, asc, desc))
467 int BufferView::unlockInset(UpdatableInset * inset)
469 if (inset && theLockingInset() == inset) {
470 inset->InsetUnlock(this);
474 } else if (inset && theLockingInset() &&
475 theLockingInset()->UnlockInsetInInset(this, inset)) {
479 return bufferlist.unlockInset(inset);
483 void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind)
485 if (!theLockingInset())
486 return; // shouldn't happen
487 if (kind == Undo::EDIT) // in this case insets would not be stored!
489 text->SetUndo(buffer(), kind,
490 text->cursor.par()->previous(),
491 text->cursor.par()->next());
495 void BufferView::updateInset(Inset * inset, bool mark_dirty)
497 pimpl_->updateInset(inset, mark_dirty);
501 bool BufferView::ChangeInsets(Inset::Code code,
502 string const & from, string const & to)
505 LyXParagraph * par = buffer()->paragraph;
506 LyXCursor cursor = text->cursor;
507 LyXCursor tmpcursor = cursor;
508 cursor.par(tmpcursor.par());
509 cursor.pos(tmpcursor.pos());
513 for (LyXParagraph::inset_iterator it = par->inset_iterator_begin();
514 it != par->inset_iterator_end(); ++it) {
515 if ((*it)->LyxCode() == code) {
516 InsetCommand * inset = static_cast<InsetCommand *>(*it);
517 if (inset->getContents() == from) {
518 inset->setContents(to);
525 // this is possible now, since SetCursor takes
526 // care about footnotes
527 text->SetCursorIntern(this, par, 0);
528 text->RedoParagraphs(this, text->cursor,
529 text->cursor.par()->next());
530 text->FullRebreak(this);
534 text->SetCursorIntern(this, cursor.par(), cursor.pos());
539 bool BufferView::ChangeRefsIfUnique(string const & from, string const & to)
541 // Check if the label 'from' appears more than once
542 vector<string> labels = buffer()->getLabelList();
543 if (count(labels.begin(), labels.end(), from) > 1)
546 return ChangeInsets(Inset::REF_CODE, from, to);
550 bool BufferView::ChangeCitationsIfUnique(string const & from, string const & to)
553 vector<pair<string,string> > keys = buffer()->getBibkeyList();
554 if (count_if(keys.begin(), keys.end(),
555 lyx::equal_1st_in_pair<string,string>(from))
559 return ChangeInsets(Inset::CITE_CODE, from, to);
563 UpdatableInset * BufferView::theLockingInset() const
565 // If NULL is not allowed we should put an Assert here. (Lgb)
567 return text->the_locking_inset;
572 void BufferView::theLockingInset(UpdatableInset * inset)
574 text->the_locking_inset = inset;
578 LyXText * BufferView::getLyXText() const
580 if (theLockingInset()) {
581 LyXText * txt = theLockingInset()->getLyXText(this, true);
589 LyXText * BufferView::getParentText(Inset * inset) const
591 if (inset->owner()) {
592 LyXText * txt = inset->getLyXText(this);
593 inset = inset->owner();
594 while (inset && inset->getLyXText(this) == txt)
595 inset = inset->owner();
597 return inset->getLyXText(this);
603 Language const * BufferView::getParentLanguage(Inset * inset) const
605 LyXText * text = getParentText(inset);
606 return text->cursor.par()->GetFontSettings(buffer()->params,
607 text->cursor.pos()).language();