]> git.lyx.org Git - lyx.git/blob - src/lyxtext.h
The BIG UNDO patch. Recodes undo handling for better use inside InsetText.
[lyx.git] / src / lyxtext.h
1 // -*- C++ -*-
2 /* This file is part of
3  * ====================================================== 
4  * 
5  *           LyX, The Document Processor
6  *       
7  *           Copyright 1995 Matthias Ettrich
8  *           Copyright 1995-2001 The LyX Team.
9  *
10  * ====================================================== */
11
12 #ifndef LYXTEXT_H
13 #define LYXTEXT_H
14
15 #ifdef __GNUG__
16 #pragma interface
17 #endif
18
19 #include "lyxfont.h"
20 #include "lyxcursor.h"
21 #include "paragraph.h"
22 #include "layout.h"
23 #include "lyxrow.h"
24 #include "vspace.h"
25
26 class Buffer;
27 class BufferParams;
28 class BufferView;
29 class InsetText;
30
31
32 /**
33   This class holds the mapping between buffer paragraphs and screen rows.
34   */
35 class LyXText {
36 public:
37         ///
38         enum text_status {
39                 ///
40                 UNCHANGED = 0,
41                 ///
42                 CHANGED_IN_DRAW = 1,
43                 ///
44                 NEED_VERY_LITTLE_REFRESH = 2,
45                 ///
46                 NEED_MORE_REFRESH = 3
47         };
48         ///
49         enum word_location {
50                 /// the word around the cursor
51                 WHOLE_WORD,
52                 /// the word begining from the cursor position
53                 PARTIAL_WORD,
54                 /// the next word (not yet used)
55                 NEXT_WORD
56         };
57
58         /// Constructor
59         LyXText(BufferView *);
60         ///
61         LyXText(InsetText *);
62    
63         /// Destructor
64         ~LyXText();
65
66         void init(BufferView *);
67         ///
68         mutable int number_of_rows;
69         ///
70         mutable int height;
71         ///
72         mutable unsigned int width;
73         /// the current font settings
74         mutable LyXFont current_font;
75         /// the current font
76         mutable LyXFont real_current_font;
77         /// first visible pixel-row is set from LyXScreen!!!
78         // unsigned is wrong here for text-insets!
79         int first;
80         ///
81         BufferView * bv_owner;
82         ///
83         InsetText * inset_owner;
84         ///
85         UpdatableInset * the_locking_inset;
86
87         ///
88         int getRealCursorX(BufferView *) const;
89         ///
90         LyXFont const getFont(Buffer const *, Paragraph * par,
91                         Paragraph::size_type pos) const;
92         ///
93         void setCharFont(Buffer const *, Paragraph * par,
94                          Paragraph::size_type pos, LyXFont const & font);
95         void setCharFont(BufferView *, Paragraph * par,
96                          Paragraph::size_type pos,
97                          LyXFont const & font, bool toggleall);
98         /// returns a pointer to the very first Paragraph
99         Paragraph * firstParagraph() const;
100   
101         /// what you expect when pressing <enter> at cursor position
102         void breakParagraph(BufferView *, char keep_layout = 0);
103
104         /** set layout over selection and make a total rebreak of
105           those paragraphs
106           */
107         Paragraph * setLayout(BufferView *, LyXCursor & actual_cursor,
108                                  LyXCursor & selection_start,
109                                  LyXCursor & selection_end,
110                                  LyXTextClass::size_type layout);
111         void setLayout(BufferView *, LyXTextClass::size_type layout);
112         
113         /// used in setlayout
114         void makeFontEntriesLayoutSpecific(Buffer const *, Paragraph * par);
115         
116         /** increment depth over selection and make a total rebreak of those 
117           paragraphs
118           */
119         void incDepth(BufferView *);
120         
121         /** decrement depth over selection and make a total rebreak of those  
122           paragraphs */
123         void decDepth(BufferView *);
124
125         /** Get the depth at current cursor position
126          */
127         int getDepth() const { return cursor.par()->getDepth(); }
128         
129         /** set font over selection and make a total rebreak of those
130           paragraphs.
131           toggleall defaults to false.
132           */
133         void setFont(BufferView *, LyXFont const &, bool toggleall = false);
134         
135         /** deletes and inserts again all paragaphs between the cursor
136           and the specified par. The Cursor is needed to set the refreshing
137           parameters. 
138           This function is needed after SetLayout and SetFont etc.
139           */
140         void redoParagraphs(BufferView *, LyXCursor const & cursor,
141                             Paragraph const * end_par) const;
142         ///
143         void redoParagraph(BufferView *) const;
144         
145         ///
146         void toggleFree(BufferView *, LyXFont const &, bool toggleall = false);
147         
148         /** recalculates the heights of all previous rows of the
149             specified paragraph.  needed, if the last characters font
150             has changed.  
151             */
152         void redoHeightOfParagraph(BufferView *, LyXCursor const & cursor);
153         
154         /** forces the redrawing of a paragraph. Needed when manipulating a 
155             right address box
156             */ 
157         void redoDrawingOfParagraph(BufferView *, LyXCursor const & cursor);
158         
159         /** insert a character, moves all the following breaks in the 
160           same Paragraph one to the right and make a little rebreak
161           */
162         void insertChar(BufferView *, char c);
163         ///
164         void insertInset(BufferView *, Inset * inset);
165    
166         /** Completes the insertion with a full rebreak.
167             Returns true if something was broken. */
168         bool fullRebreak(BufferView *);
169
170         ///
171         Row * need_break_row;
172         ///
173         mutable int refresh_y;
174         ///
175         int refresh_height;
176         ///
177         int refresh_width;
178         ///
179         int refresh_x;
180         ///
181         mutable Row * refresh_row;
182         ///
183         int refresh_pos;
184
185         /// give and set the LyXText status
186         text_status status() const;
187         void status(BufferView *, text_status) const;
188
189 private:        
190         /** wether the screen needs a refresh,
191            starting with refresh_y
192            */
193         mutable text_status status_;
194         
195 public:
196         /** returns a pointer to the row near the specified y-coordinate
197           (relative to the whole text). y is set to the real beginning
198           of this row
199           */ 
200         Row * getRowNearY(int & y) const;
201         
202         /** returns the column near the specified x-coordinate of the row 
203          x is set to the real beginning of this column
204          */ 
205         int getColumnNearX(BufferView *, Row * row,
206                            int & x, bool & boundary) const;
207         
208         /** returns a pointer to a specified row. y is set to the beginning
209          of the row
210          */
211         Row * getRow(Paragraph * par,
212                      Paragraph::size_type pos, int & y) const;
213
214         /** returns the height of a default row, needed  for scrollbar
215          */
216         int defaultHeight() const;
217    
218         /** The cursor.
219           Later this variable has to be removed. There should be now internal
220           cursor in a text (and thus not in a buffer). By keeping this it is
221           (I think) impossible to have several views with the same buffer, but
222           the cursor placed at different places.
223           [later]
224           Since the LyXText now has been moved from Buffer to BufferView
225           it should not be absolutely needed to move the cursor...
226           */
227         mutable LyXCursor cursor;
228
229         /** The structrue that keeps track of the selections set. */
230         struct Selection {
231                 Selection() 
232                         : set_(false), mark_(false)
233                         {}
234                 bool set() const {
235                         return set_;
236                 }
237                 void set(bool s) {
238                         set_ = s;
239                 }
240                 bool mark() const {
241                         return mark_;
242                 }
243                 void mark(bool m) {
244                         mark_ = m;
245                 }
246                 LyXCursor cursor;
247                 LyXCursor start;
248                 LyXCursor end;
249         private:
250                 bool set_; // former selection
251                 bool mark_; // former mark_set
252                 
253         };
254         mutable Selection selection;
255
256         /// needed for the toggling
257         LyXCursor last_sel_cursor;
258         ///
259         LyXCursor toggle_cursor;
260         ///
261         LyXCursor toggle_end_cursor;
262    
263         /// need the selection cursor:
264         void setSelection(BufferView *);
265         ///
266         void clearSelection(BufferView *) const;
267         ///
268         string const selectionAsString(Buffer const *) const;
269         
270         /// select the word we need depending on word_location
271         void getWord(LyXCursor & from, LyXCursor & to, word_location) const;
272         /// just selects the word the cursor is in
273         void selectWord(BufferView *);
274
275         /** 'selects" the next word, where the cursor is not in 
276          and returns this word as string. THe cursor will be moved 
277          to the beginning of this word. 
278          With SelectSelectedWord can this be highlighted really
279          */ 
280         string const selectNextWord(BufferView *, float & value) const;
281         ///
282         void selectSelectedWord(BufferView *);
283         ///
284         void setCursor(BufferView *, Paragraph * par,
285                        Paragraph::size_type pos,
286                        bool setfont = true,
287                        bool boundary = false) const;
288         ///
289         void setCursor(BufferView *, LyXCursor &, Paragraph * par,
290                        Paragraph::size_type pos,
291                        bool boundary = false) const;
292         ///
293         void setCursorIntern(BufferView *, Paragraph * par,
294                              Paragraph::size_type pos,
295                              bool setfont = true,
296                              bool boundary = false) const;
297         ///
298         void setCurrentFont(BufferView *) const;
299
300         ///
301         bool isBoundary(Buffer const *, Paragraph * par,
302                         Paragraph::size_type pos) const;
303         ///
304         bool isBoundary(Buffer const *, Paragraph * par,
305                          Paragraph::size_type pos,
306                          LyXFont const & font) const;
307
308         ///
309         void setCursorFromCoordinates(BufferView *, int x, int y) const;
310         ///
311         void setCursorFromCoordinates(BufferView *, LyXCursor &,
312                                       int x, int y) const;
313         ///
314         void cursorUp(BufferView *) const;
315         ///
316         void cursorDown(BufferView *) const;
317         ///
318         void cursorLeft(BufferView *, bool internal = true) const;
319         ///
320         void cursorRight(BufferView *, bool internal = true) const;
321         ///
322         void cursorLeftOneWord(BufferView *) const;
323         ///
324         void cursorLeftOneWord(LyXCursor &) const;
325         ///
326         void cursorRightOneWord(BufferView *) const;
327         ///
328         void cursorUpParagraph(BufferView *) const;
329         ///
330         void cursorDownParagraph(BufferView *) const;
331         ///
332         void cursorHome(BufferView *) const;
333         ///
334         void cursorEnd(BufferView *) const;
335         ///
336         void cursorTab(BufferView *) const;
337         ///
338         void cursorTop(BufferView *) const;
339         ///
340         void cursorBottom(BufferView *) const;
341         ///
342         void Delete(BufferView *);
343         ///
344         void backspace(BufferView *);
345         ///
346         void deleteWordForward(BufferView *);
347         ///
348         void deleteWordBackward(BufferView *);
349         ///
350         void deleteLineForward(BufferView *);
351         ///
352         bool selectWordWhenUnderCursor(BufferView *);
353         ///
354         enum TextCase {
355                 ///
356                 text_lowercase = 0,
357                 ///
358                 text_capitalization = 1,
359                 ///
360                 text_uppercase = 2
361         };
362         /// Change the case of the word at cursor position.
363         void changeCase(BufferView *, TextCase action);
364         ///
365         void changeRegionCase(BufferView * bview,
366                                        LyXCursor const & from,
367                                        LyXCursor const & to,
368                                        LyXText::TextCase action);
369         ///
370         void transposeChars(BufferView &);
371         
372         /** returns a printed row in a pixmap. The y value is needed to
373           decide, wether it is selected text or not. This is a strange
374           solution but faster.
375          */
376         void getVisibleRow(BufferView *, int y_offset, int x_offset,
377                            Row * row_ptr, int y, bool cleared=false);
378
379         ///
380         void cutSelection(BufferView *, bool = true);
381         ///
382         void copySelection(BufferView *);
383         ///
384         void pasteSelection(BufferView *);
385         ///
386         void copyEnvironmentType();
387         ///
388         void pasteEnvironmentType(BufferView *);
389         ///
390         void insertFootnote();
391         ///
392         void insertMarginpar();
393         ///
394         void insertFigure();
395         ///
396         void insertTabular();
397
398         /** the DTP switches for paragraphs. LyX will store the top settings
399          always in the first physical paragraph, the bottom settings in the
400          last. When a paragraph is broken, the top settings rest, the bottom 
401          settings are given to the new one. So I can make shure, they do not
402          duplicate themself (and you cannnot make dirty things with them! )
403          */ 
404         void setParagraph(BufferView *,
405                           bool line_top, bool line_bottom,
406                           bool pagebreak_top, bool pagebreak_bottom,
407                           VSpace const & space_top,
408                           VSpace const & space_bottom,
409                           LyXAlignment align, 
410                           string labelwidthstring,
411                           bool noindent);
412
413         /* these things are for search and replace */
414
415         /** sets the selection over the number of characters of string,
416           no check!!
417           */
418         void setSelectionOverString(BufferView *, string const & str);
419
420         /** simple replacing. The font of the first selected character
421           is used
422           */
423         void replaceSelectionWithString(BufferView *, string const & str);
424
425         /// needed to insert the selection
426         void insertStringAsLines(BufferView *, string const & str);
427         /// needed to insert the selection
428         void insertStringAsParagraphs(BufferView *, string const & str);
429
430         /// Find next inset of some specified type.
431         bool gotoNextInset(BufferView *, std::vector<Inset::Code> const & codes,
432                            string const & contents = string()) const;
433         ///
434
435         /* for the greater insets */
436   
437         /// returns false if inset wasn't found
438         bool updateInset(BufferView *, Inset *);
439         ///
440         void checkParagraph(BufferView *, Paragraph * par,
441                             Paragraph::size_type pos);
442         ///
443         int numberOfCell(Paragraph * par,
444                          Paragraph::size_type pos) const;
445         ///
446         Paragraph * getParFromID(int id) const;
447
448         ///
449         void removeTableRow(LyXCursor & cursor) const;
450         ///
451         bool isEmptyTableCell() const;
452         ///
453         void toggleAppendix(BufferView *);
454         ///
455         int workWidth(BufferView *) const;
456         ///
457         void computeBidiTables(Buffer const *, Row * row) const;
458
459         /// Maps positions in the visual string to positions in logical string.
460         inline
461         Paragraph::size_type log2vis(Paragraph::size_type pos) const {
462                 if (bidi_start == -1)
463                         return pos;
464                 else
465                         return log2vis_list[pos-bidi_start];
466         }
467
468         /// Maps positions in the logical string to positions in visual string.
469         inline
470         Paragraph::size_type vis2log(Paragraph::size_type pos) const {
471                 if (bidi_start == -1)
472                         return pos;
473                 else
474                         return vis2log_list[pos-bidi_start];
475         }
476         ///
477         inline
478         Paragraph::size_type bidi_level(Paragraph::size_type pos) const {
479                 if (bidi_start == -1)
480                         return 0;
481                 else
482                         return bidi_levels[pos-bidi_start];
483         }       
484         ///
485         inline
486         bool bidi_InRange(Paragraph::size_type pos) const {
487                 return bidi_start == -1 ||
488                         (bidi_start <= pos && pos <= bidi_end);
489         }
490 private:
491         ///
492         mutable Row * firstrow;
493         ///
494         mutable Row * lastrow;
495
496         /** Copybuffer for copy environment type.
497           Asger has learned that this should be a buffer-property instead
498           Lgb has learned that 'char' is a lousy type for non-characters
499           */
500         LyXTextClass::size_type copylayouttype;
501
502         /** inserts a new row behind the specified row, increments
503             the touched counters */
504         void insertRow(Row * row, Paragraph * par,
505                        Paragraph::size_type pos) const;
506         /** removes the row and reset the touched counters */
507         void removeRow(Row * row) const;
508
509         /** remove all following rows of the paragraph of the specified row. */
510         void removeParagraph(Row * row) const;
511
512         /** insert the specified paragraph behind the specified row */
513         void insertParagraph(BufferView *,
514                              Paragraph * par, Row * row) const;
515
516         /** appends  the implizit specified paragraph behind the specified row,
517          * start at the implizit given position */
518         void appendParagraph(BufferView *, Row * row) const;
519    
520         ///
521         void breakAgain(BufferView *, Row * row) const;
522         ///
523         void breakAgainOneRow(BufferView *, Row * row);
524         /// Calculate and set the height of the row
525         void setHeightOfRow(BufferView *, Row * row_ptr) const;
526
527         /** this calculates the specified parameters. needed when setting
528          * the cursor and when creating a visible row */ 
529         void prepareToPrint(BufferView *, Row * row, float & x,
530                             float & fill_separator, 
531                             float & fill_hfill,
532                             float & fill_label_hfill,
533                             bool bidi = true) const;
534
535         ///
536         void deleteEmptyParagraphMechanism(BufferView *,
537                                            LyXCursor const & old_cursor) const;
538
539 public:
540         /** Updates all counters starting BEHIND the row. Changed paragraphs
541          * with a dynamic left margin will be rebroken. */ 
542         void updateCounters(BufferView *, Row * row) const;
543 private:
544         ///
545         void setCounter(Buffer const *, Paragraph * par) const;
546    
547         /*
548          * some low level functions
549          */
550         
551         ///
552         int singleWidth(BufferView *, Paragraph * par,
553                         Paragraph::size_type pos) const;
554         ///
555         int singleWidth(BufferView *, Paragraph * par,
556                         Paragraph::size_type pos, char c) const;
557         ///
558         void draw(BufferView *, Row const * row,
559                   Paragraph::size_type & pos,
560                   int offset, float & x, bool cleared);
561
562         /// get the next breakpoint in a given paragraph
563         Paragraph::size_type nextBreakPoint(BufferView *, Row const * row,
564                                                int width) const;
565         /// returns the minimum space a row needs on the screen in pixel
566         int fill(BufferView *, Row * row, int workwidth) const;
567         
568         /** returns the minimum space a manual label needs on the
569           screen in pixel */ 
570         int labelFill(BufferView *, Row const * row) const;
571
572         ///
573         Paragraph::size_type
574         beginningOfMainBody(Buffer const *, Paragraph const * par) const;
575         
576         /** Returns the left beginning of the text.
577           This information cannot be taken from the layouts-objekt, because
578           in LaTeX the beginning of the text fits in some cases
579           (for example sections) exactly the label-width.
580           */
581         int leftMargin(BufferView *, Row const * row) const;
582         ///
583         int rightMargin(Buffer const *, Row const * row) const;
584         ///
585         int labelEnd (BufferView *, Row const * row) const;
586
587         /** returns the number of separators in the specified row.
588           The separator on the very last column doesnt count
589           */ 
590         int numberOfSeparators(Buffer const *, Row const * row) const;
591
592         /** returns the number of hfills in the specified row. The
593           LyX-Hfill is a LaTeX \hfill so that the hfills at the
594           beginning and at the end were ignored. This is {\em MUCH}
595           more usefull than not to ignore!
596           */
597         int numberOfHfills(Buffer const *, Row const * row) const;
598    
599         /// like NumberOfHfills, but only those in the manual label!
600         int numberOfLabelHfills(Buffer const *, Row const * row) const;
601         /** returns true, if a expansion is needed. Rules are given by 
602           LaTeX
603           */
604         bool hfillExpansion(Buffer const *, Row const * row_ptr,
605                             Paragraph::size_type pos) const;
606
607
608         ///
609         mutable std::vector<Paragraph::size_type> log2vis_list;
610
611         ///
612         mutable std::vector<Paragraph::size_type> vis2log_list;
613
614         ///
615         mutable std::vector<Paragraph::size_type> bidi_levels;
616
617         ///
618         mutable Paragraph::size_type bidi_start;
619
620         ///
621         mutable Paragraph::size_type bidi_end;
622
623         ///
624         mutable bool bidi_same_direction;
625
626         ///
627         unsigned char transformChar(unsigned char c, Paragraph * par,
628                                     Paragraph::size_type pos) const;
629
630         /** returns the paragraph position of the last character in the 
631           specified row
632           */
633         Paragraph::size_type rowLast(Row const * row) const;
634         ///
635         Paragraph::size_type rowLastPrintable(Row const * row) const;
636
637         ///
638         void charInserted();
639 public:
640         //
641         // special owner functions
642         ///
643         Paragraph * ownerParagraph() const;
644         //
645         Paragraph * ownerParagraph(Paragraph *) const;
646         // set it searching first for the right owner using the paragraph id
647         Paragraph * ownerParagraph(int id, Paragraph *) const;
648 };
649
650
651 /* returns a pointer to the row near the specified y-coordinate
652  * (relative to the whole text). y is set to the real beginning
653  * of this row */
654 inline
655 Row * LyXText::getRowNearY(int & y) const
656 {
657         // If possible we should optimize this method. (Lgb)
658         Row * tmprow = firstrow;
659         int tmpy = 0;
660         
661         while (tmprow->next() && tmpy + tmprow->height() <= y) {
662                 tmpy += tmprow->height();
663                 tmprow = tmprow->next();
664         }
665         
666         y = tmpy;   // return the real y
667         return tmprow;
668 }
669 #endif