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