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