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