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