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 // 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)
42 static LyXParagraph * buf = 0;
43 static LyXTextClassList::size_type textclass = 0;
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)
55 LyXParagraph * tmppar;
66 bool CutAndPaste::cutSelection(LyXParagraph * startpar, LyXParagraph ** endpar,
67 int start, int & end, char tc, bool doclear)
69 if (!startpar || (start > startpar->Last()))
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)) {
89 /* table stuff -- end */
90 startpar->Erase(start);
92 buf->InsertFromMinibuffer(buf->Last());
95 // more than one paragraph
96 (*endpar)->BreakParagraphConservative(end);
97 *endpar = (*endpar)->Next();
100 startpar->BreakParagraphConservative(start);
102 // store the selection
103 buf = startpar->ParFromPos(start)->next;
105 (*endpar)->previous->next = 0;
108 startpar->ParFromPos(start)->next = (*endpar);
110 (*endpar)->previous = startpar->ParFromPos(start);
112 // care about footnotes
113 if (buf->footnoteflag) {
114 LyXParagraph * tmppar = buf;
116 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
117 tmppar = tmppar->next;
121 // the cut selection should begin with standard layout
124 // paste the paragraphs again, if possible
126 startpar->Next()->ClearParagraph();
127 if (startpar->FirstPhysicalPar()->HasSameLayout(startpar->Next()) ||
128 !startpar->Next()->Last())
129 startpar->ParFromPos(start)->PasteParagraph();
135 bool CutAndPaste::copySelection(LyXParagraph * startpar, LyXParagraph * endpar,
136 int start, int end, char tc)
138 if (!startpar || (start > startpar->Last()))
145 if (!(endpar) || (startpar->ParFromPos(start) ==
146 (endpar)->ParFromPos(end))) {
147 // only within one paragraph
148 buf = new LyXParagraph;
149 LyXParagraph::size_type i = start;
150 if (end > startpar->Last())
151 end = startpar->Last();
152 for (; i < end; ++i) {
153 startpar->CopyIntoMinibuffer(i);
154 buf->InsertFromMinibuffer(buf->Last());
157 // copy more than one paragraph
158 // clone the paragraphs within the selection
159 LyXParagraph *tmppar = startpar->ParFromPos(start);
160 buf = tmppar->Clone();
161 LyXParagraph *tmppar2 = buf;
163 while (tmppar != endpar->ParFromPos(end)
165 tmppar = tmppar->next;
166 tmppar2->next = tmppar->Clone();
167 tmppar2->next->previous = tmppar2;
168 tmppar2 = tmppar2->next;
172 // care about footnotes
173 if (buf->footnoteflag) {
176 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
177 tmppar = tmppar->next;
181 // the buf paragraph is too big
182 LyXParagraph::size_type tmpi2 = startpar->PositionInParFromPos(start);
183 for (; tmpi2; --tmpi2)
186 // now tmppar 2 is too big, delete all after end
188 tmpi2 = endpar->PositionInParFromPos(end);
189 while (tmppar2->size() > tmpi2) {
190 tmppar2->Erase(tmppar2->size() - 1);
197 bool CutAndPaste::pasteSelection(LyXParagraph ** par, LyXParagraph ** endpar,
200 if (!checkPastePossible(*par, pos))
203 if (pos > (*par)->Last())
204 pos = (*par)->Last();
206 LyXParagraph * tmpbuf;
207 LyXParagraph * tmppar = *par;
210 // There are two cases: cutbuffer only one paragraph or many
212 // only within a paragraph
213 tmpbuf = buf->Clone();
214 /* table stuff -- begin */
215 bool table_too_small = false;
217 while (buf->size() && !table_too_small) {
218 if (buf->IsNewline(0)){
219 while((tmppos < tmppar->Last()) &&
220 !tmppar->IsNewline(tmppos))
223 if (tmppos < tmppar->Last())
226 table_too_small = true;
228 // This is an attempt to fix the
229 // "never insert a space at the
230 // beginning of a paragraph" problem.
231 if (!tmppos && buf->IsLineSeparator(0)) {
234 buf->CutIntoMinibuffer(0);
236 if (tmppar->InsertFromMinibuffer(tmppos))
242 /* table stuff -- end */
243 // Some provisions should be done here for checking
244 // if we are inserting at the beginning of a
245 // paragraph. If there are a space at the beginning
246 // of the text to insert and we are inserting at
247 // the beginning of the paragraph the space should
249 while (buf->size()) {
250 // This is an attempt to fix the
251 // "never insert a space at the
252 // beginning of a paragraph" problem.
253 if (!tmppos && buf->IsLineSeparator(0)) {
256 buf->CutIntoMinibuffer(0);
258 if (tmppar->InsertFromMinibuffer(tmppos))
265 *endpar = tmppar->Next();
270 // make a copy of the simple cut_buffer
272 LyXParagraph * simple_cut_clone = tmpbuf->Clone();
273 LyXParagraph * tmpbuf2 = simple_cut_clone;
274 if ((*par)->footnoteflag){
275 tmpbuf->footnoteflag = (*par)->footnoteflag;
276 tmpbuf->footnotekind = (*par)->footnotekind;
278 while (tmpbuf->next) {
279 tmpbuf = tmpbuf->next;
280 tmpbuf2->next = tmpbuf->Clone();
281 tmpbuf2->next->previous = tmpbuf2;
282 tmpbuf2 = tmpbuf2->next;
283 if ((*par)->footnoteflag){
284 tmpbuf->footnoteflag = (*par)->footnoteflag;
285 tmpbuf->footnotekind = (*par)->footnotekind;
289 // make sure there is no class difference
290 SwitchLayoutsBetweenClasses(textclass, tc, buf);
292 // make the buf exactly the same layout than
293 // the cursor paragraph
294 buf->MakeSameLayout(*par);
296 // find the end of the buffer
297 LyXParagraph * lastbuffer = buf;
298 while (lastbuffer->Next())
299 lastbuffer = lastbuffer->Next();
301 bool paste_the_end = false;
303 // open the paragraph for inserting the buf
305 if (((*par)->Last() > pos) || !(*par)->Next()) {
306 (*par)->BreakParagraphConservative(pos);
307 paste_the_end = true;
310 // set the end for redoing later
311 *endpar = (*par)->ParFromPos(pos)->next->Next();
314 lastbuffer->ParFromPos(lastbuffer->Last())->next =
315 (*par)->ParFromPos(pos)->next;
316 (*par)->ParFromPos(pos)->next->previous =
317 lastbuffer->ParFromPos(lastbuffer->Last());
319 (*par)->ParFromPos(pos)->next = buf;
320 buf->previous = (*par)->ParFromPos(pos);
322 if ((*par)->ParFromPos(pos)->Next() == lastbuffer)
325 (*par)->ParFromPos(pos)->PasteParagraph();
327 // store the new cursor position
329 tmppos = lastbuffer->Last();
331 // maybe some pasting
332 if (lastbuffer->Next() && paste_the_end) {
333 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
334 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
335 } else if (!lastbuffer->Next()->Last()) {
336 lastbuffer->Next()->MakeSameLayout(lastbuffer);
337 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
338 } else if (!lastbuffer->Last()) {
339 lastbuffer->MakeSameLayout(lastbuffer->next);
340 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
342 lastbuffer->Next()->ClearParagraph();
344 // restore the simple cut buffer
345 buf = simple_cut_clone;
353 int CutAndPaste::nrOfParagraphs() const
358 LyXParagraph * tmppar = buf;
359 while(tmppar->next) {
361 tmppar = tmppar->next;
367 int CutAndPaste::SwitchLayoutsBetweenClasses(LyXTextClassList::size_type c1,
368 LyXTextClassList::size_type c2,
372 if (!par || c1 == c2)
374 par = par->FirstPhysicalPar();
376 string name = textclasslist.NameOfLayout(c1, par->layout);
378 pair<bool, LyXTextClass::LayoutList::size_type> pp =
379 textclasslist.NumberOfLayout(c2, name);
382 } else { // layout not found
383 // use default layout "Standard" (0)
388 if (name != textclasslist.NameOfLayout(c2, par->layout)) {
390 string s = "Layout had to be changed from\n"
392 + textclasslist.NameOfLayout(c2, par->layout)
393 + "\nbecause of class conversion from\n"
394 + textclasslist.NameOfClass(c1) + " to "
395 + textclasslist.NameOfClass(c2);
396 InsetError * new_inset = new InsetError(s);
397 par->InsertChar(0, LyXParagraph::META_INSET);
398 par->InsertInset(0, new_inset);
407 bool CutAndPaste::checkPastePossible(LyXParagraph * par, int) const
409 if (!buf) return false;
411 LyXParagraph * tmppar;
413 // be carefull with footnotes in footnotes
414 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
415 // check whether the cut_buffer includes a footnote
417 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
418 tmppar = tmppar->next;
421 WriteAlert(_("Impossible operation"),
422 _("Can't paste float into float!"),
427 /* table stuff -- begin */
430 WriteAlert(_("Impossible operation"),
431 _("Table cell cannot include more than one paragraph!"),
436 /* table stuff -- end */