1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
6 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
7 **
8 **
9 ** This file may be distributed and/or modified under the terms of the
10 ** GNU General Public License version 2 as published by the Free Software
11 ** Foundation and appearing in the file gpl-2.0.txt included in the
12 ** packaging of this file.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 **
23 ** This copyright notice MUST APPEAR in all copies of the script!
24 **
25 **********************************************************************/
26 
27 #include <QRegExp>
28 #include <QAction>
29 #include <QMouseEvent>
30 #include "rs_eventhandler.h"
31 #include "rs_actioninterface.h"
32 #include "rs_dialogfactory.h"
33 #include "rs_commandevent.h"
34 #include "rs_coordinateevent.h"
35 #include "rs_commands.h"
36 #include "rs_math.h"
37 #include "rs_snapper.h"
38 #include "rs_debug.h"
39 
40 /**
41  * Constructor.
42  */
RS_EventHandler(QObject * parent)43 RS_EventHandler::RS_EventHandler(QObject* parent) : QObject(parent)
44 {
45     connect(parent, SIGNAL(relative_zero_changed(const RS_Vector&)),
46             this, SLOT(setRelativeZero(const RS_Vector&)));
47 }
48 
49 /**
50  * Destructor.
51  */
~RS_EventHandler()52 RS_EventHandler::~RS_EventHandler() {
53     RS_DEBUG->print("RS_EventHandler::~RS_EventHandler");
54 	delete defaultAction;
55 	defaultAction = nullptr;
56 
57     RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: Deleting all actions..");
58     for(auto a: currentActions){
59         delete a;
60     }
61     currentActions.clear();
62     RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: Deleting all actions..: OK");
63     RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: OK");
64 }
65 
66 
67 /**
68  * Go back in current action.
69  */
back()70 void RS_EventHandler::back() {
71     QMouseEvent e(QEvent::MouseButtonRelease, QPoint(0,0),
72                   Qt::RightButton, Qt::RightButton,Qt::NoModifier);
73     mouseReleaseEvent(&e);
74     if (!hasAction() && q_action)
75     {
76         q_action->setChecked(false);
77         q_action = nullptr;
78     }
79 }
80 
81 
82 
83 /**
84  * Go enter pressed event for current action.
85  */
enter()86 void RS_EventHandler::enter() {
87     QKeyEvent e(QEvent::KeyPress, Qt::Key_Enter, 0);
88     keyPressEvent(&e);
89 }
90 
91 
92 /**
93  * Called by QG_GraphicView
94  */
mousePressEvent(QMouseEvent * e)95 void RS_EventHandler::mousePressEvent(QMouseEvent* e) {
96     if(hasAction()){
97         currentActions.last()->mousePressEvent(e);
98         e->accept();
99     } else {
100         if (defaultAction) {
101             defaultAction->mousePressEvent(e);
102             e->accept();
103         } else {
104             RS_DEBUG->print("currently no action defined");
105             e->ignore();
106         }
107     }
108 }
109 
110 
111 
112 /**
113  * Called by QG_GraphicView
114  */
mouseReleaseEvent(QMouseEvent * e)115 void RS_EventHandler::mouseReleaseEvent(QMouseEvent* e) {
116     if(hasAction()){
117         //    if (actionIndex>=0 && currentActions[actionIndex] &&
118         //            !currentActions[actionIndex]->isFinished()) {
119         RS_DEBUG->print("call action %s",
120                         currentActions.last()->getName().toLatin1().data());
121 
122         currentActions.last()->mouseReleaseEvent(e);
123 
124         // Clean up actions - one might be finished now
125         cleanUp();
126         e->accept();
127     } else {
128         if (defaultAction) {
129             defaultAction->mouseReleaseEvent(e);
130         } else {
131             e->ignore();
132         }
133     }
134 }
135 
136 
137 
138 /**
139  * Called by QG_GraphicView
140  */
mouseMoveEvent(QMouseEvent * e)141 void RS_EventHandler::mouseMoveEvent(QMouseEvent* e)
142 {
143     if(hasAction())
144         currentActions.last()->mouseMoveEvent(e);
145 
146     else if (defaultAction)
147         defaultAction->mouseMoveEvent(e);
148 }
149 
150 /**
151  * Called by QG_GraphicView
152  */
mouseLeaveEvent()153 void RS_EventHandler::mouseLeaveEvent() {
154 
155     if(hasAction()){
156         currentActions.last()->suspend();
157     } else {
158         if (defaultAction) {
159             defaultAction->suspend();
160         }
161         //RS_DEBUG->print("currently no action defined");
162     }
163 }
164 
165 
166 
167 /**
168  * Called by QG_GraphicView
169  */
mouseEnterEvent()170 void RS_EventHandler::mouseEnterEvent() {
171 
172     if(hasAction()){
173         currentActions.last()->resume();
174     } else {
175         if (defaultAction) {
176             defaultAction->resume();
177         }
178     }
179 }
180 
181 
182 
183 /**
184  * Called by QG_GraphicView
185  */
keyPressEvent(QKeyEvent * e)186 void RS_EventHandler::keyPressEvent(QKeyEvent* e) {
187 
188     if(hasAction()){
189         currentActions.last()->keyPressEvent(e);
190     } else {
191         if (defaultAction) {
192             defaultAction->keyPressEvent(e);
193         }
194         else {
195             e->ignore();
196         }
197 
198         //RS_DEBUG->print("currently no action defined");
199     }
200 }
201 
202 
203 
204 /**
205  * Called by QG_GraphicView
206  */
keyReleaseEvent(QKeyEvent * e)207 void RS_EventHandler::keyReleaseEvent(QKeyEvent* e) {
208 
209     if(hasAction()){
210         currentActions.last()->keyReleaseEvent(e);
211     } else {
212         if (defaultAction) {
213             defaultAction->keyReleaseEvent(e);
214         }
215         else {
216             e->ignore();
217         }
218         //RS_DEBUG->print("currently no action defined");
219     }
220 }
221 
222 /**
223  * Handles command line events.
224  */
commandEvent(RS_CommandEvent * e)225 void RS_EventHandler::commandEvent(RS_CommandEvent* e) {
226     RS_DEBUG->print("RS_EventHandler::commandEvent");
227     QString cmd = e->getCommand();
228 
229     if (coordinateInputEnabled) {
230         if (!e->isAccepted()) {
231 
232             if(hasAction()){
233                 // handle absolute cartesian coordinate input:
234                 if (cmd.contains(',') && cmd.at(0)!='@') {
235 
236                     int commaPos = cmd.indexOf(',');
237                     RS_DEBUG->print("RS_EventHandler::commandEvent: 001");
238                     bool ok1, ok2;
239                     RS_DEBUG->print("RS_EventHandler::commandEvent: 002");
240                     double x = RS_Math::eval(cmd.left(commaPos), &ok1);
241                     RS_DEBUG->print("RS_EventHandler::commandEvent: 003a");
242                     double y = RS_Math::eval(cmd.mid(commaPos+1), &ok2);
243                     RS_DEBUG->print("RS_EventHandler::commandEvent: 004");
244 
245                     if (ok1 && ok2) {
246                         RS_DEBUG->print("RS_EventHandler::commandEvent: 005");
247                         RS_CoordinateEvent ce(RS_Vector(x,y));
248                         RS_DEBUG->print("RS_EventHandler::commandEvent: 006");
249 						currentActions.last()->coordinateEvent(&ce);
250 					} else
251 						RS_DIALOGFACTORY->commandMessage(
252 									"Expression Syntax Error");
253 					e->accept();
254                 }
255 
256                 // handle relative cartesian coordinate input:
257                 if (!e->isAccepted()) {
258                     if (cmd.contains(',') && cmd.at(0)=='@') {
259                         int commaPos = cmd.indexOf(',');
260                         bool ok1, ok2;
261                         double x = RS_Math::eval(cmd.mid(1, commaPos-1), &ok1);
262                         double y = RS_Math::eval(cmd.mid(commaPos+1), &ok2);
263 
264                         if (ok1 && ok2) {
265                             RS_CoordinateEvent ce(RS_Vector(x,y) + relative_zero);
266 
267                             currentActions.last()->coordinateEvent(&ce);
268                             //                            currentActions[actionIndex]->coordinateEvent(&ce);
269 						} else
270 							RS_DIALOGFACTORY->commandMessage(
271 										"Expression Syntax Error");
272 						e->accept();
273                     }
274                 }
275 
276                 // handle absolute polar coordinate input:
277                 if (!e->isAccepted()) {
278                     if (cmd.contains('<') && cmd.at(0)!='@') {
279                         int commaPos = cmd.indexOf('<');
280                         bool ok1, ok2;
281                         double r = RS_Math::eval(cmd.left(commaPos), &ok1);
282                         double a = RS_Math::eval(cmd.mid(commaPos+1), &ok2);
283 
284                         if (ok1 && ok2) {
285 							RS_Vector pos{
286 								RS_Vector::polar(r,RS_Math::deg2rad(a))};
287                             RS_CoordinateEvent ce(pos);
288                             currentActions.last()->coordinateEvent(&ce);
289 						} else
290                                 RS_DIALOGFACTORY->commandMessage(
291                                             "Expression Syntax Error");
292                         e->accept();
293                     }
294                 }
295 
296                 // handle relative polar coordinate input:
297                 if (!e->isAccepted()) {
298                     if (cmd.contains('<') && cmd.at(0)=='@') {
299                         int commaPos = cmd.indexOf('<');
300                         bool ok1, ok2;
301                         double r = RS_Math::eval(cmd.mid(1, commaPos-1), &ok1);
302                         double a = RS_Math::eval(cmd.mid(commaPos+1), &ok2);
303 
304                         if (ok1 && ok2) {
305 							RS_Vector pos = RS_Vector::polar(r,RS_Math::deg2rad(a));
306                             RS_CoordinateEvent ce(pos + relative_zero);
307                             currentActions.last()->coordinateEvent(&ce);
308 						} else
309                                 RS_DIALOGFACTORY->commandMessage(
310                                             "Expression Syntax Error");
311                         e->accept();
312                     }
313                 }
314 
315                 // send command event directly to current action:
316                 if (!e->isAccepted()) {
317 //                    std::cout<<"RS_EventHandler::commandEvent(RS_CommandEvent* e): sending cmd("<<qPrintable(e->getCommand()) <<") to action: "<<currentActions.last()->rtti()<<std::endl;
318                     currentActions.last()->commandEvent(e);
319                 }
320             }else{
321             //send the command to default action
322                 if (defaultAction) {
323                     defaultAction->commandEvent(e);
324                 }
325             }
326             // do not accept command here. Actions themselves should be responsible to accept commands
327 //            e->accept();
328         }
329     }
330 
331     RS_DEBUG->print("RS_EventHandler::commandEvent: OK");
332 }
333 
334 
335 
336 /**
337  * Enables coordinate input in the command line.
338  */
enableCoordinateInput()339 void RS_EventHandler::enableCoordinateInput() {
340     coordinateInputEnabled = true;
341 }
342 
343 
344 
345 /**
346  * Enables coordinate input in the command line.
347  */
disableCoordinateInput()348 void RS_EventHandler::disableCoordinateInput() {
349     coordinateInputEnabled = false;
350 }
351 
352 
353 
354 /**
355  * @return Current action.
356  */
getCurrentAction()357 RS_ActionInterface* RS_EventHandler::getCurrentAction(){
358     if(hasAction()){
359         return currentActions.last();
360     } else {
361         return defaultAction;
362     }
363 }
364 
365 
366 
367 /**
368  * @return The current default action.
369  */
getDefaultAction() const370 RS_ActionInterface* RS_EventHandler::getDefaultAction() const{
371     return defaultAction;
372 }
373 
374 
375 
376 /**
377  * Sets the default action.
378  */
setDefaultAction(RS_ActionInterface * action)379 void RS_EventHandler::setDefaultAction(RS_ActionInterface* action) {
380     if (defaultAction) {
381         defaultAction->finish();
382         delete defaultAction;
383         //        defaultAction = NULL;
384     }
385 
386     defaultAction = action;
387 }
388 
389 
390 
391 /**
392  * Sets the current action.
393  */
setCurrentAction(RS_ActionInterface * action)394 void RS_EventHandler::setCurrentAction(RS_ActionInterface* action) {
395     RS_DEBUG->print("RS_EventHandler::setCurrentAction");
396     if (action==NULL) {
397         return;
398     }
399 
400     // Predecessor of the new action or NULL:
401     RS_ActionInterface* predecessor = NULL;
402 
403     // Suspend current action:
404     if(hasAction()){
405         predecessor = currentActions.last();
406         predecessor->suspend();
407         predecessor->hideOptions();
408     }
409     else {
410         if (defaultAction) {
411             predecessor = defaultAction;
412             predecessor->suspend();
413             predecessor->hideOptions();
414         }
415     }
416 
417     //    // Forget about the oldest action and make space for the new action:
418     //    if (actionIndex==RS_MAXACTIONS-1) {
419     //        // delete oldest action if necessary (usually never happens):
420     //        if (currentActions[0]) {
421     //            currentActions[0]->finish();
422     //            delete currentActions[0];
423     //            currentActions[0] = NULL;
424     //        }
425     //        // Move up actionstack (optimize):
426     //        for (int i=0; i<RS_MAXACTIONS-1; ++i) {
427     //            currentActions[i] = currentActions[i+1];
428     //        }
429     //    } else if (actionIndex<RS_MAXACTIONS-1) {
430     //        actionIndex++;
431     //    }
432 
433     // Set current action:
434     currentActions.push_back(action);
435     RS_DEBUG->print("RS_EventHandler::setCurrentAction: current action is: %s",
436                     currentActions.last()->getName().toLatin1().data());
437 
438     // Initialisation of our new action:
439     RS_DEBUG->print("RS_EventHandler::setCurrentAction: init current action");
440     action->init();
441     // ## new:
442     if (action->isFinished()==false) {
443         RS_DEBUG->print("RS_EventHandler::setCurrentAction: show options");
444         currentActions.last()->showOptions();
445         RS_DEBUG->print("RS_EventHandler::setCurrentAction: set predecessor");
446         action->setPredecessor(predecessor);
447     }
448 
449     RS_DEBUG->print("RS_EventHandler::setCurrentAction: cleaning up..");
450     cleanUp();
451 
452     RS_DEBUG->print("RS_EventHandler::setCurrentAction: debugging actions");
453     debugActions();
454     RS_DEBUG->print("RS_GraphicView::setCurrentAction: OK");
455     if (q_action)
456         q_action->setChecked(true);
457 }
458 
459 
460 
461 /**
462  * Kills all running selection actions. Called when a selection action
463  * is launched to reduce confusion.
464  */
killSelectActions()465 void RS_EventHandler::killSelectActions() {
466 
467     for (auto it=currentActions.begin();it != currentActions.end();){
468         if ((*it)->rtti()==RS2::ActionSelectSingle ||
469                 (*it)->rtti()==RS2::ActionSelectContour ||
470                 (*it)->rtti()==RS2::ActionSelectWindow ||
471                 (*it)->rtti()==RS2::ActionSelectIntersected ||
472                 (*it)->rtti()==RS2::ActionSelectLayer) {
473             if( ! (*it)->isFinished()){
474                 (*it)->finish();
475             }
476             delete *it;
477             it= currentActions.erase(it);
478         }else{
479             it++;
480         }
481     }
482 }
483 
484 
485 
486 /**
487  * Kills all running actions. Called when a window is closed.
488  */
killAllActions()489 void RS_EventHandler::killAllActions()
490 {
491 	RS_DEBUG->print(__FILE__ ": %s: line %d: begin\n", __func__, __LINE__);
492 
493     if (q_action)
494     {
495         q_action->setChecked(false);
496         q_action = nullptr;
497     }
498 
499 	for(auto p: currentActions)
500     {
501 		if (!p->isFinished())
502         {
503 			p->finish();
504 		}
505 	}
506 
507     if (!defaultAction->isFinished())
508     {
509         defaultAction->finish();
510     }
511 
512 	RS_DEBUG->print(__FILE__ ": %s: line %d: begin\n", __func__, __LINE__);
513 	defaultAction->init(0);
514 }
515 
516 
517 
518 /**
519  * @return true if the action is within currentActions
520  */
isValid(RS_ActionInterface * action) const521 bool RS_EventHandler::isValid(RS_ActionInterface* action) const{
522     return currentActions.indexOf(action) >= 0;
523 }
524 
525 /**
526  * @return true if there is at least one action in the action stack.
527  */
hasAction()528 bool RS_EventHandler::hasAction()
529 {
530     foreach (RS_ActionInterface* a, currentActions)
531     {
532         if(!a->isFinished())
533             return true;
534     }
535     return false;
536 }
537 
538 
539 
540 /**
541  * Garbage collector for actions.
542  */
cleanUp()543 void RS_EventHandler::cleanUp() {
544     RS_DEBUG->print("RS_EventHandler::cleanUp");
545 
546     for (auto it=currentActions.begin(); it != currentActions.end();)
547     {
548         if( (*it)->isFinished())
549         {
550             delete *it;
551             it= currentActions.erase(it);
552         }else{
553             ++it;
554         }
555     }
556     if(hasAction()){
557         currentActions.last()->resume();
558         currentActions.last()->showOptions();
559     } else {
560 		if (defaultAction) {
561             defaultAction->resume();
562             defaultAction->showOptions();
563         }
564     }
565     RS_DEBUG->print("RS_EventHandler::cleanUp: OK");
566 }
567 
568 
569 
570 /**
571  * Sets the snap mode for all currently active actions.
572  */
setSnapMode(RS_SnapMode sm)573 void RS_EventHandler::setSnapMode(RS_SnapMode sm) {
574     for(auto a: currentActions){
575         if( ! a->isFinished()){
576             a->setSnapMode(sm);
577         }
578     }
579 
580 	if (defaultAction) {
581         defaultAction->setSnapMode(sm);
582     }
583 }
584 
585 
586 /**
587  * Sets the snap restriction for all currently active actions.
588  */
setSnapRestriction(RS2::SnapRestriction sr)589 void RS_EventHandler::setSnapRestriction(RS2::SnapRestriction sr) {
590 
591     for(auto a: currentActions){
592         if( ! a->isFinished()){
593             a->setSnapRestriction(sr);
594         }
595     }
596 
597     if (defaultAction) {
598         defaultAction->setSnapRestriction(sr);
599     }
600 }
601 
602 
debugActions() const603 void RS_EventHandler::debugActions() const{
604     //        std::cout<<"action queue size=:"<<currentActions.size()<<std::endl;
605     RS_DEBUG->print("---");
606     for(int i=0;i<currentActions.size();++i){
607 
608         if (i == currentActions.size() - 1 ) {
609             RS_DEBUG->print("Current");
610         }
611         RS_DEBUG->print("Action %03d: %s [%s]",
612                         i, currentActions.at(i)->getName().toLatin1().data(),
613                         currentActions.at(i)->isFinished() ? "finished" : "active");
614     }
615 }
616 
setQAction(QAction * action)617 void RS_EventHandler::setQAction(QAction* action)
618 {
619     if (q_action)
620     {
621         q_action->setChecked(false);
622         killAllActions();
623     }
624     q_action = action;
625 }
626 
setRelativeZero(const RS_Vector & point)627 void RS_EventHandler::setRelativeZero(const RS_Vector& point)
628 {
629     relative_zero = point;
630 }
631 
inSelectionMode()632 bool RS_EventHandler::inSelectionMode()
633 {
634     switch (getCurrentAction()->rtti())
635     {
636         case RS2::ActionDefault:
637         case RS2::ActionSelectSingle:
638         case RS2::ActionSelectWindow:
639         case RS2::ActionDeselectWindow:
640         case RS2::ActionSelectContour:
641         case RS2::ActionSelectIntersected:
642         case RS2::ActionDeselectIntersected:
643         case RS2::ActionSelectLayer:
644             return true;
645         default:
646             return false;
647     }
648 }
649 
650 // EOF
651