1 // SPDX-FileCopyrightText: 2002 Dominique Devriese <devriese@kde.org>
2 
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 #include "moving.h"
6 
7 #include "normal.h"
8 
9 #include "../objects/object_imp.h"
10 #include "../objects/object_factory.h"
11 #include "../kig/kig_document.h"
12 #include "../kig/kig_part.h"
13 #include "../kig/kig_view.h"
14 #include "../kig/kig_commands.h"
15 #include "../misc/kigpainter.h"
16 #include "../misc/calcpaths.h"
17 #include "../misc/coordinate_system.h"
18 
19 #include <QMouseEvent>
20 
21 #include <functional>
22 #include <algorithm>
23 #include <map>
24 #include <iterator>
25 
initScreen(const std::vector<ObjectCalcer * > & in)26 void MovingModeBase::initScreen( const std::vector<ObjectCalcer*>& in )
27 {
28   mcalcable = in;
29   std::set<ObjectCalcer*> calcableset( mcalcable.begin(), mcalcable.end() );
30 
31   // don't try to move objects that have been deleted from the
32   // document or internal objects that the user is not aware of..
33   std::vector<ObjectHolder*> docobjs = mdoc.document().objects();
34   for ( std::vector<ObjectHolder*>::iterator i = docobjs.begin();
35         i != docobjs.end(); ++i )
36     if ( calcableset.find( ( *i )->calcer() ) != calcableset.end() )
37       mdrawable.push_back( *i );
38 
39   std::set<ObjectHolder*> docobjsset( docobjs.begin(), docobjs.end() );
40   std::set<ObjectHolder*> drawableset( mdrawable.begin(), mdrawable.end() );
41   std::set<ObjectHolder*> notmovingobjs;
42   std::set_difference( docobjsset.begin(), docobjsset.end(), drawableset.begin(), drawableset.end(),
43                        std::inserter( notmovingobjs, notmovingobjs.begin() ) );
44 
45   mview.clearStillPix();
46   KigPainter p( mview.screenInfo(), &mview.stillPix, mdoc.document() );
47   p.drawGrid( mdoc.document().coordinateSystem(), mdoc.document().grid(),
48               mdoc.document().axes() );
49   p.drawObjects( notmovingobjs.begin(), notmovingobjs.end(), false );
50   mview.updateCurPix();
51 
52   KigPainter p2( mview.screenInfo(), &mview.curPix, mdoc.document() );
53   p2.drawObjects( drawableset.begin(), drawableset.end(), true );
54 }
55 
leftReleased(QMouseEvent *,KigWidget * v)56 void MovingModeBase::leftReleased( QMouseEvent*, KigWidget* v )
57 {
58   // clean up after ourselves:
59   for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin();
60         i != mcalcable.end(); ++i )
61     ( *i )->calc( mdoc.document() );
62   stopMove();
63   mdoc.setModified( true );
64 
65   // refresh the screen:
66   v->redrawScreen( std::vector<ObjectHolder*>() );
67   v->updateScrollBars();
68 
69   mdoc.doneMode( this );
70 }
71 
mouseMoved(QMouseEvent * e,KigWidget * v)72 void MovingModeBase::mouseMoved( QMouseEvent* e, KigWidget* v )
73 {
74   v->updateCurPix();
75   Coordinate c = v->fromScreen( e->pos() );
76 
77   bool snaptogrid = e->modifiers() & Qt::ShiftModifier;
78   moveTo( c, snaptogrid );
79   for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin();
80         i != mcalcable.end(); ++i )
81     ( *i )->calc( mdoc.document() );
82   KigPainter p( v->screenInfo(), &v->curPix, mdoc.document() );
83   // TODO: only draw the explicitly moving objects as selected, the
84   // other ones as deselected.. Needs some support from the
85   // subclasses..
86   p.drawObjects( mdrawable, true );
87   v->updateWidget( p.overlay() );
88   v->updateScrollBars();
89 }
90 
91 class MovingMode::Private
92 {
93 public:
94   // explicitly moving objects: these are the objects that the user
95   // requested to move...
96   std::vector<ObjectCalcer*> emo;
97   // point where we started moving..
98   Coordinate pwwsm;
99   MonitorDataObjects* mon;
100   // we keep a map from the emo objects to their reference location.
101   // This is the location that they claim to be at before moving
102   // starts, and we use it as a reference point to determine where
103   // they should move next..
104   std::map<const ObjectCalcer*, Coordinate> refmap;
105 };
106 
MovingMode(const std::vector<ObjectHolder * > & os,const Coordinate & c,KigWidget & v,KigPart & doc)107 MovingMode::MovingMode( const std::vector<ObjectHolder*>& os, const Coordinate& c,
108                         KigWidget& v, KigPart& doc )
109   : MovingModeBase( doc, v ), d( new Private )
110 {
111   d->pwwsm = c;
112   std::vector<ObjectCalcer*> emo;
113   std::set<ObjectCalcer*> objs;
114   for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
115     if ( (*i)->canMove() )
116     {
117       emo.push_back( ( *i )->calcer() );
118       d->refmap[( *i )->calcer()] = (*i)->moveReferencePoint();
119       objs.insert( ( *i )->calcer() );
120       std::vector<ObjectCalcer*> parents = ( *i )->calcer()->movableParents();
121       objs.insert( parents.begin(), parents.end() );
122     };
123 
124   emo = calcPath( emo );
125   for ( std::vector<ObjectCalcer*>::const_iterator i = emo.begin(); i != emo.end(); ++i )
126     if ( !isChild( *i, d->emo ) )
127       d->emo.push_back( *i );
128 
129   d->mon = new MonitorDataObjects( std::vector<ObjectCalcer*>( objs.begin(),objs.end() ) );
130 
131   std::set<ObjectCalcer*> tmp = objs;
132   for ( std::set<ObjectCalcer*>::const_iterator i = tmp.begin(); i != tmp.end(); ++i )
133   {
134     std::set<ObjectCalcer*> children = getAllChildren(*i);
135     objs.insert( children.begin(), children.end() );
136   }
137 
138   initScreen( calcPath( std::vector<ObjectCalcer*>( objs.begin(), objs.end() ) ) );
139 }
140 
stopMove()141 void MovingMode::stopMove()
142 {
143   QString text = d->emo.size() == 1 ?
144                  d->emo[0]->imp()->type()->moveAStatement() :
145                  i18np( "Move %1 Object", "Move %1 Objects", d->emo.size() );
146   KigCommand* mc = new KigCommand( mdoc, text );
147   d->mon->finish( mc );
148   mdoc.history()->push( mc );
149 }
150 
moveTo(const Coordinate & o,bool snaptogrid)151 void MovingMode::moveTo( const Coordinate& o, bool snaptogrid )
152 {
153   for( std::vector<ObjectCalcer*>::iterator i = d->emo.begin(); i != d->emo.end(); ++i )
154   {
155     assert( d->refmap.find( *i ) != d->refmap.end() );
156     Coordinate nc = d->refmap[*i] + ( o - d->pwwsm );
157     if ( snaptogrid ) nc = mdoc.document().coordinateSystem().snapToGrid( nc, mview );
158     (*i)->move( nc, mdoc.document() );
159   };
160 }
161 
PointRedefineMode(ObjectHolder * p,KigPart & d,KigWidget & v)162 PointRedefineMode::PointRedefineMode( ObjectHolder* p, KigPart& d, KigWidget& v )
163   : MovingModeBase( d, v ), mp( p ), mmon( 0 )
164 {
165   assert( dynamic_cast<ObjectTypeCalcer*>( p->calcer() ) );
166   moldtype = static_cast<ObjectTypeCalcer*>( p->calcer() )->type();
167   std::vector<ObjectCalcer*> oldparents = p->calcer()->parents();
168   std::copy( oldparents.begin(), oldparents.end(), std::back_inserter( moldparents ) );
169 
170   std::vector<ObjectCalcer*> parents = getAllParents( mp->calcer() );
171   mmon = new MonitorDataObjects( parents );
172   std::vector<ObjectCalcer*> moving = parents;
173   std::set<ObjectCalcer*> children = getAllChildren( mp->calcer() );
174   std::copy( children.begin(), children.end(), std::back_inserter( moving ) );
175   initScreen( moving );
176 }
177 
moveTo(const Coordinate & o,bool snaptogrid)178 void PointRedefineMode::moveTo( const Coordinate& o, bool snaptogrid )
179 {
180   Coordinate realo =
181     snaptogrid ? mdoc.document().coordinateSystem().snapToGrid( o, mview ) : o;
182   ObjectFactory::instance()->redefinePoint(
183     static_cast<ObjectTypeCalcer*>( mp->calcer() ), realo, mdoc.document(), mview );
184 }
185 
~PointRedefineMode()186 PointRedefineMode::~PointRedefineMode()
187 {
188 }
189 
MovingModeBase(KigPart & doc,KigWidget & v)190 MovingModeBase::MovingModeBase( KigPart& doc, KigWidget& v )
191   : KigMode( doc ), mview( v )
192 {
193 }
194 
~MovingModeBase()195 MovingModeBase::~MovingModeBase()
196 {
197 }
198 
leftMouseMoved(QMouseEvent * e,KigWidget * v)199 void MovingModeBase::leftMouseMoved( QMouseEvent* e, KigWidget* v )
200 {
201   mouseMoved( e, v );
202 }
203 
~MovingMode()204 MovingMode::~MovingMode()
205 {
206   delete d->mon;
207   delete d;
208 }
209 
stopMove()210 void PointRedefineMode::stopMove()
211 {
212   assert( dynamic_cast<ObjectTypeCalcer*>( mp->calcer() ) );
213   ObjectTypeCalcer* mpcalc = static_cast<ObjectTypeCalcer*>(  mp->calcer() );
214 
215   std::vector<ObjectCalcer*> newparents = mpcalc->parents();
216   std::vector<ObjectCalcer::shared_ptr> newparentsref(
217     newparents.begin(), newparents.end() );
218   const ObjectType* newtype = mpcalc->type();
219 
220   std::vector<ObjectCalcer*> oldparents;
221   for( std::vector<ObjectCalcer::shared_ptr>::iterator i = moldparents.begin();
222        i != moldparents.end(); ++i )
223     oldparents.push_back( i->get() );
224   mpcalc->setType( moldtype );
225   mpcalc->setParents( oldparents );
226   mp->calc( mdoc.document() );
227 
228   KigCommand* command = new KigCommand( mdoc, i18n( "Redefine Point" ) );
229   command->addTask(
230     new ChangeParentsAndTypeTask( mpcalc, newparents, newtype ) );
231   mmon->finish( command );
232   mdoc.history()->push( command );
233 }
234