1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995-2000 The LyX Team.
8 * ====================================================== */
12 #include "CutAndPaste.h"
13 #include "BufferView.h"
15 #include "lyxparagraph.h"
16 #include "insets/inseterror.h"
17 #include "lyx_gui_misc.h"
18 #include "lyxcursor.h"
21 #pragma implementation
26 extern BufferView * current_view;
28 // Jürgen, note that this means that you cannot currently have a list
29 // of selections cut/copied. So IMHO later we should have a
30 // list/vector/deque that we could store
31 // struct selection_item {
32 // LyXParagraph * buf;
33 // LyXTextClassList::size_type textclass;
35 // in and some method of choosing beween them (based on the first few chars
36 // in the selection probably.) This would be a nice feature and quite
37 // easy to implement. (Lgb)
39 // Sure but I just cleaned up this code for now with the same functionality
40 // as before. I also want to add a XClipboard function so that we can copy
41 // text from LyX to some other X-application in the form of ASCII or in the
42 // form of LaTeX (or Docbook depending on the document-class!). Think how nice
43 // it could be to select a math-inset do a "Copy to X-Clipboard as LaTeX" and
44 // then do a middle mouse button click in the application you want and have
45 // the whole formula there in LaTeX-Code. (Jug)
47 static LyXParagraph * buf = 0;
48 static LyXTextClassList::size_type textclass = 0;
50 // for now here this should be in another Cut&Paste Class!
51 // Jürgen, I moved this out of CutAndPaste since it does not operate on any
52 // member of the CutAndPaste class and in addition it was private.
53 // Perhaps it even should take a parameter? (Lgb)
60 LyXParagraph * tmppar;
71 bool CutAndPaste::cutSelection(LyXParagraph * startpar, LyXParagraph ** endpar,
72 int start, int & end, char tc, bool doclear)
74 if (!startpar || (start > startpar->Last()))
83 (startpar->ParFromPos(start) ==
84 (*endpar)->ParFromPos(end))
86 (startpar == (*endpar))
89 // only within one paragraph
90 buf = new LyXParagraph;
91 LyXParagraph::size_type i = start;
92 if (end > startpar->Last())
93 end = startpar->Last();
94 for (; i < end; ++i) {
95 startpar->CopyIntoMinibuffer(current_view->buffer()->params,
98 /* table stuff -- begin */
99 if (startpar->table && startpar->IsNewline(start)) {
102 /* table stuff -- end */
104 startpar->Erase(start);
108 buf->InsertFromMinibuffer(buf->Last());
111 // more than one paragraph
112 (*endpar)->BreakParagraphConservative(current_view->buffer()->params,
114 *endpar = (*endpar)->Next();
117 startpar->BreakParagraphConservative(current_view->buffer()->params,
120 // store the selection
122 buf = startpar->ParFromPos(start)->next;
124 buf = startpar->next;
127 (*endpar)->previous->next = 0;
131 startpar->ParFromPos(start)->next = (*endpar);
133 (*endpar)->previous = startpar->ParFromPos(start);
135 startpar->next = (*endpar);
137 (*endpar)->previous = startpar;
141 // care about footnotes
142 if (buf->footnoteflag) {
143 LyXParagraph * tmppar = buf;
145 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
146 tmppar = tmppar->next;
151 // the cut selection should begin with standard layout
154 // paste the paragraphs again, if possible
156 startpar->Next()->StripLeadingSpaces(textclass);
158 if (startpar->FirstPhysicalPar()->HasSameLayout(startpar->Next()) ||
160 if (startpar->HasSameLayout(startpar->Next()) ||
162 !startpar->Next()->Last()) {
164 startpar->ParFromPos(start)->PasteParagraph(current_view->buffer()->params);
166 startpar->PasteParagraph(current_view->buffer()->params);
168 (*endpar) = startpar; // this because endpar gets deleted here!
175 bool CutAndPaste::copySelection(LyXParagraph * startpar, LyXParagraph * endpar,
176 int start, int end, char tc)
178 if (!startpar || (start > startpar->Last()))
187 (startpar->ParFromPos(start) ==
188 (endpar)->ParFromPos(end))
193 // only within one paragraph
194 buf = new LyXParagraph;
195 LyXParagraph::size_type i = start;
196 if (end > startpar->Last())
197 end = startpar->Last();
198 for (; i < end; ++i) {
199 startpar->CopyIntoMinibuffer(current_view->buffer()->params, i);
200 buf->InsertFromMinibuffer(buf->Last());
203 // copy more than one paragraph
204 // clone the paragraphs within the selection
206 LyXParagraph * tmppar = startpar->ParFromPos(start);
208 LyXParagraph * tmppar = startpar;
210 buf = tmppar->Clone();
211 LyXParagraph * tmppar2 = buf;
215 tmppar != endpar->ParFromPos(end)
220 tmppar = tmppar->next;
221 tmppar2->next = tmppar->Clone();
222 tmppar2->next->previous = tmppar2;
223 tmppar2 = tmppar2->next;
228 // care about footnotes
229 if (buf->footnoteflag) {
232 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
233 tmppar = tmppar->next;
238 // the buf paragraph is too big
240 LyXParagraph::size_type tmpi2 = startpar->PositionInParFromPos(start);
242 LyXParagraph::size_type tmpi2 = start;
244 for (; tmpi2; --tmpi2)
247 // now tmppar 2 is too big, delete all after end
249 tmpi2 = endpar->PositionInParFromPos(end);
253 while (tmppar2->size() > tmpi2) {
254 tmppar2->Erase(tmppar2->size() - 1);
261 bool CutAndPaste::pasteSelection(LyXParagraph ** par, LyXParagraph ** endpar,
264 if (!checkPastePossible(*par, pos))
267 if (pos > (*par)->Last())
268 pos = (*par)->Last();
270 LyXParagraph * tmpbuf;
271 LyXParagraph * tmppar = *par;
274 // There are two cases: cutbuffer only one paragraph or many
276 // only within a paragraph
277 tmpbuf = buf->Clone();
279 /* table stuff -- begin */
280 bool table_too_small = false;
282 while (buf->size() && !table_too_small) {
283 if (buf->IsNewline(0)){
284 while((tmppos < tmppar->Last()) &&
285 !tmppar->IsNewline(tmppos))
288 if (tmppos < tmppar->Last())
291 table_too_small = true;
293 // This is an attempt to fix the
294 // "never insert a space at the
295 // beginning of a paragraph" problem.
296 if (!tmppos && buf->IsLineSeparator(0)) {
299 buf->CutIntoMinibuffer(current_view->buffer()->params, 0);
301 if (tmppar->InsertFromMinibuffer(tmppos))
307 /* table stuff -- end */
309 // Some provisions should be done here for checking
310 // if we are inserting at the beginning of a
311 // paragraph. If there are a space at the beginning
312 // of the text to insert and we are inserting at
313 // the beginning of the paragraph the space should
315 while (buf->size()) {
316 // This is an attempt to fix the
317 // "never insert a space at the
318 // beginning of a paragraph" problem.
319 if (!tmppos && buf->IsLineSeparator(0)) {
322 buf->CutIntoMinibuffer(current_view->buffer()->params, 0);
324 if (tmppar->InsertFromMinibuffer(tmppos))
333 *endpar = tmppar->Next();
338 // make a copy of the simple cut_buffer
340 LyXParagraph * simple_cut_clone = tmpbuf->Clone();
341 LyXParagraph * tmpbuf2 = simple_cut_clone;
343 if ((*par)->footnoteflag){
344 tmpbuf->footnoteflag = (*par)->footnoteflag;
345 tmpbuf->footnotekind = (*par)->footnotekind;
348 while (tmpbuf->next) {
349 tmpbuf = tmpbuf->next;
350 tmpbuf2->next = tmpbuf->Clone();
351 tmpbuf2->next->previous = tmpbuf2;
352 tmpbuf2 = tmpbuf2->next;
354 if ((*par)->footnoteflag){
355 tmpbuf->footnoteflag = (*par)->footnoteflag;
356 tmpbuf->footnotekind = (*par)->footnotekind;
361 // make sure there is no class difference
362 SwitchLayoutsBetweenClasses(textclass, tc, buf);
364 // make the buf exactly the same layout than
365 // the cursor paragraph
366 buf->MakeSameLayout(*par);
368 // find the end of the buffer
369 LyXParagraph * lastbuffer = buf;
370 while (lastbuffer->Next())
371 lastbuffer = lastbuffer->Next();
373 bool paste_the_end = false;
375 // open the paragraph for inserting the buf
377 if (((*par)->Last() > pos) || !(*par)->Next()) {
378 (*par)->BreakParagraphConservative(current_view->buffer()->params,
380 paste_the_end = true;
383 // set the end for redoing later
385 *endpar = (*par)->ParFromPos(pos)->next->Next();
388 lastbuffer->ParFromPos(lastbuffer->Last())->next =
389 (*par)->ParFromPos(pos)->next;
390 (*par)->ParFromPos(pos)->next->previous =
391 lastbuffer->ParFromPos(lastbuffer->Last());
393 (*par)->ParFromPos(pos)->next = buf;
394 buf->previous = (*par)->ParFromPos(pos);
396 if ((*par)->ParFromPos(pos)->Next() == lastbuffer)
399 (*par)->ParFromPos(pos)->PasteParagraph(current_view->buffer()->params);
401 *endpar = (*par)->next->Next();
404 lastbuffer->next = (*par)->next;
405 (*par)->next->previous = lastbuffer;
408 buf->previous = (*par);
410 if ((*par)->Next() == lastbuffer)
413 (*par)->PasteParagraph(current_view->buffer()->params);
415 // store the new cursor position
417 pos = lastbuffer->Last();
419 // maybe some pasting
420 if (lastbuffer->Next() && paste_the_end) {
422 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
423 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph(current_view->buffer()->params);
424 } else if (!lastbuffer->Next()->Last()) {
425 lastbuffer->Next()->MakeSameLayout(lastbuffer);
426 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph(current_view->buffer()->params);
427 } else if (!lastbuffer->Last()) {
428 lastbuffer->MakeSameLayout(lastbuffer->next);
429 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph(current_view->buffer()->params);
431 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
432 lastbuffer->PasteParagraph(current_view->buffer()->params);
433 } else if (!lastbuffer->Next()->Last()) {
434 lastbuffer->Next()->MakeSameLayout(lastbuffer);
435 lastbuffer->PasteParagraph(current_view->buffer()->params);
436 } else if (!lastbuffer->Last()) {
437 lastbuffer->MakeSameLayout(lastbuffer->next);
438 lastbuffer->PasteParagraph(current_view->buffer()->params);
441 lastbuffer->Next()->StripLeadingSpaces(tc);
443 // restore the simple cut buffer
444 buf = simple_cut_clone;
451 int CutAndPaste::nrOfParagraphs()
456 LyXParagraph * tmppar = buf;
457 while(tmppar->next) {
459 tmppar = tmppar->next;
465 int CutAndPaste::SwitchLayoutsBetweenClasses(LyXTextClassList::size_type c1,
466 LyXTextClassList::size_type c2,
470 if (!par || c1 == c2)
473 par = par->FirstPhysicalPar();
476 string name = textclasslist.NameOfLayout(c1, par->layout);
478 pair<bool, LyXTextClass::LayoutList::size_type> pp =
479 textclasslist.NumberOfLayout(c2, name);
482 } else { // layout not found
483 // use default layout "Standard" (0)
488 if (name != textclasslist.NameOfLayout(c2, par->layout)) {
490 string s = _("Layout had to be changed from\n")
492 + textclasslist.NameOfLayout(c2, par->layout)
493 + _("\nbecause of class conversion from\n")
494 + textclasslist.NameOfClass(c1) + _(" to ")
495 + textclasslist.NameOfClass(c2);
496 InsetError * new_inset = new InsetError(s);
497 par->InsertInset(0, new_inset);
506 bool CutAndPaste::checkPastePossible(LyXParagraph * par, int)
508 if (!buf) return false;
511 // be carefull with footnotes in footnotes
512 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
513 // check whether the cut_buffer includes a footnote
514 LyXParagraph * tmppar = buf;
515 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
516 tmppar = tmppar->next;
519 WriteAlert(_("Impossible operation"),
520 _("Can't paste float into float!"),
527 /* table stuff -- begin */
530 WriteAlert(_("Impossible operation"),
531 _("Table cell cannot include more than one paragraph!"),
536 /* table stuff -- end */