1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2012 Dongxu Li (dongxuli2011@gmail.com)
6 ** Copyright (C) 2011 R. van Twisk (librecad@rvt.dds.nl)
7 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
8 **
9 **
10 ** This file may be distributed and/or modified under the terms of the
11 ** GNU General Public License version 2 as published by the Free Software
12 ** Foundation and appearing in the file gpl-2.0.txt included in the
13 ** packaging of this file.
14 **
15 ** This program is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ** GNU General Public License for more details.
19 **
20 ** You should have received a copy of the GNU General Public License
21 ** along with this program; if not, write to the Free Software
22 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 **
24 ** This copyright notice MUST APPEAR in all copies of the script!
25 **
26 **********************************************************************/
27
28 #include<vector>
29 #include <QObject>
30 #include <QTextStream>
31 #include "rs_commands.h"
32
33 #include "rs_system.h"
34 #include "rs_dialogfactory.h"
35 #include "rs_debug.h"
36
37 namespace {
38 struct LC_CommandItem {
39 std::vector<std::pair<QString, QString>> const fullCmdList;
40 std::vector<std::pair<QString, QString>> const shortCmdList;
41 RS2::ActionType actionType;
42 };
43
44 // helper function to check and report command collision
45 template<typename T1, typename T2>
isCollisionFree(std::map<T1,T2> const & lookUp,T1 const & key,T2 const & value)46 bool isCollisionFree(std::map<T1, T2> const& lookUp, T1 const& key, T2 const& value)
47 {
48 if(!lookUp.count(key)) return true;
49
50 //report command string collision
51 QString msg=__FILE__+QObject::tr(": duplicated command: %1 is already taken by %2")
52 .arg(key).arg(value);
53
54 RS_DEBUG->print(RS_Debug::D_ERROR, "%s\n", msg.toStdString().c_str());
55 return false;
56 }
57 }
58
59 RS_Commands* RS_Commands::uniqueInstance = nullptr;
60
61 const char* RS_Commands::FnPrefix = "Fn";
62 const char* RS_Commands::AltPrefix = "Alt-";
63 const char* RS_Commands::MetaPrefix = "Meta-";
64
65
instance()66 RS_Commands* RS_Commands::instance() {
67 if (!uniqueInstance) {
68 uniqueInstance = new RS_Commands();
69 }
70 return uniqueInstance;
71 }
72
73 /**
74 * Constructor. Initiates main command dictionary.
75 * mainCommand keeps a map from translated commands to actionType
76 * shortCommand keeps a list of translated short commands
77 * cmdTranslation contains both ways of mapping between translated and English
78 */
RS_Commands()79 RS_Commands::RS_Commands() {
80 std::initializer_list<LC_CommandItem> commandList={
81 //draw point
82 {
83 //list all <full command, translation> pairs
84 {{"point", QObject::tr("point", "draw point")}},
85
86 //list all <short command, translation> pairs
87 {{"po", QObject::tr("po", "draw point")}},
88
89 //action type
90 RS2::ActionDrawPoint
91 },
92 //draw line
93 {
94 {{"line", QObject::tr("line", "draw line")}},
95 {{"li", QObject::tr("li", "draw line")},
96 {"l", QObject::tr("l", "draw line")}},
97 RS2::ActionDrawLine
98 },
99 //draw polyline
100 {
101 {{"polyline", QObject::tr("polyline", "draw polyline")}},
102 {{"pl", QObject::tr("pl", "draw polyline")}},
103 RS2::ActionDrawPolyline
104 },
105 //draw freehand line
106 {
107 {{"free", QObject::tr("free", "draw freehand line")}},
108 {{"fhl", QObject::tr("fhl", "draw freehand line")}},
109 RS2::ActionDrawLineFree
110 },
111 //draw spline
112 {
113 {{"spline", QObject::tr("spline", "draw spline")}},
114 {{"spl", QObject::tr("spl", "draw spline")}},
115 RS2::ActionDrawSpline
116 },
117 //draw spline through points
118 {
119 {{"spline2", QObject::tr("spline2", "spline through points")}},
120 {{"stp", QObject::tr("stp", "spline through points")}},
121 RS2::ActionDrawSplinePoints
122 },
123 //draw parallel line
124 {
125 {{"offset", QObject::tr("offset", "create offset")},
126 {"parallel", QObject::tr("parallel", "create offset")}},
127 {{"o", QObject::tr("o", "create offset")},
128 {"pa", QObject::tr("pa", "create offset")}},
129 RS2::ActionDrawLineParallel
130 },
131 //draw parallel line through point
132 {
133 {{"ptp", QObject::tr("ptp", "parallel through point")}},
134 {{"pp", QObject::tr("pp", "parallel through point")}},
135 RS2::ActionDrawLineParallelThrough
136 },
137 //draw angle bisector
138 {
139 {{"bisect", QObject::tr("bisect", "angle bisector")}},
140 {{"bi", QObject::tr("bi", "angle bisector")}},
141 RS2::ActionDrawLineBisector
142 },
143 //draw line tangent to circle from point
144 {
145 {{"tangentpc", QObject::tr("tangentpc", "tangent point and circle")}},
146 {{"tanpc", QObject::tr("tanpc", "tangent point and circle")}},
147 RS2::ActionDrawLineTangent1
148 },
149 //draw perpendicular line
150 {
151 {{"perp", QObject::tr("perp", "perpendicular line")}},
152 {{"ortho", QObject::tr("ortho", "perpendicular line")}},
153 RS2::ActionDrawLineOrthogonal
154 },
155 //draw vertical line
156 {
157 {{"vertical", QObject::tr("vertical", "vertical line")}},
158 {{"ver", QObject::tr("ver", "vertical line")}},
159 RS2::ActionDrawLineVertical
160 },
161 //draw horizontal line
162 {
163 {{"horizontal", QObject::tr("horizontal", "horizontal line")}},
164 {{"hor", QObject::tr("hor", "horizontal line")}},
165 RS2::ActionDrawLineHorizontal
166 },
167 //draw rectangle
168 {
169 {{"rectangle", QObject::tr("rectangle", "draw rectangle")}},
170 {{"rectang", QObject::tr("rectang", "draw rectangle")},
171 {"rect", QObject::tr("rect", "draw rectangle")},
172 {"rec", QObject::tr("rec", "draw rectangle")}},
173 RS2::ActionDrawLineRectangle
174 },
175 //draw polygon by 2 vertices
176 {
177 {{"polygon2v", QObject::tr("polygon2v", "polygon by 2 vertices")}},
178 {{"poly2", QObject::tr("poly2", "polygon by 2 vertices")}},
179 RS2::ActionDrawLinePolygonCorCor
180 },
181 //draw arc
182 {
183 {{"arc", QObject::tr("arc", "draw arc")}},
184 {//{"ar", QObject::tr("ar", "draw arc")},
185 {"a", QObject::tr("a", "draw arc")}},
186 RS2::ActionDrawArc3P
187 },
188 //draw circle
189 {
190 {{"circle", QObject::tr("circle", "draw circle")}},
191 {{"ci", QObject::tr("ci", "draw circle")}},
192 RS2::ActionDrawCircle
193 },
194 //draw 2 point circle
195 {
196 {{"circle2", QObject::tr("circle2", "circle 2 points")}},
197 {{"c2", QObject::tr("c2", "circle 2 points")}},
198 RS2::ActionDrawCircle2P
199 },
200 //draw 3 point circle
201 {
202 {{"circle3", QObject::tr("circle3", "circle 3 points")}},
203 {{"c3", QObject::tr("c3", "circle 3 points")}},
204 RS2::ActionDrawCircle3P
205 },
206 //draw circle with point and radius
207 {
208 {{"circlecr", QObject::tr("circlecr", "circle with center and radius")}},
209 {{"cc", QObject::tr("cc", "circle with center and radius")}},
210 RS2::ActionDrawCircleCR
211 },
212 //draw circle tangent to 3 objects
213 {
214 {{"tan3", QObject::tr("tan3", "circle tangent to 3")}},
215 {{"ct3", QObject::tr("ct3", "circle tangent to 3")}},
216 RS2::ActionDrawCircleTan3
217 },
218 //draw inscribed ellipse
219 {
220 {{"ellipseinscribed", QObject::tr("ellipseinscribed", "inscribed ellipse")}},
221 {{"ei", QObject::tr("ei", "inscribed ellipse")},
222 {"ie", QObject::tr("ie", "inscribed ellipse")}},
223 RS2::ActionDrawEllipseInscribe
224 },
225 //draw hatch
226 {
227 {{"hatch", QObject::tr("hatch", "draw hatch")}},
228 {{"ha", QObject::tr("ha", "draw hatch")}},
229 RS2::ActionDrawHatchNoSelect
230 },
231 //draw mtext
232 {
233 {{"mtext", QObject::tr("mtext", "draw mtext")}},
234 {{"mtxt", QObject::tr("mtxt", "draw mtext")}},
235 RS2::ActionDrawMText
236 },
237 //draw text
238 {
239 {{"text", QObject::tr("text", "draw text")}},
240 {{"txt", QObject::tr("txt", "draw text")}},
241 RS2::ActionDrawText
242 },
243 //zoom redraw
244 {
245 {{"regen", QObject::tr("regen", "zoom - redraw")},
246 {"redraw", QObject::tr("redraw", "zoom - redraw")}},
247 {{"rg", QObject::tr("rg", "zoom - redraw")},
248 {"zr", QObject::tr("zr", "zoom - redraw")}},
249 RS2::ActionZoomRedraw
250 },
251 //zoom window
252 {
253 {{"zoomwindow", QObject::tr("zoomwindow", "zoom - window")}},
254 {{"zw", QObject::tr("zw", "zoom - window")}},
255 RS2::ActionZoomWindow
256 },
257 //zoom auto
258 {
259 {{"zoomauto", QObject::tr("zoomauto", "zoom - auto")}},
260 {{"za", QObject::tr("za", "zoom - auto")}},
261 RS2::ActionZoomAuto
262 },
263 //zoom pan
264 {
265 {{"zoompan", QObject::tr("zoompan", "zoom - pan")}},
266 {{"zp", QObject::tr("zp", "zoom - pan")}},
267 RS2::ActionZoomPan
268 },
269 //zoom previous
270 {
271 {{"zoomprevious", QObject::tr("zoomprevious", "zoom - previous")}},
272 {{"zv", QObject::tr("zv", "zoom - previous")}},
273 RS2::ActionZoomPrevious
274 },
275 //kill actions
276 {
277 {{"kill", QObject::tr("kill", "kill all actions")}},
278 {{"k", QObject::tr("k", "kill all actions")}},
279 RS2::ActionEditKillAllActions
280 },
281 //undo cycle
282 {
283 {{"undo", QObject::tr("undo", "undo cycle")}},
284 {{"u", QObject::tr("u", "undo cycle")}},
285 RS2::ActionEditUndo
286 },
287 //redo cycle
288 {
289 {{"redo", QObject::tr("redo", "redo cycle")}},
290 {{"r", QObject::tr("r", "redo cycle")}},
291 RS2::ActionEditRedo
292 },
293 //dimension aligned
294 {
295 {{"dimaligned", QObject::tr("dimaligned", "dimension - aligned")}},
296 {{"da", QObject::tr("da", "dimension - aligned")}},
297 RS2::ActionDimAligned
298 },
299 //dimension horizontal
300 {
301 {{"dimhorizontal", QObject::tr("dimhorizontal", "dimension - horizontal")}},
302 {{"dh", QObject::tr("dh", "dimension - horizontal")}},
303 RS2::ActionDimLinearHor
304 },
305 //dimension vertical
306 {
307 {{"dimvertical", QObject::tr("dimvertical", "dimension - vertical")}},
308 {{"dv", QObject::tr("dv", "dimension - vertical")}},
309 RS2::ActionDimLinearVer
310 },
311 //dimension linear
312 {
313 {{"dimlinear", QObject::tr("dimlinear", "dimension - linear")}},
314 {{"dl", QObject::tr("dl", "dimension - linear")},
315 {"dr", QObject::tr("dr", "dimension - linear")}},
316 RS2::ActionDimLinear
317 },
318 //dimension angular
319 {
320 {{"dimangular", QObject::tr("dimangular", "dimension - angular")}},
321 {{"dan", QObject::tr("dan", "dimension - angular")}},
322 RS2::ActionDimAngular
323 },
324 //dimension radius
325 {
326 {{"dimradial", QObject::tr("dimradial", "dimension - radial")}},
327 {{"dimradius", QObject::tr("dimradius", "dimension - radius")}},
328 RS2::ActionDimRadial
329 },
330 //dimension diameter
331 {
332 {{"dimdiametric", QObject::tr("dimdiametric", "dimension - diametric")}},
333 {{"dimdiameter", QObject::tr("dimdiameter", "dimension - diametric")},
334 {"dd", QObject::tr("dd", "dimension - diametric")}},
335 RS2::ActionDimDiametric
336 },
337 //dimension leader
338 {
339 {{"dimleader", QObject::tr("dimleader", "dimension - leader")}},
340 {{"ld", QObject::tr("ld", "dimension - leader")}},
341 RS2::ActionDimLeader
342 },
343 //dimension regenerate
344 {
345 {{"dimregen", QObject::tr("dimregen", "dimension - regenerate")}},
346 {},
347 RS2::ActionToolRegenerateDimensions
348 },
349 //snap restrictions
350 {
351 {{"restrictnothing", QObject::tr("restrictnothing", "restrict - nothing")}},
352 {{"rn", QObject::tr("rn", "restrict - nothing")}},
353 RS2::ActionRestrictNothing
354 },
355 //snap orthogonal
356 {
357 {{"restrictorthogonal", QObject::tr("restrictorthogonal", "restrict - orthogonal")}},
358 {{"rr", QObject::tr("rr", "restrict - orthogonal")}},
359 RS2::ActionRestrictOrthogonal
360 },
361 //snap horizontal
362 {
363 {{"restricthorizontal", QObject::tr("restricthorizontal", "restrict - horizontal")}},
364 {{"rh", QObject::tr("rh", "restrict - horizontal")}},
365 RS2::ActionRestrictHorizontal
366 },
367 //snap vertical
368 {
369 {{"restrictvertical", QObject::tr("restrictvertical", "restrict - vertical")}},
370 {{"rv", QObject::tr("rv", "restrict - vertical")}},
371 RS2::ActionRestrictVertical
372 },
373 //move
374 {
375 {{"move", QObject::tr("move", "modify - move (copy)")}},
376 {{"mv", QObject::tr("mv", "modify - move (copy)")}},
377 RS2::ActionModifyMove
378 },
379 //bevel
380 {
381 {{"bevel", QObject::tr("bevel", "modify - bevel")}},
382 {{"bev", QObject::tr("bev", "modify - bevel")},
383 {"ch", QObject::tr("ch", "modify - bevel")}},
384 RS2::ActionModifyBevel
385 },
386 //fillet
387 {
388 {{"fillet", QObject::tr("fillet", "modify - fillet")}},
389 {{"fi", QObject::tr("fi", "modify - fillet")}},
390 RS2::ActionModifyRound
391 },
392 //divide
393 {
394 {{"divide", QObject::tr("divide", "modify - divide (cut)")},
395 {"cut", QObject::tr("cut", "modify - divide (cut)")}},
396 {{"div", QObject::tr("div", "modify - divide (cut)")},
397 {"di", QObject::tr("di", "modify - divide (cut)")}},
398 RS2::ActionModifyCut
399 },
400 //mirror
401 {
402 {{"mirror", QObject::tr("mirror", "modify - mirror")}},
403 {{"mi", QObject::tr("mi", "modify - mirror")}},
404 RS2::ActionModifyMirror
405 },
406 //revert
407 {
408 {{"revert", QObject::tr("revert", "modify - revert direction")}},
409 {{"rev", QObject::tr("rev", "modify - revert direction")}},
410 RS2::ActionModifyRevertDirection
411 },
412 //rotate
413 {
414 {{"rotate", QObject::tr("rotate", "modify - rotate")}},
415 {{"ro", QObject::tr("ro", "modify - rotate")}},
416 RS2::ActionModifyRotate
417 },
418 //scale
419 {
420 {{"scale", QObject::tr("scale", "modify - scale")}},
421 {{"sz", QObject::tr("sz", "modify - scale")}},
422 RS2::ActionModifyScale
423 },
424 //trim
425 {
426 {{"trim", QObject::tr("trim", "modify - trim (extend)")}},
427 {{"tm", QObject::tr("tm", "modify - trim (extend)")}},
428 RS2::ActionModifyTrim
429 },
430 //trim2
431 {
432 {{"trim2", QObject::tr("trim2", "modify - multi trim (extend)")}},
433 {{"tm2", QObject::tr("tm2", "modify - multi trim (extend)")},
434 {"t2", QObject::tr("t2", "modify - multi trim (extend)")}},
435 RS2::ActionModifyTrim2
436 },
437 //lengthen
438 {
439 {{"lengthen", QObject::tr("lengthen", "modify - lengthen")}},
440 {{"le", QObject::tr("le", "modify - lengthen")}},
441 RS2::ActionModifyTrimAmount
442 },
443 //stretch
444 {
445 {{"stretch", QObject::tr("stretch", "modify - stretch")}},
446 {{"ss", QObject::tr("ss", "modify - stretch")}},
447 RS2::ActionModifyStretch
448 },
449 //delete
450 {
451 {{"delete", QObject::tr("delete", "modify - delete (erase)")}},
452 {{"er", QObject::tr("er", "modify - delete (erase)")},
453 {"del", QObject::tr("del", "modify - delete (erase)")}},
454 RS2::ActionModifyDelete
455 },
456 //explode
457 {
458 {{"explode", QObject::tr("explode", "explode block/polyline into entities")}},
459 {{"xp", QObject::tr("xp", "explode block/polyline into entities")}},
460 RS2::ActionBlocksExplode
461 },
462 //snap free
463 {
464 {{"snapfree", QObject::tr("snapfree", "snap - free")}},
465 {{"os", QObject::tr("os", "snap - free")},
466 {"sf", QObject::tr("sf", "snap - free")}},
467 RS2::ActionSnapFree
468 },
469 //snap center
470 {
471 {{"snapcenter", QObject::tr("snapcenter", "snap - center")}},
472 {{"sc", QObject::tr("sc", "snap - center")}},
473 RS2::ActionSnapCenter
474 },
475 //snap dist
476 {
477 {{"snapdist", QObject::tr("snapdist", "snap - distance to endpoints")}},
478 {{"sd", QObject::tr("sd", "snap - distance to endpoints")}},
479 RS2::ActionSnapDist
480 },
481 //snap end
482 {
483 {{"snapend", QObject::tr("snapend", "snap - end points")}},
484 {{"se", QObject::tr("se", "snap - end points")}},
485 RS2::ActionSnapEndpoint
486 },
487 //snap grid
488 {
489 {{"snapgrid", QObject::tr("snapgrid", "snap - grid")}},
490 {{"sg", QObject::tr("sg", "snap - grid")}},
491 RS2::ActionSnapGrid
492 },
493 //snap intersection
494 {
495 {{"snapintersection", QObject::tr("snapintersection", "snap - intersection")}},
496 {{"si", QObject::tr("si", "snap - intersection")}},
497 RS2::ActionSnapIntersection
498 },
499 //snap middle
500 {
501 {{"snapmiddle", QObject::tr("snapmiddle", "snap - middle points")}},
502 {{"sm", QObject::tr("sm", "snap - middle points")}},
503 RS2::ActionSnapMiddle
504 },
505 //snap on entity
506 {
507 {{"snaponentity", QObject::tr("snaponentity", "snap - on entity")}},
508 {{"sn", QObject::tr("sn", "snap - on entity")},
509 {"np", QObject::tr("np", "snap - on entity")}},
510 RS2::ActionSnapOnEntity
511 },
512 //set relative zero
513 {
514 {{"setrelativezero", QObject::tr("setrelativezero", "set relative zero position")}},
515 {{"rz", QObject::tr("rz", "set relative zero position")}},
516 RS2::ActionSetRelativeZero
517 },
518 //Select all entities
519 {
520 {{"selectall", QObject::tr("selectall", "Select all entities")}},
521 {{"sa", QObject::tr("sa", "Select all entities")}},
522 RS2::ActionSelectAll
523 },
524 //DeSelect all entities
525 {
526 {{"deselectall", QObject::tr("deselectall", "deselect all entities")}},
527 {{"tn", QObject::tr("tn", "deselect all entities")}},
528 RS2::ActionDeselectAll
529 },
530 //Modify Attributes
531 {
532 {{"modifyattr", QObject::tr("modifyattr", "modify attribute")}},
533 {{"attr", QObject::tr("attr", "modify attribute")},
534 {"ma", QObject::tr("ma", "modify attribute")}},
535 RS2::ActionModifyAttributes
536 },
537 //Modify Properties
538 {
539 {{"properties", QObject::tr("properties", "modify properties")}},
540 {{"prop", QObject::tr("prop", "modify properties")},
541 {"mp", QObject::tr("mp", "modify properties")}},
542 RS2::ActionModifyEntity
543 },
544 //Distance Point to Point
545 {
546 {{"distance", QObject::tr("distance", "distance point to point")}},
547 {{"dist", QObject::tr("dist", "distance point to point")},
548 {"dpp", QObject::tr("dpp", "distance point to point")}},
549 RS2::ActionInfoDist
550 },
551 //Measure angle
552 {
553 {{"angle", QObject::tr("angle", "measure angle")}},
554 {{"ang", QObject::tr("ang", "measure angle")}},
555 RS2::ActionInfoAngle
556 },
557 //Measure area
558 {
559 {{"area", QObject::tr("area", "measure area")}},
560 {{"ar", QObject::tr("ar", "measure area")}},
561 RS2::ActionInfoArea
562 }
563 };
564
565 for(auto const& c0: commandList){
566 auto const act=c0.actionType;
567 //add full commands
568 for(auto const& p0: c0.fullCmdList){
569 if(isCollisionFree(cmdTranslation, p0.first, p0.second))
570 cmdTranslation[p0.first]=p0.second;
571 if(isCollisionFree(mainCommands, p0.second, act))
572 mainCommands[p0.second]=act;
573 }
574 //add short commands
575 for(auto const& p1: c0.shortCmdList){
576 if(isCollisionFree(cmdTranslation, p1.first, p1.second))
577 cmdTranslation[p1.first]=p1.second;
578 if(isCollisionFree(shortCommands, p1.second, act))
579 shortCommands[p1.second]=act;
580 }
581 }
582
583 // translations
584 std::vector<std::pair<QString, QString>> transList={
585 {"angle",QObject::tr("angle")},
586 {"dpi",QObject::tr("dpi")},
587 {"close",QObject::tr("close")},
588 {"chord length",QObject::tr("chord length")},
589 {"columns",QObject::tr("columns")},
590 {"columnspacing",QObject::tr("columnspacing")},
591 {"factor",QObject::tr("factor")},
592 {"length",QObject::tr("length")},
593 {"length1",QObject::tr("length1", "bevel/fillet length1")},
594 {"length2",QObject::tr("length2", "bevel/fillet length2")},
595 {"number",QObject::tr("number")},
596 {"radius",QObject::tr("radius")},
597 {"rows",QObject::tr("rows")},
598 {"rowspacing",QObject::tr("rowspacing")},
599 {"through",QObject::tr("through")},
600 {"trim",QObject::tr("trim")},
601
602 /** following are reversed translation,i.e.,from translated to english **/
603 //not used as command keywords
604 // used in function,checkCommand()
605 {QObject::tr("angle"),"angle"},
606 {QObject::tr("ang", "angle"),"angle"},
607 {QObject::tr("an", "angle"),"angle"},
608
609 {QObject::tr("center"),"center"},
610 {QObject::tr("cen", "center"),"center"},
611 {QObject::tr("ce", "center"),"center"},
612
613 {QObject::tr("chord length"),"chord length"},
614 // {QObject::tr("length", "chord length"),"chord length"},
615 {QObject::tr("cl", "chord length"),"chord length"},
616
617 {QObject::tr("close"),"close"},
618 {QObject::tr("c", "close"),"close"},
619
620 {QObject::tr("columns"),"columns"},
621 {QObject::tr("cols", "columns"),"columns"},
622 {QObject::tr("co", "columns"),"columns"},
623
624 {QObject::tr("columnspacing", "columnspacing for inserts"),"columnspacing"},
625 {QObject::tr("colspacing", "columnspacing for inserts"),"columnspacing"},
626 {QObject::tr("cs", "columnspacing for inserts"),"columnspacing"},
627
628 {QObject::tr("factor"),"factor"},
629 {QObject::tr("fact", "factor"),"factor"},
630 {QObject::tr("f", "factor"),"factor"},
631
632 {QObject::tr("help"),"help"},
633 {QObject::tr("?", "help"),"help"},
634
635 {QObject::tr("length","length"),"length"},
636 {QObject::tr("len","length"),"length"},
637 {QObject::tr("l","length"),"length"},
638
639 {QObject::tr("length1","length1"),"length1"},
640 {QObject::tr("len1","length1"),"length1"},
641 {QObject::tr("l1","length1"),"length1"},
642
643 {QObject::tr("length2","length2"),"length2"},
644 {QObject::tr("len2","length2"),"length2"},
645 {QObject::tr("l2","length2"),"length2"},
646
647 {QObject::tr("number","number"),"number"},
648 {QObject::tr("num","number"),"number"},
649 {QObject::tr("n","number"),"number"},
650
651 {QObject::tr("radius"),"radius"},
652 {QObject::tr("ra","radius"),"radius"},
653
654 {QObject::tr("reversed","reversed"),"reversed"},
655 {QObject::tr("rev","reversed"),"reversed"},
656 {QObject::tr("rev","reversed"),"reversed"},
657
658 {QObject::tr("row", "row"),"row"},
659
660 {QObject::tr("rowspacing", "rowspacing for inserts"),"rowspacing"},
661 {QObject::tr("rs","rowspacing for inserts"),"rowspacing"},
662
663 {QObject::tr("text"),"text"},
664 {QObject::tr("t","text"),"text"},
665
666 {QObject::tr("through"),"through"},
667 {QObject::tr("t","through"),"through"},
668
669 {QObject::tr("undo"),"undo"},
670 {QObject::tr("u","undo"),"undo"},
671
672 {QObject::tr("redo"),"redo"},
673 {QObject::tr("r","redo"),"redo"},
674
675 {QObject::tr("back"),"back"},
676 {QObject::tr("b","back"),"back"},
677 //printer preview
678 {QObject::tr("bw"), "blackwhite"},
679 {QObject::tr("blackwhite"), "blackwhite"},
680 {QObject::tr("color"), "color"},
681 {QObject::tr("paperoffset"),"paperoffset"},
682 {QObject::tr("graphoffset"),"graphoffset"}
683 };
684 for(auto const& p: transList){
685 cmdTranslation[p.first] = p.second;
686 }
687 }
688
689 /**
690 * Read existing alias file or create one new.
691 * In OS_WIN32 "c:\documents&settings\<user>\local configuration\application data\LibreCAD\librecad.alias"
692 * In OS_MAC "/Users/<user>/Library/Application Support/LibreCAD/librecad.alias"
693 * In OS_LINUX "/home/<user>/.local/share/data/LibreCAD/librecad.alias"
694 */
updateAlias()695 void RS_Commands::updateAlias(){
696 QString aliasName = RS_SYSTEM->getAppDataDir();
697 if (aliasName.isEmpty())
698 return;
699 aliasName += "/librecad.alias";
700 // qDebug()<<"alias file:\t"<<aliasName;
701 QFile f(aliasName);
702 QString line;
703 std::map<QString, QString> aliasList;
704 if (f.exists()) {
705
706 //alias file exists, read user defined alias
707 if (f.open(QIODevice::ReadOnly)) {
708 // qDebug()<<"alias File: "<<aliasName;
709 QTextStream ts(&f);
710 //check if is empty file or not alias file
711 // if(!line.isNull() || line == "#LibreCAD alias v1") {
712 // while (!ts.atEnd())
713 while(!ts.atEnd())
714 {
715 line=ts.readLine().trimmed();
716 if (line.isEmpty() || line.at(0)=='#' ) continue;
717 // Read alias
718 QStringList txtList = line.split(QRegExp(R"(\s)"),QString::SkipEmptyParts);
719 if (txtList.size()> 1) {
720 // qDebug()<<"reading: "<<txtList.at(0)<<"\t"<< txtList.at(1);
721 aliasList[txtList.at(0)]=txtList.at(1);
722 }
723 }
724 }
725 } else {
726 //alias file do no exist, create one with translated shortCommands
727 if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
728 QTextStream ts(&f);
729 ts << "#LibreCAD alias v1" << endl << endl;
730 ts << "# lines starting with # are comments" << endl;
731 ts << "# format are:" << endl;
732 ts << R"(# <alias>\t<command-untranslated>)" << endl;
733 ts << "# example"<<endl;
734 ts << "# l\tline"<<endl<<endl;
735 for(auto const& p: shortCommands){
736 auto const act=p.second;
737 for(auto const& pCmd: mainCommands){
738 if(pCmd.second==act){
739 ts<<p.first<<'\t'<<pCmd.first<<endl;
740 break;
741 }
742 }
743 }
744 ts.flush();
745 }
746
747 }
748 //update alias file with non present commands
749 //RLZ: to be written
750
751 //add alias to shortCommands
752 for(auto const& p: aliasList){
753 if(shortCommands.count(p.first)) continue;
754 if(mainCommands.count(p.first)) continue;
755 if(mainCommands.count(p.second)){
756 RS_DEBUG->print("adding command alias: %s\t%s\n", p.first.toStdString().c_str(), p.second.toStdString().c_str());
757 shortCommands[p.first]=mainCommands[p.second];
758 }else if(cmdTranslation.count(p.second)){
759 RS_DEBUG->print("adding command alias: %s\t%s\n", p.first.toStdString().c_str(), cmdTranslation[p.second].toStdString().c_str());
760 shortCommands[p.first]=mainCommands[cmdTranslation[p.second]];
761 }
762 }
763 f.close();
764 }
765
766
767 /**
768 * Tries to complete the given command (e.g. when tab is pressed).
769 */
complete(const QString & cmd)770 QStringList RS_Commands::complete(const QString& cmd) {
771 QStringList ret;
772 for(auto const& p: mainCommands){
773 if(p.first.startsWith(cmd, Qt::CaseInsensitive)){
774 ret << p.first;
775 }
776 }
777 ret.sort();
778
779 return ret;
780 }
781
782
783
784 /**
785 * @return Command for triggering the given action in the currently chosen
786 * language for commands.
787 *
788 * @param action ID of the action who's command will be returned.
789 * @param num Number of the command. There might be multiple commands
790 * for the same action (e.g. 'line' and 'l')
791 *
792 * @return The translated command.
793 */
cmdToAction(const QString & cmd,bool verbose)794 RS2::ActionType RS_Commands::cmdToAction(const QString& cmd, bool verbose) {
795 QString full = cmd.toLower();
796 RS2::ActionType ret = RS2::ActionNone;
797
798 // find command:
799 // RS2::ActionType* retPtr = mainCommands.value(cmd);
800 if ( mainCommands.count(cmd) ) {
801 ret = mainCommands[cmd];
802 } else if ( shortCommands.count(cmd) ) {
803 ret = shortCommands[cmd];
804 } else
805 return ret;
806
807 if (!verbose) return ret;
808 // find full command to confirm to user:
809 for(auto const& p: mainCommands){
810 if(p.second==ret){
811 RS_DEBUG->print("RS_Commands::cmdToAction: commandMessage");
812 RS_DIALOGFACTORY->commandMessage(QObject::tr("Command: %1 (%2)").arg(full).arg(p.first));
813 // RS_DialogFactory::instance()->commandMessage( QObject::tr("Command: %1").arg(full));
814 RS_DEBUG->print("RS_Commands::cmdToAction: "
815 "commandMessage: ok");
816 return ret;
817 }
818 }
819 RS_DEBUG->print(QObject::tr("RS_Commands:: command not found: %1").arg(full).toStdString().c_str());
820 return ret;
821 }
822
823 /**
824 * Gets the action for the given keycode. A keycode is a sequence
825 * of key-strokes that is entered like hotkeys.
826 */
keycodeToAction(const QString & code)827 RS2::ActionType RS_Commands::keycodeToAction(const QString& code) {
828 if(code.size() < 1)
829 return RS2::ActionNone;
830
831 QString c;
832
833 if(!(code.startsWith(FnPrefix) ||
834 code.startsWith(AltPrefix) ||
835 code.startsWith(MetaPrefix))) {
836 if(code.size() < 1 || code.contains(QRegExp("^[a-z].*",Qt::CaseInsensitive)) == false )
837 return RS2::ActionNone;
838 c = code.toLower();
839 } else {
840 c = code;
841 }
842
843
844 // std::cout<<"regex: "<<qPrintable(c)<<" matches: "<< c.contains(QRegExp("^[a-z].*",Qt::CaseInsensitive))<<std::endl;
845 // std::cout<<"RS2::ActionType RS_Commands::keycodeToAction("<<qPrintable(c)<<")"<<std::endl;
846
847 auto it = shortCommands.find(c);
848
849 if( it == shortCommands.end() ) {
850
851 //not found, searching for main commands
852 it = mainCommands.find(c);
853 if( it == mainCommands.end() ){
854 // RS_DIALOGFACTORY->commandMessage(QObject::tr("Command not found: %1").arg(c));
855 return RS2::ActionNone;
856 }
857 }
858 //found
859 RS_DIALOGFACTORY->commandMessage(QObject::tr("Accepted keycode: %1").arg(c));
860 //fixme, need to handle multiple hits
861 return it->second;
862 }
863
864
865 /**
866 * @return translated command for the given English command.
867 */
command(const QString & cmd)868 QString RS_Commands::command(const QString& cmd) {
869 auto it= instance()->cmdTranslation.find(cmd);
870 if(it != instance()->cmdTranslation.end()){
871 return instance()->cmdTranslation[cmd];
872 }
873 RS_DIALOGFACTORY->commandMessage(QObject::tr("Command not found: %1").arg(cmd));
874 RS_DEBUG->print(RS_Debug::D_WARNING,
875 "RS_Commands::command: command '%s' unknown", cmd.toLatin1().data());
876 return "";
877 }
878
879
880
881 /**
882 * Checks if the given string 'str' matches the given command 'cmd' for action
883 * 'action'.
884 *
885 * @param cmd The command we want to check for (e.g. 'angle').
886 * @param action The action which wants to know.
887 * @param str The string typically entered by the user.
888 */
checkCommand(const QString & cmd,const QString & str,RS2::ActionType)889 bool RS_Commands::checkCommand(const QString& cmd, const QString& str,
890 RS2::ActionType /*action*/) {
891
892 QString const& strl = str.toLower();
893 QString const& cmdLower = cmd.toLower();
894 auto it = instance()->cmdTranslation.find(cmdLower);
895 if(it != instance()->cmdTranslation.end()){
896 RS2::ActionType type0=instance()->cmdToAction(it->second, false);
897 if( type0 != RS2::ActionNone ) {
898 return type0 ==instance()->cmdToAction(strl);
899 }
900 }
901
902 it = instance()->cmdTranslation.find(strl);
903 if(it != instance()->cmdTranslation.end()) return it->second == cmdLower;
904 return false;
905 }
906
907
908 /**
909 * @return the local translation for "Commands available:".
910 */
msgAvailableCommands()911 QString RS_Commands::msgAvailableCommands() {
912 return QObject::tr("Available commands:");
913 }
914
915 /**
916 * @brief extractCliCal, filter cli calculator math expression
917 * @param cmd, cli string
918 * @return math expression for RS_Math:eval();
919 */
filterCliCal(const QString & cmd)920 QString RS_Commands::filterCliCal(const QString& cmd)
921 {
922
923 QString str=cmd.trimmed();
924 const QRegExp calCmd(R"(^(cal|calculate))");
925 if(!(str.contains(calCmd)
926 || str.startsWith(QObject::tr("cal","command to trigger cli calculator"), Qt::CaseInsensitive)
927 || str.startsWith(QObject::tr("calculate","command to trigger cli calculator"), Qt::CaseInsensitive)
928 )) {
929 return QString();
930 }
931 int index=str.indexOf(QRegExp(R"(\s)"));
932 bool spaceFound=(index>=0);
933 str=str.mid(index);
934 index=str.indexOf(QRegExp(R"(\S)"));
935 if(!(spaceFound && index>=0)) return QString();
936 str=str.mid(index);
937 return str;
938 }
939
940 // EOF
941