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 "lyxparagraph.h"
14 #include "insets/inseterror.h"
15 #include "lyx_gui_misc.h"
18 #pragma implementation
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;
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)
34 static LyXParagraph * buf = 0;
35 static LyXTextClassList::size_type textclass;
37 // for now here this should be in another Cut&Paste Class!
38 // Jürgen, I moved this out of CutAndPaste since it does not operate on any
39 // member of the CutAndPaste class and in addition it was private.
40 // Perhaps it even should take a parameter? (Lgb)
46 LyXParagraph * tmppar;
57 bool CutAndPaste::cutSelection(LyXParagraph * startpar, LyXParagraph ** endpar,
58 int start, int & end, char tc, bool doclear)
60 if (!startpar || (start > startpar->Last()))
67 if (!(*endpar) || (startpar->ParFromPos(start) ==
68 (*endpar)->ParFromPos(end))) {
69 // only within one paragraph
70 buf = new LyXParagraph;
71 LyXParagraph::size_type i = start;
72 if (end > startpar->Last())
73 end = startpar->Last();
74 for (; i < end; ++i) {
75 startpar->CopyIntoMinibuffer(start);
76 /* table stuff -- begin */
77 if (startpar->table && startpar->IsNewline(start)) {
80 /* table stuff -- end */
81 startpar->Erase(start);
83 buf->InsertFromMinibuffer(buf->Last());
86 // more than one paragraph
87 (*endpar)->BreakParagraphConservative(end);
88 *endpar = (*endpar)->Next();
91 startpar->BreakParagraphConservative(start);
93 // store the selection
94 buf = startpar->ParFromPos(start)->next;
96 (*endpar)->previous->next = 0;
99 startpar->ParFromPos(start)->next = (*endpar);
101 (*endpar)->previous = startpar->ParFromPos(start);
103 // care about footnotes
104 if (buf->footnoteflag) {
105 LyXParagraph * tmppar = buf;
107 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
108 tmppar = tmppar->next;
112 // the cut selection should begin with standard layout
115 // paste the paragraphs again, if possible
117 startpar->Next()->ClearParagraph();
118 if (startpar->FirstPhysicalPar()->HasSameLayout(startpar->Next()) ||
119 !startpar->Next()->Last())
120 startpar->ParFromPos(start)->PasteParagraph();
126 bool CutAndPaste::copySelection(LyXParagraph * startpar, LyXParagraph * endpar,
127 int start, int end, char tc)
129 if (!startpar || (start > startpar->Last()))
136 if (!(endpar) || (startpar->ParFromPos(start) ==
137 (endpar)->ParFromPos(end))) {
138 // only within one paragraph
139 buf = new LyXParagraph;
140 LyXParagraph::size_type i = start;
141 if (end > startpar->Last())
142 end = startpar->Last();
143 for (; i < end; ++i) {
144 startpar->CopyIntoMinibuffer(i);
145 buf->InsertFromMinibuffer(buf->Last());
148 // copy more than one paragraph
149 // clone the paragraphs within the selection
150 LyXParagraph *tmppar = startpar->ParFromPos(start);
151 buf = tmppar->Clone();
152 LyXParagraph *tmppar2 = buf;
154 while (tmppar != endpar->ParFromPos(end)
156 tmppar = tmppar->next;
157 tmppar2->next = tmppar->Clone();
158 tmppar2->next->previous = tmppar2;
159 tmppar2 = tmppar2->next;
163 // care about footnotes
164 if (buf->footnoteflag) {
167 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
168 tmppar = tmppar->next;
172 // the buf paragraph is too big
173 LyXParagraph::size_type tmpi2 = startpar->PositionInParFromPos(start);
174 for (; tmpi2; --tmpi2)
177 // now tmppar 2 is too big, delete all after end
179 tmpi2 = endpar->PositionInParFromPos(end);
180 while (tmppar2->size() > tmpi2) {
181 tmppar2->Erase(tmppar2->size() - 1);
188 bool CutAndPaste::pasteSelection(LyXParagraph ** par, LyXParagraph ** endpar,
191 if (!checkPastePossible(*par, pos))
194 if (pos > (*par)->Last())
195 pos = (*par)->Last();
197 LyXParagraph * tmpbuf;
198 LyXParagraph * tmppar = *par;
201 // There are two cases: cutbuffer only one paragraph or many
203 // only within a paragraph
204 tmpbuf = buf->Clone();
205 /* table stuff -- begin */
206 bool table_too_small = false;
208 while (buf->size() && !table_too_small) {
209 if (buf->IsNewline(0)){
210 while((tmppos < tmppar->Last()) &&
211 !tmppar->IsNewline(tmppos))
214 if (tmppos < tmppar->Last())
217 table_too_small = true;
219 // This is an attempt to fix the
220 // "never insert a space at the
221 // beginning of a paragraph" problem.
222 if (!tmppos && buf->IsLineSeparator(0)) {
225 buf->CutIntoMinibuffer(0);
227 if (tmppar->InsertFromMinibuffer(tmppos))
233 /* table stuff -- end */
234 // Some provisions should be done here for checking
235 // if we are inserting at the beginning of a
236 // paragraph. If there are a space at the beginning
237 // of the text to insert and we are inserting at
238 // the beginning of the paragraph the space should
240 while (buf->size()) {
241 // This is an attempt to fix the
242 // "never insert a space at the
243 // beginning of a paragraph" problem.
244 if (!tmppos && buf->IsLineSeparator(0)) {
247 buf->CutIntoMinibuffer(0);
249 if (tmppar->InsertFromMinibuffer(tmppos))
256 *endpar = tmppar->Next();
261 // make a copy of the simple cut_buffer
263 LyXParagraph * simple_cut_clone = tmpbuf->Clone();
264 LyXParagraph * tmpbuf2 = simple_cut_clone;
265 if ((*par)->footnoteflag){
266 tmpbuf->footnoteflag = (*par)->footnoteflag;
267 tmpbuf->footnotekind = (*par)->footnotekind;
269 while (tmpbuf->next) {
270 tmpbuf = tmpbuf->next;
271 tmpbuf2->next = tmpbuf->Clone();
272 tmpbuf2->next->previous = tmpbuf2;
273 tmpbuf2 = tmpbuf2->next;
274 if ((*par)->footnoteflag){
275 tmpbuf->footnoteflag = (*par)->footnoteflag;
276 tmpbuf->footnotekind = (*par)->footnotekind;
280 // make sure there is no class difference
281 SwitchLayoutsBetweenClasses(textclass, tc, buf);
283 // make the buf exactly the same layout than
284 // the cursor paragraph
285 buf->MakeSameLayout(*par);
287 // find the end of the buffer
288 LyXParagraph * lastbuffer = buf;
289 while (lastbuffer->Next())
290 lastbuffer = lastbuffer->Next();
292 bool paste_the_end = false;
294 // open the paragraph for inserting the buf
296 if (((*par)->Last() > pos) || !(*par)->Next()) {
297 (*par)->BreakParagraphConservative(pos);
298 paste_the_end = true;
301 // set the end for redoing later
302 *endpar = (*par)->ParFromPos(pos)->next->Next();
305 lastbuffer->ParFromPos(lastbuffer->Last())->next =
306 (*par)->ParFromPos(pos)->next;
307 (*par)->ParFromPos(pos)->next->previous =
308 lastbuffer->ParFromPos(lastbuffer->Last());
310 (*par)->ParFromPos(pos)->next = buf;
311 buf->previous = (*par)->ParFromPos(pos);
313 if ((*par)->ParFromPos(pos)->Next() == lastbuffer)
316 (*par)->ParFromPos(pos)->PasteParagraph();
318 // store the new cursor position
320 tmppos = lastbuffer->Last();
322 // maybe some pasting
323 if (lastbuffer->Next() && paste_the_end) {
324 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
325 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
326 } else if (!lastbuffer->Next()->Last()) {
327 lastbuffer->Next()->MakeSameLayout(lastbuffer);
328 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
329 } else if (!lastbuffer->Last()) {
330 lastbuffer->MakeSameLayout(lastbuffer->next);
331 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
333 lastbuffer->Next()->ClearParagraph();
335 // restore the simple cut buffer
336 buf = simple_cut_clone;
344 int CutAndPaste::nrOfParagraphs() const
349 LyXParagraph * tmppar = buf;
350 while(tmppar->next) {
352 tmppar = tmppar->next;
358 int CutAndPaste::SwitchLayoutsBetweenClasses(LyXTextClassList::size_type c1,
359 LyXTextClassList::size_type c2,
363 if (!par || c1 == c2)
365 par = par->FirstPhysicalPar();
367 string name = textclasslist.NameOfLayout(c1, par->layout);
369 pair<bool, LyXTextClass::LayoutList::size_type> pp =
370 textclasslist.NumberOfLayout(c2, name);
373 } else { // layout not found
374 // use default layout "Standard" (0)
379 if (name != textclasslist.NameOfLayout(c2, par->layout)) {
381 string s = "Layout had to be changed from\n"
383 + textclasslist.NameOfLayout(c2, par->layout)
384 + "\nbecause of class conversion from\n"
385 + textclasslist.NameOfClass(c1) + " to "
386 + textclasslist.NameOfClass(c2);
387 InsetError * new_inset = new InsetError(s);
388 par->InsertChar(0, LyXParagraph::META_INSET);
389 par->InsertInset(0, new_inset);
398 bool CutAndPaste::checkPastePossible(LyXParagraph * par, int) const
400 if (!buf) return false;
402 LyXParagraph * tmppar;
404 // be carefull with footnotes in footnotes
405 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
406 // check whether the cut_buffer includes a footnote
408 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
409 tmppar = tmppar->next;
412 WriteAlert(_("Impossible operation"),
413 _("Can't paste float into float!"),
418 /* table stuff -- begin */
421 WriteAlert(_("Impossible operation"),
422 _("Table cell cannot include more than one paragraph!"),
427 /* table stuff -- end */