]> git.lyx.org Git - features.git/blob - src/BufferView2.C
remove !NEW_INSETS cruft
[features.git] / src / BufferView2.C
1 // -*- C++ -*-
2 /* This file is part of
3  * ====================================================== 
4  * 
5  *           LyX, The Document Processor
6  *        
7  *           Copyright 1995 Matthias Ettrich
8  *           Copyright 1995-2000 The LyX Team.
9  *
10  * ====================================================== */
11
12 #include <config.h>
13
14 #include <fstream>
15 #include <algorithm>
16
17 #include "BufferView.h"
18 #include "buffer.h"
19 #include "lyxcursor.h"
20 #include "lyxtext.h"
21 #include "insets/inseterror.h"
22 #include "insets/insetinfo.h"
23 #include "insets/insetspecialchar.h"
24 #include "LyXView.h"
25 #include "bufferlist.h"
26 #include "support/FileInfo.h"
27 #include "lyxscreen.h"
28 #include "support/filetools.h"
29 #include "lyx_gui_misc.h"
30 #include "LaTeX.h"
31 #include "BufferView_pimpl.h"
32 #include "insets/insetcommand.h" //ChangeRefs
33 #include "support/lyxfunctional.h" //equal_1st_in_pair
34 #include "language.h"
35 #include "gettext.h"
36
37 extern BufferList bufferlist;
38
39 using std::pair;
40 using std::endl;
41 using std::ifstream;
42 using std::vector;
43 using std::find;
44 using std::count;
45 using std::count_if;
46
47 // Inserts a file into current document
48 bool BufferView::insertLyXFile(string const & filen)
49         //
50         // Copyright CHT Software Service GmbH
51         // Uwe C. Schroeder
52         //
53         // Insert a Lyxformat - file into current buffer
54         //
55         // Moved from lyx_cb.C (Lgb)
56 {
57         if (filen.empty()) return false;
58
59         string const fname = MakeAbsPath(filen);
60
61         // check if file exist
62         FileInfo const fi(fname);
63
64         if (!fi.readable()) {
65                 WriteAlert(_("Error!"),
66                            _("Specified file is unreadable: "),
67                            MakeDisplayPath(fname, 50));
68                 return false;
69         }
70         
71         beforeChange(text);
72
73         ifstream ifs(fname.c_str());
74         if (!ifs) {
75                 WriteAlert(_("Error!"),
76                            _("Cannot open specified file: "),
77                            MakeDisplayPath(fname, 50));
78                 return false;
79         }
80         
81         char const c = ifs.peek();
82        
83         LyXLex lex(0, 0);
84         lex.setStream(ifs);
85
86         bool res = true;
87
88         if (c == '#') {
89                 lyxerr.debug() << "Will insert file with header" << endl;
90                 res = buffer()->readFile(lex, text->cursor.par());
91         } else {
92                 lyxerr.debug() << "Will insert file without header" << endl;
93                 res = buffer()->readLyXformat2(lex, text->cursor.par());
94         }
95
96         resize();
97         return res;
98 }
99
100
101 bool BufferView::removeAutoInsets()
102 {
103         LyXParagraph * par = buffer()->paragraph;
104
105         LyXCursor tmpcursor = text->cursor;
106         LyXCursor cursor;
107
108         bool a = false;
109
110         while (par) {
111                 // this has to be done before the delete
112                 text->SetCursor(this, cursor, par, 0);
113                 if (par->AutoDeleteInsets()){
114                         a = true;
115                         text->RedoParagraphs(this, cursor,
116                                              cursor.par()->next());
117                         text->FullRebreak(this);
118                 }
119                 par = par->next();
120         }
121
122         // avoid forbidden cursor positions caused by error removing
123         if (tmpcursor.pos() > tmpcursor.par()->size())
124                 tmpcursor.pos(tmpcursor.par()->size());
125
126         text->SetCursorIntern(this, tmpcursor.par(), tmpcursor.pos());
127
128         return a;
129 }
130
131
132 void BufferView::insertErrors(TeXErrors & terr)
133 {
134         // Save the cursor position
135         LyXCursor cursor = text->cursor;
136
137         for (TeXErrors::Errors::const_iterator cit = terr.begin();
138              cit != terr.end();
139              ++cit) {
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;
144
145                 // Insert error string for row number
146                 int tmpid = -1; 
147                 int tmppos = -1;
148
149                 if (buffer()->texrow.getIdFromRow(errorrow, tmpid, tmppos)) {
150                         buffer()->texrow.increasePos(tmpid, tmppos);
151                 }
152                 
153                 LyXParagraph * texrowpar = 0;
154
155                 if (tmpid == -1) {
156                         texrowpar = text->FirstParagraph();
157                         tmppos = 0;
158                 } else {
159                         texrowpar = text->GetParFromID(tmpid);
160                 }
161
162                 if (texrowpar == 0)
163                         continue;
164
165                 InsetError * new_inset = new InsetError(msgtxt);
166                 text->SetCursorIntern(this, texrowpar, tmppos);
167                 text->InsertInset(this, new_inset);
168                 text->FullRebreak(this);
169         }
170         // Restore the cursor position
171         text->SetCursorIntern(this, cursor.par(), cursor.pos());
172 }
173
174
175 void BufferView::setCursorFromRow(int row)
176 {
177         int tmpid = -1; 
178         int tmppos = -1;
179
180         buffer()->texrow.getIdFromRow(row, tmpid, tmppos);
181
182         LyXParagraph * texrowpar;
183
184         if (tmpid == -1) {
185                 texrowpar = text->FirstParagraph();
186                 tmppos = 0;
187         } else {
188                 texrowpar = text->GetParFromID(tmpid);
189         }
190         text->SetCursor(this, texrowpar, tmppos);
191 }
192
193
194 bool BufferView::insertInset(Inset * inset, string const & lout,
195                              bool /*no_table*/)
196 {
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);
202                 return false;
203         }
204
205         // not quite sure if we want this...
206         text->SetCursorParUndo(buffer());
207         text->FreezeUndo();
208         
209         beforeChange(text);
210         if (!lout.empty()) {
211                 update(text, BufferView::SELECT|BufferView::FITCUR);
212                 text->BreakParagraph(this);
213                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
214
215                 if (text->cursor.par()->size()) {
216                         text->CursorLeft(this);
217                         
218                         text->BreakParagraph(this);
219                         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
220                 }
221
222                 pair<bool, LyXTextClass::size_type> lres =
223                         textclasslist.NumberOfLayout(buffer()->params
224                                                      .textclass, lout);
225                 LyXTextClass::size_type lay;
226                 if (lres.first != false) {
227                         // layout found
228                         lay = lres.second;
229                 } else {
230                         // layout not fount using default "Standard" (0)
231                         lay = 0;
232                 }
233                  
234                 text->SetLayout(this, lay);
235                 
236                 text->SetParagraph(this, 0, 0,
237                                    0, 0,
238                                    VSpace(VSpace::NONE), VSpace(VSpace::NONE),
239                                    LYX_ALIGN_LAYOUT, 
240                                    string(),
241                                    0);
242                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
243                 
244                 text->current_font.setLatex(LyXFont::OFF);
245         }
246         
247         text->InsertInset(this, inset);
248         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
249
250         text->UnFreezeUndo();
251         return true;
252 }
253
254
255 // Open and lock an updatable inset
256 bool BufferView::open_new_inset(UpdatableInset * new_inset, bool behind)
257 {
258         beforeChange(text);
259         text->FinishUndo();
260         if (!insertInset(new_inset)) {
261                 delete new_inset;
262                 return false;
263         }
264         if (behind) {
265                 LyXFont & font = getLyXText()->real_current_font;
266                 new_inset->Edit(this, new_inset->width(this, font), 0, 0);
267         } else
268                 new_inset->Edit(this, 0, 0, 0);
269         return true;
270 }
271
272 /* This is also a buffer property (ale) */
273 // Not so sure about that. a goto Label function can not be buffer local, just
274 // think how this will work in a multiwindo/buffer environment, all the
275 // cursors in all the views showing this buffer will move. (Lgb)
276 // OK, then no cursor action should be allowed in buffer. (ale)
277 bool BufferView::gotoLabel(string const & label)
278
279 {
280         for (Buffer::inset_iterator it = buffer()->inset_iterator_begin();
281              it != buffer()->inset_iterator_end(); ++it) {
282                 vector<string> labels = (*it)->getLabelList();
283                 if (find(labels.begin(),labels.end(),label)
284                      != labels.end()) {
285                         beforeChange(text);
286                         text->SetCursor(this, it.getPar(), it.getPos());
287                         text->sel_cursor = text->cursor;
288                         update(text, BufferView::SELECT|BufferView::FITCUR);
289                         return true;
290                 }
291         }
292         return false;
293 }
294
295
296 void BufferView::insertNote()
297 {
298         InsetInfo * new_inset = new InsetInfo();
299         insertInset(new_inset);
300         new_inset->Edit(this, 0, 0, 0);
301 }
302
303
304 void BufferView::menuUndo()
305 {
306         if (available()) {
307                 owner()->message(_("Undo"));
308                 hideCursor();
309                 beforeChange(text);
310                 update(text, BufferView::SELECT|BufferView::FITCUR);
311                 if (!text->TextUndo(this))
312                         owner()->message(_("No forther undo information"));
313                 else
314                         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
315                 setState();
316         }
317 }
318
319
320 void BufferView::menuRedo()
321 {
322         if (theLockingInset()) {
323                 owner()->message(_("Redo not yet supported in math mode"));
324                 return;
325         }    
326    
327         if (available()) {
328                 owner()->message(_("Redo"));
329                 hideCursor();
330                 beforeChange(text);
331                 update(text, BufferView::SELECT|BufferView::FITCUR);
332                 if (!text->TextRedo(this))
333                         owner()->message(_("No further redo information"));
334                 else
335                         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
336                 setState();
337         }
338 }
339
340
341 void BufferView::hyphenationPoint()
342 {
343         if (available()) {
344                 hideCursor();
345                 update(text, BufferView::SELECT|BufferView::FITCUR);
346                 InsetSpecialChar * new_inset = 
347                         new InsetSpecialChar(InsetSpecialChar::HYPHENATION);
348                 insertInset(new_inset);
349         }
350 }
351
352
353 void BufferView::ldots()
354 {
355         if (available())  {
356                 hideCursor();
357                 update(text, BufferView::SELECT|BufferView::FITCUR);
358                 InsetSpecialChar * new_inset = 
359                         new InsetSpecialChar(InsetSpecialChar::LDOTS);
360                 insertInset(new_inset);
361         }
362 }
363
364
365 void BufferView::endOfSentenceDot()
366 {
367         if (available()) {
368                 hideCursor();
369                 update(text, BufferView::SELECT|BufferView::FITCUR);
370                 InsetSpecialChar * new_inset = 
371                         new InsetSpecialChar(InsetSpecialChar::END_OF_SENTENCE);
372                 insertInset(new_inset);
373         }
374 }
375
376
377 void BufferView::menuSeparator()
378 {
379         if (available()) {
380                 hideCursor();
381                 update(text, BufferView::SELECT|BufferView::FITCUR);
382                 InsetSpecialChar * new_inset = 
383                         new InsetSpecialChar(InsetSpecialChar::MENU_SEPARATOR);
384                 insertInset(new_inset);
385         }
386 }
387
388
389 void BufferView::newline()
390 {
391         if (available()) {
392                 hideCursor();
393                 update(text, BufferView::SELECT|BufferView::FITCUR);
394                 text->InsertChar(this, LyXParagraph::META_NEWLINE);
395                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
396         }
397 }
398
399
400 void BufferView::protectedBlank(LyXText * lt)
401 {
402         if (available()) {
403                 hideCursor();
404                 update(lt, BufferView::SELECT|BufferView::FITCUR);
405                 InsetSpecialChar * new_inset =
406                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
407                 if (!insertInset(new_inset))
408                         delete new_inset;
409                 else
410                         updateInset(new_inset, true);
411         }
412 }
413
414
415 void BufferView::hfill()
416 {
417         if (available()) {
418                 hideCursor();
419                 update(text, BufferView::SELECT|BufferView::FITCUR);
420                 text->InsertChar(this, LyXParagraph::META_HFILL);
421                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
422         }
423 }
424
425
426 void BufferView::copyEnvironment()
427 {
428         if (available()) {
429                 text->copyEnvironmentType();
430                 // clear the selection, even if mark_set
431                 toggleSelection();
432                 text->ClearSelection(this);
433                 update(text, BufferView::SELECT|BufferView::FITCUR);
434                 owner()->message(_("Paragraph environment type copied"));
435         }
436 }
437
438
439 void BufferView::pasteEnvironment()
440 {
441         if (available()) {
442                 text->pasteEnvironmentType(this);
443                 owner()->message(_("Paragraph environment type set"));
444                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
445         }
446 }
447
448
449 void BufferView::copy()
450 {
451         if (available()) {
452                 text->CopySelection(this);
453                 // clear the selection, even if mark_set
454                 toggleSelection();
455                 text->ClearSelection(this);
456                 update(text, BufferView::SELECT|BufferView::FITCUR);
457                 owner()->message(_("Copy"));
458         }
459 }
460
461 void BufferView::cut()
462 {
463         if (available()) {
464                 hideCursor();
465                 update(text, BufferView::SELECT|BufferView::FITCUR);
466                 text->CutSelection(this);
467                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
468                 owner()->message(_("Cut"));
469         }
470 }
471
472
473 void BufferView::paste()
474 {
475         if (!available()) return;
476
477         owner()->message(_("Paste"));
478
479         hideCursor();
480         // clear the selection
481         toggleSelection();
482         text->ClearSelection(this);
483         update(text, BufferView::SELECT|BufferView::FITCUR);
484         
485         // paste
486         text->PasteSelection(this);
487         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
488         
489         // clear the selection 
490         toggleSelection();
491         text->ClearSelection(this);
492         update(text, BufferView::SELECT|BufferView::FITCUR);
493 }
494
495
496 void BufferView::gotoInset(std::vector<Inset::Code> const & codes,
497                            bool same_content)
498 {
499         if (!available()) return;
500    
501         hideCursor();
502         beforeChange(text);
503         update(text, BufferView::SELECT|BufferView::FITCUR);
504
505         string contents;
506         if (same_content &&
507             text->cursor.par()->GetChar(text->cursor.pos()) == LyXParagraph::META_INSET) {
508                 Inset const * inset = text->cursor.par()->GetInset(text->cursor.pos());
509                 if (find(codes.begin(), codes.end(), inset->LyxCode())
510                     != codes.end())
511                         contents =
512                                 static_cast<InsetCommand const *>(inset)->getContents();
513         }
514         
515         if (!text->GotoNextInset(this, codes, contents)) {
516                 if (text->cursor.pos() 
517                     || text->cursor.par() != text->FirstParagraph()) {
518                                 LyXCursor tmp = text->cursor;
519                                 text->cursor.par(text->FirstParagraph());
520                                 text->cursor.pos(0);
521                                 if (!text->GotoNextInset(this, codes, contents)) {
522                                         text->cursor = tmp;
523                                         owner()->message(_("No more insets"));
524                                 }
525                         } else {
526                                 owner()->message(_("No more insets"));
527                         }
528         }
529         update(text, BufferView::SELECT|BufferView::FITCUR);
530         text->sel_cursor = text->cursor;
531 }
532
533
534 void BufferView::gotoInset(Inset::Code code, bool same_content)
535 {
536         gotoInset(vector<Inset::Code>(1, code), same_content);
537 }
538
539
540 void BufferView::insertCorrectQuote()
541 {
542         char c;
543
544         if (text->cursor.pos())
545                 c = text->cursor.par()->GetChar(text->cursor.pos() - 1);
546         else 
547                 c = ' ';
548
549         insertInset(new InsetQuotes(c, buffer()->params));
550 }
551
552
553 /* these functions are for the spellchecker */ 
554 string const BufferView::nextWord(float & value)
555 {
556         if (!available()) {
557                 value = 1;
558                 return string();
559         }
560
561         return text->SelectNextWord(this, value);
562 }
563
564   
565 void BufferView::selectLastWord()
566 {
567         if (!available()) return;
568    
569         hideCursor();
570         beforeChange(text);
571         text->SelectSelectedWord(this);
572         toggleSelection(false);
573         update(text, BufferView::SELECT|BufferView::FITCUR);
574 }
575
576
577 void BufferView::endOfSpellCheck()
578 {
579         if (!available()) return;
580    
581         hideCursor();
582         beforeChange(text);
583         text->SelectSelectedWord(this);
584         text->ClearSelection(this);
585         update(text, BufferView::SELECT|BufferView::FITCUR);
586 }
587
588
589 void BufferView::replaceWord(string const & replacestring)
590 {
591         if (!available()) return;
592
593         hideCursor();
594         update(text, BufferView::SELECT|BufferView::FITCUR);
595    
596         /* clear the selection (if there is any) */ 
597         toggleSelection(false);
598         update(text, BufferView::SELECT|BufferView::FITCUR);
599    
600         /* clear the selection (if there is any) */ 
601         toggleSelection(false);
602         text->ReplaceSelectionWithString(this, replacestring);
603    
604         text->SetSelectionOverString(this, replacestring);
605
606         // Go back so that replacement string is also spellchecked
607         for (string::size_type i = 0; i < replacestring.length() + 1; ++i) {
608                 text->CursorLeft(this);
609         }
610         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
611 }
612 // End of spellchecker stuff
613
614
615 bool BufferView::lockInset(UpdatableInset * inset)
616 {
617         if (!theLockingInset() && inset) {
618                 theLockingInset(inset);
619                 return true;
620         } else if (inset) {
621             return theLockingInset()->LockInsetInInset(this, inset);
622         }
623         return false;
624 }
625
626
627 void BufferView::showLockedInsetCursor(int x, int y, int asc, int desc)
628 {
629         if (theLockingInset() && available()) {
630                 LyXCursor cursor = text->cursor;
631                 if ((cursor.pos() - 1 >= 0) &&
632                     (cursor.par()->GetChar(cursor.pos() - 1) ==
633                      LyXParagraph::META_INSET) &&
634                     (cursor.par()->GetInset(cursor.pos() - 1) ==
635                      theLockingInset()->GetLockingInset()))
636                         text->SetCursor(this, cursor,
637                                         cursor.par(), cursor.pos() - 1);
638                 LyXScreen::Cursor_Shape shape = LyXScreen::BAR_SHAPE;
639                 LyXText * txt = getLyXText();
640                 if (theLockingInset()->GetLockingInset()->LyxCode() ==
641                     Inset::TEXT_CODE &&
642                     (txt->real_current_font.language() !=
643                      buffer()->params.language
644                      || txt->real_current_font.isVisibleRightToLeft()
645                      != buffer()->params.language->RightToLeft()))
646                         shape = (txt->real_current_font.isVisibleRightToLeft())
647                                 ? LyXScreen::REVERSED_L_SHAPE
648                                 : LyXScreen::L_SHAPE;
649                 y += cursor.y() + theLockingInset()->InsetInInsetY();
650                 pimpl_->screen_->ShowManualCursor(text, x, y, asc, desc,
651                                                   shape);
652         }
653 }
654
655
656 void BufferView::hideLockedInsetCursor()
657 {
658         if (theLockingInset() && available()) {
659                 pimpl_->screen_->HideCursor();
660         }
661 }
662
663
664 void BufferView::fitLockedInsetCursor(int x, int y, int asc, int desc)
665 {
666         if (theLockingInset() && available()) {
667                 y += text->cursor.y() + theLockingInset()->InsetInInsetY();
668                 if (pimpl_->screen_->FitManualCursor(text, this, x, y, asc, desc))
669                         updateScrollbar();
670         }
671 }
672
673
674 int BufferView::unlockInset(UpdatableInset * inset)
675 {
676         if (inset && theLockingInset() == inset) {
677                 inset->InsetUnlock(this);
678                 theLockingInset(0);
679                 text->FinishUndo();
680                 return 0;
681         } else if (inset && theLockingInset() &&
682                    theLockingInset()->UnlockInsetInInset(this, inset)) {
683                 text->FinishUndo();
684                 return 0;
685         }
686         return bufferlist.unlockInset(inset);
687 }
688
689
690 void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind)
691 {
692         if (!theLockingInset())
693                 return; // shouldn't happen
694         if (kind == Undo::EDIT) // in this case insets would not be stored!
695                 kind = Undo::FINISH;
696         text->SetUndo(buffer(), kind,
697                       text->cursor.par()->previous(), 
698                       text->cursor.par()->next());
699 }
700
701
702 void BufferView::updateInset(Inset * inset, bool mark_dirty)
703 {
704         if (!inset)
705                 return;
706
707         // first check for locking insets
708         if (theLockingInset()) {
709                 if (theLockingInset() == inset) {
710                         if (text->UpdateInset(this, inset)) {
711                                 update();
712                                 if (mark_dirty) {
713                                         buffer()->markDirty();
714                                 }
715                                 updateScrollbar();
716                                 return;
717                         }
718                 } else if (theLockingInset()->UpdateInsetInInset(this,inset)) {
719                         if (text->UpdateInset(this, theLockingInset())) {
720                                 update();
721                                 if (mark_dirty){
722                                         buffer()->markDirty();
723                                 }
724                                 updateScrollbar();
725                                 return;
726                         }
727                 }
728         }
729   
730         // then check the current buffer
731         if (available()) {
732                 hideCursor();
733                 update(text, BufferView::UPDATE);
734                 if (text->UpdateInset(this, inset)) {
735                         if (mark_dirty)
736                                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
737                         else 
738                                 update(text, SELECT);
739                         return;
740                 }
741         }
742 }
743
744
745 bool BufferView::ChangeInsets(Inset::Code code,
746                               string const & from, string const & to)
747 {
748         bool flag = false;
749         LyXParagraph * par = buffer()->paragraph;
750         LyXCursor cursor = text->cursor;
751         LyXCursor tmpcursor = cursor;
752         cursor.par(tmpcursor.par());
753         cursor.pos(tmpcursor.pos());
754
755         while (par) {
756                 bool flag2 = false;
757                 for (LyXParagraph::inset_iterator it = par->inset_iterator_begin();
758                      it != par->inset_iterator_end(); ++it) {
759                         if ((*it)->LyxCode() == code) {
760                                 InsetCommand * inset = static_cast<InsetCommand *>(*it);
761                                 if (inset->getContents() == from) {
762                                         inset->setContents(to);
763                                         flag2 = true;
764                                 }
765                         }
766                 }
767                 if (flag2) {
768                         flag = true;
769                         // this is possible now, since SetCursor takes
770                         // care about footnotes
771                         text->SetCursorIntern(this, par, 0);
772                         text->RedoParagraphs(this, text->cursor,
773                                              text->cursor.par()->next());
774                         text->FullRebreak(this);
775                 }
776                 par = par->next();
777         }
778         text->SetCursorIntern(this, cursor.par(), cursor.pos());
779         return flag;
780 }
781
782
783 bool BufferView::ChangeRefsIfUnique(string const & from, string const & to)
784 {
785         // Check if the label 'from' appears more than once
786         vector<string> labels = buffer()->getLabelList();
787         if (count(labels.begin(), labels.end(), from) > 1)
788                 return false;
789
790         return ChangeInsets(Inset::REF_CODE, from, to);
791 }
792
793
794 bool BufferView::ChangeCitationsIfUnique(string const & from, string const & to)
795 {
796
797         vector<pair<string,string> > keys = buffer()->getBibkeyList();  
798         if (count_if(keys.begin(), keys.end(), 
799                      lyx::equal_1st_in_pair<string,string>(from)) 
800             > 1)
801                 return false;
802
803         return ChangeInsets(Inset::CITE_CODE, from, to);
804 }
805
806 UpdatableInset * BufferView::theLockingInset() const
807 {
808         // If NULL is not allowed we should put an Assert here. (Lgb)
809         if (text)
810                 return text->the_locking_inset;
811         return 0;
812 }
813
814
815 void BufferView::theLockingInset(UpdatableInset * inset)
816 {
817         text->the_locking_inset = inset;
818 }
819
820
821 LyXText * BufferView::getLyXText() const
822 {
823         if (theLockingInset()) {
824                 LyXText * txt = theLockingInset()->getLyXText(this, true);
825                 if (txt)
826                         return txt;
827         }
828         return text;
829 }
830
831
832 LyXText * BufferView::getParentText(Inset * inset) const
833 {
834         if (inset->owner()) {
835                 LyXText * txt = inset->getLyXText(this);
836                 inset = inset->owner();
837                 while (inset && inset->getLyXText(this) == txt)
838                         inset = inset->owner();
839                 if (inset)
840                         return inset->getLyXText(this);
841         }
842         return text;
843 }
844
845
846 Language const * BufferView::getParentLanguage(Inset * inset) const
847 {
848         LyXText * text = getParentText(inset);
849         return text->cursor.par()->GetFontSettings(buffer()->params,
850                                                    text->cursor.pos()).language();
851 }