]> git.lyx.org Git - lyx.git/blob - src/BufferView2.C
734d7c1fbd911b1ec1dc030b55a3184a49f3f389
[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
35 extern BufferList bufferlist;
36
37 using std::pair;
38 using std::endl;
39 using std::ifstream;
40 using std::vector;
41 using std::find;
42 using std::count;
43
44 // Inserts a file into current document
45 bool BufferView::insertLyXFile(string const & filen)
46         //
47         // Copyright CHT Software Service GmbH
48         // Uwe C. Schroeder
49         //
50         // Insert a Lyxformat - file into current buffer
51         //
52         // Moved from lyx_cb.C (Lgb)
53 {
54         if (filen.empty()) return false;
55
56         string const fname = MakeAbsPath(filen);
57
58         // check if file exist
59         FileInfo const fi(fname);
60
61         if (!fi.readable()) {
62                 WriteAlert(_("Error!"),
63                            _("Specified file is unreadable: "),
64                            MakeDisplayPath(fname, 50));
65                 return false;
66         }
67         
68         beforeChange();
69
70         ifstream ifs(fname.c_str());
71         if (!ifs) {
72                 WriteAlert(_("Error!"),
73                            _("Cannot open specified file: "),
74                            MakeDisplayPath(fname, 50));
75                 return false;
76         }
77         
78         char const c = ifs.peek();
79        
80         LyXLex lex(0, 0);
81         lex.setStream(ifs);
82
83         bool res = true;
84
85         if (c == '#') {
86                 lyxerr.debug() << "Will insert file with header" << endl;
87                 res = buffer()->readFile(lex, text->cursor.par());
88         } else {
89                 lyxerr.debug() << "Will insert file without header" << endl;
90                 res = buffer()->readLyXformat2(lex, text->cursor.par());
91         }
92
93         resize();
94         return res;
95 }
96
97
98 bool BufferView::removeAutoInsets()
99 {
100         LyXParagraph * par = buffer()->paragraph;
101
102         LyXCursor tmpcursor = text->cursor;
103         LyXCursor cursor;
104
105         bool a = false;
106         while (par) {
107                 // this has to be done before the delete
108 #ifndef NEW_INSETS
109                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
110 #endif
111                         text->SetCursor(this, cursor, par, 0);
112                 if (par->AutoDeleteInsets()){
113                         a = true;
114 #ifndef NEW_INSETS
115                         if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
116 #endif
117                                 text->RedoParagraphs(this, cursor,
118                                                      cursor.par()->Next());
119                                 text->FullRebreak(this);
120 #ifndef NEW_INSETS
121                         }
122 #endif
123                 }
124                 par = par->next;
125         }
126         // avoid forbidden cursor positions caused by error removing
127         if (tmpcursor.pos() > tmpcursor.par()->Last())
128                 tmpcursor.pos(tmpcursor.par()->Last());
129         text->SetCursorIntern(this, tmpcursor.par(), tmpcursor.pos());
130
131         return a;
132 }
133
134
135 void BufferView::insertErrors(TeXErrors & terr)
136 {
137         // Save the cursor position
138         LyXCursor cursor = text->cursor;
139
140 #ifndef NEW_INSETS
141         // This is drastic, but it's the only fix, I could find. (Asger)
142         allFloats(1, 0);
143         allFloats(1, 1);
144 #endif
145
146         for (TeXErrors::Errors::const_iterator cit = terr.begin();
147              cit != terr.end();
148              ++cit) {
149                 string const desctext((*cit).error_desc);
150                 string const errortext((*cit).error_text);
151                 string const msgtxt = desctext + '\n' + errortext;
152                 int const errorrow = (*cit).error_in_line;
153
154                 // Insert error string for row number
155                 int tmpid = -1; 
156                 int tmppos = -1;
157
158                 if (buffer()->texrow.getIdFromRow(errorrow, tmpid, tmppos)) {
159                         buffer()->texrow.increasePos(tmpid, tmppos);
160                 }
161                 
162                 LyXParagraph * texrowpar = 0;
163
164                 if (tmpid == -1) {
165                         texrowpar = text->FirstParagraph();
166                         tmppos = 0;
167                 } else {
168                         texrowpar = text->GetParFromID(tmpid);
169                 }
170
171                 if (texrowpar == 0)
172                         continue;
173
174                 InsetError * new_inset = new InsetError(msgtxt);
175                 text->SetCursorIntern(this, texrowpar, tmppos);
176                 text->InsertInset(this, new_inset);
177                 text->FullRebreak(this);
178         }
179         // Restore the cursor position
180         text->SetCursorIntern(this, cursor.par(), cursor.pos());
181 }
182
183
184 void BufferView::setCursorFromRow(int row)
185 {
186         int tmpid = -1; 
187         int tmppos = -1;
188
189         buffer()->texrow.getIdFromRow(row, tmpid, tmppos);
190
191         LyXParagraph * texrowpar;
192
193         if (tmpid == -1) {
194                 texrowpar = text->FirstParagraph();
195                 tmppos = 0;
196         } else {
197                 texrowpar = text->GetParFromID(tmpid);
198         }
199         text->SetCursor(this, texrowpar, tmppos);
200 }
201
202
203 bool BufferView::insertInset(Inset * inset, string const & lout,
204                              bool /*no_table*/)
205 {
206         // if we are in a locking inset we should try to insert the
207         // inset there otherwise this is a illegal function now
208         if (theLockingInset()) {
209                 if (theLockingInset()->InsertInsetAllowed(inset))
210                     return theLockingInset()->InsertInset(this, inset);
211                 return false;
212         }
213
214         // not quite sure if we want this...
215         text->SetCursorParUndo(buffer());
216         text->FreezeUndo();
217         
218         beforeChange();
219         if (!lout.empty()) {
220                 update(BufferView::SELECT|BufferView::FITCUR);
221                 text->BreakParagraph(this);
222                 update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
223                 
224                 if (text->cursor.par()->Last()) {
225                         text->CursorLeft(this);
226                         
227                         text->BreakParagraph(this);
228                         update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
229                 }
230
231                 pair<bool, LyXTextClass::size_type> lres =
232                         textclasslist.NumberOfLayout(buffer()->params
233                                                      .textclass, lout);
234                 LyXTextClass::size_type lay;
235                 if (lres.first != false) {
236                         // layout found
237                         lay = lres.second;
238                 } else {
239                         // layout not fount using default "Standard" (0)
240                         lay = 0;
241                 }
242                  
243                 text->SetLayout(this, lay);
244                 
245                 text->SetParagraph(this, 0, 0,
246                                    0, 0,
247                                    VSpace(VSpace::NONE), VSpace(VSpace::NONE),
248                                    LYX_ALIGN_LAYOUT, 
249                                    string(),
250                                    0);
251                 update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
252                 
253                 text->current_font.setLatex(LyXFont::OFF);
254         }
255         
256         text->InsertInset(this, inset);
257         update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
258
259         text->UnFreezeUndo();
260         return true;
261 }
262
263
264 // Open and lock an updatable inset
265 bool BufferView::open_new_inset(UpdatableInset * new_inset, bool behind)
266 {
267         beforeChange();
268         text->FinishUndo();
269         if (!insertInset(new_inset)) {
270                 delete new_inset;
271                 return false;
272         }
273         if (behind) {
274                 LyXFont & font = getLyXText()->real_current_font;
275                 new_inset->Edit(this, new_inset->width(this, font), 0, 0);
276         } else
277                 new_inset->Edit(this, 0, 0, 0);
278         return true;
279 }
280
281 /* This is also a buffer property (ale) */
282 // Not so sure about that. a goto Label function can not be buffer local, just
283 // think how this will work in a multiwindo/buffer environment, all the
284 // cursors in all the views showing this buffer will move. (Lgb)
285 // OK, then no cursor action should be allowed in buffer. (ale)
286 bool BufferView::gotoLabel(string const & label)
287
288 {
289         for (Buffer::inset_iterator it = buffer()->inset_iterator_begin();
290              it != buffer()->inset_iterator_end(); ++it) {
291                 vector<string> labels = (*it)->getLabelList();
292                 if (find(labels.begin(),labels.end(),label)
293                      != labels.end()) {
294                         beforeChange();
295                         text->SetCursor(this, it.getPar(), it.getPos());
296                         text->sel_cursor = text->cursor;
297                         update(BufferView::SELECT|BufferView::FITCUR);
298                         return true;
299                 }
300         }
301         return false;
302 }
303
304
305 #ifndef NEW_INSETS
306 void BufferView::allFloats(char flag, char figmar)
307 {
308         if (!available()) return;
309
310         LyXCursor cursor = text->cursor;
311
312         if (!flag
313             && cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
314             && ((figmar 
315                  && cursor.par()->footnotekind != LyXParagraph::FOOTNOTE 
316                  && cursor.par()->footnotekind != LyXParagraph::MARGIN
317                     )
318                 || (!figmar
319                     && cursor.par()->footnotekind != LyXParagraph::FIG 
320                     && cursor.par()->footnotekind != LyXParagraph::TAB
321                     && cursor.par()->footnotekind != LyXParagraph::WIDE_FIG 
322                     && cursor.par()->footnotekind != LyXParagraph::WIDE_TAB
323                     && cursor.par()->footnotekind != LyXParagraph::ALGORITHM)))
324                 toggleFloat();
325         else
326                 beforeChange();
327
328         LyXCursor tmpcursor = cursor;
329         cursor.par(tmpcursor.par()->ParFromPos(tmpcursor.pos()));
330         cursor.pos(tmpcursor.par()->PositionInParFromPos(tmpcursor.pos()));
331
332         LyXParagraph *par = buffer()->paragraph;
333         while (par) {
334                 if (flag) {
335                         if (par->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
336                             && ((figmar 
337                                  && par->footnotekind != LyXParagraph::FOOTNOTE 
338                                  && par->footnotekind !=  LyXParagraph::MARGIN)
339                                 || (!figmar
340                                     && par->footnotekind != LyXParagraph::FIG 
341                                     && par->footnotekind != LyXParagraph::TAB
342                                     && par->footnotekind != LyXParagraph::WIDE_FIG 
343                                     && par->footnotekind != LyXParagraph::WIDE_TAB
344                                     && par->footnotekind != LyXParagraph::ALGORITHM
345                                         )
346                                     )
347                                 ) {
348                                 if (par->previous
349                                     && par->previous->footnoteflag != 
350                                     LyXParagraph::CLOSED_FOOTNOTE){ /* should be */ 
351                                         text->SetCursorIntern(this, 
352                                                               par->previous,
353                                                               0);
354                                         text->OpenFootnote(this);
355                                 }
356                         }
357                 } else {
358                         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
359                             && (
360                                     (figmar 
361                                      &&
362                                      par->footnotekind != LyXParagraph::FOOTNOTE 
363                                      &&
364                                      par->footnotekind !=  LyXParagraph::MARGIN
365                                             )
366                                     ||
367                                     (!figmar
368                                      &&
369                                      par->footnotekind != LyXParagraph::FIG 
370                                      &&
371                                      par->footnotekind != LyXParagraph::TAB
372                                      &&
373                                      par->footnotekind != LyXParagraph::WIDE_FIG 
374                                      &&
375                                      par->footnotekind != LyXParagraph::WIDE_TAB
376                                      &&
377                                      par->footnotekind != LyXParagraph::ALGORITHM
378                                             )
379                                     )
380                                 ) {
381                                 text->SetCursorIntern(this, par, 0);
382                                 text->CloseFootnote(this);
383                         }
384                 }
385                 par = par->next;
386         }
387
388         text->SetCursorIntern(this, cursor.par(), cursor.pos());
389         redraw();
390         fitCursor(text);
391 }
392 #endif
393
394
395 void BufferView::insertNote()
396 {
397         InsetInfo * new_inset = new InsetInfo();
398         insertInset(new_inset);
399         new_inset->Edit(this, 0, 0, 0);
400 }
401
402
403 #ifndef NEW_INSETS
404 void BufferView::openStuff()
405 {
406         if (available()) {
407                 owner()->getMiniBuffer()->Set(_("Open/Close..."));
408                 hideCursor();
409                 beforeChange();
410                 update(BufferView::SELECT|BufferView::FITCUR);
411                 text->OpenStuff(this);
412                 update(BufferView::SELECT|BufferView::FITCUR);
413                 setState();
414         }
415 }
416
417
418 void BufferView::toggleFloat()
419 {
420         if (available()) {
421                 owner()->getMiniBuffer()->Set(_("Open/Close..."));
422                 hideCursor();
423                 beforeChange();
424                 update(BufferView::SELECT|BufferView::FITCUR);
425                 text->ToggleFootnote(this);
426                 update(BufferView::SELECT|BufferView::FITCUR);
427                 setState();
428         }
429 }
430 #endif
431
432 void BufferView::menuUndo()
433 {
434         if (available()) {
435                 owner()->getMiniBuffer()->Set(_("Undo"));
436                 hideCursor();
437                 beforeChange();
438                 update(BufferView::SELECT|BufferView::FITCUR);
439                 if (!text->TextUndo(this))
440                         owner()->getMiniBuffer()->Set(_("No further undo information"));
441                 else
442                         update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
443                 setState();
444         }
445 }
446
447
448 void BufferView::menuRedo()
449 {
450         if (theLockingInset()) {
451                 owner()->getMiniBuffer()->Set(_("Redo not yet supported in math mode"));
452                 return;
453         }    
454    
455         if (available()) {
456                 owner()->getMiniBuffer()->Set(_("Redo"));
457                 hideCursor();
458                 beforeChange();
459                 update(BufferView::SELECT|BufferView::FITCUR);
460                 if (!text->TextRedo(this))
461                         owner()->getMiniBuffer()->Set(_("No further redo information"));
462                 else
463                         update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
464                 setState();
465         }
466 }
467
468
469 void BufferView::hyphenationPoint()
470 {
471         if (available()) {
472                 hideCursor();
473                 update(BufferView::SELECT|BufferView::FITCUR);
474                 InsetSpecialChar * new_inset = 
475                         new InsetSpecialChar(InsetSpecialChar::HYPHENATION);
476                 insertInset(new_inset);
477         }
478 }
479
480
481 void BufferView::ldots()
482 {
483         if (available())  {
484                 hideCursor();
485                 update(BufferView::SELECT|BufferView::FITCUR);
486                 InsetSpecialChar * new_inset = 
487                         new InsetSpecialChar(InsetSpecialChar::LDOTS);
488                 insertInset(new_inset);
489         }
490 }
491
492
493 void BufferView::endOfSentenceDot()
494 {
495         if (available()) {
496                 hideCursor();
497                 update(BufferView::SELECT|BufferView::FITCUR);
498                 InsetSpecialChar * new_inset = 
499                         new InsetSpecialChar(InsetSpecialChar::END_OF_SENTENCE);
500                 insertInset(new_inset);
501         }
502 }
503
504
505 void BufferView::menuSeparator()
506 {
507         if (available()) {
508                 hideCursor();
509                 update(BufferView::SELECT|BufferView::FITCUR);
510                 InsetSpecialChar * new_inset = 
511                         new InsetSpecialChar(InsetSpecialChar::MENU_SEPARATOR);
512                 insertInset(new_inset);
513         }
514 }
515
516
517 void BufferView::newline()
518 {
519         if (available()) {
520                 hideCursor();
521                 update(BufferView::SELECT|BufferView::FITCUR);
522                 text->InsertChar(this, LyXParagraph::META_NEWLINE);
523                 update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
524         }
525 }
526
527
528 void BufferView::protectedBlank()
529 {
530         if (available()) {
531                 hideCursor();
532                 update(BufferView::SELECT|BufferView::FITCUR);
533                 InsetSpecialChar * new_inset =
534                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
535                 insertInset(new_inset);
536         }
537 }
538
539
540 void BufferView::hfill()
541 {
542         if (available()) {
543                 hideCursor();
544                 update(BufferView::SELECT|BufferView::FITCUR);
545                 text->InsertChar(this, LyXParagraph::META_HFILL);
546                 update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
547         }
548 }
549
550 void BufferView::copyEnvironment()
551 {
552         if (available()) {
553                 text->copyEnvironmentType();
554                 // clear the selection, even if mark_set
555                 toggleSelection();
556                 text->ClearSelection();
557                 update(BufferView::SELECT|BufferView::FITCUR);
558                 owner()->getMiniBuffer()->Set(_("Paragraph environment type copied"));
559         }
560 }
561
562
563 void BufferView::pasteEnvironment()
564 {
565         if (available()) {
566                 text->pasteEnvironmentType(this);
567                 owner()->getMiniBuffer()->Set(_("Paragraph environment type set"));
568                 update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
569         }
570 }
571
572
573 void BufferView::copy()
574 {
575         if (available()) {
576                 text->CopySelection(this);
577                 // clear the selection, even if mark_set
578                 toggleSelection();
579                 text->ClearSelection();
580                 update(BufferView::SELECT|BufferView::FITCUR);
581                 owner()->getMiniBuffer()->Set(_("Copy"));
582         }
583 }
584
585 void BufferView::cut()
586 {
587         if (available()) {
588                 hideCursor();
589                 update(BufferView::SELECT|BufferView::FITCUR);
590                 text->CutSelection(this);
591                 update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
592                 owner()->getMiniBuffer()->Set(_("Cut"));
593         }
594 }
595
596
597 void BufferView::paste()
598 {
599         if (!available()) return;
600         
601         owner()->getMiniBuffer()->Set(_("Paste"));
602         hideCursor();
603         // clear the selection
604         toggleSelection();
605         text->ClearSelection();
606         update(BufferView::SELECT|BufferView::FITCUR);
607         
608         // paste
609         text->PasteSelection(this);
610         update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
611         
612         // clear the selection 
613         toggleSelection();
614         text->ClearSelection();
615         update(BufferView::SELECT|BufferView::FITCUR);
616 }
617
618
619 void BufferView::gotoInset(std::vector<Inset::Code> const & codes,
620                            bool same_content)
621 {
622         if (!available()) return;
623    
624         hideCursor();
625         beforeChange();
626         update(BufferView::SELECT|BufferView::FITCUR);
627
628         string contents;
629         if (same_content &&
630             text->cursor.par()->GetChar(text->cursor.pos()) == LyXParagraph::META_INSET) {
631                 Inset const * inset = text->cursor.par()->GetInset(text->cursor.pos());
632                 if (find(codes.begin(), codes.end(), inset->LyxCode())
633                     != codes.end())
634                         contents =
635                                 static_cast<InsetCommand const *>(inset)->getContents();
636         }
637         
638         if (!text->GotoNextInset(this, codes, contents)) {
639                 if (text->cursor.pos() 
640                     || text->cursor.par() != text->FirstParagraph()) {
641                                 LyXCursor tmp = text->cursor;
642                                 text->cursor.par(text->FirstParagraph());
643                                 text->cursor.pos(0);
644                                 if (!text->GotoNextInset(this, codes, contents)) {
645                                         text->cursor = tmp;
646                                         owner()->getMiniBuffer()->Set(_("No more insets"));
647                                         LyXBell();
648                                 }
649                         } else {
650                                 owner()->getMiniBuffer()->Set(_("No more insets"));
651                                 LyXBell();
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::ChangeRefs(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() == Inset::REF_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 ChangeRefs(from, to);
940 }
941
942
943 UpdatableInset * BufferView::theLockingInset() const
944 {
945         // If NULL is not allowed we should put an Assert here. (Lgb)
946         if (text)
947                 return text->the_locking_inset;
948         return 0;
949 }
950
951
952 void BufferView::theLockingInset(UpdatableInset * inset)
953 {
954     text->the_locking_inset = inset;
955 }
956
957
958 LyXText * BufferView::getLyXText() const
959 {
960         if (theLockingInset()) {
961                 LyXText * txt = theLockingInset()->getLyXText(this);
962                 if (txt)
963                         return txt;
964         }
965         return text;
966 }
967
968
969 LyXText * BufferView::getParentText(Inset * inset) const
970 {
971         if (inset->owner()) {
972                 LyXText * txt = inset->getLyXText(this);
973                 inset = inset->owner();
974                 while (inset && inset->getLyXText(this) == txt)
975                         inset = inset->owner();
976                 if (inset)
977                         return inset->getLyXText(this);
978         }
979         return text;
980 }
981
982 Language const * BufferView::getParentLanguage(Inset * inset) const
983 {
984         LyXText * text = getParentText(inset);
985         return text->cursor.par()->GetFontSettings(buffer()->params,
986                                                    text->cursor.pos()).language();
987 }