]> git.lyx.org Git - lyx.git/blob - src/BufferView2.C
another pesky \#warning snuck in
[lyx.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 #include "lyxfunc.h"
37
38 extern BufferList bufferlist;
39
40 using std::pair;
41 using std::endl;
42 using std::ifstream;
43 using std::vector;
44 using std::find;
45 using std::count;
46 using std::count_if;
47
48 // Inserts a file into current document
49 bool BufferView::insertLyXFile(string const & filen)
50         //
51         // Copyright CHT Software Service GmbH
52         // Uwe C. Schroeder
53         //
54         // Insert a Lyxformat - file into current buffer
55         //
56         // Moved from lyx_cb.C (Lgb)
57 {
58         if (filen.empty()) return false;
59
60         string const fname = MakeAbsPath(filen);
61
62         // check if file exist
63         FileInfo const fi(fname);
64
65         if (!fi.readable()) {
66                 WriteAlert(_("Error!"),
67                            _("Specified file is unreadable: "),
68                            MakeDisplayPath(fname, 50));
69                 return false;
70         }
71         
72         beforeChange(text);
73
74         ifstream ifs(fname.c_str());
75         if (!ifs) {
76                 WriteAlert(_("Error!"),
77                            _("Cannot open specified file: "),
78                            MakeDisplayPath(fname, 50));
79                 return false;
80         }
81         
82         char const c = ifs.peek();
83        
84         LyXLex lex(0, 0);
85         lex.setStream(ifs);
86
87         bool res = true;
88
89         if (c == '#') {
90                 lyxerr.debug() << "Will insert file with header" << endl;
91                 res = buffer()->readFile(lex, text->cursor.par());
92         } else {
93                 lyxerr.debug() << "Will insert file without header" << endl;
94                 res = buffer()->readLyXformat2(lex, text->cursor.par());
95         }
96
97         resize();
98         return res;
99 }
100
101
102 bool BufferView::removeAutoInsets()
103 {
104         LyXParagraph * par = buffer()->paragraph;
105
106         LyXCursor tmpcursor = text->cursor;
107         LyXCursor cursor;
108
109         bool a = false;
110 #ifndef NEW_INSETS
111         while (par) {
112                 // this has to be done before the delete
113                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
114                         text->SetCursor(this, cursor, par, 0);
115                 if (par->AutoDeleteInsets()){
116                         a = true;
117                         if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
118                                 text->RedoParagraphs(this, cursor,
119                                                      cursor.par()->next());
120                                 text->FullRebreak(this);
121                         }
122                 }
123                 par = par->next_;
124         }
125
126         // avoid forbidden cursor positions caused by error removing
127         if (tmpcursor.pos() > tmpcursor.par()->Last())
128                 tmpcursor.pos(tmpcursor.par()->Last());
129 #else
130         while (par) {
131                 // this has to be done before the delete
132                 text->SetCursor(this, cursor, par, 0);
133                 if (par->AutoDeleteInsets()){
134                         a = true;
135                         text->RedoParagraphs(this, cursor,
136                                              cursor.par()->next());
137                         text->FullRebreak(this);
138                 }
139                 par = par->next();
140         }
141
142         // avoid forbidden cursor positions caused by error removing
143         if (tmpcursor.pos() > tmpcursor.par()->size())
144                 tmpcursor.pos(tmpcursor.par()->size());
145 #endif
146         text->SetCursorIntern(this, tmpcursor.par(), tmpcursor.pos());
147
148         return a;
149 }
150
151
152 void BufferView::insertErrors(TeXErrors & terr)
153 {
154         // Save the cursor position
155         LyXCursor cursor = text->cursor;
156
157 #ifndef NEW_INSETS
158         // This is drastic, but it's the only fix, I could find. (Asger)
159         allFloats(1, 0);
160         allFloats(1, 1);
161 #endif
162
163         for (TeXErrors::Errors::const_iterator cit = terr.begin();
164              cit != terr.end();
165              ++cit) {
166                 string const desctext((*cit).error_desc);
167                 string const errortext((*cit).error_text);
168                 string const msgtxt = desctext + '\n' + errortext;
169                 int const errorrow = (*cit).error_in_line;
170
171                 // Insert error string for row number
172                 int tmpid = -1; 
173                 int tmppos = -1;
174
175                 if (buffer()->texrow.getIdFromRow(errorrow, tmpid, tmppos)) {
176                         buffer()->texrow.increasePos(tmpid, tmppos);
177                 }
178                 
179                 LyXParagraph * texrowpar = 0;
180
181                 if (tmpid == -1) {
182                         texrowpar = text->FirstParagraph();
183                         tmppos = 0;
184                 } else {
185                         texrowpar = text->GetParFromID(tmpid);
186                 }
187
188                 if (texrowpar == 0)
189                         continue;
190
191                 InsetError * new_inset = new InsetError(msgtxt);
192                 text->SetCursorIntern(this, texrowpar, tmppos);
193                 text->InsertInset(this, new_inset);
194                 text->FullRebreak(this);
195         }
196         // Restore the cursor position
197         text->SetCursorIntern(this, cursor.par(), cursor.pos());
198 }
199
200
201 void BufferView::setCursorFromRow(int row)
202 {
203         int tmpid = -1; 
204         int tmppos = -1;
205
206         buffer()->texrow.getIdFromRow(row, tmpid, tmppos);
207
208         LyXParagraph * texrowpar;
209
210         if (tmpid == -1) {
211                 texrowpar = text->FirstParagraph();
212                 tmppos = 0;
213         } else {
214                 texrowpar = text->GetParFromID(tmpid);
215         }
216         text->SetCursor(this, texrowpar, tmppos);
217 }
218
219
220 bool BufferView::insertInset(Inset * inset, string const & lout,
221                              bool /*no_table*/)
222 {
223         // if we are in a locking inset we should try to insert the
224         // inset there otherwise this is a illegal function now
225         if (theLockingInset()) {
226                 if (theLockingInset()->InsertInsetAllowed(inset))
227                     return theLockingInset()->InsertInset(this, inset);
228                 return false;
229         }
230
231         // not quite sure if we want this...
232         text->SetCursorParUndo(buffer());
233         text->FreezeUndo();
234         
235         beforeChange(text);
236         if (!lout.empty()) {
237                 update(text, BufferView::SELECT|BufferView::FITCUR);
238                 text->BreakParagraph(this);
239                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
240
241 #ifndef NEW_INSETS
242                 if (text->cursor.par()->Last()) {
243 #else
244                 if (text->cursor.par()->size()) {
245 #endif
246                         text->CursorLeft(this);
247                         
248                         text->BreakParagraph(this);
249                         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
250                 }
251
252                 pair<bool, LyXTextClass::size_type> lres =
253                         textclasslist.NumberOfLayout(buffer()->params
254                                                      .textclass, lout);
255                 LyXTextClass::size_type lay;
256                 if (lres.first != false) {
257                         // layout found
258                         lay = lres.second;
259                 } else {
260                         // layout not fount using default "Standard" (0)
261                         lay = 0;
262                 }
263                  
264                 text->SetLayout(this, lay);
265                 
266                 text->SetParagraph(this, 0, 0,
267                                    0, 0,
268                                    VSpace(VSpace::NONE), VSpace(VSpace::NONE),
269                                    LYX_ALIGN_LAYOUT, 
270                                    string(),
271                                    0);
272                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
273                 
274                 text->current_font.setLatex(LyXFont::OFF);
275         }
276         
277         text->InsertInset(this, inset);
278         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
279
280         text->UnFreezeUndo();
281         return true;
282 }
283
284
285 // Open and lock an updatable inset
286 bool BufferView::open_new_inset(UpdatableInset * new_inset, bool behind)
287 {
288         beforeChange(text);
289         text->FinishUndo();
290         if (!insertInset(new_inset)) {
291                 delete new_inset;
292                 return false;
293         }
294         if (behind) {
295                 LyXFont & font = getLyXText()->real_current_font;
296                 new_inset->Edit(this, new_inset->width(this, font), 0, 0);
297         } else
298                 new_inset->Edit(this, 0, 0, 0);
299         return true;
300 }
301
302 /* This is also a buffer property (ale) */
303 // Not so sure about that. a goto Label function can not be buffer local, just
304 // think how this will work in a multiwindo/buffer environment, all the
305 // cursors in all the views showing this buffer will move. (Lgb)
306 // OK, then no cursor action should be allowed in buffer. (ale)
307 bool BufferView::gotoLabel(string const & label)
308
309 {
310         for (Buffer::inset_iterator it = buffer()->inset_iterator_begin();
311              it != buffer()->inset_iterator_end(); ++it) {
312                 vector<string> labels = (*it)->getLabelList();
313                 if (find(labels.begin(),labels.end(),label)
314                      != labels.end()) {
315                         beforeChange(text);
316                         text->SetCursor(this, it.getPar(), it.getPos());
317                         text->sel_cursor = text->cursor;
318                         update(text, BufferView::SELECT|BufferView::FITCUR);
319                         return true;
320                 }
321         }
322         return false;
323 }
324
325
326 #ifndef NEW_INSETS
327 void BufferView::allFloats(char flag, char figmar)
328 {
329         if (!available()) return;
330
331         LyXCursor cursor = text->cursor;
332
333         if (!flag
334             && cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
335             && ((figmar 
336                  && cursor.par()->footnotekind != LyXParagraph::FOOTNOTE 
337                  && cursor.par()->footnotekind != LyXParagraph::MARGIN
338                     )
339                 || (!figmar
340                     && cursor.par()->footnotekind != LyXParagraph::FIG 
341                     && cursor.par()->footnotekind != LyXParagraph::TAB
342                     && cursor.par()->footnotekind != LyXParagraph::WIDE_FIG 
343                     && cursor.par()->footnotekind != LyXParagraph::WIDE_TAB
344                     && cursor.par()->footnotekind != LyXParagraph::ALGORITHM)))
345                 toggleFloat();
346         else
347                 beforeChange(text);
348
349         LyXCursor tmpcursor = cursor;
350         cursor.par(tmpcursor.par()->ParFromPos(tmpcursor.pos()));
351         cursor.pos(tmpcursor.par()->PositionInParFromPos(tmpcursor.pos()));
352
353         LyXParagraph *par = buffer()->paragraph;
354         while (par) {
355                 if (flag) {
356                         if (par->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
357                             && ((figmar 
358                                  && par->footnotekind != LyXParagraph::FOOTNOTE 
359                                  && par->footnotekind !=  LyXParagraph::MARGIN)
360                                 || (!figmar
361                                     && par->footnotekind != LyXParagraph::FIG 
362                                     && par->footnotekind != LyXParagraph::TAB
363                                     && par->footnotekind != LyXParagraph::WIDE_FIG 
364                                     && par->footnotekind != LyXParagraph::WIDE_TAB
365                                     && par->footnotekind != LyXParagraph::ALGORITHM
366                                         )
367                                     )
368                                 ) {
369                                 if (par->previous_
370                                     && par->previous_->footnoteflag != 
371                                     LyXParagraph::CLOSED_FOOTNOTE){ /* should be */ 
372                                         text->SetCursorIntern(this, 
373                                                               par->previous_,
374                                                               0);
375                                         text->OpenFootnote(this);
376                                 }
377                         }
378                 } else {
379                         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
380                             && (
381                                     (figmar 
382                                      &&
383                                      par->footnotekind != LyXParagraph::FOOTNOTE 
384                                      &&
385                                      par->footnotekind !=  LyXParagraph::MARGIN
386                                             )
387                                     ||
388                                     (!figmar
389                                      &&
390                                      par->footnotekind != LyXParagraph::FIG 
391                                      &&
392                                      par->footnotekind != LyXParagraph::TAB
393                                      &&
394                                      par->footnotekind != LyXParagraph::WIDE_FIG 
395                                      &&
396                                      par->footnotekind != LyXParagraph::WIDE_TAB
397                                      &&
398                                      par->footnotekind != LyXParagraph::ALGORITHM
399                                             )
400                                     )
401                                 ) {
402                                 text->SetCursorIntern(this, par, 0);
403                                 text->CloseFootnote(this);
404                         }
405                 }
406                 par = par->next_;
407         }
408
409         text->SetCursorIntern(this, cursor.par(), cursor.pos());
410         redraw();
411         fitCursor(text);
412 }
413 #endif
414
415
416 void BufferView::insertNote()
417 {
418         InsetInfo * new_inset = new InsetInfo();
419         insertInset(new_inset);
420         new_inset->Edit(this, 0, 0, 0);
421 }
422
423
424 #ifndef NEW_INSETS
425 void BufferView::openStuff()
426 {
427         if (available()) {
428                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
429                                                 _("Open/Close..."));
430                 hideCursor();
431                 beforeChange(text);
432                 update(text, BufferView::SELECT|BufferView::FITCUR);
433                 text->OpenStuff(this);
434                 update(text, BufferView::SELECT|BufferView::FITCUR);
435                 setState();
436         }
437 }
438
439
440 void BufferView::toggleFloat()
441 {
442         if (available()) {
443                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
444                                                 _("Open/Close..."));
445                 hideCursor();
446                 beforeChange(text);
447                 update(text, BufferView::SELECT|BufferView::FITCUR);
448                 text->ToggleFootnote(this);
449                 update(text, BufferView::SELECT|BufferView::FITCUR);
450                 setState();
451         }
452 }
453 #endif
454
455 void BufferView::menuUndo()
456 {
457         if (available()) {
458                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("Undo"));
459                 hideCursor();
460                 beforeChange(text);
461                 update(text, BufferView::SELECT|BufferView::FITCUR);
462                 if (!text->TextUndo(this))
463                         owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
464                                                         _("No forther undo information"));
465                 else
466                         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
467                 setState();
468         }
469 }
470
471
472 void BufferView::menuRedo()
473 {
474         if (theLockingInset()) {
475                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
476                                                 _("Redo not yet supported in math mode"));
477                 return;
478         }    
479    
480         if (available()) {
481                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
482                                                 _("Redo"));
483                 hideCursor();
484                 beforeChange(text);
485                 update(text, BufferView::SELECT|BufferView::FITCUR);
486                 if (!text->TextRedo(this))
487                         owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
488                                                         _("No further redo information"));
489                 else
490                         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
491                 setState();
492         }
493 }
494
495
496 void BufferView::hyphenationPoint()
497 {
498         if (available()) {
499                 hideCursor();
500                 update(text, BufferView::SELECT|BufferView::FITCUR);
501                 InsetSpecialChar * new_inset = 
502                         new InsetSpecialChar(InsetSpecialChar::HYPHENATION);
503                 insertInset(new_inset);
504         }
505 }
506
507
508 void BufferView::ldots()
509 {
510         if (available())  {
511                 hideCursor();
512                 update(text, BufferView::SELECT|BufferView::FITCUR);
513                 InsetSpecialChar * new_inset = 
514                         new InsetSpecialChar(InsetSpecialChar::LDOTS);
515                 insertInset(new_inset);
516         }
517 }
518
519
520 void BufferView::endOfSentenceDot()
521 {
522         if (available()) {
523                 hideCursor();
524                 update(text, BufferView::SELECT|BufferView::FITCUR);
525                 InsetSpecialChar * new_inset = 
526                         new InsetSpecialChar(InsetSpecialChar::END_OF_SENTENCE);
527                 insertInset(new_inset);
528         }
529 }
530
531
532 void BufferView::menuSeparator()
533 {
534         if (available()) {
535                 hideCursor();
536                 update(text, BufferView::SELECT|BufferView::FITCUR);
537                 InsetSpecialChar * new_inset = 
538                         new InsetSpecialChar(InsetSpecialChar::MENU_SEPARATOR);
539                 insertInset(new_inset);
540         }
541 }
542
543
544 void BufferView::newline()
545 {
546         if (available()) {
547                 hideCursor();
548                 update(text, BufferView::SELECT|BufferView::FITCUR);
549                 text->InsertChar(this, LyXParagraph::META_NEWLINE);
550                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
551         }
552 }
553
554
555 void BufferView::protectedBlank(LyXText * lt)
556 {
557         if (available()) {
558                 hideCursor();
559                 update(lt, BufferView::SELECT|BufferView::FITCUR);
560                 InsetSpecialChar * new_inset =
561                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
562                 if (!insertInset(new_inset))
563                         delete new_inset;
564                 else
565                         updateInset(new_inset, true);
566         }
567 }
568
569
570 void BufferView::hfill()
571 {
572         if (available()) {
573                 hideCursor();
574                 update(text, BufferView::SELECT|BufferView::FITCUR);
575                 text->InsertChar(this, LyXParagraph::META_HFILL);
576                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
577         }
578 }
579
580
581 void BufferView::copyEnvironment()
582 {
583         if (available()) {
584                 text->copyEnvironmentType();
585                 // clear the selection, even if mark_set
586                 toggleSelection();
587                 text->ClearSelection(this);
588                 update(text, BufferView::SELECT|BufferView::FITCUR);
589                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
590                                                 _("Paragraph environment type copied"));
591         }
592 }
593
594
595 void BufferView::pasteEnvironment()
596 {
597         if (available()) {
598                 text->pasteEnvironmentType(this);
599                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
600                                                 _("Paragraph environment type set"));
601                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
602         }
603 }
604
605
606 void BufferView::copy()
607 {
608         if (available()) {
609                 text->CopySelection(this);
610                 // clear the selection, even if mark_set
611                 toggleSelection();
612                 text->ClearSelection(this);
613                 update(text, BufferView::SELECT|BufferView::FITCUR);
614                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("Copy"));
615         }
616 }
617
618 void BufferView::cut()
619 {
620         if (available()) {
621                 hideCursor();
622                 update(text, BufferView::SELECT|BufferView::FITCUR);
623                 text->CutSelection(this);
624                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
625                 owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("Cut"));
626         }
627 }
628
629
630 void BufferView::paste()
631 {
632         if (!available()) return;
633
634         owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("Paste"));
635
636         hideCursor();
637         // clear the selection
638         toggleSelection();
639         text->ClearSelection(this);
640         update(text, BufferView::SELECT|BufferView::FITCUR);
641         
642         // paste
643         text->PasteSelection(this);
644         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
645         
646         // clear the selection 
647         toggleSelection();
648         text->ClearSelection(this);
649         update(text, BufferView::SELECT|BufferView::FITCUR);
650 }
651
652
653 void BufferView::gotoInset(std::vector<Inset::Code> const & codes,
654                            bool same_content)
655 {
656         if (!available()) return;
657    
658         hideCursor();
659         beforeChange(text);
660         update(text, BufferView::SELECT|BufferView::FITCUR);
661
662         string contents;
663         if (same_content &&
664             text->cursor.par()->GetChar(text->cursor.pos()) == LyXParagraph::META_INSET) {
665                 Inset const * inset = text->cursor.par()->GetInset(text->cursor.pos());
666                 if (find(codes.begin(), codes.end(), inset->LyxCode())
667                     != codes.end())
668                         contents =
669                                 static_cast<InsetCommand const *>(inset)->getContents();
670         }
671         
672         if (!text->GotoNextInset(this, codes, contents)) {
673                 if (text->cursor.pos() 
674                     || text->cursor.par() != text->FirstParagraph()) {
675                                 LyXCursor tmp = text->cursor;
676                                 text->cursor.par(text->FirstParagraph());
677                                 text->cursor.pos(0);
678                                 if (!text->GotoNextInset(this, codes, contents)) {
679                                         text->cursor = tmp;
680                                         owner()->getLyXFunc()
681                                                 ->Dispatch(LFUN_MESSAGE,
682                                                            _("No more insets"));
683                                 }
684                         } else {
685                                 owner()->getLyXFunc()
686                                         ->Dispatch(LFUN_MESSAGE,
687                                                    _("No more insets"));
688                         }
689         }
690         update(text, BufferView::SELECT|BufferView::FITCUR);
691         text->sel_cursor = text->cursor;
692 }
693
694
695 void BufferView::gotoInset(Inset::Code code, bool same_content)
696 {
697         gotoInset(vector<Inset::Code>(1, code), same_content);
698 }
699
700
701 void BufferView::insertCorrectQuote()
702 {
703         char c;
704
705         if (text->cursor.pos())
706                 c = text->cursor.par()->GetChar(text->cursor.pos() - 1);
707         else 
708                 c = ' ';
709
710         insertInset(new InsetQuotes(c, buffer()->params));
711 }
712
713
714 /* these functions are for the spellchecker */ 
715 string const BufferView::nextWord(float & value)
716 {
717         if (!available()) {
718                 value = 1;
719                 return string();
720         }
721
722         return text->SelectNextWord(this, value);
723 }
724
725   
726 void BufferView::selectLastWord()
727 {
728         if (!available()) return;
729    
730         hideCursor();
731         beforeChange(text);
732         text->SelectSelectedWord(this);
733         toggleSelection(false);
734         update(text, BufferView::SELECT|BufferView::FITCUR);
735 }
736
737
738 void BufferView::endOfSpellCheck()
739 {
740         if (!available()) return;
741    
742         hideCursor();
743         beforeChange(text);
744         text->SelectSelectedWord(this);
745         text->ClearSelection(this);
746         update(text, BufferView::SELECT|BufferView::FITCUR);
747 }
748
749
750 void BufferView::replaceWord(string const & replacestring)
751 {
752         if (!available()) return;
753
754         hideCursor();
755         update(text, BufferView::SELECT|BufferView::FITCUR);
756    
757         /* clear the selection (if there is any) */ 
758         toggleSelection(false);
759         update(text, BufferView::SELECT|BufferView::FITCUR);
760    
761         /* clear the selection (if there is any) */ 
762         toggleSelection(false);
763         text->ReplaceSelectionWithString(this, replacestring);
764    
765         text->SetSelectionOverString(this, replacestring);
766
767         // Go back so that replacement string is also spellchecked
768         for (string::size_type i = 0; i < replacestring.length() + 1; ++i) {
769                 text->CursorLeft(this);
770         }
771         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
772 }
773 // End of spellchecker stuff
774
775
776 bool BufferView::lockInset(UpdatableInset * inset)
777 {
778         if (!theLockingInset() && inset) {
779                 theLockingInset(inset);
780                 return true;
781         } else if (inset) {
782             return theLockingInset()->LockInsetInInset(this, inset);
783         }
784         return false;
785 }
786
787
788 void BufferView::showLockedInsetCursor(int x, int y, int asc, int desc)
789 {
790         if (theLockingInset() && available()) {
791                 LyXCursor cursor = text->cursor;
792                 if ((cursor.pos() - 1 >= 0) &&
793                     (cursor.par()->GetChar(cursor.pos() - 1) ==
794                      LyXParagraph::META_INSET) &&
795                     (cursor.par()->GetInset(cursor.pos() - 1) ==
796                      theLockingInset()->GetLockingInset()))
797                         text->SetCursor(this, cursor,
798                                         cursor.par(), cursor.pos() - 1);
799                 LyXScreen::Cursor_Shape shape = LyXScreen::BAR_SHAPE;
800                 LyXText * txt = getLyXText();
801                 if (theLockingInset()->GetLockingInset()->LyxCode() ==
802                     Inset::TEXT_CODE &&
803                     (txt->real_current_font.language() !=
804                      buffer()->params.language
805                      || txt->real_current_font.isVisibleRightToLeft()
806                      != buffer()->params.language->RightToLeft()))
807                         shape = (txt->real_current_font.isVisibleRightToLeft())
808                                 ? LyXScreen::REVERSED_L_SHAPE
809                                 : LyXScreen::L_SHAPE;
810                 y += cursor.y() + theLockingInset()->InsetInInsetY();
811                 pimpl_->screen_->ShowManualCursor(text, x, y, asc, desc,
812                                                   shape);
813         }
814 }
815
816
817 void BufferView::hideLockedInsetCursor()
818 {
819         if (theLockingInset() && available()) {
820                 pimpl_->screen_->HideCursor();
821         }
822 }
823
824
825 void BufferView::fitLockedInsetCursor(int x, int y, int asc, int desc)
826 {
827         if (theLockingInset() && available()) {
828                 y += text->cursor.y() + theLockingInset()->InsetInInsetY();
829                 if (pimpl_->screen_->FitManualCursor(text, this, x, y, asc, desc))
830                         updateScrollbar();
831         }
832 }
833
834
835 int BufferView::unlockInset(UpdatableInset * inset)
836 {
837         if (inset && theLockingInset() == inset) {
838                 inset->InsetUnlock(this);
839                 theLockingInset(0);
840                 text->FinishUndo();
841                 return 0;
842         } else if (inset && theLockingInset() &&
843                    theLockingInset()->UnlockInsetInInset(this, inset)) {
844                 text->FinishUndo();
845                 return 0;
846         }
847         return bufferlist.unlockInset(inset);
848 }
849
850
851 void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind)
852 {
853         if (!theLockingInset())
854                 return; // shouldn't happen
855         if (kind == Undo::EDIT) // in this case insets would not be stored!
856                 kind = Undo::FINISH;
857 #ifndef NEW_INSETS
858         text->SetUndo(buffer(), kind,
859                       text->cursor.par()->
860                       ParFromPos(text->cursor.pos())->previous_, 
861                       text->cursor.par()->
862                       ParFromPos(text->cursor.pos())->next_);
863 #else
864         text->SetUndo(buffer(), kind,
865                       text->cursor.par()->previous(), 
866                       text->cursor.par()->next());
867 #endif
868 }
869
870
871 void BufferView::updateInset(Inset * inset, bool mark_dirty)
872 {
873         if (!inset)
874                 return;
875
876         // first check for locking insets
877         if (theLockingInset()) {
878                 if (theLockingInset() == inset) {
879                         if (text->UpdateInset(this, inset)) {
880                                 update();
881                                 if (mark_dirty) {
882                                         buffer()->markDirty();
883                                 }
884                                 updateScrollbar();
885                                 return;
886                         }
887                 } else if (theLockingInset()->UpdateInsetInInset(this,inset)) {
888                         if (text->UpdateInset(this, theLockingInset())) {
889                                 update();
890                                 if (mark_dirty){
891                                         buffer()->markDirty();
892                                 }
893                                 updateScrollbar();
894                                 return;
895                         }
896                 }
897         }
898   
899         // then check the current buffer
900         if (available()) {
901                 hideCursor();
902                 update(text, BufferView::UPDATE);
903                 if (text->UpdateInset(this, inset)) {
904                         if (mark_dirty)
905                                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
906                         else 
907                                 update(text, SELECT);
908                         return;
909                 }
910         }
911 }
912
913
914 bool BufferView::ChangeInsets(Inset::Code code,
915                               string const & from, string const & to)
916 {
917         bool flag = false;
918         LyXParagraph * par = buffer()->paragraph;
919         LyXCursor cursor = text->cursor;
920         LyXCursor tmpcursor = cursor;
921 #ifndef NEW_INSETS
922         cursor.par(tmpcursor.par()->ParFromPos(tmpcursor.pos()));
923         cursor.pos(tmpcursor.par()->PositionInParFromPos(tmpcursor.pos()));
924 #else
925         cursor.par(tmpcursor.par());
926         cursor.pos(tmpcursor.pos());
927 #endif
928
929         while (par) {
930                 bool flag2 = false;
931                 for (LyXParagraph::inset_iterator it = par->inset_iterator_begin();
932                      it != par->inset_iterator_end(); ++it) {
933                         if ((*it)->LyxCode() == code) {
934                                 InsetCommand * inset = static_cast<InsetCommand *>(*it);
935                                 if (inset->getContents() == from) {
936                                         inset->setContents(to);
937                                         flag2 = true;
938                                 }
939                         }
940                 }
941 #ifndef NEW_INSETS
942                 if (flag2) {
943                         flag = true;
944                         if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
945                                 // this is possible now, since SetCursor takes
946                                 // care about footnotes
947                                 text->SetCursorIntern(this, par, 0);
948                                 text->RedoParagraphs(this, text->cursor,
949                                                      text->cursor.par()->next());
950                                 text->FullRebreak(this);
951                         }
952                 }
953                 par = par->next_;
954 #else
955                 if (flag2) {
956                         flag = true;
957                         // this is possible now, since SetCursor takes
958                         // care about footnotes
959                         text->SetCursorIntern(this, par, 0);
960                         text->RedoParagraphs(this, text->cursor,
961                                              text->cursor.par()->next());
962                         text->FullRebreak(this);
963                 }
964                 par = par->next();
965 #endif
966         }
967         text->SetCursorIntern(this, cursor.par(), cursor.pos());
968         return flag;
969 }
970
971
972 bool BufferView::ChangeRefsIfUnique(string const & from, string const & to)
973 {
974         // Check if the label 'from' appears more than once
975         vector<string> labels = buffer()->getLabelList();
976         if (count(labels.begin(), labels.end(), from) > 1)
977                 return false;
978
979         return ChangeInsets(Inset::REF_CODE, from, to);
980 }
981
982
983 bool BufferView::ChangeCitationsIfUnique(string const & from, string const & to)
984 {
985
986         vector<pair<string,string> > keys = buffer()->getBibkeyList();  
987         if (count_if(keys.begin(), keys.end(), 
988                      equal_1st_in_pair<string,string>(from)) 
989             > 1)
990                 return false;
991
992         return ChangeInsets(Inset::CITE_CODE, from, to);
993 }
994
995 UpdatableInset * BufferView::theLockingInset() const
996 {
997         // If NULL is not allowed we should put an Assert here. (Lgb)
998         if (text)
999                 return text->the_locking_inset;
1000         return 0;
1001 }
1002
1003
1004 void BufferView::theLockingInset(UpdatableInset * inset)
1005 {
1006     text->the_locking_inset = inset;
1007 }
1008
1009
1010 LyXText * BufferView::getLyXText() const
1011 {
1012         if (theLockingInset()) {
1013                 LyXText * txt = theLockingInset()->getLyXText(this, true);
1014                 if (txt)
1015                         return txt;
1016         }
1017         return text;
1018 }
1019
1020
1021 LyXText * BufferView::getParentText(Inset * inset) const
1022 {
1023         if (inset->owner()) {
1024                 LyXText * txt = inset->getLyXText(this);
1025                 inset = inset->owner();
1026                 while (inset && inset->getLyXText(this) == txt)
1027                         inset = inset->owner();
1028                 if (inset)
1029                         return inset->getLyXText(this);
1030         }
1031         return text;
1032 }
1033
1034
1035 Language const * BufferView::getParentLanguage(Inset * inset) const
1036 {
1037         LyXText * text = getParentText(inset);
1038         return text->cursor.par()->GetFontSettings(buffer()->params,
1039                                                    text->cursor.pos()).language();
1040 }