]> Shamusworld >> Repos - architektonas/blob - src/base/rs_eventhandler.cpp
Initial import
[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         currentActions[actionIndex]->keyReleaseEvent(e);
226     } else {
227         if (defaultAction!=NULL) {
228             defaultAction->keyReleaseEvent(e);
229         }
230                 else {
231                         e->ignore();
232                 }
233         //RS_DEBUG->print("currently no action defined");
234     }
235 }
236
237 /**
238  * Handles command line events.
239  */
240 void RS_EventHandler::commandEvent(RS_CommandEvent * e)
241 {
242         RS_DEBUG->print("RS_EventHandler::commandEvent");
243         QString cmd = e->getCommand();
244
245         if (coordinateInputEnabled)
246         {
247                 if (!e->isAccepted())
248                 {
249                         // handle absolute cartesian coordinate input:
250                         if (cmd.contains(',') && cmd.at(0) != '@')
251                         {
252                                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
253                                         && !currentActions[actionIndex]->isFinished())
254                                 {
255 //                                      int commaPos = cmd.find(',');
256                                         int commaPos = cmd.indexOf(',');
257                                         RS_DEBUG->print("RS_EventHandler::commandEvent: 001");
258                                         bool ok1, ok2;
259                                         RS_DEBUG->print("RS_EventHandler::commandEvent: 002");
260                                         double x = RS_Math::eval(cmd.left(commaPos), &ok1);
261                                         RS_DEBUG->print("RS_EventHandler::commandEvent: 003a");
262                                         double y = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
263                                         RS_DEBUG->print("RS_EventHandler::commandEvent: 004");
264
265                                         if (ok1 && ok2)
266                                         {
267                                                 RS_DEBUG->print("RS_EventHandler::commandEvent: 005");
268                                                 RS_CoordinateEvent ce(Vector(x, y));
269                                                 RS_DEBUG->print("RS_EventHandler::commandEvent: 006");
270                                                 currentActions[actionIndex]->coordinateEvent(&ce);
271                                         }
272                                         else
273                                         {
274                                                 if (RS_DIALOGFACTORY != NULL)
275                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
276                                         }
277
278                                         e->accept();
279                                 }
280                         }
281                 }
282
283                 // handle relative cartesian coordinate input:
284                 if (!e->isAccepted())
285                 {
286                         if (cmd.contains(',') && cmd.at(0) == '@')
287                         {
288                                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
289                                         && !currentActions[actionIndex]->isFinished())
290                                 {
291 //                                      int commaPos = cmd.find(',');
292                                         int commaPos = cmd.indexOf(',');
293                                         bool ok1, ok2;
294                                         double x = RS_Math::eval(cmd.mid(1, commaPos - 1), &ok1);
295                                         double y = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
296
297                                         if (ok1 && ok2)
298                                         {
299                                                 RS_CoordinateEvent ce(Vector(x,y) +
300                                                         graphicView->getRelativeZero());
301                                                 currentActions[actionIndex]->coordinateEvent(&ce);
302                                         }
303                                         else
304                                         {
305                                                 if (RS_DIALOGFACTORY != NULL)
306                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
307                                         }
308
309                                         e->accept();
310                                 }
311                         }
312                 }
313
314                 // handle absolute polar coordinate input:
315                 if (!e->isAccepted())
316                 {
317                         if (cmd.contains('<') && cmd.at(0) != '@')
318                         {
319                                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
320                                         && !currentActions[actionIndex]->isFinished())
321                                 {
322 //                                      int commaPos = cmd.find('<');
323                                         int commaPos = cmd.indexOf('<');
324                                         bool ok1, ok2;
325                                         double r = RS_Math::eval(cmd.left(commaPos), &ok1);
326                                         double a = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
327
328                                         if (ok1 && ok2)
329                                         {
330                                                 Vector pos;
331                                                 pos.setPolar(r,RS_Math::deg2rad(a));
332                                                 RS_CoordinateEvent ce(pos);
333                                                 currentActions[actionIndex]->coordinateEvent(&ce);
334                                         }
335                                         else
336                                         {
337                                                 if (RS_DIALOGFACTORY != NULL)
338                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
339                                         }
340
341                                         e->accept();
342                                 }
343                         }
344                 }
345
346                 // handle relative polar coordinate input:
347                 if (!e->isAccepted())
348                 {
349                         if (cmd.contains('<') && cmd.at(0) == '@')
350                         {
351                                 if (actionIndex >= 0 && currentActions[actionIndex] !=NULL
352                                         && !currentActions[actionIndex]->isFinished())
353                                 {
354 //                                      int commaPos = cmd.find('<');
355                                         int commaPos = cmd.indexOf('<');
356                                         bool ok1, ok2;
357                                         double r = RS_Math::eval(cmd.mid(1, commaPos - 1), &ok1);
358                                         double a = RS_Math::eval(cmd.mid(commaPos + 1), &ok2);
359
360                                         if (ok1 && ok2)
361                                         {
362                                                 Vector pos;
363                                                 pos.setPolar(r,RS_Math::deg2rad(a));
364                                                 RS_CoordinateEvent ce(pos +
365                                                         graphicView->getRelativeZero());
366                                                 currentActions[actionIndex]->coordinateEvent(&ce);
367                                         }
368                                         else
369                                         {
370                                                 if (RS_DIALOGFACTORY != NULL)
371                                                         RS_DIALOGFACTORY->commandMessage("Expression Syntax Error");
372                                         }
373
374                                         e->accept();
375                                 }
376                         }
377                 }
378         }
379
380         // send command event directly to current action:
381         if (!e->isAccepted())
382         {
383                 if (actionIndex >= 0 && currentActions[actionIndex] != NULL
384                         && !currentActions[actionIndex]->isFinished())
385                 {
386                         currentActions[actionIndex]->commandEvent(e);
387                         e->accept();
388                 }
389                 else
390                 {
391                         if (defaultAction != NULL)
392                         {
393                                 defaultAction->commandEvent(e);
394                                 //e->accept();
395                         }
396                 }
397         }
398
399         RS_DEBUG->print("RS_EventHandler::commandEvent: OK");
400 }
401
402 /**
403  * Enables coordinate input in the command line.
404  */
405 void RS_EventHandler::enableCoordinateInput()
406 {
407         coordinateInputEnabled = true;
408 }
409
410 /**
411  * Enables coordinate input in the command line.
412  */
413 void RS_EventHandler::disableCoordinateInput()
414 {
415         coordinateInputEnabled = false;
416 }
417
418 /**
419  * @return Current action.
420  */
421 RS_ActionInterface * RS_EventHandler::getCurrentAction()
422 {
423         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
424                 && !currentActions[actionIndex]->isFinished())
425                 return currentActions[actionIndex];
426
427         return defaultAction;
428 }
429
430 /**
431  * @return The current default action.
432  */
433 RS_ActionInterface * RS_EventHandler::getDefaultAction()
434 {
435         return defaultAction;
436 }
437
438 /**
439  * Sets the default action.
440  */
441 void RS_EventHandler::setDefaultAction(RS_ActionInterface * action)
442 {
443         if (defaultAction != NULL)
444         {
445                 defaultAction->finish();
446                 delete defaultAction;
447                 defaultAction = NULL;
448         }
449
450         defaultAction = action;
451 }
452
453 /**
454  * Sets the current action.
455  */
456 void RS_EventHandler::setCurrentAction(RS_ActionInterface * action)
457 {
458         RS_DEBUG->print("RS_EventHandler::setCurrentAction");
459
460         if (action == NULL)
461                 return;
462
463         // Predecessor of the new action or NULL:
464         RS_ActionInterface* predecessor = NULL;
465
466         // Suspend current action:
467         if (actionIndex >= 0 && currentActions[actionIndex] != NULL
468                 && !currentActions[actionIndex]->isFinished())
469         {
470                 predecessor = currentActions[actionIndex];
471                 predecessor->suspend();
472                 predecessor->hideOptions();
473         }
474         else
475         {
476                 if (defaultAction != NULL)
477                 {
478                         predecessor = defaultAction;
479                         predecessor->suspend();
480                         predecessor->hideOptions();
481                 }
482         }
483
484         // Forget about the oldest action and make space for the new action:
485         if (actionIndex == RS_MAXACTIONS - 1)
486         {
487                 // delete oldest action if necessary (usually never happens):
488                 if (currentActions[0] != NULL)
489                 {
490                         currentActions[0]->finish();
491                         delete currentActions[0];
492                         currentActions[0] = NULL;
493                 }
494
495                 // Move up actionstack (optimize):
496                 for(int i=0; i<RS_MAXACTIONS-1; ++i)
497                 {
498                         currentActions[i] = currentActions[i + 1];
499                 }
500         }
501         else if (actionIndex < RS_MAXACTIONS - 1)
502         {
503                 actionIndex++;
504         }
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     do {
593         // search first used action (o)
594         while (currentActions[o]==NULL && o<RS_MAXACTIONS) {
595             o++;
596         }
597
598         // delete action if it is finished
599         if (o<RS_MAXACTIONS && currentActions[o]!=NULL &&
600                 currentActions[o]->isFinished()) {
601             delete currentActions[o];
602             currentActions[o] = NULL;
603
604             doResume = true;
605         }
606
607         // move a running action up in the stack
608         if (o<RS_MAXACTIONS && currentActions[o]!=NULL) {
609             if (n!=o) {
610                 currentActions[n] = currentActions[o];
611                 resume = n;
612                 currentActions[o] = NULL;
613             } else {
614                 if (o<RS_MAXACTIONS) {
615                     o++;
616                 }
617             }
618             actionIndex = n;
619             if (n<RS_MAXACTIONS-1) {
620                 n++;
621             }
622         }
623     } while (o<RS_MAXACTIONS);
624
625     debugActions();
626
627     // Resume last used action:
628     if (doResume) {
629         if (currentActions[resume]!=NULL &&
630                 !currentActions[resume]->isFinished()) {
631
632             currentActions[resume]->resume();
633             currentActions[resume]->showOptions();
634         } else {
635             if (defaultAction!=NULL) {
636                 defaultAction->resume();
637                         defaultAction->showOptions();
638             }
639         }
640     }
641     RS_DEBUG->print("RS_EventHandler::cleanUp: OK");
642 }
643
644 /**
645  * Sets the snap mode for all currently active actions.
646  */
647 void RS_EventHandler::setSnapMode(RS2::SnapMode sm)
648 {
649         for(int c=0; c<RS_MAXACTIONS; ++c)
650                 if (currentActions[c] != NULL)
651                         currentActions[c]->setSnapMode(sm);
652
653         if (defaultAction!=NULL)
654                 defaultAction->setSnapMode(sm);
655 }
656
657 /**
658  * Sets the snap restriction for all currently active actions.
659  */
660 void RS_EventHandler::setSnapRestriction(RS2::SnapRestriction sr)
661 {
662         for(int c=0; c<RS_MAXACTIONS; ++c)
663                 if (currentActions[c] != NULL)
664                         currentActions[c]->setSnapRestriction(sr);
665
666         if (defaultAction != NULL)
667                 defaultAction->setSnapRestriction(sr);
668 }
669
670 void RS_EventHandler::debugActions()
671 {
672         RS_DEBUG->print("---");
673
674         for(int c=0; c<RS_MAXACTIONS; ++c)
675         {
676                 if (c == actionIndex)
677                         RS_DEBUG->print("Current");
678
679                 if (currentActions[c] != NULL)
680                         RS_DEBUG->print("Action %03d: %s [%s]",
681                                 c, currentActions[c]->getName().toLatin1().data(),
682                                 currentActions[c]->isFinished() ? "finished" : "active");
683                 else
684                         RS_DEBUG->print("Action %03d: NULL", c);
685         }
686 }