]> Shamusworld >> Repos - architektonas/blob - src/applicationwindow.cpp
Fix incorrect object naming, keep hidden layers hidden when printing.
[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 <QPrintPreviewDialog>
32 #include "about.h"
33 #include "blockwidget.h"
34 #include "commandprocessor.h"
35 #include "consolewidget.h"
36 #include "drawingsettingsdlg.h"
37 #include "drawingview.h"
38 #include "fileio.h"
39 #include "generaltab.h"
40 #include "global.h"
41 #include "layerwidget.h"
42 #include "objectwidget.h"
43 #include "painter.h"
44 #include "penwidget.h"
45 #include "settingsdialog.h"
46 #include "structs.h"
47 #include "utils.h"
48
49 // Class variables
50 DrawingView * ApplicationWindow::drawing;
51
52 ApplicationWindow::ApplicationWindow():
53         baseUnitInput(new QLineEdit),
54         dimensionSizeInput(new QLineEdit),
55         settings("Underground Software", "Architektonas")
56 {
57         drawing = new DrawingView(this);
58         drawing->setMouseTracking(true);                // We want *all* mouse events...!
59         drawing->setFocusPolicy(Qt::StrongFocus);
60         setCentralWidget(drawing);
61
62         aboutWin = new AboutWindow(this);
63
64         setWindowIcon(QIcon(":/res/atns-icon.png"));
65 //      setWindowTitle("Architektonas");
66
67         CreateActions();
68         CreateMenus();
69         CreateToolbars();
70
71         // Create Dock widgets
72         QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
73         LayerWidget * lw = new LayerWidget;
74         dock1->setWidget(lw);
75         addDockWidget(Qt::RightDockWidgetArea, dock1);
76         QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
77         BlockWidget * bw = new BlockWidget;
78         dock2->setWidget(bw);
79         addDockWidget(Qt::RightDockWidgetArea, dock2);
80         QDockWidget * dock3 = new QDockWidget(tr("Object"), this);
81         ObjectWidget * ow = new ObjectWidget;
82         dock3->setWidget(ow);
83         addDockWidget(Qt::RightDockWidgetArea, dock3);
84         QDockWidget * dock4 = new QDockWidget(tr("Command"), this);
85         cw = new ConsoleWidget;
86         dock4->setWidget(cw);
87         addDockWidget(Qt::BottomDockWidgetArea, dock4);
88
89         // Needed for saveState()
90         dock1->setObjectName("Layers");
91         dock2->setObjectName("Blocks");
92         dock3->setObjectName("Object");
93         dock4->setObjectName("Commands");
94
95         // Create status bar
96         zoomIndicator = new QLabel("Zoom: 100% Grid: 12.0\" BU: Inch");
97         statusBar()->addPermanentWidget(zoomIndicator);
98         statusBar()->showMessage(tr("Ready"));
99
100         ReadSettings();
101         // Make sure the bottom left corner gets owned by the right side:
102         setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
103         setUnifiedTitleAndToolBarOnMac(true);
104         Global::font =  new QFont("Verdana", 15, QFont::Bold);
105
106         connect(lw, SIGNAL(LayerDeleted(int)), drawing, SLOT(DeleteCurrentLayer(int)));
107         connect(lw, SIGNAL(LayerToggled()), drawing, SLOT(HandleLayerToggle()));
108         connect(lw, SIGNAL(LayersSwapped(int, int)), drawing, SLOT(HandleLayerSwap(int, int)));
109         connect(this, SIGNAL(ReloadLayers()), lw, SLOT(Reload()));
110
111         connect(drawing, SIGNAL(ObjectHovered(Object *)), ow, SLOT(ShowInfo(Object *)));
112         connect(drawing, SIGNAL(NeedZoomUpdate()), this, SLOT(UpdateZoom()));
113
114         connect(cw->cmdProc, SIGNAL(UpdateNeeded()), this, SLOT(UpdateFromCommand()));
115 }
116
117 void ApplicationWindow::closeEvent(QCloseEvent * event)
118 {
119         WriteSettings();
120         event->accept();                // Use ignore() if can't close for some reason
121         //Do we have a memory leak here if we don't delete the font in the Object???
122 }
123
124 void ApplicationWindow::FileNew(void)
125 {
126         // Warn the user if drawing has changed and hasn't been saved...
127         if (drawing->dirty)
128         {
129                 QMessageBox msg;
130
131                 msg.setText("The document has been modified.");
132                 msg.setInformativeText("Do you want to save your changes?");
133                 msg.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
134                 msg.setDefaultButton(QMessageBox::Save);
135                 int response = msg.exec();
136
137                 switch (response)
138                 {
139                 case QMessageBox::Save:
140                         // Save was clicked
141                         FileSave();
142                         break;
143                 case QMessageBox::Discard:
144                         // Don't Save was clicked
145                         break;
146                 case QMessageBox::Cancel:
147                         // Cancel was clicked
148                         return;
149 //                      break;
150                 }
151         }
152
153         FileIO::ResetLayerVectors();
154         emit ReloadLayers();
155         DeleteContents(drawing->document.objects);
156         drawing->document.objects.clear();
157         drawing->dirty = false;
158         drawing->update();
159         documentName.clear();
160 //      setWindowTitle("Architektonas - Untitled");
161         setWindowFilePath(documentName);
162         statusBar()->showMessage(tr("New drawing is ready."));
163 }
164
165 void ApplicationWindow::FileOpen(void)
166 {
167         QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
168                 "", tr("Architektonas files (*.drawing)"));
169
170         // User cancelled open
171         if (filename.isEmpty())
172                 return;
173
174         LoadFile(filename);
175 }
176
177 void ApplicationWindow::FileOpenRecent(void)
178 {
179         QAction * action = qobject_cast<QAction *>(sender());
180
181         if (!action)
182                 return;
183
184         LoadFile(action->data().toString());
185 }
186
187 void ApplicationWindow::LoadFile(QString filename)
188 {
189         FILE * file = fopen(filename.toUtf8().data(), "r");
190
191         if (file == 0)
192         {
193                 QMessageBox msg;
194                 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
195                 msg.setIcon(QMessageBox::Critical);
196                 msg.exec();
197                 return;
198         }
199
200         Container container(true);      // Make sure it's a top level container...
201         bool successful = FileIO::LoadAtnsFile(file, &container);
202         fclose(file);
203
204         if (!successful)
205         {
206                 QMessageBox msg;
207                 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
208                 msg.setIcon(QMessageBox::Critical);
209                 msg.exec();
210                 // Make sure to delete any hanging objects in the container...
211                 DeleteContents(container.objects);
212                 return;
213         }
214
215         // Keep memory leaks from happening by getting rid of the old document
216         DeleteContents(drawing->document.objects);
217         emit ReloadLayers();
218         // We can do this because the vector is just a bunch of pointers to our
219         // Objects, and the Containers (non-empty) can be moved this way with no
220         // problem.
221         drawing->document = container;
222         drawing->dirty = false;
223         drawing->update();
224         documentName = filename;
225 //      setWindowTitle(QString("Architektonas - %1").arg(documentName));
226         AdjustMRU(filename);
227         statusBar()->showMessage(tr("Drawing loaded."));
228 }
229
230 void ApplicationWindow::FileSave(void)
231 {
232         if (documentName.isEmpty())
233                 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
234                         "", tr("Architektonas drawings (*.drawing)"));
235
236         FILE * file = fopen(documentName.toUtf8().data(), "w");
237
238         if (file == 0)
239         {
240                 QMessageBox msg;
241                 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
242                 msg.setIcon(QMessageBox::Critical);
243                 msg.exec();
244                 return;
245         }
246
247         bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
248         fclose(file);
249
250         if (!successful)
251         {
252                 QMessageBox msg;
253                 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
254                 msg.setIcon(QMessageBox::Critical);
255                 msg.exec();
256                 // In this case, we should unlink the created file, since it's not
257                 // right...
258 //              unlink(documentName.toUtf8().data());
259                 QFile::remove(documentName);
260                 return;
261         }
262
263         drawing->dirty = false;
264 //      setWindowTitle(QString("Architektonas - %1").arg(documentName));
265         AdjustMRU(documentName);
266         statusBar()->showMessage(tr("Drawing saved."));
267 }
268
269 void ApplicationWindow::FileSaveAs(void)
270 {
271         QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
272                 documentName, tr("Architektonas drawings (*.drawing)"));
273
274         if (!filename.isEmpty())
275         {
276                 documentName = filename;
277                 FileSave();
278         }
279 }
280
281 void ApplicationWindow::PrintPreview(void)
282 {
283         QPrintPreviewDialog * dlg = new QPrintPreviewDialog(this);
284
285         connect(dlg, SIGNAL(paintRequested(QPrinter *)), this, SLOT(HandlePrintRequest(QPrinter *)));
286
287         dlg->exec();
288 }
289
290 void ApplicationWindow::HandlePrintRequest(QPrinter * printer)
291 {
292         QPainter qtPainter(printer);
293         Painter painter(&qtPainter);
294
295         // Save vars for screen
296         Point originSave = Global::origin;
297         double zoomSave = Global::zoom;
298         Vector screenSizeSave = Global::screenSize;
299
300         // Adjust zoom + origin to fit the paper (or NxM pages if we have 'em)
301         Rect r = drawing->GetObjectExtents((Object *)(&(drawing->document)));
302
303         QPageLayout pageLayout = printer->pageLayout();
304         QRect pageRect = pageLayout.paintRectPixels(printer->resolution());
305
306         Global::origin = r.BottomLeft();
307         Global::screenSize.x = pageRect.width();
308         Global::screenSize.y = pageRect.height();
309
310         double xScale = (double)pageRect.width() / r.Width();
311         double yScale = (double)pageRect.height() / r.Height();
312         Global::zoom = qMin(xScale, yScale);
313
314         if (xScale < yScale)
315                 Global::origin.y -= (((double)pageRect.height() / Global::zoom) - r.Height()) / 2.0;
316         else
317                 Global::origin.x -= (((double)pageRect.width() / Global::zoom) - r.Width()) / 2.0;
318
319         // Do object rendering...
320         for(int i=0; i<Global::numLayers; i++)
321         {
322                 if (Global::layerHidden[i] == false)
323                         drawing->RenderObjects(&painter, drawing->document.objects, i);
324         }
325
326         // Restore vars
327         Global::origin = originSave;
328         Global::zoom = zoomSave;
329         Global::screenSize = screenSizeSave;
330 }
331
332 //
333 // Right-click menu
334 //
335 void ApplicationWindow::contextMenuEvent(QContextMenuEvent * event)
336 {
337         // Proof of concept, still need to code up the real thing
338         QMenu menu(this);
339
340         VPVector hovered = drawing->GetHovered();
341
342         if ((drawing->select.size() > 0) || (hovered.size() > 0))
343         {
344                 QMenu * layerMenu = menu.addMenu("To layer");
345
346                 layerAct.clear();
347
348                 for(int i=0; i<Global::numLayers; i++)
349                 {
350                         QAction * act = new QAction(QIcon(), Global::layerName[i].c_str(), this);
351                         act->setData(i);
352                         layerMenu->addAction(act);
353                         layerAct.append(act);
354                         connect(act, SIGNAL(triggered()), this, SLOT(MoveToLayer()));
355                 }
356         }
357
358         menu.addAction(mirrorAct);
359         menu.addAction(rotateAct);
360         menu.addAction(trimAct);
361         menu.exec(event->globalPos());
362 }
363
364 void ApplicationWindow::MoveToLayer(void)
365 {
366         QAction * act = qobject_cast<QAction *>(sender());
367
368         drawing->MoveSelectedToLayer(act->data().toInt());
369         drawing->update();
370 }
371
372 void ApplicationWindow::UpdateFromCommand(void)
373 {
374         cw->SetToolPrompt();
375         drawing->update();
376 }
377
378 void ApplicationWindow::SnapToGridTool(void)
379 {
380         Global::snapToGrid = snapToGridAct->isChecked();
381 }
382
383 void ApplicationWindow::FixAngle(void)
384 {
385         Global::fixedAngle = fixAngleAct->isChecked();
386 }
387
388 void ApplicationWindow::FixLength(void)
389 {
390         Global::fixedLength = fixLengthAct->isChecked();
391 }
392
393 void ApplicationWindow::DeleteTool(void)
394 {
395         // For this tool, we check first to see if anything is selected. If so, we
396         // delete those and *don't* select the delete tool.
397         if (drawing->select.size() > 0)
398         {
399                 DeleteSelectedObjects(drawing->document.objects);
400                 drawing->update();
401                 deleteAct->setChecked(false);
402                 return;
403         }
404
405         // Otherwise, toggle the state of the tool
406         ClearUIToolStatesExcept(deleteAct);
407         SetInternalToolStates();
408         Global::toolSuppressCrosshair = true;
409 }
410
411 void ApplicationWindow::DimensionTool(void)
412 {
413         ClearUIToolStatesExcept(addDimensionAct);
414         SetInternalToolStates();
415 }
416
417 void ApplicationWindow::RotateTool(void)
418 {
419         ClearUIToolStatesExcept(rotateAct);
420
421         // Do tear-down if Rotate tool has been turned off
422         if (!rotateAct->isChecked())
423                 drawing->RotateHandler(ToolCleanup, Point(0, 0));
424
425         SetInternalToolStates();
426 }
427
428 void ApplicationWindow::MirrorTool(void)
429 {
430         ClearUIToolStatesExcept(mirrorAct);
431
432         // Do tear-down if Rotate tool has been turned off
433         if (!mirrorAct->isChecked())
434                 drawing->MirrorHandler(ToolCleanup, Point(0, 0));
435
436         SetInternalToolStates();
437 }
438
439 void ApplicationWindow::TrimTool(void)
440 {
441         ClearUIToolStatesExcept(trimAct);
442         SetInternalToolStates();
443         Global::toolSuppressCrosshair = true;
444 }
445
446 void ApplicationWindow::ParallelTool(void)
447 {
448         ClearUIToolStatesExcept(parallelAct);
449         SetInternalToolStates();
450         Global::toolSuppressCrosshair = true;
451 }
452
453 void ApplicationWindow::TriangulateTool(void)
454 {
455         ClearUIToolStatesExcept(triangulateAct);
456         SetInternalToolStates();
457 }
458
459 void ApplicationWindow::AddLineTool(void)
460 {
461         ClearUIToolStatesExcept(addLineAct);
462         SetInternalToolStates();
463 }
464
465 void ApplicationWindow::AddCircleTool(void)
466 {
467         ClearUIToolStatesExcept(addCircleAct);
468         SetInternalToolStates();
469 }
470
471 void ApplicationWindow::AddArcTool(void)
472 {
473         ClearUIToolStatesExcept(addArcAct);
474         SetInternalToolStates();
475 }
476
477 void ApplicationWindow::AddPolygonTool(void)
478 {
479         ClearUIToolStatesExcept(addPolygonAct);
480         SetInternalToolStates();
481 }
482
483 void ApplicationWindow::AddSplineTool(void)
484 {
485         ClearUIToolStatesExcept(addSplineAct);
486         SetInternalToolStates();
487 }
488
489 void ApplicationWindow::ZoomInTool(void)
490 {
491         double zoomFactor = 1.20;
492         QSize size = drawing->size();
493         Vector center = Painter::QtToCartesianCoords(Vector(size.width() / 2.0, size.height() / 2.0));
494
495         Global::origin = center - ((center - Global::origin) / zoomFactor);
496         Global::zoom *= zoomFactor;
497
498         UpdateZoom();
499 }
500
501 void ApplicationWindow::ZoomOutTool(void)
502 {
503         double zoomFactor = 1.20;
504         QSize size = drawing->size();
505         Vector center = Painter::QtToCartesianCoords(Vector(size.width() / 2.0, size.height() / 2.0));
506
507         Global::origin = center + ((Global::origin - center) * zoomFactor);
508         Global::zoom /= zoomFactor;
509
510         UpdateZoom();
511 }
512
513 void ApplicationWindow::UpdateZoom(void)
514 {
515         // And now, a bunch of heuristics to select the right grid size--autogrid!
516         // :-P
517         if (Global::zoom < 0.25)
518                 Global::gridSpacing = 48.0;
519         else if (Global::zoom >= 0.25 && Global::zoom < 0.50)
520                 Global::gridSpacing = 36.0;
521         else if (Global::zoom >= 0.50 && Global::zoom < 1.00)
522                 Global::gridSpacing = 24.0;
523         else if (Global::zoom >= 1.00 && Global::zoom < 2.00)
524                 Global::gridSpacing = 12.0;
525         else if (Global::zoom >= 2.00 && Global::zoom < 4.00)
526                 Global::gridSpacing = 6.0;
527         else if (Global::zoom >= 4.00 && Global::zoom < 8.00)
528                 Global::gridSpacing = 3.0;
529         else if (Global::zoom >= 8.00 && Global::zoom < 16.00)
530                 Global::gridSpacing = 1.0;
531         else if (Global::zoom >= 16.00 && Global::zoom < 32.00)
532                 Global::gridSpacing = 0.5;
533         else if (Global::zoom >= 32.00 && Global::zoom < 64.00)
534                 Global::gridSpacing = 0.25;
535         else if (Global::zoom >= 64.00 && Global::zoom < 128.00)
536                 Global::gridSpacing = 0.125;
537         else if (Global::zoom >= 128.00 && Global::zoom < 256.00)
538                 Global::gridSpacing = 0.0625;
539         else if (Global::zoom >= 256.00 && Global::zoom < 512.00)
540                 Global::gridSpacing = 0.03125;
541         else
542                 Global::gridSpacing = 0.015625;
543
544         drawing->update();
545
546         zoomIndicator->setText(QString("Zoom: %1% Grid: %2\" BU: Inch").arg(Global::zoom * 100.0).arg(Global::gridSpacing));
547
548         // This is the problem...  Changing this causes the state to update itself again, screwing up the origin...  !!! FIX !!! (commented out for now)
549 //      baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
550 }
551
552 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
553 {
554         QAction * actionList[] = {
555                 addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct,
556                 addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct,
557                 triangulateAct, parallelAct, 0
558         };
559
560         for(int i=0; actionList[i]!=0; i++)
561         {
562                 if (actionList[i] != exception)
563                         actionList[i]->setChecked(false);
564         }
565 }
566
567 void ApplicationWindow::SetInternalToolStates(void)
568 {
569         // We can be sure that if we've come here, then either an active tool is
570         // being deactivated, or a new tool is being activated.  In either case,
571         // the tool state needs to be reset.  Also, we reset the crosshair
572         // suppression flag.
573         Global::toolState = TSNone;
574         Global::toolSuppressCrosshair = false;
575
576         if (addLineAct->isChecked())
577                 Global::tool = TTLine;
578         else if (addCircleAct->isChecked())
579                 Global::tool = TTCircle;
580         else if (addArcAct->isChecked())
581                 Global::tool = TTArc;
582         else if (addDimensionAct->isChecked())
583                 Global::tool = TTDimension;
584         else if (addSplineAct->isChecked())
585                 Global::tool = TTSpline;
586         else if (addPolygonAct->isChecked())
587                 Global::tool = TTPolygon;
588         else if (deleteAct->isChecked())
589                 Global::tool = TTDelete;
590         else if (mirrorAct->isChecked())
591                 Global::tool = TTMirror;
592         else if (rotateAct->isChecked())
593                 Global::tool = TTRotate;
594         else if (trimAct->isChecked())
595                 Global::tool = TTTrim;
596         else if (parallelAct->isChecked())
597                 Global::tool = TTParallel;
598         else if (triangulateAct->isChecked())
599                 Global::tool = TTTriangulate;
600         else
601                 Global::tool = TTNone;
602
603         cw->SetToolPrompt();
604         drawing->update();
605 }
606
607 void ApplicationWindow::HelpAbout(void)
608 {
609         aboutWin->show();
610 }
611
612 void ApplicationWindow::Settings(void)
613 {
614         SettingsDialog dlg(this);
615         dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
616
617         if (dlg.exec() == false)
618                 return;
619
620         // Deal with stuff here (since user hit "OK" button...)
621         drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
622         WriteSettings();
623 }
624
625 void ApplicationWindow::DrawingSettings(void)
626 {
627         DrawingSettingsDlg dlg(this);
628         dlg.baseUnit->setCurrentIndex(drawing->document.baseUnit);
629         dlg.unitStyle->setCurrentIndex(drawing->document.unitStyle);
630         dlg.decimalPrecision->setCurrentIndex(drawing->document.decimalPrecision);
631         dlg.fractionalPrecision->setCurrentIndex(drawing->document.fractionalPrecision);
632
633         if (dlg.exec() == false)
634                 return;
635
636         // Deal with stuff here (since user hit "OK" button...)
637         drawing->document.baseUnit = dlg.baseUnit->currentIndex();
638         drawing->document.unitStyle = dlg.unitStyle->currentIndex();
639         drawing->document.decimalPrecision= dlg.decimalPrecision->currentIndex();
640         drawing->document.fractionalPrecision = dlg.fractionalPrecision->currentIndex();
641         drawing->update();
642 }
643
644 //
645 // Group a bunch of selected objects (which can include other groups) together
646 // or ungroup a selected group.
647 //
648 void ApplicationWindow::HandleGrouping(void)
649 {
650         int numSelected = drawing->select.size();
651
652         // If nothing selected, do nothing
653         if (numSelected == 0)
654         {
655                 statusBar()->showMessage(tr("No objects selected to make a group from."));
656                 return;
657         }
658
659         // If it's a group that's selected, ungroup it and leave the objects in a
660         // selected state
661         if (numSelected == 1)
662         {
663                 Object * obj = (Object *)drawing->select[0];
664
665                 if (obj->type != OTContainer)
666                 {
667                         statusBar()->showMessage(tr("A group requires two or more selected objects."));
668                         return;
669                 }
670
671                 // Need the parent of the group, we're assuming here that the parent is
672                 // the drawing's document. Does it matter? Maybe...
673                 // Could just stipulate that grouping like this only takes place where
674                 // the parent of the group is the drawing's document. Makes life much
675                 // simpler.
676                 Container * c = (Container *)obj;
677                 SelectAll(c->objects);
678                 RemoveSelectedObjects(drawing->document.objects);
679                 AddObjectsTo(drawing->document.objects, c->objects);
680                 drawing->select.clear();
681                 AddObjectsTo(drawing->select, c->objects);
682                 delete c;
683                 statusBar()->showMessage(tr("Objects ungrouped."));
684 //printf("Ungroup: document size = %li\n", drawing->document.objects.size());
685         }
686         // Otherwise, if it's a group of 2 or more objects (which can be groups too)
687         // group them and select the group
688         else if (numSelected > 1)
689         {
690                 Container * c = new Container();
691                 MoveSelectedObjectsTo(c->objects, drawing->document.objects);
692                 drawing->document.objects.push_back(c);
693                 ClearSelected(c->objects);
694                 c->selected = true;
695                 c->layer = Global::activeLayer;
696
697                 Rect r = drawing->GetObjectExtents((Object *)c);
698                 c->p[0] = r.TopLeft();
699                 c->p[1] = r.BottomRight();
700
701                 drawing->select.clear();
702                 drawing->select.push_back(c);
703                 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(numSelected));
704 //printf("Group: document size = %li\n", drawing->document.objects.size());
705         }
706
707         drawing->update();
708 }
709
710 void ApplicationWindow::HandleConnection(void)
711 {
712 #if 0
713 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
714 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
715         int itemsSelected = drawing->document.ItemsSelected();
716
717         // If nothing selected, do nothing
718         if (itemsSelected == 0)
719         {
720                 statusBar()->showMessage(tr("No objects selected to connect."));
721                 return;
722         }
723
724         // If one thing selected, do nothing
725         if (itemsSelected == 1)
726         {
727                 statusBar()->showMessage(tr("Nothing to connect object to."));
728                 return;
729         }
730
731         // This is O(n^2 / 2) :-P
732         for(int i=0; i<itemsSelected; i++)
733         {
734                 Object * obj1 = drawing->document.SelectedItem(i);
735
736                 for(int j=i+1; j<itemsSelected; j++)
737                 {
738                         Object * obj2 = drawing->document.SelectedItem(j);
739                         double t, u, v, w;
740
741 //                      if ((obj1->type != OTLine) || (obj2->type != OTLine))
742 //                              continue;
743
744                         if ((obj1->type == OTLine) && (obj2->type == OTLine))
745                         {
746 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
747                                 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
748 //printf("  (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
749
750                                 if (intersects)
751                                 {
752         //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
753                                         obj1->Connect(obj2, u);
754                                         obj2->Connect(obj1, t);
755                                 }
756                         }
757                         else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
758                                 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
759                         {
760 printf("Testing Line<->Dimension intersection...\n");
761                                 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
762                                 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
763
764                                 int intersects = Geometry::Intersects(line, dim, &t, &u);
765 printf("   -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
766
767                                 if (intersects)
768                                 {
769                                         obj1->Connect(obj2, u);
770                                         obj2->Connect(obj1, t);
771                                 }
772                         }
773                 }
774         }
775 #else
776 #endif
777 }
778
779 void ApplicationWindow::HandleDisconnection(void)
780 {
781 }
782
783 void ApplicationWindow::HandleGridSizeInPixels(int /*size*/)
784 {
785 //      drawing->SetGridSize((uint32_t)size);
786         drawing->update();
787 }
788
789 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
790 {
791         // Parse the text...
792         bool ok;
793         double value = text.toDouble(&ok);
794
795         // Nothing parsable to a double, so quit...
796         if (!ok || value == 0)
797                 return;
798
799         Global::gridSpacing = value;
800         Global::zoom = drawing->gridPixels / Global::gridSpacing;
801         drawing->update();
802 }
803
804 void ApplicationWindow::HandleDimensionSize(QString text)
805 {
806 /*
807 This is the third input on the view toolbar; not sure what it was supposed to do... (resize all dimensions in the drawing?)
808 */
809         // Parse the text...
810         bool ok;
811         double value = text.toDouble(&ok);
812
813         // Nothing parsable to a double, so quit...
814         if (!ok || value == 0)
815                 return;
816
817 //      drawing->document.ResizeAllDimensions(value);
818         drawing->update();
819 }
820
821 void ApplicationWindow::EditCopy(void)
822 {
823         if (drawing->select.size() > 0)
824         {
825                 DeleteContents(clipboard);
826                 clipboard = CopySelectedObjects(drawing->document.objects);
827         }
828 }
829
830 void ApplicationWindow::EditCut(void)
831 {
832         if (drawing->select.size() > 0)
833         {
834                 DeleteContents(clipboard);
835                 clipboard = MoveSelectedObjectsFrom(drawing->document.objects);
836                 drawing->update();
837         }
838 }
839
840 void ApplicationWindow::EditPaste(void)
841 {
842         if (clipboard.size() > 0)
843         {
844                 // We want to maybe make it so that the pasted objects are being moved in a "mouse drag" state...
845                 ClearSelected(drawing->document.objects);
846                 SelectAll(clipboard);
847                 drawing->document.Add(CopyObjects(clipboard));
848                 drawing->update();
849         }
850 }
851
852 //
853 // Select all *visible* objects.  If an object is on a layer that is not
854 // visible, skip it.
855 //
856 void ApplicationWindow::SelectAllObjects(void)
857 {
858         // Set object's state & update the drawing
859         SelectAll(drawing->document.objects);
860         drawing->update();
861 }
862
863 void ApplicationWindow::CreateActions(void)
864 {
865         exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
866                 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
867         connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
868
869         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);
870         connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
871
872         fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
873                 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
874         connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
875
876         fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
877                 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
878         connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
879
880         deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
881         connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
882
883         addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
884         connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
885
886         addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
887         connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
888
889         addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
890         connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
891
892         addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
893         connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
894
895         addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
896         connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
897
898         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);
899         connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
900
901         aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
902         connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
903
904         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);
905         connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
906
907         zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
908         connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
909
910         zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
911         connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
912
913         fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
914         connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
915
916         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")));
917         connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
918
919         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")));
920         connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
921
922         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")));
923         connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
924
925         fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
926
927         settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
928         connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
929
930         drawingSettingsAct = CreateAction(tr("&Drawing Settings"), tr("Drawing settings"), tr("Change certain defaults for the current drawing."), QIcon(":/res/settings.png"), QKeySequence());
931         connect(drawingSettingsAct, SIGNAL(triggered()), this, SLOT(DrawingSettings()));
932
933         groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
934         connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
935
936         connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
937         connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
938
939         disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
940         connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
941
942         mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
943         connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
944
945         trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
946         connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
947
948         parallelAct = CreateAction(tr("&Parallel"), tr("Parallel"), tr("Create copies of objects parallel to the original."), QIcon(":/res/parallel-tool.png"), QKeySequence("p,l"), true);
949         connect(parallelAct, SIGNAL(triggered()), this, SLOT(ParallelTool()));
950
951         triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
952         connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
953
954         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")));
955         connect(editCutAct, SIGNAL(triggered()), this, SLOT(EditCut()));
956
957         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")));
958         connect(editCopyAct, SIGNAL(triggered()), this, SLOT(EditCopy()));
959
960         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")));
961         connect(editPasteAct, SIGNAL(triggered()), this, SLOT(EditPaste()));
962
963         selectAllAct = CreateAction(tr("Select &All"), tr("Select All Objects"), tr("Select all objects in the drawing."), QIcon(), QKeySequence(tr("Ctrl+a")));
964         connect(selectAllAct, SIGNAL(triggered()), this, SLOT(SelectAllObjects()));
965
966         printPreviewAct = CreateAction(tr("&Print Preview"), tr("Print Preview"), tr("Shows preview of printing operation."), QIcon(":/res/print-preview.png"), QKeySequence(tr("Ctrl+p")));
967         connect(printPreviewAct, SIGNAL(triggered()), this, SLOT(PrintPreview()));
968
969 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
970 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
971 /*      QActionGroup * group = new QActionGroup(this);
972         group->addAction(deleteAct);
973         group->addAction(addDimensionAct);
974         group->addAction(addLineAct);
975         group->addAction(addCircleAct);
976         group->addAction(addArcAct);//*/
977
978         for(int i=0; i<MRU_MAX; i++)
979         {
980                 QAction * rfa = new QAction(this);
981                 rfa->setVisible(false);
982                 connect(rfa, SIGNAL(triggered()), this, SLOT(FileOpenRecent()));
983                 mruAct.append(rfa);
984         }
985 }
986
987 //
988 // Consolidates action creation from a multi-step process to a single-step one.
989 //
990 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
991         QString statustip, QIcon icon, QKeySequence key, bool checkable/*= false*/)
992 {
993         QAction * action = new QAction(icon, name, this);
994         action->setToolTip(tooltip);
995         action->setStatusTip(statustip);
996         action->setShortcut(key);
997         action->setCheckable(checkable);
998
999         return action;
1000 }
1001
1002 //
1003 // This is essentially the same as the previous function, but this allows more
1004 // than one key sequence to be added as key shortcuts.
1005 //
1006 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
1007         QString statustip, QIcon icon, QKeySequence key1, QKeySequence key2,
1008         bool checkable/*= false*/)
1009 {
1010         QAction * action = new QAction(icon, name, this);
1011         action->setToolTip(tooltip);
1012         action->setStatusTip(statustip);
1013         QList<QKeySequence> keyList;
1014         keyList.append(key1);
1015         keyList.append(key2);
1016         action->setShortcuts(keyList);
1017         action->setCheckable(checkable);
1018
1019         return action;
1020 }
1021
1022 void ApplicationWindow::CreateMenus(void)
1023 {
1024         QMenu * menu = menuBar()->addMenu(tr("&File"));
1025         menu->addAction(fileNewAct);
1026         menu->addAction(fileOpenAct);
1027
1028         QMenu * recentMenu = menu->addMenu(tr("Open &Recent"));
1029
1030         for(int i=0; i<MRU_MAX; i++)
1031                 recentMenu->addAction(mruAct.at(i));
1032
1033         UpdateMRUActionList();
1034
1035         menu->addAction(fileSaveAct);
1036         menu->addAction(fileSaveAsAct);
1037         menu->addAction(fileCloseAct);
1038         menu->addSeparator();
1039         menu->addAction(printPreviewAct);
1040         menu->addSeparator();
1041         menu->addAction(exitAct);
1042
1043         menu = menuBar()->addMenu(tr("&View"));
1044         menu->addAction(zoomInAct);
1045         menu->addAction(zoomOutAct);
1046
1047         menu = menuBar()->addMenu(tr("&Edit"));
1048         menu->addAction(snapToGridAct);
1049         menu->addAction(groupAct);
1050         menu->addAction(fixAngleAct);
1051         menu->addAction(fixLengthAct);
1052         menu->addAction(rotateAct);
1053         menu->addAction(mirrorAct);
1054         menu->addAction(trimAct);
1055         menu->addAction(parallelAct);
1056         menu->addAction(triangulateAct);
1057         menu->addAction(connectAct);
1058         menu->addAction(disconnectAct);
1059         menu->addSeparator();
1060         menu->addAction(selectAllAct);
1061         menu->addAction(editCutAct);
1062         menu->addAction(editCopyAct);
1063         menu->addAction(editPasteAct);
1064         menu->addAction(deleteAct);
1065         menu->addSeparator();
1066         menu->addAction(addLineAct);
1067         menu->addAction(addCircleAct);
1068         menu->addAction(addArcAct);
1069         menu->addAction(addPolygonAct);
1070         menu->addAction(addSplineAct);
1071         menu->addAction(addDimensionAct);
1072         menu->addSeparator();
1073         menu->addAction(drawingSettingsAct);
1074         menu->addAction(settingsAct);
1075
1076         menu = menuBar()->addMenu(tr("&Help"));
1077         menu->addAction(aboutAct);
1078 }
1079
1080 void ApplicationWindow::CreateToolbars(void)
1081 {
1082         QToolBar * toolbar = addToolBar(tr("File"));
1083         toolbar->setObjectName("File"); // Needed for saveState()
1084         toolbar->addAction(fileNewAct);
1085         toolbar->addAction(fileOpenAct);
1086         toolbar->addAction(fileSaveAct);
1087         toolbar->addAction(fileSaveAsAct);
1088         toolbar->addAction(fileCloseAct);
1089
1090         toolbar = addToolBar(tr("View"));
1091         toolbar->setObjectName("View");
1092         toolbar->addAction(zoomInAct);
1093         toolbar->addAction(zoomOutAct);
1094
1095         QSpinBox * spinbox = new QSpinBox;
1096         toolbar->addWidget(spinbox);
1097         toolbar->addWidget(baseUnitInput);
1098         toolbar->addWidget(dimensionSizeInput);
1099
1100         toolbar = addToolBar(tr("Edit"));
1101         toolbar->setObjectName("Edit");
1102         toolbar->addAction(snapToGridAct);
1103         toolbar->addAction(groupAct);
1104         toolbar->addAction(fixAngleAct);
1105         toolbar->addAction(fixLengthAct);
1106         toolbar->addAction(rotateAct);
1107         toolbar->addAction(mirrorAct);
1108         toolbar->addAction(trimAct);
1109         toolbar->addAction(parallelAct);
1110         toolbar->addAction(triangulateAct);
1111         toolbar->addAction(editCutAct);
1112         toolbar->addAction(editCopyAct);
1113         toolbar->addAction(editPasteAct);
1114         toolbar->addAction(deleteAct);
1115         toolbar->addAction(connectAct);
1116         toolbar->addAction(disconnectAct);
1117         toolbar->addSeparator();
1118         toolbar->addAction(addLineAct);
1119         toolbar->addAction(addCircleAct);
1120         toolbar->addAction(addArcAct);
1121         toolbar->addAction(addPolygonAct);
1122         toolbar->addAction(addSplineAct);
1123         toolbar->addAction(addDimensionAct);
1124
1125         spinbox->setRange(4, 256);
1126         spinbox->setValue(12);
1127         baseUnitInput->setText("12");
1128         connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
1129         connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
1130         connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
1131
1132         PenWidget * pw = new PenWidget();
1133         toolbar = addToolBar(tr("Pen"));
1134         toolbar->setObjectName(tr("Pen"));
1135         toolbar->addWidget(pw);
1136         connect(drawing, SIGNAL(ObjectSelected(Object *)), pw, SLOT(SetFields(Object *)));
1137         connect(pw->tbStamp, SIGNAL(triggered(QAction *)), drawing, SLOT(HandlePenStamp(QAction *)));
1138         connect(pw->tbDropper, SIGNAL(triggered(QAction *)), drawing, SLOT(HandlePenDropper(QAction *)));
1139 }
1140
1141 void ApplicationWindow::ReadSettings(void)
1142 {
1143         QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
1144         QSize size = settings.value("size", QSize(400, 400)).toSize();
1145         drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
1146         Global::snapToGrid = settings.value("snapToGrid", true).toBool();
1147         snapToGridAct->setChecked(Global::snapToGrid);
1148         resize(size);
1149         move(pos);
1150         restoreState(settings.value("windowState").toByteArray());
1151 }
1152
1153 void ApplicationWindow::WriteSettings(void)
1154 {
1155         settings.setValue("pos", pos());
1156         settings.setValue("size", size());
1157         settings.setValue("windowState", saveState());
1158         settings.setValue("useAntialiasing", drawing->useAntialiasing);
1159         settings.setValue("snapToGrid", snapToGridAct->isChecked());
1160 }
1161
1162 void ApplicationWindow::UpdateMRUActionList(void)
1163 {
1164         QStringList mruFilePaths = settings.value("recentFiles").toStringList();
1165
1166         int mruSize = (mruFilePaths.size() <= MRU_MAX ? mruFilePaths.size() : MRU_MAX);
1167
1168         for(int i=0; i<mruSize; i++)
1169         {
1170                 QString filename = QFileInfo(mruFilePaths.at(i)).fileName();
1171                 mruAct.at(i)->setText(filename);
1172                 mruAct.at(i)->setData(mruFilePaths.at(i));
1173                 mruAct.at(i)->setVisible(true);
1174         }
1175
1176         for(int i=mruSize; i<MRU_MAX; i++)
1177                 mruAct.at(i)->setVisible(false);
1178 }
1179
1180 void ApplicationWindow::AdjustMRU(const QString & filePath)
1181 {
1182         documentName = filePath;
1183         setWindowFilePath(documentName);
1184
1185         QStringList mruFilePaths = settings.value("recentFiles").toStringList();
1186         mruFilePaths.removeAll(filePath);
1187         mruFilePaths.prepend(filePath);
1188
1189         while (mruFilePaths.size() > MRU_MAX)
1190                 mruFilePaths.removeLast();
1191
1192         settings.setValue("recentFiles", mruFilePaths);
1193
1194         UpdateMRUActionList();
1195 }