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