1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995-2001 The LyX Team.
8 * ====================================================== */
12 #include "CutAndPaste.h"
13 #include "BufferView.h"
15 #include "paragraph.h"
16 #include "insets/inseterror.h"
17 #include "lyx_gui_misc.h"
18 #include "lyxcursor.h"
22 #pragma implementation
27 extern BufferView * current_view;
29 // Jürgen, note that this means that you cannot currently have a list
30 // of selections cut/copied. So IMHO later we should have a
31 // list/vector/deque that we could store
32 // struct selection_item {
34 // LyXTextClassList::size_type textclass;
36 // in and some method of choosing beween them (based on the first few chars
37 // in the selection probably.) This would be a nice feature and quite
38 // easy to implement. (Lgb)
40 // Sure but I just cleaned up this code for now with the same functionality
41 // as before. I also want to add a XClipboard function so that we can copy
42 // text from LyX to some other X-application in the form of ASCII or in the
43 // form of LaTeX (or Docbook depending on the document-class!). Think how nice
44 // it could be to select a math-inset do a "Copy to X-Clipboard as LaTeX" and
45 // then do a middle mouse button click in the application you want and have
46 // the whole formula there in LaTeX-Code. (Jug)
51 LyXTextClassList::size_type textclass = 0;
53 // for now here this should be in another Cut&Paste Class!
54 // Jürgen, I moved this out of CutAndPaste since it does not operate on any
55 // member of the CutAndPaste class and in addition it was private.
56 // Perhaps it even should take a parameter? (Lgb)
75 bool CutAndPaste::cutSelection(Paragraph * startpar, Paragraph ** endpar,
76 int start, int & end, char tc, bool doclear,
79 if (!startpar || (start > startpar->size()))
87 if (!(*endpar) || startpar == (*endpar)) {
88 // only within one paragraph
91 Paragraph::size_type i = start;
92 if (end > startpar->size())
93 end = startpar->size();
94 for (; i < end; ++i) {
96 startpar->copyIntoMinibuffer(*current_view->buffer(),
98 startpar->erase(start);
100 buf->insertFromMinibuffer(buf->size());
104 // more than one paragraph
105 (*endpar)->breakParagraphConservative(current_view->buffer()->params,
107 *endpar = (*endpar)->next();
110 startpar->breakParagraphConservative(current_view->buffer()->params,
113 // store the selection
115 buf = startpar->next();
118 startpar->next()->previous(0);
120 (*endpar)->previous()->next(0);
123 startpar->next(*endpar);
125 (*endpar)->previous(startpar);
127 // the cut selection should begin with standard layout
131 // paste the paragraphs again, if possible
133 startpar->next()->stripLeadingSpaces(textclass);
134 if (startpar->hasSameLayout(startpar->next()) ||
135 !startpar->next()->size()) {
136 startpar->pasteParagraph(current_view->buffer()->params);
137 (*endpar) = startpar; // this because endpar gets deleted here!
144 bool CutAndPaste::copySelection(Paragraph * startpar, Paragraph * endpar,
145 int start, int end, char tc)
147 if (!startpar || (start > startpar->size()))
155 startpar == endpar) {
156 // only within one paragraph
158 Paragraph::size_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());
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;
172 while (tmppar != endpar
174 tmppar = tmppar->next();
175 tmppar2->next(new Paragraph(*tmppar, false));
176 tmppar2->next()->previous(tmppar2);
177 tmppar2 = tmppar2->next();
181 // the buf paragraph is too big
182 Paragraph::size_type tmpi2 = start;
183 for (; tmpi2; --tmpi2)
186 // now tmppar 2 is too big, delete all after end
188 while (tmppar2->size() > tmpi2) {
189 tmppar2->erase(tmppar2->size() - 1);
196 bool CutAndPaste::pasteSelection(Paragraph ** par, Paragraph ** endpar,
199 if (!checkPastePossible(*par))
202 if (pos > (*par)->size())
203 pos = (*par)->size();
205 // Paragraph * tmpbuf;
206 Paragraph * tmppar = *par;
209 // There are two cases: cutbuffer only one paragraph or many
211 // only within a paragraph
212 Paragraph * tmpbuf = new Paragraph(*buf, false);
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
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)) {
227 buf->cutIntoMinibuffer(current_view->buffer()->params, 0);
229 if (tmppar->insertFromMinibuffer(tmppos))
235 *endpar = tmppar->next();
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;
245 while (tmpbuf->next()) {
246 tmpbuf = tmpbuf->next();
247 tmpbuf2->next(new Paragraph(*tmpbuf, false));
248 tmpbuf2->next()->previous(tmpbuf2);
249 tmpbuf2 = tmpbuf2->next();
252 // make sure there is no class difference
253 SwitchLayoutsBetweenClasses(textclass, tc, buf);
255 // make the buf exactly the same layout than
256 // the cursor paragraph
257 buf->makeSameLayout(*par);
259 // find the end of the buffer
260 Paragraph * lastbuffer = buf;
261 while (lastbuffer->next())
262 lastbuffer = lastbuffer->next();
264 bool paste_the_end = false;
266 // open the paragraph for inserting the buf
268 if (((*par)->size() > pos) || !(*par)->next()) {
269 (*par)->breakParagraphConservative(current_view->buffer()->params,
271 paste_the_end = true;
273 // set the end for redoing later
274 *endpar = (*par)->next()->next();
277 lastbuffer->next((*par)->next());
278 (*par)->next()->previous(lastbuffer);
283 if ((*par)->next() == lastbuffer)
286 (*par)->pasteParagraph(current_view->buffer()->params);
287 // store the new cursor position
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);
301 lastbuffer->next()->stripLeadingSpaces(tc);
303 // restore the simple cut buffer
304 buf = simple_cut_clone;
311 int CutAndPaste::nrOfParagraphs()
317 Paragraph * tmppar = buf;
318 while(tmppar->next()) {
320 tmppar = tmppar->next();
326 int CutAndPaste::SwitchLayoutsBetweenClasses(LyXTextClassList::size_type c1,
327 LyXTextClassList::size_type c2,
331 if (!par || c1 == c2)
335 string const name = textclasslist.NameOfLayout(c1,
338 pair<bool, LyXTextClass::LayoutList::size_type> pp =
339 textclasslist.NumberOfLayout(c2, name);
342 } else { // layout not found
343 // use default layout "Standard" (0)
348 if (name != textclasslist.NameOfLayout(c2, par->layout)) {
350 string const s = _("Layout had to be changed from\n")
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);
365 bool CutAndPaste::checkPastePossible(Paragraph *)
367 if (!buf) return false;