]> Shamusworld >> Repos - architektonas/blob - src/base/rs_eventhandler.cpp
3484ca9f159b11e83d4dee41b4a81219706c2c3b
[architektonas] / src / base / rs_eventhandler.cpp
1 // rs_eventhandler.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 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  05/28/2010  Added this text. :-)
13 //
14
15 #include "rs_eventhandler.h"
16
17 #include "actioninterface.h"
18 #include "rs_commandevent.h"
19 #include "rs_debug.h"
20 #include "rs_dialogfactory.h"
21 #include "graphicview.h"
22 #include "rs_math.h"
23
24 /**
25  * Constructor.
26  */
27 RS_EventHandler::RS_EventHandler(GraphicView * graphicView)
28 {
29         this->graphicView = graphicView;
30         actionIndex = -1;
31
32         for(int i=0; i<RS_MAXACTIONS; ++i)
33                 currentActions[i] = NULL;
34
35         coordinateInputEnabled = true;
36         defaultAction = NULL;
37 }
38
39 /**
40  * Destructor.
41  */
42 RS_EventHandler::~RS_EventHandler()
43 {
44         RS_DEBUG->print("RS_EventHandler::~RS_EventHandler");
45
46         if (defaultAction != NULL)
47         {
48                 defaultAction->finish();
49                 delete defaultAction;
50                 defaultAction = NULL;
51         }
52
53         killAllActions();
54
55         RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: Deleting all actions..");
56
57         for(int i=0; i<RS_MAXACTIONS; ++i)
58         {
59                 if (currentActions[i] != NULL)
60                 {
61                         currentActions[i]->setFinished();
62                         //delete currentActions[i];
63                         //currentActions[i] = NULL;
64                 }
65         }
66
67         cleanUp();
68         RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: Deleting all actions..: OK");
69         RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: OK");
70 }
71
72 /**
73  * Go back in current action.
74  */
75 void RS_EventHandler::back()
76 {
77         QMouseEvent e(QEvent::MouseButtonRelease, QPoint(0, 0), Qt::RightButton, Qt::RightButton,
78                 Qt::NoModifier);
79         mouseReleaseEvent(&e);
80 }
81
82 /**
83  * Go enter pressed event for current action.
84  */
85 void RS_EventHandler::enter()
86 {
87 //      QKeyEvent e(QEvent::KeyPress, Qt::Key_Enter, '\n', 0);
88         QKeyEvent e(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n", false, 0);
89         keyPressEvent(&e);
90 }
91
92 /**
93  * Called by GraphicView
94  */
95 void RS_EventHandler::mousePressEvent(QMouseEvent * e)
96 {
97         if (actionIndex >= 0 && currentActions[actionIndex] != NULL)
98         {
99                 currentActions[actionIndex]->mousePressEvent(e);
100                 e->accept();
101         }
102         else
103         {
104                 if (defaultAction != NULL)
105                 {
106                         defaultAction->mousePressEvent(e);
107                         e->accept();
108                 }
109                 else
110                 {
111                         RS_DEBUG->print("currently no action defined");
112                         e->ignore();
113                 }
114         }
115 }
116
117 /**
118  * Called by GraphicView
119  */
120 void RS_EventHandler::mouseReleaseEvent(QMouseEvent * e)
121 {
122         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
123                 && !currentActions[actionIndex]->isFinished())
124         {
125                 RS_DEBUG->print("call action %s", currentActions[actionIndex]->getName().toLatin1().data());
126                 currentActions[actionIndex]->mouseReleaseEvent(e);
127
128                 // Clean up actions - one might be finished now
129                 cleanUp();
130                 e->accept();
131         }
132         else
133         {
134                 if (defaultAction)
135                         defaultAction->mouseReleaseEvent(e);
136                 else
137                         e->ignore();
138         }
139 }
140
141 /**
142  * Called by GraphicView
143  */
144 void RS_EventHandler::mouseMoveEvent(QMouseEvent * e)
145 {
146         if (actionIndex >= 0 && currentActions[actionIndex]
147                 && !currentActions[actionIndex]->isFinished())
148         {
149                 currentActions[actionIndex]->mouseMoveEvent(e);
150                 e->accept();
151         }
152         else
153         {
154                 if (defaultAction)
155                 {
156                         defaultAction->mouseMoveEvent(e);
157                         e->accept();
158                 }
159                 else
160                         e->ignore();
161                 //RS_DEBUG->print("currently no action defined");
162         }
163 }
164
165 /**
166  * Called by GraphicView
167  */
168 void RS_EventHandler::mouseLeaveEvent()
169 {
170         if (actionIndex >= 0 && currentActions[actionIndex]
171                 && !currentActions[actionIndex]->isFinished())
172         {
173                 currentActions[actionIndex]->suspend();
174         }
175         else
176         {
177                 if (defaultAction)
178                         defaultAction->suspend();
179                 //RS_DEBUG->print("currently no action defined");
180         }
181 }
182
183 /**
184  * Called by GraphicView
185  */
186 void RS_EventHandler::mouseEnterEvent()
187 {
188         if (actionIndex >= 0 && currentActions[actionIndex]
189                 && !currentActions[actionIndex]->isFinished())
190         {
191                 currentActions[actionIndex]->resume();
192         }
193         else
194         {
195                 if (defaultAction)
196                         defaultAction->resume();
197         }
198 }
199
200 /**
201  * Called by GraphicView
202  */
203 void RS_EventHandler::keyPressEvent(QKeyEvent * e)
204 {
205         if (actionIndex >= 0 && currentActions[actionIndex]
206                 && !currentActions[actionIndex]->isFinished())
207         {
208                 currentActions[actionIndex]->keyPressEvent(e);
209         }
210         else
211         {
212                 if (defaultAction)
213                         defaultAction->keyPressEvent(e);
214                 else
215                         e->ignore();
216
217                 //RS_DEBUG->print("currently no action defined");
218         }
219 }
220
221 /**
222  * Called by GraphicView
223  */
224 void RS_EventHandler::keyReleaseEvent(QKeyEvent * e)
225 {
226         if (actionIndex >= 0 && currentActions[actionIndex]
227                 && !currentActions[actionIndex]->isFinished())
228         {
229                 currentActions[actionIndex]->keyReleaseEvent(e);
230         }
231         else
232         {
233                 if (defaultAction)
234                         defaultAction->keyReleaseEvent(e);
235                 else
236                         e->ignore();
237
238                 //RS_DEBUG->print("currently no action defined");
239         }
240 }
241
242 /**
243  * Handles command line events.
244  */
245 void RS_EventHandler::commandEvent(RS_CommandEvent * e)
246 {
247         RS_DEBUG->print("RS_EventHandler::commandEvent");
248         QString cmd = e->getCommand();
249
250         if (coordinateInputEnabled)
251         {
252                 if (!e->isAccepted())
253                 {
254                         // handle absolute cartesian coordinate input:
255                         if (cmd.contains(',') && cmd.at(0) != '@')
256                         {
257                                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
258                                         && !currentActions[actionIndex]->isFinished())
259                                 {
260                                         int commaPos = cmd.indexOf(',');
261                                         RS_DEBUG->print("RS_EventHandler::commandEvent: 001");
262                                         bool ok1, ok2;
263                                         RS_DEBUG->print("RS_EventHandler::commandEvent: 002");
264                                         double x = RS_Math::eval(cmd.left(commaPos), &ok1);
265                                         RS_DEBUG->print("RS_EventHandler::commandEvent: 003a");
266                                         double y = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
267                                         RS_DEBUG->print("RS_EventHandler::commandEvent: 004");
268
269                                         if (ok1 && ok2)
270                                         {
271 //                                              RS_DEBUG->print("RS_EventHandler::commandEvent: 005");
272 //                                              RS_CoordinateEvent ce(Vector(x, y));
273                                                 RS_DEBUG->print("RS_EventHandler::commandEvent: 006");
274 //                                              currentActions[actionIndex]->coordinateEvent(&ce);
275                                                 Vector ce(x, y);
276                                                 currentActions[actionIndex]->coordinateEvent(&ce);
277                                         }
278                                         else
279                                         {
280                                                 if (RS_DIALOGFACTORY != NULL)
281                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
282                                         }
283
284                                         e->accept();
285                                 }
286                         }
287                 }
288
289                 // handle relative cartesian coordinate input:
290                 if (!e->isAccepted())
291                 {
292                         if (cmd.contains(',') && cmd.at(0) == '@')
293                         {
294                                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
295                                         && !currentActions[actionIndex]->isFinished())
296                                 {
297                                         int commaPos = cmd.indexOf(',');
298                                         bool ok1, ok2;
299                                         double x = RS_Math::eval(cmd.mid(1, commaPos - 1), &ok1);
300                                         double y = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
301
302                                         if (ok1 && ok2)
303                                         {
304 //                                              RS_CoordinateEvent ce(Vector(x,y) + graphicView->getRelativeZero());
305 //                                              currentActions[actionIndex]->coordinateEvent(&ce);
306                                                 Vector ce(Vector(x,y) + graphicView->getRelativeZero());
307                                                 currentActions[actionIndex]->coordinateEvent(&ce);
308                                         }
309                                         else
310                                         {
311                                                 if (RS_DIALOGFACTORY != NULL)
312                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
313                                         }
314
315                                         e->accept();
316                                 }
317                         }
318                 }
319
320                 // handle absolute polar coordinate input:
321                 if (!e->isAccepted())
322                 {
323                         if (cmd.contains('<') && cmd.at(0) != '@')
324                         {
325                                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
326                                         && !currentActions[actionIndex]->isFinished())
327                                 {
328                                         int commaPos = cmd.indexOf('<');
329                                         bool ok1, ok2;
330                                         double r = RS_Math::eval(cmd.left(commaPos), &ok1);
331                                         double a = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
332
333                                         if (ok1 && ok2)
334                                         {
335                                                 Vector pos;
336                                                 pos.setPolar(r,RS_Math::deg2rad(a));
337 //                                              RS_CoordinateEvent ce(pos);
338 //                                              currentActions[actionIndex]->coordinateEvent(&ce);
339                                                 currentActions[actionIndex]->coordinateEvent(&pos);
340                                         }
341                                         else
342                                         {
343                                                 if (RS_DIALOGFACTORY != NULL)
344                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
345                                         }
346
347                                         e->accept();
348                                 }
349                         }
350                 }
351
352                 // handle relative polar coordinate input:
353                 if (!e->isAccepted())
354                 {
355                         if (cmd.contains('<') && cmd.at(0) == '@')
356                         {
357                                 if (actionIndex >= 0 && currentActions[actionIndex] !=NULL
358                                         && !currentActions[actionIndex]->isFinished())
359                                 {
360 //                                      int commaPos = cmd.find('<');
361                                         int commaPos = cmd.indexOf('<');
362                                         bool ok1, ok2;
363                                         double r = RS_Math::eval(cmd.mid(1, commaPos - 1), &ok1);
364                                         double a = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
365
366                                         if (ok1 && ok2)
367                                         {
368                                                 Vector pos;
369                                                 pos.setPolar(r,RS_Math::deg2rad(a));
370 //                                              RS_CoordinateEvent ce(pos + graphicView->getRelativeZero());
371 //                                              currentActions[actionIndex]->coordinateEvent(&ce);
372                                                 Vector ce(pos + graphicView->getRelativeZero());
373                                                 currentActions[actionIndex]->coordinateEvent(&ce);
374                                         }
375                                         else
376                                         {
377                                                 if (RS_DIALOGFACTORY)
378                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
379                                         }
380
381                                         e->accept();
382                                 }
383                         }
384                 }
385         }
386
387         // send command event directly to current action:
388         if (!e->isAccepted())
389         {
390                 if (actionIndex >= 0 && currentActions[actionIndex]
391                         && !currentActions[actionIndex]->isFinished())
392                 {
393                         currentActions[actionIndex]->commandEvent(e);
394                         e->accept();
395                 }
396                 else
397                 {
398                         if (defaultAction)
399                                 defaultAction->commandEvent(e);
400                 }
401         }
402
403         RS_DEBUG->print("RS_EventHandler::commandEvent: OK");
404 }
405
406 /**
407  * Enables coordinate input in the command line.
408  */
409 void RS_EventHandler::enableCoordinateInput()
410 {
411         coordinateInputEnabled = true;
412 }
413
414 /**
415  * Enables coordinate input in the command line.
416  */
417 void RS_EventHandler::disableCoordinateInput()
418 {
419         coordinateInputEnabled = false;
420 }
421
422 /**
423  * @return Current action.
424  */
425 ActionInterface * RS_EventHandler::getCurrentAction()
426 {
427         if (actionIndex >= 0 && currentActions[actionIndex]
428                 && !currentActions[actionIndex]->isFinished())
429                 return currentActions[actionIndex];
430
431         return defaultAction;
432 }
433
434 /**
435  * @return The current default action.
436  */
437 ActionInterface * RS_EventHandler::getDefaultAction()
438 {
439         return defaultAction;
440 }
441
442 /**
443  * Sets the default action.
444  */
445 void RS_EventHandler::setDefaultAction(ActionInterface * action)
446 {
447         if (defaultAction)
448         {
449                 defaultAction->finish();
450                 delete defaultAction;
451                 defaultAction = NULL;
452         }
453
454         defaultAction = action;
455 }
456
457 /**
458  * Sets the current action.
459  */
460 void RS_EventHandler::setCurrentAction(ActionInterface * action)
461 {
462         RS_DEBUG->print("RS_EventHandler::setCurrentAction");
463
464         if (!action)
465                 return;
466
467         // Predecessor of the new action or NULL:
468         ActionInterface * predecessor = NULL;
469
470         // Suspend current action:
471         if (actionIndex >= 0 && currentActions[actionIndex]
472                 && !currentActions[actionIndex]->isFinished())
473         {
474                 predecessor = currentActions[actionIndex];
475                 predecessor->suspend();
476                 predecessor->hideOptions();
477         }
478         else
479         {
480                 if (defaultAction)
481                 {
482                         predecessor = defaultAction;
483                         predecessor->suspend();
484                         predecessor->hideOptions();
485                 }
486         }
487
488         // Forget about the oldest action and make space for the new action:
489         if (actionIndex == RS_MAXACTIONS - 1)
490         {
491                 // delete oldest action if necessary (usually never happens):
492                 if (currentActions[0])
493                 {
494                         currentActions[0]->finish();
495                         delete currentActions[0];
496                         currentActions[0] = NULL;
497                 }
498
499                 // Move up actionstack (optimize):
500                 for(int i=0; i<RS_MAXACTIONS-1; ++i)
501                         currentActions[i] = currentActions[i + 1];
502         }
503         else if (actionIndex < RS_MAXACTIONS - 1)
504                 actionIndex++;
505
506         // Set current action:
507         currentActions[actionIndex] = action;
508         RS_DEBUG->print("RS_EventHandler::setCurrentAction: current action is: %s",
509                 currentActions[actionIndex]->getName().toLatin1().data());
510
511         // Initialisation of our new action:
512         RS_DEBUG->print("RS_EventHandler::setCurrentAction: init current action");
513         action->init();
514
515         // ## new:
516         if (action->isFinished() == false)
517         {
518                 RS_DEBUG->print("RS_EventHandler::setCurrentAction: show options");
519                 currentActions[actionIndex]->showOptions();
520                 RS_DEBUG->print("RS_EventHandler::setCurrentAction: set predecessor");
521                 action->setPredecessor(predecessor);
522         }
523
524         RS_DEBUG->print("RS_EventHandler::setCurrentAction: cleaning up..");
525         cleanUp();
526
527         RS_DEBUG->print("RS_EventHandler::setCurrentAction: debugging actions");
528         debugActions();
529         RS_DEBUG->print("GraphicView::setCurrentAction: OK");
530 }
531
532 /**
533  * Kills all running selection actions. Called when a selection action
534  * is launched to reduce confusion.
535  */
536 void RS_EventHandler::killSelectActions()
537 {
538         for(int c=0; c<RS_MAXACTIONS; ++c)
539         {
540                 if (currentActions[c])
541                 {
542                         if (currentActions[c]->rtti() == RS2::ActionSelectSingle
543                                 || currentActions[c]->rtti() == RS2::ActionSelectContour
544                                 || currentActions[c]->rtti() == RS2::ActionSelectWindow
545                                 || currentActions[c]->rtti() == RS2::ActionSelectIntersected
546                                 || currentActions[c]->rtti() == RS2::ActionSelectLayer)
547                                 currentActions[c]->finish();
548                 }
549         }
550 }
551
552 /**
553  * Kills all running actions. Called when a window is closed.
554  */
555 void RS_EventHandler::killAllActions()
556 {
557         /*
558     for (int c=0; c<RS_MAXACTIONS; ++c) {
559         if (currentActions[c]!=NULL) {
560             currentActions[c]->finish();
561         }
562     }
563     cleanUp();
564         */
565 }
566
567 /**
568  * @return true if there is at least one action in the action stack.
569  */
570 bool RS_EventHandler::hasAction()
571 {
572         if (actionIndex != -1 || defaultAction)
573                 return true;
574
575         return false;
576 }
577
578 /**
579  * Garbage collector for actions.
580  */
581 void RS_EventHandler::cleanUp()
582 {
583         RS_DEBUG->print("RS_EventHandler::cleanUp");
584
585         int o = 0;                              // old index
586         int n = 0;                              // new index
587         int resume = 0;                 // index of action to resume
588         bool doResume = false;  // do we need to resume an action
589         actionIndex = -1;
590
591         debugActions();
592
593         do
594         {
595                 // search first used action (o)
596                 while (currentActions[o] == NULL && o < RS_MAXACTIONS)
597                         o++;
598
599                 // delete action if it is finished
600                 if (o < RS_MAXACTIONS && currentActions[o] != NULL
601                         && currentActions[o]->isFinished())
602                 {
603                         delete currentActions[o];
604                         currentActions[o] = NULL;
605                         doResume = true;
606                 }
607
608                 // move a running action up in the stack
609                 if (o < RS_MAXACTIONS && currentActions[o] != NULL)
610                 {
611                         if (n != o)
612                         {
613                                 currentActions[n] = currentActions[o];
614                                 resume = n;
615                                 currentActions[o] = NULL;
616                         }
617                         else
618                         {
619                                 if (o < RS_MAXACTIONS)
620                                         o++;
621                         }
622
623                         actionIndex = n;
624
625                         if (n < RS_MAXACTIONS - 1)
626                                 n++;
627                 }
628         }
629         while (o < RS_MAXACTIONS);
630
631         debugActions();
632
633         // Resume last used action:
634         if (doResume)
635         {
636                 if (currentActions[resume] && !currentActions[resume]->isFinished())
637                 {
638                         currentActions[resume]->resume();
639                         currentActions[resume]->showOptions();
640                 }
641                 else
642                 {
643                         if (defaultAction)
644                         {
645                                 defaultAction->resume();
646                                 defaultAction->showOptions();
647                         }
648                 }
649         }
650
651         RS_DEBUG->print("RS_EventHandler::cleanUp: OK");
652 }
653
654 /**
655  * Sets the snap mode for all currently active actions.
656  */
657 void RS_EventHandler::setSnapMode(RS2::SnapMode sm)
658 {
659 #if 0
660         for(int c=0; c<RS_MAXACTIONS; ++c)
661                 if (currentActions[c])
662                         currentActions[c]->setSnapMode(sm);
663
664         if (defaultAction)
665                 defaultAction->setSnapMode(sm);
666 #else
667 #warning "!!! Not sure if this is going to work correctly..."
668         graphicView->snapper.setSnapMode(sm);
669 #endif
670 }
671
672 /**
673  * Sets the snap restriction for all currently active actions.
674  */
675 void RS_EventHandler::setSnapRestriction(RS2::SnapRestriction sr)
676 {
677 #if 0
678         for(int c=0; c<RS_MAXACTIONS; ++c)
679                 if (currentActions[c])
680                         currentActions[c]->setSnapRestriction(sr);
681
682         if (defaultAction)
683                 defaultAction->setSnapRestriction(sr);
684 #else
685 #warning "!!! Not sure if this is going to work correctly..."
686         graphicView->snapper.setSnapRestriction(sr);
687 #endif
688 }
689
690 void RS_EventHandler::debugActions()
691 {
692         RS_DEBUG->print("---");
693
694         for(int c=0; c<RS_MAXACTIONS; ++c)
695         {
696                 if (c == actionIndex)
697                         RS_DEBUG->print("Current");
698
699                 if (currentActions[c])
700                         RS_DEBUG->print("Action %03d: %s [%s]",
701                                 c, currentActions[c]->getName().toLatin1().data(),
702                                 currentActions[c]->isFinished() ? "finished" : "active");
703                 else
704                         RS_DEBUG->print("Action %03d: NULL", c);
705         }
706 }