]> git.lyx.org Git - lyx.git/blob - src/paragraph_funcs.C
Fix natbib bug spotted by JMarc.
[lyx.git] / src / paragraph_funcs.C
1 /**
2  * \file paragraph_funcs.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS
9  */
10
11 #include <config.h>
12
13 #include "paragraph_funcs.h"
14 #include "paragraph_pimpl.h"
15 #include "buffer.h"
16 #include "ParagraphParameters.h"
17 #include "lyxtextclasslist.h"
18 #include "debug.h"
19
20 using lyx::pos_type;
21 //using lyx::layout_type;
22 using std::endl;
23
24
25 void breakParagraph(BufferParams const & bparams,
26                     Paragraph * par,
27                     pos_type pos,
28                     int flag)
29 {
30         // create a new paragraph
31         Paragraph * tmp = new Paragraph(par);
32         // without doing that we get a crash when typing <Return> at the
33         // end of a paragraph
34         tmp->layout(bparams.getLyXTextClass().defaultLayout());
35         // remember to set the inset_owner
36         tmp->setInsetOwner(par->inInset());
37
38         if (bparams.tracking_changes)
39                 tmp->trackChanges();
40  
41         // this is an idea for a more userfriendly layout handling, I will
42         // see what the users say
43
44         // layout stays the same with latex-environments
45         if (flag) {
46                 tmp->layout(par->layout());
47                 tmp->setLabelWidthString(par->params().labelWidthString());
48         }
49
50         bool const isempty = (par->layout()->keepempty && par->empty());
51
52         if (!isempty && (par->size() > pos || par->empty() || flag == 2)) {
53                 tmp->layout(par->layout());
54                 tmp->params().align(par->params().align());
55                 tmp->setLabelWidthString(par->params().labelWidthString());
56
57                 tmp->params().lineBottom(par->params().lineBottom());
58                 par->params().lineBottom(false);
59                 tmp->params().pagebreakBottom(par->params().pagebreakBottom());
60                 par->params().pagebreakBottom(false);
61                 tmp->params().spaceBottom(par->params().spaceBottom());
62                 par->params().spaceBottom(VSpace(VSpace::NONE));
63
64                 tmp->params().depth(par->params().depth());
65                 tmp->params().noindent(par->params().noindent());
66
67                 // copy everything behind the break-position
68                 // to the new paragraph
69
70 #ifdef WITH_WARNINGS
71 #warning this seems wrong
72 #endif
73                 /* FIXME: if !keepempty, empty() == true, then we reach
74                  * here with size() == 0. So pos_end becomes - 1. Why
75                  * doesn't this cause problems ???
76                  */
77                 pos_type pos_end = par->size() - 1;
78                 pos_type i = pos;
79                 pos_type j = pos;
80
81                 for (; i <= pos_end; ++i) {
82                         Change::Type change(par->lookupChange(i));
83                         par->cutIntoMinibuffer(bparams, i);
84                         if (tmp->insertFromMinibuffer(j - pos)) {
85                                 tmp->pimpl_->setChange(j - pos, change);
86                                 ++j;
87                         }
88                 }
89                 for (i = pos_end; i >= pos; --i) {
90                         par->pimpl_->eraseIntern(i);
91                 }
92         }
93
94         if (pos)
95                 return;
96
97         tmp->params().lineTop(par->params().lineTop());
98         tmp->params().pagebreakTop(par->params().pagebreakTop());
99         tmp->params().spaceTop(par->params().spaceTop());
100         tmp->bibkey = par->bibkey;
101
102         par->bibkey = 0;
103         par->params().clear();
104
105         par->layout(bparams.getLyXTextClass().defaultLayout());
106
107         // layout stays the same with latex-environments
108         if (flag) {
109                 par->layout(tmp->layout());
110                 par->setLabelWidthString(tmp->params().labelWidthString());
111                 par->params().depth(tmp->params().depth());
112         }
113
114         // subtle, but needed to get empty pars working right
115         if (bparams.tracking_changes) {
116                 if (!par->size()) {
117                         par->cleanChanges();
118                 } else if (!tmp->size()) {
119                         tmp->cleanChanges();
120                 }
121         }
122 }
123
124
125 void breakParagraphConservative(BufferParams const & bparams,
126                                 Paragraph * par,
127                                 pos_type pos)
128 {
129         // create a new paragraph
130         Paragraph * tmp = new Paragraph(par);
131         tmp->makeSameLayout(par);
132
133         // When can pos > Last()?
134         // I guess pos == Last() is possible.
135         if (par->size() > pos) {
136                 // copy everything behind the break-position to the new
137                 // paragraph
138                 pos_type pos_end = par->size() - 1;
139
140                 for (pos_type i = pos, j = pos; i <= pos_end; ++i) {
141                         par->cutIntoMinibuffer(bparams, i);
142                         if (tmp->insertFromMinibuffer(j - pos))
143                                 ++j;
144                 }
145
146                 for (pos_type k = pos_end; k >= pos; --k) {
147                         par->erase(k);
148                 }
149         }
150 }
151
152
153 void mergeParagraph(BufferParams const & bparams, Paragraph * par)
154 {
155         Paragraph * the_next = par->next();
156
157         // first the DTP-stuff
158         par->params().lineBottom(the_next->params().lineBottom());
159         par->params().spaceBottom(the_next->params().spaceBottom());
160         par->params().pagebreakBottom(the_next->params().pagebreakBottom());
161
162         pos_type pos_end = the_next->size() - 1;
163         pos_type pos_insert = par->size();
164
165         // ok, now copy the paragraph
166         for (pos_type i = 0, j = 0; i <= pos_end; ++i) {
167                 the_next->cutIntoMinibuffer(bparams, i);
168                 if (par->insertFromMinibuffer(pos_insert + j))
169                         ++j;
170         }
171
172         // delete the next paragraph
173         Paragraph * ppar = the_next->previous();
174         Paragraph * npar = the_next->next();
175         delete the_next;
176         ppar->next(npar);
177 }
178
179
180 #if 0
181 Paragraph * depthHook(Paragraph * par, Paragraph::depth_type depth)
182 {
183         Paragraph * newpar = par;
184
185         do {
186                 newpar = newpar->previous();
187         } while (newpar && newpar->getDepth() > depth);
188
189         if (!newpar) {
190                 if (par->previous() || par->getDepth())
191                         lyxerr << "Error (depthHook): "
192                                << "no hook." << endl;
193                 newpar = par;
194         }
195         return newpar;
196 }
197
198
199 Paragraph * outerHook(Paragraph * par)
200 {
201         if (!par->getDepth())
202                 return 0;
203         return depthHook(par, Paragraph::depth_type(par->getDepth() - 1));
204 }
205
206
207 bool isFirstInSequence(Paragraph * par)
208 {
209         Paragraph const * dhook = depthHook(par, par->getDepth());
210         return (dhook == par
211                 || dhook->getLayout() != par->getLayout()
212                 || dhook->getDepth() != par->getDepth());
213 }
214
215
216 int getEndLabel(Paragraph * para, BufferParams const & bparams)
217 {
218         Paragraph * par = para;
219         while (par) {
220                 Paragraph::depth_type par_depth = par->getDepth();
221                 layout_type layout = par->getLayout();
222                 int const endlabeltype =
223                         textclasslist.Style(bparams.textclass,
224                                             layout).endlabeltype;
225                 if (endlabeltype != END_LABEL_NO_LABEL) {
226                         if (!para->next())
227                                 return endlabeltype;
228
229                         Paragraph::depth_type const next_depth =
230                                 para->next()->getDepth();
231                         if (par_depth > next_depth ||
232                             (par_depth == next_depth
233                              && layout != para->next()->getLayout()))
234                                 return endlabeltype;
235                         break;
236                 }
237                 if (par_depth == 0)
238                         break;
239                 par = outerHook(par);
240         }
241         return END_LABEL_NO_LABEL;
242 }
243 #endif