]> Shamusworld >> Repos - architektonas/blob - src/base/rs_modification.cpp
Changed RS_Graphic to Drawing; this is less confusing as a drawing is
[architektonas] / src / base / rs_modification.cpp
1 // rs_modification.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  06/01/2010  Added this text. :-)
13 //
14
15 #include "rs_modification.h"
16
17 #include "rs_clipboard.h"
18 #include "rs_creation.h"
19 #include "rs_entity.h"
20 #include "drawing.h"
21 #include "rs_information.h"
22 #include "rs_insert.h"
23 #include "rs_polyline.h"
24 #include "rs_text.h"
25 #include "rs_units.h"
26
27 /**
28  * Default constructor.
29  *
30  * @param container The container to which we will add
31  *        entities. Usually that's an Drawing entity but
32  *        it can also be a polyline, text, ...
33  * @param graphicView Pointer to graphic view or NULL if you don't want the
34  *        any views to be updated.
35  * @param handleUndo true: Handle undo functionalitiy.
36  */
37 RS_Modification::RS_Modification(RS_EntityContainer & container,
38         RS_GraphicView * graphicView, bool handleUndo)
39 {
40     this->container = &container;
41     this->graphicView = graphicView;
42     this->handleUndo = handleUndo;
43     graphic = container.getGraphic();
44     document = container.getDocument();
45 }
46
47 /**
48  * Deletes all selected entities.
49  */
50 void RS_Modification::remove()
51 {
52         if (container == NULL)
53         {
54                 RS_DEBUG->print("RS_Modification::remove: no valid container", RS_Debug::D_WARNING);
55                 return;
56         }
57
58         if (document != NULL)
59                 document->startUndoCycle();
60
61         // not safe (?)
62         for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
63         {
64                 if (e != NULL && e->isSelected())
65                 {
66                         e->setSelected(false);
67                         e->changeUndoState();
68
69                         if (document != NULL)
70                                 document->addUndoable(e);
71                 }
72         }
73
74         if (document != NULL)
75                 document->endUndoCycle();
76
77         graphicView->redraw();
78 }
79
80 /**
81  * Changes the attributes of all selected
82  */
83 bool RS_Modification::changeAttributes(RS_AttributesData & data)
84 {
85         if (container == NULL)
86         {
87                 RS_DEBUG->print("RS_Modification::changeAttributes: no valid container", RS_Debug::D_WARNING);
88                 return false;
89         }
90
91 //      Q3PtrList<RS_Entity> addList;
92 //      addList.setAutoDelete(false);
93         QList<RS_Entity *> addList;
94
95         if (document != NULL)
96                 document->startUndoCycle();
97
98         for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
99         {
100                 //for (uint i=0; i<container->count(); ++i) {
101                 //RS_Entity* e = container->entityAt(i);
102                 if (e != NULL && e->isSelected())
103                 {
104                         RS_Entity * ec = e->clone();
105                         ec->setSelected(false);
106
107                         RS_Pen pen = ec->getPen(false);
108
109                         if (data.changeLayer == true)
110                                 ec->setLayer(data.layer);
111
112                         if (data.changeColor == true)
113                                 pen.setColor(data.pen.getColor());
114
115                         if (data.changeLineType == true)
116                                 pen.setLineType(data.pen.getLineType());
117
118                         if (data.changeWidth == true)
119                                 pen.setWidth(data.pen.getWidth());
120
121                         ec->setPen(pen);
122
123                         //if (data.useCurrentLayer) {
124                         //    ec->setLayerToActive();
125                         //}
126                         //if (data.useCurrentAttributes) {
127                         //    ec->setPenToActive();
128                         //}
129                         //if (ec->rtti()==RS2::EntityInsert) {
130                         //    ((RS_Insert*)ec)->update();
131                         //}
132                         ec->update();
133                         addList.append(ec);
134                 }
135         }
136
137         deselectOriginals(true);
138         addNewEntities(addList);
139
140         if (document != NULL)
141                 document->endUndoCycle();
142
143         if (graphicView != NULL)
144                 graphicView->redraw();
145
146         return true;
147 }
148
149
150 /**
151  * Copies all selected entities from the given container to the clipboard.
152  * Layers and blocks that are needed are also copied if the container is
153  * or is part of an Drawing.
154  *
155  * @param container The entity container.
156  * @param ref Reference point. The entities will be moved by -ref.
157  * @param cut true: cut instead of copying, false: copy
158  */
159 void RS_Modification::copy(const Vector& ref, const bool cut) {
160
161     if (container==NULL) {
162         RS_DEBUG->print("RS_Modification::copy: no valid container",
163                         RS_Debug::D_WARNING);
164         return;
165     }
166
167     RS_CLIPBOARD->clear();
168     if (graphic!=NULL) {
169         RS_CLIPBOARD->getGraphic()->setUnit(graphic->getUnit());
170     } else {
171         RS_CLIPBOARD->getGraphic()->setUnit(RS2::None);
172     }
173
174     // start undo cycle for the container if we're cutting
175     if (cut && document!=NULL) {
176         document->startUndoCycle();
177     }
178
179     // copy entities / layers / blocks
180     for (RS_Entity* e=container->firstEntity(); e!=NULL;
181             e=container->nextEntity()) {
182         //for (uint i=0; i<container->count(); ++i) {
183         //RS_Entity* e = container->entityAt(i);
184
185         if (e!=NULL && e->isSelected()) {
186             copyEntity(e, ref, cut);
187         }
188     }
189
190     if (cut && document!=NULL) {
191         document->endUndoCycle();
192     }
193 }
194
195
196
197 /**
198  * Copies the given entity from the given container to the clipboard.
199  * Layers and blocks that are needed are also copied if the container is
200  * or is part of an Drawing.
201  *
202  * @param e The entity.
203  * @param ref Reference point. The entities will be moved by -ref.
204  * @param cut true: cut instead of copying, false: copy
205  */
206 void RS_Modification::copyEntity(RS_Entity* e, const Vector& ref,
207                                  const bool cut) {
208
209     if (e!=NULL && e->isSelected()) {
210         // delete entity in graphic view:
211         if (cut) {
212             if (graphicView!=NULL) {
213                 graphicView->deleteEntity(e);
214             }
215             e->setSelected(false);
216         } else {
217             if (graphicView!=NULL) {
218                 graphicView->deleteEntity(e);
219             }
220             e->setSelected(false);
221             if (graphicView!=NULL) {
222                 graphicView->drawEntity(e);
223             }
224         }
225
226         // add entity to clipboard:
227         RS_Entity* c = e->clone();
228         c->move(-ref);
229         RS_CLIPBOARD->addEntity(c);
230
231         copyLayers(e);
232         copyBlocks(e);
233
234         // set layer to the layer clone:
235         RS_Layer* l = e->getLayer();
236         if (l!=NULL) {
237             c->setLayer(l->getName());
238         }
239
240         // make sure all sub entities point to layers of the clipboard
241         if (c->isContainer()) {
242             RS_EntityContainer* ec = (RS_EntityContainer*)c;
243
244             for (RS_Entity* e2 = ec->firstEntity(RS2::ResolveAll); e2!=NULL;
245                     e2 = ec->nextEntity(RS2::ResolveAll)) {
246
247                 //RS_Entity* e2 = ec->entityAt(i);
248                 RS_Layer* l2 = e2->getLayer();
249
250                 if (l2!=NULL) {
251                     e2->setLayer(l2->getName());
252                 }
253             }
254         }
255
256         if (cut) {
257             e->changeUndoState();
258             if (document!=NULL) {
259                 document->addUndoable(e);
260             }
261         }
262     }
263
264 }
265
266
267
268 /**
269  * Copies all layers of the given entity to the clipboard.
270  */
271 void RS_Modification::copyLayers(RS_Entity* e) {
272
273     if (e==NULL) {
274         return;
275     }
276
277     // add layer(s) of the entity if it's not an insert
278     //  (inserts are on layer '0'):
279     if (e->rtti()!=RS2::EntityInsert) {
280         RS_Layer* l = e->getLayer();
281         if (l!=NULL) {
282             if (!RS_CLIPBOARD->hasLayer(l->getName())) {
283                 RS_CLIPBOARD->addLayer(l->clone());
284             }
285         }
286     }
287
288     // special handling of inserts:
289     else {
290         // insert: add layer(s) of subentities:
291         RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
292         if (b!=NULL) {
293             for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
294                     e2=b->nextEntity()) {
295                 //for (uint i=0; i<b->count(); ++i) {
296                 //RS_Entity* e2 = b->entityAt(i);
297                 copyLayers(e2);
298             }
299         }
300     }
301 }
302
303
304
305 /**
306  * Copies all blocks of the given entity to the clipboard.
307  */
308 void RS_Modification::copyBlocks(RS_Entity* e) {
309
310     if (e==NULL) {
311         return;
312     }
313
314     // add block of the entity if it's an insert
315     if (e->rtti()==RS2::EntityInsert) {
316         RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
317         if (b!=NULL) {
318             // add block of an insert:
319             if (!RS_CLIPBOARD->hasBlock(b->getName())) {
320                 RS_CLIPBOARD->addBlock((RS_Block*)b->clone());
321             }
322
323             for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
324                     e2=b->nextEntity()) {
325                 //for (uint i=0; i<b->count(); ++i) {
326                 //RS_Entity* e2 = b->entityAt(i);
327                 copyBlocks(e2);
328             }
329         }
330     }
331 }
332
333
334
335 /**
336  * Pastes all entities from the clipboard into the container.
337  * Layers and blocks that are needed are also copied if the container is
338  * or is part of an Drawing.
339  *
340  * @param data Paste data.
341  * @param source The source from where to paste. NULL means the source
342  *      is the clipboard.
343  */
344 void RS_Modification::paste(const RS_PasteData& data, Drawing* source) {
345
346     if (graphic==NULL) {
347         RS_DEBUG->print(RS_Debug::D_WARNING,
348                         "RS_Modification::paste: Graphic is NULL");
349         return;
350     }
351
352     double factor = 1.0;
353
354     if (source==NULL) {
355         source = RS_CLIPBOARD->getGraphic();
356
357         // graphics from the clipboard need to be scaled. from the part lib not:
358         RS2::Unit sourceUnit = source->getUnit();
359         RS2::Unit targetUnit = graphic->getUnit();
360         factor = RS_Units::convert(1.0, sourceUnit, targetUnit);
361     }
362
363     if (document!=NULL) {
364         document->startUndoCycle();
365     }
366
367
368     // insert layers:
369     if (graphic!=NULL) {
370         RS_Layer* layer = graphic->getActiveLayer();
371         for(uint i=0; i<source->countLayers(); ++i) {
372             RS_Layer* l = source->layerAt(i);
373             if (l!=NULL) {
374                 if (graphic->findLayer(l->getName())==NULL) {
375                     graphic->addLayer(l->clone());
376                 }
377             }
378         }
379         graphic->activateLayer(layer);
380     }
381
382     // insert blocks:
383     if (graphic!=NULL) {
384         for(uint i=0; i<source->countBlocks(); ++i) {
385             RS_Block* b = source->blockAt(i);
386             if (b!=NULL) {
387                 if (graphic->findBlock(b->getName())==NULL) {
388                     RS_Block* bc = (RS_Block*)b->clone();
389                     bc->reparent(container);
390                     //bc->scale(bc->getBasePoint(), Vector(factor, factor));
391                     // scale block but don't scale inserts in block
392                     //  (they already scale with their block)
393                     for(uint i2=0; i2<bc->count(); ++i2) {
394                         RS_Entity* e = bc->entityAt(i2);
395                         if (e!=NULL && e->rtti()!=RS2::EntityInsert) {
396                             e->scale(bc->getBasePoint(),
397                                      Vector(factor, factor));
398                         } else {
399                             Vector ip = ((RS_Insert*)e)->getInsertionPoint();
400                             ip.scale(bc->getBasePoint(),
401                                      Vector(factor, factor));
402                             ((RS_Insert*)e)->setInsertionPoint(ip);
403                             e->update();
404                         }
405                     }
406
407                     graphic->addBlock(bc);
408                 }
409             }
410         }
411     }
412
413     // add entities to this host (graphic or a new block)
414     RS_EntityContainer* host = container;
415     QString blockName;
416
417     // create new block:
418     if (graphic!=NULL) {
419         if (data.asInsert==true) {
420             RS_BlockList* blkList = graphic->getBlockList();
421             if (blkList!=NULL) {
422                 blockName = blkList->newName(data.blockName);
423
424                 RS_Block* blk =
425                     new RS_Block(graphic,
426                                  RS_BlockData(blockName,
427                                               Vector(0.0,0.0), false));
428                 graphic->addBlock(blk);
429
430                 host = blk;
431             }
432         }
433     }
434
435     // insert entities:
436     //for (uint i=0; i<((RS_EntityContainer*)source)->count(); ++i) {
437     //RS_Entity* e = source->entityAt(i);
438     for (RS_Entity* e=((RS_EntityContainer*)source)->firstEntity();
439             e!=NULL;
440             e=((RS_EntityContainer*)source)->nextEntity()) {
441
442         if (e!=NULL) {
443
444             QString layerName = "0";
445             RS_Layer* layer = e->getLayer();
446             if (layer!=NULL) {
447                 layerName = layer->getName();
448             }
449             RS_Entity* e2 = e->clone();
450             e2->reparent(host);
451             if (data.asInsert==false) {
452                 e2->move(data.insertionPoint);
453             }
454             // don't adjust insert factor - block was already adjusted to unit
455             if (e2->rtti()==RS2::EntityInsert) {
456                 Vector ip = ((RS_Insert*)e2)->getInsertionPoint();
457                 ip.scale(data.insertionPoint, Vector(factor, factor));
458                 ((RS_Insert*)e2)->setInsertionPoint(ip);
459                 e2->update();
460             } else {
461                 e2->scale(data.insertionPoint, Vector(factor, factor));
462             }
463             host->addEntity(e2);
464             e2->setLayer(layerName);
465
466             // make sure all sub entities point to layers of the container
467             if (e2->isContainer()) {
468                 RS_EntityContainer* ec = (RS_EntityContainer*)e2;
469
470                 for (RS_Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
471                         e3 = ec->nextEntity(RS2::ResolveAll)) {
472
473                     //RS_Entity* e3 = ec->entityAt(i);
474                     RS_Layer* l2 = e3->getLayer();
475                     if (l2!=NULL) {
476                         e3->setLayer(l2->getName());
477                     }
478                 }
479             }
480
481             if (document!=NULL && data.asInsert==false) {
482                 document->addUndoable(e2);
483             }
484         }
485     }
486
487     if (data.asInsert==true) {
488         RS_Insert* ins =
489             new RS_Insert(container,
490                           RS_InsertData(
491                               blockName,
492                               data.insertionPoint,
493                               Vector(data.factor, data.factor),
494                               data.angle,
495                               1,1,Vector(0.0,0.0)));
496         container->addEntity(ins);
497         ins->setLayerToActive();
498         ins->setPenToActive();
499
500         if (document!=NULL) {
501             document->addUndoable(ins);
502         }
503     }
504
505     if (document!=NULL) {
506         document->endUndoCycle();
507     }
508 }
509
510
511 /**
512  * Splits a polyline into two leaving out a gap.
513  *
514  * @param polyline The original polyline
515  * @param e1 1st entity on which the first cutting point is.
516  * @param v1 1st cutting point.
517  * @param e2 2nd entity on which the first cutting point is.
518  * @param v2 2nd cutting point.
519  * @param polyline1 Pointer to a polyline pointer which will hold the
520  *        1st resulting new polyline. Pass NULL if you don't
521  *        need those pointers.
522  * @param polyline2 Pointer to a polyline pointer which will hold the
523  *        2nd resulting new polyline. Pass NULL if you don't
524  *        need those pointers.
525  *
526  * @todo Support arcs in polylines, check for wrong parameters
527  *
528  * @return true
529  */
530 bool RS_Modification::splitPolyline(RS_Polyline& polyline,
531                                     RS_Entity& e1, Vector v1,
532                                     RS_Entity& e2, Vector v2,
533                                     RS_Polyline** polyline1,
534                                     RS_Polyline** polyline2) const {
535
536     if (container==NULL) {
537         RS_DEBUG->print("RS_Modification::splitPolyline: no valid container",
538                         RS_Debug::D_WARNING);
539         return false;
540     }
541
542     RS_Entity* firstEntity = polyline.firstEntity();
543     Vector firstPoint(false);
544     if (firstEntity->rtti()==RS2::EntityLine) {
545         firstPoint = ((RS_Line*)firstEntity)->getStartpoint();
546     }
547     RS_Polyline* pl1 =
548         new RS_Polyline(container,
549                         RS_PolylineData(firstPoint, Vector(0.0,0.0), 0));
550     RS_Polyline* pl2 = new RS_Polyline(container);
551     RS_Polyline* pl = pl1;      // Current polyline
552     RS_Line* line = NULL;
553     RS_Arc* arc = NULL;
554
555     if (polyline1!=NULL) {
556         *polyline1 = pl1;
557     }
558     if (polyline2!=NULL) {
559         *polyline2 = pl2;
560     }
561
562     for (RS_Entity* e = polyline.firstEntity();
563             e != NULL;
564             e = polyline.nextEntity()) {
565
566         if (e->rtti()==RS2::EntityLine) {
567             line = (RS_Line*)e;
568             arc = NULL;
569         } else if (e->rtti()==RS2::EntityArc) {
570             arc = (RS_Arc*)e;
571             line = NULL;
572         } else {
573             line = NULL;
574             arc = NULL;
575         }
576
577         if (line!=NULL /*|| arc!=NULL*/) {
578
579             if (e==&e1 && e==&e2) {
580                 // Trim within a single entity:
581                 Vector sp = line->getStartpoint();
582                 double dist1 = (v1-sp).magnitude();
583                 double dist2 = (v2-sp).magnitude();
584                 pl->addVertex(dist1<dist2 ? v1 : v2, 0.0);
585                 pl = pl2;
586                 pl->setStartpoint(dist1<dist2 ? v2 : v1);
587                 pl->addVertex(line->getEndpoint(), 0.0);
588             } else if (e==&e1 || e==&e2) {
589                 // Trim entities:
590                 Vector v = (e==&e1 ? v1 : v2);
591                 if (pl==pl1) {
592                     // Trim endpoint of entity to first vector
593                     pl->addVertex(v, 0.0);
594                     pl = NULL;
595                 } else {
596                     // Trim startpoint of entity to second vector
597                     pl = pl2;
598                     pl->setStartpoint(v);
599                     pl->addVertex(line->getEndpoint(), 0.0);
600                 }
601             } else {
602                 // Add entities to polylines
603                 if (line!=NULL && pl!=NULL) {
604                     pl->addVertex(line->getEndpoint(), 0.0);
605                 }
606             }
607         }
608     }
609
610     container->addEntity(pl1);
611     container->addEntity(pl2);
612     //container->removeEntity(&polyline);
613     polyline.changeUndoState();
614
615     return true;
616 }
617
618
619
620 /**
621  * Adds a node to the given polyline. The new node is placed between
622  * the start and end point of the given segment.
623  *
624  * @param node The position of the new node.
625  *
626  * @return Pointer to the new polyline or NULL.
627  */
628 /*
629 RS_Polyline* RS_Modification::addPolylineNode(RS_Polyline& polyline,
630         const RS_AtomicEntity& segment,
631         const Vector& node) {
632     RS_DEBUG->print("RS_Modification::addPolylineNode");
633
634     if (container==NULL) {
635         RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
636                         RS_Debug::D_WARNING);
637         return NULL;
638     }
639
640     if (segment.getParent()!=&polyline) {
641         RS_DEBUG->print("RS_Modification::addPolylineNode: "
642                         "segment not part of the polyline",
643                         RS_Debug::D_WARNING);
644         return NULL;
645     }
646
647     RS_Polyline* newPolyline = new RS_Polyline(container);
648     newPolyline->setClosed(polyline.isClosed());
649     newPolyline->setSelected(polyline.isSelected());
650     newPolyline->setLayer(polyline.getLayer());
651     newPolyline->setPen(polyline.getPen());
652
653     // copy polyline and add new node:
654     bool first = true;
655     RS_Entity* lastEntity = polyline.lastEntity();
656     for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
657             e=polyline.nextEntity()) {
658
659         if (e->isAtomic()) {
660             RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
661             double bulge = 0.0;
662             if (ae->rtti()==RS2::EntityArc) {
663                 RS_DEBUG->print("RS_Modification::addPolylineNode: arc segment");
664                 bulge = ((RS_Arc*)ae)->getBulge();
665             } else {
666                 RS_DEBUG->print("RS_Modification::addPolylineNode: line segment");
667                 bulge = 0.0;
668             }
669
670             if (first) {
671                 RS_DEBUG->print("RS_Modification::addPolylineNode: first segment: %f/%f",
672                                 ae->getStartpoint().x, ae->getStartpoint().y);
673
674                 newPolyline->setNextBulge(bulge);
675                 newPolyline->addVertex(ae->getStartpoint());
676                 first = false;
677             }
678
679             // segment to split:
680             if (ae==&segment) {
681                 RS_DEBUG->print("RS_Modification::addPolylineNode: split segment found");
682
683                 RS_DEBUG->print("RS_Modification::addPolylineNode: node: %f/%f",
684                                 node.x, node.y);
685
686                 newPolyline->setNextBulge(0.0);
687                 newPolyline->addVertex(node);
688
689                 RS_DEBUG->print("RS_Modification::addPolylineNode: after node: %f/%f",
690                                 ae->getEndpoint().x, ae->getEndpoint().y);
691
692                 if (ae!=lastEntity || polyline.isClosed()==false) {
693                     newPolyline->setNextBulge(0.0);
694                     newPolyline->addVertex(ae->getEndpoint());
695                 }
696             } else {
697                 RS_DEBUG->print("RS_Modification::addPolylineNode: normal vertex found: %f/%f",
698                                 ae->getEndpoint().x, ae->getEndpoint().y);
699
700                 if (ae!=lastEntity || polyline.isClosed()==false) {
701                     newPolyline->setNextBulge(bulge);
702                     newPolyline->addVertex(ae->getEndpoint());
703                 }
704             }
705         } else {
706             RS_DEBUG->print("RS_Modification::addPolylineNode: "
707                             "Polyline contains non-atomic entities",
708                             RS_Debug::D_WARNING);
709         }
710     }
711
712     newPolyline->setNextBulge(polyline.getClosingBulge());
713     newPolyline->endPolyline();
714
715     // add new polyline:
716     container->addEntity(newPolyline);
717     if (graphicView!=NULL) {
718         graphicView->deleteEntity(&polyline);
719         graphicView->drawEntity(newPolyline);
720     }
721
722     if (document!=NULL && handleUndo) {
723         document->startUndoCycle();
724
725         polyline.setUndoState(true);
726         document->addUndoable(&polyline);
727         document->addUndoable(newPolyline);
728
729         document->endUndoCycle();
730     }
731
732     return newPolyline;
733 }
734 */
735
736
737
738 /**
739  * Deletes a node from a polyline.
740  *
741  * @param node The node to delete.
742  *
743  * @return Pointer to the new polyline or NULL.
744  */
745 /*
746 RS_Polyline* RS_Modification::deletePolylineNode(RS_Polyline& polyline,
747         const Vector& node) {
748
749     RS_DEBUG->print("RS_Modification::deletePolylineNode");
750
751     if (container==NULL) {
752         RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
753                         RS_Debug::D_WARNING);
754         return NULL;
755     }
756
757     if (node.valid==false) {
758         RS_DEBUG->print("RS_Modification::deletePolylineNode: "
759                         "node not valid",
760                         RS_Debug::D_WARNING);
761         return NULL;
762     }
763
764     // check if the polyline is no longer there after deleting the node:
765     if (polyline.count()==1) {
766         RS_Entity* e = polyline.firstEntity();
767         if (e!=NULL && e->isAtomic()) {
768             RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
769             if (node.distanceTo(ae->getStartpoint())<1.0e-6 ||
770                     node.distanceTo(ae->getEndpoint())<1.0e-6) {
771
772                 if (graphicView!=NULL) {
773                     graphicView->deleteEntity(&polyline);
774                 }
775
776                 if (document!=NULL && handleUndo) {
777                     document->startUndoCycle();
778                     polyline.setUndoState(true);
779                     document->addUndoable(&polyline);
780                     document->endUndoCycle();
781                 }
782             }
783         }
784         return NULL;
785     }
786
787     RS_Polyline* newPolyline = new RS_Polyline(container);
788     newPolyline->setClosed(polyline.isClosed());
789     newPolyline->setSelected(polyline.isSelected());
790     newPolyline->setLayer(polyline.getLayer());
791     newPolyline->setPen(polyline.getPen());
792
793     // copy polyline and drop deleted node:
794     bool first = true;
795     bool lastDropped = false;
796     RS_Entity* lastEntity = polyline.lastEntity();
797     for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
798             e=polyline.nextEntity()) {
799
800         if (e->isAtomic()) {
801             RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
802             double bulge = 0.0;
803             if (ae->rtti()==RS2::EntityArc) {
804                 RS_DEBUG->print("RS_Modification::deletePolylineNode: arc segment");
805                 bulge = ((RS_Arc*)ae)->getBulge();
806             } else {
807                 RS_DEBUG->print("RS_Modification::deletePolylineNode: line segment");
808                 bulge = 0.0;
809             }
810
811             // last entity is closing entity and will be added below with endPolyline()
812             if (e==lastEntity && polyline.isClosed()) {
813                 continue;
814             }
815
816             // first vertex (startpoint)
817             if (first && node.distanceTo(ae->getStartpoint())>1.0e-6) {
818                 RS_DEBUG->print("RS_Modification::deletePolylineNode: first node: %f/%f",
819                                 ae->getStartpoint().x, ae->getStartpoint().y);
820
821                 newPolyline->setNextBulge(bulge);
822                 newPolyline->addVertex(ae->getStartpoint());
823                 first = false;
824             }
825
826             // normal node (not deleted):
827             if (first==false && node.distanceTo(ae->getEndpoint())>1.0e-6) {
828                 RS_DEBUG->print("RS_Modification::deletePolylineNode: normal vertex found: %f/%f",
829                                 ae->getEndpoint().x, ae->getEndpoint().y);
830                 if (lastDropped) {
831                     //bulge = 0.0;
832                 }
833                 newPolyline->setNextBulge(bulge);
834                 newPolyline->addVertex(ae->getEndpoint());
835                 lastDropped = false;
836             }
837
838             // drop deleted node:
839             else {
840                 RS_DEBUG->print("RS_Modification::deletePolylineNode: deleting vertex: %f/%f",
841                                 ae->getEndpoint().x, ae->getEndpoint().y);
842                 lastDropped = true;
843             }
844         } else {
845             RS_DEBUG->print("RS_Modification::deletePolylineNode: "
846                             "Polyline contains non-atomic entities",
847                             RS_Debug::D_WARNING);
848         }
849     }
850
851     RS_DEBUG->print("RS_Modification::deletePolylineNode: ending polyline");
852     newPolyline->setNextBulge(polyline.getClosingBulge());
853     newPolyline->endPolyline();
854
855     //if (newPolyline->count()==1) {
856     //}
857
858     // add new polyline:
859     RS_DEBUG->print("RS_Modification::deletePolylineNode: adding new polyline");
860     container->addEntity(newPolyline);
861     if (graphicView!=NULL) {
862         graphicView->deleteEntity(&polyline);
863         graphicView->drawEntity(newPolyline);
864     }
865
866     RS_DEBUG->print("RS_Modification::deletePolylineNode: handling undo");
867     if (document!=NULL && handleUndo) {
868         document->startUndoCycle();
869
870         polyline.setUndoState(true);
871         document->addUndoable(&polyline);
872         document->addUndoable(newPolyline);
873
874         document->endUndoCycle();
875     }
876
877     return newPolyline;
878 }
879 */
880
881
882
883 /**
884  * Deletes all nodes between the two given nodes (exclusive).
885  *
886  * @param node1 First limiting node.
887  * @param node2 Second limiting node.
888  *
889  * @return Pointer to the new polyline or NULL.
890  */
891 /*
892 RS_Polyline* RS_Modification::deletePolylineNodesBetween(RS_Polyline& polyline,
893         RS_AtomicEntity& segment, const Vector& node1, const Vector& node2) {
894
895     RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween");
896
897     if (container==NULL) {
898         RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
899                         RS_Debug::D_WARNING);
900         return NULL;
901     }
902
903     if (node1.valid==false || node2.valid==false) {
904         RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
905                         "node not valid",
906                         RS_Debug::D_WARNING);
907         return NULL;
908     }
909
910     if (node1.distanceTo(node2)<1.0e-6) {
911         RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
912                         "nodes are identical",
913                         RS_Debug::D_WARNING);
914         return NULL;
915     }
916
917     // check if there's nothing to delete:
918     for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
919             e=polyline.nextEntity()) {
920
921         if (e->isAtomic()) {
922             RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
923
924             if ((node1.distanceTo(ae->getStartpoint())<1.0e-6 &&
925                     node2.distanceTo(ae->getEndpoint())<1.0e-6) ||
926                     (node2.distanceTo(ae->getStartpoint())<1.0e-6 &&
927                      node1.distanceTo(ae->getEndpoint())<1.0e-6)) {
928
929                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
930                                 "nothing to delete",
931                                 RS_Debug::D_WARNING);
932                 return NULL;
933             }
934         }
935     }
936
937
938     // check if the start point is involved:
939     bool startpointInvolved = false;
940     if (node1.distanceTo(polyline.getStartpoint())<1.0e-6 ||
941             node2.distanceTo(polyline.getStartpoint())<1.0e-6) {
942         startpointInvolved = true;
943     }
944
945
946     // check which part of the polyline has to be deleted:
947     bool deleteStart = false;
948     if (polyline.isClosed()) {
949         bool found = false;
950         double length1 = 0.0;
951         double length2 = 0.0;
952         RS_Entity* e=polyline.firstEntity();
953
954         if (startpointInvolved) {
955             if (e->isAtomic()) {
956                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
957                 length1+=ae->getLength();
958                         }
959             e = polyline.nextEntity();
960         }
961         for (; e!=NULL; e=polyline.nextEntity()) {
962
963             if (e->isAtomic()) {
964                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
965
966                 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
967                         node2.distanceTo(ae->getStartpoint())<1.0e-6) {
968
969                     found = !found;
970                 }
971
972                 if (found) {
973                     length2+=ae->getLength();
974                 } else {
975                     length1+=ae->getLength();
976                 }
977             }
978         }
979         if (length1<length2) {
980             deleteStart = true;
981         } else {
982             deleteStart = false;
983         }
984     }
985
986     RS_Polyline* newPolyline = new RS_Polyline(container);
987     newPolyline->setClosed(polyline.isClosed());
988     newPolyline->setSelected(polyline.isSelected());
989     newPolyline->setLayer(polyline.getLayer());
990     newPolyline->setPen(polyline.getPen());
991
992     if (startpointInvolved && deleteStart && polyline.isClosed()) {
993         newPolyline->setNextBulge(0.0);
994         newPolyline->addVertex(polyline.getStartpoint());
995     }
996
997     // copy polyline and drop deleted nodes:
998     bool first = true;
999     bool removing = deleteStart;
1000     bool done = false;
1001     bool nextIsStraight = false;
1002     RS_Entity* lastEntity = polyline.lastEntity();
1003     int i=0;
1004     double bulge = 0.0;
1005     for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1006             e=polyline.nextEntity()) {
1007
1008         RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: entity: %d", i++);
1009         RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
1010
1011         if (e->isAtomic()) {
1012             RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1013             if (ae->rtti()==RS2::EntityArc) {
1014                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: arc segment");
1015                 bulge = ((RS_Arc*)ae)->getBulge();
1016             } else {
1017                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: line segment");
1018                 bulge = 0.0;
1019             }
1020
1021             // last entity is closing entity and will be added below with endPolyline()
1022             if (e==lastEntity && polyline.isClosed()) {
1023                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1024                                 "dropping last vertex of closed polyline");
1025                 continue;
1026             }
1027
1028             // first vertex (startpoint)
1029             if (first) {
1030                 if (!removing) {
1031                     RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: first node: %f/%f",
1032                                     ae->getStartpoint().x, ae->getStartpoint().y);
1033                     newPolyline->setNextBulge(bulge);
1034                     newPolyline->addVertex(ae->getStartpoint());
1035                     first = false;
1036                 }
1037             }
1038
1039             // stop removing nodes:
1040             if (removing==true &&
1041                     (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1042                      node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1043                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1044                                 "stop removing at: %f/%f",
1045                                 ae->getEndpoint().x, ae->getEndpoint().y);
1046                 removing = false;
1047                 done = true;
1048                                 if (first==false) {
1049                         nextIsStraight = true;
1050                                 }
1051             }
1052
1053             // normal node (not deleted):
1054             if (removing==false && (done==false || deleteStart==false)) {
1055                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1056                                 "normal vertex found: %f/%f",
1057                                 ae->getEndpoint().x, ae->getEndpoint().y);
1058                 if (nextIsStraight) {
1059                     bulge = 0.0;
1060                     nextIsStraight = false;
1061                 }
1062                 newPolyline->setNextBulge(bulge);
1063                 newPolyline->addVertex(ae->getEndpoint());
1064             }
1065
1066             // drop deleted node:
1067             else {
1068                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1069                                 "deleting vertex: %f/%f",
1070                                 ae->getEndpoint().x, ae->getEndpoint().y);
1071             }
1072
1073             // start to remove nodes from now on:
1074             if (done==false && removing==false &&
1075                     (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1076                      node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1077                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1078                                 "start removing at: %f/%f",
1079                                 ae->getEndpoint().x, ae->getEndpoint().y);
1080                 removing = true;
1081             }
1082
1083             if (done) {
1084                 done=false;
1085             }
1086         } else {
1087             RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1088                             "Polyline contains non-atomic entities",
1089                             RS_Debug::D_WARNING);
1090         }
1091     }
1092
1093     RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: ending polyline");
1094     newPolyline->setNextBulge(polyline.getClosingBulge());
1095     newPolyline->endPolyline();
1096
1097     // add new polyline:
1098     RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: adding new polyline");
1099     container->addEntity(newPolyline);
1100     if (graphicView!=NULL) {
1101         graphicView->deleteEntity(&polyline);
1102         graphicView->drawEntity(newPolyline);
1103     }
1104
1105     RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: handling undo");
1106     if (document!=NULL && handleUndo) {
1107         document->startUndoCycle();
1108
1109         polyline.setUndoState(true);
1110         document->addUndoable(&polyline);
1111         document->addUndoable(newPolyline);
1112
1113         document->endUndoCycle();
1114     }
1115
1116     return newPolyline;
1117 }
1118 */
1119
1120
1121
1122 /**
1123  * Trims two segments of a polyline all nodes between the two trim segments
1124  * are removed.
1125  *
1126  * @param polyline The polyline entity.
1127  * @param segment1 First segment to trim.
1128  * @param segment2 Second segment to trim.
1129  *
1130  * @return Pointer to the new polyline or NULL.
1131  */
1132 /*
1133 RS_Polyline* RS_Modification::polylineTrim(RS_Polyline& polyline,
1134         RS_AtomicEntity& segment1,
1135         RS_AtomicEntity& segment2) {
1136
1137     RS_DEBUG->print("RS_Modification::polylineTrim");
1138
1139     if (container==NULL) {
1140         RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
1141                         RS_Debug::D_WARNING);
1142         return NULL;
1143     }
1144
1145     if (segment1.getParent()!=&polyline || segment2.getParent()!=&polyline) {
1146         RS_DEBUG->print("RS_Modification::polylineTrim: "
1147                         "segments not in polyline",
1148                         RS_Debug::D_WARNING);
1149         return NULL;
1150     }
1151
1152     if (&segment1==&segment2) {
1153         RS_DEBUG->print("RS_Modification::polylineTrim: "
1154                         "segments are identical",
1155                         RS_Debug::D_WARNING);
1156         return NULL;
1157     }
1158
1159     VectorSolutions sol;
1160     sol = RS_Information::getIntersection(&segment1, &segment2, false);
1161
1162     if (sol.getNumber()==0) {
1163         RS_DEBUG->print("RS_Modification::polylineTrim: "
1164                         "segments cannot be trimmed",
1165                         RS_Debug::D_WARNING);
1166         return NULL;
1167     }
1168
1169     // check which segment comes first in the polyline:
1170     RS_AtomicEntity* firstSegment;
1171     if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1172         firstSegment = &segment2;
1173     } else {
1174         firstSegment = &segment1;
1175     }
1176
1177     // find out if we need to trim towards the open part of the polyline
1178     bool reverseTrim;
1179     reverseTrim = !RS_Math::isSameDirection(firstSegment->getDirection1(),
1180                                             firstSegment->getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1181     //reverseTrim = reverseTrim || !RS_Math::isSameDirection(segment2.getDirection1(),
1182     //  segment2.getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1183
1184     RS_Polyline* newPolyline = new RS_Polyline(container);
1185     newPolyline->setClosed(polyline.isClosed());
1186     newPolyline->setSelected(polyline.isSelected());
1187     newPolyline->setLayer(polyline.getLayer());
1188     newPolyline->setPen(polyline.getPen());
1189
1190     // normal trimming: start removing nodes at trim segment. ends stay the same
1191     if (reverseTrim==false) {
1192         // copy polyline, trim segments and drop between nodes:
1193         bool first = true;
1194         bool removing = false;
1195         bool nextIsStraight = false;
1196         RS_Entity* lastEntity = polyline.lastEntity();
1197         for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1198                 e=polyline.nextEntity()) {
1199
1200             if (e->isAtomic()) {
1201                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1202                 double bulge = 0.0;
1203                 if (ae->rtti()==RS2::EntityArc) {
1204                     RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1205                     bulge = ((RS_Arc*)ae)->getBulge();
1206                 } else {
1207                     RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1208                     bulge = 0.0;
1209                 }
1210
1211                 // last entity is closing entity and will be added below with endPolyline()
1212                 if (e==lastEntity && polyline.isClosed()) {
1213                     RS_DEBUG->print("RS_Modification::polylineTrim: "
1214                                     "dropping last vertex of closed polyline");
1215                     continue;
1216                 }
1217
1218                 // first vertex (startpoint)
1219                 if (first) {
1220                     RS_DEBUG->print("RS_Modification::polylineTrim: first node: %f/%f",
1221                                     ae->getStartpoint().x, ae->getStartpoint().y);
1222
1223                     newPolyline->setNextBulge(bulge);
1224                     newPolyline->addVertex(ae->getStartpoint());
1225                     first = false;
1226                 }
1227
1228                 // trim and start removing nodes:
1229                 if (removing==false && (ae==&segment1 || ae==&segment2)) {
1230                     RS_DEBUG->print("RS_Modification::polylineTrim: "
1231                                     "start removing at trim point %f/%f",
1232                                     sol.get(0).x, sol.get(0).y);
1233                     newPolyline->setNextBulge(0.0);
1234                     newPolyline->addVertex(sol.get(0));
1235                     removing = true;
1236                     nextIsStraight = true;
1237                 }
1238
1239                 // stop removing nodes:
1240                 else if (removing==true && (ae==&segment1 || ae==&segment2)) {
1241                     RS_DEBUG->print("RS_Modification::polylineTrim: stop removing at: %f/%f",
1242                                     ae->getEndpoint().x, ae->getEndpoint().y);
1243                     removing = false;
1244                 }
1245
1246                 // normal node (not deleted):
1247                 if (removing==false) {
1248                     RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1249                                     ae->getEndpoint().x, ae->getEndpoint().y);
1250                     if (nextIsStraight) {
1251                         newPolyline->setNextBulge(0.0);
1252                         nextIsStraight = false;
1253                     } else {
1254                         newPolyline->setNextBulge(bulge);
1255                     }
1256                     newPolyline->addVertex(ae->getEndpoint());
1257                 }
1258             } else {
1259                 RS_DEBUG->print("RS_Modification::polylineTrim: "
1260                                 "Polyline contains non-atomic entities",
1261                                 RS_Debug::D_WARNING);
1262             }
1263         }
1264     }
1265
1266     // reverse trimming: remove nodes at the ends and keep those in between
1267     else {
1268         // copy polyline, trim segments and drop between nodes:
1269         //bool first = true;
1270         bool removing = true;
1271         bool nextIsStraight = false;
1272         RS_Entity* lastEntity = polyline.lastEntity();
1273         for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1274                 e=polyline.nextEntity()) {
1275
1276             if (e->isAtomic()) {
1277                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1278                 double bulge = 0.0;
1279                 if (ae->rtti()==RS2::EntityArc) {
1280                     RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1281                     bulge = ((RS_Arc*)ae)->getBulge();
1282                 } else {
1283                     RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1284                     bulge = 0.0;
1285                 }
1286
1287                 // last entity is closing entity and will be added below with endPolyline()
1288                 if (e==lastEntity && polyline.isClosed()) {
1289                     RS_DEBUG->print("RS_Modification::polylineTrim: "
1290                                     "dropping last vertex of closed polyline");
1291                     continue;
1292                 }
1293
1294                 // trim and stop removing nodes:
1295                 if (removing==true && (ae==&segment1 || ae==&segment2)) {
1296                     RS_DEBUG->print("RS_Modification::polylineTrim: "
1297                                     "stop removing at trim point %f/%f",
1298                                     sol.get(0).x, sol.get(0).y);
1299                     newPolyline->setNextBulge(0.0);
1300                     // start of new polyline:
1301                     newPolyline->addVertex(sol.get(0));
1302                     removing = false;
1303                     nextIsStraight = true;
1304                 }
1305
1306                 // start removing nodes again:
1307                 else if (removing==false && (ae==&segment1 || ae==&segment2)) {
1308                     RS_DEBUG->print("RS_Modification::polylineTrim: start removing at: %f/%f",
1309                                     ae->getEndpoint().x, ae->getEndpoint().y);
1310                     newPolyline->setNextBulge(0.0);
1311                     // start of new polyline:
1312                     newPolyline->addVertex(sol.get(0));
1313                     removing = true;
1314                 }
1315
1316                 // normal node (not deleted):
1317                 if (removing==false) {
1318                     RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1319                                     ae->getEndpoint().x, ae->getEndpoint().y);
1320                     if (nextIsStraight) {
1321                         newPolyline->setNextBulge(0.0);
1322                         nextIsStraight = false;
1323                     } else {
1324                         newPolyline->setNextBulge(bulge);
1325                     }
1326                     newPolyline->addVertex(ae->getEndpoint());
1327                 }
1328             } else {
1329                 RS_DEBUG->print("RS_Modification::polylineTrim: "
1330                                 "Polyline contains non-atomic entities",
1331                                 RS_Debug::D_WARNING);
1332             }
1333         }
1334     }
1335
1336     RS_DEBUG->print("RS_Modification::polylineTrim: ending polyline");
1337     newPolyline->setNextBulge(polyline.getClosingBulge());
1338     newPolyline->endPolyline();
1339
1340     // add new polyline:
1341     RS_DEBUG->print("RS_Modification::polylineTrim: adding new polyline");
1342     container->addEntity(newPolyline);
1343     if (graphicView!=NULL) {
1344         graphicView->deleteEntity(&polyline);
1345         graphicView->drawEntity(newPolyline);
1346     }
1347
1348     RS_DEBUG->print("RS_Modification::polylineTrim: handling undo");
1349     if (document!=NULL && handleUndo) {
1350         document->startUndoCycle();
1351
1352         polyline.setUndoState(true);
1353         document->addUndoable(&polyline);
1354         document->addUndoable(newPolyline);
1355
1356         document->endUndoCycle();
1357     }
1358
1359     return newPolyline;
1360 }
1361 */
1362
1363 /**
1364  * Moves all selected entities with the given data for the move
1365  * modification.
1366  */
1367 bool RS_Modification::move(RS_MoveData & data)
1368 {
1369         if (container == NULL)
1370         {
1371                 RS_DEBUG->print("RS_Modification::move: no valid container", RS_Debug::D_WARNING);
1372                 return false;
1373         }
1374
1375 //    Q3PtrList<RS_Entity> addList;
1376 //    addList.setAutoDelete(false);
1377         QList<RS_Entity *> addList;
1378
1379         if (document != NULL && handleUndo)
1380                 document->startUndoCycle();
1381
1382         // Create new entites
1383         for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1384         {
1385                 // too slow:
1386                 //for (uint i=0; i<container->count(); ++i) {
1387                 //RS_Entity* e = container->entityAt(i);
1388                 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1389                 {
1390                         if (e != NULL && e->isSelected())
1391                         {
1392                                 RS_Entity * ec = e->clone();
1393                                 ec->move(data.offset * num);
1394
1395                                 if (data.useCurrentLayer)
1396                                         ec->setLayerToActive();
1397
1398                                 if (data.useCurrentAttributes)
1399                                         ec->setPenToActive();
1400
1401                                 if (ec->rtti() == RS2::EntityInsert)
1402                                         ((RS_Insert *)ec)->update();
1403
1404                                 // since 2.0.4.0: keep selection
1405                                 ec->setSelected(true);
1406                                 addList.append(ec);
1407                         }
1408                 }
1409         }
1410
1411         deselectOriginals(data.number==0);
1412         addNewEntities(addList);
1413
1414         if (document != NULL && handleUndo)
1415                 document->endUndoCycle();
1416
1417         if (graphicView != NULL)
1418                 graphicView->redraw();
1419
1420         return true;
1421 }
1422
1423 /**
1424  * Rotates all selected entities with the given data for the rotation.
1425  */
1426 bool RS_Modification::rotate(RS_RotateData & data)
1427 {
1428         if (container == NULL)
1429         {
1430                 RS_DEBUG->print("RS_Modification::rotate: no valid container",
1431                                                 RS_Debug::D_WARNING);
1432                 return false;
1433         }
1434
1435 //      Q3PtrList<RS_Entity> addList;
1436 //      addList.setAutoDelete(false);
1437         QList<RS_Entity *> addList;
1438
1439         if (document!=NULL && handleUndo)
1440                 document->startUndoCycle();
1441
1442         // Create new entites
1443         for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1444         {
1445                 for (RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1446                 {
1447                         //for (uint i=0; i<container->count(); ++i) {
1448                         //RS_Entity* e = container->entityAt(i);
1449
1450                         if (e != NULL && e->isSelected())
1451                         {
1452                                 RS_Entity * ec = e->clone();
1453                                 ec->setSelected(false);
1454                                 ec->rotate(data.center, data.angle*num);
1455
1456                                 if (data.useCurrentLayer)
1457                                         ec->setLayerToActive();
1458
1459                                 if (data.useCurrentAttributes)
1460                                         ec->setPenToActive();
1461
1462                                 if (ec->rtti() == RS2::EntityInsert)
1463                                         ((RS_Insert *)ec)->update();
1464
1465                                 addList.append(ec);
1466                         }
1467                 }
1468         }
1469
1470         deselectOriginals(data.number == 0);
1471         addNewEntities(addList);
1472
1473         if (document != NULL && handleUndo)
1474                 document->endUndoCycle();
1475
1476         if (graphicView != NULL)
1477                 graphicView->redraw();
1478
1479         return true;
1480 }
1481
1482 /**
1483  * Moves all selected entities with the given data for the scale
1484  * modification.
1485  */
1486 bool RS_Modification::scale(RS_ScaleData & data)
1487 {
1488         if (container == NULL)
1489         {
1490                 RS_DEBUG->print("RS_Modification::scale: no valid container", RS_Debug::D_WARNING);
1491                 return false;
1492         }
1493
1494 //      Q3PtrList<RS_Entity> addList;
1495 //      addList.setAutoDelete(false);
1496         QList<RS_Entity *> addList;
1497
1498         if (document!=NULL && handleUndo)
1499                 document->startUndoCycle();
1500
1501         // Create new entites
1502         for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1503         {
1504                 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1505                 {
1506                         //for (uint i=0; i<container->count(); ++i) {
1507                         //RS_Entity* e = container->entityAt(i);
1508                         if (e != NULL && e->isSelected())
1509                         {
1510                                 RS_Entity * ec = e->clone();
1511                                 ec->setSelected(false);
1512                                 ec->scale(data.referencePoint, RS_Math::pow(data.factor, num));
1513
1514                                 if (data.useCurrentLayer)
1515                                         ec->setLayerToActive();
1516
1517                                 if (data.useCurrentAttributes)
1518                                         ec->setPenToActive();
1519
1520                                 if (ec->rtti()==RS2::EntityInsert)
1521                                         ((RS_Insert*)ec)->update();
1522
1523                                 addList.append(ec);
1524                         }
1525                 }
1526         }
1527
1528         deselectOriginals(data.number == 0);
1529         addNewEntities(addList);
1530
1531         if (document != NULL && handleUndo)
1532                 document->endUndoCycle();
1533
1534         if (graphicView != NULL)
1535                 graphicView->redraw();
1536
1537         return true;
1538 }
1539
1540 /**
1541  * Mirror all selected entities with the given data for the mirror
1542  * modification.
1543  */
1544 bool RS_Modification::mirror(RS_MirrorData & data)
1545 {
1546         if (container==NULL) {
1547                 RS_DEBUG->print("RS_Modification::mirror: no valid container",
1548                                                 RS_Debug::D_WARNING);
1549                 return false;
1550         }
1551
1552 //      Q3PtrList<RS_Entity> addList;
1553 //      addList.setAutoDelete(false);
1554         QList<RS_Entity *> addList;
1555
1556         if (document!=NULL && handleUndo) {
1557                 document->startUndoCycle();
1558         }
1559
1560         // Create new entites
1561         for (int num=1;
1562                         num<=(int)data.copy || (data.copy==false && num<=1);
1563                         num++) {
1564                 for (RS_Entity* e=container->firstEntity();
1565                                 e!=NULL;
1566                                 e=container->nextEntity()) {
1567                         //for (uint i=0; i<container->count(); ++i) {
1568                         //RS_Entity* e = container->entityAt(i);
1569
1570                         if (e!=NULL && e->isSelected()) {
1571                                 RS_Entity* ec = e->clone();
1572                                 ec->setSelected(false);
1573
1574                                 ec->mirror(data.axisPoint1, data.axisPoint2);
1575                                 if (data.useCurrentLayer) {
1576                                         ec->setLayerToActive();
1577                                 }
1578                                 if (data.useCurrentAttributes) {
1579                                         ec->setPenToActive();
1580                                 }
1581                                 if (ec->rtti()==RS2::EntityInsert) {
1582                                         ((RS_Insert*)ec)->update();
1583                                 }
1584                                 addList.append(ec);
1585                         }
1586                 }
1587         }
1588
1589         deselectOriginals(data.copy==false);
1590         addNewEntities(addList);
1591
1592         if (document!=NULL && handleUndo) {
1593                 document->endUndoCycle();
1594         }
1595
1596         if (graphicView!=NULL) {
1597                 graphicView->redraw();
1598         }
1599         return true;
1600 }
1601
1602 /**
1603  * Rotates entities around two centers with the given parameters.
1604  */
1605 bool RS_Modification::rotate2(RS_Rotate2Data & data)
1606 {
1607         if (container==NULL) {
1608                 RS_DEBUG->print("RS_Modification::rotate2: no valid container",
1609                                                 RS_Debug::D_WARNING);
1610                 return false;
1611         }
1612
1613 //      Q3PtrList<RS_Entity> addList;
1614 //      addList.setAutoDelete(false);
1615         QList<RS_Entity *> addList;
1616
1617         if (document!=NULL && handleUndo) {
1618                 document->startUndoCycle();
1619         }
1620
1621         // Create new entites
1622         for (int num=1;
1623                         num<=data.number || (data.number==0 && num<=1);
1624                         num++) {
1625
1626                 for (RS_Entity* e=container->firstEntity();
1627                                 e!=NULL;
1628                                 e=container->nextEntity()) {
1629                         //for (uint i=0; i<container->count(); ++i) {
1630                         //RS_Entity* e = container->entityAt(i);
1631
1632                         if (e!=NULL && e->isSelected()) {
1633                                 RS_Entity* ec = e->clone();
1634                                 ec->setSelected(false);
1635
1636                                 ec->rotate(data.center1, data.angle1*num);
1637                                 Vector center2 = data.center2;
1638                                 center2.rotate(data.center1, data.angle1*num);
1639
1640                                 ec->rotate(center2, data.angle2*num);
1641                                 if (data.useCurrentLayer) {
1642                                         ec->setLayerToActive();
1643                                 }
1644                                 if (data.useCurrentAttributes) {
1645                                         ec->setPenToActive();
1646                                 }
1647                                 if (ec->rtti()==RS2::EntityInsert) {
1648                                         ((RS_Insert*)ec)->update();
1649                                 }
1650                                 addList.append(ec);
1651                         }
1652                 }
1653         }
1654
1655         deselectOriginals(data.number==0);
1656         addNewEntities(addList);
1657
1658         if (document!=NULL && handleUndo) {
1659                 document->endUndoCycle();
1660         }
1661
1662         if (graphicView!=NULL) {
1663                 graphicView->redraw();
1664         }
1665         return true;
1666 }
1667
1668 /**
1669  * Moves and rotates entities with the given parameters.
1670  */
1671 bool RS_Modification::moveRotate(RS_MoveRotateData & data)
1672 {
1673     if (container==NULL) {
1674         RS_DEBUG->print("RS_Modification::moveRotate: no valid container",
1675                         RS_Debug::D_WARNING);
1676         return false;
1677     }
1678
1679 //      Q3PtrList<RS_Entity> addList;
1680 //      addList.setAutoDelete(false);
1681         QList<RS_Entity *> addList;
1682
1683     if (document!=NULL && handleUndo) {
1684         document->startUndoCycle();
1685     }
1686
1687     // Create new entites
1688     for (int num=1;
1689             num<=data.number || (data.number==0 && num<=1);
1690             num++) {
1691         for (RS_Entity* e=container->firstEntity();
1692                 e!=NULL;
1693                 e=container->nextEntity()) {
1694             //for (uint i=0; i<container->count(); ++i) {
1695             //RS_Entity* e = container->entityAt(i);
1696
1697             if (e!=NULL && e->isSelected()) {
1698                 RS_Entity* ec = e->clone();
1699                 ec->setSelected(false);
1700
1701                 ec->move(data.offset*num);
1702                 ec->rotate(data.referencePoint + data.offset*num,
1703                            data.angle*num);
1704                 if (data.useCurrentLayer) {
1705                     ec->setLayerToActive();
1706                 }
1707                 if (data.useCurrentAttributes) {
1708                     ec->setPenToActive();
1709                 }
1710                 if (ec->rtti()==RS2::EntityInsert) {
1711                     ((RS_Insert*)ec)->update();
1712                 }
1713                 addList.append(ec);
1714             }
1715         }
1716     }
1717
1718     deselectOriginals(data.number==0);
1719     addNewEntities(addList);
1720
1721     if (document!=NULL && handleUndo) {
1722         document->endUndoCycle();
1723     }
1724     if (graphicView!=NULL) {
1725         graphicView->redraw();
1726     }
1727
1728     return true;
1729 }
1730
1731 /**
1732  * Deselects all selected entities and removes them if remove is true;
1733  *
1734  * @param remove true: Remove entites.
1735  */
1736 void RS_Modification::deselectOriginals(bool remove)
1737 {
1738         for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1739         {
1740                 //for (uint i=0; i<container->count(); ++i) {
1741                 //RS_Entity* e = container->entityAt(i);
1742
1743                 if (e != NULL)
1744                 {
1745                         bool selected = false;
1746                         /*
1747                                         if (e->isAtomic()) {
1748                                                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1749                                                 if (ae->isStartpointSelected() ||
1750                                                                 ae->isEndpointSelected()) {
1751
1752                                                         selected = true;
1753                                                 }
1754                                         }
1755                         */
1756
1757                         if (e->isSelected())
1758                                 selected = true;
1759
1760                         if (selected)
1761                         {
1762                                 e->setSelected(false);
1763
1764                                 if (remove)
1765                                 {
1766                                         //if (graphicView!=NULL) {
1767                                         //    graphicView->deleteEntity(e);
1768                                         //}
1769                                         e->changeUndoState();
1770
1771                                         if (document != NULL && handleUndo)
1772                                                 document->addUndoable(e);
1773                                 }
1774                                 else
1775                                 {
1776                                         //if (graphicView!=NULL) {
1777                                         //    graphicView->drawEntity(e);
1778                                         //}
1779                                 }
1780                         }
1781                 }
1782         }
1783 }
1784
1785 /**
1786  * Adds the given entities to the container and draws the entities if
1787  * there's a graphic view available.
1788  *
1789  * @param addList Entities to add.
1790  */
1791 //void RS_Modification::addNewEntities(Q3PtrList<RS_Entity> & addList)
1792 void RS_Modification::addNewEntities(QList<RS_Entity *> & addList)
1793 {
1794 //      for(RS_Entity * e=addList.first(); e!=NULL; e=addList.next())
1795         for(int i=0; i<addList.size(); i++)
1796         {
1797                 RS_Entity * e = addList[i];
1798
1799                 if (e != NULL)
1800                 {
1801                         container->addEntity(e);
1802
1803                         if (document != NULL && handleUndo)
1804                                 document->addUndoable(e);
1805                         //if (graphicView!=NULL) {
1806                         //    graphicView->drawEntity(e);
1807                         //}
1808                 }
1809         }
1810 }
1811
1812 /**
1813  * Trims or extends the given trimEntity to the intersection point of the
1814  * trimEntity and the limitEntity.
1815  *
1816  * @param trimCoord Coordinate which defines which endpoint of the
1817  *   trim entity to trim.
1818  * @param trimEntity Entity which will be trimmed.
1819  * @param limitCoord Coordinate which defines the intersection to which the
1820  *    trim entity will be trimmed.
1821  * @param limitEntity Entity to which the trim entity will be trimmed.
1822  * @param both true: Trim both entities. false: trim trimEntity only.
1823  */
1824 bool RS_Modification::trim(const Vector& trimCoord, RS_AtomicEntity* trimEntity,
1825         const Vector& limitCoord, RS_Entity* limitEntity, bool both)
1826 {
1827     if (trimEntity==NULL || limitEntity==NULL)
1828         {
1829         RS_DEBUG->print(RS_Debug::D_WARNING,
1830                         "RS_Modification::trim: At least one entity is NULL");
1831         return false;
1832     }
1833
1834     if (both && !limitEntity->isAtomic())
1835         {
1836         RS_DEBUG->print(RS_Debug::D_WARNING,
1837                         "RS_Modification::trim: limitEntity is not atomic");
1838     }
1839
1840     VectorSolutions sol;
1841
1842         if (limitEntity->isAtomic())
1843         {
1844         // intersection(s) of the two entities:
1845         sol = RS_Information::getIntersection(trimEntity, limitEntity, false);
1846     } else if (limitEntity->isContainer()) {
1847         RS_EntityContainer* ec = (RS_EntityContainer*)limitEntity;
1848
1849         sol.alloc(128);
1850         int i=0;
1851
1852         for (RS_Entity* e=ec->firstEntity(RS2::ResolveAll); e!=NULL;
1853                 e=ec->nextEntity(RS2::ResolveAll)) {
1854             //for (int i=0; i<container->count(); ++i) {
1855             //    RS_Entity* e = container->entityAt(i);
1856
1857             if (e!=NULL) {
1858
1859                 VectorSolutions s2 = RS_Information::getIntersection(trimEntity,
1860                                         e, false);
1861
1862                 if (s2.hasValid()) {
1863                     for (int k=0; k<s2.getNumber(); ++k) {
1864                         if (i<128 && s2.get(k).valid) {
1865                             if (e->isPointOnEntity(s2.get(k), 1.0e-4)) {
1866                                 sol.set(i++, s2.get(k));
1867                             }
1868                         }
1869                     }
1870                     //break;
1871                 }
1872             }
1873         }
1874     }
1875
1876     if (sol.hasValid()==false) {
1877         return false;
1878     }
1879
1880     RS_AtomicEntity* trimmed1 = NULL;
1881     RS_AtomicEntity* trimmed2 = NULL;
1882
1883     // remove trim entity from view:
1884     if (trimEntity->rtti()==RS2::EntityCircle) {
1885         // convert a circle into a trimmable arc
1886         RS_Circle* c = (RS_Circle*)trimEntity;
1887         double am = c->getCenter().angleTo(trimCoord);
1888         RS_ArcData d(c->getCenter(),
1889                      c->getRadius(),
1890                      RS_Math::correctAngle(am-M_PI/2),
1891                      RS_Math::correctAngle(am+M_PI/2), false);
1892         trimmed1 = new RS_Arc(trimEntity->getParent(), d);
1893     } else {
1894         trimmed1 = (RS_AtomicEntity*)trimEntity->clone();
1895         trimmed1->setHighlighted(false);
1896     }
1897     if (graphicView!=NULL) {
1898         graphicView->deleteEntity(trimEntity);
1899     }
1900
1901     // remove limit entity from view:
1902     if (both) {
1903         trimmed2 = (RS_AtomicEntity*)limitEntity->clone();
1904         trimmed2->setHighlighted(false);
1905         if (graphicView!=NULL) {
1906             graphicView->deleteEntity(limitEntity);
1907         }
1908     }
1909
1910     // trim trim entity
1911     int ind = 0;
1912     Vector is = sol.getClosest(limitCoord, NULL, &ind);
1913     //sol.getClosest(limitCoord, NULL, &ind);
1914     RS_DEBUG->print("RS_Modification::trim: limitCoord: %f/%f", limitCoord.x, limitCoord.y);
1915     RS_DEBUG->print("RS_Modification::trim: sol.get(0): %f/%f", sol.get(0).x, sol.get(0).y);
1916     RS_DEBUG->print("RS_Modification::trim: sol.get(1): %f/%f", sol.get(1).x, sol.get(1).y);
1917     RS_DEBUG->print("RS_Modification::trim: ind: %d", ind);
1918     Vector is2 = sol.get(ind==0 ? 1 : 0);
1919     //Vector is2 = sol.get(ind);
1920     RS_DEBUG->print("RS_Modification::trim: is2: %f/%f", is2.x, is2.y);
1921
1922     //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1923     RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1924
1925     switch (ending) {
1926     case RS2::EndingStart:
1927         trimmed1->trimStartpoint(is);
1928         if (trimEntity->rtti()==RS2::EntityCircle) {
1929             trimmed1->trimEndpoint(is2);
1930         }
1931         break;
1932     case RS2::EndingEnd:
1933         trimmed1->trimEndpoint(is);
1934         if (trimEntity->rtti()==RS2::EntityCircle) {
1935             trimmed1->trimStartpoint(is2);
1936         }
1937         break;
1938     default:
1939         break;
1940     }
1941
1942     // trim limit entity:
1943     if (both) {
1944         Vector is = sol.getClosest(limitCoord);
1945
1946         RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1947
1948         switch (ending) {
1949         case RS2::EndingStart:
1950             trimmed2->trimStartpoint(is);
1951             break;
1952         case RS2::EndingEnd:
1953             trimmed2->trimEndpoint(is);
1954             break;
1955         default:
1956             break;
1957         }
1958     }
1959
1960     // add new trimmed trim entity:
1961     container->addEntity(trimmed1);
1962     if (graphicView!=NULL) {
1963         graphicView->drawEntity(trimmed1);
1964     }
1965
1966     // add new trimmed limit entity:
1967     if (both) {
1968         container->addEntity(trimmed2);
1969         if (graphicView!=NULL) {
1970             graphicView->drawEntity(trimmed2);
1971         }
1972     }
1973
1974     if (document!=NULL && handleUndo) {
1975         document->startUndoCycle();
1976         document->addUndoable(trimmed1);
1977         trimEntity->setUndoState(true);
1978         document->addUndoable(trimEntity);
1979         if (both) {
1980             document->addUndoable(trimmed2);
1981             limitEntity->setUndoState(true);
1982             document->addUndoable(limitEntity);
1983         }
1984         document->endUndoCycle();
1985     }
1986
1987     return true;
1988 }
1989
1990
1991
1992 /**
1993  * Trims or extends the given trimEntity by the given amount.
1994  *
1995  * @param trimCoord Coordinate which defines which endpoint of the
1996  *   trim entity to trim.
1997  * @param trimEntity Entity which will be trimmed.
1998  * @param dist Amount to trim by.
1999  */
2000 bool RS_Modification::trimAmount(const Vector& trimCoord,
2001                                  RS_AtomicEntity* trimEntity,
2002                                  double dist) {
2003
2004     if (trimEntity==NULL) {
2005         RS_DEBUG->print(RS_Debug::D_WARNING,
2006                         "RS_Modification::trimAmount: Entity is NULL");
2007         return false;
2008     }
2009
2010     RS_AtomicEntity* trimmed = NULL;
2011
2012     // remove trim entity:
2013     trimmed = (RS_AtomicEntity*)trimEntity->clone();
2014     if (graphicView!=NULL) {
2015         graphicView->deleteEntity(trimEntity);
2016     }
2017
2018     // trim trim entity
2019     Vector is = trimmed->getNearestDist(-dist, trimCoord);
2020     if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2021             trimCoord.distanceTo(trimmed->getEndpoint())) {
2022         trimmed->trimStartpoint(is);
2023     } else {
2024         trimmed->trimEndpoint(is);
2025     }
2026
2027     // add new trimmed trim entity:
2028     container->addEntity(trimmed);
2029
2030     if (graphicView!=NULL) {
2031         graphicView->drawEntity(trimmed);
2032     }
2033
2034     if (document!=NULL && handleUndo) {
2035         document->startUndoCycle();
2036         document->addUndoable(trimmed);
2037         trimEntity->setUndoState(true);
2038         document->addUndoable(trimEntity);
2039         document->endUndoCycle();
2040     }
2041
2042     return true;
2043 }
2044
2045
2046
2047 /**
2048  * Cuts the given entity at the given point.
2049  */
2050 bool RS_Modification::cut(const Vector& cutCoord,
2051                           RS_AtomicEntity* cutEntity) {
2052
2053     if (cutEntity==NULL) {
2054         RS_DEBUG->print(RS_Debug::D_WARNING,
2055                         "RS_Modification::cut: Entity is NULL");
2056         return false;
2057     }
2058
2059     if (!cutCoord.valid) {
2060         RS_DEBUG->print(RS_Debug::D_WARNING,
2061                         "RS_Modification::cut: Point invalid.");
2062         return false;
2063     }
2064
2065     // cut point is at endpoint of entity:
2066     if (cutCoord.distanceTo(cutEntity->getStartpoint())<1.0e-6 ||
2067             cutCoord.distanceTo(cutEntity->getEndpoint())<1.0e-6) {
2068         RS_DEBUG->print(RS_Debug::D_WARNING,
2069                         "RS_Modification::cut: Cutting point on endpoint");
2070         return false;
2071     }
2072
2073     // delete cut entity on the screen:
2074     if (graphicView!=NULL) {
2075         graphicView->deleteEntity(cutEntity);
2076     }
2077
2078     RS_AtomicEntity* cut1 = NULL;
2079     RS_AtomicEntity* cut2 = NULL;
2080
2081     // create new two halves:
2082     if (cutEntity->rtti()==RS2::EntityCircle) {
2083         RS_Circle* c = (RS_Circle*)cutEntity;
2084         cut1 = new RS_Arc(cutEntity->getParent(),
2085                           RS_ArcData(c->getCenter(),
2086                                      c->getRadius(),
2087                                      0.0,0.0, false));
2088         cut1->setPen(cutEntity->getPen());
2089         cut1->setLayer(cutEntity->getLayer());
2090         cut2 = NULL;
2091
2092         cut1->trimEndpoint(cutCoord);
2093         cut1->trimStartpoint(cutCoord);
2094     } else {
2095         cut1 = (RS_AtomicEntity*)cutEntity->clone();
2096         cut2 = (RS_AtomicEntity*)cutEntity->clone();
2097
2098         cut1->trimEndpoint(cutCoord);
2099         cut2->trimStartpoint(cutCoord);
2100     }
2101
2102     // add new cut entity:
2103     container->addEntity(cut1);
2104     if (cut2!=NULL) {
2105         container->addEntity(cut2);
2106     }
2107
2108     if (graphicView!=NULL) {
2109         graphicView->drawEntity(cut1);
2110         if (cut2!=NULL) {
2111             graphicView->drawEntity(cut2);
2112         }
2113     }
2114
2115     if (document!=NULL && handleUndo) {
2116         document->startUndoCycle();
2117         document->addUndoable(cut1);
2118         if (cut2!=NULL) {
2119             document->addUndoable(cut2);
2120         }
2121         cutEntity->setUndoState(true);
2122         document->addUndoable(cutEntity);
2123         document->endUndoCycle();
2124     }
2125
2126     return true;
2127 }
2128
2129 /**
2130  * Stretching.
2131  */
2132 bool RS_Modification::stretch(const Vector& firstCorner, const Vector& secondCorner,
2133         const Vector& offset)
2134 {
2135     if (!offset.valid)
2136         {
2137         RS_DEBUG->print(RS_Debug::D_WARNING,
2138                         "RS_Modification::stretch: Offset invalid");
2139         return false;
2140     }
2141
2142 //      Q3PtrList<RS_Entity> addList;
2143 //      addList.setAutoDelete(false);
2144         QList<RS_Entity *> addList;
2145
2146     if (document!=NULL && handleUndo) {
2147         document->startUndoCycle();
2148     }
2149
2150     // Create new entites
2151     for (RS_Entity* e=container->firstEntity();
2152             e!=NULL;
2153             e=container->nextEntity()) {
2154         //for (int i=0; i<container->count(); ++i) {
2155         //    RS_Entity* e = container->entityAt(i);
2156
2157         if (e!=NULL &&
2158                 e->isVisible() &&
2159                 !e->isLocked() &&
2160                 (e->isInWindow(firstCorner, secondCorner) ||
2161                  e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2162
2163             RS_Entity* ec = e->clone();
2164             ec->stretch(firstCorner, secondCorner, offset);
2165             addList.append(ec);
2166             e->setSelected(true);
2167         }
2168     }
2169
2170     deselectOriginals(true);
2171     addNewEntities(addList);
2172
2173     if (document!=NULL && handleUndo) {
2174         document->endUndoCycle();
2175     }
2176
2177     if (graphicView!=NULL) {
2178         graphicView->redraw();
2179     }
2180     return true;
2181 }
2182
2183
2184
2185 /**
2186  * Bevels a corner.
2187  *
2188  * @param coord1 Mouse coordinate to specify direction from intersection.
2189  * @param entity1 First entity of the corner.
2190  * @param coord2 Mouse coordinate to specify direction from intersection.
2191  * @param entity2 Second entity of the corner.
2192  * @param data Lengths and trim flag.
2193  */
2194 bool RS_Modification::bevel(const Vector& coord1, RS_AtomicEntity* entity1,
2195                             const Vector& coord2, RS_AtomicEntity* entity2,
2196                             RS_BevelData& data) {
2197
2198     RS_DEBUG->print("RS_Modification::bevel");
2199
2200     if (entity1==NULL || entity2==NULL) {
2201         RS_DEBUG->print(RS_Debug::D_WARNING,
2202                         "RS_Modification::bevel: At least one entity is NULL");
2203         return false;
2204     }
2205
2206     RS_EntityContainer* baseContainer = container;
2207     bool isPolyline = false;
2208     bool isClosedPolyline = false;
2209
2210     if (document!=NULL && handleUndo) {
2211         document->startUndoCycle();
2212     }
2213
2214     // find out whether we're bevelling within a polyline:
2215     if (entity1->getParent()!=NULL && entity1->getParent()->rtti()==RS2::EntityPolyline) {
2216         RS_DEBUG->print("RS_Modification::bevel: trimming polyline segments");
2217         if (entity1->getParent()!=entity2->getParent()) {
2218             RS_DEBUG->print(RS_Debug::D_WARNING,
2219                             "RS_Modification::bevel: entities not in the same polyline");
2220             return false;
2221         }
2222         // clone polyline for undo
2223         if (document!=NULL && handleUndo) {
2224             RS_EntityContainer* cl =
2225                 (RS_EntityContainer*)entity1->getParent()->clone();
2226             container->addEntity(cl);
2227             //cl->setUndoState(true);
2228             document->addUndoable(cl);
2229
2230             document->addUndoable(entity1->getParent());
2231             entity1->getParent()->setUndoState(true);
2232
2233             baseContainer = cl;
2234         }
2235
2236         entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2237         entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2238
2239         //baseContainer = entity1->getParent();
2240         isPolyline = true;
2241                 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2242     }
2243
2244     RS_DEBUG->print("RS_Modification::bevel: getting intersection");
2245
2246     VectorSolutions sol =
2247         RS_Information::getIntersection(entity1, entity2, false);
2248
2249     if (sol.getNumber()==0) {
2250         return false;
2251     }
2252
2253     RS_AtomicEntity* trimmed1 = NULL;
2254     RS_AtomicEntity* trimmed2 = NULL;
2255
2256     //if (data.trim || isPolyline) {
2257         if (isPolyline) {
2258             trimmed1 = entity1;
2259             trimmed2 = entity2;
2260         } else {
2261             trimmed1 = (RS_AtomicEntity*)entity1->clone();
2262             trimmed2 = (RS_AtomicEntity*)entity2->clone();
2263         }
2264
2265         // remove trim entity (on screen):
2266         if (data.trim==true || isPolyline) {
2267             if (graphicView!=NULL) {
2268                 if (isPolyline) {
2269                     graphicView->deleteEntity(baseContainer);
2270                 } else {
2271                     graphicView->deleteEntity(entity1);
2272                     graphicView->deleteEntity(entity2);
2273                 }
2274             }
2275         }
2276
2277         // trim entities to intersection
2278         RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 01");
2279         bool start1 = false;
2280         Vector is = sol.getClosest(coord2);
2281         RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is);
2282         switch (ending1) {
2283         case RS2::EndingStart:
2284             trimmed1->trimStartpoint(is);
2285             start1 = true;
2286             break;
2287         case RS2::EndingEnd:
2288             trimmed1->trimEndpoint(is);
2289             start1 = false;
2290             break;
2291         default:
2292             break;
2293         }
2294
2295         RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 02");
2296         bool start2 = false;
2297         is = sol.getClosest(coord1);
2298         RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is);
2299         switch (ending2) {
2300         case RS2::EndingStart:
2301             trimmed2->trimStartpoint(is);
2302             start2 = true;
2303             break;
2304         case RS2::EndingEnd:
2305             trimmed2->trimEndpoint(is);
2306             start2 = false;
2307             break;
2308         default:
2309             break;
2310         }
2311     //}
2312
2313
2314     // find definitive bevel points
2315     RS_DEBUG->print("RS_Modification::bevel: find definitive bevel points");
2316     Vector bp1 = trimmed1->getNearestDist(data.length1, start1);
2317     Vector bp2 = trimmed2->getNearestDist(data.length2, start2);
2318
2319     // final trim:
2320     RS_DEBUG->print("RS_Modification::bevel: final trim");
2321     if (data.trim==true) {
2322         switch (ending1) {
2323         case RS2::EndingStart:
2324             trimmed1->trimStartpoint(bp1);
2325             break;
2326         case RS2::EndingEnd:
2327             trimmed1->trimEndpoint(bp1);
2328             break;
2329         default:
2330             break;
2331         }
2332
2333         switch (ending2) {
2334         case RS2::EndingStart:
2335             trimmed2->trimStartpoint(bp2);
2336             break;
2337         case RS2::EndingEnd:
2338             trimmed2->trimEndpoint(bp2);
2339             break;
2340         default:
2341             break;
2342         }
2343
2344         // add new trimmed entities:
2345         if (isPolyline==false) {
2346             container->addEntity(trimmed1);
2347             container->addEntity(trimmed2);
2348         }
2349         if (graphicView!=NULL) {
2350             if (!isPolyline) {
2351                 graphicView->drawEntity(trimmed1);
2352                 graphicView->drawEntity(trimmed2);
2353             }
2354         }
2355     }
2356
2357
2358     // add bevel line:
2359     RS_DEBUG->print("RS_Modification::bevel: add bevel line");
2360     RS_Line* bevel = new RS_Line(baseContainer, RS_LineData(bp1, bp2));
2361
2362     if (isPolyline==false) {
2363         baseContainer->addEntity(bevel);
2364     } else {
2365         int idx1 = baseContainer->findEntity(trimmed1);
2366         int idx2 = baseContainer->findEntity(trimmed2);
2367
2368         bevel->setSelected(baseContainer->isSelected());
2369         bevel->setLayer(baseContainer->getLayer());
2370         bevel->setPen(baseContainer->getPen());
2371
2372                 bool insertAfter1 = false;
2373                 if (!isClosedPolyline) {
2374                         insertAfter1 = (idx1<idx2);
2375                 }
2376                 else {
2377                         insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2378                                 (idx2==0 && idx1==(int)baseContainer->count()-1));
2379                 }
2380
2381         // insert bevel at the right position:
2382         //if ((idx1<idx2 && idx1!=0) ||
2383                 //      (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2384                 if (insertAfter1) {
2385             if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2386                 bevel->reverse();
2387             }
2388             baseContainer->insertEntity(idx1+1, bevel);
2389         } else {
2390             if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2391                 bevel->reverse();
2392             }
2393             baseContainer->insertEntity(idx2+1, bevel);
2394         }
2395     }
2396
2397     if (isPolyline) {
2398         ((RS_Polyline*)baseContainer)->updateEndpoints();
2399     }
2400
2401     if (graphicView!=NULL) {
2402         if (isPolyline) {
2403             graphicView->drawEntity(baseContainer);
2404         } else {
2405             graphicView->drawEntity(bevel);
2406         }
2407     }
2408
2409     RS_DEBUG->print("RS_Modification::bevel: handling undo");
2410
2411     if (document!=NULL && handleUndo) {
2412         //document->startUndoCycle();
2413
2414         if (isPolyline==false && data.trim==true) {
2415             document->addUndoable(trimmed1);
2416             entity1->setUndoState(true);
2417             document->addUndoable(entity1);
2418
2419             document->addUndoable(trimmed2);
2420             entity2->setUndoState(true);
2421             document->addUndoable(entity2);
2422         }
2423
2424         if (isPolyline==false) {
2425             document->addUndoable(bevel);
2426         }
2427
2428         document->endUndoCycle();
2429     }
2430
2431     if (data.trim==false) {
2432         RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements");
2433         delete trimmed1;
2434         delete trimmed2;
2435         RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements: ok");
2436     }
2437
2438     return true;
2439
2440 }
2441
2442
2443
2444 /**
2445  * Rounds a corner.
2446  *
2447  * @param coord Mouse coordinate to specify the rounding.
2448  * @param entity1 First entity of the corner.
2449  * @param entity2 Second entity of the corner.
2450  * @param data Radius and trim flag.
2451  */
2452 bool RS_Modification::round(const Vector& coord,
2453                             const Vector& coord1,
2454                             RS_AtomicEntity* entity1,
2455                             const Vector& coord2,
2456                             RS_AtomicEntity* entity2,
2457                             RS_RoundData& data) {
2458
2459     if (entity1==NULL || entity2==NULL) {
2460         RS_DEBUG->print(RS_Debug::D_WARNING,
2461                         "RS_Modification::round: At least one entity is NULL");
2462         return false;
2463     }
2464
2465     RS_EntityContainer* baseContainer = container;
2466     bool isPolyline = false;
2467     bool isClosedPolyline = false;
2468
2469     if (document!=NULL && handleUndo) {
2470         document->startUndoCycle();
2471     }
2472
2473     // find out whether we're rounding within a polyline:
2474     if (entity1->getParent()!=NULL &&
2475                 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2476
2477         if (entity1->getParent()!=entity2->getParent()) {
2478             RS_DEBUG->print(RS_Debug::D_WARNING,
2479                             "RS_Modification::round: entities not in "
2480                                                         "the same polyline");
2481             if (document!=NULL && handleUndo) {
2482                 document->endUndoCycle();
2483             }
2484             return false;
2485         }
2486
2487         // clone polyline for undo
2488         if (document!=NULL && handleUndo) {
2489             RS_EntityContainer* cl =
2490                 (RS_EntityContainer*)entity1->getParent()->clone();
2491             container->addEntity(cl);
2492             document->addUndoable(cl);
2493
2494             document->addUndoable(entity1->getParent());
2495             entity1->getParent()->setUndoState(true);
2496
2497             baseContainer = cl;
2498         }
2499
2500         entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2501         entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2502
2503         isPolyline = true;
2504                 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2505     }
2506
2507     // create 2 tmp parallels
2508     RS_Creation creation(NULL, NULL);
2509     RS_Entity* par1 = creation.createParallel(coord, data.radius, 1, entity1);
2510     RS_Entity* par2 = creation.createParallel(coord, data.radius, 1, entity2);
2511
2512     VectorSolutions sol2 =
2513         RS_Information::getIntersection(entity1, entity2, false);
2514
2515     VectorSolutions sol =
2516         RS_Information::getIntersection(par1, par2, false);
2517
2518     if (sol.getNumber()==0) {
2519         if (document!=NULL && handleUndo) {
2520             document->endUndoCycle();
2521         }
2522         return false;
2523     }
2524
2525     // there might be two intersections: choose the closest:
2526     Vector is = sol.getClosest(coord);
2527     Vector p1 = entity1->getNearestPointOnEntity(is, false);
2528     Vector p2 = entity2->getNearestPointOnEntity(is, false);
2529     double ang1 = is.angleTo(p1);
2530     double ang2 = is.angleTo(p2);
2531     bool reversed = (RS_Math::getAngleDifference(ang1, ang2)>M_PI);
2532
2533     RS_Arc* arc = new RS_Arc(baseContainer,
2534                              RS_ArcData(is,
2535                                         data.radius,
2536                                         ang1, ang2,
2537                                         reversed));
2538
2539
2540     RS_AtomicEntity* trimmed1 = NULL;
2541     RS_AtomicEntity* trimmed2 = NULL;
2542
2543     if (data.trim || isPolyline) {
2544         if (isPolyline) {
2545             trimmed1 = entity1;
2546             trimmed2 = entity2;
2547         } else {
2548             trimmed1 = (RS_AtomicEntity*)entity1->clone();
2549             trimmed2 = (RS_AtomicEntity*)entity2->clone();
2550         }
2551
2552         // remove trim entity:
2553         if (graphicView!=NULL) {
2554             if (isPolyline) {
2555                 graphicView->deleteEntity(baseContainer);
2556             } else {
2557                 graphicView->deleteEntity(entity1);
2558                 graphicView->deleteEntity(entity2);
2559             }
2560         }
2561
2562         // trim entities to intersection
2563         Vector is2 = sol2.getClosest(coord2);
2564         RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2565         switch (ending1) {
2566         case RS2::EndingStart:
2567             trimmed1->trimStartpoint(p1);
2568             break;
2569         case RS2::EndingEnd:
2570             trimmed1->trimEndpoint(p1);
2571             break;
2572         default:
2573             break;
2574         }
2575
2576         is2 = sol2.getClosest(coord1);
2577         RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2578         switch (ending2) {
2579         case RS2::EndingStart:
2580             trimmed2->trimStartpoint(p2);
2581             break;
2582         case RS2::EndingEnd:
2583             trimmed2->trimEndpoint(p2);
2584             break;
2585         default:
2586             break;
2587         }
2588
2589         // add new trimmed entities:
2590         if (isPolyline==false) {
2591             container->addEntity(trimmed1);
2592             container->addEntity(trimmed2);
2593         }
2594         if (graphicView!=NULL) {
2595             if (!isPolyline) {
2596                 graphicView->drawEntity(trimmed1);
2597                 graphicView->drawEntity(trimmed2);
2598             }
2599         }
2600     }
2601
2602     // add rounding:
2603     if (isPolyline==false) {
2604         baseContainer->addEntity(arc);
2605     } else {
2606         // find out which base entity is before the rounding:
2607         int idx1 = baseContainer->findEntity(trimmed1);
2608         int idx2 = baseContainer->findEntity(trimmed2);
2609
2610         arc->setSelected(baseContainer->isSelected());
2611         arc->setLayer(baseContainer->getLayer());
2612         arc->setPen(baseContainer->getPen());
2613
2614                 RS_DEBUG->print("RS_Modification::round: idx1<idx2: %d", (int)(idx1<idx2));
2615                 RS_DEBUG->print("RS_Modification::round: idx1!=0: %d", (int)(idx1!=0));
2616                 RS_DEBUG->print("RS_Modification::round: idx2==0: %d", (int)(idx2==0));
2617                 RS_DEBUG->print("RS_Modification::round: idx1==(int)baseContainer->count()-1: %d",
2618                         (int)(idx1==(int)baseContainer->count()-1));
2619
2620                 bool insertAfter1 = false;
2621                 if (!isClosedPolyline) {
2622                         insertAfter1 = (idx1<idx2);
2623                 }
2624                 else {
2625                         insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2626                                 (idx2==0 && idx1==(int)baseContainer->count()-1));
2627                 }
2628
2629         // insert rounding at the right position:
2630         //if ((idx1<idx2 && idx1!=0) ||
2631                 //      (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2632         //if (idx1<idx2) {
2633         if (insertAfter1) {
2634             if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2635                 arc->reverse();
2636             }
2637             baseContainer->insertEntity(idx1+1, arc);
2638         } else {
2639             if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2640                 arc->reverse();
2641             }
2642             baseContainer->insertEntity(idx2+1, arc);
2643         }
2644     }
2645
2646     if (isPolyline) {
2647         ((RS_Polyline*)baseContainer)->updateEndpoints();
2648     }
2649
2650     if (graphicView!=NULL) {
2651         if (isPolyline) {
2652             graphicView->drawEntity(baseContainer);
2653         } else {
2654             graphicView->drawEntity(arc);
2655         }
2656     }
2657
2658     if (document!=NULL && handleUndo) {
2659         if (isPolyline==false && data.trim==true) {
2660             document->addUndoable(trimmed1);
2661             entity1->setUndoState(true);
2662             document->addUndoable(entity1);
2663
2664             document->addUndoable(trimmed2);
2665             entity2->setUndoState(true);
2666             document->addUndoable(entity2);
2667         }
2668
2669         if (isPolyline==false) {
2670             document->addUndoable(arc);
2671         }
2672
2673         document->endUndoCycle();
2674     }
2675
2676     delete par1;
2677     delete par2;
2678
2679     return true;
2680 }
2681
2682 /**
2683  * Removes the selected entity containers and adds the entities in them as
2684  * new single entities.
2685  */
2686 bool RS_Modification::explode()
2687 {
2688     if (container == NULL)
2689         {
2690         RS_DEBUG->print("RS_Modification::explode: no valid container for addinge entities",
2691                         RS_Debug::D_WARNING);
2692         return false;
2693     }
2694
2695 //      Q3PtrList<RS_Entity> addList;
2696 //      addList.setAutoDelete(false);
2697         QList<RS_Entity *> addList;
2698
2699     if (document!=NULL && handleUndo) {
2700         document->startUndoCycle();
2701     }
2702
2703     for (RS_Entity* e=container->firstEntity();
2704             e!=NULL;
2705             e=container->nextEntity()) {
2706         //for (uint i=0; i<container->count(); ++i) {
2707         //RS_Entity* e = container->entityAt(i);
2708
2709         if (e!=NULL && e->isSelected()) {
2710             if (e->isContainer()) {
2711
2712                 // add entities from container:
2713                 RS_EntityContainer* ec = (RS_EntityContainer*)e;
2714                 //ec->setSelected(false);
2715
2716                 // iterate and explode container:
2717                 //for (uint i2=0; i2<ec->count(); ++i2) {
2718                 //    RS_Entity* e2 = ec->entityAt(i2);
2719                 RS2::ResolveLevel rl;
2720                 bool resolvePen;
2721                 bool resolveLayer;
2722
2723                 switch (ec->rtti()) {
2724                 case RS2::EntityText:
2725                 case RS2::EntityHatch:
2726                 case RS2::EntityPolyline:
2727                     rl = RS2::ResolveAll;
2728                     resolveLayer = true;
2729                     resolvePen = false;
2730                     break;
2731
2732                 case RS2::EntityInsert:
2733                     resolvePen = false;
2734                     resolveLayer = false;
2735                     rl = RS2::ResolveNone;
2736                     break;
2737
2738                 case RS2::EntityDimAligned:
2739                 case RS2::EntityDimLinear:
2740                 case RS2::EntityDimRadial:
2741                 case RS2::EntityDimDiametric:
2742                 case RS2::EntityDimAngular:
2743                 case RS2::EntityDimLeader:
2744                     rl = RS2::ResolveNone;
2745                     resolveLayer = true;
2746                     resolvePen = false;
2747                     break;
2748
2749                 default:
2750                     rl = RS2::ResolveAll;
2751                     resolveLayer = true;
2752                     resolvePen = false;
2753                     break;
2754                 }
2755
2756                 for (RS_Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2757                         e2 = ec->nextEntity(rl)) {
2758
2759                     if (e2!=NULL) {
2760                         RS_Entity* clone = e2->clone();
2761                         clone->setSelected(false);
2762                         clone->reparent(container);
2763
2764                         if (resolveLayer) {
2765                             clone->setLayer(ec->getLayer());
2766                         } else {
2767                             clone->setLayer(e2->getLayer());
2768                         }
2769
2770                         clone->setPen(ec->getPen(resolvePen));
2771
2772                         addList.append(clone);
2773
2774                         clone->update();
2775                     }
2776                 }
2777             } else {
2778                 e->setSelected(false);
2779             }
2780         }
2781     }
2782
2783     deselectOriginals(true);
2784     addNewEntities(addList);
2785
2786     if (document!=NULL && handleUndo) {
2787         document->endUndoCycle();
2788     }
2789
2790     if (graphicView!=NULL) {
2791         graphicView->redraw();
2792     }
2793
2794     return true;
2795 }
2796
2797 bool RS_Modification::explodeTextIntoLetters()
2798 {
2799     if (container == NULL)
2800         {
2801         RS_DEBUG->print("RS_Modification::explodeTextIntoLetters: no valid container"
2802                         " for addinge entities", RS_Debug::D_WARNING);
2803         return false;
2804     }
2805
2806 //      Q3PtrList<RS_Entity> addList;
2807 //      addList.setAutoDelete(false);
2808         QList<RS_Entity *> addList;
2809
2810     if (document!=NULL && handleUndo) {
2811         document->startUndoCycle();
2812     }
2813
2814     for (RS_Entity* e=container->firstEntity();
2815             e!=NULL;
2816             e=container->nextEntity()) {
2817         if (e!=NULL && e->isSelected()) {
2818             if (e->rtti()==RS2::EntityText) {
2819                 // add letters of text:
2820                 RS_Text* text = (RS_Text*)e;
2821                 explodeTextIntoLetters(text, addList);
2822             } else {
2823                 e->setSelected(false);
2824             }
2825         }
2826     }
2827
2828     deselectOriginals(true);
2829     addNewEntities(addList);
2830
2831     if (document!=NULL && handleUndo) {
2832         document->endUndoCycle();
2833     }
2834
2835     if (graphicView!=NULL) {
2836         graphicView->redraw();
2837     }
2838
2839     return true;
2840 }
2841
2842 //bool RS_Modification::explodeTextIntoLetters(RS_Text* text, Q3PtrList<RS_Entity>& addList)
2843 bool RS_Modification::explodeTextIntoLetters(RS_Text * text, QList<RS_Entity *> & addList)
2844 {
2845         if (text == NULL)
2846                 return false;
2847
2848         // iterate though lines:
2849         for(RS_Entity * e2=text->firstEntity(); e2!=NULL; e2=text->nextEntity())
2850         {
2851                 if (e2 == NULL)
2852                         break;
2853
2854                 // text lines:
2855                 if (e2->rtti() == RS2::EntityContainer)
2856                 {
2857                         RS_EntityContainer * line = (RS_EntityContainer *)e2;
2858
2859                         // iterate though letters:
2860                         for(RS_Entity * e3=line->firstEntity(); e3!=NULL; e3=line->nextEntity())
2861                         {
2862                                 if (e3 == NULL)
2863                                         break;
2864
2865                                 // super / sub texts:
2866                                 if (e3->rtti() == RS2::EntityText)
2867                                         explodeTextIntoLetters((RS_Text *)e3, addList);
2868                                 // normal letters:
2869                                 else if (e3->rtti() == RS2::EntityInsert)
2870                                 {
2871                                         RS_Insert * letter = (RS_Insert *)e3;
2872
2873                                         RS_Text * tl = new RS_Text(container, RS_TextData(letter->getInsertionPoint(),
2874                                                 text->getHeight(), 100.0, RS2::VAlignBottom, RS2::HAlignLeft,
2875                                                 RS2::LeftToRight, RS2::Exact, 1.0, letter->getName(), text->getStyle(),
2876                                                 letter->getAngle(), RS2::Update));
2877
2878                                         tl->setLayer(text->getLayer());
2879                                         tl->setPen(text->getPen());
2880
2881                                         addList.append(tl);
2882                                         tl->update();
2883                                 }
2884                         }
2885                 }
2886         }
2887
2888         return true;
2889 }
2890
2891 /**
2892  * Moves all reference points of selected entities with the given data.
2893  */
2894 bool RS_Modification::moveRef(RS_MoveRefData& data)
2895 {
2896         if (container == NULL)
2897         {
2898                 RS_DEBUG->print("RS_Modification::moveRef: no valid container", RS_Debug::D_WARNING);
2899                 return false;
2900         }
2901
2902         //      Q3PtrList<RS_Entity> addList;
2903         //      addList.setAutoDelete(false);
2904         QList<RS_Entity *> addList;
2905
2906         if (document != NULL && handleUndo)
2907                 document->startUndoCycle();
2908
2909         // Create new entites
2910         for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
2911         {
2912                 if (e != NULL && e->isSelected())
2913                 {
2914                         RS_Entity * ec = e->clone();
2915                         ec->moveRef(data.ref, data.offset);
2916                         // since 2.0.4.0: keep it selected
2917                         ec->setSelected(true);
2918                         addList.append(ec);
2919                 }
2920         }
2921
2922         deselectOriginals(true);
2923         addNewEntities(addList);
2924
2925         if (document != NULL && handleUndo)
2926                 document->endUndoCycle();
2927
2928         if (graphicView != NULL)
2929                 graphicView->redraw();
2930
2931         return true;
2932 }