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