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