]> Shamusworld >> Repos - architektonas/blobdiff - src/applicationwindow.cpp
Added Parallel tool + command processing.
[architektonas] / src / applicationwindow.cpp
index b156d15fa90ab926f2ea92098b380b9beef57fa1..d3f014ff05a2ab51060838b5a0be4f665b800b4f 100644 (file)
@@ -5,11 +5,13 @@
 // (C) 2011 Underground Software
 // See the README and GPLv3 files for licensing and warranty information
 //
-// JLH = James L. Hammons <jlhamm@acm.org>
+// JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  03/22/2011  Created this file
+// JLH  09/29/2011  Added simple zoom in/out functionality
+// JLH  10/03/2011  Fixed zoom tool to zoom in/out from center of screen
 //
 
 // FIXED:
 
 #include "applicationwindow.h"
 
+#include <QPrintPreviewDialog>
+#include "about.h"
+#include "blockwidget.h"
+#include "commandprocessor.h"
+#include "consolewidget.h"
 #include "drawingview.h"
+#include "fileio.h"
+#include "generaltab.h"
+#include "global.h"
+#include "layerwidget.h"
+#include "objectwidget.h"
+#include "painter.h"
+#include "penwidget.h"
+#include "settingsdialog.h"
+#include "structs.h"
+#include "utils.h"
 
+// Class variables
+DrawingView * ApplicationWindow::drawing;
 
-ApplicationWindow::ApplicationWindow(): settings("Underground Software", "Architektonas")
+ApplicationWindow::ApplicationWindow():
+       baseUnitInput(new QLineEdit),
+       dimensionSizeInput(new QLineEdit),
+       settings("Underground Software", "Architektonas")
 {
        drawing = new DrawingView(this);
+       drawing->setMouseTracking(true);                // We want *all* mouse events...!
+       drawing->setFocusPolicy(Qt::StrongFocus);
        setCentralWidget(drawing);
 
-//     ((TTEdit *)qApp)->charWnd = new CharWindow(this);
+       aboutWin = new AboutWindow(this);
 
        setWindowIcon(QIcon(":/res/atns-icon.png"));
-       setWindowTitle("Architektonas");
+//     setWindowTitle("Architektonas");
 
        CreateActions();
        CreateMenus();
        CreateToolbars();
 
-       //      Create status bar
+       // Create Dock widgets
+       QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
+       LayerWidget * lw = new LayerWidget;
+       dock1->setWidget(lw);
+       addDockWidget(Qt::RightDockWidgetArea, dock1);
+       QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
+       BlockWidget * bw = new BlockWidget;
+       dock2->setWidget(bw);
+       addDockWidget(Qt::RightDockWidgetArea, dock2);
+       QDockWidget * dock3 = new QDockWidget(tr("Object"), this);
+       ObjectWidget * ow = new ObjectWidget;
+       dock3->setWidget(ow);
+       addDockWidget(Qt::RightDockWidgetArea, dock3);
+       QDockWidget * dock4 = new QDockWidget(tr("Command"), this);
+       cw = new ConsoleWidget;
+       dock4->setWidget(cw);
+       addDockWidget(Qt::BottomDockWidgetArea, dock4);
+
+       // Needed for saveState()
+       dock1->setObjectName("Layers");
+       dock2->setObjectName("Blocks");
+       dock3->setObjectName("Object");
+       dock4->setObjectName("Commands");
+
+       // Create status bar
+       zoomIndicator = new QLabel("Zoom: 100% Grid: 12.0\" BU: Inch");
+       statusBar()->addPermanentWidget(zoomIndicator);
        statusBar()->showMessage(tr("Ready"));
 
        ReadSettings();
+       // Make sure the bottom left corner gets owned by the right side:
+       setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
+       setUnifiedTitleAndToolBarOnMac(true);
+       Global::font =  new QFont("Verdana", 15, QFont::Bold);
 
-//     connect(textEdit->document(), SIGNAL(contentsChanged()),
-//                     this, SLOT(documentWasModified()));
+       connect(lw, SIGNAL(LayerDeleted(int)), drawing, SLOT(DeleteCurrentLayer(int)));
+       connect(lw, SIGNAL(LayerToggled()), drawing, SLOT(HandleLayerToggle()));
+       connect(lw, SIGNAL(LayersSwapped(int, int)), drawing, SLOT(HandleLayerSwap(int, int)));
+       connect(this, SIGNAL(ReloadLayers()), lw, SLOT(Reload()));
 
-//     setCurrentFile("");
-       setUnifiedTitleAndToolBarOnMac(true);
+       connect(drawing, SIGNAL(ObjectHovered(Object *)), ow, SLOT(ShowInfo(Object *)));
+       connect(drawing, SIGNAL(NeedZoomUpdate()), this, SLOT(UpdateZoom()));
 
-//     ((TTEdit *)qApp)->charWnd->show();//eh?
-       Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
+       connect(cw->cmdProc, SIGNAL(UpdateNeeded()), this, SLOT(UpdateFromCommand()));
 }
 
 void ApplicationWindow::closeEvent(QCloseEvent * event)
 {
        WriteSettings();
-       event->accept();                                                        // Use ignore() if can't close for some reason
+       event->accept();                // Use ignore() if can't close for some reason
        //Do we have a memory leak here if we don't delete the font in the Object???
 }
 
-//void ApplicationWindow::FileOpen(void)
-//{
-//}
+void ApplicationWindow::FileNew(void)
+{
+       // Warn the user if drawing has changed and hasn't been saved...
+       if (drawing->dirty)
+       {
+               QMessageBox msg;
+
+               msg.setText("The document has been modified.");
+               msg.setInformativeText("Do you want to save your changes?");
+               msg.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
+               msg.setDefaultButton(QMessageBox::Save);
+               int response = msg.exec();
+
+               switch (response)
+               {
+               case QMessageBox::Save:
+                       // Save was clicked
+                       FileSave();
+                       break;
+               case QMessageBox::Discard:
+                       // Don't Save was clicked
+                       break;
+               case QMessageBox::Cancel:
+                       // Cancel was clicked
+                       return;
+//                     break;
+               }
+       }
+
+       FileIO::ResetLayerVectors();
+       emit ReloadLayers();
+       DeleteContents(drawing->document.objects);
+       drawing->document.objects.clear();
+       drawing->dirty = false;
+       drawing->update();
+       documentName.clear();
+//     setWindowTitle("Architektonas - Untitled");
+       setWindowFilePath(documentName);
+       statusBar()->showMessage(tr("New drawing is ready."));
+}
+
+void ApplicationWindow::FileOpen(void)
+{
+       QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
+               "", tr("Architektonas files (*.drawing)"));
+
+       // User cancelled open
+       if (filename.isEmpty())
+               return;
+
+       LoadFile(filename);
+}
+
+void ApplicationWindow::FileOpenRecent(void)
+{
+       QAction * action = qobject_cast<QAction *>(sender());
+
+       if (!action)
+               return;
+
+       LoadFile(action->data().toString());
+}
+
+void ApplicationWindow::LoadFile(QString filename)
+{
+       FILE * file = fopen(filename.toUtf8().data(), "r");
+
+       if (file == 0)
+       {
+               QMessageBox msg;
+               msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
+               msg.setIcon(QMessageBox::Critical);
+               msg.exec();
+               return;
+       }
+
+       Container container(true);      // Make sure it's a top level container...
+       bool successful = FileIO::LoadAtnsFile(file, &container);
+       fclose(file);
+
+       if (!successful)
+       {
+               QMessageBox msg;
+               msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
+               msg.setIcon(QMessageBox::Critical);
+               msg.exec();
+               // Make sure to delete any hanging objects in the container...
+               DeleteContents(container.objects);
+               return;
+       }
+
+       // Keep memory leaks from happening by getting rid of the old document
+       DeleteContents(drawing->document.objects);
+       emit ReloadLayers();
+       // We can do this because the vector is just a bunch of pointers to our
+       // Objects, and the Containers (non-empty) can be moved this way with no
+       // problem.
+       drawing->document = container;
+       drawing->dirty = false;
+       drawing->update();
+       documentName = filename;
+//     setWindowTitle(QString("Architektonas - %1").arg(documentName));
+       AdjustMRU(filename);
+       statusBar()->showMessage(tr("Drawing loaded."));
+}
+
+void ApplicationWindow::FileSave(void)
+{
+       if (documentName.isEmpty())
+               documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
+                       "", tr("Architektonas drawings (*.drawing)"));
+
+       FILE * file = fopen(documentName.toUtf8().data(), "w");
+
+       if (file == 0)
+       {
+               QMessageBox msg;
+               msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
+               msg.setIcon(QMessageBox::Critical);
+               msg.exec();
+               return;
+       }
+
+       bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
+       fclose(file);
+
+       if (!successful)
+       {
+               QMessageBox msg;
+               msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
+               msg.setIcon(QMessageBox::Critical);
+               msg.exec();
+               // In this case, we should unlink the created file, since it's not
+               // right...
+//             unlink(documentName.toUtf8().data());
+               QFile::remove(documentName);
+               return;
+       }
+
+       drawing->dirty = false;
+//     setWindowTitle(QString("Architektonas - %1").arg(documentName));
+       AdjustMRU(documentName);
+       statusBar()->showMessage(tr("Drawing saved."));
+}
+
+void ApplicationWindow::FileSaveAs(void)
+{
+       QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
+               documentName, tr("Architektonas drawings (*.drawing)"));
+
+       if (!filename.isEmpty())
+       {
+               documentName = filename;
+               FileSave();
+       }
+}
+
+void ApplicationWindow::PrintPreview(void)
+{
+       QPrintPreviewDialog * dlg = new QPrintPreviewDialog(this);
+
+       connect(dlg, SIGNAL(paintRequested(QPrinter *)), this, SLOT(HandlePrintRequest(QPrinter *)));
+
+       dlg->exec();
+}
+
+void ApplicationWindow::HandlePrintRequest(QPrinter * printer)
+{
+       QPainter qtPainter(printer);
+       Painter painter(&qtPainter);
+
+       // Save vars for screen
+       Point originSave = Global::origin;
+       double zoomSave = Global::zoom;
+       Vector screenSizeSave = Global::screenSize;
+
+       // Adjust zoom + origin to fit the paper (or NxM pages if we have 'em)
+       Rect r = drawing->GetObjectExtents((Object *)(&(drawing->document)));
+
+       QPageLayout pageLayout = printer->pageLayout();
+       QRect pageRect = pageLayout.paintRectPixels(printer->resolution());
+
+       Global::origin = r.BottomLeft();
+       Global::screenSize.x = pageRect.width();
+       Global::screenSize.y = pageRect.height();
+
+       double xScale = (double)pageRect.width() / r.Width();
+       double yScale = (double)pageRect.height() / r.Height();
+       Global::zoom = qMin(xScale, yScale);
+
+       if (xScale < yScale)
+               Global::origin.y -= (((double)pageRect.height() / Global::zoom) - r.Height()) / 2.0;
+       else
+               Global::origin.x -= (((double)pageRect.width() / Global::zoom) - r.Width()) / 2.0;
+
+       // Do object rendering...
+       for(int i=0; i<Global::numLayers; i++)
+               drawing->RenderObjects(&painter, drawing->document.objects, i);
+
+       // Restore vars
+       Global::origin = originSave;
+       Global::zoom = zoomSave;
+       Global::screenSize = screenSizeSave;
+}
+
+//
+// Right-click menu
+//
+void ApplicationWindow::contextMenuEvent(QContextMenuEvent * event)
+{
+       // Proof of concept, still need to code up the real thing
+       QMenu menu(this);
+
+       VPVector hovered = drawing->GetHovered();
+
+       if ((drawing->select.size() > 0) || (hovered.size() > 0))
+       {
+               QMenu * layerMenu = menu.addMenu("To layer");
+
+               layerAct.clear();
+
+               for(int i=0; i<Global::numLayers; i++)
+               {
+                       QAction * act = new QAction(QIcon(), Global::layerName[i].c_str(), this);
+                       act->setData(i);
+                       layerMenu->addAction(act);
+                       layerAct.append(act);
+                       connect(act, SIGNAL(triggered()), this, SLOT(MoveToLayer()));
+               }
+       }
+
+       menu.addAction(mirrorAct);
+       menu.addAction(rotateAct);
+       menu.addAction(trimAct);
+       menu.exec(event->globalPos());
+}
+
+void ApplicationWindow::MoveToLayer(void)
+{
+       QAction * act = qobject_cast<QAction *>(sender());
+
+       drawing->MoveSelectedToLayer(act->data().toInt());
+       drawing->update();
+}
+
+void ApplicationWindow::UpdateFromCommand(void)
+{
+       cw->SetToolPrompt();
+       drawing->update();
+}
+
+void ApplicationWindow::SnapToGridTool(void)
+{
+       Global::snapToGrid = snapToGridAct->isChecked();
+}
 
 void ApplicationWindow::FixAngle(void)
 {
-       Object::SetFixedAngle(fixAngleAct->isChecked());
+       Global::fixedAngle = fixAngleAct->isChecked();
 }
 
 void ApplicationWindow::FixLength(void)
 {
-       Object::SetFixedLength(fixLengthAct->isChecked());
+       Global::fixedLength = fixLengthAct->isChecked();
 }
 
 void ApplicationWindow::DeleteTool(void)
 {
-       Object::SetDeleteActive(deleteAct->isChecked());
+       // For this tool, we check first to see if anything is selected. If so, we
+       // delete those and *don't* select the delete tool.
+       if (drawing->select.size() > 0)
+       {
+               DeleteSelectedObjects(drawing->document.objects);
+               drawing->update();
+               deleteAct->setChecked(false);
+               return;
+       }
+
+       // Otherwise, toggle the state of the tool
+       ClearUIToolStatesExcept(deleteAct);
+       SetInternalToolStates();
+       Global::toolSuppressCrosshair = true;
+}
+
+void ApplicationWindow::DimensionTool(void)
+{
+       ClearUIToolStatesExcept(addDimensionAct);
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::RotateTool(void)
+{
+       ClearUIToolStatesExcept(rotateAct);
+
+       // Do tear-down if Rotate tool has been turned off
+       if (!rotateAct->isChecked())
+               drawing->RotateHandler(ToolCleanup, Point(0, 0));
+
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::MirrorTool(void)
+{
+       ClearUIToolStatesExcept(mirrorAct);
+
+       // Do tear-down if Rotate tool has been turned off
+       if (!mirrorAct->isChecked())
+               drawing->MirrorHandler(ToolCleanup, Point(0, 0));
+
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::TrimTool(void)
+{
+       ClearUIToolStatesExcept(trimAct);
+       SetInternalToolStates();
+       Global::toolSuppressCrosshair = true;
+}
+
+void ApplicationWindow::ParallelTool(void)
+{
+       ClearUIToolStatesExcept(parallelAct);
+       SetInternalToolStates();
+       Global::toolSuppressCrosshair = true;
+}
+
+void ApplicationWindow::TriangulateTool(void)
+{
+       ClearUIToolStatesExcept(triangulateAct);
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::AddLineTool(void)
+{
+       ClearUIToolStatesExcept(addLineAct);
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::AddCircleTool(void)
+{
+       ClearUIToolStatesExcept(addCircleAct);
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::AddArcTool(void)
+{
+       ClearUIToolStatesExcept(addArcAct);
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::AddPolygonTool(void)
+{
+       ClearUIToolStatesExcept(addPolygonAct);
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::AddSplineTool(void)
+{
+       ClearUIToolStatesExcept(addSplineAct);
+       SetInternalToolStates();
+}
+
+void ApplicationWindow::ZoomInTool(void)
+{
+       double zoomFactor = 1.20;
+       QSize size = drawing->size();
+       Vector center = Painter::QtToCartesianCoords(Vector(size.width() / 2.0, size.height() / 2.0));
+
+       Global::origin = center - ((center - Global::origin) / zoomFactor);
+       Global::zoom *= zoomFactor;
+
+       UpdateZoom();
+}
+
+void ApplicationWindow::ZoomOutTool(void)
+{
+       double zoomFactor = 1.20;
+       QSize size = drawing->size();
+       Vector center = Painter::QtToCartesianCoords(Vector(size.width() / 2.0, size.height() / 2.0));
+
+       Global::origin = center + ((Global::origin - center) * zoomFactor);
+       Global::zoom /= zoomFactor;
+
+       UpdateZoom();
+}
+
+void ApplicationWindow::UpdateZoom(void)
+{
+       // And now, a bunch of heuristics to select the right grid size--autogrid!
+       // :-P
+       if (Global::zoom < 0.25)
+               Global::gridSpacing = 48.0;
+       else if (Global::zoom >= 0.25 && Global::zoom < 0.50)
+               Global::gridSpacing = 36.0;
+       else if (Global::zoom >= 0.50 && Global::zoom < 1.00)
+               Global::gridSpacing = 24.0;
+       else if (Global::zoom >= 1.00 && Global::zoom < 2.00)
+               Global::gridSpacing = 12.0;
+       else if (Global::zoom >= 2.00 && Global::zoom < 4.00)
+               Global::gridSpacing = 6.0;
+       else if (Global::zoom >= 4.00 && Global::zoom < 8.00)
+               Global::gridSpacing = 3.0;
+       else if (Global::zoom >= 8.00 && Global::zoom < 16.00)
+               Global::gridSpacing = 1.0;
+       else if (Global::zoom >= 16.00 && Global::zoom < 32.00)
+               Global::gridSpacing = 0.5;
+       else if (Global::zoom >= 32.00 && Global::zoom < 64.00)
+               Global::gridSpacing = 0.25;
+       else if (Global::zoom >= 64.00 && Global::zoom < 128.00)
+               Global::gridSpacing = 0.125;
+       else if (Global::zoom >= 128.00 && Global::zoom < 256.00)
+               Global::gridSpacing = 0.0625;
+       else if (Global::zoom >= 256.00 && Global::zoom < 512.00)
+               Global::gridSpacing = 0.03125;
+       else
+               Global::gridSpacing = 0.015625;
+
+       drawing->update();
+
+       zoomIndicator->setText(QString("Zoom: %1% Grid: %2\" BU: Inch").arg(Global::zoom * 100.0).arg(Global::gridSpacing));
+
+       // This is the problem...  Changing this causes the state to update itself again, screwing up the origin...  !!! FIX !!! (commented out for now)
+//     baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
+}
+
+void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
+{
+       QAction * actionList[] = {
+               addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct,
+               addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct,
+               triangulateAct, 0
+       };
+
+       for(int i=0; actionList[i]!=0; i++)
+       {
+               if (actionList[i] != exception)
+                       actionList[i]->setChecked(false);
+       }
+}
+
+void ApplicationWindow::SetInternalToolStates(void)
+{
+       // We can be sure that if we've come here, then either an active tool is
+       // being deactivated, or a new tool is being activated.  In either case,
+       // the tool state needs to be reset.  Also, we reset the crosshair
+       // suppression flag.
+       Global::toolState = TSNone;
+       Global::toolSuppressCrosshair = false;
+
+       if (addLineAct->isChecked())
+               Global::tool = TTLine;
+       else if (addCircleAct->isChecked())
+               Global::tool = TTCircle;
+       else if (addArcAct->isChecked())
+               Global::tool = TTArc;
+       else if (addDimensionAct->isChecked())
+               Global::tool = TTDimension;
+       else if (addSplineAct->isChecked())
+               Global::tool = TTSpline;
+       else if (addPolygonAct->isChecked())
+               Global::tool = TTPolygon;
+       else if (deleteAct->isChecked())
+               Global::tool = TTDelete;
+       else if (mirrorAct->isChecked())
+               Global::tool = TTMirror;
+       else if (rotateAct->isChecked())
+               Global::tool = TTRotate;
+       else if (trimAct->isChecked())
+               Global::tool = TTTrim;
+       else if (parallelAct->isChecked())
+               Global::tool = TTParallel;
+       else if (triangulateAct->isChecked())
+               Global::tool = TTTriangulate;
+       else
+               Global::tool = TTNone;
+
+       cw->SetToolPrompt();//cw->cmdline);
+       drawing->update();
+}
+
+void ApplicationWindow::HelpAbout(void)
+{
+       aboutWin->show();
+}
+
+void ApplicationWindow::Settings(void)
+{
+       SettingsDialog dlg(this);
+       dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
+
+       if (dlg.exec() == false)
+               return;
+
+       // Deal with stuff here (since user hit "OK" button...)
+       drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
+       WriteSettings();
+}
+
+//
+// Group a bunch of selected objects (which can include other groups) together
+// or ungroup a selected group.
+//
+void ApplicationWindow::HandleGrouping(void)
+{
+       int numSelected = drawing->select.size();
+
+       // If nothing selected, do nothing
+       if (numSelected == 0)
+       {
+               statusBar()->showMessage(tr("No objects selected to make a group from."));
+               return;
+       }
+
+       // If it's a group that's selected, ungroup it and leave the objects in a
+       // selected state
+       if (numSelected == 1)
+       {
+               Object * obj = (Object *)drawing->select[0];
+
+               if (obj->type != OTContainer)
+               {
+                       statusBar()->showMessage(tr("A group requires two or more selected objects."));
+                       return;
+               }
+
+               // Need the parent of the group, we're assuming here that the parent is
+               // the drawing's document. Does it matter? Maybe...
+               // Could just stipulate that grouping like this only takes place where
+               // the parent of the group is the drawing's document. Makes life much
+               // simpler.
+               Container * c = (Container *)obj;
+               SelectAll(c->objects);
+               RemoveSelectedObjects(drawing->document.objects);
+               AddObjectsTo(drawing->document.objects, c->objects);
+               drawing->select.clear();
+               AddObjectsTo(drawing->select, c->objects);
+               delete c;
+               statusBar()->showMessage(tr("Objects ungrouped."));
+//printf("Ungroup: document size = %li\n", drawing->document.objects.size());
+       }
+       // Otherwise, if it's a group of 2 or more objects (which can be groups too)
+       // group them and select the group
+       else if (numSelected > 1)
+       {
+               Container * c = new Container();
+               MoveSelectedObjectsTo(c->objects, drawing->document.objects);
+               drawing->document.objects.push_back(c);
+               ClearSelected(c->objects);
+               c->selected = true;
+               c->layer = Global::activeLayer;
+
+               Rect r = drawing->GetObjectExtents((Object *)c);
+               c->p[0] = r.TopLeft();
+               c->p[1] = r.BottomRight();
+
+               drawing->select.clear();
+               drawing->select.push_back(c);
+               statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(numSelected));
+//printf("Group: document size = %li\n", drawing->document.objects.size());
+       }
+
+       drawing->update();
+}
+
+void ApplicationWindow::HandleConnection(void)
+{
+#if 0
+//double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
+//printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
+       int itemsSelected = drawing->document.ItemsSelected();
+
+       // If nothing selected, do nothing
+       if (itemsSelected == 0)
+       {
+               statusBar()->showMessage(tr("No objects selected to connect."));
+               return;
+       }
+
+       // If one thing selected, do nothing
+       if (itemsSelected == 1)
+       {
+               statusBar()->showMessage(tr("Nothing to connect object to."));
+               return;
+       }
+
+       // This is O(n^2 / 2) :-P
+       for(int i=0; i<itemsSelected; i++)
+       {
+               Object * obj1 = drawing->document.SelectedItem(i);
+
+               for(int j=i+1; j<itemsSelected; j++)
+               {
+                       Object * obj2 = drawing->document.SelectedItem(j);
+                       double t, u, v, w;
+
+//                     if ((obj1->type != OTLine) || (obj2->type != OTLine))
+//                             continue;
+
+                       if ((obj1->type == OTLine) && (obj2->type == OTLine))
+                       {
+//printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
+                               int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
+//printf("  (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
+
+                               if (intersects)
+                               {
+       //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
+                                       obj1->Connect(obj2, u);
+                                       obj2->Connect(obj1, t);
+                               }
+                       }
+                       else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
+                               || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
+                       {
+printf("Testing Line<->Dimension intersection...\n");
+                               Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
+                               Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
+
+                               int intersects = Geometry::Intersects(line, dim, &t, &u);
+printf("   -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
+
+                               if (intersects)
+                               {
+                                       obj1->Connect(obj2, u);
+                                       obj2->Connect(obj1, t);
+                               }
+                       }
+               }
+       }
+#else
+#endif
+}
+
+void ApplicationWindow::HandleDisconnection(void)
+{
+}
+
+void ApplicationWindow::HandleGridSizeInPixels(int /*size*/)
+{
+//     drawing->SetGridSize((uint32_t)size);
+       drawing->update();
+}
+
+void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
+{
+       // Parse the text...
+       bool ok;
+       double value = text.toDouble(&ok);
+
+       // Nothing parsable to a double, so quit...
+       if (!ok || value == 0)
+               return;
+
+       Global::gridSpacing = value;
+       Global::zoom = drawing->gridPixels / Global::gridSpacing;
+       drawing->update();
+}
+
+void ApplicationWindow::HandleDimensionSize(QString text)
+{
+/*
+This is the third input on the view toolbar; not sure what it was supposed to do... (resize all dimensions in the drawing?)
+*/
+       // Parse the text...
+       bool ok;
+       double value = text.toDouble(&ok);
+
+       // Nothing parsable to a double, so quit...
+       if (!ok || value == 0)
+               return;
+
+//     drawing->document.ResizeAllDimensions(value);
+       drawing->update();
+}
+
+void ApplicationWindow::EditCopy(void)
+{
+       if (drawing->select.size() > 0)
+       {
+               DeleteContents(clipboard);
+               clipboard = CopySelectedObjects(drawing->document.objects);
+       }
+}
+
+void ApplicationWindow::EditCut(void)
+{
+       if (drawing->select.size() > 0)
+       {
+               DeleteContents(clipboard);
+               clipboard = MoveSelectedObjectsFrom(drawing->document.objects);
+               drawing->update();
+       }
+}
+
+void ApplicationWindow::EditPaste(void)
+{
+       if (clipboard.size() > 0)
+       {
+               // We want to maybe make it so that the pasted objects are being moved in a "mouse drag" state...
+               ClearSelected(drawing->document.objects);
+               SelectAll(clipboard);
+               drawing->document.Add(CopyObjects(clipboard));
+               drawing->update();
+       }
+}
+
+//
+// Select all *visible* objects.  If an object is on a layer that is not
+// visible, skip it.
+//
+void ApplicationWindow::SelectAllObjects(void)
+{
+       // Set object's state & update the drawing
+       SelectAll(drawing->document.objects);
+       drawing->update();
 }
 
 void ApplicationWindow::CreateActions(void)
@@ -90,6 +843,9 @@ void ApplicationWindow::CreateActions(void)
                QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
        connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
 
+       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);
+       connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
+
        fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
                QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
        connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
@@ -98,23 +854,115 @@ void ApplicationWindow::CreateActions(void)
                QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
        connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
 
-       deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/generic-tool.png"), QKeySequence(), true);
+       deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
        connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
 
-       addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
+       connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
+
+       addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
+       connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
+
+       addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
+       connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
+
+       addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
+       connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
+
+       addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
+       connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
+
+       addSplineAct = CreateAction(tr("Add &Spline"), tr("Add Spline"), tr("Add a NURB spline to the drawing."), QIcon(":/res/add-spline-tool.png"), QKeySequence("A,S"), true);
+       connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
+
+       aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
+
+       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);
+       connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
+
+       zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
+       connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
+
+       zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
+       connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
+
+       fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
+       connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
+
+       fileOpenAct = CreateAction(tr("&Open Drawing"), tr("Open Drawing"), tr("Opens an existing drawing from a file."), QIcon(":/res/file-open.png"), QKeySequence(tr("Ctrl+o")));
+       connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
+
+       fileSaveAct = CreateAction(tr("&Save Drawing"), tr("Save Drawing"), tr("Saves the current drawing to a file."), QIcon(":/res/file-save.png"), QKeySequence(tr("Ctrl+s")));
+       connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
+
+       fileSaveAsAct = CreateAction(tr("Save Drawing &As"), tr("Save As"), tr("Saves the current drawing to a file with a different name."), QIcon(":/res/file-save-as.png"), QKeySequence(tr("Ctrl+Shift+s")));
+       connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
+
+       fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
+
+       settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
+       connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
+
+       groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
+       connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
+
+       connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
+       connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
+
+       disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
+       connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
+
+       mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
+       connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
+
+       trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
+       connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
+
+       parallelAct = CreateAction(tr("&Parallel"), tr("Parallel"), tr("Create copies of objects parallel to the original."), QIcon(":/res/parallel-tool.png"), QKeySequence("p,l"), true);
+       connect(parallelAct, SIGNAL(triggered()), this, SLOT(ParallelTool()));
+
+       triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
+       connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
 
-       addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds a line to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       editCutAct = CreateAction(tr("&Cut Objects"), tr("Cut Objects"), tr("Cut objects from the drawing to the clipboard."), QIcon(":/res/editcut2.png"), QKeySequence(tr("Ctrl+x")));
+       connect(editCutAct, SIGNAL(triggered()), this, SLOT(EditCut()));
 
-       addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds a circle to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       editCopyAct = CreateAction(tr("&Copy Objects"), tr("Copy Objects"), tr("Copy objects from the drawing to the clipboard."), QIcon(":/res/editcopy2.png"), QKeySequence(tr("Ctrl+c")));
+       connect(editCopyAct, SIGNAL(triggered()), this, SLOT(EditCopy()));
 
-       addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds an arc to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       editPasteAct = CreateAction(tr("&Paste Objects"), tr("Paste Objects"), tr("Paste objects from the clipboard to the drawing."), QIcon(":/res/editpaste2.png"), QKeySequence(tr("Ctrl+v")));
+       connect(editPasteAct, SIGNAL(triggered()), this, SLOT(EditPaste()));
+
+       selectAllAct = CreateAction(tr("Select &All"), tr("Select All Objects"), tr("Select all objects in the drawing."), QIcon(), QKeySequence(tr("Ctrl+a")));
+       connect(selectAllAct, SIGNAL(triggered()), this, SLOT(SelectAllObjects()));
+
+       printPreviewAct = CreateAction(tr("&Print Preview"), tr("Print Preview"), tr("Shows preview of printing operation."), QIcon(":/res/print-preview.png"), QKeySequence(tr("Ctrl+p")));
+       connect(printPreviewAct, SIGNAL(triggered()), this, SLOT(PrintPreview()));
+
+//Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
+// Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
+/*     QActionGroup * group = new QActionGroup(this);
+       group->addAction(deleteAct);
+       group->addAction(addDimensionAct);
+       group->addAction(addLineAct);
+       group->addAction(addCircleAct);
+       group->addAction(addArcAct);//*/
+
+       for(int i=0; i<MRU_MAX; i++)
+       {
+               QAction * rfa = new QAction(this);
+               rfa->setVisible(false);
+               connect(rfa, SIGNAL(triggered()), this, SLOT(FileOpenRecent()));
+               mruAct.append(rfa);
+       }
 }
 
 //
 // Consolidates action creation from a multi-step process to a single-step one.
 //
-QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
-       QIcon icon, QKeySequence key, bool checkable/*= false*/)
+QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
+       QString statustip, QIcon icon, QKeySequence key, bool checkable/*= false*/)
 {
        QAction * action = new QAction(icon, name, this);
        action->setToolTip(tooltip);
@@ -129,8 +977,9 @@ QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString
 // This is essentially the same as the previous function, but this allows more
 // than one key sequence to be added as key shortcuts.
 //
-QAction * ApplicationWindow::CreateAction2(QString name, QString tooltip, QString statustip,
-       QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
+QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
+       QString statustip, QIcon icon, QKeySequence key1, QKeySequence key2,
+       bool checkable/*= false*/)
 {
        QAction * action = new QAction(icon, name, this);
        action->setToolTip(tooltip);
@@ -147,67 +996,172 @@ QAction * ApplicationWindow::CreateAction2(QString name, QString tooltip, QStrin
 void ApplicationWindow::CreateMenus(void)
 {
        QMenu * menu = menuBar()->addMenu(tr("&File"));
-//     fileMenu->addAction(newAct);
-//     fileMenu->addAction(openAct);
-//     fileMenu->addAction(saveAct);
-//     fileMenu->addAction(saveAsAct);
-//     fileMenu->addSeparator();
+       menu->addAction(fileNewAct);
+       menu->addAction(fileOpenAct);
+
+       QMenu * recentMenu = menu->addMenu(tr("Open &Recent"));
+
+       for(int i=0; i<MRU_MAX; i++)
+               recentMenu->addAction(mruAct.at(i));
+
+       UpdateMRUActionList();
+
+       menu->addAction(fileSaveAct);
+       menu->addAction(fileSaveAsAct);
+       menu->addAction(fileCloseAct);
+       menu->addSeparator();
+       menu->addAction(printPreviewAct);
+       menu->addSeparator();
        menu->addAction(exitAct);
 
+       menu = menuBar()->addMenu(tr("&View"));
+       menu->addAction(zoomInAct);
+       menu->addAction(zoomOutAct);
+
        menu = menuBar()->addMenu(tr("&Edit"));
+       menu->addAction(snapToGridAct);
+       menu->addAction(groupAct);
        menu->addAction(fixAngleAct);
        menu->addAction(fixLengthAct);
+       menu->addAction(rotateAct);
+       menu->addAction(mirrorAct);
+       menu->addAction(trimAct);
+       menu->addAction(parallelAct);
+       menu->addAction(triangulateAct);
+       menu->addAction(connectAct);
+       menu->addAction(disconnectAct);
        menu->addSeparator();
+       menu->addAction(selectAllAct);
+       menu->addAction(editCutAct);
+       menu->addAction(editCopyAct);
+       menu->addAction(editPasteAct);
        menu->addAction(deleteAct);
        menu->addSeparator();
        menu->addAction(addLineAct);
        menu->addAction(addCircleAct);
        menu->addAction(addArcAct);
+       menu->addAction(addPolygonAct);
+       menu->addAction(addSplineAct);
        menu->addAction(addDimensionAct);
+       menu->addSeparator();
+       menu->addAction(settingsAct);
 
-//     editMenu = menuBar()->addMenu(tr("&Edit"));
-//     editMenu->addAction(cutAct);
-//     editMenu->addAction(copyAct);
-//     editMenu->addAction(pasteAct);
-
-//     menuBar()->addSeparator();
-
-//     helpMenu = menuBar()->addMenu(tr("&Help"));
-//     helpMenu->addAction(aboutAct);
-//     helpMenu->addAction(aboutQtAct);
+       menu = menuBar()->addMenu(tr("&Help"));
+       menu->addAction(aboutAct);
 }
 
 void ApplicationWindow::CreateToolbars(void)
 {
        QToolBar * toolbar = addToolBar(tr("File"));
-       toolbar->addAction(exitAct);
+       toolbar->setObjectName("File"); // Needed for saveState()
+       toolbar->addAction(fileNewAct);
+       toolbar->addAction(fileOpenAct);
+       toolbar->addAction(fileSaveAct);
+       toolbar->addAction(fileSaveAsAct);
+       toolbar->addAction(fileCloseAct);
+
+       toolbar = addToolBar(tr("View"));
+       toolbar->setObjectName("View");
+       toolbar->addAction(zoomInAct);
+       toolbar->addAction(zoomOutAct);
+
+       QSpinBox * spinbox = new QSpinBox;
+       toolbar->addWidget(spinbox);
+       toolbar->addWidget(baseUnitInput);
+       toolbar->addWidget(dimensionSizeInput);
 
        toolbar = addToolBar(tr("Edit"));
+       toolbar->setObjectName("Edit");
+       toolbar->addAction(snapToGridAct);
+       toolbar->addAction(groupAct);
        toolbar->addAction(fixAngleAct);
        toolbar->addAction(fixLengthAct);
+       toolbar->addAction(rotateAct);
+       toolbar->addAction(mirrorAct);
+       toolbar->addAction(trimAct);
+       toolbar->addAction(parallelAct);
+       toolbar->addAction(triangulateAct);
+       toolbar->addAction(editCutAct);
+       toolbar->addAction(editCopyAct);
+       toolbar->addAction(editPasteAct);
        toolbar->addAction(deleteAct);
+       toolbar->addAction(connectAct);
+       toolbar->addAction(disconnectAct);
+       toolbar->addSeparator();
        toolbar->addAction(addLineAct);
        toolbar->addAction(addCircleAct);
        toolbar->addAction(addArcAct);
+       toolbar->addAction(addPolygonAct);
+       toolbar->addAction(addSplineAct);
        toolbar->addAction(addDimensionAct);
+
+       spinbox->setRange(4, 256);
+       spinbox->setValue(12);
+       baseUnitInput->setText("12");
+       connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
+       connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
+       connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
+
+       PenWidget * pw = new PenWidget();
+       toolbar = addToolBar(tr("Pen"));
+       toolbar->setObjectName(tr("Pen"));
+       toolbar->addWidget(pw);
+       connect(drawing, SIGNAL(ObjectSelected(Object *)), pw, SLOT(SetFields(Object *)));
+       connect(pw->tbStamp, SIGNAL(triggered(QAction *)), drawing, SLOT(HandlePenStamp(QAction *)));
+       connect(pw->tbDropper, SIGNAL(triggered(QAction *)), drawing, SLOT(HandlePenDropper(QAction *)));
 }
 
 void ApplicationWindow::ReadSettings(void)
 {
        QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
        QSize size = settings.value("size", QSize(400, 400)).toSize();
+       drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
+       snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
        resize(size);
        move(pos);
-//     pos = settings.value("charWndPos", QPoint(0, 0)).toPoint();
-//     size = settings.value("charWndSize", QSize(200, 200)).toSize();
-//     ((TTEdit *)qApp)->charWnd->resize(size);
-//     ((TTEdit *)qApp)->charWnd->move(pos);
+       restoreState(settings.value("windowState").toByteArray());
 }
 
 void ApplicationWindow::WriteSettings(void)
 {
        settings.setValue("pos", pos());
        settings.setValue("size", size());
-//     settings.setValue("charWndPos", ((TTEdit *)qApp)->charWnd->pos());
-//     settings.setValue("charWndSize", ((TTEdit *)qApp)->charWnd->size());
+       settings.setValue("windowState", saveState());
+       settings.setValue("useAntialiasing", drawing->useAntialiasing);
+       settings.setValue("snapToGrid", snapToGridAct->isChecked());
+}
+
+void ApplicationWindow::UpdateMRUActionList(void)
+{
+       QStringList mruFilePaths = settings.value("recentFiles").toStringList();
+
+       int mruSize = (mruFilePaths.size() <= MRU_MAX ? mruFilePaths.size() : MRU_MAX);
+
+       for(int i=0; i<mruSize; i++)
+       {
+               QString filename = QFileInfo(mruFilePaths.at(i)).fileName();
+               mruAct.at(i)->setText(filename);
+               mruAct.at(i)->setData(mruFilePaths.at(i));
+               mruAct.at(i)->setVisible(true);
+       }
+
+       for(int i=mruSize; i<MRU_MAX; i++)
+               mruAct.at(i)->setVisible(false);
+}
+
+void ApplicationWindow::AdjustMRU(const QString & filePath)
+{
+       documentName = filePath;
+       setWindowFilePath(documentName);
+
+       QStringList mruFilePaths = settings.value("recentFiles").toStringList();
+       mruFilePaths.removeAll(filePath);
+       mruFilePaths.prepend(filePath);
+
+       while (mruFilePaths.size() > MRU_MAX)
+               mruFilePaths.removeLast();
+
+       settings.setValue("recentFiles", mruFilePaths);
+
+       UpdateMRUActionList();
 }