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