]> git.lyx.org Git - lyx.git/blob - src/CutAndPaste.C
makefile cleanup, and avoid some warnings
[lyx.git] / src / CutAndPaste.C
1 /* This file is part of
2  * ======================================================
3  *
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995-2001 The LyX Team.
7  *
8  * ====================================================== */
9
10 #include <config.h>
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 #include "CutAndPaste.h"
17 //#include "debug.h"
18 #include "BufferView.h"
19 #include "buffer.h"
20 #include "paragraph.h"
21 #include "ParagraphParameters.h"
22 #include "lyxtext.h"
23 #include "lyxcursor.h"
24 #include "gettext.h"
25 #include "iterators.h"
26 #include "lyxtextclasslist.h"
27
28 #include "insets/inseterror.h"
29
30 using std::pair;
31 using lyx::pos_type;
32 using lyx::textclass_type;
33
34 extern BufferView * current_view;
35
36 // Jürgen, note that this means that you cannot currently have a list
37 // of selections cut/copied. So IMHO later we should have a
38 // list/vector/deque that we could store
39 // struct selection_item {
40 //       Paragraph * buf;
41 //       LyXTextClassList::size_type textclass;
42 // };
43 // in and some method of choosing beween them (based on the first few chars
44 // in the selection probably.) This would be a nice feature and quite
45 // easy to implement. (Lgb)
46 //
47 // Sure but I just cleaned up this code for now with the same functionality
48 // as before. I also want to add a XClipboard function so that we can copy
49 // text from LyX to some other X-application in the form of ASCII or in the
50 // form of LaTeX (or Docbook depending on the document-class!). Think how nice
51 // it could be to select a math-inset do a "Copy to X-Clipboard as LaTeX" and
52 // then do a middle mouse button click in the application you want and have
53 // the whole formula there in LaTeX-Code. (Jug)
54
55 namespace {
56
57 Paragraph * buf = 0;
58 textclass_type textclass = 0;
59
60 // for now here this should be in another Cut&Paste Class!
61 // Jürgen, I moved this out of CutAndPaste since it does not operate on any
62 // member of the CutAndPaste class and in addition it was private.
63 // Perhaps it even should take a parameter? (Lgb)
64 void DeleteBuffer()
65 {
66         if (!buf)
67                 return;
68
69         Paragraph * tmppar;
70
71         while (buf) {
72                 tmppar =  buf;
73                 buf = buf->next();
74                 delete tmppar;
75         }
76         buf = 0;
77 }
78
79 } // namespace anon
80
81
82 bool CutAndPaste::cutSelection(Paragraph * startpar, Paragraph ** endpar,
83                                int start, int & end, char tc, bool doclear,
84                                                            bool realcut)
85 {
86         if (!startpar || (start > startpar->size()))
87                 return false;
88
89         if (realcut)
90                 DeleteBuffer();
91
92         textclass = tc;
93
94         if (!(*endpar) || startpar == (*endpar)) {
95                 // only within one paragraph
96                 if (realcut) {
97                         buf = new Paragraph;
98                         buf->layout(startpar->layout());
99                 }
100                 pos_type i = start;
101                 if (end > startpar->size())
102                         end = startpar->size();
103                 for (; i < end; ++i) {
104                         if (realcut)
105                                 startpar->copyIntoMinibuffer(*current_view->buffer(),
106                                                              start);
107                         startpar->erase(start);
108                         if (realcut)
109                                 buf->insertFromMinibuffer(buf->size());
110                 }
111                 end = start - 1;
112         } else {
113                 // more than one paragraph
114                 (*endpar)->breakParagraphConservative(current_view->buffer()->params,
115                                                       end);
116                 *endpar = (*endpar)->next();
117                 end = 0;
118
119                 startpar->breakParagraphConservative(current_view->buffer()->params,
120                                                      start);
121
122                 // store the selection
123                 if (realcut) {
124                         buf = startpar->next();
125                         buf->previous(0);
126                 } else {
127                         startpar->next()->previous(0);
128                 }
129                 (*endpar)->previous()->next(0);
130
131                 // cut the selection
132                 startpar->next(*endpar);
133
134                 (*endpar)->previous(startpar);
135
136                 // the cut selection should begin with standard layout
137                 if (realcut) {
138                         buf->params().clear();
139                         buf->bibkey = 0;
140                         buf->layout(textclasslist[current_view->buffer()->params.textclass].defaultLayoutName());
141                 }
142
143                 // paste the paragraphs again, if possible
144                 if (doclear)
145                         startpar->next()->stripLeadingSpaces(textclass);
146                 if (startpar->hasSameLayout(startpar->next()) ||
147                     !startpar->next()->size()) {
148                         startpar->pasteParagraph(current_view->buffer()->params);
149                         (*endpar) = startpar; // this because endpar gets deleted here!
150                 }
151                 // this paragraph's are of noone's owner!
152                 Paragraph * p = buf;
153                 while (p) {
154                         p->setInsetOwner(0);
155                         p = p->next();
156                 }
157         }
158         return true;
159 }
160
161
162 bool CutAndPaste::copySelection(Paragraph * startpar, Paragraph * endpar,
163                                 int start, int end, char tc)
164 {
165         if (!startpar || (start > startpar->size()))
166                 return false;
167
168         DeleteBuffer();
169
170         textclass = tc;
171
172         if (!endpar || startpar == endpar) {
173                 // only within one paragraph
174                 buf = new Paragraph;
175                 buf->layout(startpar->layout());
176                 pos_type i = start;
177                 if (end > startpar->size())
178                         end = startpar->size();
179                 for (; i < end; ++i) {
180                         startpar->copyIntoMinibuffer(*current_view->buffer(), i);
181                         buf->insertFromMinibuffer(buf->size());
182                 }
183         } else {
184                 // copy more than one paragraph
185                 // clone the paragraphs within the selection
186                 Paragraph * tmppar = startpar;
187                 buf = new Paragraph(*tmppar, false);
188                 Paragraph * tmppar2 = buf;
189
190                 while (tmppar != endpar
191                        && tmppar->next()) {
192                         tmppar = tmppar->next();
193                         tmppar2->next(new Paragraph(*tmppar, false));
194                         tmppar2->next()->previous(tmppar2);
195                         tmppar2 = tmppar2->next();
196                 }
197                 tmppar2->next(0);
198
199                 // the buf paragraph is too big
200                 pos_type tmpi2 = start;
201                 for (; tmpi2; --tmpi2)
202                         buf->erase(0);
203
204                 // now tmppar 2 is too big, delete all after end
205                 tmpi2 = end;
206                 while (tmppar2->size() > tmpi2) {
207                         tmppar2->erase(tmppar2->size() - 1);
208                 }
209                 // this paragraph's are of noone's owner!
210                 tmppar = buf;
211                 while (tmppar) {
212                         tmppar->setInsetOwner(0);
213                         tmppar = tmppar->next();
214                 }
215         }
216         return true;
217 }
218
219
220 bool CutAndPaste::pasteSelection(Paragraph ** par, Paragraph ** endpar,
221                                  int & pos, char tc)
222 {
223         if (!checkPastePossible(*par))
224                 return false;
225
226         if (pos > (*par)->size())
227                 pos = (*par)->size();
228
229 #if 0
230         // Paragraph * tmpbuf;
231         Paragraph * tmppar = *par;
232         int tmppos = pos;
233
234         // There are two cases: cutbuffer only one paragraph or many
235         if (!buf->next()) {
236                 // only within a paragraph
237                 Paragraph * tmpbuf = new Paragraph(*buf, false);
238
239                 // Some provisions should be done here for checking
240                 // if we are inserting at the beginning of a
241                 // paragraph. If there are a space at the beginning
242                 // of the text to insert and we are inserting at
243                 // the beginning of the paragraph the space should
244                 // be removed.
245                 while (buf->size()) {
246                         // This is an attempt to fix the
247                         // "never insert a space at the
248                         // beginning of a paragraph" problem.
249                         if (!tmppos && buf->isLineSeparator(0)) {
250                                 buf->erase(0);
251                         } else {
252                                 buf->cutIntoMinibuffer(current_view->buffer()->params, 0);
253                                 buf->erase(0);
254                                 if (tmppar->insertFromMinibuffer(tmppos))
255                                         ++tmppos;
256                         }
257                 }
258                 delete buf;
259                 buf = tmpbuf;
260                 *endpar = tmppar->next();
261                 pos = tmppos;
262         } else
263 #endif
264         {
265                 // many paragraphs
266
267                 // make a copy of the simple cut_buffer
268                 Paragraph * tmpbuf = buf;
269                 Paragraph * simple_cut_clone = new Paragraph(*tmpbuf, false);
270                 Paragraph * tmpbuf2 = simple_cut_clone;
271
272                 while (tmpbuf->next()) {
273                         tmpbuf = tmpbuf->next();
274                         tmpbuf2->next(new Paragraph(*tmpbuf, false));
275                         tmpbuf2->next()->previous(tmpbuf2);
276                         tmpbuf2 = tmpbuf2->next();
277                 }
278
279                 // now remove all out of the buffer which is NOT allowed in the
280                 // new environment and set also another font if that is required
281                 tmpbuf = buf;
282                 int depth_delta = (*par)->params().depth() - tmpbuf->params().depth();
283                 // temporary set *par as previous of tmpbuf as we might have to realize
284                 // the font.
285                 tmpbuf->previous(*par);
286                 Paragraph::depth_type max_depth = (*par)->getMaxDepthAfter(current_view->buffer());
287                 while(tmpbuf) {
288                         // if we have a negative jump so that the depth would go below
289                         // 0 depth then we have to redo the delta to this new max depth
290                         // level so that subsequent paragraphs are aligned correctly to
291                         // this paragraph at level 0.
292                         if ((static_cast<int>(tmpbuf->params().depth()) + depth_delta) < 0)
293                                 depth_delta = 0;
294                         // set the right depth so that we are not too deep or shallow.
295                         tmpbuf->params().depth(tmpbuf->params().depth() + depth_delta);
296                         if (tmpbuf->params().depth() > max_depth)
297                                 tmpbuf->params().depth(max_depth);
298                         // only set this from the 2nd on as the 2nd depends for maxDepth
299                         // still on *par
300                         if (tmpbuf->previous() != (*par))
301                                 max_depth = tmpbuf->getMaxDepthAfter(current_view->buffer());
302                         // set the inset owner of this paragraph
303                         tmpbuf->setInsetOwner((*par)->inInset());
304                         for(pos_type i = 0; i < tmpbuf->size(); ++i) {
305                                 if (tmpbuf->getChar(i) == Paragraph::META_INSET) {
306                                         if (!(*par)->insetAllowed(tmpbuf->getInset(i)->lyxCode()))
307                                         {
308                                                 tmpbuf->erase(i--);
309                                         }
310                                 } else {
311                                         LyXFont f1 = tmpbuf->getFont(current_view->buffer()->params,i);
312                                         LyXFont f2 = f1;
313                                         if (!(*par)->checkInsertChar(f1)) {
314                                                 tmpbuf->erase(i--);
315                                         } else if (f1 != f2) {
316                                                 tmpbuf->setFont(i, f1);
317                                         }
318                                 }
319                         }
320                         tmpbuf = tmpbuf->next();
321                 }
322                 // now reset it to 0
323                 buf->previous(0);
324
325                 // make sure there is no class difference
326                 SwitchLayoutsBetweenClasses(textclass, tc, buf,
327                                             current_view->buffer()->params);
328
329                 // make the buf exactly the same layout than
330                 // the cursor paragraph
331                 buf->makeSameLayout(*par);
332
333                 // find the end of the buffer
334                 Paragraph * lastbuffer = buf;
335                 while (lastbuffer->next())
336                         lastbuffer = lastbuffer->next();
337
338                 bool paste_the_end = false;
339
340                 // open the paragraph for inserting the buf
341                 // if necessary
342                 if (((*par)->size() > pos) || !(*par)->next()) {
343                         (*par)->breakParagraphConservative(current_view->buffer()->params,
344                                                            pos);
345                         paste_the_end = true;
346                 }
347                 // set the end for redoing later
348                 *endpar = (*par)->next()->next();
349
350                 // paste it!
351                 lastbuffer->next((*par)->next());
352                 (*par)->next()->previous(lastbuffer);
353
354                 (*par)->next(buf);
355                 buf->previous(*par);
356
357                 if ((*par)->next() == lastbuffer)
358                         lastbuffer = *par;
359
360                 (*par)->pasteParagraph(current_view->buffer()->params);
361                 // store the new cursor position
362                 *par = lastbuffer;
363                 pos = lastbuffer->size();
364                 // maybe some pasting
365                 if (lastbuffer->next() && paste_the_end) {
366                         if (lastbuffer->next()->hasSameLayout(lastbuffer)) {
367                                 lastbuffer->pasteParagraph(current_view->buffer()->params);
368                         } else if (!lastbuffer->next()->size()) {
369                                 lastbuffer->next()->makeSameLayout(lastbuffer);
370                                 lastbuffer->pasteParagraph(current_view->buffer()->params);
371                         } else if (!lastbuffer->size()) {
372                                 lastbuffer->makeSameLayout(lastbuffer->next());
373                                 lastbuffer->pasteParagraph(current_view->buffer()->params);
374                         } else
375                                 lastbuffer->next()->stripLeadingSpaces(tc);
376                 }
377                 // restore the simple cut buffer
378                 buf = simple_cut_clone;
379         }
380
381         return true;
382 }
383
384
385 int CutAndPaste::nrOfParagraphs()
386 {
387         if (!buf)
388                 return 0;
389
390         int n = 1;
391         Paragraph * tmppar = buf;
392         while (tmppar->next()) {
393                 ++n;
394                 tmppar = tmppar->next();
395         }
396         return n;
397 }
398
399
400 int CutAndPaste::SwitchLayoutsBetweenClasses(textclass_type c1,
401                                              textclass_type c2,
402                                              Paragraph * par,
403                                              BufferParams const & /*bparams*/)
404 {
405         int ret = 0;
406         if (!par || c1 == c2)
407                 return ret;
408
409         ParIterator end = ParIterator();
410         for (ParIterator it = ParIterator(par); it != end; ++it) {
411                 par = *it;
412                 string const name = par->layout();
413                 LyXTextClass const & tclass = textclasslist[c2];
414
415                 bool hasLayout = tclass.hasLayout(name);
416
417                 string lay = tclass.defaultLayoutName();
418                 if (hasLayout) {
419                         lay = name;
420                 } else {
421                         // not found: use default layout
422                         lay = tclass.defaultLayoutName();
423                 }
424                 par->layout(lay);
425
426                 if (name != par->layout()) {
427                         ++ret;
428                         string const s = _("Layout had to be changed from\n")
429                                 + name + _(" to ")
430                                 + par->layout()
431                                 + _("\nbecause of class conversion from\n")
432                                 + textclasslist[c1].name() + _(" to ")
433                                 + textclasslist[c2].name();
434                         InsetError * new_inset = new InsetError(s);
435                         LyXText * txt = current_view->getLyXText();
436                         LyXCursor cur = txt->cursor;
437                         txt->setCursorIntern(current_view, par, 0);
438                         txt->insertInset(current_view, new_inset);
439                         txt->fullRebreak(current_view);
440                         txt->setCursorIntern(current_view, cur.par(), cur.pos());
441                 }
442         }
443         return ret;
444 }
445
446
447 bool CutAndPaste::checkPastePossible(Paragraph *)
448 {
449         if (!buf) return false;
450
451         return true;
452 }