]> Shamusworld >> Repos - architektonas/blob - src/base/rs_eventhandler.cpp
Changed RS_Graphic to Drawing; this is less confusing as a drawing is
[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_coordinateevent.h"
20
21 /**
22  * Constructor.
23  */
24 RS_EventHandler::RS_EventHandler(RS_GraphicView * graphicView)
25 {
26         this->graphicView = graphicView;
27         actionIndex = -1;
28
29         for(int i=0; i<RS_MAXACTIONS; ++i)
30                 currentActions[i] = NULL;
31
32         coordinateInputEnabled = true;
33         defaultAction = NULL;
34 }
35
36 /**
37  * Destructor.
38  */
39 RS_EventHandler::~RS_EventHandler()
40 {
41         RS_DEBUG->print("RS_EventHandler::~RS_EventHandler");
42
43         if (defaultAction != NULL)
44         {
45                 defaultAction->finish();
46                 delete defaultAction;
47                 defaultAction = NULL;
48         }
49
50         killAllActions();
51
52         RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: Deleting all actions..");
53
54         for(int i=0; i<RS_MAXACTIONS; ++i)
55         {
56                 if (currentActions[i] != NULL)
57                 {
58                         currentActions[i]->setFinished();
59                         //delete currentActions[i];
60                         //currentActions[i] = NULL;
61                 }
62         }
63
64         cleanUp();
65         RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: Deleting all actions..: OK");
66         RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: OK");
67 }
68
69 /**
70  * Go back in current action.
71  */
72 void RS_EventHandler::back()
73 {
74         QMouseEvent e(QEvent::MouseButtonRelease, QPoint(0, 0), Qt::RightButton, Qt::RightButton,
75                 Qt::NoModifier);
76         mouseReleaseEvent(&e);
77 }
78
79 /**
80  * Go enter pressed event for current action.
81  */
82 void RS_EventHandler::enter()
83 {
84 //      QKeyEvent e(QEvent::KeyPress, Qt::Key_Enter, '\n', 0);
85         QKeyEvent e(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n", false, 0);
86         keyPressEvent(&e);
87 }
88
89 /**
90  * Called by RS_GraphicView
91  */
92 void RS_EventHandler::mousePressEvent(QMouseEvent * e)
93 {
94         if (actionIndex >= 0 && currentActions[actionIndex] != NULL)
95         {
96                 currentActions[actionIndex]->mousePressEvent(e);
97                 e->accept();
98         }
99         else
100         {
101                 if (defaultAction != NULL)
102                 {
103                         defaultAction->mousePressEvent(e);
104                         e->accept();
105                 }
106                 else
107                 {
108                         RS_DEBUG->print("currently no action defined");
109                         e->ignore();
110                 }
111         }
112 }
113
114 /**
115  * Called by RS_GraphicView
116  */
117 void RS_EventHandler::mouseReleaseEvent(QMouseEvent * e)
118 {
119         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
120                 && !currentActions[actionIndex]->isFinished())
121         {
122                 RS_DEBUG->print("call action %s", currentActions[actionIndex]->getName().toLatin1().data());
123                 currentActions[actionIndex]->mouseReleaseEvent(e);
124
125                 // Clean up actions - one might be finished now
126                 cleanUp();
127                 e->accept();
128         }
129         else
130         {
131                 if (defaultAction != NULL)
132                         defaultAction->mouseReleaseEvent(e);
133                 else
134                         e->ignore();
135         }
136 }
137
138 /**
139  * Called by RS_GraphicView
140  */
141 void RS_EventHandler::mouseMoveEvent(QMouseEvent * e)
142 {
143         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
144                 && !currentActions[actionIndex]->isFinished())
145         {
146                 currentActions[actionIndex]->mouseMoveEvent(e);
147                 e->accept();
148         }
149         else
150         {
151                 if (defaultAction!=NULL)
152                 {
153                         defaultAction->mouseMoveEvent(e);
154                         e->accept();
155                 }
156                 else
157                         e->ignore();
158                 //RS_DEBUG->print("currently no action defined");
159         }
160 }
161
162 /**
163  * Called by RS_GraphicView
164  */
165 void RS_EventHandler::mouseLeaveEvent()
166 {
167         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
168                 && !currentActions[actionIndex]->isFinished())
169         {
170                 currentActions[actionIndex]->suspend();
171         }
172         else
173         {
174                 if (defaultAction != NULL)
175                         defaultAction->suspend();
176                 //RS_DEBUG->print("currently no action defined");
177         }
178 }
179
180 /**
181  * Called by RS_GraphicView
182  */
183 void RS_EventHandler::mouseEnterEvent()
184 {
185         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
186                 && !currentActions[actionIndex]->isFinished())
187         {
188                 currentActions[actionIndex]->resume();
189         }
190         else
191         {
192                 if (defaultAction != NULL)
193                         defaultAction->resume();
194         }
195 }
196
197 /**
198  * Called by RS_GraphicView
199  */
200 void RS_EventHandler::keyPressEvent(QKeyEvent * e)
201 {
202         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
203                 && !currentActions[actionIndex]->isFinished())
204         {
205                 currentActions[actionIndex]->keyPressEvent(e);
206         }
207         else
208         {
209                 if (defaultAction != NULL)
210                         defaultAction->keyPressEvent(e);
211                 else
212                         e->ignore();
213
214                 //RS_DEBUG->print("currently no action defined");
215         }
216 }
217
218 /**
219  * Called by RS_GraphicView
220  */
221 void RS_EventHandler::keyReleaseEvent(QKeyEvent* e)
222 {
223         if (actionIndex >= 0 && currentActions[actionIndex] != NULL &&
224                 !currentActions[actionIndex]->isFinished())
225         {
226                 currentActions[actionIndex]->keyReleaseEvent(e);
227         }
228         else
229         {
230                 if (defaultAction != NULL)
231                 {
232                         defaultAction->keyReleaseEvent(e);
233                 }
234                 else
235                 {
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                                         }
276                                         else
277                                         {
278                                                 if (RS_DIALOGFACTORY != NULL)
279                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
280                                         }
281
282                                         e->accept();
283                                 }
284                         }
285                 }
286
287                 // handle relative cartesian coordinate input:
288                 if (!e->isAccepted())
289                 {
290                         if (cmd.contains(',') && cmd.at(0) == '@')
291                         {
292                                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
293                                         && !currentActions[actionIndex]->isFinished())
294                                 {
295 //                                      int commaPos = cmd.find(',');
296                                         int commaPos = cmd.indexOf(',');
297                                         bool ok1, ok2;
298                                         double x = RS_Math::eval(cmd.mid(1, commaPos - 1), &ok1);
299                                         double y = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
300
301                                         if (ok1 && ok2)
302                                         {
303                                                 RS_CoordinateEvent ce(Vector(x,y) +
304                                                         graphicView->getRelativeZero());
305                                                 currentActions[actionIndex]->coordinateEvent(&ce);
306                                         }
307                                         else
308                                         {
309                                                 if (RS_DIALOGFACTORY != NULL)
310                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
311                                         }
312
313                                         e->accept();
314                                 }
315                         }
316                 }
317
318                 // handle absolute polar coordinate input:
319                 if (!e->isAccepted())
320                 {
321                         if (cmd.contains('<') && cmd.at(0) != '@')
322                         {
323                                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
324                                         && !currentActions[actionIndex]->isFinished())
325                                 {
326 //                                      int commaPos = cmd.find('<');
327                                         int commaPos = cmd.indexOf('<');
328                                         bool ok1, ok2;
329                                         double r = RS_Math::eval(cmd.left(commaPos), &ok1);
330                                         double a = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
331
332                                         if (ok1 && ok2)
333                                         {
334                                                 Vector pos;
335                                                 pos.setPolar(r,RS_Math::deg2rad(a));
336                                                 RS_CoordinateEvent ce(pos);
337                                                 currentActions[actionIndex]->coordinateEvent(&ce);
338                                         }
339                                         else
340                                         {
341                                                 if (RS_DIALOGFACTORY != NULL)
342                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
343                                         }
344
345                                         e->accept();
346                                 }
347                         }
348                 }
349
350                 // handle relative polar coordinate input:
351                 if (!e->isAccepted())
352                 {
353                         if (cmd.contains('<') && cmd.at(0) == '@')
354                         {
355                                 if (actionIndex >= 0 && currentActions[actionIndex] !=NULL
356                                         && !currentActions[actionIndex]->isFinished())
357                                 {
358 //                                      int commaPos = cmd.find('<');
359                                         int commaPos = cmd.indexOf('<');
360                                         bool ok1, ok2;
361                                         double r = RS_Math::eval(cmd.mid(1, commaPos - 1), &ok1);
362                                         double a = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
363
364                                         if (ok1 && ok2)
365                                         {
366                                                 Vector pos;
367                                                 pos.setPolar(r,RS_Math::deg2rad(a));
368                                                 RS_CoordinateEvent ce(pos +
369                                                         graphicView->getRelativeZero());
370                                                 currentActions[actionIndex]->coordinateEvent(&ce);
371                                         }
372                                         else
373                                         {
374                                                 if (RS_DIALOGFACTORY != NULL)
375                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
376                                         }
377
378                                         e->accept();
379                                 }
380                         }
381                 }
382         }
383
384         // send command event directly to current action:
385         if (!e->isAccepted())
386         {
387                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
388                         && !currentActions[actionIndex]->isFinished())
389                 {
390                         currentActions[actionIndex]->commandEvent(e);
391                         e->accept();
392                 }
393                 else
394                 {
395                         if (defaultAction != NULL)
396                         {
397                                 defaultAction->commandEvent(e);
398                                 //e->accept();
399                         }
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 RS_ActionInterface * RS_EventHandler::getCurrentAction()
426 {
427         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
428                 && !currentActions[actionIndex]->isFinished())
429                 return currentActions[actionIndex];
430
431         return defaultAction;
432 }
433
434 /**
435  * @return The current default action.
436  */
437 RS_ActionInterface * RS_EventHandler::getDefaultAction()
438 {
439         return defaultAction;
440 }
441
442 /**
443  * Sets the default action.
444  */
445 void RS_EventHandler::setDefaultAction(RS_ActionInterface * action)
446 {
447         if (defaultAction != NULL)
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(RS_ActionInterface * action)
461 {
462         RS_DEBUG->print("RS_EventHandler::setCurrentAction");
463
464         if (action == NULL)
465                 return;
466
467         // Predecessor of the new action or NULL:
468         RS_ActionInterface * predecessor = NULL;
469
470         // Suspend current action:
471         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
472                 && !currentActions[actionIndex]->isFinished())
473         {
474                 predecessor = currentActions[actionIndex];
475                 predecessor->suspend();
476                 predecessor->hideOptions();
477         }
478         else
479         {
480                 if (defaultAction != NULL)
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] != NULL)
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("RS_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] != NULL)
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 != NULL)
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] != NULL && !currentActions[resume]->isFinished())
637                 {
638                         currentActions[resume]->resume();
639                         currentActions[resume]->showOptions();
640                 }
641                 else
642                 {
643                         if (defaultAction != NULL)
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         for(int c=0; c<RS_MAXACTIONS; ++c)
660                 if (currentActions[c] != NULL)
661                         currentActions[c]->setSnapMode(sm);
662
663         if (defaultAction!=NULL)
664                 defaultAction->setSnapMode(sm);
665 }
666
667 /**
668  * Sets the snap restriction for all currently active actions.
669  */
670 void RS_EventHandler::setSnapRestriction(RS2::SnapRestriction sr)
671 {
672         for(int c=0; c<RS_MAXACTIONS; ++c)
673                 if (currentActions[c] != NULL)
674                         currentActions[c]->setSnapRestriction(sr);
675
676         if (defaultAction != NULL)
677                 defaultAction->setSnapRestriction(sr);
678 }
679
680 void RS_EventHandler::debugActions()
681 {
682         RS_DEBUG->print("---");
683
684         for(int c=0; c<RS_MAXACTIONS; ++c)
685         {
686                 if (c == actionIndex)
687                         RS_DEBUG->print("Current");
688
689                 if (currentActions[c] != NULL)
690                         RS_DEBUG->print("Action %03d: %s [%s]",
691                                 c, currentActions[c]->getName().toLatin1().data(),
692                                 currentActions[c]->isFinished() ? "finished" : "active");
693                 else
694                         RS_DEBUG->print("Action %03d: NULL", c);
695         }
696 }