]> git.lyx.org Git - lyx.git/blob - src/CutAndPaste.C
whitespace changes;
[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 #include "CutAndPaste.h"
13 #include "BufferView.h"
14 #include "buffer.h"
15 #include "paragraph.h"
16 #include "insets/inseterror.h"
17 #include "lyx_gui_misc.h"
18 #include "lyxcursor.h"
19 #include "gettext.h"
20
21 #ifdef __GNUG__
22 #pragma implementation
23 #endif
24
25 using std::pair;
26 using lyx::pos_type;
27
28 extern BufferView * current_view;
29
30 // Jürgen, note that this means that you cannot currently have a list
31 // of selections cut/copied. So IMHO later we should have a
32 // list/vector/deque that we could store
33 // struct selection_item {
34 //       Paragraph * buf;
35 //       LyXTextClassList::size_type textclass;
36 // };
37 // in and some method of choosing beween them (based on the first few chars
38 // in the selection probably.) This would be a nice feature and quite
39 // easy to implement. (Lgb)
40 //
41 // Sure but I just cleaned up this code for now with the same functionality
42 // as before. I also want to add a XClipboard function so that we can copy
43 // text from LyX to some other X-application in the form of ASCII or in the
44 // form of LaTeX (or Docbook depending on the document-class!). Think how nice
45 // it could be to select a math-inset do a "Copy to X-Clipboard as LaTeX" and
46 // then do a middle mouse button click in the application you want and have
47 // the whole formula there in LaTeX-Code. (Jug)
48
49 namespace {
50
51 Paragraph * buf = 0;
52 LyXTextClassList::size_type textclass = 0;
53
54 // for now here this should be in another Cut&Paste Class!
55 // Jürgen, I moved this out of CutAndPaste since it does not operate on any
56 // member of the CutAndPaste class and in addition it was private.
57 // Perhaps it even should take a parameter? (Lgb)
58 void DeleteBuffer()
59 {
60         if (!buf)
61                 return;
62         
63         Paragraph * tmppar;
64         
65         while (buf) {
66                 tmppar =  buf;
67                 buf = buf->next();
68                 delete tmppar;
69         }
70         buf = 0;
71 }
72
73 } // namespace anon
74
75
76 bool CutAndPaste::cutSelection(Paragraph * startpar, Paragraph ** endpar,
77                                int start, int & end, char tc, bool doclear,
78                                                            bool realcut)
79 {
80         if (!startpar || (start > startpar->size()))
81                 return false;
82         
83         if (realcut)
84                 DeleteBuffer();
85         
86         textclass = tc;
87         
88         if (!(*endpar) || startpar == (*endpar)) {
89                 // only within one paragraph
90                 if (realcut)
91                         buf = new Paragraph;
92                 pos_type i = start;
93                 if (end > startpar->size())
94                         end = startpar->size();
95                 for (; i < end; ++i) {
96                         if (realcut)
97                                 startpar->copyIntoMinibuffer(*current_view->buffer(),
98                                                              start);
99                         startpar->erase(start);
100                         if (realcut)
101                                 buf->insertFromMinibuffer(buf->size());
102                 }
103                 end = start - 1;
104         } else {
105                 // more than one paragraph
106                 (*endpar)->breakParagraphConservative(current_view->buffer()->params,
107                                                       end);
108                 *endpar = (*endpar)->next();
109                 end = 0;
110                 
111                 startpar->breakParagraphConservative(current_view->buffer()->params,
112                                                      start);
113                 
114                 // store the selection
115                 if (realcut) {
116                         buf = startpar->next();
117                         buf->previous(0);
118                 } else {
119                         startpar->next()->previous(0);
120                 }
121                 (*endpar)->previous()->next(0);
122                 
123                 // cut the selection
124                 startpar->next(*endpar);
125                 
126                 (*endpar)->previous(startpar);
127                 
128                 // the cut selection should begin with standard layout
129                 if (realcut)
130                         buf->clear(); 
131                 
132                 // paste the paragraphs again, if possible
133                 if (doclear)
134                         startpar->next()->stripLeadingSpaces(textclass);
135                 if (startpar->hasSameLayout(startpar->next()) ||
136                     !startpar->next()->size()) {
137                         startpar->pasteParagraph(current_view->buffer()->params);
138                         (*endpar) = startpar; // this because endpar gets deleted here!
139                 }
140         }
141         return true;
142 }
143
144
145 bool CutAndPaste::copySelection(Paragraph * startpar, Paragraph * endpar,
146                                 int start, int end, char tc)
147 {
148         if (!startpar || (start > startpar->size()))
149                 return false;
150         
151         DeleteBuffer();
152         
153         textclass = tc;
154         
155         if (!endpar || startpar == endpar) {
156                 // only within one paragraph
157                 buf = new Paragraph;
158                 pos_type i = start;
159                 if (end > startpar->size())
160                         end = startpar->size();
161                 for (; i < end; ++i) {
162                         startpar->copyIntoMinibuffer(*current_view->buffer(), i);
163                         buf->insertFromMinibuffer(buf->size());
164                 }
165         } else {
166                 // copy more than one paragraph
167                 // clone the paragraphs within the selection
168                 Paragraph * tmppar = startpar;
169                 buf = new Paragraph(*tmppar, false);
170                 Paragraph * tmppar2 = buf;
171                 
172                 while (tmppar != endpar
173                        && tmppar->next()) {
174                         tmppar = tmppar->next();
175                         tmppar2->next(new Paragraph(*tmppar, false));
176                         tmppar2->next()->previous(tmppar2);
177                         tmppar2 = tmppar2->next();
178                 }
179                 tmppar2->next(0);
180                 
181                 // the buf paragraph is too big
182                 pos_type tmpi2 = start;
183                 for (; tmpi2; --tmpi2)
184                         buf->erase(0);
185                 
186                 // now tmppar 2 is too big, delete all after end
187                 tmpi2 = end;
188                 while (tmppar2->size() > tmpi2) {
189                         tmppar2->erase(tmppar2->size() - 1);
190                 }
191         }
192         return true;
193 }
194
195
196 bool CutAndPaste::pasteSelection(Paragraph ** par, Paragraph ** endpar,
197                                  int & pos, char tc)
198 {
199         if (!checkPastePossible(*par))
200                 return false;
201         
202         if (pos > (*par)->size())
203                 pos = (*par)->size();
204         
205         // Paragraph * tmpbuf;
206         Paragraph * tmppar = *par;
207         int tmppos = pos;
208         
209         // There are two cases: cutbuffer only one paragraph or many
210         if (!buf->next()) {
211                 // only within a paragraph
212                 Paragraph * tmpbuf = new Paragraph(*buf, false);
213                 
214                 // Some provisions should be done here for checking
215                 // if we are inserting at the beginning of a
216                 // paragraph. If there are a space at the beginning
217                 // of the text to insert and we are inserting at
218                 // the beginning of the paragraph the space should
219                 // be removed.
220                 while (buf->size()) {
221                         // This is an attempt to fix the
222                         // "never insert a space at the
223                         // beginning of a paragraph" problem.
224                         if (!tmppos && buf->isLineSeparator(0)) {
225                                 buf->erase(0);
226                         } else {
227                                 buf->cutIntoMinibuffer(current_view->buffer()->params, 0);
228                                 buf->erase(0);
229                                 if (tmppar->insertFromMinibuffer(tmppos))
230                                         ++tmppos;
231                         }
232                 }
233                 delete buf;
234                 buf = tmpbuf;
235                 *endpar = tmppar->next();
236                 pos = tmppos;
237         } else {
238                 // many paragraphs
239                 
240                 // make a copy of the simple cut_buffer
241                 Paragraph * tmpbuf = buf;
242                 Paragraph * simple_cut_clone = new Paragraph(*tmpbuf, false);
243                 Paragraph * tmpbuf2 = simple_cut_clone;
244                 
245                 while (tmpbuf->next()) {
246                         tmpbuf = tmpbuf->next();
247                         tmpbuf2->next(new Paragraph(*tmpbuf, false));
248                         tmpbuf2->next()->previous(tmpbuf2);
249                         tmpbuf2 = tmpbuf2->next();
250                 }
251                 
252                 // make sure there is no class difference
253                 SwitchLayoutsBetweenClasses(textclass, tc, buf);
254                 
255                 // make the buf exactly the same layout than
256                 // the cursor paragraph
257                 buf->makeSameLayout(*par);
258                 
259                 // find the end of the buffer
260                 Paragraph * lastbuffer = buf;
261                 while (lastbuffer->next())
262                         lastbuffer = lastbuffer->next();
263                 
264                 bool paste_the_end = false;
265                 
266                 // open the paragraph for inserting the buf
267                 // if necessary
268                 if (((*par)->size() > pos) || !(*par)->next()) {
269                         (*par)->breakParagraphConservative(current_view->buffer()->params,
270                                                            pos);
271                         paste_the_end = true;
272                 }
273                 // set the end for redoing later
274                 *endpar = (*par)->next()->next();
275                 
276                 // paste it!
277                 lastbuffer->next((*par)->next());
278                 (*par)->next()->previous(lastbuffer);
279                 
280                 (*par)->next(buf);
281                 buf->previous(*par);
282                 
283                 if ((*par)->next() == lastbuffer)
284                         lastbuffer = *par;
285                 
286                 (*par)->pasteParagraph(current_view->buffer()->params);
287                 // store the new cursor position
288                 *par = lastbuffer;
289                 pos = lastbuffer->size();
290                 // maybe some pasting
291                 if (lastbuffer->next() && paste_the_end) {
292                         if (lastbuffer->next()->hasSameLayout(lastbuffer)) {
293                                 lastbuffer->pasteParagraph(current_view->buffer()->params);
294                         } else if (!lastbuffer->next()->size()) {
295                                 lastbuffer->next()->makeSameLayout(lastbuffer);
296                                 lastbuffer->pasteParagraph(current_view->buffer()->params);
297                         } else if (!lastbuffer->size()) {
298                                 lastbuffer->makeSameLayout(lastbuffer->next());
299                                 lastbuffer->pasteParagraph(current_view->buffer()->params);
300                         } else
301                                 lastbuffer->next()->stripLeadingSpaces(tc);
302                 }
303                 // restore the simple cut buffer
304                 buf = simple_cut_clone;
305         }
306         
307         return true;
308 }
309
310
311 int CutAndPaste::nrOfParagraphs()
312 {
313         if (!buf)
314                 return 0;
315         
316         int n = 1;
317         Paragraph * tmppar = buf;
318         while(tmppar->next()) {
319                 ++n;
320                 tmppar = tmppar->next();
321         }
322         return n;
323 }
324
325
326 int CutAndPaste::SwitchLayoutsBetweenClasses(LyXTextClassList::size_type c1,
327                                              LyXTextClassList::size_type c2,
328                                              Paragraph * par)
329 {
330         int ret = 0;
331         if (!par || c1 == c2)
332                 return ret;
333         
334         while (par) {
335                 string const name = textclasslist.NameOfLayout(c1,
336                                                                par->layout);
337                 int lay = 0;
338                 pair<bool, LyXTextClass::LayoutList::size_type> pp =
339                         textclasslist.NumberOfLayout(c2, name);
340                 if (pp.first) {
341                         lay = pp.second;
342                 } else { // layout not found
343                         // use default layout "Standard" (0)
344                         lay = 0;
345                 }
346                 par->layout = lay;
347                 
348                 if (name != textclasslist.NameOfLayout(c2, par->layout)) {
349                         ++ret;
350                         string const s = _("Layout had to be changed from\n")
351                                 + name + _(" to ")
352                                 + textclasslist.NameOfLayout(c2, par->layout)
353                                 + _("\nbecause of class conversion from\n")
354                                 + textclasslist.NameOfClass(c1) + _(" to ")
355                                 + textclasslist.NameOfClass(c2);
356                         InsetError * new_inset = new InsetError(s);
357                         par->insertInset(0, new_inset);
358                 }
359                 par = par->next();
360         }
361         return ret;
362 }
363
364
365 bool CutAndPaste::checkPastePossible(Paragraph *)
366 {
367         if (!buf) return false;
368         
369         return true;
370 }