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