1 #include "Global.h"
2 #include "MainWindow.h"
3
4 #include "LayerDock.h"
5 #include "MapView.h"
6 #include "PropertiesDock.h"
7 #include "InfoDock.h"
8 #include "DirtyDock.h"
9 #include "StyleDock.h"
10 #include "FeaturesDock.h"
11 #include "Command.h"
12 #include "DocumentCommands.h"
13 #include "FeatureCommands.h"
14 #include "RelationCommands.h"
15 #include "ImportExportOSC.h"
16 #include "ExportGPX.h"
17 #include "ImportExportKML.h"
18 #ifdef USE_PROTOBUF
19 #include "ImportExportPBF.h"
20 #endif
21 #include "ImportExportGdal.h"
22 #include "CreateAreaInteraction.h"
23 #include "CreateDoubleWayInteraction.h"
24 #include "CreateNodeInteraction.h"
25 #include "BuildBridgeInteraction.h"
26 #include "CreateRoundaboutInteraction.h"
27 #include "CreatePolygonInteraction.h"
28 #include "CreateSingleWayInteraction.h"
29 #include "EditInteraction.h"
30 #include "MoveNodeInteraction.h"
31 #include "RotateInteraction.h"
32 #include "ScaleInteraction.h"
33 #include "ZoomInteraction.h"
34 #include "ExtrudeInteraction.h"
35 #include "Coord.h"
36 #include "DownloadOSM.h"
37 #include "ImportGPX.h"
38 #include "ImportNGT.h"
39 #include "ImportOSM.h"
40 #include "Document.h"
41 #include "Layer.h"
42 #include "ImageMapLayer.h"
43 #include "Features.h"
44 #include "FeatureManipulations.h"
45 #include "LayerIterator.h"
46 #include "MasPaintStyle.h"
47 #include "MapCSSPaintstyle.h"
48 #include "PaintStyleEditor.h"
49 #include "Utils/Utils.h"
50 #include "DirtyList.h"
51 #include "DirtyListExecutorOSC.h"
52 #include "RemoteControlServer.hpp"
53
54 #include <ui_MainWindow.h>
55 #include <ui_AboutDialog.h>
56 #include <ui_UploadMapDialog.h>
57 #include <ui_SelectionDialog.h>
58 #include <ui_ExportDialog.h>
59 #include <ui_PropertiesDialog.h>
60
61 #include "Preferences/PreferencesDialog.h"
62 #include "Preferences/MerkaartorPreferences.h"
63 #include "Preferences/ProjectionsList.h"
64 #include "Preferences/WMSPreferencesDialog.h"
65 #include "Preferences/TMSPreferencesDialog.h"
66 #include "Preferences/ProjPreferencesDialog.h"
67 #include "Preferences/FilterPreferencesDialog.h"
68 #include "Utils/SelectionDialog.h"
69 #include "Utils/MDiscardableDialog.h"
70 #include "QMapControl/imagemanager.h"
71 #ifdef USE_WEBKIT
72 #include "QMapControl/browserimagemanager.h"
73 #endif
74 #include "QMapControl/mapadapter.h"
75 #include "QMapControl/wmsmapadapter.h"
76 #include "Tools/ActionsDialog.h"
77 #include "GotoDialog.h"
78 #include "TerraceDialog.h"
79
80 #ifdef GEOIMAGE
81 #include "GeoImageDock.h"
82 #endif
83
84 #include "Render/NativeRenderDialog.h"
85
86 #include "qgps.h"
87 #include "qgpsdevice.h"
88
89 #include <QtCore>
90 #include <QtGui>
91 #include <QTcpServer>
92 #include <QTcpSocket>
93 #include <QXmlStreamReader>
94 #include <QStyleFactory>
95 #include <QMessageBox>
96 #include <QFileDialog>
97 #include <QInputDialog>
98 #include <QToolTip>
99
100 #include "qttoolbardialog.h"
101
102 #include <locale.h>
103 #include <limits.h>
104
105 #include "proj.h"
106 #include "gdal_version.h"
107
108 #include "Utils/SlippyMapWidget.h"
109
110 namespace {
111
112 const QString MIME_OPENSTREETMAP_XML = "application/x-openstreetmap+xml";
113 const QString MIME_GOOGLE_EARTH_KML = "application/vnd.google-earth.kml+xml";
114 const QString MIME_GPX = "application/gpx+xml";
115 const QString MIME_MERKAARTOR_UNDO_XML = "application/x-merkaartor-undo+xml";
116
117 } // namespace
118
119 using namespace Merkaartor;
120
121 class MainWindowPrivate
122 {
123 public:
MainWindowPrivate()124 MainWindowPrivate()
125 : lastPrefTabIndex(0)
126 , projActgrp(0)
127 , theListeningServer(0)
128 , latSaveDirtyLevel(0)
129 #ifdef GEOIMAGE
130 , dropTarget(0)
131 #endif
132 , numImages(0)
133 {
134 title = QString("%1 v%2").arg(STRINGIFY(PRODUCT)).arg(STRINGIFY(REVISION));
135 }
136
137 QString FILTER_OPEN_NATIVE;
138 QString FILTER_OPEN_SUPPORTED;
139 QString FILTER_IMPORT_SUPPORTED;
140 int lastPrefTabIndex;
141 QString defStyle;
142 StyleDock* theStyle;
143 FeaturesDock* theFeats;
144 QString title;
145 QActionGroup* projActgrp;
146 RemoteControlServer* theListeningServer;
147 PropertiesDock* theProperties;
148 RendererOptions renderOptions;
149 int latSaveDirtyLevel;
150 #ifdef GEOIMAGE
151 Node *dropTarget;
152 #endif
153 int numImages;
154 };
155
156 namespace {
157
SetOptionValue(RendererOptions & options,RendererOptions::RenderOption option,bool on)158 void SetOptionValue(RendererOptions& options,
159 RendererOptions::RenderOption option, bool on) {
160 if (on) {
161 options.options |= option;
162 } else {
163 options.options &= ~option;
164 }
165 }
166
167 } // namespace
168
MainWindow(QWidget * parent)169 MainWindow::MainWindow(QWidget *parent)
170 : QMainWindow(parent)
171 , ui(new Ui::MainWindow)
172 , theDocument(0)
173 , gpsRecLayer(0)
174 , curGpsTrackSegment(0)
175 , qtTranslator(0)
176 , merkaartorTranslator(0)
177 , toolBarManager(0)
178 {
179 setlocale(LC_NUMERIC, "C"); // impose decimal point separator
180 qsrand(QDateTime::currentDateTime().toTime_t()); //initialize random generator
181
182 p = new MainWindowPrivate;
183
184 QString supported_import_formats("*.gpx *.osm *.osc *.ngt *.nmea *.nma *.kml *.csv");
185 #ifdef GEOIMAGE
186 supported_import_formats += " *.jpg";
187 #endif
188 supported_import_formats += " *.shp *.gml";
189 #ifdef USE_PROTOBUF
190 supported_import_formats += " *.pbf";
191 #endif
192 QString supported_import_formats_desc =
193 tr("GPS Exchange format (*.gpx)\n") \
194 +tr("OpenStreetMap format (*.osm)\n") \
195 +tr("OpenStreetMap change format (*.osc)\n") \
196 +tr("Noni GPSPlot format (*.ngt)\n") \
197 +tr("NMEA GPS log format (*.nmea *.nma)\n") \
198 +tr("KML file (*.kml)\n") \
199 +tr("Comma delimited format (*.csv)\n");
200
201 #ifdef GEOIMAGE
202 supported_import_formats_desc += tr("Geotagged images (*.jpg)\n");
203 #endif
204 supported_import_formats_desc += tr("ESRI Shapefile (*.shp)\n") + tr("Geography Markup Language (*.gml)\n");
205 #ifdef USE_PROTOBUF
206 supported_import_formats_desc += tr("Protobuf Binary Format (*.pbf)\n");
207 #endif
208
209 p->FILTER_OPEN_NATIVE = tr("Merkaartor document (*.mdc)\n");
210
211 p->FILTER_OPEN_SUPPORTED = QString(tr("Supported formats") + " (*.mdc %1)\n").arg(supported_import_formats);
212 p->FILTER_OPEN_SUPPORTED += tr("Merkaartor document (*.mdc)\n") + supported_import_formats_desc;
213 p->FILTER_OPEN_SUPPORTED += tr("All Files (*)");
214
215 p->FILTER_IMPORT_SUPPORTED = QString(tr("Supported formats") + " (%1)\n").arg(supported_import_formats);
216 p->FILTER_IMPORT_SUPPORTED += supported_import_formats_desc;
217 p->FILTER_IMPORT_SUPPORTED += tr("All Files (*)");
218
219 theProgressDialog = NULL;
220 theProgressBar = NULL;
221 theProgressLabel = NULL;
222
223 if (M_PREFS->getMerkaartorStyle())
224 QApplication::setStyle(QStyleFactory::create(M_PREFS->getMerkaartorStyleString()));
225
226 ui->setupUi(this);
227 M_STYLE->loadPainters(M_PREFS->getDefaultStyle());
228
229 blockSignals(true);
230
231 ViewportStatusLabel = new QLabel(this);
232 MeterPerPixelLabel = new QLabel(this);
233 AdjusmentMeterLabel = new QLabel(this);
234
235 pbImages = new QProgressBar(this);
236 statusBar()->addPermanentWidget(ViewportStatusLabel);
237 statusBar()->addPermanentWidget(pbImages);
238 statusBar()->addPermanentWidget(MeterPerPixelLabel);
239 statusBar()->addPermanentWidget(AdjusmentMeterLabel);
240 #ifndef NDEBUG
241 PaintTimeLabel = new QLabel(this);
242 PaintTimeLabel->setMinimumWidth(23);
243 statusBar()->addPermanentWidget(PaintTimeLabel);
244 #endif
245
246 updateLanguage();
247
248 ViewportStatusLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
249 pbImages->setMaximumWidth(200);
250 pbImages->setFormat(tr("tile %v / %m"));
251 #ifdef _MOBILE
252 pbImages->setVisible(false);
253 #endif
254
255 SlippyMapWidget::theSlippyCache = new SlippyMapCache;
256
257 theView = new MapView(this);
258 setCentralWidget(theView);
259
260 theInfo = new InfoDock(this);
261 connect(theInfo, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWindowMenu(bool)));
262
263 theLayers = new LayerDock(this);
264 connect(theLayers, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWindowMenu(bool)));
265
266 p->theProperties = new PropertiesDock(this);
267 connect(p->theProperties, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWindowMenu(bool)));
268 on_editPropertiesAction_triggered();
269
270 theDirty = new DirtyDock(this);
271 connect(theDirty, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWindowMenu(bool)));
272
273 p->theStyle = new StyleDock(this);
274 connect(p->theStyle, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWindowMenu(bool)));
275
276 p->theFeats = new FeaturesDock(this);
277 connect(p->theFeats, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWindowMenu(bool)));
278 connect(theView, SIGNAL(viewportChanged()), p->theFeats, SLOT(on_Viewport_changed()), Qt::QueuedConnection);
279 connect(this, SIGNAL(content_changed()), p->theFeats, SLOT(on_Viewport_changed()), Qt::QueuedConnection);
280 connect(this, SIGNAL(content_changed()), p->theProperties, SLOT(adjustSelection()), Qt::QueuedConnection);
281
282 theGPS = new QGPS(this);
283 connect(theGPS, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWindowMenu(bool)));
284
285 #ifdef GEOIMAGE
286 theGeoImage = new GeoImageDock(this);
287 theGeoImage->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
288 addDockWidget(Qt::RightDockWidgetArea, theGeoImage);
289 connect(theGeoImage, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWindowMenu(bool)));
290 #endif
291
292 connect(theLayers, SIGNAL(layersChanged(bool)), this, SLOT(adjustLayers(bool)));
293 connect(theLayers, SIGNAL(layersCleared()), this, SIGNAL(content_changed()));
294 connect(theLayers, SIGNAL(layersClosed()), this, SIGNAL(content_changed()));
295 connect(theLayers, SIGNAL(layersProjection(const QString&)), this, SLOT(projectionSet(const QString&)));
296
297 connect (M_PREFS, SIGNAL(bookmarkChanged()), this, SLOT(updateBookmarksMenu()));
298 updateBookmarksMenu();
299 connect (ui->menuBookmarks, SIGNAL(triggered(QAction *)), this, SLOT(bookmarkTriggered(QAction *)));
300
301 updateRecentOpenMenu();
302 connect (ui->menuRecentOpen, SIGNAL(triggered(QAction *)), this, SLOT(recentOpenTriggered(QAction *)));
303
304 updateRecentImportMenu();
305 connect (ui->menuRecentImport, SIGNAL(triggered(QAction *)), this, SLOT(recentImportTriggered(QAction *)));
306
307 updateStyleMenu();
308 connect (ui->menuStyles, SIGNAL(triggered(QAction *)), this, SLOT(styleTriggered(QAction *)));
309
310 ui->viewDownloadedAction->setChecked(M_PREFS->getDownloadedVisible());
311 ui->viewDirtyAction->setChecked(M_PREFS->getDirtyVisible());
312 ui->viewScaleAction->setChecked(M_PREFS->getScaleVisible());
313 ui->viewPhotosAction->setChecked(M_PREFS->getPhotosVisible());
314 ui->viewShowLatLonGridAction->setChecked(M_PREFS->getLatLonGridVisible());
315 ui->viewStyleBackgroundAction->setChecked(M_PREFS->getBackgroundVisible());
316 ui->viewStyleForegroundAction->setChecked(M_PREFS->getForegroundVisible());
317 ui->viewStyleTouchupAction->setChecked(M_PREFS->getTouchupVisible());
318 ui->viewNamesAction->setChecked(M_PREFS->getNamesVisible());
319 ui->viewTrackPointsAction->setChecked(M_PREFS->getTrackPointsVisible());
320 ui->viewTrackSegmentsAction->setChecked(M_PREFS->getTrackSegmentsVisible());
321 ui->viewRelationsAction->setChecked(M_PREFS->getRelationsVisible());
322 ui->viewVirtualNodesAction->setChecked(M_PREFS->getVirtualNodesVisible());
323 ui->viewLockZoomAction->setChecked(M_PREFS->getZoomBoris());
324 ui->viewWireframeAction->setChecked(M_PREFS->getWireframeView());
325
326 SetOptionValue(p->renderOptions, RendererOptions::BackgroundVisible, M_PREFS->getBackgroundVisible());
327 SetOptionValue(p->renderOptions, RendererOptions::ForegroundVisible, M_PREFS->getForegroundVisible());
328 SetOptionValue(p->renderOptions, RendererOptions::TouchupVisible, M_PREFS->getTouchupVisible());
329 SetOptionValue(p->renderOptions, RendererOptions::NamesVisible, M_PREFS->getNamesVisible());
330 SetOptionValue(p->renderOptions, RendererOptions::PhotosVisible, M_PREFS->getPhotosVisible());
331 SetOptionValue(p->renderOptions, RendererOptions::VirtualNodesVisible, M_PREFS->getVirtualNodesVisible());
332 SetOptionValue(p->renderOptions, RendererOptions::NodesVisible, M_PREFS->getTrackPointsVisible());
333 SetOptionValue(p->renderOptions, RendererOptions::TrackSegmentVisible, M_PREFS->getTrackSegmentsVisible());
334 SetOptionValue(p->renderOptions, RendererOptions::RelationsVisible, M_PREFS->getRelationsVisible());
335 SetOptionValue(p->renderOptions, RendererOptions::DownloadedVisible, M_PREFS->getDownloadedVisible());
336 SetOptionValue(p->renderOptions, RendererOptions::ScaleVisible, M_PREFS->getScaleVisible());
337 SetOptionValue(p->renderOptions, RendererOptions::LatLonGridVisible, M_PREFS->getLatLonGridVisible());
338 SetOptionValue(p->renderOptions, RendererOptions::LockZoom, M_PREFS->getZoomBoris());
339
340 updateMenu();
341
342 QActionGroup* actgrpArrows = new QActionGroup(this);
343 actgrpArrows->addAction(ui->viewArrowsNeverAction);
344 actgrpArrows->addAction(ui->viewArrowsOnewayAction);
345 actgrpArrows->addAction(ui->viewArrowsAlwaysAction);
346 switch (M_PREFS->getDirectionalArrowsVisible()) {
347 case RendererOptions::ArrowsNever:
348 ui->viewArrowsNeverAction->setChecked(true);
349 p->renderOptions.arrowOptions = RendererOptions::ArrowsNever;
350 break;
351 case RendererOptions::ArrowsOneway:
352 ui->viewArrowsOnewayAction->setChecked(true);
353 p->renderOptions.arrowOptions = RendererOptions::ArrowsOneway;
354 break;
355 case RendererOptions::ArrowsAlways:
356 ui->viewArrowsAlwaysAction->setChecked(true);
357 p->renderOptions.arrowOptions = RendererOptions::ArrowsAlways;
358 break;
359 }
360
361 theView->setRenderOptions(p->renderOptions);
362
363 ui->gpsCenterAction->setChecked(M_PREFS->getGpsMapCenter());
364
365 connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardChanged()));
366
367 #ifndef _MOBILE
368 theLayers->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
369 addDockWidget(Qt::LeftDockWidgetArea, theLayers);
370
371 p->theProperties->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
372 addDockWidget(Qt::LeftDockWidgetArea, p->theProperties);
373
374 theInfo->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
375 addDockWidget(Qt::RightDockWidgetArea, theInfo);
376
377 theDirty->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
378 addDockWidget(Qt::RightDockWidgetArea, theDirty);
379
380 p->theStyle->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
381 addDockWidget(Qt::RightDockWidgetArea, p->theStyle);
382
383 p->theFeats->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
384 addDockWidget(Qt::RightDockWidgetArea, p->theFeats);
385
386 theGPS->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
387 addDockWidget(Qt::RightDockWidgetArea, theGPS);
388
389 #else
390 p->theProperties->setVisible(false);
391 theInfo->setVisible(false);
392 theLayers->setVisible(false);
393 theDirty->setVisible(false);
394 theFeats->setVisible(false);
395 theGPS->setVisible(false);
396
397 toolBar->setVisible(false);
398 mobileToolBar->setVisible(true);
399
400 gpsPopupAction->setMenu(menuGps);
401 dynamic_cast<QToolButton*>(mobileToolBar->widgetForAction(gpsPopupAction))->setPopupMode(QToolButton::InstantPopup);
402
403 #ifdef _WINCE
404 windowPropertiesAction->setText(tr("Properties..."));
405 menuBar()->setDefaultAction(windowPropertiesAction);
406 #endif // _WINCE
407 #endif // _MOBILE
408
409 #ifndef OSMARENDER
410 ui->renderSVGAction->setVisible(false);
411 #endif
412
413 #ifndef GEOIMAGE
414 ui->windowGeoimageAction->setVisible(false);
415 ui->viewPhotosAction->setVisible(false);
416 #endif
417
418 ui->viewStyleBackgroundAction->setVisible(false);
419 ui->viewStyleForegroundAction->setVisible(false);
420 ui->viewStyleTouchupAction->setVisible(false);
421
422 createToolBarManager(); // has to be before restorestate
423 M_PREFS->restoreMainWindowState( this );
424
425 if (!M_PREFS->getProjectionsList()->getProjections()->size()) {
426 qWarning() << "Projection list empty. (Projections.xml file could not be opened?).";
427 }
428
429 #define NUMOP 3
430 static const char *opStr[NUMOP] = {
431 QT_TR_NOOP("Low"), QT_TR_NOOP("High"), QT_TR_NOOP("Opaque")};
432
433 int o = M_PREFS->getAreaOpacity();
434 QActionGroup* actgrp = new QActionGroup(this);
435 for (int i=0; i<NUMOP; i++) {
436 QAction* act = new QAction(tr(opStr[i]), ui->mnuAreaOpacity);
437 actgrp->addAction(act);
438 qreal a = M_PREFS->getAlpha(opStr[i]);
439 act->setData(a);
440 act->setCheckable(true);
441 ui->mnuAreaOpacity->addAction(act);
442 if (o == int(a*100))
443 act->setChecked(true);
444 }
445 connect(ui->mnuAreaOpacity, SIGNAL(triggered(QAction*)), this, SLOT(setAreaOpacity(QAction*)));
446
447 if (!g_Merk_Frisius) {
448 ui->layersNewDrawingAction->setVisible(false);
449 }
450
451 blockSignals(false);
452
453 QTimer::singleShot( 0, this, SLOT(delayedInit()) );
454 }
455
delayedInit()456 void MainWindow::delayedInit()
457 {
458 QList<QAction*> actions = findChildren<QAction*>();
459 for (int i=0; i<actions.size(); i++) {
460 shortcutsDefault[actions[i]->objectName()] = actions[i]->shortcut().toString();
461 }
462 QStringList shortcuts = M_PREFS->getShortcuts();
463 for (int i=0; i<shortcuts.size(); i+=2) {
464 QAction* act = findChild<QAction*>(shortcuts[i]);
465 if (act)
466 act->setShortcut(QKeySequence(shortcuts[i+1]));
467 }
468
469 updateWindowMenu();
470
471 p->theListeningServer = new RemoteControlServer(this);
472 connect( p->theListeningServer, &RemoteControlServer::requestReceived,
473 this, [this](QString url) { loadUrl(url); } );
474
475 if (M_PREFS->getLocalServer()) {
476 p->theListeningServer->listen();
477 }
478
479 if (M_PREFS->getHideToolbarLabels()) {
480 setToolButtonStyle(Qt::ToolButtonIconOnly);
481 } else {
482 setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
483 }
484
485 // M_PREFS->initialPosition(theView);
486 on_fileNewAction_triggered();
487 invalidateView();
488 }
489
handleMessage(const QString & msg)490 void MainWindow::handleMessage(const QString &msg)
491 {
492 QStringList args = msg.split("$", QString::SkipEmptyParts);
493 QStringList fileNames;
494 for (int i=0; i < args.size(); ++i) {
495 if (args[i] == "-l" || args[i] == "--log") {
496 ++i;
497 } else {
498 QUrl u(args[i]);
499 if (u.scheme() == "osm") {
500 loadUrl(u);
501 continue;
502 }
503 if (args[i].endsWith(".mdc", Qt::CaseInsensitive))
504 loadDocument(args[i]);
505 else
506 fileNames.append(args[i]);
507 }
508 }
509
510 if (fileNames.size() > 0) {
511 importFiles(theDocument, fileNames, NULL);
512 }
513 }
514
~MainWindow(void)515 MainWindow::~MainWindow(void)
516 {
517 p->theProperties->setSelection(NULL);
518
519 delete M_STYLE;
520 delete theDocument;
521 delete theView;
522 delete p->theProperties;
523
524 delete qtTranslator;
525 delete merkaartorTranslator;
526
527 delete SlippyMapWidget::theSlippyCache;
528
529 delete p;
530
531 delete M_PREFS;
532 delete ui;
533 }
534
launchInteraction(Interaction * anInteraction)535 void MainWindow::launchInteraction(Interaction* anInteraction)
536 {
537 QList<Feature*> theSnapList;
538 EditInteraction* EI = dynamic_cast<EditInteraction*>(theView->interaction());
539 if (EI) {
540 theSnapList = EI->snapList();
541 ui->editRemoveAction->setEnabled(false);
542 ui->editReverseAction->setEnabled(false);
543 }
544 if (!theSnapList.size())
545 if (p->theProperties)
546 theSnapList = p->theProperties->selection();
547 if (theView->interaction())
548 delete theView->interaction();
549 theView->setInteraction(anInteraction);
550 if (anInteraction) {
551 ui->editPropertiesAction->setChecked(dynamic_cast<EditInteraction*>(anInteraction) != NULL);
552 ui->editMoveAction->setChecked(dynamic_cast<MoveNodeInteraction*>(anInteraction) != NULL);
553 ui->editRotateAction->setChecked(dynamic_cast<RotateInteraction*>(anInteraction) != NULL);
554 ui->editScaleAction->setChecked(dynamic_cast<ScaleInteraction*>(anInteraction) != NULL);
555 ui->createNodeAction->setChecked(dynamic_cast<CreateNodeInteraction*>(anInteraction) != NULL);
556 ui->createRoadAction->setChecked(dynamic_cast<CreateSingleWayInteraction*>(anInteraction) != NULL);
557 ui->createAreaAction->setChecked(dynamic_cast<CreateAreaInteraction*>(anInteraction) != NULL);
558 ui->roadExtrudeAction->setChecked(dynamic_cast<ExtrudeInteraction*>(anInteraction) != NULL);
559 ui->markBridgeAction->setChecked(dynamic_cast<BuildBridgeInteraction*>(anInteraction) != NULL);
560
561 EditInteraction* EI = dynamic_cast<EditInteraction*>(anInteraction);
562 if (EI)
563 EI->setSnap(theSnapList);
564 } else {
565 #ifndef _MOBILE
566 theView->setCursor(QCursor(Qt::ArrowCursor));
567 #endif
568 launchInteraction(new EditInteraction(this));
569 //Q_ASSERT(theView->interaction());
570 }
571 }
572
onCustomcontextmenurequested(const QPoint & pos)573 void MainWindow::onCustomcontextmenurequested(const QPoint & pos)
574 {
575 #ifndef _MOBILE
576 if (/*EditInteraction* ei = */dynamic_cast<EditInteraction*>(theView->interaction()) || dynamic_cast<MoveNodeInteraction*>(theView->interaction())) {
577 QMenu menu;
578
579 //FIXME Some of these actions on WIN32-MSVC corrupts the heap.
580
581 //QMenu editMenu(tr("Edit"));
582 //for(int i=0; i<Main->menuEdit->actions().size(); ++i) {
583 // if (Main->menuEdit->actions()[i]->isEnabled())
584 // editMenu.addAction(Main->menuEdit->actions()[i]);
585 //}
586 //if (editMenu.actions().size())
587 // menu.addMenu(&editMenu);
588
589 //QMenu createMenu(tr("Create"));
590 //for(int i=0; i<Main->menuCreate->actions().size(); ++i) {
591 // if (Main->menuCreate->actions()[i]->isEnabled())
592 // createMenu.addAction(Main->menuCreate->actions()[i]);
593 //}
594 //if (createMenu.actions().size())
595 // menu.addMenu(&createMenu);
596
597 menu.addAction(ui->viewZoomOutAction);
598 menu.addAction(ui->viewZoomWindowAction);
599 menu.addAction(ui->viewZoomInAction);
600
601 QMenu featureMenu(tr("Feature"));
602 for(int i=0; i<ui->menu_Feature->actions().size(); ++i) {
603 if (ui->menu_Feature->actions()[i]->isEnabled())
604 featureMenu.addAction(ui->menu_Feature->actions()[i]);
605 }
606 if (featureMenu.actions().size())
607 menu.addMenu(&featureMenu);
608
609
610 QMenu nodeMenu(tr("Node"));
611 for(int i=0; i<ui->menu_Node->actions().size(); ++i) {
612 if (ui->menu_Node->actions()[i]->isEnabled())
613 nodeMenu.addAction(ui->menu_Node->actions()[i]);
614 }
615 if (nodeMenu.actions().size())
616 menu.addMenu(&nodeMenu);
617
618 QMenu roadMenu(tr("Way"));
619 for(int i=0; i<ui->menuRoad->actions().size(); ++i) {
620 if (ui->menuRoad->actions()[i]->isEnabled())
621 roadMenu.addAction(ui->menuRoad->actions()[i]);
622 }
623 if (roadMenu.actions().size())
624 menu.addMenu(&roadMenu);
625
626 QMenu relationMenu(tr("Relation"));
627 for(int i=0; i<ui->menuRelation->actions().size(); ++i) {
628 if (ui->menuRelation->actions()[i]->isEnabled())
629 relationMenu.addAction(ui->menuRelation->actions()[i]);
630 }
631 if (relationMenu.actions().size())
632 menu.addMenu(&relationMenu);
633
634 if (menu.actions().size()) {
635 if (menu.actions().size() == 1) {
636 for (int i=0; i < menu.actions()[0]->menu()->actions().size(); ++i) {
637 menu.addAction(menu.actions()[0]->menu()->actions()[i]);
638 }
639 menu.removeAction(menu.actions()[0]);
640 }
641 menu.exec(theView->mapToGlobal(pos));
642 }
643 }
644 #endif
645 }
646
onImagerequested(ImageMapLayer *)647 void MainWindow::onImagerequested(ImageMapLayer *)
648 {
649 #ifndef _MOBILE
650 ++p->numImages;
651 pbImages->setRange(0, p->numImages);
652 //pbImages->setValue(0);
653 pbImages->update();
654 if (pbImages->value() < 0)
655 pbImages->setValue(0);
656 #endif
657 }
658
onImagereceived(ImageMapLayer * aLayer)659 void MainWindow::onImagereceived(ImageMapLayer *aLayer)
660 {
661 #ifndef _MOBILE
662 if (pbImages->value() < pbImages->maximum())
663 pbImages->setValue(pbImages->value()+1);
664 #endif
665 theView->on_imageReceived(aLayer);
666 }
667
onLoadingfinished(ImageMapLayer *)668 void MainWindow::onLoadingfinished(ImageMapLayer *)
669 {
670 p->numImages = 0;
671 #ifndef _MOBILE
672 pbImages->reset();
673 #endif
674 }
675
updateSegmentMode(QMouseEvent * mouseEvent)676 void MainWindow::updateSegmentMode(QMouseEvent* mouseEvent)
677 {
678 g_Merk_Segment_Mode = (mouseEvent->modifiers() & Qt::AltModifier) || dynamic_cast<ExtrudeInteraction*>(theView->interaction());
679 }
680
eventFilter(QObject *,QEvent * event)681 bool MainWindow::eventFilter(QObject */* watched */, QEvent *event)
682 {
683 switch (event->type()) {
684
685 #ifdef GEOIMAGE
686 case QEvent::DragEnter: {
687 QDragEnterEvent* devent = static_cast<QDragEnterEvent*>(event);
688
689 if (devent->mimeData()->hasUrls() && devent->mimeData()->urls().first().toLocalFile().endsWith(".jpg", Qt::CaseInsensitive)) {
690 p->dropTarget = NULL;
691 event->accept();
692 return true;
693 } else
694 event->ignore();
695
696 return false;
697 }
698
699 case QEvent::DragMove: {
700 QDragMoveEvent* devent = static_cast<QDragMoveEvent*>(event);
701
702 QMouseEvent mE(QEvent::MouseMove, devent->pos(), Qt::LeftButton, Qt::LeftButton, qApp->keyboardModifiers());
703 theView->mouseMoveEvent(&mE);
704
705 Node *tP;
706 for (VisibleFeatureIterator it(document()); !it.isEnd(); ++it) {
707 QList<Feature*> NoSnap;
708 if ((tP = CAST_NODE(it.get())) && tP->pixelDistance(devent->pos(), 5.01, NoSnap, theView) < 5.01) {
709 p->dropTarget = tP;
710 QRect acceptedRect(tP->projected().toPoint() - QPoint(3, 3), tP->projected().toPoint() + QPoint(3, 3));
711 devent->acceptProposedAction();
712 devent->accept(acceptedRect);
713 return true;
714 }
715 }
716 devent->acceptProposedAction();
717 devent->accept();
718 return true;
719 }
720
721 case QEvent::Drop: {
722 QDropEvent* devent = static_cast<QDropEvent*>(event);
723
724 // first save the image url because the even->mimeData() releases its data very soon
725 // this is probably because the drop action ends with calling of this event
726 // so the program that started the drag-action thinks the data isn't needed anymore
727 QList<QUrl> imageUrls = devent->mimeData()->urls();
728 QStringList locFiles;
729 foreach(QUrl url, imageUrls)
730 locFiles << url.toLocalFile();
731
732 if (locFiles.size() > 1)
733 geoImage()->loadImages(locFiles);
734 else {
735 QMenu menu(this);
736 QString imageFn = locFiles[0];
737 Coord mapC = theView->fromView(devent->pos());
738 Coord pos = GeoImageDock::getGeoDataFromImage(imageFn);
739
740 if (pos.isNull()) {
741 QAction *add, *load;
742 load = menu.addAction(tr("Load image"));
743 if (p->dropTarget)
744 add = menu.addAction(tr("Add node position to image"));
745 else
746 add = menu.addAction(tr("Geotag image with this position"));
747 menu.addSeparator();
748 menu.addAction(tr("Cancel"));
749 QAction* res = menu.exec(QCursor::pos());
750 if (res == add) {
751 if (p->dropTarget)
752 geoImage()->addGeoDataToImage(p->dropTarget->position(), imageFn);
753 else
754 geoImage()->addGeoDataToImage(mapC,imageFn);
755 geoImage()->loadImages(locFiles);
756 } else if (res == load)
757 geoImage()->loadImage(imageFn, mapC);
758 } else
759 geoImage()->loadImages(locFiles);
760 }
761
762 return false;
763 }
764 #endif // GEOIMAGE
765
766 case QEvent::MouseButtonDblClick: {
767 if (!theDocument)
768 return true;
769
770 if (!theView->updatesEnabled())
771 return true;
772
773 if (!theView->interaction())
774 return true;
775
776 QMouseEvent* mevent = static_cast<QMouseEvent*>(event);
777 updateSegmentMode(mevent);
778
779 theView->interaction()->mouseEvent(mevent);
780
781 if (M_PREFS->getSelectModeCreation()) {
782 MoveNodeInteraction* MI = NULL;
783 if (!M_PREFS->getSeparateMoveMode()) {
784 MI = dynamic_cast<MoveNodeInteraction*>(theView->interaction());
785 }
786 EditInteraction* EI = dynamic_cast<EditInteraction*>(theView->interaction());
787 if ((EI && EI->isIdle()) || (MI && MI->isIdle())) {
788 if ((EI->lastSnap() && EI->lastSnap()->getType() & IFeature::LineString) || !EI->lastSnap())
789 CreateNodeInteraction::createNode(theView->fromView(mevent->pos()), EI->lastSnap());
790 else if (EI->lastSnap() && EI->lastSnap()->getType() == IFeature::Point) {
791 Node* N = CAST_NODE(EI->lastSnap());
792 CreateSingleWayInteraction* CI = new CreateSingleWayInteraction(this, N, false);
793 N->invalidatePainter();
794 launchInteraction(CI);
795 theInfo->setHtml(theView->interaction()->toHtml());
796 #ifndef _MOBILE
797 theView->setCursor(CI->cursor());
798 #endif
799 theView->update();
800 return true;
801 }
802 }
803 }
804
805 return false;
806 }
807
808 case QEvent::MouseButtonPress: {
809 if (!theDocument)
810 return true;
811
812 if (!theView->interaction())
813 return true;
814
815 QMouseEvent* mevent = static_cast<QMouseEvent*>(event);
816 updateSegmentMode(mevent);
817
818 theView->interaction()->mouseEvent(mevent);
819 if (theInfo)
820 theInfo->setHtml(theView->interaction()->toHtml());
821
822 return false;
823 }
824
825 case QEvent::MouseButtonRelease: {
826 if (!document())
827 return true;
828
829 if (!theView->interaction())
830 return true;
831
832 QMouseEvent* mevent = static_cast<QMouseEvent*>(event);
833 updateSegmentMode(mevent);
834
835 theView->interaction()->mouseEvent(mevent);
836
837 return false;
838 }
839
840 case QEvent::MouseMove: {
841 if (!theDocument)
842 return true;
843
844 if (!theView->updatesEnabled())
845 return true;
846
847 if (!theView->interaction())
848 return false;
849
850 QMouseEvent* mevent = static_cast<QMouseEvent*>(event);
851 updateSegmentMode(mevent);
852
853 theView->interaction()->mouseEvent(mevent);
854
855 if (!M_PREFS->getSeparateMoveMode()) {
856 EditInteraction* EI = dynamic_cast<EditInteraction*>(theView->interaction());
857 if (EI && EI->isIdle()) {
858 if (EI->lastSnap() && p->theProperties->isSelected(EI->lastSnap())) {
859 MoveNodeInteraction* MI = new MoveNodeInteraction(this);
860 launchInteraction(MI);
861 // main()->info()->setHtml(interaction()->toHtml());
862 #ifndef _MOBILE
863 theView->setCursor(MI->cursor());
864 #endif
865 theView->update();
866 return false;
867 }
868 }
869 MoveNodeInteraction* MI = dynamic_cast<MoveNodeInteraction*>(theView->interaction());
870 if (MI && !MI->lastSnap() && MI->isIdle()) {
871 EditInteraction* EI = new EditInteraction(this);
872 launchInteraction(EI);
873 #ifndef _MOBILE
874 theView->setCursor(EI->cursor());
875 #endif
876 theView->update();
877 return false;
878 }
879
880 }
881
882 return false;
883 }
884
885 case QEvent::Wheel: {
886 if (!theDocument)
887 return true;
888
889 return false;
890 }
891
892 case QEvent::ToolTip: {
893 QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
894 //Coord p = p->theProjection.inverse(helpEvent->pos());
895 if (M_PREFS->getMapTooltip()) {
896 if (!toolTip().isEmpty())
897 QToolTip::showText(helpEvent->globalPos(), toolTip());
898 else
899 QToolTip::hideText();
900 }
901 return true;
902 }
903
904 case QEvent::KeyPress: {
905 QKeyEvent *ke = static_cast< QKeyEvent* >( event );
906 switch ( ke->key() ) {
907 case Qt::Key_Space:
908 ke->accept();
909 theView->setBackgroundOnlyPanZoom(true);
910 return true;
911
912 case Qt::Key_Tab:
913 theView->setFocus();
914 ke->accept();
915
916 // if (!isSelectionLocked())
917 // lockSelection();
918 // else
919 {
920 FeatureSnapInteraction* intr = dynamic_cast<FeatureSnapInteraction*>(theView->interaction());
921 if (intr)
922 intr->nextSnap();
923 }
924 return true;
925
926 case Qt::Key_Backtab:
927 theView->setFocus();
928 ke->accept();
929
930 // if (!isSelectionLocked())
931 // lockSelection();
932 // else
933 {
934 FeatureSnapInteraction* intr = dynamic_cast<FeatureSnapInteraction*>(theView->interaction());
935 if (intr)
936 intr->nextSnap();
937 }
938 return true;
939
940 case Qt::Key_T:
941 {
942 theView->rotateScreen(theView->rect().center(), 15.);
943 return true;
944 }
945
946 case Qt::Key_O:
947 {
948 CreateSingleWayInteraction* intr = dynamic_cast<CreateSingleWayInteraction*>(theView->interaction());
949 if (!intr)
950 return false;
951
952 theView->setFocus();
953 ke->accept();
954 intr->setSnapAngle(45.);
955
956 return true;
957 }
958
959 case Qt::Key_H:
960 {
961 CreateSingleWayInteraction* intr = dynamic_cast<CreateSingleWayInteraction*>(theView->interaction());
962 if (!intr)
963 return false;
964
965 theView->setFocus();
966 ke->accept();
967 intr->setSnapAngle(30.);
968
969 return true;
970 }
971
972 case Qt::Key_P:
973 {
974 CreateSingleWayInteraction* intr = dynamic_cast<CreateSingleWayInteraction*>(theView->interaction());
975 if (!intr)
976 return false;
977
978 theView->setFocus();
979 ke->accept();
980 intr->setParallelMode(true);
981
982 return true;
983 }
984
985 case Qt::Key_C:
986 {
987 CreateSingleWayInteraction* CI = dynamic_cast<CreateSingleWayInteraction*>(theView->interaction());
988 if (CI) {
989 theView->setFocus();
990 ke->accept();
991 CI->closeAndFinish();
992 } else {
993 CreateAreaInteraction* AI = dynamic_cast<CreateAreaInteraction*>(theView->interaction());
994 if (AI) {
995 theView->setFocus();
996 ke->accept();
997 AI->closeAndFinish();
998 }
999 else
1000 return false;
1001 }
1002 return true;
1003 }
1004
1005 default:
1006 break;
1007
1008 }
1009 }
1010 break;
1011
1012 case QEvent::KeyRelease: {
1013 QKeyEvent *ke = static_cast< QKeyEvent* >( event );
1014 switch ( ke->key() ) {
1015 case Qt::Key_Space:
1016 ke->accept();
1017 theView->setBackgroundOnlyPanZoom(false);
1018 return true;
1019
1020 case Qt::Key_O:
1021 case Qt::Key_H:
1022 {
1023 CreateSingleWayInteraction* intr = dynamic_cast<CreateSingleWayInteraction*>(theView->interaction());
1024 if (!intr)
1025 return false;
1026
1027 ke->accept();
1028 intr->setSnapAngle(0);
1029
1030 return true;
1031 }
1032
1033 case Qt::Key_P:
1034 {
1035 CreateSingleWayInteraction* intr = dynamic_cast<CreateSingleWayInteraction*>(theView->interaction());
1036 if (!intr)
1037 return false;
1038
1039 ke->accept();
1040 intr->setParallelMode(false);
1041
1042 return true;
1043 }
1044
1045 default:
1046 break;
1047 }
1048 }
1049 break;
1050
1051 case QEvent::Leave: {
1052 if (theInfo)
1053 theInfo->unsetHoverHtml();
1054 FeatureSnapInteraction* intr = dynamic_cast<FeatureSnapInteraction*>(theView->interaction());
1055 if (intr)
1056 intr->clearLastSnap();
1057 theView->update();
1058 }
1059
1060 default:
1061 break;
1062 }
1063
1064 return false;
1065 }
1066
1067 namespace {
1068
AddActionsIntoManager(QtToolBarManager * manager,QWidget * widget,const QString & label)1069 void AddActionsIntoManager(QtToolBarManager* manager, QWidget* widget,
1070 const QString& label) {
1071 foreach(QAction* a, widget->actions()) {
1072 if (!a->isSeparator() && !a->menu())
1073 manager->addAction(a, label);
1074 }
1075 }
1076
1077 } // namespace
1078
createToolBarManager()1079 void MainWindow::createToolBarManager()
1080 {
1081 toolBarManager = new QtToolBarManager(this);
1082 toolBarManager->setMainWindow(this);
1083
1084 AddActionsIntoManager(toolBarManager, ui->menuFile, tr("File"));
1085 AddActionsIntoManager(toolBarManager, ui->menuEdit, tr("Edit"));
1086 AddActionsIntoManager(toolBarManager, ui->menuView, tr("View"));
1087 AddActionsIntoManager(toolBarManager, ui->menu_Show, tr("Show"));
1088 AddActionsIntoManager(toolBarManager, ui->menuShow_directional_Arrows, tr("Directional Arrows"));
1089 AddActionsIntoManager(toolBarManager, ui->menuGps, tr("GPS"));
1090 AddActionsIntoManager(toolBarManager, ui->menuLayers, tr("Layers"));
1091 AddActionsIntoManager(toolBarManager, ui->menuCreate, tr("Create"));
1092 AddActionsIntoManager(toolBarManager, ui->menu_Feature, tr("Feature"));
1093 AddActionsIntoManager(toolBarManager, ui->menu_Node, tr("Node"));
1094 AddActionsIntoManager(toolBarManager, ui->menuRoad, tr("Way"));
1095 AddActionsIntoManager(toolBarManager, ui->menuRelation, tr("Relation"));
1096 AddActionsIntoManager(toolBarManager, ui->menuTools, tr("Tools"));
1097 AddActionsIntoManager(toolBarManager, ui->menuWindow, tr("Windows"));
1098 AddActionsIntoManager(toolBarManager, ui->menuHelp, tr("Help"));
1099
1100 toolBarManager->addToolBar(ui->toolBar, QString());
1101
1102 QSettings* Sets = M_PREFS->getQSettings();
1103 if (!g_Merk_Ignore_Preferences && !g_Merk_Reset_Preferences)
1104 if (Sets->contains("MainWindow/Toolbars"))
1105 toolBarManager->restoreState(Sets->value("MainWindow/Toolbars").toByteArray());
1106 }
1107
on_toolsToolbarsAction_triggered()1108 void MainWindow::on_toolsToolbarsAction_triggered()
1109 {
1110 QtToolBarDialog dlg(this);
1111 dlg.setToolBarManager(toolBarManager);
1112 dlg.exec();
1113
1114 QSettings* Sets = M_PREFS->getQSettings();
1115 Sets->setValue("MainWindow/Toolbars", toolBarManager->saveState());
1116 }
1117
createProgressDialog()1118 void MainWindow::createProgressDialog()
1119 {
1120 theProgressDialog = new QProgressDialog(this);
1121 theProgressDialog->setWindowModality(Qt::ApplicationModal);
1122 theProgressDialog->setMinimumDuration(0);
1123
1124 theProgressBar = new QProgressBar(theProgressDialog);
1125 theProgressBar->setTextVisible(false);
1126 theProgressDialog->setBar(theProgressBar);
1127
1128 theProgressLabel = new QLabel();
1129 theProgressLabel->setAlignment(Qt::AlignCenter);
1130 theProgressDialog->setLabel(theProgressLabel);
1131
1132 theProgressDialog->setMaximum(11);
1133 theProgressDialog->reset();
1134 }
1135
deleteProgressDialog()1136 void MainWindow::deleteProgressDialog()
1137 {
1138 SAFE_DELETE(theProgressDialog)
1139 theProgressBar = NULL;
1140 theProgressLabel = NULL;
1141 }
1142
setAreaOpacity(QAction * act)1143 void MainWindow::setAreaOpacity(QAction *act)
1144 {
1145 qreal a = act->data().toDouble();
1146 M_PREFS->setAreaOpacity(int(a*100));
1147
1148 theView->invalidate(true, true, false);
1149 }
1150
adjustLayers(bool adjustViewport)1151 void MainWindow::adjustLayers(bool adjustViewport)
1152 {
1153 if (M_PREFS->getZoomBoris()) {
1154 ImageMapLayer* l = NULL;
1155 for (LayerIterator<ImageMapLayer*> ImgIt(theDocument); !ImgIt.isEnd(); ++ImgIt) {
1156 l = ImgIt.get();
1157 break;
1158 }
1159 if (l && l->isTiled()) {
1160 theView->projection().setProjectionType(l->projection());
1161 updateProjectionMenu();
1162 }
1163 }
1164 if (adjustViewport) {
1165 CoordBox theVp;
1166 theVp = theView->viewport();
1167 theView->setViewport(theVp, theView->rect());
1168 }
1169 invalidateView(true);
1170 }
1171
invalidateView(bool UpdateDock)1172 void MainWindow::invalidateView(bool UpdateDock)
1173 {
1174 theView->setRenderOptions(p->renderOptions);
1175 theView->invalidate(true, true, true);
1176 //theLayers->updateContent();
1177 if (UpdateDock)
1178 p->theProperties->resetValues();
1179 }
1180
toggleButtonStyle()1181 void MainWindow::toggleButtonStyle()
1182 {
1183 if (M_PREFS->getHideToolbarLabels()) {
1184 M_PREFS->setHideToolbarLabels(false);
1185 setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
1186 } else {
1187 M_PREFS->setHideToolbarLabels(true);
1188 setToolButtonStyle(Qt::ToolButtonIconOnly);
1189 }
1190 }
1191
properties()1192 PropertiesDock* MainWindow::properties()
1193 {
1194 return p->theProperties;
1195 }
1196
info()1197 InfoDock* MainWindow::info()
1198 {
1199 return theInfo;
1200 }
1201
1202 #ifdef GEOIMAGE
geoImage()1203 GeoImageDock* MainWindow::geoImage()
1204 {
1205 return theGeoImage;
1206 }
1207 #endif
1208
features()1209 FeaturesDock* MainWindow::features()
1210 {
1211 return p->theFeats;
1212 }
1213
document()1214 Document* MainWindow::document()
1215 {
1216 return theDocument;
1217 }
1218
on_editCutAction_triggered()1219 void MainWindow::on_editCutAction_triggered()
1220 {
1221 // Export
1222 QClipboard *clipboard = QApplication::clipboard();
1223 QMimeData* md = new QMimeData();
1224
1225 QBuffer osmBuf;
1226 osmBuf.open(QIODevice::WriteOnly);
1227
1228 QList<Feature*> exportedFeatures = document()->exportCoreOSM(p->theProperties->selection());
1229 theDocument->exportOSM(this, &osmBuf, exportedFeatures);
1230 md->setText(QString(osmBuf.data()));
1231 md->setData(MIME_OPENSTREETMAP_XML, osmBuf.data());
1232
1233 ImportExportKML kmlexp(theDocument);
1234 QBuffer kmlBuf;
1235 kmlBuf.open(QIODevice::WriteOnly);
1236 if (kmlexp.setDevice(&kmlBuf)) {
1237 kmlexp.export_(p->theProperties->selection());
1238 md->setData(MIME_GOOGLE_EARTH_KML, kmlBuf.data());
1239 }
1240
1241 ExportGPX gpxexp(theDocument);
1242 QBuffer gpxBuf;
1243 gpxBuf.open(QIODevice::WriteOnly);
1244 if (gpxexp.setDevice(&gpxBuf)) {
1245 gpxexp.export_(p->theProperties->selection());
1246 md->setData(MIME_GPX, gpxBuf.data());
1247 }
1248
1249 //Deletion
1250 QList<Feature*> Sel;
1251 for (int i=0; i<p->theProperties->selectionSize(); ++i)
1252 Sel.push_back(p->theProperties->selection(i));
1253 if (Sel.size() == 0) return;
1254
1255 CommandList* theList = new CommandList(MainWindow::tr("Cut Features"), Sel[0]);
1256 for (int i=0; i<Sel.size(); ++i) {
1257 QList<Feature*> Alternatives;
1258 theList->add(new RemoveFeatureCommand(document(), Sel[i], Alternatives));
1259 }
1260
1261 if (theList->size()) {
1262 document()->addHistory(theList);
1263 }
1264 else {
1265 delete theList;
1266 return;
1267 }
1268
1269 QString xml;
1270 QXmlStreamWriter stream(&xml);
1271 stream.setAutoFormatting(true);
1272 stream.setAutoFormattingIndent(2);
1273 stream.writeStartDocument();
1274 stream.writeStartElement("MerkaartorUndo");
1275 stream.writeAttribute("documentid", theDocument->id());
1276 theList->toXML(stream);
1277 stream.writeEndElement();
1278 stream.writeEndDocument();
1279 md->setData(MIME_MERKAARTOR_UNDO_XML, xml.toUtf8());
1280 // qDebug() << doc.toString(2);
1281
1282 clipboard->setMimeData(md);
1283
1284 properties()->setSelection(0);
1285 properties()->checkMenuStatus();
1286 view()->invalidate(true, true, false);
1287 }
1288
on_editCopyAction_triggered()1289 void MainWindow::on_editCopyAction_triggered()
1290 {
1291 QClipboard *clipboard = QApplication::clipboard();
1292 QMimeData* md = new QMimeData();
1293
1294 QBuffer osmBuf;
1295 osmBuf.open(QIODevice::WriteOnly);
1296
1297 QList<Feature*> exportedFeatures = document()->exportCoreOSM(p->theProperties->selection(), true);
1298 theDocument->exportOSM(this, &osmBuf, exportedFeatures);
1299 md->setText(QString(osmBuf.data()));
1300 md->setData(MIME_OPENSTREETMAP_XML, osmBuf.data());
1301
1302 ImportExportKML kmlexp(theDocument);
1303 QBuffer kmlBuf;
1304 kmlBuf.open(QIODevice::WriteOnly);
1305 if (kmlexp.setDevice(&kmlBuf)) {
1306 kmlexp.export_(p->theProperties->selection());
1307 md->setData(MIME_GOOGLE_EARTH_KML, kmlBuf.data());
1308 }
1309
1310 ExportGPX gpxexp(theDocument);
1311 QBuffer gpxBuf;
1312 gpxBuf.open(QIODevice::WriteOnly);
1313 if (gpxexp.setDevice(&gpxBuf)) {
1314 gpxexp.export_(p->theProperties->selection());
1315 md->setData(MIME_GPX, gpxBuf.data());
1316 }
1317
1318 clipboard->setMimeData(md);
1319 invalidateView();
1320 }
1321
on_editPasteFeatureAction_triggered()1322 void MainWindow::on_editPasteFeatureAction_triggered()
1323 {
1324 DrawingLayer* l = dynamic_cast<DrawingLayer*>(theDocument->getDirtyOrOriginLayer());
1325 if (!l)
1326 return;
1327
1328 Document* doc;
1329
1330 QClipboard *clipboard = QApplication::clipboard();
1331 if (clipboard->mimeData()->hasFormat(MIME_MERKAARTOR_UNDO_XML)) {
1332 QDomDocument theXmlDoc;
1333 if (!theXmlDoc.setContent(clipboard->mimeData()->data(MIME_MERKAARTOR_UNDO_XML))) {
1334 // Do nothing.
1335 } else {
1336 QDomElement root = theXmlDoc.firstChildElement("MerkaartorUndo");
1337 if (!root.isNull()) {
1338 QString docId = root.attribute("documentid");
1339 if (theDocument->id() == docId) {
1340
1341 QDomNodeList nl = theXmlDoc.elementsByTagName("RemoveFeatureCommand");
1342 for (int i=0; i<nl.size(); ++i) {
1343 nl.at(i).toElement().setAttribute("layer", l->id());
1344 }
1345
1346 QString xml;
1347 QTextStream tstr(&xml, QIODevice::ReadOnly);
1348 root.firstChildElement("CommandList").save(tstr, 2);
1349 QXmlStreamReader stream(xml);
1350
1351 CommandList* theList = CommandList::fromXML(theDocument, stream);
1352 theList->setReversed(true);
1353 theList->redo();
1354 theList->setDescription("Paste Features");
1355 theDocument->addHistory(theList);
1356
1357 view()->invalidate(true, true, false);
1358
1359 return;
1360 }
1361 }
1362 }
1363 }
1364
1365 if (!(doc = Document::getDocumentFromClipboard())) {
1366 dieClipboardInvalid();
1367 return;
1368 }
1369
1370 CommandList* theList = new CommandList();
1371 theList->setDescription("Paste Features");
1372 QList<Feature*> theFeats = theDocument->mergeDocument(doc, theDocument->getDirtyOrOriginLayer(), theList);
1373
1374 if (theList->size())
1375 document()->addHistory(theList);
1376 else
1377 delete theList;
1378
1379 delete doc;
1380
1381 p->theProperties->setSelection(theFeats);
1382 view()->invalidate(true, true, false);
1383 }
1384
dieClipboardInvalid()1385 void MainWindow::dieClipboardInvalid()
1386 {
1387 QMessageBox::critical(this, tr("Clipboard invalid"), tr("Clipboard do not contain valid data."));
1388 }
1389
on_editPasteOverwriteAction_triggered()1390 void MainWindow::on_editPasteOverwriteAction_triggered()
1391 {
1392 QList<Feature*> sel = properties()->selection();
1393 if (!sel.size())
1394 return;
1395
1396 Document* doc;
1397 if (!(doc = Document::getDocumentFromClipboard())) {
1398 dieClipboardInvalid();
1399 return;
1400 }
1401
1402 CommandList* theList = new CommandList();
1403 theList->setDescription("Paste tags (overwrite)");
1404
1405 for(int i=0; i < sel.size(); ++i) {
1406 theList->add(new ClearTagsCommand(sel[i], theDocument->getDirtyOrOriginLayer(sel[i]->layer())));
1407 for (FeatureIterator k(doc); !k.isEnd(); ++k) {
1408 // Allow any<->any pasting but only takes top level feature into account
1409 if (k.get()->sizeParents())
1410 continue;
1411 Feature::mergeTags(theDocument, theList, sel[i], k.get());
1412 }
1413 }
1414
1415 if (theList->size())
1416 document()->addHistory(theList);
1417 else
1418 delete theList;
1419
1420 delete doc;
1421 invalidateView();
1422 }
1423
on_editPasteMergeAction_triggered()1424 void MainWindow::on_editPasteMergeAction_triggered()
1425 {
1426 QList<Feature*> sel = properties()->selection();
1427 if (!sel.size())
1428 return;
1429
1430 Document* doc;
1431 if (!(doc = Document::getDocumentFromClipboard())) {
1432 dieClipboardInvalid();
1433 return;
1434 }
1435
1436 CommandList* theList = new CommandList();
1437 theList->setDescription("Paste tags (merge)");
1438
1439 for(int i=0; i < sel.size(); ++i) {
1440 for (FeatureIterator k(doc); !k.isEnd(); ++k) {
1441 // Allow any<->any pasting but only takes top level feature into account
1442 if (k.get()->sizeParents())
1443 continue;
1444 Feature::mergeTags(theDocument, theList, sel[i], k.get());
1445 }
1446 }
1447
1448 if (theList->size())
1449 document()->addHistory(theList);
1450 else
1451 delete theList;
1452
1453 delete doc;
1454 invalidateView();
1455 }
1456
clipboardChanged()1457 void MainWindow::clipboardChanged()
1458 {
1459 ui->editPasteFeatureAction->setEnabled(false);
1460 ui->editPasteMergeAction->setEnabled(false);
1461 ui->editPasteOverwriteAction->setEnabled(false);
1462
1463 QClipboard *clipboard = QApplication::clipboard();
1464 //qDebug() << "Clipboard mime: " << clipboard->mimeData()->formats();
1465 QDomDocument theXmlDoc;
1466 bool ok = false;
1467 // mimeData() returns nullptr if not supported by the platform
1468 if (clipboard->mimeData()) {
1469 if (clipboard->mimeData()->hasFormat(MIME_OPENSTREETMAP_XML))
1470 ok = theXmlDoc.setContent(clipboard->mimeData()->data(MIME_OPENSTREETMAP_XML));
1471 else if (clipboard->mimeData()->hasText())
1472 ok = theXmlDoc.setContent(clipboard->text());
1473 }
1474
1475 if (!ok) {
1476 return;
1477 }
1478
1479 QDomElement c = theXmlDoc.documentElement();
1480
1481 if (c.tagName() != "osm" && c.tagName() != "kml") {
1482 return;
1483 }
1484
1485 ui->editPasteFeatureAction->setEnabled(true);
1486 ui->editPasteMergeAction->setEnabled(true);
1487 ui->editPasteOverwriteAction->setEnabled(true);
1488 }
1489
on_editRedoAction_triggered()1490 void MainWindow::on_editRedoAction_triggered()
1491 {
1492 theDocument->redoHistory();
1493 p->theProperties->adjustSelection();
1494 invalidateView();
1495 }
1496
on_editUndoAction_triggered()1497 void MainWindow::on_editUndoAction_triggered()
1498 {
1499 theDocument->undoHistory();
1500 p->theProperties->adjustSelection();
1501 invalidateView();
1502 }
1503
on_editPropertiesAction_triggered()1504 void MainWindow::on_editPropertiesAction_triggered()
1505 {
1506 if (theView->interaction() && dynamic_cast<EditInteraction*>(theView->interaction()))
1507 p->theProperties->setSelection(0);
1508 theView->unlockSelection();
1509 // theView->invalidate(true, true, false);
1510 launchInteraction(new EditInteraction(this));
1511 view()->setInteracting(false);
1512 theInfo->setHtml(theView->interaction()->toHtml());
1513 }
1514
on_editRemoveAction_triggered()1515 void MainWindow::on_editRemoveAction_triggered()
1516 {
1517 emit remove_triggered();
1518 emit content_changed();
1519 }
1520
on_editMoveAction_triggered()1521 void MainWindow::on_editMoveAction_triggered()
1522 {
1523 if (M_PREFS->getSeparateMoveMode()) {
1524 launchInteraction(new MoveNodeInteraction(this));
1525 theInfo->setHtml(theView->interaction()->toHtml());
1526 }
1527 }
1528
on_editRotateAction_triggered()1529 void MainWindow::on_editRotateAction_triggered()
1530 {
1531 launchInteraction(new RotateInteraction(this));
1532 theInfo->setHtml(theView->interaction()->toHtml());
1533 }
1534
on_editScaleAction_triggered()1535 void MainWindow::on_editScaleAction_triggered()
1536 {
1537 launchInteraction(new ScaleInteraction(this));
1538 theInfo->setHtml(theView->interaction()->toHtml());
1539 }
1540
on_editReverseAction_triggered()1541 void MainWindow::on_editReverseAction_triggered()
1542 {
1543 emit reverse_triggered();
1544 }
1545
on_fileImportGDALAction_triggered()1546 void MainWindow::on_fileImportGDALAction_triggered() {
1547 if (QMessageBox::warning(this,
1548 MainWindow::tr("GDAL import warning"),
1549 MainWindow::tr(
1550 "You are about to import file(s) using GDAL. This feature is rather experimental, and may or may NOT work, possibly causing a crash. Make sure you won't loose any data in case it doesn't work out.\n"
1551 "Please do report bugs in case of a crash, but don't be surprised about it.\n"
1552 "\n"
1553 "Continue with import?\n"
1554 ),
1555 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
1556 {
1557 importAction(true);
1558 }
1559 }
1560
on_fileImportAction_triggered()1561 void MainWindow::on_fileImportAction_triggered() {
1562 importAction(false);
1563
1564 }
1565
importAction(bool useGdal)1566 void MainWindow::importAction( bool useGdal ) {
1567 QStringList fileNames = QFileDialog::getOpenFileNames(
1568 this,
1569 tr("Import file"),
1570 QString(), p->FILTER_IMPORT_SUPPORTED);
1571
1572 if (fileNames.isEmpty())
1573 return;
1574
1575 view()->setUpdatesEnabled(false);
1576 theLayers->setUpdatesEnabled(false);
1577
1578 QStringList importedFiles;
1579 importFiles(theDocument, fileNames, &importedFiles, useGdal);
1580
1581 foreach (QString currentFileName, importedFiles)
1582 M_PREFS->addRecentImport(currentFileName);
1583
1584 updateRecentImportMenu();
1585
1586 view()->setUpdatesEnabled(true);
1587 theLayers->setUpdatesEnabled(true);
1588
1589 on_editPropertiesAction_triggered();
1590 theDocument->history().setActions(ui->editUndoAction, ui->editRedoAction, ui->fileUploadAction);
1591 }
1592
mayDiscardUnsavedChanges(QWidget * aWidget)1593 static bool mayDiscardUnsavedChanges(QWidget* aWidget)
1594 {
1595 return QMessageBox::question(aWidget, MainWindow::tr("Unsaved changes"),
1596 MainWindow::tr("The current map contains unsaved changes that will be lost when starting a new one.\n"
1597 "Do you want to cancel starting a new map or continue and discard the old changes?"),
1598 QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Discard;
1599 }
1600
mayDiscardStyleChanges(QWidget * aWidget)1601 static bool mayDiscardStyleChanges(QWidget* aWidget)
1602 {
1603 return QMessageBox::question(aWidget, MainWindow::tr("Unsaved Style changes"),
1604 MainWindow::tr("You have modified the current style.\n"
1605 "Do you want to save your changes?"),
1606 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No;
1607 }
1608
startBusyCursor()1609 void MainWindow::startBusyCursor() {
1610 #ifndef Q_OS_SYMBIAN
1611 QApplication::setOverrideCursor(Qt::BusyCursor);
1612 #endif
1613 }
1614
endBusyCursor()1615 void MainWindow::endBusyCursor() {
1616 #ifndef Q_OS_SYMBIAN
1617 QApplication::restoreOverrideCursor();
1618 #endif
1619 }
1620
importFile(Document * mapDocument,const QString & fileName,Layer * & newLayer)1621 MainWindow::ImportStatus MainWindow::importFile(Document * mapDocument, const QString& fileName, Layer*& newLayer) {
1622 MainWindow::ImportStatus result;
1623
1624 qDebug() << "Importing file" << fileName << "using native parsers.";
1625
1626 QString baseFileName = fileName.section('/', - 1);
1627 if (fileName.toLower().endsWith(".gpx")) {
1628 QList<TrackLayer*> theTracklayers;
1629 newLayer = new TrackLayer( baseFileName + " - " + tr("Waypoints"), baseFileName);
1630 mapDocument->add(newLayer);
1631 theTracklayers.append((TrackLayer*) newLayer);
1632 bool importOK = ImportGPX::import(this, fileName, mapDocument, theTracklayers);
1633 if (!importOK) {
1634 for (int i=0; i<theTracklayers.size(); i++) {
1635 mapDocument->remove(theTracklayers[i]);
1636 SAFE_DELETE(theTracklayers[i]);
1637 }
1638 newLayer = NULL;
1639 } else {
1640 if (!newLayer->size()) {
1641 mapDocument->remove(newLayer);
1642 SAFE_DELETE(newLayer);
1643 }
1644 for (int i=1; i<theTracklayers.size(); i++) {
1645 if (theTracklayers[i]->name().isEmpty())
1646 theTracklayers[i]->setName(QString(baseFileName + " - " + tr("Track %1").arg(i)));
1647 if (importOK && M_PREFS->getAutoExtractTracks()) {
1648 theTracklayers[i]->extractLayer();
1649 }
1650 }
1651 }
1652 result = importOK ? IMPORT_OK : IMPORT_ERROR;
1653 }
1654 else if (fileName.toLower().endsWith(".osm")) {
1655 newLayer = new DrawingLayer( baseFileName );
1656 mapDocument->add(newLayer);
1657 result = importOSM(this, fileName, mapDocument, newLayer) ? IMPORT_OK : IMPORT_ERROR;
1658 }
1659 #ifndef FRISIUS_BUILD
1660 else if (fileName.toLower().endsWith(".osc")) {
1661 if (g_Merk_Frisius) {
1662 newLayer = new DrawingLayer( baseFileName );
1663 mapDocument->add(newLayer);
1664 } else {
1665 newLayer = mapDocument->getDirtyOrOriginLayer();
1666 }
1667 result = mapDocument->importOSC(fileName, (DrawingLayer*)newLayer) ? IMPORT_OK : IMPORT_ERROR;
1668 }
1669 #endif
1670 else if (fileName.toLower().endsWith(".ngt")) {
1671 newLayer = new TrackLayer( baseFileName );
1672 newLayer->setUploadable(false);
1673 mapDocument->add(newLayer);
1674 bool importOK = importNGT(this, fileName, mapDocument, newLayer);
1675 if (importOK && M_PREFS->getAutoExtractTracks()) {
1676 ((TrackLayer *)newLayer)->extractLayer();
1677 }
1678 result = importOK ? IMPORT_OK : IMPORT_ERROR;
1679 }
1680 else if (fileName.toLower().endsWith(".nmea") || (fileName.toLower().endsWith(".nma"))) {
1681 newLayer = new TrackLayer( baseFileName );
1682 newLayer->setUploadable(false);
1683 mapDocument->add(newLayer);
1684 bool importOK = mapDocument->importNMEA(fileName, (TrackLayer *)newLayer);
1685 if (importOK && M_PREFS->getAutoExtractTracks()) {
1686 ((TrackLayer *)newLayer)->extractLayer();
1687 }
1688 result = importOK ? IMPORT_OK : IMPORT_ERROR;
1689 }
1690 else if (fileName.toLower().endsWith(".kml")) {
1691 if (QMessageBox::warning(this, MainWindow::tr("Big Fat Copyright Warning"),
1692 MainWindow::tr(
1693 "You are trying to import a KML file. Please be aware that:\n"
1694 "\n"
1695 " - You cannot import to OSM a KML file created from Google Earth. While you might\n"
1696 " think that nodes you created from GE are yours, they are not!\n"
1697 " They are still a derivative work from GE, and, as such, cannot be used in OSM.\n"
1698 "\n"
1699 " - If you downloaded it from the Internet, chances are that there is a copyright on it.\n"
1700 " Please be absolutely sure that using those data in OSM is permitted by the author, or\n"
1701 " that the data is public domain.\n"
1702 "\n"
1703 "If unsure, please seek advice on the \"legal\" or \"talk\" openstreetmap mailing lists.\n"
1704 "\n"
1705 "Are you absolutely sure this KML can legally be imported in OSM?"),
1706 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
1707 {
1708 newLayer = new DrawingLayer( baseFileName );
1709 newLayer->setUploadable(false);
1710 mapDocument->add(newLayer);
1711 result = mapDocument->importKML(fileName, (TrackLayer *)newLayer) ? IMPORT_OK : IMPORT_ERROR;
1712 } else
1713 result = IMPORT_ABORTED;
1714 }
1715 else if (fileName.toLower().endsWith(".csv")) {
1716 #ifndef Q_OS_SYMBIAN
1717 QApplication::restoreOverrideCursor();
1718 #endif
1719 newLayer = new DrawingLayer( baseFileName );
1720 newLayer->setUploadable(false);
1721 mapDocument->add(newLayer);
1722 result = mapDocument->importCSV(fileName, (DrawingLayer*)newLayer) ? IMPORT_OK : IMPORT_ERROR;
1723 }
1724 #ifdef USE_PROTOBUF
1725 else if (fileName.toLower().endsWith(".pbf")) {
1726 newLayer = new DrawingLayer( baseFileName );
1727 mapDocument->add(newLayer);
1728 result = mapDocument->importPBF(fileName, (DrawingLayer*)newLayer) ? IMPORT_OK : IMPORT_ERROR;
1729 }
1730 #endif
1731 else {
1732 qDebug() << "File type not recognized. If this file was recognized by previous versions, use Import GDAL function.";
1733 result = IMPORT_ERROR;
1734 }
1735
1736 if (result == IMPORT_ERROR && newLayer) {
1737 mapDocument->remove(newLayer);
1738 SAFE_DELETE(newLayer);
1739 }
1740
1741 return result;
1742 }
1743
importFileUsingGDAL(Document * mapDocument,const QString & fileName,Layer * & newLayer)1744 MainWindow::ImportStatus MainWindow::importFileUsingGDAL( Document* mapDocument, const QString& fileName, Layer*& newLayer ) {
1745 MainWindow::ImportStatus result;
1746
1747 qDebug() << "Importing file" << fileName << "using GDAL.";
1748
1749 QString baseFileName = fileName.section('/', - 1);
1750 newLayer = new DrawingLayer( baseFileName );
1751 newLayer->setUploadable(false);
1752 mapDocument->add(newLayer);
1753 result = mapDocument->importGDAL(fileName, (DrawingLayer*)newLayer) ? IMPORT_OK : IMPORT_ERROR;
1754 if (result == IMPORT_ERROR) {
1755 mapDocument->remove(newLayer);
1756 SAFE_DELETE(newLayer);
1757 }
1758
1759 return result;
1760 }
1761
1762 /**
1763 * Auxilary function to test the import functionality. May be removed when the
1764 * import is decoupled from the whole app, but as of now that is too much work.
1765 */
testImport(const QString filePath)1766 bool MainWindow::testImport(const QString filePath)
1767 {
1768 qDebug() << "Testing import with file: " << filePath;
1769 Layer* newLayer = nullptr;
1770 importFileUsingGDAL(theDocument, filePath, newLayer);
1771 if (newLayer == nullptr) {
1772 qDebug() << "FAILED";
1773 return false;
1774 } else {
1775 QRectF bbox = newLayer->boundingBox();
1776 int elements = newLayer->size();
1777 // Our test data are contained in this rectangle; only rough location is tested, mostly to check for swapper coordinates
1778 QRectF testRect = QRectF(QPointF(4,50) , QPointF(5,51) );
1779 // Return true if nonzero elements were imported and they are contained in our testRect
1780 return (elements > 0) && testRect.contains(bbox);
1781 }
1782 }
1783
1784
importFiles(Document * mapDocument,const QStringList & fileNames,QStringList * importedFileNames,bool useGdal)1785 bool MainWindow::importFiles(Document * mapDocument, const QStringList & fileNames, QStringList * importedFileNames, bool useGdal )
1786 {
1787 createProgressDialog();
1788 #ifndef Q_OS_SYMBIAN
1789 QApplication::setOverrideCursor(Qt::BusyCursor);
1790 #endif
1791
1792 bool foundImport = false;
1793
1794 QStringList filesToProcess = fileNames;
1795
1796 #ifdef GEOIMAGE
1797 /* Geotagged images should be imported as a group, let's do it first. */
1798 QStringList images = fileNames.filter(".jpg", Qt::CaseInsensitive);
1799 if (!images.isEmpty()) {
1800 theGeoImage->loadImages(images);
1801 QString cur;
1802 foreach (cur, images)
1803 filesToProcess.removeAll(cur);
1804 foundImport = true;
1805 }
1806 #endif
1807
1808 QStringListIterator it(filesToProcess);
1809 while (it.hasNext())
1810 {
1811 const QString & fn = it.next();
1812
1813 Layer* newLayer = NULL;
1814 // TODO: The passing mechanism of newLayer is evil black magic.
1815 ImportStatus fileImportResult;
1816 if (useGdal)
1817 fileImportResult = importFileUsingGDAL(mapDocument, fn, newLayer);
1818 else
1819 fileImportResult = importFile(mapDocument, fn, newLayer);
1820
1821 switch (fileImportResult) {
1822 case IMPORT_OK:
1823 foundImport = true;
1824
1825 if (importedFileNames)
1826 importedFileNames->append(fn);
1827
1828 emit content_changed();
1829 break;
1830 case IMPORT_ERROR:
1831 QMessageBox::warning(this, tr("No valid file"), tr("%1 could not be opened.").arg(fn));
1832 case IMPORT_ABORTED:
1833 // noop
1834 break;
1835 }
1836 }
1837 endBusyCursor();
1838 deleteProgressDialog();
1839 invalidateView(false);
1840
1841 return foundImport;
1842 }
1843
loadUrl(const QString & urlString)1844 void MainWindow::loadUrl(const QString& urlString)
1845 {
1846 qDebug() << "Loading url: " << urlString;
1847 loadUrl(QUrl(urlString));
1848 }
1849
loadUrl(const QUrl & theUrl)1850 void MainWindow::loadUrl(const QUrl& theUrl)
1851 {
1852 activateWindow();
1853
1854 #ifdef QT5
1855 QUrlQuery theQuery(theUrl);
1856 #define theQuery theQuery
1857 #else
1858 #define theQuery theUrl
1859 #endif
1860 if (theUrl.path() == "/load_object") {
1861 QString obj = theQuery.queryItemValue("objects");
1862 IFeature::FId mId;
1863 if (obj.startsWith("n")) {
1864 obj.remove("n");
1865 mId.type = IFeature::Point;
1866 mId.numId = obj.toLongLong();
1867 } else if (obj.startsWith("w")) {
1868 obj.remove("w");
1869 mId.type = IFeature::LineString;
1870 mId.numId = obj.toLongLong();
1871 } else if (obj.startsWith("r")) {
1872 obj.remove("r");
1873 mId.type = IFeature::LineString;
1874 mId.numId = obj.toLongLong();
1875 } else {
1876 QMessageBox::critical(this, tr("Incoming Remote Control Request"),
1877 tr("Wanted to load object '%1', but don't know how to do that. Sorry.").arg(theUrl.toString()));
1878 return;
1879 }
1880 Feature* F = theDocument->getFeature(mId);
1881 if (!F) {
1882 /* The feature is missing, download it first. */
1883 createProgressDialog();
1884 downloadFeature(this, mId, theDocument, NULL);
1885 deleteProgressDialog();
1886 F = theDocument->getFeature(mId);
1887 }
1888 /* The feature is on our map, just select it. */
1889 if (F) { /* If F existed, e.g., was not deleted*/
1890 if (theView) {
1891 theView->setViewport(F->boundingBox(), theView->rect());
1892 on_fileDownloadMoreAction_triggered();
1893 }
1894 properties()->setSelection(0);
1895 properties()->addSelection(F);
1896 emit content_changed();
1897 }
1898 } else if (theUrl.path() == "/add_node") {
1899 qreal lat = theQuery.queryItemValue("lat").toDouble();
1900 qreal lon = theQuery.queryItemValue("lon").toDouble();
1901 QString addtagsstring=theQuery.queryItemValue("addtags");
1902 Coord pos=Coord(lon,lat);
1903 Node* N;
1904 CommandList* theList;
1905 Layer* l=document()->getDirtyOrOriginLayer();
1906 N = g_backend.allocNode(g_Merk_MainWindow->document()->getDirtyOrOriginLayer(), pos);
1907 N->setDirtyLevel(1);
1908 QString poiName=".";
1909 if (addtagsstring.size()>0) {
1910 QStringList addtags = QUrl::fromPercentEncoding(addtagsstring.toUtf8()).split("|");
1911 foreach (const QString &tag, addtags) {
1912 QStringList kv = tag.split("=");
1913 QString k=kv[0];
1914 QString v;
1915 if (kv.size()>0) {
1916 v=kv[1];
1917 if (k=="name") poiName=v;
1918 }
1919 N->setTag(k,v);
1920 }
1921 }
1922 theList = new CommandList(MainWindow::tr("Remote add POI %1 %2").arg(N->id().numId).arg(poiName), N);
1923 theList->add(new AddFeatureCommand(l,N,true));
1924 g_Merk_MainWindow->properties()->setSelection(0);
1925 N->updateMeta();
1926 document()->addHistory(theList);
1927 properties()->setSelection(0);
1928 properties()->addSelection(N);
1929 theView->invalidate(true, true, false);
1930 CoordBox cb;
1931 cb = N->boundingBox();
1932 if (!cb.isNull()) {
1933 CoordBox mini(cb.center()-COORD_ENLARGE, cb.center()+COORD_ENLARGE);
1934 cb.merge(mini);
1935 cb = cb.zoomed(1.1);
1936 theView->setViewport(cb, theView->rect());
1937 }
1938 emit content_changed();
1939 } else if (theUrl.path() == "/load_and_zoom") {
1940 qreal t = theQuery.queryItemValue("top").toDouble();
1941 qreal b = theQuery.queryItemValue("bottom").toDouble();
1942 qreal r = theQuery.queryItemValue("right").toDouble();
1943 qreal l = theQuery.queryItemValue("left").toDouble();
1944
1945 if (theView) {
1946 CoordBox vp(Coord(l,b), Coord(r,t));
1947 theView->setViewport(vp, theView->rect());
1948 on_fileDownloadMoreAction_triggered();
1949 }
1950 properties()->setSelection(0);
1951
1952 Feature* F;
1953 IFeature::FId mId;
1954 QString sel = theQuery.queryItemValue("select");
1955 if (!sel.isNull()) {
1956 QStringList sl = sel.split(",");
1957 foreach (QString f, sl) {
1958 if (f.startsWith("node")) {
1959 f.remove("node");
1960 mId.type = IFeature::Point;
1961 mId.numId = f.toLongLong();
1962 } else if (f.startsWith("way")) {
1963 f.remove("way");
1964 mId.type = IFeature::LineString;
1965 mId.numId = f.toLongLong();
1966 } else if (f.startsWith("relation")) {
1967 f.remove("relation");
1968 mId.type = IFeature::OsmRelation;
1969 mId.numId = f.toLongLong();
1970 }
1971 F = theDocument->getFeature(mId);
1972 if (F)
1973 properties()->addSelection(F);
1974 }
1975 }
1976 } else {
1977 QMessageBox::critical(this, tr("Incoming Remote control request"), tr("Unknown action url: %1").arg(theUrl.toString()));
1978 }
1979 #undef theQuery
1980 }
1981
on_fileOpenAction_triggered()1982 void MainWindow::on_fileOpenAction_triggered()
1983 {
1984 if (hasUnsavedChanges() && !mayDiscardUnsavedChanges(this))
1985 return;
1986
1987 QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), QString(), p->FILTER_OPEN_NATIVE );
1988
1989 if (!fileName.isNull())
1990 loadDocument(fileName);
1991 }
1992
on_fileUploadAction_triggered()1993 void MainWindow::on_fileUploadAction_triggered()
1994 {
1995
1996 if (QString(qVersion()) < "4.3.3")
1997 {
1998 if (QMessageBox::question(this,
1999 tr("Old Qt version detected"),
2000 tr("Your setup uses Qt %1, which contains various known errors in uploading "
2001 "data to OpenStreetMap leading to 401 server response codes. Are you sure you want to continue (which is not "
2002 "recommended).\n"
2003 "For more information see http://wiki.openstreetmap.org/index.php/Problem_uploading_with_Merkaartor").arg(qVersion()),QMessageBox::Yes|QMessageBox::No) != QMessageBox::Yes)
2004 return;
2005 }
2006
2007 while (M_PREFS->getOsmUser().isEmpty()) {
2008 int ret = QMessageBox::warning(this, tr("Upload OSM"), tr("You don't seem to have specified your\n"
2009 "OpenStreetMap username and password.\nDo you want to do this now?"), QMessageBox::Yes | QMessageBox::No);
2010 if (ret == QMessageBox::Yes) {
2011 toolsPreferencesAction_triggered(true);
2012 } else
2013 return;
2014 }
2015 on_editPropertiesAction_triggered();
2016 syncOSM(M_PREFS->getOsmApiUrl(), M_PREFS->getOsmUser(), M_PREFS->getOsmPassword());
2017
2018 theDocument->history().updateActions();
2019 theDirty->updateList();
2020 invalidateView();
2021 }
2022
warnMapDownloadFailed()2023 void MainWindow::warnMapDownloadFailed() {
2024 QMessageBox::warning(this, tr("Error downloading"), tr("The map could not be downloaded"));
2025 }
2026
on_fileDownloadAction_triggered()2027 void MainWindow::on_fileDownloadAction_triggered()
2028 {
2029 createProgressDialog();
2030
2031 if (downloadOSM(this, theView->viewport(), theDocument)) {
2032 on_editPropertiesAction_triggered();
2033 } else
2034 warnMapDownloadFailed();
2035
2036 deleteProgressDialog();
2037
2038 updateBookmarksMenu();
2039
2040 emit content_changed();
2041 }
2042
on_fileDownloadMoreAction_triggered()2043 void MainWindow::on_fileDownloadMoreAction_triggered()
2044 {
2045 createProgressDialog();
2046
2047 if (!downloadMoreOSM(this, theView->viewport(), theDocument)) {
2048 warnMapDownloadFailed();
2049 }
2050
2051 deleteProgressDialog();
2052
2053 emit content_changed();
2054 }
2055
on_layersMapdustAction_triggered()2056 void MainWindow::on_layersMapdustAction_triggered()
2057 {
2058 SpecialLayer* sl = NULL;
2059 for (int i=0; i<theDocument->layerSize(); ++i) {
2060 if (theDocument->getLayer(i)->classType() == Layer::MapDustLayer) {
2061 sl = dynamic_cast<SpecialLayer*>(theDocument->getLayer(i));
2062 while (sl->size())
2063 {
2064 sl->deleteFeature(sl->get(0));
2065 }
2066 }
2067 }
2068
2069 createProgressDialog();
2070
2071 if (!::downloadMapdust(this, theView->viewport(), theDocument, sl)) {
2072 QMessageBox::warning(this, tr("Error downloading MapDust"), tr("The MapDust bugs could not be downloaded"));
2073 }
2074
2075 deleteProgressDialog();
2076 }
2077
downloadFeatures(const QList<Feature * > & aDownloadList)2078 void MainWindow::downloadFeatures(const QList<Feature*>& aDownloadList)
2079 {
2080 createProgressDialog();
2081
2082 if (!::downloadFeatures(this, aDownloadList, theDocument)) {
2083 QMessageBox::warning(this, tr("Error downloading"), tr("The map could not be downloaded"));
2084 }
2085
2086 deleteProgressDialog();
2087
2088 emit content_changed();
2089
2090 }
2091
on_fileWorkOfflineAction_triggered()2092 void MainWindow::on_fileWorkOfflineAction_triggered()
2093 {
2094 M_PREFS->setOfflineMode(!M_PREFS->getOfflineMode());
2095 updateMenu();
2096 }
2097
on_filePrintAction_triggered()2098 void MainWindow::on_filePrintAction_triggered()
2099 {
2100 NativeRenderDialog osmR(theDocument, theView->viewport(), this);
2101 osmR.exec();
2102 }
2103
on_filePropertiesAction_triggered()2104 void MainWindow::on_filePropertiesAction_triggered()
2105 {
2106 QDialog dlg(this);
2107 Ui::PropertiesDialog Prop;
2108 Prop.setupUi(&dlg);
2109
2110 QString h;
2111 h += theView->toPropertiesHtml();
2112 h += "<br/>";
2113 h += theDocument->toPropertiesHtml();
2114 Prop.textBrowser->setHtml(h);
2115
2116 dlg.exec();
2117 }
2118
on_helpAboutAction_triggered()2119 void MainWindow::on_helpAboutAction_triggered()
2120 {
2121 QDialog dlg(this);
2122 Ui::AboutDialog About;
2123 About.setupUi(&dlg);
2124 dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowContextHelpButtonHint);
2125 dlg.setWindowFlags(dlg.windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
2126 About.Version->setText(About.Version->text().arg(STRINGIFY(REVISION)));
2127 About.QTVersion->setText(About.QTVersion->text().arg(qVersion()).arg(QT_VERSION_STR));
2128 PJ_INFO projVer = proj_info();
2129 About.ProjVersion->setText(About.ProjVersion->text().arg(QString("%1.%2.%3").arg(projVer.major).arg(projVer.minor).arg(projVer.patch)));
2130 About.GdalVersion->setText(About.GdalVersion->text().arg(GDAL_RELEASE_NAME));
2131
2132 QFile ct(":/Utils/CHANGELOG");
2133 ct.open(QIODevice::ReadOnly);
2134 QTextStream cl(&ct);
2135 About.txtChangelog->setPlainText(cl.readAll());
2136 QPixmap px(":/Utils/Merkaartor_About.png");
2137 About.pxIcon->setPixmap(px);
2138 About.lblUrl->setOpenExternalLinks(true);
2139 dlg.exec();
2140 }
2141
on_viewZoomAllAction_triggered()2142 void MainWindow::on_viewZoomAllAction_triggered()
2143 {
2144 QPair<bool, CoordBox> BBox(theDocument->boundingBox());
2145 if (BBox.first) {
2146 BBox.second.resize(1.01);
2147 theView->setViewport(BBox.second, theView->rect());
2148 invalidateView();
2149 }
2150 }
2151
on_viewZoomInAction_triggered()2152 void MainWindow::on_viewZoomInAction_triggered()
2153 {
2154 theView->zoomIn();
2155 }
2156
on_viewZoomOutAction_triggered()2157 void MainWindow::on_viewZoomOutAction_triggered()
2158 {
2159 theView->zoomOut();
2160 }
2161
on_viewZoomWindowAction_triggered()2162 void MainWindow::on_viewZoomWindowAction_triggered()
2163 {
2164 launchInteraction(new ZoomInteraction(this));
2165 }
2166
on_viewLockZoomAction_triggered()2167 void MainWindow::on_viewLockZoomAction_triggered()
2168 {
2169 M_PREFS->setZoomBoris(!M_PREFS->getZoomBoris());
2170 SetOptionValue(p->renderOptions, RendererOptions::LockZoom, M_PREFS->getZoomBoris());
2171 ui->viewLockZoomAction->setChecked(M_PREFS->getZoomBoris());
2172 ImageMapLayer* l = NULL;
2173 for (LayerIterator<ImageMapLayer*> ImgIt(theDocument); !ImgIt.isEnd(); ++ImgIt) {
2174 l = ImgIt.get();
2175 break;
2176 }
2177 if (l && l->isTiled()) {
2178 theView->projection().setProjectionType(l->projection());
2179 theView->setViewport(theView->viewport(), theView->rect());
2180 }
2181 theView->adjustZoomToBoris();
2182 updateProjectionMenu();
2183 invalidateView();
2184 }
2185
on_viewDownloadedAction_triggered()2186 void MainWindow::on_viewDownloadedAction_triggered()
2187 {
2188 M_PREFS->setDownloadedVisible(!M_PREFS->getDownloadedVisible());
2189 SetOptionValue(p->renderOptions, RendererOptions::DownloadedVisible, M_PREFS->getDownloadedVisible());
2190 ui->viewDownloadedAction->setChecked(M_PREFS->getDownloadedVisible());
2191 invalidateView();
2192 }
2193
on_viewDirtyAction_triggered()2194 void MainWindow::on_viewDirtyAction_triggered()
2195 {
2196 M_PREFS->setDirtyVisible(!M_PREFS->getDirtyVisible());
2197 SetOptionValue(p->renderOptions, RendererOptions::DirtyVisible, M_PREFS->getDirtyVisible());
2198 ui->viewDirtyAction->setChecked(M_PREFS->getDirtyVisible());
2199 invalidateView();
2200 }
2201
on_viewScaleAction_triggered()2202 void MainWindow::on_viewScaleAction_triggered()
2203 {
2204 M_PREFS->setScaleVisible(!M_PREFS->getScaleVisible());
2205 SetOptionValue(p->renderOptions, RendererOptions::ScaleVisible, M_PREFS->getScaleVisible());
2206 ui->viewScaleAction->setChecked(M_PREFS->getScaleVisible());
2207 invalidateView();
2208 }
2209
on_viewPhotosAction_triggered()2210 void MainWindow::on_viewPhotosAction_triggered()
2211 {
2212 M_PREFS->setPhotosVisible(!M_PREFS->getPhotosVisible());
2213 SetOptionValue(p->renderOptions, RendererOptions::PhotosVisible, M_PREFS->getPhotosVisible());
2214 ui->viewPhotosAction->setChecked(M_PREFS->getPhotosVisible());
2215 invalidateView();
2216 }
2217
on_viewShowLatLonGridAction_triggered()2218 void MainWindow::on_viewShowLatLonGridAction_triggered()
2219 {
2220 M_PREFS->setLatLonGridVisible(!M_PREFS->getLatLonGridVisible());
2221 SetOptionValue(p->renderOptions, RendererOptions::LatLonGridVisible, M_PREFS->getLatLonGridVisible());
2222 ui->viewShowLatLonGridAction->setChecked(M_PREFS->getLatLonGridVisible());
2223 invalidateView();
2224 }
2225
on_viewStyleBackgroundAction_triggered()2226 void MainWindow::on_viewStyleBackgroundAction_triggered()
2227 {
2228 M_PREFS->setBackgroundVisible(!M_PREFS->getBackgroundVisible());
2229 SetOptionValue(p->renderOptions, RendererOptions::BackgroundVisible, M_PREFS->getBackgroundVisible());
2230 ui->viewStyleBackgroundAction->setChecked(M_PREFS->getBackgroundVisible());
2231 invalidateView();
2232 }
2233
on_viewStyleForegroundAction_triggered()2234 void MainWindow::on_viewStyleForegroundAction_triggered()
2235 {
2236 M_PREFS->setForegroundVisible(!M_PREFS->getForegroundVisible());
2237 SetOptionValue(p->renderOptions, RendererOptions::ForegroundVisible, M_PREFS->getForegroundVisible());
2238 ui->viewStyleForegroundAction->setChecked(M_PREFS->getForegroundVisible());
2239 invalidateView();
2240 }
2241
on_viewStyleTouchupAction_triggered()2242 void MainWindow::on_viewStyleTouchupAction_triggered()
2243 {
2244 M_PREFS->setTouchupVisible(!M_PREFS->getTouchupVisible());
2245 SetOptionValue(p->renderOptions, RendererOptions::TouchupVisible, M_PREFS->getTouchupVisible());
2246 ui->viewStyleTouchupAction->setChecked(M_PREFS->getTouchupVisible());
2247 invalidateView();
2248 }
2249
on_viewNamesAction_triggered()2250 void MainWindow::on_viewNamesAction_triggered()
2251 {
2252 M_PREFS->setNamesVisible(!M_PREFS->getNamesVisible());
2253 SetOptionValue(p->renderOptions, RendererOptions::NamesVisible, M_PREFS->getNamesVisible());
2254 ui->viewNamesAction->setChecked(M_PREFS->getNamesVisible());
2255 invalidateView();
2256 }
2257
on_viewVirtualNodesAction_triggered()2258 void MainWindow::on_viewVirtualNodesAction_triggered()
2259 {
2260 M_PREFS->setVirtualNodesVisible(!M_PREFS->getVirtualNodesVisible());
2261 SetOptionValue(p->renderOptions, RendererOptions::VirtualNodesVisible, M_PREFS->getVirtualNodesVisible());
2262 ui->viewVirtualNodesAction->setChecked(M_PREFS->getVirtualNodesVisible());
2263 invalidateView();
2264 }
2265
on_viewTrackPointsAction_triggered()2266 void MainWindow::on_viewTrackPointsAction_triggered()
2267 {
2268 M_PREFS->setTrackPointsVisible(!M_PREFS->getTrackPointsVisible());
2269 SetOptionValue(p->renderOptions, RendererOptions::NodesVisible, M_PREFS->getTrackPointsVisible());
2270 ui->viewTrackPointsAction->setChecked(M_PREFS->getTrackPointsVisible());
2271 invalidateView();
2272 }
2273
on_viewTrackSegmentsAction_triggered()2274 void MainWindow::on_viewTrackSegmentsAction_triggered()
2275 {
2276 M_PREFS->setTrackSegmentsVisible(!M_PREFS->getTrackSegmentsVisible());
2277 SetOptionValue(p->renderOptions, RendererOptions::TrackSegmentVisible, M_PREFS->getTrackSegmentsVisible());
2278 ui->viewTrackSegmentsAction->setChecked(M_PREFS->getTrackSegmentsVisible());
2279 invalidateView();
2280 }
2281
on_viewRelationsAction_triggered()2282 void MainWindow::on_viewRelationsAction_triggered()
2283 {
2284 M_PREFS->setRelationsVisible(!M_PREFS->getRelationsVisible());
2285 SetOptionValue(p->renderOptions, RendererOptions::RelationsVisible, M_PREFS->getRelationsVisible());
2286 ui->viewRelationsAction->setChecked(M_PREFS->getRelationsVisible());
2287 invalidateView();
2288 }
2289
on_viewGotoAction_triggered()2290 void MainWindow::on_viewGotoAction_triggered()
2291 {
2292 GotoDialog* Dlg = new GotoDialog(theView, this);
2293 if (Dlg->exec() == QDialog::Accepted) {
2294 if (!Dlg->newViewport().isNull() && !Dlg->newViewport().isEmpty()) {
2295 theView->setViewport(Dlg->newViewport(), theView->rect());
2296 invalidateView();
2297 }
2298 }
2299 delete Dlg;
2300 }
2301
on_viewArrowsNeverAction_triggered(bool checked)2302 void MainWindow::on_viewArrowsNeverAction_triggered(bool checked)
2303 {
2304 if (checked) {
2305 M_PREFS->setDirectionalArrowsVisible(RendererOptions::ArrowsNever);
2306 p->renderOptions.arrowOptions = RendererOptions::ArrowsNever;
2307 invalidateView();
2308 }
2309 }
2310
on_viewArrowsOnewayAction_triggered(bool checked)2311 void MainWindow::on_viewArrowsOnewayAction_triggered(bool checked)
2312 {
2313 if (checked) {
2314 M_PREFS->setDirectionalArrowsVisible(RendererOptions::ArrowsOneway);
2315 p->renderOptions.arrowOptions = RendererOptions::ArrowsOneway;
2316 invalidateView();
2317 }
2318 }
2319
on_viewArrowsAlwaysAction_triggered(bool checked)2320 void MainWindow::on_viewArrowsAlwaysAction_triggered(bool checked)
2321 {
2322 if (checked) {
2323 M_PREFS->setDirectionalArrowsVisible(RendererOptions::ArrowsAlways);
2324 p->renderOptions.arrowOptions = RendererOptions::ArrowsAlways;
2325 invalidateView();
2326 }
2327 }
2328
on_fileNewAction_triggered()2329 void MainWindow::on_fileNewAction_triggered()
2330 {
2331 launchInteraction(0);
2332 p->theProperties->setSelection(0);
2333
2334 if (theDocument)
2335 saveTemplateDocument(TEMPLATE_DOCUMENT);
2336
2337 if (!theDocument || !hasUnsavedChanges() || mayDiscardUnsavedChanges(this)) {
2338 p->theFeats->invalidate();
2339 SAFE_DELETE(theDocument);
2340 theView->setDocument(NULL);
2341 p->latSaveDirtyLevel = 0;
2342 g_feat_rndId = 0;
2343
2344 if (M_PREFS->getHasAutoLoadDocument())
2345 loadTemplateDocument(M_PREFS->getAutoLoadDocumentFilename());
2346 else if (!g_Merk_IgnoreStartupTemplate)
2347 loadTemplateDocument(TEMPLATE_DOCUMENT);
2348
2349 if (!theDocument) {
2350 theDocument = new Document(theLayers);
2351 theDocument->addDefaultLayers();
2352 theView->projection().setProjectionType(M_PREFS->getProjectionType());
2353 theView->setViewport(WORLD_COORDBOX, theView->rect());
2354 }
2355 theView->setDocument(theDocument);
2356 theDocument->history().setActions(ui->editUndoAction, ui->editRedoAction, ui->fileUploadAction);
2357 connect (theDocument, SIGNAL(historyChanged()), theDirty, SLOT(updateList()));
2358 connect (theDocument, SIGNAL(historyChanged()), this, SIGNAL(content_changed()));
2359 connect(theDocument, SIGNAL(imageRequested(ImageMapLayer*)),
2360 this, SLOT(onImagerequested(ImageMapLayer*)), Qt::QueuedConnection);
2361 connect(theDocument, SIGNAL(imageReceived(ImageMapLayer*)),
2362 this, SLOT(onImagereceived(ImageMapLayer*)), Qt::QueuedConnection);
2363 connect(theDocument, SIGNAL(loadingFinished(ImageMapLayer*)),
2364 this, SLOT(onLoadingfinished(ImageMapLayer*)), Qt::QueuedConnection);
2365 theDirty->updateList();
2366
2367 currentProjectFile.clear();
2368 setWindowTitle(QString("%1 - %2").arg(theDocument->title()).arg(p->title));
2369
2370 updateProjectionMenu();
2371
2372 emit content_changed();
2373 on_editPropertiesAction_triggered();
2374 adjustLayers(true);
2375 }
2376
2377 #ifdef GEOIMAGE
2378 if (theGeoImage)
2379 theGeoImage->clear();
2380 #endif
2381 }
2382
on_createDoubleWayAction_triggered()2383 void MainWindow::on_createDoubleWayAction_triggered()
2384 {
2385 launchInteraction(new CreateDoubleWayInteraction(this));
2386 theInfo->setHtml(theView->interaction()->toHtml());
2387 }
2388
on_createRoundaboutAction_triggered()2389 void MainWindow::on_createRoundaboutAction_triggered()
2390 {
2391 launchInteraction(new CreateRoundaboutInteraction(this));
2392 theInfo->setHtml(theView->interaction()->toHtml());
2393 }
2394
2395 namespace {
2396
2397 // TODO: Move Qt4/Qt5 wrappers to a separate file.
getInteger(QWidget * parent,const QString & title,const QString & label,int value=0,int minimum=INT_MIN,int maximum=INT_MAX,int step=1,bool * ok=NULL)2398 int getInteger(QWidget* parent, const QString& title, const QString& label, int value = 0, int minimum = INT_MIN, int maximum = INT_MAX, int step = 1, bool* ok = NULL) {
2399 #ifdef QT5
2400 return QInputDialog::getInt(parent, title, label, value, minimum, maximum, step, ok);
2401 #else
2402 return QInputDialog::getInteger(parent, title, label, value, minimum, maximum, step, ok);
2403 #endif
2404 }
2405
2406 }
2407
on_createPolygonAction_triggered()2408 void MainWindow::on_createPolygonAction_triggered()
2409 {
2410 QList< QPair <QString, QString> > tags;
2411 int Sides = getInteger(this, tr("Create Polygon"), tr("Specify the number of sides"), M_PREFS->getPolygonSides(), 3);
2412 M_PREFS->setPolygonSides(Sides);
2413 launchInteraction(new CreatePolygonInteraction(this, Sides, tags));
2414 theInfo->setHtml(theView->interaction()->toHtml());
2415 }
2416
on_createRectangleAction_triggered()2417 void MainWindow::on_createRectangleAction_triggered()
2418 {
2419 QList< QPair <QString, QString> > tags;
2420 tags << qMakePair(QString("building"), QString("yes"));
2421 launchInteraction(new CreatePolygonInteraction(this, 4, tags));
2422 theInfo->setHtml(theView->interaction()->toHtml());
2423 }
2424
on_createRoadAction_triggered()2425 void MainWindow::on_createRoadAction_triggered()
2426 {
2427 Node * firstPoint = NULL;
2428
2429 if (p->theProperties->selectionSize() == 1)
2430 {
2431 Feature * feature = p->theProperties->selection(0);
2432 firstPoint = dynamic_cast<Node*>(feature);
2433 }
2434
2435 launchInteraction(new CreateSingleWayInteraction(this, firstPoint, false));
2436 theInfo->setHtml(theView->interaction()->toHtml());
2437 }
2438
on_createCurvedRoadAction_triggered()2439 void MainWindow::on_createCurvedRoadAction_triggered()
2440 {
2441 launchInteraction(new CreateSingleWayInteraction(this, NULL, true));
2442 theInfo->setHtml(theView->interaction()->toHtml());
2443 }
2444
on_createAreaAction_triggered()2445 void MainWindow::on_createAreaAction_triggered()
2446 {
2447 launchInteraction(new CreateAreaInteraction(this));
2448 theInfo->setHtml(theView->interaction()->toHtml());
2449 }
2450
on_createNodeAction_triggered()2451 void MainWindow::on_createNodeAction_triggered()
2452 {
2453 launchInteraction(new CreateNodeInteraction(this));
2454 theInfo->setHtml(theView->interaction()->toHtml());
2455 }
2456
on_markBridgeAction_triggered()2457 void MainWindow::on_markBridgeAction_triggered()
2458 {
2459 launchInteraction(new BuildBridgeInteraction(this));
2460 theInfo->setHtml(theView->interaction()->toHtml());
2461 }
2462
on_roadJoinAction_triggered()2463 void MainWindow::on_roadJoinAction_triggered()
2464 {
2465 CommandList* theList = new CommandList(MainWindow::tr("Join Ways"), NULL);
2466 joinRoads(theDocument, theList, p->theProperties);
2467 if (theList->empty())
2468 delete theList;
2469 else
2470 {
2471 theDocument->addHistory(theList);
2472 emit content_changed();
2473 invalidateView();
2474 }
2475 }
2476
on_roadSplitAction_triggered()2477 void MainWindow::on_roadSplitAction_triggered()
2478 {
2479 CommandList* theList = new CommandList(MainWindow::tr("Split Ways"), NULL);
2480 splitRoads(theDocument, theList, p->theProperties);
2481 if (theList->empty())
2482 delete theList;
2483 else
2484 {
2485 theDocument->addHistory(theList);
2486 emit content_changed();
2487 invalidateView();
2488 }
2489 }
2490
on_roadBreakAction_triggered()2491 void MainWindow::on_roadBreakAction_triggered()
2492 {
2493 CommandList* theList = new CommandList(MainWindow::tr("Break Ways"), NULL);
2494 breakRoads(theDocument, theList, p->theProperties);
2495 if (theList->empty())
2496 delete theList;
2497 else
2498 {
2499 theDocument->addHistory(theList);
2500 emit content_changed();
2501 invalidateView();
2502 }
2503 }
2504
on_roadSimplifyAction_triggered()2505 void MainWindow::on_roadSimplifyAction_triggered()
2506 {
2507 CommandList* theList = new CommandList(MainWindow::tr("Simplify Ways"), NULL);
2508 qreal threshold = 3.0; // in metres; TODO: allow user-specified threshold
2509 simplifyRoads(theDocument, theList, p->theProperties, threshold);
2510 if (theList->empty())
2511 delete theList;
2512 else
2513 {
2514 theDocument->addHistory(theList);
2515 emit content_changed();
2516 invalidateView();
2517 }
2518 }
2519
on_featureSelectChildrenAction_triggered()2520 void MainWindow::on_featureSelectChildrenAction_triggered()
2521 {
2522 QList<Feature*> theFeatures;
2523 foreach (Feature* F, p->theProperties->selection()) {
2524 theFeatures << F;
2525 for (int i=0; i<F->size(); ++i)
2526 theFeatures << F->get(i);
2527 }
2528 p->theProperties->setSelection(theFeatures);
2529 p->theProperties->checkMenuStatus();
2530 invalidateView();
2531 }
2532
on_featureSelectParentsAction_triggered()2533 void MainWindow::on_featureSelectParentsAction_triggered()
2534 {
2535 QList<Feature*> theFeatures;
2536 foreach (Feature* F, p->theProperties->selection()) {
2537 for (int i=0; i<F->sizeParents(); ++i) {
2538 Feature* Feat = STATIC_CAST_FEATURE(F->getParent(i));
2539 theFeatures << Feat;
2540 }
2541 }
2542 p->theProperties->setSelection(theFeatures);
2543 p->theProperties->checkMenuStatus();
2544 invalidateView();
2545 }
2546
on_featureDownloadMissingChildrenAction_triggered()2547 void MainWindow::on_featureDownloadMissingChildrenAction_triggered()
2548 {
2549 #ifndef _MOBILE
2550 QList<Feature*> toResolve;
2551 foreach (Feature* F, p->theProperties->selection()) {
2552 if (F->notEverythingDownloaded()) {
2553 toResolve.push_back(F);
2554 }
2555 }
2556 downloadFeatures(toResolve);
2557 #endif
2558 }
2559
on_featureDeleteAction_triggered()2560 void MainWindow::on_featureDeleteAction_triggered()
2561 {
2562 Feature* F = p->theProperties->selection(0);
2563 if (!F)
2564 return;
2565
2566 while (F->sizeParents()) {
2567 Feature* p = (Feature*)(F->getParent(0));
2568 if (p)
2569 p->remove(F);
2570 }
2571 F->layer()->deleteFeature(F);
2572 p->theProperties->setSelection(0);
2573
2574 emit content_changed();
2575 invalidateView();
2576 }
2577
on_featureCommitAction_triggered()2578 void MainWindow::on_featureCommitAction_triggered()
2579 {
2580 CommandList* theList = new CommandList(MainWindow::tr("Force Feature upload"), NULL);
2581 commitFeatures(theDocument, theList, p->theProperties);
2582 if (theList->empty())
2583 delete theList;
2584 else
2585 {
2586 theDocument->addHistory(theList);
2587 invalidateView();
2588 }
2589 }
2590
on_roadCreateJunctionAction_triggered()2591 void MainWindow::on_roadCreateJunctionAction_triggered()
2592 {
2593 CommandList* theList = new CommandList(MainWindow::tr("Create Junction"), NULL);
2594 int n = createJunction(theDocument, theList, p->theProperties, false);
2595 if (n > 1) {
2596 MDiscardableMessage dlg(view(),
2597 MainWindow::tr("Multiple intersection."),
2598 MainWindow::tr("Those roads have multiple intersections.\nDo you still want to create a junction for each one (Unwanted junctions can still be deleted afterhand)?"));
2599 if (dlg.check() != QDialog::Accepted)
2600 return;
2601 }
2602 createJunction(theDocument, theList, p->theProperties, true);
2603
2604 if (theList->empty())
2605 delete theList;
2606 else
2607 {
2608 theDocument->addHistory(theList);
2609 invalidateView();
2610 }
2611 }
2612
on_roadAddStreetNumbersAction_triggered()2613 void MainWindow::on_roadAddStreetNumbersAction_triggered()
2614 {
2615 CommandList* theList = new CommandList(MainWindow::tr("Add Street Numbers"), NULL);
2616
2617 addStreetNumbers(theDocument, theList, p->theProperties);
2618
2619 if (theList->empty())
2620 delete theList;
2621 else
2622 {
2623 theDocument->addHistory(theList);
2624 invalidateView();
2625 }
2626 }
2627
on_roadSubdivideAction_triggered()2628 void MainWindow::on_roadSubdivideAction_triggered()
2629 {
2630 #if QT_VERSION < 0x040500
2631 {
2632 int divisions = getInteger(this, tr("Number of segments to divide into"), tr("Specify the number of segments"), 2, 99);
2633 #else
2634 QInputDialog *Dlg = new QInputDialog(this);
2635 Dlg->setInputMode(QInputDialog::IntInput);
2636 Dlg->setIntRange(2, 99);
2637 Dlg->setLabelText(tr("Number of segments to divide into"));
2638 if (Dlg->exec() == QDialog::Accepted) {
2639 int divisions = Dlg->intValue();
2640 #endif
2641 CommandList* theList = new CommandList(MainWindow::tr("Subdivide way into %1").arg(divisions), NULL);
2642 subdivideRoad(theDocument, theList, p->theProperties, divisions);
2643 if (theList->empty())
2644 delete theList;
2645 else {
2646 theDocument->addHistory(theList);
2647 invalidateView();
2648 }
2649 }
2650 #if QT_VERSION > 0x040499
2651 delete Dlg;
2652 #endif
2653 }
2654
2655 void MainWindow::on_roadAxisAlignAction_triggered()
2656 {
2657 const unsigned int max_axes = 16;
2658 bool ok;
2659 unsigned int axes;
2660
2661 axes = axisAlignGuessAxes(p->theProperties, view()->projection(), max_axes);
2662 if (!axes)
2663 axes = 4;
2664 axes = getInteger(this, tr("Axis Align"),
2665 tr("Specify the number of regular axes to align edges on (e.g. 4 for rectangular)"),
2666 axes, 3, max_axes, 1, &ok);
2667 if (!ok)
2668 return;
2669
2670 // Create a command description
2671 const QString special_names[] = {
2672 tr("triangular"),
2673 tr("rectangular"),
2674 tr("pentagonal"),
2675 tr("hexagonal"),
2676 tr("heptagonal"),
2677 tr("octagonal"),
2678 };
2679 QString command_name;
2680 if (axes < 3 + (sizeof(special_names)/sizeof(special_names[0])))
2681 command_name = tr("Align onto %1 axes").arg(special_names[axes-3]);
2682 else
2683 command_name = tr("Align onto %1 regular axes").arg(axes);
2684
2685 // Do the manipulation
2686 CommandList* theList = new CommandList(command_name, NULL);
2687 AxisAlignResult result = axisAlignRoads(theDocument, theList, p->theProperties, view()->projection(), axes);
2688 if (result != AxisAlignSuccess || theList->empty()) {
2689 if (result == AxisAlignSharpAngles)
2690 QMessageBox::critical(this, tr("Unable to align to axes"),
2691 tr("Align to axes operation failed. Please adjust any sharp corners and try again."));
2692 else if (result == AxisAlignFail)
2693 QMessageBox::critical(this, tr("Unable to align to axes"),
2694 tr("Align to axes operation failed and did not converge on a solution."));
2695 delete theList;
2696 } else {
2697 theDocument->addHistory(theList);
2698 invalidateView();
2699 }
2700 }
2701
2702 void MainWindow::on_roadExtrudeAction_triggered()
2703 {
2704 launchInteraction(new ExtrudeInteraction(this));
2705 theInfo->setHtml(theView->interaction()->toHtml());
2706 }
2707
2708 void MainWindow::on_roadBingExtractAction_triggered()
2709 {
2710 CommandList* theList = new CommandList(MainWindow::tr("Bing Extract"), NULL);
2711 bingExtract(theDocument, theList, p->theProperties, theView->viewport());
2712 if (theList->empty())
2713 delete theList;
2714 else
2715 {
2716 theDocument->addHistory(theList);
2717 // theView->properties()->setSelection(F);
2718 invalidateView();
2719 }
2720 }
2721
2722 void MainWindow::on_nodeAlignAction_triggered()
2723 {
2724 //MapFeature* F = theView->properties()->selection(0);
2725 CommandList* theList = new CommandList(MainWindow::tr("Align Nodes"), NULL);
2726 alignNodes(theDocument, theList, p->theProperties);
2727 if (theList->empty())
2728 delete theList;
2729 else
2730 {
2731 theDocument->addHistory(theList);
2732 // theView->properties()->setSelection(F);
2733 invalidateView();
2734 }
2735 }
2736
2737 void MainWindow::on_nodeSpreadAction_triggered()
2738 {
2739 CommandList* theList = new CommandList(MainWindow::tr("Spread Nodes"), NULL);
2740 spreadNodes(theDocument, theList, p->theProperties);
2741 if (theList->empty())
2742 delete theList;
2743 else
2744 {
2745 theDocument->addHistory(theList);
2746 invalidateView();
2747 }
2748 }
2749
2750 void MainWindow::on_nodeMergeAction_triggered()
2751 {
2752 Feature* F = p->theProperties->selection(0);
2753 CommandList* theList = new CommandList(MainWindow::tr("Merge Nodes into %1").arg(F->id().numId), F);
2754 mergeNodes(theDocument, theList, p->theProperties);
2755 if (theList->empty())
2756 delete theList;
2757 else
2758 {
2759 theDocument->addHistory(theList);
2760 p->theProperties->setSelection(F);
2761 invalidateView();
2762 }
2763 }
2764
2765 void MainWindow::on_nodeDetachAction_triggered()
2766 {
2767 Feature* F = p->theProperties->selection(0);
2768 CommandList* theList = new CommandList(MainWindow::tr("Detach Node %1").arg(F->id().numId), F);
2769 detachNode(theDocument, theList, p->theProperties);
2770 if (theList->empty())
2771 delete theList;
2772 else
2773 {
2774 theDocument->addHistory(theList);
2775 p->theProperties->setSelection(F);
2776 invalidateView();
2777 }
2778 }
2779
2780 void MainWindow::on_relationAddMemberAction_triggered()
2781 {
2782 CommandList* theList = new CommandList(MainWindow::tr("Add member to relation"), NULL);
2783 addRelationMember(theDocument, theList, p->theProperties);
2784 if (theList->empty())
2785 delete theList;
2786 else {
2787 theDocument->addHistory(theList);
2788 invalidateView();
2789 }
2790 }
2791
2792 void MainWindow::on_relationRemoveMemberAction_triggered()
2793 {
2794 CommandList* theList = new CommandList(MainWindow::tr("Remove member from relation"), NULL);
2795 removeRelationMember(theDocument, theList, p->theProperties);
2796 if (theList->empty())
2797 delete theList;
2798 else {
2799 theDocument->addHistory(theList);
2800 invalidateView();
2801 }
2802 }
2803
2804 void MainWindow::on_relationAddToMultipolygonAction_triggered()
2805 {
2806 CommandList* theList = new CommandList(MainWindow::tr("Add to Multipolygon"), NULL);
2807 addToMultipolygon(theDocument, theList, p->theProperties);
2808 if (theList->empty())
2809 delete theList;
2810 else {
2811 theDocument->addHistory(theList);
2812 invalidateView();
2813 }
2814 }
2815
2816 void MainWindow::on_areaJoinAction_triggered()
2817 {
2818 CommandList* theList = new CommandList(MainWindow::tr("Join areas"), NULL);
2819 joinAreas(theDocument, theList, p->theProperties);
2820 if (theList->empty())
2821 delete theList;
2822 else {
2823 theDocument->addHistory(theList);
2824 invalidateView();
2825 }
2826 }
2827
2828 void MainWindow::on_areaSplitAction_triggered()
2829 {
2830 CommandList* theList = new CommandList(MainWindow::tr("Split area"), NULL);
2831 splitArea(theDocument, theList, p->theProperties);
2832 if (theList->empty())
2833 delete theList;
2834 else {
2835 theDocument->addHistory(theList);
2836 invalidateView();
2837 }
2838 }
2839
2840 void MainWindow::on_areaTerraceAction_triggered()
2841 {
2842 TerraceDialog* Dlg = new TerraceDialog(this);
2843 if (Dlg->exec() == QDialog::Accepted) {
2844 int divisions = Dlg->numHouses();
2845 CommandList* theList = new CommandList(MainWindow::tr("Terrace area into %1").arg(divisions), NULL);
2846 terraceArea(theDocument, theList, p->theProperties, divisions);
2847 // Add the house numbers to the houses in the selection
2848 if (Dlg->hasHouseNumbers()) {
2849 QStringList numbers = Dlg->houseNumbers();
2850 QList<Feature*> areas = p->theProperties->selection();
2851 int i = 0;
2852 foreach (Feature* area, areas) {
2853 if (i >= numbers.size())
2854 break;
2855 if (!numbers[i].isEmpty())
2856 theList->add(new SetTagCommand(area, "addr:housenumber", numbers[i]));
2857 ++i;
2858 }
2859 }
2860 if (theList->empty())
2861 delete theList;
2862 else {
2863 theDocument->addHistory(theList);
2864 invalidateView();
2865 }
2866 }
2867 delete Dlg;
2868 }
2869
2870 void MainWindow::on_createRelationAction_triggered()
2871 {
2872 Relation* R = g_backend.allocRelation(document()->getDirtyOrOriginLayer());
2873 CommandList* theList = new CommandList(MainWindow::tr("Create Relation %1").arg(R->description()), R);
2874 theList->add(
2875 new AddFeatureCommand(document()->getDirtyOrOriginLayer(), R, true));
2876 for (int i = 0; i < p->theProperties->selectionSize(); ++i)
2877 theList->add(new RelationAddFeatureCommand(R, QString(), p->theProperties->selection(i)));
2878 theDocument->addHistory(theList);
2879 p->theProperties->setSelection(R);
2880 invalidateView();
2881 }
2882
2883 void MainWindow::on_editMapStyleAction_triggered()
2884 {
2885 PaintStyleEditor* dlg = new PaintStyleEditor(this, M_STYLE->getGlobalPainter(), M_STYLE->getPainters());
2886 connect(dlg, SIGNAL(stylesApplied(GlobalPainter*, QList<Painter>* )), this, SLOT(applyPainters(GlobalPainter*, QList<Painter>* )));
2887 GlobalPainter saveGlobalPainter = M_STYLE->getGlobalPainter();
2888 QList<Painter> savePainters = M_STYLE->getPainters();
2889 if (dlg->exec() == QDialog::Accepted) {
2890 applyPainters(&dlg->theGlobalPainter, &dlg->thePainters);
2891 } else {
2892 /* FIXME: Is it really needed? The painter should be already set up. */
2893 applyPainters(&saveGlobalPainter, &savePainters);
2894 }
2895
2896 delete dlg;
2897 }
2898
2899 void MainWindow::applyStyles(QString NewStyle)
2900 {
2901 if (NewStyle != M_PREFS->getDefaultStyle())
2902 {
2903 if (M_STYLE->isDirty() && !mayDiscardStyleChanges(this)) {
2904 on_mapStyleSaveAction_triggered();
2905 }
2906 M_PREFS->setDefaultStyle(NewStyle);
2907 M_STYLE->loadPainters(M_PREFS->getDefaultStyle());
2908 theDocument->setPainters(M_STYLE->getPainters());
2909 invalidateView(false);
2910 }
2911 }
2912
2913 void MainWindow::applyPainters(GlobalPainter* theGlobalPainter, QList<Painter>* thePainters)
2914 {
2915 M_STYLE->setGlobalPainter(*theGlobalPainter);
2916 M_STYLE->setPainters(*thePainters);
2917
2918 theDocument->setPainters(*thePainters);
2919 invalidateView(false);
2920 }
2921
2922 //MapLayer* MainWindow::activeLayer()
2923 //{
2924 //// return theLayers->activeLayer();
2925 // //The "active" layer is always the dirty layer
2926 // return theDocument->getDirtyLayer();
2927 //}
2928
2929 MapView* MainWindow::view()
2930 {
2931 return theView;
2932 }
2933
2934 void MainWindow::on_mapStyleSaveAction_triggered()
2935 {
2936 QString f = M_STYLE->getFilename();
2937 if (f.isEmpty() || f.startsWith(":") || f.startsWith("qrc:")) {
2938 on_mapStyleSaveAsAction_triggered();
2939 return;
2940 }
2941 M_STYLE->savePainters(f);
2942 }
2943
2944 void MainWindow::on_mapStyleSaveAsAction_triggered()
2945 {
2946 QString f;
2947 QFileDialog dlg(this, tr("Save map style"), M_PREFS->getCustomStyle(), tr("Merkaartor map style (*.mas)"));
2948 dlg.setFileMode(QFileDialog::AnyFile);
2949 dlg.setDefaultSuffix("mas");
2950 dlg.setAcceptMode(QFileDialog::AcceptSave);
2951
2952 if (dlg.exec()) {
2953 if (dlg.selectedFiles().size())
2954 f = dlg.selectedFiles()[0];
2955 }
2956 if (!f.isNull()) {
2957 M_STYLE->savePainters(f);
2958 }
2959 updateStyleMenu();
2960 }
2961
2962 void MainWindow::on_mapStyleLoadAction_triggered()
2963 {
2964 if (M_STYLE->isDirty() && !mayDiscardStyleChanges(this)) {
2965 on_mapStyleSaveAction_triggered();
2966 }
2967
2968 QString f = QFileDialog::getOpenFileName(this, tr("Load map style"), QString(),
2969 tr("Supported formats")+" (*.mas *.css)\n" \
2970 + tr("Merkaartor map style (*.mas)\n")
2971 + tr("MapCSS stylesheet (*.css)"));
2972 if (!f.isNull()) {
2973 if (f.endsWith("css"))
2974 MapCSSPaintstyle::instance()->loadPainters(f);
2975 else {
2976 M_STYLE->loadPainters(f);
2977 document()->setPainters(M_STYLE->getPainters());
2978 invalidateView();
2979 }
2980 }
2981 }
2982
2983 void MainWindow::on_toolsWMSServersAction_triggered()
2984 {
2985 WMSPreferencesDialog* WMSPref;
2986 WMSPref = new WMSPreferencesDialog();
2987 if (WMSPref->exec() == QDialog::Accepted) {
2988 for (LayerIterator<ImageMapLayer*> ImgIt(theDocument); !ImgIt.isEnd(); ++ImgIt)
2989 ImgIt.get()->updateWidget();
2990 adjustLayers(true);
2991 }
2992 }
2993
2994 void MainWindow::on_toolsTMSServersAction_triggered()
2995 {
2996 TMSPreferencesDialog* TMSPref;
2997 TMSPref = new TMSPreferencesDialog();
2998 if (TMSPref->exec() == QDialog::Accepted) {
2999 for (LayerIterator<ImageMapLayer*> ImgIt(theDocument); !ImgIt.isEnd(); ++ImgIt)
3000 ImgIt.get()->updateWidget();
3001 adjustLayers(true);
3002 }
3003 }
3004
3005 void MainWindow::on_toolsProjectionsAction_triggered()
3006 {
3007 ProjPreferencesDialog* prefDlg = new ProjPreferencesDialog();
3008 if (prefDlg->exec() == QDialog::Accepted) {
3009 updateProjectionMenu();
3010 }
3011 }
3012
3013 void MainWindow::on_toolsFiltersAction_triggered()
3014 {
3015 FilterPreferencesDialog* prefDlg = new FilterPreferencesDialog();
3016 prefDlg->exec();
3017 // if (prefDlg->exec() == QDialog::Accepted) {
3018 // updateFilterMenu();
3019 // }
3020 }
3021
3022 void MainWindow::on_toolsResetDiscardableAction_triggered()
3023 {
3024 QSettings* Sets = M_PREFS->getQSettings();
3025 Sets->remove("DiscardableDialogs");
3026 }
3027
3028 void MainWindow::on_toolsRebuildHistoryAction_triggered()
3029 {
3030 QMessageBox::StandardButton ret = QMessageBox::warning(this, tr("Rebuild History"), tr("An attempt will be made to rebuild the history.\nNo guarantee, though, and no Undo.\nAre you sure you want to try this? ")
3031 , QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
3032 if (ret == QMessageBox::Yes) {
3033 theDocument->rebuildHistory();
3034 theDirty->updateList();
3035 }
3036 }
3037
3038 namespace {
3039
3040 void CollectActions(QList<QAction*>& collectedActions, const QWidget* widget) {
3041 foreach(QAction* a, widget->actions()) {
3042 if (!a->isSeparator() && !a->menu())
3043 collectedActions << a;
3044 }
3045 }
3046
3047 } // namespace
3048
3049 void MainWindow::on_toolsShortcutsAction_triggered()
3050 {
3051 QList<QAction*> theActions;
3052
3053 CollectActions(theActions, ui->menuFile);
3054 CollectActions(theActions, ui->menuEdit);
3055 CollectActions(theActions, ui->menuView);
3056 CollectActions(theActions, ui->menu_Show);
3057 CollectActions(theActions, ui->menuShow_directional_Arrows);
3058 CollectActions(theActions, ui->menuGps);
3059 CollectActions(theActions, ui->menuLayers);
3060 CollectActions(theActions, ui->menuCreate);
3061 CollectActions(theActions, ui->menu_Feature);
3062 CollectActions(theActions, ui->menu_Node);
3063 CollectActions(theActions, ui->menuRoad);
3064 CollectActions(theActions, ui->menuRelation);
3065 CollectActions(theActions, ui->menuTools);
3066 CollectActions(theActions, ui->menuWindow);
3067 CollectActions(theActions, ui->menuHelp);
3068
3069 ActionsDialog(theActions, this).exec();
3070 }
3071
3072 void MainWindow::toolsPreferencesAction_triggered(bool focusData)
3073 {
3074 PreferencesDialog* Pref = new PreferencesDialog(this);
3075 if (focusData)
3076 Pref->tabPref->setCurrentWidget(Pref->tabData);
3077 else
3078 Pref->tabPref->setCurrentIndex(p->lastPrefTabIndex);
3079 connect (Pref, SIGNAL(preferencesChanged(PreferencesDialog*)), this, SLOT(preferencesChanged(PreferencesDialog*)));
3080 Pref->exec();
3081 p->lastPrefTabIndex = Pref->tabPref->currentIndex();
3082 }
3083
3084 void MainWindow::preferencesChanged(PreferencesDialog* prefs)
3085 {
3086 QString qVer = QString(qVersion()).replace('.', QChar());
3087 int iQVer = qVer.toInt();
3088 if (iQVer < 451) {
3089 QApplication::setStyle(QStyleFactory::create("skulpture"));
3090 } else {
3091 if (!M_PREFS->getMerkaartorStyle()) {
3092 if (QApplication::style()->objectName() != p->defStyle)
3093 QApplication::setStyle(p->defStyle);
3094 } else {
3095 QApplication::setStyle(QStyleFactory::create(M_PREFS->getMerkaartorStyleString()));
3096 }
3097 }
3098 ui->mnuProjections->menuAction()->setEnabled(true);
3099 if (M_PREFS->getZoomBoris()) {
3100 ImageMapLayer* l = NULL;
3101 for (LayerIterator<ImageMapLayer*> ImgIt(theDocument); !ImgIt.isEnd(); ++ImgIt) {
3102 l = ImgIt.get();
3103 break;
3104 }
3105 if (l && l->isTiled()) {
3106 ui->mnuProjections->menuAction()->setEnabled(false);
3107 view()->projection().setProjectionType(l->projection());
3108 view()->zoom(0.99, view()->rect().center());
3109 }
3110 }
3111 if (M_PREFS->getLocalServer()) {
3112 p->theListeningServer->listen();
3113 } else {
3114 p->theListeningServer->close();
3115 }
3116
3117 applyStyles(prefs->cbStyles->itemData(prefs->cbStyles->currentIndex()).toString());
3118 updateStyleMenu();
3119
3120 updateMenu();
3121 launchInteraction(new EditInteraction(this));
3122 invalidateView(false);
3123 }
3124
3125 bool MainWindow::getPathToSave(const QString& title, const QString& extension, const QString& allowedTypes, QString* path) {
3126 const QString defaultFile = QString("%1/%2.%3").arg(M_PREFS->getworkingdir()).arg(tr("untitled")).arg(extension);
3127 QFileDialog dlg(this, title, defaultFile, allowedTypes);
3128 dlg.setFileMode(QFileDialog::AnyFile);
3129 dlg.setDefaultSuffix(extension);
3130 dlg.setAcceptMode(QFileDialog::AcceptSave);
3131
3132 if (dlg.exec() && dlg.selectedFiles().size() && !dlg.selectedFiles()[0].isEmpty()) {
3133 *path = dlg.selectedFiles()[0];
3134 return true;
3135 }
3136 return false;
3137 }
3138
3139 void MainWindow::on_fileSaveAsAction_triggered()
3140 {
3141 QString path;
3142 if (getPathToSave(tr("Save Merkaartor document"), "mdc", tr("Merkaartor documents Files (*.mdc)") + "\n" + tr("All Files (*)"), &path)) {
3143 saveDocument(path);
3144 M_PREFS->addRecentOpen(path);
3145 updateRecentOpenMenu();
3146 }
3147 }
3148
3149 void MainWindow::on_fileSaveAsTemplateAction_triggered()
3150 {
3151 QString path;
3152 if (getPathToSave(tr("Save Merkaartor template document"), "mdc", tr("Merkaartor documents Files (*.mdc)") + "\n" + tr("All Files (*)"), &path)) {
3153 saveTemplateDocument(path);
3154 }
3155 }
3156
3157 void MainWindow::on_fileSaveAction_triggered()
3158 {
3159 if (!currentProjectFile.isEmpty()) {
3160 saveDocument(currentProjectFile);
3161 } else {
3162 on_fileSaveAsAction_triggered();
3163 }
3164 }
3165
3166 void MainWindow::doSaveDocument(QFile* file, bool asTemplate)
3167 {
3168 startBusyCursor();
3169 QXmlStreamWriter stream(file);
3170 stream.setAutoFormatting(true);
3171 stream.setAutoFormattingIndent(2);
3172 stream.writeStartDocument();
3173 stream.writeStartElement("MerkaartorDocument");
3174 stream.writeAttribute("version", "1.2");
3175 stream.writeAttribute("creator", QString("%1").arg(p->title));
3176
3177 QProgressDialog progress("Saving document...", "Cancel", 0, 0);
3178 progress.setWindowModality(Qt::WindowModal);
3179
3180 theDocument->toXML(stream, asTemplate, &progress);
3181 theView->toXML(stream);
3182
3183 stream.writeEndDocument();
3184
3185 progress.setValue(progress.maximum());
3186
3187 theDocument->setTitle(QFileInfo(currentProjectFile).fileName());
3188 setWindowTitle(QString("%1 - %2").arg(theDocument->title()).arg(p->title));
3189
3190 endBusyCursor();
3191 }
3192
3193 void MainWindow::saveDocument(const QString& fn)
3194 {
3195 QFile file(fn);
3196 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
3197 QMessageBox::critical(this, tr("Unable to open save file"), tr("%1 could not be opened for writing.").arg(fn));
3198 on_fileSaveAsAction_triggered();
3199 return;
3200 }
3201
3202 doSaveDocument(&file);
3203 file.close();
3204 currentProjectFile = fn;
3205
3206 p->latSaveDirtyLevel = theDocument->getDirtySize();
3207 }
3208
3209 void MainWindow::saveTemplateDocument(const QString& fn)
3210 {
3211 QFile file(fn);
3212 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
3213 QMessageBox::critical(this, tr("Unable to open save template document"), tr("%1 could not be opened for writing.").arg(fn));
3214 return;
3215 }
3216
3217 doSaveDocument(&file, true);
3218 file.close();
3219 }
3220
3221 Document* MainWindow::doLoadDocument(QFile* file)
3222 {
3223 QProgressDialog progress("Loading document...", "Cancel", 0, 0, this);
3224 progress.setWindowModality(Qt::WindowModal);
3225
3226 QXmlStreamReader stream(file);
3227 while (stream.readNext() && stream.tokenType() != QXmlStreamReader::Invalid && stream.tokenType() != QXmlStreamReader::StartElement)
3228 ;
3229 if (stream.tokenType() != QXmlStreamReader::StartElement || stream.name() != "MerkaartorDocument") {
3230 QMessageBox::critical(this, tr("Invalid file"), tr("%1 is not a valid Merkaartor document.").arg(file->fileName()));
3231 return NULL;
3232 }
3233 double version = stream.attributes().value("version").toString().toDouble();
3234
3235 progress.setMaximum(file->size());
3236
3237 Document* newDoc = NULL;
3238
3239 if (version < 2.) {
3240 stream.readNext();
3241 while(!stream.atEnd() && !stream.isEndElement()) {
3242 if (stream.name() == "MapDocument") {
3243 newDoc = Document::fromXML(QFileInfo(*file).fileName(), stream, version, theLayers, &progress);
3244
3245 if (progress.wasCanceled())
3246 break;
3247 } else if (stream.name() == "MapView") {
3248 view()->fromXML(stream);
3249 } else if (!stream.isWhitespace()) {
3250 qDebug() << "Main: logic error: " << stream.name() << " : " << stream.tokenType() << " (" << stream.lineNumber() << ")";
3251 stream.skipCurrentElement();
3252 }
3253
3254 if (progress.wasCanceled())
3255 break;
3256
3257 stream.readNext();
3258 }
3259 }
3260 progress.reset();
3261
3262 updateProjectionMenu();
3263
3264 #ifdef GEOIMAGE
3265 if (theGeoImage)
3266 theGeoImage->clear();
3267 #endif
3268 return newDoc;
3269 }
3270
3271 void MainWindow::loadDocument(QString fn)
3272 {
3273 QFile file(fn);
3274 if (!file.open(QIODevice::ReadOnly)) {
3275 QMessageBox::critical(this, tr("Invalid file"), tr("%1 could not be opened.").arg(fn));
3276 return;
3277 }
3278
3279 Document* newDoc = doLoadDocument(&file);
3280 file.close();
3281
3282 if (newDoc) {
3283 theView->stopRendering();
3284 p->theProperties->setSelection(0);
3285 p->theFeats->invalidate();
3286 delete theDocument;
3287 theDocument = newDoc;
3288 theView->setDocument(theDocument);
3289 on_editPropertiesAction_triggered();
3290 theDocument->history().setActions(ui->editUndoAction, ui->editRedoAction, ui->fileUploadAction);
3291 connect (theDocument, SIGNAL(historyChanged()), theDirty, SLOT(updateList()));
3292 connect (theDocument, SIGNAL(historyChanged()), this, SIGNAL(content_changed()));
3293 connect(theDocument, SIGNAL(imageRequested(ImageMapLayer*)),
3294 this, SLOT(onImagerequested(ImageMapLayer*)), Qt::QueuedConnection);
3295 connect(theDocument, SIGNAL(imageReceived(ImageMapLayer*)),
3296 this, SLOT(onImagereceived(ImageMapLayer*)), Qt::QueuedConnection);
3297 connect(theDocument, SIGNAL(loadingFinished(ImageMapLayer*)),
3298 this, SLOT(onLoadingfinished(ImageMapLayer*)), Qt::QueuedConnection);
3299 theDirty->updateList();
3300 currentProjectFile = fn;
3301 setWindowTitle(QString("%1 - %2").arg(theDocument->title()).arg(p->title));
3302 p->latSaveDirtyLevel = theDocument->getDirtySize();
3303 theView->resumeRendering();
3304 }
3305
3306 M_PREFS->addRecentOpen(fn);
3307 updateRecentOpenMenu();
3308
3309 emit content_changed();
3310 }
3311
3312 void MainWindow::loadTemplateDocument(QString fn)
3313 {
3314 Document* newDoc = NULL;
3315 QFile file(fn);
3316 if (file.open(QIODevice::ReadOnly)) {
3317 newDoc = doLoadDocument(&file);
3318 file.close();
3319 }
3320
3321 if (newDoc) {
3322 theDocument = newDoc;
3323 theDocument->setTitle(tr("untitled"));
3324 }
3325 }
3326
3327 void MainWindow::on_exportOSMAction_triggered()
3328 {
3329 QList<Feature*> theFeatures;
3330
3331 createProgressDialog();
3332 if (!selectExportedFeatures(theFeatures))
3333 return;
3334
3335 QString path;
3336 if (getPathToSave(tr("Export OSM"), "osm", tr("OSM Files (*.osm)") + "\n" + tr("All Files (*)"), &path)) {
3337 QFile file(path);
3338 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
3339 return;
3340
3341 theDocument->exportOSM(this, &file, theFeatures);
3342 file.close();
3343 }
3344 deleteProgressDialog();
3345 }
3346
3347 void MainWindow::on_exportOSCAction_triggered()
3348 {
3349 #ifndef FRISIUS_BUILD
3350 QString path;
3351 if (getPathToSave(tr("Export osmChange"), "osc", tr("osmChange Files (*.osc)") + "\n" + tr("All Files (*)"), &path)) {
3352 startBusyCursor();
3353 ImportExportOSC osc(document());
3354 if (osc.saveFile(path)) {
3355 osc.export_();
3356 }
3357 endBusyCursor();
3358 }
3359 #endif
3360 }
3361
3362
3363 void MainWindow::on_exportGPXAction_triggered()
3364 {
3365 QList<Feature*> theFeatures;
3366
3367 createProgressDialog();
3368 if (!selectExportedFeatures(theFeatures))
3369 return;
3370
3371 QString path;
3372 if (getPathToSave(tr("Export GPX"), "gpx", tr("GPX Files (*.gpx)") + "\n" + tr("All Files (*)"), &path)) {
3373 startBusyCursor();
3374 ExportGPX gpx(document());
3375 if (gpx.saveFile(path)) {
3376 gpx.export_(theFeatures);
3377 }
3378 endBusyCursor();
3379 }
3380 deleteProgressDialog();
3381 }
3382
3383 void MainWindow::on_exportGDALAction_triggered()
3384 {
3385 QList<Feature*> theFeatures;
3386
3387 createProgressDialog();
3388 if (!selectExportedFeatures(theFeatures))
3389 return;
3390 startBusyCursor();
3391 ImportExportGdal gdal(document());
3392 gdal.export_(theFeatures);
3393 endBusyCursor();
3394
3395 deleteProgressDialog();
3396 }
3397
3398 void MainWindow::on_exportKMLAction_triggered()
3399 {
3400 QList<Feature*> theFeatures;
3401
3402 createProgressDialog();
3403 if (!selectExportedFeatures(theFeatures))
3404 return;
3405
3406 QString path;
3407 if (getPathToSave(tr("Export KML"), "kml", tr("KML Files (*.kml)") + "\n" + tr("All Files (*)"), &path)) {
3408 startBusyCursor();
3409 ImportExportKML kml(document());
3410 if (kml.saveFile(path)) {
3411 kml.export_(theFeatures);
3412 }
3413 endBusyCursor();
3414 }
3415 deleteProgressDialog();
3416 }
3417
3418 bool MainWindow::selectExportedFeatures(QList<Feature*>& theFeatures)
3419 {
3420 QDialog dlg(this);
3421 Ui::ExportDialog dlgExport;
3422 dlgExport.setupUi(&dlg);
3423 switch(M_PREFS->getExportType()) {
3424 case Export_All:
3425 dlgExport.rbAll->setChecked(true);
3426 break;
3427 case Export_Viewport:
3428 dlgExport.rbViewport->setChecked(true);
3429 break;
3430 case Export_Selected:
3431 dlgExport.rbSelected->setChecked(true);
3432 break;
3433 default:
3434 return false;
3435
3436 }
3437 if (dlg.exec()) {
3438 if (dlgExport.rbAll->isChecked()) {
3439 for (VisibleFeatureIterator i(document()); !i.isEnd(); ++i) {
3440 if (i.get()->notEverythingDownloaded())
3441 continue;
3442
3443 theFeatures.append(i.get());
3444 }
3445 M_PREFS->setExportType(Export_All);
3446 return true;
3447 }
3448 else if (dlgExport.rbViewport->isChecked()) {
3449 CoordBox aCoordBox = view()->viewport();
3450
3451 theFeatures.clear();
3452 for (VisibleFeatureIterator i(document()); !i.isEnd(); ++i) {
3453 if (i.get()->notEverythingDownloaded())
3454 continue;
3455
3456 if (Node* P = dynamic_cast<Node*>(i.get())) {
3457 if (aCoordBox.contains(P->position())) {
3458 theFeatures.append(P);
3459 }
3460 } else
3461 if (Way* G = dynamic_cast<Way*>(i.get())) {
3462 if (aCoordBox.intersects(G->boundingBox())) {
3463 for (int j=0; j < G->size(); j++) {
3464 if (Node* P = dynamic_cast<Node*>(G->get(j)))
3465 if (!aCoordBox.contains(P->position()))
3466 theFeatures.append(P);
3467 }
3468 theFeatures.append(G);
3469 }
3470 } else
3471 //FIXME Not working for relation (not made of point?)
3472 if (Relation* G = dynamic_cast<Relation*>(i.get())) {
3473 if (aCoordBox.intersects(G->boundingBox())) {
3474 for (int j=0; j < G->size(); j++) {
3475 if (Way* R = dynamic_cast<Way*>(G->get(j))) {
3476 if (!aCoordBox.contains(R->boundingBox())) {
3477 for (int k=0; k < R->size(); k++) {
3478 if (Node* P = dynamic_cast<Node*>(R->get(k)))
3479 if (!aCoordBox.contains(P->position()))
3480 theFeatures.append(P);
3481 }
3482 theFeatures.append(R);
3483 }
3484 }
3485 }
3486 theFeatures.append(G);
3487 }
3488 }
3489 }
3490 M_PREFS->setExportType(Export_Viewport);
3491 }
3492 else if (dlgExport.rbSelected->isChecked()) {
3493 theFeatures = p->theProperties->selection();
3494 M_PREFS->setExportType(Export_Selected);
3495 }
3496
3497 QProgressDialog* dlg = getProgressDialog();
3498 if (dlg)
3499 dlg->setWindowTitle(tr("Feature extraction"));
3500
3501 QProgressBar* Bar = getProgressBar();
3502 if (Bar) {
3503 Bar->setTextVisible(false);
3504 Bar->setMaximum(theFeatures.size());
3505 }
3506
3507 QLabel* Lbl = getProgressLabel();
3508 if (Lbl)
3509 Lbl->setText(tr("Extracting features..."));
3510
3511 if (dlg)
3512 dlg->show();
3513
3514 theFeatures = document()->exportCoreOSM(theFeatures, false, dlg);
3515 return true;
3516 }
3517 return false;
3518 }
3519
3520 void MainWindow::on_editSelectAction_triggered()
3521 {
3522 SelectionDialog* Sel = new SelectionDialog(this);
3523
3524 if (Sel->exec() == QDialog::Accepted) {
3525 QString out;
3526 int idx = 0;
3527 QString in = Sel->edTagQuery->text();
3528 QList<TagSelector*> terms;
3529 while (idx < in.length()) {
3530 TagSelector* t = TagSelector::parse(in, idx);
3531 if (!t) break;
3532 terms.append(t);
3533 }
3534
3535 if (terms.count()) {
3536 out += terms[terms.count()-1]->asExpression(true);
3537 for (int i=terms.count()-2; i>=0; --i) {
3538 out += " and parent(";
3539 out += terms[i]->asExpression(true);
3540 out += ") ";
3541 }
3542 } else
3543 return;
3544
3545 qDebug() << out;
3546 TagSelector* tsel = TagSelector::parse(out);
3547 if (!tsel)
3548 return;
3549 qDebug() << tsel->asExpression(false);
3550
3551 int selMaxResult = Sel->sbMaxResult->value();
3552
3553 QList <Feature *> selection;
3554 int added = 0;
3555 for (VisibleFeatureIterator i(theDocument); !i.isEnd() && (!selMaxResult || added < selMaxResult); ++i) {
3556 Feature* F = i.get();
3557 if (tsel->matches(F, theView->pixelPerM())) {
3558 selection.push_back(F);
3559 ++added;
3560 }
3561 }
3562 p->theProperties->setMultiSelection(selection);
3563 p->theProperties->checkMenuStatus();
3564 }
3565 }
3566
3567 void MainWindow::closeEvent(QCloseEvent * event)
3568 {
3569 if (hasUnsavedChanges() && !mayDiscardUnsavedChanges(this)) {
3570 event->ignore();
3571 return;
3572 }
3573
3574 if (M_STYLE->isDirty() && !mayDiscardStyleChanges(this)) {
3575 on_mapStyleSaveAction_triggered();
3576 }
3577
3578 M_PREFS->saveMainWindowState( this );
3579 // M_PREFS->setInitialPosition(theView);
3580 M_PREFS->setworkingdir(QDir::currentPath());
3581
3582 saveTemplateDocument(TEMPLATE_DOCUMENT);
3583 M_PREFS->save();
3584 QMainWindow::closeEvent(event);
3585 }
3586
3587 QMenu *MainWindow::createPopupMenu()
3588 {
3589 QMenu* mnu = QMainWindow::createPopupMenu();
3590 mnu->addSeparator();
3591
3592 QAction* toolbarstyle = new QAction(tr("Hide tool buttons labels"), mnu);
3593 toolbarstyle->setCheckable(true);
3594 toolbarstyle->setChecked(M_PREFS->getHideToolbarLabels());
3595 connect(toolbarstyle, SIGNAL(triggered()), SLOT(toggleButtonStyle()));
3596 mnu->addAction(toolbarstyle);
3597
3598 return mnu;
3599 }
3600
3601 void MainWindow::updateBookmarksMenu()
3602 {
3603 for(int i=ui->menuBookmarks->actions().count()-1; i > 2 ; i--) {
3604 ui->menuBookmarks->removeAction(ui->menuBookmarks->actions()[3]);
3605 }
3606
3607 BookmarkListIterator it(*(M_PREFS->getBookmarks()));
3608 while (it.hasNext()) {
3609 it.next();
3610 if (it.value().deleted == false) {
3611 QAction* a = new QAction(it.key(), ui->menuBookmarks);
3612 ui->menuBookmarks->addAction(a);
3613 }
3614 }
3615 }
3616
3617 void MainWindow::updateRecentOpenMenu()
3618 {
3619 for(int i=ui->menuRecentOpen->actions().count()-1; i >= 0; i--) {
3620 ui->menuRecentOpen->removeAction(ui->menuRecentOpen->actions()[0]);
3621 }
3622
3623 if (!M_PREFS->getRecentOpen().size()) {
3624 ui->menuRecentOpen->setEnabled(false);
3625 return;
3626 }
3627
3628 ui->menuRecentOpen->setEnabled(true);
3629 QStringList RecentOpen = M_PREFS->getRecentOpen();
3630 for (int i=0; i<RecentOpen.size(); i++) {
3631 QAction* a = new QAction(RecentOpen[i], ui->menuRecentOpen);
3632 ui->menuRecentOpen->addAction(a);
3633 }
3634 }
3635
3636 void MainWindow::updateRecentImportMenu()
3637 {
3638 for(int i=ui->menuRecentImport->actions().count()-1; i >= 0; i--) {
3639 ui->menuRecentImport->removeAction(ui->menuRecentImport->actions()[0]);
3640 }
3641
3642 if (!M_PREFS->getRecentImport().size()) {
3643 ui->menuRecentImport->setEnabled(false);
3644 return;
3645 }
3646
3647 ui->menuRecentImport->setEnabled(true);
3648 QStringList RecentImport = M_PREFS->getRecentImport();
3649 for (int i=0; i<RecentImport.size(); i++) {
3650 QAction* a = new QAction(RecentImport[i], ui->menuRecentImport);
3651 ui->menuRecentImport->addAction(a);
3652 }
3653 }
3654
3655 void MainWindow::updateProjectionMenu()
3656 {
3657 #ifndef _MOBILE
3658 SAFE_DELETE(p->projActgrp)
3659 p->projActgrp = new QActionGroup(this);
3660 bool projFound = false;
3661 foreach (ProjectionItem it, *M_PREFS->getProjectionsList()->getProjections()) {
3662 if (it.deleted)
3663 continue;
3664 QAction* a = new QAction(it.name, p->projActgrp);
3665 a->setCheckable (true);
3666 if (it.name.contains(theView->projection().getProjectionType(), Qt::CaseInsensitive)) {
3667 a->setChecked(true);
3668 projFound = true;
3669 }
3670 ui->mnuProjections->addAction(a);
3671 }
3672 if (!projFound) {
3673 QAction* a = new QAction(theView->projection().getProjectionType(), p->projActgrp);
3674 a->setCheckable (true);
3675 a->setChecked(true);
3676 ui->mnuProjections->addAction(a);
3677 M_PREFS->getProjectionsList()->addProjection(ProjectionItem(theView->projection().getProjectionType(), theView->projection().getProjectionProj4()));
3678 }
3679 connect (ui->mnuProjections, SIGNAL(triggered(QAction *)), this, SLOT(projectionTriggered(QAction *)));
3680 #endif
3681 ui->mnuProjections->menuAction()->setEnabled(true);
3682 if (M_PREFS->getZoomBoris() && theDocument) {
3683 ImageMapLayer* l = NULL;
3684 for (LayerIterator<ImageMapLayer*> ImgIt(theDocument); !ImgIt.isEnd(); ++ImgIt) {
3685 l = ImgIt.get();
3686 break;
3687 }
3688 if (l && l->isTiled())
3689 ui->mnuProjections->menuAction()->setEnabled(false);
3690 }
3691 }
3692
3693 void MainWindow::updateStyleMenu()
3694 {
3695 for(int i=ui->menuStyles->actions().count()-1; i > 4 ; i--) {
3696 ui->menuStyles->removeAction(ui->menuStyles->actions()[5]);
3697 }
3698 p->theStyle->clearItems();
3699
3700 QActionGroup* actgrp = new QActionGroup(this);
3701 QDir intStyles(BUILTIN_STYLES_DIR);
3702 for (int i=0; i < intStyles.entryList().size(); ++i) {
3703 QAction* a = new QAction(QString(tr("%1 (int)")).arg(intStyles.entryList().at(i)), ui->menuStyles);
3704 actgrp->addAction(a);
3705 a->setCheckable(true);
3706 a->setData(QVariant(intStyles.entryInfoList().at(i).absoluteFilePath()));
3707 ui->menuStyles->addAction(a);
3708 if (intStyles.entryInfoList().at(i).absoluteFilePath() == M_PREFS->getDefaultStyle())
3709 a->setChecked(true);
3710 p->theStyle->addItem(a);
3711 }
3712 if (!M_PREFS->getCustomStyle().isEmpty()) {
3713 QDir customStyles(M_PREFS->getCustomStyle(), "*.mas *.msz");
3714 for (int i=0; i < customStyles.entryList().size(); ++i) {
3715 QAction* a = new QAction(customStyles.entryList().at(i), ui->menuStyles);
3716 actgrp->addAction(a);
3717 a->setCheckable(true);
3718 a->setData(QVariant(customStyles.entryInfoList().at(i).absoluteFilePath()));
3719 ui->menuStyles->addAction(a);
3720 if (customStyles.entryInfoList().at(i).absoluteFilePath() == M_PREFS->getDefaultStyle())
3721 a->setChecked(true);
3722 p->theStyle->addItem(a);
3723 }
3724 }
3725 }
3726
3727 void MainWindow::updateWindowMenu(bool)
3728 {
3729 ui->windowPropertiesAction->setChecked(p->theProperties->isVisible());
3730 ui->windowLayersAction->setChecked(theLayers->isVisible());
3731 ui->windowInfoAction->setChecked(theInfo->isVisible());
3732 ui->windowDirtyAction->setChecked(theDirty->isVisible());
3733 ui->windowFeatsAction->setChecked(p->theFeats->isVisible());
3734 ui->windowGPSAction->setChecked(theGPS->isVisible());
3735 #ifdef GEOIMAGE
3736 ui->windowGeoimageAction->setChecked(theGeoImage->isVisible());
3737 #endif
3738 ui->windowStylesAction->setChecked(p->theStyle->isVisible());
3739 }
3740
3741 void MainWindow::on_bookmarkAddAction_triggered()
3742 {
3743 bool ok = true;
3744 QString text;
3745
3746 BookmarkList* Bookmarks = M_PREFS->getBookmarks();
3747 QStringList bkName;
3748 BookmarkListIterator i(*Bookmarks);
3749 while (i.hasNext()) {
3750 i.next();
3751 if (i.value().deleted == false)
3752 bkName.append(i.key());
3753 }
3754 while (ok) {
3755 text = QInputDialog::getItem(this, MainWindow::tr("Add Bookmark"),
3756 MainWindow::tr("Specify the name of the bookmark."), bkName, 0, true, &ok);
3757 if (ok) {
3758 if (text.isEmpty()) {
3759 QMessageBox::critical(this, tr("Invalid bookmark name"),
3760 tr("Bookmark cannot be blank."), QMessageBox::Ok);
3761 continue;
3762 }
3763 if (Bookmarks->contains(text)) {
3764 QString newBk = QInputDialog::getText(this, MainWindow::tr("Warning: Bookmark name already exists"),
3765 MainWindow::tr("Enter a new one, keep the same to overwrite or cancel."), QLineEdit::Normal,
3766 text, &ok);
3767 if (ok && Bookmarks->contains(newBk)) {
3768 for(int i=2; i < ui->menuBookmarks->actions().count(); i++) {
3769 if (ui->menuBookmarks->actions()[i]->text() == newBk) {
3770 ui->menuBookmarks->removeAction(ui->menuBookmarks->actions()[i]);
3771 break;
3772 }
3773 }
3774 }
3775 text = newBk;
3776 }
3777 break;
3778 }
3779 }
3780 if (ok) {
3781 CoordBox Clip = view()->viewport();
3782 Bookmark B(text, Clip);
3783 Bookmarks->insert(text, B);
3784 M_PREFS->save();
3785
3786 QAction* a = new QAction(text,ui-> menuBookmarks);
3787 ui->menuBookmarks->addAction(a);
3788 }
3789 }
3790
3791 void MainWindow::on_bookmarkRemoveAction_triggered()
3792 {
3793 bool ok;
3794
3795 BookmarkList* Bookmarks = M_PREFS->getBookmarks();
3796 QStringList bkName;
3797 BookmarkListIterator i(*Bookmarks);
3798 while (i.hasNext()) {
3799 i.next();
3800 if (i.value().deleted == false)
3801 bkName.append(i.key());
3802 }
3803 QString item = QInputDialog::getItem(this, MainWindow::tr("Remove Bookmark"),
3804 MainWindow::tr("Select the bookmark to remove."), bkName, 0, false, &ok);
3805 if (ok) {
3806 Bookmark B = Bookmarks->value(item);
3807 B.deleted = true;
3808 Bookmarks->insert(item, B);
3809 M_PREFS->save();
3810
3811 for(int i=2; i < ui->menuBookmarks->actions().count(); i++) {
3812 if (ui->menuBookmarks->actions()[i]->text() == item) {
3813 ui->menuBookmarks->removeAction(ui->menuBookmarks->actions()[i]);
3814 break;
3815 }
3816 }
3817 }
3818 }
3819
3820 void MainWindow::bookmarkTriggered(QAction* anAction)
3821 {
3822 if (anAction == ui->bookmarkAddAction || anAction == ui->bookmarkRemoveAction)
3823 return;
3824 BookmarkList* Bookmarks = M_PREFS->getBookmarks();
3825 theView->setViewport(Bookmarks->value(anAction->text()).Coordinates, theView->rect());
3826
3827 invalidateView();
3828 }
3829
3830 void MainWindow::recentOpenTriggered(QAction* anAction)
3831 {
3832 if (hasUnsavedChanges() && !mayDiscardUnsavedChanges(this))
3833 return;
3834
3835 QString fileName(anAction->text());
3836 loadDocument(fileName);
3837 }
3838
3839 void MainWindow::recentImportTriggered(QAction* anAction)
3840 {
3841 view()->setUpdatesEnabled(false);
3842 theLayers->setUpdatesEnabled(false);
3843
3844 QStringList fileNames(anAction->text());
3845 QStringList importedFiles;
3846 importFiles(theDocument, fileNames, &importedFiles);
3847
3848 foreach (QString currentFileName, importedFiles)
3849 M_PREFS->addRecentImport(currentFileName);
3850
3851 updateRecentImportMenu();
3852
3853 view()->setUpdatesEnabled(true);
3854 theLayers->setUpdatesEnabled(true);
3855
3856 on_editPropertiesAction_triggered();
3857 theDocument->history().setActions(ui->editUndoAction, ui->editRedoAction, ui->fileUploadAction);
3858 }
3859
3860 #ifndef _MOBILE
3861 void MainWindow::projectionSet(const QString& prj)
3862 {
3863 if(false == theView->projection().setProjectionType(prj))
3864 QMessageBox::critical(this, tr("Invalid projection"), tr("Unable to set projection \"%1\".").arg(prj));
3865 updateProjectionMenu();
3866 theView->setViewport(theView->viewport(), theView->rect());
3867 invalidateView();
3868 }
3869
3870 void MainWindow::projectionTriggered(QAction* anAction)
3871 {
3872 if(false == theView->projection().setProjectionType(anAction->text()))
3873 QMessageBox::critical(this, tr("Invalid projection"), tr("Unable to set projection \"%1\".").arg(anAction->text()));
3874 else
3875 M_PREFS->setProjectionType(anAction->text());
3876 theView->setViewport(theView->viewport(), theView->rect());
3877 invalidateView();
3878 }
3879 #endif
3880
3881 void MainWindow::styleTriggered(QAction* anAction)
3882 {
3883 if (!anAction->isCheckable())
3884 return;
3885
3886 QString NewStyle = anAction->data().toString();
3887 p->theStyle->setCurrent(anAction);
3888 applyStyles(NewStyle);
3889 }
3890
3891 void MainWindow::on_windowPropertiesAction_triggered()
3892 {
3893 p->theProperties->setVisible(!p->theProperties->isVisible());
3894 ui->windowPropertiesAction->setChecked(p->theProperties->isVisible());
3895 }
3896
3897 void MainWindow::on_windowLayersAction_triggered()
3898 {
3899 theLayers->setVisible(!theLayers->isVisible());
3900 ui->windowLayersAction->setChecked(theLayers->isVisible());
3901 }
3902
3903 void MainWindow::on_windowInfoAction_triggered()
3904 {
3905 theInfo->setVisible(!theInfo->isVisible());
3906 ui->windowInfoAction->setChecked(theInfo->isVisible());
3907 }
3908
3909 void MainWindow::on_windowDirtyAction_triggered()
3910 {
3911 theDirty->setVisible(!theDirty->isVisible());
3912 ui->windowDirtyAction->setChecked(theDirty->isVisible());
3913 }
3914
3915 void MainWindow::on_windowFeatsAction_triggered()
3916 {
3917 p->theFeats->setVisible(!p->theFeats->isVisible());
3918 ui->windowFeatsAction->setChecked(p->theFeats->isVisible());
3919 }
3920
3921 void MainWindow::on_windowToolbarAction_triggered()
3922 {
3923 foreach (QObject* child, children()) {
3924 if (QToolBar* tb = qobject_cast<QToolBar*>(child))
3925 tb->setVisible(!tb->isVisible());
3926 }
3927 }
3928
3929 void MainWindow::on_windowGPSAction_triggered()
3930 {
3931 theGPS->setVisible(!theGPS->isVisible());
3932 ui->windowGPSAction->setChecked(theGPS->isVisible());
3933 }
3934
3935 #ifdef GEOIMAGE
3936 void MainWindow::on_windowGeoimageAction_triggered()
3937 {
3938 theGeoImage->setVisible(!theGeoImage->isVisible());
3939 ui->windowGeoimageAction->setChecked(theGeoImage->isVisible());
3940 }
3941 #endif
3942
3943 void MainWindow::on_windowStylesAction_triggered()
3944 {
3945 p->theStyle->setVisible(!p->theStyle->isVisible());
3946 ui->windowStylesAction->setChecked(p->theStyle->isVisible());
3947 }
3948
3949 void MainWindow::on_windowHideAllAction_triggered()
3950 {
3951 fullscreenState = saveState(1);
3952
3953 ui->windowHideAllAction->setEnabled(false);
3954 ui->windowHideAllAction->setVisible(false);
3955 ui->windowShowAllAction->setEnabled(true);
3956 ui->windowShowAllAction->setVisible(true);
3957
3958 // ui->toolBar->setVisible(false);
3959 theInfo->setVisible(false);
3960 theDirty->setVisible(false);
3961 p->theFeats->setVisible(false);
3962 theLayers->setVisible(false);
3963 p->theProperties->setVisible(false);
3964 theGPS->setVisible(false);
3965 p->theStyle->setVisible(false);
3966 #ifdef GEOIMAGE
3967 theGeoImage->setVisible(false);
3968 #endif
3969 }
3970
3971 void MainWindow::on_windowShowAllAction_triggered()
3972 {
3973 restoreState(fullscreenState, 1);
3974
3975 ui->windowHideAllAction->setEnabled(true);
3976 ui->windowHideAllAction->setVisible(true);
3977 ui->windowShowAllAction->setEnabled(false);
3978 ui->windowShowAllAction->setVisible(false);
3979 }
3980
3981 void MainWindow::on_gpsConnectAction_triggered()
3982 {
3983 #ifndef Q_OS_SYMBIAN
3984 QGPSDevice* aGps;
3985 if (M_PREFS->getGpsUseGpsd())
3986 aGps = new QGPSDDevice("gpsd");
3987 else
3988 aGps = new QGPSComDevice(M_PREFS->getGpsPort());
3989 #else
3990 QGPSS60Device* aGps = new QGPSS60Device();
3991 #endif
3992 if (aGps->openDevice()) {
3993 connect(aGps, SIGNAL(updatePosition(qreal, qreal, QDateTime, qreal, qreal, qreal)),
3994 this, SLOT(updateGpsPosition(qreal, qreal, QDateTime, qreal, qreal, qreal)));
3995
3996 ui->gpsConnectAction->setEnabled(false);
3997 ui->gpsReplayAction->setEnabled(false);
3998 ui->gpsDisconnectAction->setEnabled(true);
3999 ui->gpsRecordAction->setEnabled(true);
4000 ui->gpsPauseAction->setEnabled(true);
4001 theGPS->setGpsDevice(aGps);
4002 theGPS->resetGpsStatus();
4003 theGPS->startGps();
4004 } else {
4005 QMessageBox::critical(this, tr("GPS error"),
4006 tr("Unable to open GPS port."), QMessageBox::Ok);
4007 delete aGps;
4008 }
4009 }
4010
4011 void MainWindow::on_gpsReplayAction_triggered()
4012 {
4013 QString fileName = QFileDialog::getOpenFileName(
4014 this,
4015 tr("Open NMEA log file"),
4016 "", "NMEA GPS log format (*.nmea *.nma)" );
4017
4018 if (fileName.isEmpty())
4019 return;
4020
4021 QGPSFileDevice* aGps = new QGPSFileDevice(fileName);
4022 if (aGps->openDevice()) {
4023 connect(aGps, SIGNAL(updatePosition(qreal, qreal, QDateTime, qreal, qreal, qreal)),
4024 this, SLOT(updateGpsPosition(qreal, qreal, QDateTime, qreal, qreal, qreal)));
4025
4026 ui->gpsConnectAction->setEnabled(false);
4027 ui->gpsReplayAction->setEnabled(false);
4028 ui->gpsDisconnectAction->setEnabled(true);
4029 ui->gpsRecordAction->setEnabled(true);
4030 ui->gpsPauseAction->setEnabled(true);
4031
4032 theGPS->setGpsDevice(aGps);
4033 theGPS->resetGpsStatus();
4034 theGPS->startGps();
4035 }
4036 }
4037
4038 void MainWindow::on_gpsDisconnectAction_triggered()
4039 {
4040 ui->gpsConnectAction->setEnabled(true);
4041 ui->gpsReplayAction->setEnabled(true);
4042 ui->gpsDisconnectAction->setEnabled(false);
4043 ui->gpsRecordAction->setEnabled(false);
4044 ui->gpsPauseAction->setEnabled(false);
4045 ui->gpsRecordAction->setChecked(false);
4046 ui->gpsPauseAction->setChecked(false);
4047
4048 disconnect(theGPS->getGpsDevice(), SIGNAL(updatePosition(qreal, qreal, QDateTime, qreal, qreal, qreal)),
4049 this, SLOT(updateGpsPosition(qreal, qreal, QDateTime, qreal, qreal, qreal)));
4050 theGPS->stopGps();
4051 theGPS->resetGpsStatus();
4052 }
4053
4054 void MainWindow::updateGpsPosition(qreal latitude, qreal longitude, QDateTime time, qreal altitude, qreal speed, qreal heading)
4055 {
4056 Q_UNUSED(heading)
4057 if (theGPS->getGpsDevice()) {
4058 Coord gpsCoord(longitude,latitude);
4059 if (M_PREFS->getGpsMapCenter()) {
4060 CoordBox vp = theView->viewport();
4061 qreal lonDiff = vp.lonDiff();
4062 qreal latDiff = vp.latDiff();
4063 QRectF vpr = vp.adjusted(lonDiff / 4, -latDiff / 4, -lonDiff / 4, latDiff / 4);
4064 if (!vpr.contains(gpsCoord)) {
4065 theView->setCenter(gpsCoord, theView->rect());
4066 theView->invalidate(false, false, true);
4067 }
4068 }
4069
4070 if (ui->gpsRecordAction->isChecked() && !ui->gpsPauseAction->isChecked()) {
4071 TrackNode* pt = g_backend.allocTrackNode(gpsRecLayer, gpsCoord);
4072 pt->setTime(time);
4073 pt->setElevation(altitude);
4074 pt->setSpeed(speed);
4075 gpsRecLayer->add(pt);
4076 curGpsTrackSegment->add(pt);
4077 }
4078 }
4079 theView->update();
4080 }
4081
4082 QGPS* MainWindow::gps()
4083 {
4084 return theGPS;
4085 }
4086
4087 void MainWindow::on_gpsCenterAction_triggered()
4088 {
4089 M_PREFS->setGpsMapCenter(!M_PREFS->getGpsMapCenter());
4090 ui->gpsCenterAction->setChecked(M_PREFS->getGpsMapCenter());
4091 invalidateView();
4092 }
4093
4094 void MainWindow::on_gpsRecordAction_triggered()
4095 {
4096 if (ui->gpsRecordAction->isChecked()) {
4097 if (theDocument) {
4098 QString fn = "log-" + QDateTime::currentDateTime().toString(Qt::ISODate);
4099 fn.replace(':', '-');
4100
4101 gpsRecLayer = new TrackLayer();
4102 gpsRecLayer->setName(fn);
4103 theDocument->add(gpsRecLayer);
4104
4105 curGpsTrackSegment = g_backend.allocSegment(gpsRecLayer);
4106 gpsRecLayer->add(curGpsTrackSegment);
4107 } else {
4108 ui->gpsRecordAction->setChecked(false);
4109 }
4110 } else {
4111 ui->gpsPauseAction->setChecked(false);
4112 }
4113 }
4114 void MainWindow::on_gpsPauseAction_triggered()
4115 {
4116 if (ui->gpsPauseAction->isChecked()) {
4117 if (!ui->gpsRecordAction->isChecked()) {
4118 ui->gpsPauseAction->setChecked(false);
4119 }
4120 } else {
4121 if (theDocument && ui->gpsRecordAction->isChecked()) {
4122 curGpsTrackSegment = g_backend.allocSegment(gpsRecLayer);
4123 gpsRecLayer->add(curGpsTrackSegment);
4124 }
4125 }
4126 }
4127
4128 void MainWindow::on_toolTemplatesSaveAction_triggered()
4129 {
4130 QString path;
4131 if (getPathToSave(tr("Save Tag Templates"), "mat", tr("Merkaartor tag templates (*.mat)") + "\n" + tr("All Files (*)"), &path)) {
4132 p->theProperties->saveTemplates(path);
4133 }
4134 }
4135
4136 void MainWindow::on_toolTemplatesMergeAction_triggered()
4137 {
4138 QString fileName = QFileDialog::getOpenFileName(
4139 this,
4140 tr("Open Tag Templates"),
4141 "", "Merkaartor tag templates (*.mat)" );
4142
4143 if (fileName.isEmpty())
4144 return;
4145
4146 p->theProperties->mergeTemplates(fileName);
4147 p->theProperties->resetValues();
4148 }
4149
4150 void MainWindow::on_toolTemplatesLoadAction_triggered()
4151 {
4152 QString fileName = QFileDialog::getOpenFileName(
4153 this,
4154 tr("Open Tag Templates"),
4155 "", "Merkaartor tag templates (*.mat)" );
4156
4157 if (fileName.isEmpty())
4158 return;
4159
4160 p->theProperties->loadTemplates(fileName);
4161 p->theProperties->resetValues();
4162 }
4163
4164
4165 #if defined(Q_OS_MAC)
4166 QString MainWindow::macOsTranslationsPath() {
4167 QDir resources = QDir(QCoreApplication::applicationDirPath());
4168 resources.cdUp();
4169 resources.cd("Resources");
4170 return resources.absolutePath();
4171 }
4172 #endif
4173
4174 QString MainWindow::makeAbsolute(const QString& path) {
4175 if (QDir::isAbsolutePath(path))
4176 return path;
4177 else
4178 return QCoreApplication::applicationDirPath() + "/" + path;
4179 }
4180
4181 /* Compose the list of translation paths. */
4182 QStringList MainWindow::translationPaths() {
4183 QStringList paths;
4184 /* Try the macros first, as they are defined by the user. */
4185 paths << makeAbsolute(STRINGIFY(TRANSDIR_SYSTEM));
4186 paths << makeAbsolute(STRINGIFY(TRANSDIR_MERKAARTOR));
4187 paths << QCoreApplication::applicationDirPath();
4188 paths << QCoreApplication::applicationDirPath() + "/translations";
4189 #if defined(Q_OS_MAC)
4190 paths << macOsTranslationsPath();
4191 #endif
4192 paths << QLibraryInfo::location(QLibraryInfo::TranslationsPath);
4193 return paths;
4194 }
4195
4196 bool MainWindow::tryLoadTranslator(const QString& languageFile, QTranslator* theTranslator)
4197 {
4198 qDebug() << "Looking for translations file: " << languageFile;
4199 QStringList paths = translationPaths();
4200 foreach (const QString &path, paths) {
4201 qDebug() << " Trying directory " << path;
4202 if (theTranslator->load(languageFile, path)) {
4203 qDebug() << " Found it.";
4204 return true;
4205 }
4206 }
4207 qDebug() << " Not found.";
4208 return false;
4209 }
4210
4211 void MainWindow::updateLanguage()
4212 {
4213 if (qtTranslator) {
4214 QCoreApplication::removeTranslator(qtTranslator);
4215 }
4216 if (merkaartorTranslator) {
4217 QCoreApplication::removeTranslator(merkaartorTranslator);
4218 }
4219 QString language = getDefaultLanguage();
4220 if (language != "-" && language != "en") {
4221 qtTranslator = new QTranslator;
4222 const QString languagePrefix = language.left(2);
4223 if (tryLoadTranslator("qt_"+languagePrefix, qtTranslator))
4224 QCoreApplication::installTranslator(qtTranslator);
4225
4226 // Do not prevent Merkaartor translations to be loaded, even if there is no Qt translation for the language.
4227 merkaartorTranslator = new QTranslator;
4228 if (tryLoadTranslator("merkaartor_"+language, merkaartorTranslator))
4229 QCoreApplication::installTranslator(merkaartorTranslator);
4230 else
4231 statusBar()->showMessage(tr("Warning! Could not load the Merkaartor translations for the \"%1\" language. Switching to default English.").arg(language), 15000);
4232 }
4233 ui->retranslateUi(this);
4234 }
4235
4236 void MainWindow::updateMenu()
4237 {
4238 if (M_PREFS->getOfflineMode()) {
4239 ui->fileWorkOfflineAction->setChecked(true);
4240 ui->fileDownloadAction->setEnabled(false);
4241 ui->fileDownloadMoreAction->setEnabled(false);
4242 ui->fileUploadAction->setEnabled(false);
4243 } else {
4244 ui->fileWorkOfflineAction->setChecked(false);
4245 ui->fileDownloadAction->setEnabled(true);
4246 ui->fileDownloadMoreAction->setEnabled(true);
4247 ui->fileUploadAction->setEnabled(true);
4248 }
4249
4250 if (M_PREFS->getSeparateMoveMode())
4251 ui->editMoveAction->setVisible(true);
4252 else
4253 ui->editMoveAction->setVisible(false);
4254 }
4255
4256 void MainWindow::on_layersNewImageAction_triggered()
4257 {
4258 if (theDocument)
4259 theDocument->addImageLayer();
4260 }
4261
4262 void MainWindow::on_layersNewDrawingAction_triggered()
4263 {
4264 if (theDocument)
4265 theDocument->addDrawingLayer();
4266 }
4267
4268 void MainWindow::on_layersNewFilterAction_triggered()
4269 {
4270 if (theDocument)
4271 theDocument->addFilterLayer();
4272 }
4273
4274 bool MainWindow::hasUnsavedChanges()
4275 {
4276 if (!theDocument)
4277 return false;
4278
4279 if (theDocument->getDirtySize() == p->latSaveDirtyLevel)
4280 return false;
4281
4282 return true;
4283 }
4284
4285 void MainWindow::syncOSM(const QString& aWeb, const QString& aUser, const QString& aPwd)
4286 {
4287 #ifndef FRISIUS_BUILD
4288 if (checkForConflicts(theDocument)) {
4289 QMessageBox::warning(this,tr("Unresolved conflicts"), tr("Please resolve existing conflicts first"));
4290 return;
4291 }
4292
4293 DirtyListBuild Future;
4294 theDocument->history().buildDirtyList(Future);
4295 DirtyListDescriber Describer(theDocument,Future);
4296 if (Describer.showChanges(this) && Describer.tasks()) {
4297 Future.resetUpdates();
4298 DirtyListExecutorOSC Exec(theDocument,Future,aWeb,aUser,aPwd,Describer.tasks());
4299 if (Exec.executeChanges(this)) {
4300 if (M_PREFS->getAutoHistoryCleanup() && !theDocument->getDirtyOrOriginLayer()->getDirtySize())
4301 theDocument->history().cleanup();
4302
4303 p->latSaveDirtyLevel = theDocument->getDirtySize();
4304
4305 if (!currentProjectFile.isEmpty()) {
4306 if (M_PREFS->getAutoSaveDoc()) {
4307 saveDocument(currentProjectFile);
4308 } else {
4309 if (QMessageBox::warning(this,tr("Unsaved changes"),
4310 tr("It is strongly recommended to save the changes to your document after an upload.\nDo you want to do this now?"),
4311 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) {
4312 saveDocument(currentProjectFile);
4313
4314 }
4315 }
4316 }
4317 }
4318 }
4319 #endif
4320 }
4321
4322 void MainWindow::on_viewWireframeAction_toggled(bool val)
4323 {
4324 M_PREFS->setWireframeView(val);
4325 invalidateView();
4326 }
4327