]> git.lyx.org Git - lyx.git/blob - src/BufferView2.C
705885486557c3cecc6375bda449f10346d86e5b
[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(text, BufferView::SELECT|BufferView::FITCUR);
223                 text->BreakParagraph(this);
224                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
225                 
226                 if (text->cursor.par()->Last()) {
227                         text->CursorLeft(this);
228                         
229                         text->BreakParagraph(this);
230                         update(text, 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(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
254                 
255                 text->current_font.setLatex(LyXFont::OFF);
256         }
257         
258         text->InsertInset(this, inset);
259         update(text, 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(text, 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(text, BufferView::SELECT|BufferView::FITCUR);
413                 text->OpenStuff(this);
414                 update(text, 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(text, BufferView::SELECT|BufferView::FITCUR);
427                 text->ToggleFootnote(this);
428                 update(text, 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(text, BufferView::SELECT|BufferView::FITCUR);
441                 if (!text->TextUndo(this))
442                         owner()->getMiniBuffer()->Set(_("No further undo information"));
443                 else
444                         update(text, 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(text, BufferView::SELECT|BufferView::FITCUR);
462                 if (!text->TextRedo(this))
463                         owner()->getMiniBuffer()->Set(_("No further redo information"));
464                 else
465                         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
466                 setState();
467         }
468 }
469
470
471 void BufferView::hyphenationPoint()
472 {
473         if (available()) {
474                 hideCursor();
475                 update(text, 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(text, 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(text, 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(text, 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(text, BufferView::SELECT|BufferView::FITCUR);
524                 text->InsertChar(this, LyXParagraph::META_NEWLINE);
525                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
526         }
527 }
528
529
530 void BufferView::protectedBlank(LyXText * lt)
531 {
532         if (available()) {
533                 hideCursor();
534                 update(lt, BufferView::SELECT|BufferView::FITCUR);
535                 InsetSpecialChar * new_inset =
536                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
537                 if (!insertInset(new_inset))
538                         delete new_inset;
539                 else
540                         updateInset(new_inset, true);
541         }
542 }
543
544
545 void BufferView::hfill()
546 {
547         if (available()) {
548                 hideCursor();
549                 update(text, BufferView::SELECT|BufferView::FITCUR);
550                 text->InsertChar(this, LyXParagraph::META_HFILL);
551                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
552         }
553 }
554
555 void BufferView::copyEnvironment()
556 {
557         if (available()) {
558                 text->copyEnvironmentType();
559                 // clear the selection, even if mark_set
560                 toggleSelection();
561                 text->ClearSelection();
562                 update(text, BufferView::SELECT|BufferView::FITCUR);
563                 owner()->getMiniBuffer()->Set(_("Paragraph environment type copied"));
564         }
565 }
566
567
568 void BufferView::pasteEnvironment()
569 {
570         if (available()) {
571                 text->pasteEnvironmentType(this);
572                 owner()->getMiniBuffer()->Set(_("Paragraph environment type set"));
573                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
574         }
575 }
576
577
578 void BufferView::copy()
579 {
580         if (available()) {
581                 text->CopySelection(this);
582                 // clear the selection, even if mark_set
583                 toggleSelection();
584                 text->ClearSelection();
585                 update(text, BufferView::SELECT|BufferView::FITCUR);
586                 owner()->getMiniBuffer()->Set(_("Copy"));
587         }
588 }
589
590 void BufferView::cut()
591 {
592         if (available()) {
593                 hideCursor();
594                 update(text, BufferView::SELECT|BufferView::FITCUR);
595                 text->CutSelection(this);
596                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
597                 owner()->getMiniBuffer()->Set(_("Cut"));
598         }
599 }
600
601
602 void BufferView::paste()
603 {
604         if (!available()) return;
605         
606         owner()->getMiniBuffer()->Set(_("Paste"));
607         hideCursor();
608         // clear the selection
609         toggleSelection();
610         text->ClearSelection();
611         update(text, BufferView::SELECT|BufferView::FITCUR);
612         
613         // paste
614         text->PasteSelection(this);
615         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
616         
617         // clear the selection 
618         toggleSelection();
619         text->ClearSelection();
620         update(text, BufferView::SELECT|BufferView::FITCUR);
621 }
622
623
624 void BufferView::gotoInset(std::vector<Inset::Code> const & codes,
625                            bool same_content)
626 {
627         if (!available()) return;
628    
629         hideCursor();
630         beforeChange();
631         update(text, BufferView::SELECT|BufferView::FITCUR);
632
633         string contents;
634         if (same_content &&
635             text->cursor.par()->GetChar(text->cursor.pos()) == LyXParagraph::META_INSET) {
636                 Inset const * inset = text->cursor.par()->GetInset(text->cursor.pos());
637                 if (find(codes.begin(), codes.end(), inset->LyxCode())
638                     != codes.end())
639                         contents =
640                                 static_cast<InsetCommand const *>(inset)->getContents();
641         }
642         
643         if (!text->GotoNextInset(this, codes, contents)) {
644                 if (text->cursor.pos() 
645                     || text->cursor.par() != text->FirstParagraph()) {
646                                 LyXCursor tmp = text->cursor;
647                                 text->cursor.par(text->FirstParagraph());
648                                 text->cursor.pos(0);
649                                 if (!text->GotoNextInset(this, codes, contents)) {
650                                         text->cursor = tmp;
651                                         owner()->getMiniBuffer()->Set(_("No more insets"));
652                                 }
653                         } else {
654                                 owner()->getMiniBuffer()->Set(_("No more insets"));
655                         }
656         }
657         update(text, BufferView::SELECT|BufferView::FITCUR);
658         text->sel_cursor = text->cursor;
659 }
660
661
662 void BufferView::gotoInset(Inset::Code code, bool same_content)
663 {
664         gotoInset(vector<Inset::Code>(1, code), same_content);
665 }
666
667
668 void BufferView::insertCorrectQuote()
669 {
670         char c;
671
672         if (text->cursor.pos())
673                 c = text->cursor.par()->GetChar(text->cursor.pos() - 1);
674         else 
675                 c = ' ';
676
677         insertInset(new InsetQuotes(c, buffer()->params));
678 }
679
680
681 /* these functions are for the spellchecker */ 
682 string const BufferView::nextWord(float & value)
683 {
684         if (!available()) {
685                 value = 1;
686                 return string();
687         }
688
689         return text->SelectNextWord(this, value);
690 }
691
692   
693 void BufferView::selectLastWord()
694 {
695         if (!available()) return;
696    
697         hideCursor();
698         beforeChange();
699         text->SelectSelectedWord(this);
700         toggleSelection(false);
701         update(text, BufferView::SELECT|BufferView::FITCUR);
702 }
703
704
705 void BufferView::endOfSpellCheck()
706 {
707         if (!available()) return;
708    
709         hideCursor();
710         beforeChange();
711         text->SelectSelectedWord(this);
712         text->ClearSelection();
713         update(text, BufferView::SELECT|BufferView::FITCUR);
714 }
715
716
717 void BufferView::replaceWord(string const & replacestring)
718 {
719         if (!available()) return;
720
721         hideCursor();
722         update(text, BufferView::SELECT|BufferView::FITCUR);
723    
724         /* clear the selection (if there is any) */ 
725         toggleSelection(false);
726         update(text, BufferView::SELECT|BufferView::FITCUR);
727    
728         /* clear the selection (if there is any) */ 
729         toggleSelection(false);
730         text->ReplaceSelectionWithString(this, replacestring);
731    
732         text->SetSelectionOverString(this, replacestring);
733
734         // Go back so that replacement string is also spellchecked
735         for (string::size_type i = 0; i < replacestring.length() + 1; ++i) {
736                 text->CursorLeft(this);
737         }
738         update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
739 }
740 // End of spellchecker stuff
741
742
743 bool BufferView::lockInset(UpdatableInset * inset)
744 {
745         if (!theLockingInset() && inset) {
746                 theLockingInset(inset);
747                 return true;
748         } else if (inset) {
749             return theLockingInset()->LockInsetInInset(this, inset);
750         }
751         return false;
752 }
753
754
755 void BufferView::showLockedInsetCursor(int x, int y, int asc, int desc)
756 {
757         if (theLockingInset() && available()) {
758                 LyXCursor cursor = text->cursor;
759                 if ((cursor.pos() - 1 >= 0) &&
760                     (cursor.par()->GetChar(cursor.pos() - 1) ==
761                      LyXParagraph::META_INSET) &&
762                     (cursor.par()->GetInset(cursor.pos() - 1) ==
763                      theLockingInset()->GetLockingInset()))
764                         text->SetCursor(this, cursor,
765                                         cursor.par(), cursor.pos() - 1);
766                 LyXScreen::Cursor_Shape shape = LyXScreen::BAR_SHAPE;
767                 LyXText * txt = getLyXText();
768                 if (theLockingInset()->GetLockingInset()->LyxCode() ==
769                     Inset::TEXT_CODE &&
770                     (txt->real_current_font.language() !=
771                      buffer()->params.language
772                      || txt->real_current_font.isVisibleRightToLeft()
773                      != buffer()->params.language->RightToLeft()))
774                         shape = (txt->real_current_font.isVisibleRightToLeft())
775                                 ? LyXScreen::REVERSED_L_SHAPE
776                                 : LyXScreen::L_SHAPE;
777                 y += cursor.y() + theLockingInset()->InsetInInsetY();
778                 pimpl_->screen_->ShowManualCursor(text, x, y, asc, desc,
779                                                   shape);
780         }
781 }
782
783
784 void BufferView::hideLockedInsetCursor()
785 {
786         if (theLockingInset() && available()) {
787                 pimpl_->screen_->HideCursor();
788         }
789 }
790
791
792 void BufferView::fitLockedInsetCursor(int x, int y, int asc, int desc)
793 {
794         if (theLockingInset() && available()) {
795                 y += text->cursor.y() + theLockingInset()->InsetInInsetY();
796                 if (pimpl_->screen_->FitManualCursor(text, this, x, y, asc, desc))
797                         updateScrollbar();
798         }
799 }
800
801
802 int BufferView::unlockInset(UpdatableInset * inset)
803 {
804         if (inset && theLockingInset() == inset) {
805                 inset->InsetUnlock(this);
806                 theLockingInset(0);
807                 text->FinishUndo();
808                 return 0;
809         } else if (inset && theLockingInset() &&
810                    theLockingInset()->UnlockInsetInInset(this, inset)) {
811                 text->FinishUndo();
812                 return 0;
813         }
814         return bufferlist.unlockInset(inset);
815 }
816
817
818 void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind)
819 {
820         if (!theLockingInset())
821                 return; // shouldn't happen
822         if (kind == Undo::EDIT) // in this case insets would not be stored!
823                 kind = Undo::FINISH;
824         text->SetUndo(buffer(), kind,
825 #ifndef NEW_INSETS
826                       text->cursor.par()->
827                       ParFromPos(text->cursor.pos())->previous, 
828                       text->cursor.par()->
829                       ParFromPos(text->cursor.pos())->next
830 #else
831                       text->cursor.par()->previous, 
832                       text->cursor.par()->next
833 #endif
834                 );
835 }
836
837
838 void BufferView::updateInset(Inset * inset, bool mark_dirty)
839 {
840         if (!inset)
841                 return;
842
843         // first check for locking insets
844         if (theLockingInset()) {
845                 if (theLockingInset() == inset) {
846                         if (text->UpdateInset(this, inset)) {
847                                 update();
848                                 if (mark_dirty) {
849                                         if (buffer()->isLyxClean())
850                                                 owner()->getMiniBuffer()->
851                                                         setTimer(4);
852                                         buffer()->markDirty();
853                                 }
854                                 updateScrollbar();
855                                 return;
856                         }
857                 } else if (theLockingInset()->UpdateInsetInInset(this,inset)) {
858                         if (text->UpdateInset(this, theLockingInset())) {
859                                 update();
860                                 if (mark_dirty){
861                                         if (buffer()->isLyxClean())
862                                                 owner()->getMiniBuffer()->
863                                                         setTimer(4);
864                                         buffer()->markDirty();
865                                 }
866                                 updateScrollbar();
867                                 return;
868                         }
869                 }
870         }
871   
872         // then check the current buffer
873         if (available()) {
874                 hideCursor();
875                 update(text, BufferView::UPDATE);
876                 if (text->UpdateInset(this, inset)) {
877                         if (mark_dirty)
878                                 update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
879                         else 
880                                 update(text, SELECT);
881                         return;
882                 }
883         }
884 }
885
886
887 bool BufferView::ChangeInsets(Inset::Code code, string const & from, string const & to)
888 {
889         bool flag = false;
890         LyXParagraph * par = buffer()->paragraph;
891         LyXCursor cursor = text->cursor;
892         LyXCursor tmpcursor = cursor;
893 #ifndef NEW_INSETS
894         cursor.par(tmpcursor.par()->ParFromPos(tmpcursor.pos()));
895         cursor.pos(tmpcursor.par()->PositionInParFromPos(tmpcursor.pos()));
896 #else
897         cursor.par(tmpcursor.par());
898         cursor.pos(tmpcursor.pos());
899 #endif
900
901         while (par) {
902                 bool flag2 = false;
903                 for (LyXParagraph::inset_iterator it = par->inset_iterator_begin();
904                      it != par->inset_iterator_end(); ++it) {
905                         if ((*it)->LyxCode() == code) {
906                                 InsetCommand * inset = static_cast<InsetCommand *>(*it);
907                                 if (inset->getContents() == from) {
908                                         inset->setContents(to);
909                                         flag2 = true;
910                                 }
911                         }
912                 }
913                 if (flag2) {
914                         flag = true;
915 #ifndef NEW_INSETS
916                         if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
917 #endif
918                                 // this is possible now, since SetCursor takes
919                                 // care about footnotes
920                                 text->SetCursorIntern(this, par, 0);
921                                 text->RedoParagraphs(this, text->cursor,
922                                                      text->cursor.par()->Next());
923                                 text->FullRebreak(this);
924 #ifndef NEW_INSETS
925                         }
926 #endif
927                 }
928                 par = par->next;
929         }
930         text->SetCursorIntern(this, cursor.par(), cursor.pos());
931         return flag;
932 }
933
934
935 bool BufferView::ChangeRefsIfUnique(string const & from, string const & to)
936 {
937         // Check if the label 'from' appears more than once
938         vector<string> labels = buffer()->getLabelList();
939         if (count(labels.begin(), labels.end(), from) > 1)
940                 return false;
941
942         return ChangeInsets(Inset::REF_CODE, from, to);
943 }
944
945
946 bool BufferView::ChangeCitationsIfUnique(string const & from, string const & to)
947 {
948
949         vector<pair<string,string> > keys = buffer()->getBibkeyList();  
950         if (count_if(keys.begin(), keys.end(), 
951                      equal_1st_in_pair<string,string>(from)) 
952             > 1)
953                 return false;
954
955         return ChangeInsets(Inset::CITE_CODE, from, to);
956 }
957
958 UpdatableInset * BufferView::theLockingInset() const
959 {
960         // If NULL is not allowed we should put an Assert here. (Lgb)
961         if (text)
962                 return text->the_locking_inset;
963         return 0;
964 }
965
966
967 void BufferView::theLockingInset(UpdatableInset * inset)
968 {
969     text->the_locking_inset = inset;
970 }
971
972
973 LyXText * BufferView::getLyXText() const
974 {
975         if (theLockingInset()) {
976                 LyXText * txt = theLockingInset()->getLyXText(this);
977                 if (txt)
978                         return txt;
979         }
980         return text;
981 }
982
983
984 LyXText * BufferView::getParentText(Inset * inset) const
985 {
986         if (inset->owner()) {
987                 LyXText * txt = inset->getLyXText(this);
988                 inset = inset->owner();
989                 while (inset && inset->getLyXText(this) == txt)
990                         inset = inset->owner();
991                 if (inset)
992                         return inset->getLyXText(this);
993         }
994         return text;
995 }
996
997 Language const * BufferView::getParentLanguage(Inset * inset) const
998 {
999         LyXText * text = getParentText(inset);
1000         return text->cursor.par()->GetFontSettings(buffer()->params,
1001                                                    text->cursor.pos()).language();
1002 }