]> git.lyx.org Git - lyx.git/blob - src/BufferView2.C
continue the crusade to get rid of current_view
[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 "BufferView.h"
15 #include "buffer.h"
16 #include "lyxcursor.h"
17 #include "lyxtext.h"
18 #include "insets/inseterror.h"
19 #include "insets/insetinfo.h"
20 #include "insets/insetspecialchar.h"
21 #include "LyXView.h"
22 #include "minibuffer.h"
23 #include "bufferlist.h"
24 #include "support/FileInfo.h"
25 #include "lyxscreen.h"
26
27 extern BufferList bufferlist;
28
29 using std::ifstream;
30
31 // Inserts a file into current document
32 bool BufferView::insertLyXFile(string const & filen)
33         //
34         // (c) CHT Software Service GmbH
35         // Uwe C. Schroeder
36         //
37         // Insert a Lyxformat - file into current buffer
38         //
39         // Moved from lyx_cb.C (Lgb)
40 {
41         if (filen.empty()) return false;
42
43         string fname = MakeAbsPath(filen);
44
45         // check if file exist
46         FileInfo fi(fname);
47
48         if (!fi.readable()) {
49                 WriteAlert(_("Error!"),
50                            _("Specified file is unreadable: "),
51                            MakeDisplayPath(fname, 50));
52                 return false;
53         }
54         
55         beforeChange();
56
57         ifstream ifs(fname.c_str());
58         if (!ifs) {
59                 WriteAlert(_("Error!"),
60                            _("Cannot open specified file: "),
61                            MakeDisplayPath(fname, 50));
62                 return false;
63         }
64         LyXLex lex(0, 0);
65         lex.setStream(ifs);
66         char c; ifs.get(c);
67         ifs.putback(c);
68
69         bool res = true;
70
71         if (c == '#') {
72                 lyxerr.debug() << "Will insert file with header" << endl;
73                 res = buffer()->readFile(lex, text->cursor.par);
74         } else {
75                 lyxerr.debug() << "Will insert file without header" << endl;
76                 res = buffer()->readLyXformat2(lex, text->cursor.par);
77         }
78
79         resize();
80         return res;
81 }
82
83 bool BufferView::removeAutoInsets()
84 {
85         LyXParagraph * par = buffer()->paragraph;
86
87         LyXCursor cursor = text->cursor;
88         LyXCursor tmpcursor = cursor;
89         cursor.par = tmpcursor.par->ParFromPos(tmpcursor.pos);
90         cursor.pos = tmpcursor.par->PositionInParFromPos(tmpcursor.pos);
91
92         bool a = false;
93         while (par) {
94                 if (par->AutoDeleteInsets()){
95                         a = true;
96                         if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
97                                 // this is possible now, since SetCursor takes
98                                 // care about footnotes
99                                 text->SetCursorIntern(par, 0);
100                                 text->RedoParagraphs(text->cursor,
101                                                      text->cursor.par->Next());
102                                 text->FullRebreak();
103                         }
104                 }
105                 par = par->next;
106         }
107         // avoid forbidden cursor positions caused by error removing
108         if (cursor.pos > cursor.par->Last())
109                 cursor.pos = cursor.par->Last();
110         text->SetCursorIntern(cursor.par, cursor.pos);
111
112         return a;
113 }
114
115
116 void BufferView::insertErrors(TeXErrors & terr)
117 {
118         // Save the cursor position
119         LyXCursor cursor = text->cursor;
120
121         // This is drastic, but it's the only fix, I could find. (Asger)
122         allFloats(1, 0);
123         allFloats(1, 1);
124
125         for (TeXErrors::Errors::const_iterator cit = terr.begin();
126              cit != terr.end();
127              ++cit) {
128                 string desctext((*cit).error_desc);
129                 string errortext((*cit).error_text);
130                 string msgtxt = desctext + '\n' + errortext;
131                 int errorrow = (*cit).error_in_line;
132
133                 // Insert error string for row number
134                 int tmpid = -1; 
135                 int tmppos = -1;
136
137                 buffer()->texrow.getIdFromRow(errorrow, tmpid, tmppos);
138
139                 LyXParagraph * texrowpar = 0;
140
141                 if (tmpid == -1) {
142                         texrowpar = text->FirstParagraph();
143                         tmppos = 0;
144                 } else {
145                         texrowpar = text->GetParFromID(tmpid);
146                 }
147
148                 if (texrowpar == 0)
149                         continue;
150
151                 InsetError * new_inset = new InsetError(msgtxt);
152                 text->SetCursorIntern(texrowpar, tmppos);
153                 text->InsertInset(new_inset);
154                 text->FullRebreak();
155         }
156         // Restore the cursor position
157         text->SetCursorIntern(cursor.par, cursor.pos);
158 }
159
160
161 void BufferView::setCursorFromRow(int row)
162 {
163         int tmpid = -1; 
164         int tmppos = -1;
165
166         buffer()->texrow.getIdFromRow(row, tmpid, tmppos);
167
168         LyXParagraph * texrowpar;
169
170         if (tmpid == -1) {
171                 texrowpar = text->FirstParagraph();
172                 tmppos = 0;
173         } else {
174                 texrowpar = text->GetParFromID(tmpid);
175         }
176         text->SetCursor(texrowpar, tmppos);
177 }
178
179 void BufferView::insertInset(Inset * inset, string const & lout,
180                          bool no_table)
181 {
182         // check for table/list in tables
183         if (no_table && text->cursor.par->table){
184                 WriteAlert(_("Impossible Operation!"),
185                            _("Cannot insert table/list in table."),
186                            _("Sorry."));
187                 return;
188         }
189         // not quite sure if we want this...
190         text->SetCursorParUndo();
191         text->FreezeUndo();
192         
193         beforeChange();
194         if (!lout.empty()) {
195                 update(-2);
196                 text->BreakParagraph();
197                 update(-1);
198                 
199                 if (text->cursor.par->Last()) {
200                         text->CursorLeft();
201                         
202                         text->BreakParagraph();
203                         update(-1);
204                 }
205
206                 int lay = textclasslist.NumberOfLayout(buffer()->params.textclass,
207                                                        lout).second;
208                 if (lay == -1) // layout not found
209                         // use default layout "Standard" (0)
210                         lay = 0;
211                 
212                 text->SetLayout(lay);
213                 
214                 text->SetParagraph(0, 0,
215                                    0, 0,
216                                    VSpace(VSpace::NONE), VSpace(VSpace::NONE),
217                                    LYX_ALIGN_LAYOUT, 
218                                    string(),
219                                    0);
220                 update(-1);
221                 
222                 text->current_font.setLatex(LyXFont::OFF);
223         }
224         
225         text->InsertInset(inset);
226         update(-1);
227
228         text->UnFreezeUndo();   
229 }
230
231
232 // Open and lock an updatable inset
233 void BufferView::open_new_inset(UpdatableInset * new_inset)
234 {
235         beforeChange();
236         text->FinishUndo();
237         insertInset(new_inset);
238         text->CursorLeft();
239         update(1);
240         new_inset->Edit(this, 0, 0);
241 }
242
243 /* This is also a buffer property (ale) */
244 // Not so sure about that. a goto Label function can not be buffer local, just
245 // think how this will work in a multiwindo/buffer environment, all the
246 // cursors in all the views showing this buffer will move. (Lgb)
247 // OK, then no cursor action should be allowed in buffer. (ale)
248 bool BufferView::gotoLabel(string const & label)
249
250 {
251         LyXParagraph * par = buffer()->paragraph;
252         LyXParagraph::size_type pos;
253         Inset * inset;
254         while (par) {
255                 pos = -1;
256                 while ((inset = par->ReturnNextInsetPointer(pos))){     
257                         for (int i = 0; i < inset->GetNumberOfLabels(); ++i) {
258                                 if (label == inset->getLabel(i)) {
259                                         beforeChange();
260                                         text->SetCursor(par, pos);
261                                         text->sel_cursor = text->cursor;
262                                         update(0);
263                                         return true;
264                                 }
265                         }
266                         ++pos;
267                 } 
268                 par = par->next;
269         }
270         return false;
271 }
272
273 void BufferView::allFloats(char flag, char figmar)
274 {
275         if (!available()) return;
276
277         LyXCursor cursor = text->cursor;
278
279         if (!flag && cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
280             && ((figmar 
281                  && cursor.par->footnotekind != LyXParagraph::FOOTNOTE 
282                  && cursor.par->footnotekind != LyXParagraph::MARGIN)
283                 || (!figmar
284                     && cursor.par->footnotekind != LyXParagraph::FIG 
285                     && cursor.par->footnotekind != LyXParagraph::TAB
286                     && cursor.par->footnotekind != LyXParagraph::WIDE_FIG 
287                     && cursor.par->footnotekind != LyXParagraph::WIDE_TAB
288                     && cursor.par->footnotekind != LyXParagraph::ALGORITHM)))
289                 toggleFloat();
290         else
291                 beforeChange();
292
293         LyXCursor tmpcursor = cursor;
294         cursor.par = tmpcursor.par->ParFromPos(tmpcursor.pos);
295         cursor.pos = tmpcursor.par->PositionInParFromPos(tmpcursor.pos);
296
297         LyXParagraph *par = buffer()->paragraph;
298         while (par) {
299                 if (flag) {
300                         if (par->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
301                             && ((figmar 
302                                  && par->footnotekind != LyXParagraph::FOOTNOTE 
303                                  && par->footnotekind !=  LyXParagraph::MARGIN)
304                                 || (!figmar
305                                     && par->footnotekind != LyXParagraph::FIG 
306                                     && par->footnotekind != LyXParagraph::TAB
307                                     && par->footnotekind != LyXParagraph::WIDE_FIG 
308                                     && par->footnotekind != LyXParagraph::WIDE_TAB
309                                     && par->footnotekind != LyXParagraph::ALGORITHM
310                                         )
311                                     )
312                                 ) {
313                                 if (par->previous
314                                     && par->previous->footnoteflag != 
315                                     LyXParagraph::CLOSED_FOOTNOTE){ /* should be */ 
316                                         text->SetCursorIntern(par->previous,
317                                                               0);
318                                         text->OpenFootnote();
319                                 }
320                         }
321                 } else {
322                         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
323                             && (
324                                     (figmar 
325                                      &&
326                                      par->footnotekind != LyXParagraph::FOOTNOTE 
327                                      &&
328                                      par->footnotekind !=  LyXParagraph::MARGIN
329                                             )
330                                     ||
331                                     (!figmar
332                                      &&
333                                      par->footnotekind != LyXParagraph::FIG 
334                                      &&
335                                      par->footnotekind != LyXParagraph::TAB
336                                      &&
337                                      par->footnotekind != LyXParagraph::WIDE_FIG 
338                                      &&
339                                      par->footnotekind != LyXParagraph::WIDE_TAB
340                                      &&
341                                      par->footnotekind != LyXParagraph::ALGORITHM
342                                             )
343                                     )
344                                 ) {
345                                 text->SetCursorIntern(par, 0);
346                                 text->CloseFootnote();
347                         }
348                 }
349                 par = par->next;
350         }
351
352         text->SetCursorIntern(cursor.par, cursor.pos);
353         redraw();
354         fitCursor();
355         updateScrollbar();
356 }
357
358
359 void BufferView::insertNote()
360 {
361         InsetInfo * new_inset = new InsetInfo();
362         insertInset(new_inset);
363         new_inset->Edit(this, 0, 0);
364 }
365
366
367 void BufferView::openStuff()
368 {
369         if (available()) {
370                 owner()->getMiniBuffer()->Set(_("Open/Close..."));
371                 hideCursor();
372                 beforeChange();
373                 update(-2);
374                 text->OpenStuff();
375                 update(0);
376                 setState();
377         }
378 }
379
380
381 void BufferView::toggleFloat()
382 {
383         if (available()) {
384                 owner()->getMiniBuffer()->Set(_("Open/Close..."));
385                 hideCursor();
386                 beforeChange();
387                 update(-2);
388                 text->ToggleFootnote();
389                 update(0);
390                 setState();
391         }
392 }
393
394 void BufferView::menuUndo()
395 {
396         if (available()) {
397                 owner()->getMiniBuffer()->Set(_("Undo"));
398                 hideCursor();
399                 beforeChange();
400                 update(-2);
401                 if (!text->TextUndo())
402                         owner()->getMiniBuffer()->Set(_("No further undo information"));
403                 else
404                         update(-1);
405                 setState();
406         }
407 }
408
409
410 void BufferView::menuRedo()
411 {
412         if (the_locking_inset) {
413                 owner()->getMiniBuffer()->Set(_("Redo not yet supported in math mode"));
414                 return;
415         }    
416    
417         if (available()) {
418                 owner()->getMiniBuffer()->Set(_("Redo"));
419                 hideCursor();
420                 beforeChange();
421                 update(-2);
422                 if (!text->TextRedo())
423                         owner()->getMiniBuffer()->Set(_("No further redo information"));
424                 else
425                         update(-1);
426                 setState();
427         }
428 }
429
430
431 void BufferView::hyphenationPoint()
432 {
433         if (available()) {
434                 hideCursor();
435                 update(-2);
436                 InsetSpecialChar * new_inset = 
437                         new InsetSpecialChar(InsetSpecialChar::HYPHENATION);
438                 insertInset(new_inset);
439         }
440 }
441
442
443 void BufferView::ldots()
444 {
445         if (available())  {
446                 hideCursor();
447                 update(-2);
448                 InsetSpecialChar * new_inset = 
449                         new InsetSpecialChar(InsetSpecialChar::LDOTS);
450                 insertInset(new_inset);
451         }
452 }
453
454
455 void BufferView::endOfSentenceDot()
456 {
457         if (available()) {
458                 hideCursor();
459                 update(-2);
460                 InsetSpecialChar * new_inset = 
461                         new InsetSpecialChar(InsetSpecialChar::END_OF_SENTENCE);
462                 insertInset(new_inset);
463         }
464 }
465
466
467 void BufferView::menuSeparator()
468 {
469         if (available()) {
470                 hideCursor();
471                 update(-2);
472                 InsetSpecialChar * new_inset = 
473                         new InsetSpecialChar(InsetSpecialChar::MENU_SEPARATOR);
474                 insertInset(new_inset);
475         }
476 }
477
478
479 void BufferView::newline()
480 {
481         if (available()) {
482                 hideCursor();
483                 update(-2);
484                 text->InsertChar(LyXParagraph::META_NEWLINE);
485                 update(-1);
486         }
487 }
488
489
490 void BufferView::protectedBlank()
491 {
492         if (available()) {
493                 hideCursor();
494                 update(-2);
495                 text->InsertChar(LyXParagraph::META_PROTECTED_SEPARATOR);
496                 update(-1);
497         }
498 }
499
500
501 void BufferView::hfill()
502 {
503         if (available()) {
504                 hideCursor();
505                 update(-2);
506                 text->InsertChar(LyXParagraph::META_HFILL);
507                 update(-1);
508         }
509 }
510
511 void BufferView::copyEnvironment()
512 {
513         if (available()) {
514                 text->copyEnvironmentType();
515                 // clear the selection, even if mark_set
516                 toggleSelection();
517                 text->ClearSelection();
518                 update(-2);
519                 owner()->getMiniBuffer()->Set(_("Paragraph environment type copied"));
520         }
521 }
522
523
524 void BufferView::pasteEnvironment()
525 {
526         if (available()) {
527                 text->pasteEnvironmentType();
528                 owner()->getMiniBuffer()->Set(_("Paragraph environment type set"));
529                 update(1);
530         }
531 }
532
533
534 void BufferView::copy()
535 {
536         if (available()) {
537                 text->CopySelection();
538                 // clear the selection, even if mark_set
539                 toggleSelection();
540                 text->ClearSelection();
541                 update(-2);
542                 owner()->getMiniBuffer()->Set(_("Copy"));
543         }
544 }
545
546 void BufferView::cut()
547 {
548         if (available()) {
549                 hideCursor();
550                 update(-2);
551                 text->CutSelection();
552                 update(1);
553                 owner()->getMiniBuffer()->Set(_("Cut"));
554         }
555 }
556
557
558 void BufferView::paste()
559 {
560         if (!available()) return;
561         
562         owner()->getMiniBuffer()->Set(_("Paste"));
563         hideCursor();
564         // clear the selection
565         toggleSelection();
566         text->ClearSelection();
567         update(-2);
568         
569         // paste
570         text->PasteSelection();
571         update(1);
572         
573         // clear the selection 
574         toggleSelection();
575         text->ClearSelection();
576         update(-2);
577 }
578
579
580 void BufferView::gotoNote()
581 {
582         if (!available()) return;
583    
584         hideCursor();
585         beforeChange();
586         update(-2);
587         LyXCursor tmp;
588    
589         if (!text->GotoNextNote()) {
590                 if (text->cursor.pos 
591                     || text->cursor.par != text->FirstParagraph()) {
592                                 tmp = text->cursor;
593                                 text->cursor.par = text->FirstParagraph();
594                                 text->cursor.pos = 0;
595                                 if (!text->GotoNextNote()) {
596                                         text->cursor = tmp;
597                                         owner()->getMiniBuffer()->Set(_("No more notes"));
598                                         LyXBell();
599                                 }
600                         } else {
601                                 owner()->getMiniBuffer()->Set(_("No more notes"));
602                                 LyXBell();
603                         }
604         }
605         update(0);
606         text->sel_cursor = text->cursor;
607 }
608
609
610 void BufferView::insertCorrectQuote()
611 {
612         char c;
613
614         if (text->cursor.pos)
615                 c = text->cursor.par->GetChar(text->cursor.pos - 1);
616         else 
617                 c = ' ';
618
619         insertInset(new InsetQuotes(c, buffer()->params));
620 }
621
622
623 /* these functions are for the spellchecker */ 
624 char * BufferView::nextWord(float & value)
625 {
626         if (!available()) {
627                 value = 1;
628                 return 0;
629         }
630
631         char * string = text->SelectNextWord(value);
632
633         return string;
634 }
635
636   
637 void BufferView::selectLastWord()
638 {
639         if (!available()) return;
640    
641         hideCursor();
642         beforeChange();
643         text->SelectSelectedWord();
644         toggleSelection(false);
645         update(0);
646 }
647
648
649 void BufferView::endOfSpellCheck()
650 {
651         if (!available()) return;
652    
653         hideCursor();
654         beforeChange();
655         text->SelectSelectedWord();
656         text->ClearSelection();
657         update(0);
658 }
659
660
661 void BufferView::replaceWord(string const & replacestring)
662 {
663         if (!available()) return;
664
665         hideCursor();
666         update(-2);
667    
668         /* clear the selection (if there is any) */ 
669         toggleSelection(false);
670         update(-2);
671    
672         /* clear the selection (if there is any) */ 
673         toggleSelection(false);
674         text->ReplaceSelectionWithString(replacestring.c_str());
675    
676         text->SetSelectionOverString(replacestring.c_str());
677
678         // Go back so that replacement string is also spellchecked
679         for (string::size_type i = 0; i < replacestring.length() + 1; ++i) {
680                 text->CursorLeftIntern();
681         }
682         update(1);
683 }
684 // End of spellchecker stuff
685
686
687 /* these functions return 1 if an error occured, 
688    otherwise 0 */
689 int BufferView::lockInset(UpdatableInset * inset)
690 {
691         if (!the_locking_inset && inset){
692                 the_locking_inset = inset;
693                 return 0;
694         }
695         return 1;
696 }
697
698
699 void BufferView::showLockedInsetCursor(long x, long y, int asc, int desc)
700 {
701         if (the_locking_inset && available()) {
702                 y += text->cursor.y;
703                 screen->ShowManualCursor(x, y,
704                                               asc, desc);
705         }
706 }
707
708
709 void BufferView::hideLockedInsetCursor()
710 {
711         if (the_locking_inset && available()) {
712                 screen->HideCursor();
713         }
714 }
715
716
717 void BufferView::fitLockedInsetCursor(long x, long y, int asc, int desc)
718 {
719         if (the_locking_inset && available()){
720                 y += text->cursor.y;
721                 if (screen->FitManualCursor(x, y, asc, desc))
722                         updateScrollbar();
723         }
724 }
725
726
727 int BufferView::unlockInset(UpdatableInset * inset)
728 {
729         if (inset && the_locking_inset == inset) {
730                 inset->InsetUnlock(this);
731                 the_locking_inset = 0;
732                 text->FinishUndo();
733                 return 0;
734         }
735         return bufferlist.unlockInset(inset);
736 }
737
738
739 void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind)
740 {
741         if (!the_locking_inset)
742                 return; // shouldn't happen
743         if (kind == Undo::EDIT) // in this case insets would not be stored!
744                 kind = Undo::FINISH;
745         text->SetUndo(kind,
746                       text->cursor.par->
747                       ParFromPos(text->cursor.pos)->previous, 
748                       text->cursor.par->
749                       ParFromPos(text->cursor.pos)->next);
750 }