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