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