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