1 /******************************************************************************************************
2 * (C) 2019 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3 * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4 * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5 ******************************************************************************************************/
6
7 #include "CmdMediator.h"
8 #include "Document.h"
9 #include "DocumentModelCoords.h"
10 #include "EngaugeAssert.h"
11 #include "GraphicsScene.h"
12 #include "GuidelineAbstract.h"
13 #include "GuidelineEllipse.h"
14 #include "GuidelineFactory.h"
15 #include "GuidelineLine.h"
16 #include "Guidelines.h"
17 #include "GuidelineState.h"
18 #include "Logger.h"
19 #include "MainWindow.h"
20 #include "MainWindowModel.h"
21 #include <QGraphicsItem>
22 #include <QGraphicsScene>
23 #include <QMap>
24 #include <qmath.h>
25 #include <QTextStream>
26
Guidelines(MainWindow & mainWindow)27 Guidelines::Guidelines (MainWindow &mainWindow) :
28 m_mainWindow (mainWindow),
29 m_guidelineFactory (nullptr)
30 {
31 }
32
~Guidelines()33 Guidelines::~Guidelines ()
34 {
35 clear ();
36 delete m_guidelineFactory;
37 }
38
clear()39 void Guidelines::clear ()
40 {
41 GuidelineContainerPrivate::iterator itr;
42
43 for (itr = m_guidelineContainerXT.begin(); itr != m_guidelineContainerXT.end(); itr++) {
44 GuidelineAbstract *guideline = *itr;
45
46 // Remove the guideline from its scene
47 QGraphicsScene *scene = &guideline->scene();
48
49 if (scene != nullptr) {
50
51 guideline->removeFromScene (scene);
52
53 }
54 }
55
56 for (itr = m_guidelineContainerYR.begin(); itr != m_guidelineContainerYR.end(); itr++) {
57 GuidelineAbstract *guideline = *itr;
58
59 // Remove the guideline from its scene
60 QGraphicsScene *scene = &guideline->scene();
61
62 if (scene != nullptr) {
63
64 guideline->removeFromScene (scene);
65
66 }
67 }
68
69 m_guidelineContainerXT.clear ();
70 m_guidelineContainerYR.clear ();
71 }
72
color() const73 ColorPalette Guidelines::color () const
74 {
75 return m_mainWindow.modelMainWindow().guidelineColor();
76 }
77
coordsType() const78 CoordsType Guidelines::coordsType () const
79 {
80 return m_mainWindow.cmdMediator()->document().modelCoords().coordsType();
81 }
82
createGuideline(const QString & identifier,GuidelineState stateInitial)83 GuidelineAbstract *Guidelines::createGuideline (const QString &identifier,
84 GuidelineState stateInitial)
85 {
86 LOG4CPP_DEBUG_S ((*mainCat)) << "Guidelines::createGuideline"
87 << " identifier=" << identifier.toLatin1().data()
88 << " state=" << guidelineStateAsString (stateInitial).toLatin1().data();
89
90 GuidelineAbstract *guideline = m_guidelineFactory->createGuideline (*this,
91 stateInitial,
92 m_mainWindow,
93 identifier);
94
95 return guideline;
96 }
97
createGuidelineR(const QString & identifier,double r)98 void Guidelines::createGuidelineR (const QString &identifier,
99 double r)
100 {
101 GuidelineAbstract *guideline = createGuideline (identifier,
102 GUIDELINE_STATE_DEPLOYED_CONSTANT_R_SELECT_EDIT_APPEARING);
103 if (guideline) {
104 guideline->updateGeometry (r);
105 }
106
107 m_guidelineContainerYR.append (guideline);
108 }
109
createGuidelineR(const QString & identifier,const QPointF & posScreen)110 void Guidelines::createGuidelineR (const QString &identifier,
111 const QPointF &posScreen)
112 {
113 GuidelineAbstract *guideline = createGuideline (identifier,
114 GUIDELINE_STATE_DEPLOYED_CONSTANT_R_SELECT_EDIT_APPEARING);
115 if (guideline) {
116 guideline->updateGeometry (posScreen);
117 }
118
119 m_guidelineContainerYR.append (guideline);
120 }
121
createGuidelineT(const QString & identifier,double t)122 void Guidelines::createGuidelineT (const QString &identifier,
123 double t)
124 {
125 GuidelineAbstract *guideline = createGuideline (identifier,
126 GUIDELINE_STATE_DEPLOYED_CONSTANT_T_SELECT_EDIT_APPEARING);
127 if (guideline) {
128 guideline->updateGeometry (t);
129 }
130
131 m_guidelineContainerXT.append (guideline);
132 }
133
createGuidelineT(const QString & identifier,const QPointF & posScreen)134 void Guidelines::createGuidelineT (const QString &identifier,
135 const QPointF &posScreen)
136 {
137 GuidelineAbstract *guideline = createGuideline (identifier,
138 GUIDELINE_STATE_DEPLOYED_CONSTANT_T_SELECT_EDIT_APPEARING);
139 if (guideline) {
140 guideline->updateGeometry (posScreen);
141 }
142
143 m_guidelineContainerXT.append (guideline);
144 }
145
createGuidelineX(const QString & identifier,double x)146 void Guidelines::createGuidelineX (const QString &identifier,
147 double x)
148 {
149 GuidelineAbstract *guideline = createGuideline (identifier,
150 GUIDELINE_STATE_DEPLOYED_CONSTANT_X_SELECT_EDIT_APPEARING);
151 if (guideline) {
152 guideline->updateGeometry (x);
153 }
154
155 m_guidelineContainerXT.append (guideline);
156 }
157
createGuidelineX(const QString & identifier,const QPointF & posScreen)158 void Guidelines::createGuidelineX (const QString &identifier,
159 const QPointF &posScreen)
160 {
161 GuidelineAbstract *guideline = createGuideline (identifier,
162 GUIDELINE_STATE_DEPLOYED_CONSTANT_X_SELECT_EDIT_APPEARING);
163 if (guideline) {
164 guideline->updateGeometry (posScreen);
165 }
166
167 m_guidelineContainerXT.append (guideline);
168 }
169
createGuidelineY(const QString & identifier,double y)170 void Guidelines::createGuidelineY (const QString &identifier,
171 double y)
172 {
173 GuidelineAbstract *guideline = createGuideline (identifier,
174 GUIDELINE_STATE_DEPLOYED_CONSTANT_Y_SELECT_EDIT_APPEARING);
175 if (guideline) {
176 guideline->updateGeometry (y);
177 }
178
179 m_guidelineContainerYR.append (guideline);
180 }
181
createGuidelineY(const QString & identifier,const QPointF & posScreen)182 void Guidelines::createGuidelineY (const QString &identifier,
183 const QPointF &posScreen)
184 {
185 GuidelineAbstract *guideline = createGuideline (identifier,
186 GUIDELINE_STATE_DEPLOYED_CONSTANT_Y_SELECT_EDIT_APPEARING);
187 if (guideline) {
188 guideline->updateGeometry (posScreen);
189 }
190
191 m_guidelineContainerYR.append (guideline);
192 }
193
createReplacementGuideline(const QString & identifierReplaced,double newValue,GuidelineState guidelineStateForReplacement)194 void Guidelines::createReplacementGuideline (const QString &identifierReplaced,
195 double newValue,
196 GuidelineState guidelineStateForReplacement)
197 {
198 LOG4CPP_DEBUG_S ((*mainCat)) << "Guidelines::createReplacementGuideline";
199
200 // Out with the old. Since it is still on the stack we only unregister, versus remove, it
201 unregisterGuideline (identifierReplaced);
202
203 // And in with the new
204 switch (guidelineStateForReplacement) {
205 case GUIDELINE_STATE_DEPLOYED_CONSTANT_R_SELECT_EDIT:
206 createGuidelineR (identifierReplaced,
207 newValue);
208 break;
209
210 case GUIDELINE_STATE_DEPLOYED_CONSTANT_T_SELECT_EDIT:
211 createGuidelineT(identifierReplaced,
212 newValue);
213 break;
214
215 case GUIDELINE_STATE_DEPLOYED_CONSTANT_X_SELECT_EDIT:
216 createGuidelineX(identifierReplaced,
217 newValue);
218 break;
219
220 case GUIDELINE_STATE_DEPLOYED_CONSTANT_Y_SELECT_EDIT:
221 createGuidelineY(identifierReplaced,
222 newValue);
223 break;
224
225 default:
226 LOG4CPP_ERROR_S ((*mainCat)) << "Guidelines::createReplacementGuideline encountered unexpected state "
227 << guidelineStateAsString (guidelineStateForReplacement).toLatin1().data();
228
229 }
230 }
231
findIdentifierXT(const QString & identifier)232 GuidelineContainerPrivate::iterator Guidelines::findIdentifierXT (const QString &identifier)
233 {
234 GuidelineContainerPrivate::iterator itr;
235
236 // Find the closest point
237 for (itr = m_guidelineContainerXT.begin (); itr != m_guidelineContainerXT.end (); itr++) {
238 GuidelineAbstract *guideline = *itr;
239 if (identifier == guideline->identifier()) {
240 return itr;
241 }
242 }
243
244 LOG4CPP_DEBUG_S ((*mainCat)) << "Guidelines::findIdentifierXT could not find " << identifier.toLatin1().data();
245
246 return m_guidelineContainerXT.end();
247 }
248
findIdentifierYR(const QString & identifier)249 GuidelineContainerPrivate::iterator Guidelines::findIdentifierYR (const QString &identifier)
250 {
251 GuidelineContainerPrivate::iterator itr;
252
253 // Find the closest point
254 for (itr = m_guidelineContainerYR.begin (); itr != m_guidelineContainerYR.end (); itr++) {
255 GuidelineAbstract *guideline = *itr;
256 if (identifier == guideline->identifier()) {
257 return itr;
258 }
259 }
260
261 LOG4CPP_DEBUG_S ((*mainCat)) << "Guidelines::findIdentifierYR could not find " << identifier.toLatin1().data();
262
263 return m_guidelineContainerYR.end(); // Return something
264 }
265
guidelineContainerPrivateXT() const266 const GuidelineContainerPrivate &Guidelines::guidelineContainerPrivateXT () const
267 {
268 return m_guidelineContainerXT;
269 }
270
guidelineContainerPrivateYR() const271 const GuidelineContainerPrivate &Guidelines::guidelineContainerPrivateYR () const
272 {
273 return m_guidelineContainerYR;
274 }
275
handleActiveChange(bool active)276 void Guidelines::handleActiveChange (bool active)
277 {
278 GuidelineContainerPrivate::iterator itr;
279
280 for (itr = m_guidelineContainerXT.begin(); itr != m_guidelineContainerXT.end(); itr++) {
281 GuidelineAbstract *guideline = *itr;
282
283 guideline->handleActiveChange (active);
284 }
285
286 for (itr = m_guidelineContainerYR.begin(); itr != m_guidelineContainerYR.end(); itr++) {
287 GuidelineAbstract *guideline = *itr;
288
289 guideline->handleActiveChange (active);
290 }
291 }
292
handleGuidelineMode(bool visible,bool isLocked)293 void Guidelines::handleGuidelineMode (bool visible,
294 bool isLocked)
295 {
296 GuidelineContainerPrivate::iterator itr;
297
298 for (itr = m_guidelineContainerXT.begin(); itr != m_guidelineContainerXT.end(); itr++) {
299 GuidelineAbstract *guideline = *itr;
300
301 guideline->handleGuidelineMode (visible,
302 isLocked);
303 }
304
305 for (itr = m_guidelineContainerYR.begin(); itr != m_guidelineContainerYR.end(); itr++) {
306 GuidelineAbstract *guideline = *itr;
307
308 guideline->handleGuidelineMode (visible,
309 isLocked);
310 }
311 }
312
initialize(GraphicsScene & scene)313 void Guidelines::initialize (GraphicsScene &scene)
314 {
315 m_guidelineFactory = new GuidelineFactory (&scene);
316 }
317
modelGuidelines() const318 DocumentModelGuidelines Guidelines::modelGuidelines () const
319 {
320 GuidelineValues valuesXT, valuesYR;
321
322 GuidelineContainerPrivate::const_iterator itr;
323
324 for (itr = m_guidelineContainerXT.begin(); itr != m_guidelineContainerXT.end(); itr++) {
325 const GuidelineAbstract *guideline = *itr;
326 QString identifier = guideline->identifier();
327 double value = guideline->posCursorGraph().x();
328 valuesXT [identifier] = value;
329 }
330
331 for (itr = m_guidelineContainerYR.begin(); itr != m_guidelineContainerYR.end(); itr++) {
332 const GuidelineAbstract *guideline = *itr;
333 QString identifier = guideline->identifier();
334 double value = guideline->posCursorGraph().y();
335 valuesYR [identifier] = value;
336 }
337
338 DocumentModelGuidelines model (valuesXT,
339 valuesYR);
340
341 return model;
342 }
343
moveGuidelineXT(const QString & identifier,double valueAfter)344 void Guidelines::moveGuidelineXT (const QString &identifier,
345 double valueAfter)
346 {
347 LOG4CPP_DEBUG_S ((*mainCat)) << "Guidelines::moveGuidelineXT"
348 << " identifier=" << identifier.toLatin1().data()
349 << " value=" << valueAfter;
350
351 GuidelineContainerPrivate::iterator itr = findIdentifierXT (identifier);
352
353 if (itr== m_guidelineContainerXT.end ()) {
354 LOG4CPP_ERROR_S ((*mainCat)) << "Guidelines::moveGuidelineXT";
355 } else {
356 // Move it
357 GuidelineAbstract *guideline = *itr;
358 guideline->updateGeometry (valueAfter);
359 }
360 }
361
moveGuidelineYR(const QString & identifier,double valueAfter)362 void Guidelines::moveGuidelineYR (const QString &identifier,
363 double valueAfter)
364 {
365 LOG4CPP_DEBUG_S ((*mainCat)) << "Guidelines::moveGuidelineYR"
366 << " identifier=" << identifier.toLatin1().data()
367 << " value=" << valueAfter;
368
369 GuidelineContainerPrivate::iterator itr = findIdentifierYR (identifier);
370
371 if (itr == m_guidelineContainerYR.end ()) {
372 LOG4CPP_ERROR_S ((*mainCat)) << "Guidelines::moveGuidelineYR";
373 } else {
374 // Move it
375 GuidelineAbstract *guideline = *itr;
376 guideline->updateGeometry (valueAfter);
377 }
378 }
379
registerGuidelineXT(GuidelineAbstract * guideline)380 void Guidelines::registerGuidelineXT (GuidelineAbstract *guideline)
381 {
382 m_guidelineContainerXT.push_back (guideline);
383 }
384
registerGuidelineYR(GuidelineAbstract * guideline)385 void Guidelines::registerGuidelineYR (GuidelineAbstract *guideline)
386 {
387 m_guidelineContainerYR.push_back (guideline);
388 }
389
removeGuideline(const QString & identifier)390 void Guidelines::removeGuideline (const QString &identifier)
391 {
392 LOG4CPP_DEBUG_S ((*mainCat)) << "Guidelines::removeGuideline"
393 << " identifier=" << identifier.toLatin1().data();
394
395 GuidelineAbstract *guideline = unregisterGuideline (identifier);
396
397 if (guideline != nullptr) {
398 delete guideline;
399 }
400 }
401
setModelGuidelines(CoordsType coordsType,const DocumentModelGuidelines & modelGuidelines)402 void Guidelines::setModelGuidelines (CoordsType coordsType,
403 const DocumentModelGuidelines &modelGuidelines)
404 {
405 clear ();
406
407 GuidelineValues valuesXT = modelGuidelines.valuesX();
408 GuidelineValues valuesYR = modelGuidelines.valuesY();
409
410 GuidelineValues::const_iterator itr;
411
412 for (itr = valuesXT.begin(); itr != valuesXT.end(); itr++) {
413 QString identifier = itr.key();
414 double value = itr.value();
415
416 if (coordsType == COORDS_TYPE_CARTESIAN) {
417 createGuidelineX (identifier,
418 value);
419 } else {
420 createGuidelineT (identifier,
421 value);
422 }
423 }
424
425 for (itr = valuesYR.begin(); itr != valuesYR.end(); itr++) {
426 QString identifier = itr.key();
427 double value = itr.value();
428
429 if (coordsType == COORDS_TYPE_CARTESIAN) {
430 createGuidelineY (identifier,
431 value);
432 } else {
433 createGuidelineR (identifier,
434 value);
435 }
436 }
437 }
438
stateDump() const439 QString Guidelines::stateDump () const
440 {
441 // Sort the entries
442 QStringList sortedXT, sortedYR;
443 GuidelineContainerPrivate::const_iterator itrSort;
444
445 for (itrSort = m_guidelineContainerXT.begin(); itrSort != m_guidelineContainerXT.end(); itrSort++) {
446 GuidelineAbstract *guideline = *itrSort;
447 sortedXT << guideline->stateDump ();
448 }
449
450 for (itrSort = m_guidelineContainerYR.begin(); itrSort != m_guidelineContainerYR.end(); itrSort++) {
451 GuidelineAbstract *guideline = *itrSort;
452 sortedYR << guideline->stateDump ();
453 }
454
455 std::sort (sortedXT.begin(),
456 sortedXT.end());
457 std::sort (sortedYR.begin(),
458 sortedYR.end());
459
460 // Convert entries to output text
461 QString out;
462 QTextStream str (&out);
463
464 str << "Guidelines::stateDump:\n";
465
466 QStringList::const_iterator itrOut;
467
468 for (itrOut = sortedXT.begin(); itrOut != sortedXT.end(); itrOut++) {
469 QString entry = *itrOut;
470 str << " " << entry << "\n";
471 }
472
473 for (itrOut = sortedYR.begin(); itrOut != sortedYR.end(); itrOut++) {
474 QString entry = *itrOut;
475 str << " " << entry << "\n";
476 }
477
478 return out;
479 }
480
transformation() const481 Transformation Guidelines::transformation() const
482 {
483 return m_mainWindow.transformation ();
484 }
485
unregisterGuideline(const QString & identifier)486 GuidelineAbstract *Guidelines::unregisterGuideline (const QString &identifier)
487 {
488 LOG4CPP_DEBUG_S ((*mainCat)) << "Guidelines::unregisterGuideline"
489 << " identifier=" << identifier.toLatin1().data();
490
491 // Try to unregister XT entry
492 GuidelineContainerPrivate::iterator itrXT = findIdentifierXT (identifier);
493 if (itrXT != m_guidelineContainerXT.end ()) {
494 m_guidelineContainerXT.erase (itrXT);
495
496 return *itrXT;
497 }
498
499 // Try to remove YR entry
500 GuidelineContainerPrivate::iterator itrYR = findIdentifierYR (identifier);
501 if (itrYR != m_guidelineContainerYR.end ()) {
502 m_guidelineContainerYR.erase (itrYR);
503
504 return *itrYR;
505 }
506
507 LOG4CPP_ERROR_S ((*mainCat)) << "Guidelines::unregisterGuideline cannot find "
508 << identifier.toLatin1().data();
509 return nullptr;
510 }
511
updateColor()512 void Guidelines::updateColor ()
513 {
514 GuidelineContainerPrivate::const_iterator itr;
515
516 for (itr = m_guidelineContainerXT.begin(); itr != m_guidelineContainerXT.end(); itr++) {
517 GuidelineAbstract *guideline = *itr;
518 guideline->updateColor ();
519 }
520
521 for (itr = m_guidelineContainerYR.begin(); itr != m_guidelineContainerYR.end(); itr++) {
522 GuidelineAbstract *guideline = *itr;
523 guideline->updateColor ();
524 }
525 }
526
updateWithLatestTransformation()527 void Guidelines::updateWithLatestTransformation ()
528 {
529 GuidelineContainerPrivate::iterator itr;
530
531 for (itr = m_guidelineContainerXT.begin(); itr != m_guidelineContainerXT.end(); itr++) {
532 GuidelineAbstract *guideline = *itr;
533 guideline->updateWithLatestTransformation ();
534 }
535
536 for (itr = m_guidelineContainerYR.begin(); itr != m_guidelineContainerYR.end(); itr++) {
537 GuidelineAbstract *guideline = *itr;
538 guideline->updateWithLatestTransformation ();
539 }
540 }
541