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