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