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