]> Shamusworld >> Repos - architektonas/blob - src/applicationwindow.cpp
96b13ca8b6a66964d8094784d17f062d96342ab2
[architektonas] / src / applicationwindow.cpp
1 //
2 // applicationwindow.cpp: Architektonas
3 //
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -------------------------------------------------------------
12 // JLH  03/22/2011  Created this file
13 // JLH  09/29/2011  Added simple zoom in/out functionality
14 // JLH  10/03/2011  Fixed zoom tool to zoom in/out from center of screen
15 //
16
17 // FIXED:
18 //
19 //
20 // STILL TO BE DONE:
21 //
22 //
23
24 // Uncomment this for debugging...
25 //#define DEBUG
26 //#define DEBUGFOO                      // Various tool debugging...
27 //#define DEBUGTP                               // Toolpalette debugging...
28
29 #include "applicationwindow.h"
30
31 #include "about.h"
32 #include "blockwidget.h"
33 #include "drawingview.h"
34 #include "fileio.h"
35 #include "generaltab.h"
36 #include "layerwidget.h"
37 #include "painter.h"
38 #include "settingsdialog.h"
39
40
41 ApplicationWindow::ApplicationWindow(): settings("Underground Software", "Architektonas")
42 {
43         drawing = new DrawingView(this);
44         drawing->setMouseTracking(true);                // We want *all* mouse events...!
45         setCentralWidget(drawing);
46
47         aboutWin = new AboutWindow(this);
48
49 //      ((TTEdit *)qApp)->charWnd = new CharWindow(this);
50
51         setWindowIcon(QIcon(":/res/atns-icon.png"));
52         setWindowTitle("Architektonas");
53
54         CreateActions();
55         CreateMenus();
56         CreateToolbars();
57
58         // Create Dock widgets
59         QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
60         LayerWidget * lw = new LayerWidget;
61         dock1->setWidget(lw);
62         addDockWidget(Qt::RightDockWidgetArea, dock1);
63         QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
64         BlockWidget * bw = new BlockWidget;
65         dock2->setWidget(bw);
66         addDockWidget(Qt::RightDockWidgetArea, dock2);
67         // Needed for saveState()
68         dock1->setObjectName("Layers");
69         dock2->setObjectName("Blocks");
70
71         //      Create status bar
72         zoomIndicator = new QLabel("Grid: 12.0\" Zoom: 12.5%");
73         statusBar()->addPermanentWidget(zoomIndicator);
74         statusBar()->showMessage(tr("Ready"));
75
76         ReadSettings();
77         setUnifiedTitleAndToolBarOnMac(true);
78         Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
79 }
80
81
82 void ApplicationWindow::closeEvent(QCloseEvent * event)
83 {
84         WriteSettings();
85         event->accept();                                                        // Use ignore() if can't close for some reason
86         //Do we have a memory leak here if we don't delete the font in the Object???
87 }
88
89
90 void ApplicationWindow::FileNew(void)
91 {
92         // Should warn the user if drawing hasn't been saved...
93         drawing->document.Clear();
94         drawing->update();
95         documentName.clear();
96         setWindowTitle("Architektonas - Untitled");
97         statusBar()->showMessage(tr("New drawing is ready."));
98 }
99
100
101 void ApplicationWindow::FileOpen(void)
102 {
103         QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
104                 "", tr("Architektonas files (*.drawing)"));
105         FILE * file = fopen(filename.toAscii().data(), "r");
106
107         if (file == 0)
108         {
109                 QMessageBox msg;
110                 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
111                 msg.setIcon(QMessageBox::Critical);
112                 msg.exec();
113                 return;
114         }
115
116         Container container(Vector(0, 0));
117         bool successful = FileIO::LoadAtnsFile(file, &container);
118         fclose(file);
119
120         if (!successful)
121         {
122                 QMessageBox msg;
123                 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
124                 msg.setIcon(QMessageBox::Critical);
125                 msg.exec();
126                 return;
127         }
128
129 printf("FileOpen: container size = %li\n", container.objects.size());
130         drawing->document = container;
131         drawing->update();
132         documentName = filename;
133         setWindowTitle(QString("Architektonas - %1").arg(documentName));
134         statusBar()->showMessage(tr("Drawing loaded."));
135 }
136
137
138 void ApplicationWindow::FileSave(void)
139 {
140         if (documentName.isEmpty())
141                 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
142                         "", tr("Architektonas drawings (*.drawing)"));
143
144         FILE * file = fopen(documentName.toAscii().data(), "w");
145
146         if (file == 0)
147         {
148                 QMessageBox msg;
149                 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
150                 msg.setIcon(QMessageBox::Critical);
151                 msg.exec();
152                 return;
153         }
154
155         bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
156         fclose(file);
157
158         if (!successful)
159         {
160                 QMessageBox msg;
161                 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
162                 msg.setIcon(QMessageBox::Critical);
163                 msg.exec();
164                 // In this case, we should unlink the created file, since it's not right...
165                 unlink(documentName.toAscii().data());
166                 return;
167         }
168
169         setWindowTitle(QString("Architektonas - %1").arg(documentName));
170         statusBar()->showMessage(tr("Drawing saved."));
171 }
172
173
174 void ApplicationWindow::FileSaveAs(void)
175 {
176         QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
177                 documentName, tr("Architektonas drawings (*.drawing)"));
178
179         if (!filename.isEmpty())
180         {
181                 documentName = filename;
182                 FileSave();
183         }
184 }
185
186
187 void ApplicationWindow::SnapToGridTool(void)
188 {
189         Object::SetSnapMode(snapToGridAct->isChecked());
190 }
191
192
193 void ApplicationWindow::FixAngle(void)
194 {
195         Object::SetFixedAngle(fixAngleAct->isChecked());
196 }
197
198
199 void ApplicationWindow::FixLength(void)
200 {
201         Object::SetFixedLength(fixLengthAct->isChecked());
202 }
203
204
205 // We want certain tools to be exclusive, and this approach isn't working correctly...
206 void ApplicationWindow::DeleteTool(void)
207 {
208         // For this tool, we check first to see if anything is selected. If so, we
209         // delete those and *don't* select the delete tool.
210         if (drawing->document.ItemsSelected() > 0)
211         {
212                 drawing->document.DeleteSelectedItems();
213                 drawing->update();
214                 deleteAct->setChecked(false);
215                 return;
216         }
217
218         // Otherwise, toggle the state of the tool
219         ClearUIToolStatesExcept(deleteAct);
220         SetInternalToolStates();
221 }
222
223
224 void ApplicationWindow::DimensionTool(void)
225 {
226         ClearUIToolStatesExcept(addDimensionAct);
227         SetInternalToolStates();
228 }
229
230
231 void ApplicationWindow::RotateTool(void)
232 {
233         ClearUIToolStatesExcept(rotateAct);
234         SetInternalToolStates();
235 }
236
237
238 void ApplicationWindow::AddLineTool(void)
239 {
240         ClearUIToolStatesExcept(addLineAct);
241         SetInternalToolStates();
242 }
243
244
245 void ApplicationWindow::AddCircleTool(void)
246 {
247         ClearUIToolStatesExcept(addCircleAct);
248         SetInternalToolStates();
249 }
250
251
252 void ApplicationWindow::AddArcTool(void)
253 {
254         ClearUIToolStatesExcept(addArcAct);
255         SetInternalToolStates();
256 }
257
258
259 void ApplicationWindow::AddPolygonTool(void)
260 {
261         ClearUIToolStatesExcept(addPolygonAct);
262         SetInternalToolStates();
263 }
264
265
266 void ApplicationWindow::ZoomInTool(void)
267 {
268         double zoomFactor = 2.0;
269 /*
270 We need to find the center of the screen, then figure out where the new corner
271 will be in the zoomed in window.
272
273 So we know in Qt coords, the center is found via:
274 size.width()  / 2 --> xCenter
275 size.height() / 2 --> yCenter
276
277 transform x/yCenter to Cartesian coordinates. So far, so good.
278
279 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
280 (after subtracting from center, that is...)
281 */
282         QSize size = drawing->size();
283         Vector center(size.width() / 2.0, size.height() / 2.0);
284 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
285         center = Painter::QtToCartesianCoords(center);
286 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
287         Vector newOrigin = center - ((center - Painter::origin) / zoomFactor);
288 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
289         Painter::origin = newOrigin;
290
291 //printf("Zoom in... level going from %02f to ", Painter::zoom);
292         // This just zooms leaving origin intact... should zoom in at the current center! [DONE]
293         // This should actually be calculated by drawing->gridPixels / grid size.
294         Painter::zoom *= zoomFactor;
295         drawing->gridSpacing = 12.0 / Painter::zoom;
296 //      zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
297         zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(drawing->gridSpacing));
298         drawing->UpdateGridBackground();
299         drawing->update();
300 }
301
302
303 void ApplicationWindow::ZoomOutTool(void)
304 {
305 /*
306 Ok, real example.
307 center = (436, 311)
308 origin = (223, 160.5)
309 newOrigin should be (-10, -10)
310 Why isn't it?
311
312 center - origin = (213, 150.5)
313 origin - center = (-213, -150.5)
314 x 2 = (-426, -301)
315 + center = (-10, -10)
316
317 */
318         double zoomFactor = 2.0;
319         QSize size = drawing->size();
320         Vector center(size.width() / 2.0, size.height() / 2.0);
321 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
322         center = Painter::QtToCartesianCoords(center);
323 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
324 //      Vector newOrigin = (center - Painter::origin) * zoomFactor;
325 //      Vector newOrigin = center - (Painter::origin * zoomFactor);
326         Vector newOrigin = center + ((Painter::origin - center) * zoomFactor);
327 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
328         Painter::origin = newOrigin;
329 //printf("Zoom out...\n");
330         // This just zooms leaving origin intact... should zoom out at the current center! [DONE]
331         Painter::zoom /= zoomFactor;
332         drawing->gridSpacing = 12.0 / Painter::zoom;
333 //      zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
334         zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(drawing->gridSpacing));
335         drawing->UpdateGridBackground();
336         drawing->update();
337 }
338
339
340 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
341 {
342         if (exception != addArcAct)
343                 addArcAct->setChecked(false);
344
345         if (exception != addCircleAct)
346                 addCircleAct->setChecked(false);
347
348         if (exception != addDimensionAct)
349                 addDimensionAct->setChecked(false);
350
351         if (exception != addLineAct)
352                 addLineAct->setChecked(false);
353
354         if (exception != addPolygonAct)
355                 addPolygonAct->setChecked(false);
356
357         if (exception != deleteAct)
358                 deleteAct->setChecked(false);
359
360         if (exception != rotateAct)
361                 rotateAct->setChecked(false);
362 }
363
364
365 void ApplicationWindow::SetInternalToolStates(void)
366 {
367         Object::SetDeleteActive(deleteAct->isChecked());
368         Object::SetDimensionActive(addDimensionAct->isChecked());
369         drawing->SetRotateToolActive(rotateAct->isChecked());
370
371         // We can be sure that if we've come here, then either an active tool is
372         // being deactivated, or a new tool is being created. In either case, the
373         // old tool needs to be deleted.
374         if (drawing->toolAction)
375         {
376                 delete drawing->toolAction;
377                 drawing->toolAction = NULL;
378         }
379
380         drawing->SetAddLineToolActive(addLineAct->isChecked());
381         drawing->SetAddCircleToolActive(addCircleAct->isChecked());
382         drawing->SetAddDimensionToolActive(addDimensionAct->isChecked());
383 }
384
385
386 void ApplicationWindow::HelpAbout(void)
387 {
388         aboutWin->show();
389 }
390
391
392 void ApplicationWindow::Settings(void)
393 {
394         SettingsDialog dlg(this);
395         dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
396
397         if (dlg.exec() == false)
398                 return;
399
400         // Deal with stuff here (since user hit "OK" button...)
401         drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
402         WriteSettings();
403 }
404
405
406 //
407 // Group a bunch of selected objects (which can include other groups) together
408 // or ungroup a selected group.
409 //
410 void ApplicationWindow::HandleGrouping(void)
411 {
412         int itemsSelected = drawing->document.ItemsSelected();
413
414         // If nothing selected, do nothing
415         if (itemsSelected == 0)
416         {
417                 statusBar()->showMessage(tr("No objects selected to make a group from."));
418                 return;
419         }
420
421         // If it's a group that's selected, ungroup it and leave the objects in a
422         // selected state
423         if (itemsSelected == 1)
424         {
425                 Object * object = drawing->document.SelectedItem(0);
426
427 #if 0
428 if (object == NULL)
429         printf("SelectedItem = NULL!\n");
430 else
431         printf("SelectedItem = %08X, type = %i\n", object, object->type);
432 #endif
433
434                 if (object == NULL || object->type != OTContainer)
435                 {
436                         statusBar()->showMessage(tr("A group requires two or more selected objects."));
437                         return;
438                 }
439
440                 // Need the parent of the group, we're assuming here that the parent is
441                 // the drawing's document. Does it matter? Maybe...
442                 // Could just stipulate that grouping like this only takes place where the
443                 // parent of the group is the drawing's document. Makes life much simpler.
444                 ((Container *)object)->SelectAll();
445                 ((Container *)object)->MoveContentsTo(&(drawing->document));
446                 drawing->document.Delete(object);
447                 statusBar()->showMessage(tr("Objects ungrouped."));
448         }
449         // Otherwise, if it's a group of 2 or more objects (which can be groups too)
450         // group them and select the group
451         else if (itemsSelected > 1)
452         {
453                 Container * container = new Container(Vector(), &(drawing->document));
454                 drawing->document.MoveSelectedContentsTo(container);
455                 drawing->document.Add(container);
456                 container->DeselectAll();
457                 container->state = OSSelected;
458                 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
459         }
460
461         drawing->update();
462 }
463
464
465 void ApplicationWindow::HandleGridSizeInPixels(int size)
466 {
467         drawing->SetGridSize(size);
468         drawing->update();
469 }
470
471
472 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
473 {
474         // Parse the text...
475         bool ok;
476         double value = text.toDouble(&ok);
477
478         // Nothing parsable to a double, so quit...
479         if (!ok)
480                 return;
481
482         drawing->gridSpacing = value;
483         Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
484         drawing->update();
485 }
486
487
488 void ApplicationWindow::CreateActions(void)
489 {
490         exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
491                 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
492         connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
493
494         snapToGridAct = CreateAction(tr("Snap To &Grid"), tr("Snap To Grid"), tr("Snaps mouse cursor to the visible grid when moving/creating objects."), QIcon(":/res/snap-to-grid-tool.png"), QKeySequence(tr("S")), true);
495         connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
496
497         fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
498                 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
499         connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
500
501         fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
502                 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
503         connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
504
505         deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
506         connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
507
508         addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
509         connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
510
511         addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
512         connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
513
514         addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
515         connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
516
517         addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
518         connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
519
520         addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
521         connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
522
523         aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
524         connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
525
526         rotateAct = CreateAction(tr("&Rotate Objects"), tr("Rotate"), tr("Rotate object(s) around an arbitrary center."), QIcon(":/res/rotate-tool.png"), QKeySequence(tr("R,O")), true);
527         connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
528
529         zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
530         connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
531
532         zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
533         connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
534
535         fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n")));
536         connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
537
538         fileOpenAct = CreateAction(tr("&Open Drawing"), tr("Open Drawing"), tr("Opens an existing drawing from a file."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+o")));
539         connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
540
541         fileSaveAct = CreateAction(tr("&Save Drawing"), tr("Save Drawing"), tr("Saves the current drawing to a file."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+s")));
542         connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
543
544         fileSaveAsAct = CreateAction(tr("Save Drawing &As"), tr("Save As"), tr("Saves the current drawing to a file with a different name."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+Shift+s")));
545         connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
546
547         fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+w")));
548
549         settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/generic-tool.png"), QKeySequence());
550         connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
551
552         groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
553         connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
554
555 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
556 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
557 /*      QActionGroup * group = new QActionGroup(this);
558         group->addAction(deleteAct);
559         group->addAction(addDimensionAct);
560         group->addAction(addLineAct);
561         group->addAction(addCircleAct);
562         group->addAction(addArcAct);//*/
563 }
564
565
566 //
567 // Consolidates action creation from a multi-step process to a single-step one.
568 //
569 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
570         QIcon icon, QKeySequence key, bool checkable/*= false*/)
571 {
572         QAction * action = new QAction(icon, name, this);
573         action->setToolTip(tooltip);
574         action->setStatusTip(statustip);
575         action->setShortcut(key);
576         action->setCheckable(checkable);
577
578         return action;
579 }
580
581
582 //
583 // This is essentially the same as the previous function, but this allows more
584 // than one key sequence to be added as key shortcuts.
585 //
586 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
587         QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
588 {
589         QAction * action = new QAction(icon, name, this);
590         action->setToolTip(tooltip);
591         action->setStatusTip(statustip);
592         QList<QKeySequence> keyList;
593         keyList.append(key1);
594         keyList.append(key2);
595         action->setShortcuts(keyList);
596         action->setCheckable(checkable);
597
598         return action;
599 }
600
601
602 void ApplicationWindow::CreateMenus(void)
603 {
604         QMenu * menu = menuBar()->addMenu(tr("&File"));
605         menu->addAction(fileNewAct);
606         menu->addAction(fileOpenAct);
607         menu->addAction(fileSaveAct);
608         menu->addAction(fileSaveAsAct);
609         menu->addAction(fileCloseAct);
610         menu->addSeparator();
611         menu->addAction(exitAct);
612
613         menu = menuBar()->addMenu(tr("&View"));
614         menu->addAction(zoomInAct);
615         menu->addAction(zoomOutAct);
616
617         menu = menuBar()->addMenu(tr("&Edit"));
618         menu->addAction(snapToGridAct);
619         menu->addAction(groupAct);
620         menu->addAction(fixAngleAct);
621         menu->addAction(fixLengthAct);
622         menu->addAction(rotateAct);
623         menu->addSeparator();
624         menu->addAction(deleteAct);
625         menu->addSeparator();
626         menu->addAction(addLineAct);
627         menu->addAction(addCircleAct);
628         menu->addAction(addArcAct);
629         menu->addAction(addPolygonAct);
630         menu->addAction(addDimensionAct);
631         menu->addSeparator();
632         menu->addAction(settingsAct);
633
634         menu = menuBar()->addMenu(tr("&Help"));
635         menu->addAction(aboutAct);
636 }
637
638
639 void ApplicationWindow::CreateToolbars(void)
640 {
641         QToolBar * toolbar = addToolBar(tr("File"));
642         toolbar->setObjectName("File"); // Needed for saveState()
643         toolbar->addAction(exitAct);
644
645         toolbar = addToolBar(tr("View"));
646         toolbar->setObjectName("View");
647         toolbar->addAction(zoomInAct);
648         toolbar->addAction(zoomOutAct);
649
650         QSpinBox * spinbox = new QSpinBox;
651         toolbar->addWidget(spinbox);
652         QLineEdit * lineedit = new QLineEdit;
653         toolbar->addWidget(lineedit);
654
655         toolbar = addToolBar(tr("Edit"));
656         toolbar->setObjectName("Edit");
657         toolbar->addAction(snapToGridAct);
658         toolbar->addAction(groupAct);
659         toolbar->addAction(fixAngleAct);
660         toolbar->addAction(fixLengthAct);
661         toolbar->addAction(rotateAct);
662         toolbar->addAction(deleteAct);
663         toolbar->addSeparator();
664         toolbar->addAction(addLineAct);
665         toolbar->addAction(addCircleAct);
666         toolbar->addAction(addArcAct);
667         toolbar->addAction(addPolygonAct);
668         toolbar->addAction(addDimensionAct);
669
670         spinbox->setRange(4, 256);
671         spinbox->setValue(12);
672         lineedit->setText("12");
673         connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
674         connect(lineedit, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
675 }
676
677
678 void ApplicationWindow::ReadSettings(void)
679 {
680         QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
681         QSize size = settings.value("size", QSize(400, 400)).toSize();
682         drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
683         snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
684         resize(size);
685         move(pos);
686         restoreState(settings.value("windowState").toByteArray());
687 }
688
689
690 void ApplicationWindow::WriteSettings(void)
691 {
692         settings.setValue("pos", pos());
693         settings.setValue("size", size());
694         settings.setValue("windowState", saveState());
695         settings.setValue("useAntialiasing", drawing->useAntialiasing);
696         settings.setValue("snapToGrid", snapToGridAct->isChecked());
697 }
698