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();
130 (*endpar) = startpar; // this because endpar gets deleted here!
137 bool CutAndPaste::copySelection(LyXParagraph * startpar, LyXParagraph * endpar,
138 int start, int end, char tc)
140 if (!startpar || (start > startpar->Last()))
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());
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;
165 while (tmppar != endpar->ParFromPos(end)
167 tmppar = tmppar->next;
168 tmppar2->next = tmppar->Clone();
169 tmppar2->next->previous = tmppar2;
170 tmppar2 = tmppar2->next;
174 // care about footnotes
175 if (buf->footnoteflag) {
178 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
179 tmppar = tmppar->next;
183 // the buf paragraph is too big
184 LyXParagraph::size_type tmpi2 = startpar->PositionInParFromPos(start);
185 for (; tmpi2; --tmpi2)
188 // now tmppar 2 is too big, delete all after end
190 tmpi2 = endpar->PositionInParFromPos(end);
191 while (tmppar2->size() > tmpi2) {
192 tmppar2->Erase(tmppar2->size() - 1);
199 bool CutAndPaste::pasteSelection(LyXParagraph ** par, LyXParagraph ** endpar,
202 if (!checkPastePossible(*par, pos))
205 if (pos > (*par)->Last())
206 pos = (*par)->Last();
208 LyXParagraph * tmpbuf;
209 LyXParagraph * tmppar = *par;
212 // There are two cases: cutbuffer only one paragraph or many
214 // only within a paragraph
215 tmpbuf = buf->Clone();
216 /* table stuff -- begin */
217 bool table_too_small = false;
219 while (buf->size() && !table_too_small) {
220 if (buf->IsNewline(0)){
221 while((tmppos < tmppar->Last()) &&
222 !tmppar->IsNewline(tmppos))
225 if (tmppos < tmppar->Last())
228 table_too_small = true;
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)) {
236 buf->CutIntoMinibuffer(0);
238 if (tmppar->InsertFromMinibuffer(tmppos))
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
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)) {
258 buf->CutIntoMinibuffer(0);
260 if (tmppar->InsertFromMinibuffer(tmppos))
267 *endpar = tmppar->Next();
272 // make a copy of the simple cut_buffer
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;
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;
291 // make sure there is no class difference
292 SwitchLayoutsBetweenClasses(textclass, tc, buf);
294 // make the buf exactly the same layout than
295 // the cursor paragraph
296 buf->MakeSameLayout(*par);
298 // find the end of the buffer
299 LyXParagraph * lastbuffer = buf;
300 while (lastbuffer->Next())
301 lastbuffer = lastbuffer->Next();
303 bool paste_the_end = false;
305 // open the paragraph for inserting the buf
307 if (((*par)->Last() > pos) || !(*par)->Next()) {
308 (*par)->BreakParagraphConservative(pos);
309 paste_the_end = true;
312 // set the end for redoing later
313 *endpar = (*par)->ParFromPos(pos)->next->Next();
316 lastbuffer->ParFromPos(lastbuffer->Last())->next =
317 (*par)->ParFromPos(pos)->next;
318 (*par)->ParFromPos(pos)->next->previous =
319 lastbuffer->ParFromPos(lastbuffer->Last());
321 (*par)->ParFromPos(pos)->next = buf;
322 buf->previous = (*par)->ParFromPos(pos);
324 if ((*par)->ParFromPos(pos)->Next() == lastbuffer)
327 (*par)->ParFromPos(pos)->PasteParagraph();
329 // store the new cursor position
331 pos = lastbuffer->Last();
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();
344 lastbuffer->Next()->ClearParagraph();
346 // restore the simple cut buffer
347 buf = simple_cut_clone;
354 int CutAndPaste::nrOfParagraphs() const
359 LyXParagraph * tmppar = buf;
360 while(tmppar->next) {
362 tmppar = tmppar->next;
368 int CutAndPaste::SwitchLayoutsBetweenClasses(LyXTextClassList::size_type c1,
369 LyXTextClassList::size_type c2,
373 if (!par || c1 == c2)
375 par = par->FirstPhysicalPar();
377 string name = textclasslist.NameOfLayout(c1, par->layout);
379 pair<bool, LyXTextClass::LayoutList::size_type> pp =
380 textclasslist.NumberOfLayout(c2, name);
383 } else { // layout not found
384 // use default layout "Standard" (0)
389 if (name != textclasslist.NameOfLayout(c2, par->layout)) {
391 string s = "Layout had to be changed from\n"
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);
408 bool CutAndPaste::checkPastePossible(LyXParagraph * par, int) const
410 if (!buf) return false;
412 LyXParagraph * tmppar;
414 // be carefull with footnotes in footnotes
415 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
416 // check whether the cut_buffer includes a footnote
418 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
419 tmppar = tmppar->next;
422 WriteAlert(_("Impossible operation"),
423 _("Can't paste float into float!"),
428 /* table stuff -- begin */
431 WriteAlert(_("Impossible operation"),
432 _("Table cell cannot include more than one paragraph!"),
437 /* table stuff -- end */