MapWizard: move most recently used URL on top of static server history (and make...
[marble:marble.git] / src / lib / MapWizard.cpp
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2011 Utku Aydın <utkuaydin34@gmail.com>
9 //
10
11 #include "MapWizard.h"
12 #include "ui_MapWizard.h"
13
14 #include "global.h"
15 #include "MarbleDirs.h"
16 #include "MarbleDebug.h"
17 #include "ServerLayout.h"
18 #include "GeoSceneDocument.h"
19 #include "GeoSceneHead.h"
20 #include "GeoSceneIcon.h"
21 #include "GeoSceneZoom.h"
22 #include "GeoSceneMap.h"
23 #include "GeoSceneLayer.h"
24 #include "GeoSceneTexture.h"
25 #include "GeoSceneSettings.h"
26 #include "GeoSceneProperty.h"
27 #include "GeoSceneGeodata.h"
28 #include "GeoSceneLegend.h"
29 #include "GeoSceneSection.h"
30 #include "GeoSceneItem.h"
31 #include "GeoSceneVector.h"
32 #include "GeoWriter.h"
33 #include "DgmlElementDictionary.h"
34
35 #include <stdlib.h>
36 #include <QtCore/QDir>
37 #include <QtCore/QFile>
38 #include <QtCore/QProcess>
39 #include <QtCore/QSharedPointer>
40 #include <QtCore/QTimer>
41 #include <QtCore/QTemporaryFile>
42 #include <QtGui/QPixmap>
43 #include <QtGui/QMessageBox>
44 #include <QtGui/QFileDialog>
45 #include <QtGui/QImageReader>
46 #include <QtGui/QDialogButtonBox>
47 #include <QtNetwork/QNetworkAccessManager>
48 #include <QtNetwork/QNetworkReply>
49 #include <QtNetwork/QNetworkRequest>
50 #include <QtXml/QDomElement>
51 #include <QtXml/QXmlStreamWriter>
52
53 namespace Marble
54 {
55
56 class MapWizardPrivate
57 {
58 public:
59     MapWizardPrivate()
60         : m_serverCapabilitiesValid( false )
61     {}
62
63     void pageEntered( int id );
64
65     Ui::MapWizard uiWidget;
66
67     QString mapTheme;
68
69     QNetworkAccessManager xmlAccessManager;
70     QNetworkAccessManager legendAccessManager;
71     QNetworkAccessManager levelZeroAccessManager;
72     QStringList wmsServerList;
73     QStringList staticUrlServerList;
74     bool m_serverCapabilitiesValid;
75
76     enum mapType
77     {
78         NoMap,
79         StaticImageMap,
80         WmsMap,
81         StaticUrlMap
82     };
83
84     mapType mapProviderType;
85     QByteArray levelZero;
86     QImage previewImage;
87
88     QString protocol;
89     QString host;
90     QString path;
91     QString query;
92     QString format;
93
94     QString wmsProjection;
95     QStringList wmsLegends;
96
97     QString sourceImage;
98
99     QString dgmlOutput;
100     QString legendHtml;
101 };
102
103 void MapWizardPrivate::pageEntered( int id )
104 {
105     if ( id == 1 ) {
106         m_serverCapabilitiesValid = false;
107     } else if ( id == 2 || id == 4 ) {
108         levelZero.clear();
109         uiWidget.comboBoxStaticUrlServer->clear();
110         uiWidget.comboBoxStaticUrlServer->addItems( staticUrlServerList );
111         uiWidget.comboBoxStaticUrlServer->addItem( "http://" );
112     } else if ( id == 5 ) {
113         if ( mapProviderType == MapWizardPrivate::StaticImageMap ) {
114             previewImage = QImage( uiWidget.lineEditSource->text() ).scaled( 136, 136, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
115         } else {
116             previewImage = QImage::fromData( levelZero ).scaled( 136, 136, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
117         }
118         uiWidget.labelPreview->setPixmap( QPixmap::fromImage( previewImage ) );
119     } else if ( id == 7 ) {
120         uiWidget.labelThumbnail->setPixmap( QPixmap::fromImage( previewImage ) );
121     }
122 }
123
124 MapWizard::MapWizard( QWidget* parent ) : QWizard( parent ), d( new MapWizardPrivate )
125 {
126     d->uiWidget.setupUi( this );
127     QListIterator<QByteArray> i( QImageReader::supportedImageFormats() );
128
129     while( i.hasNext() ) {
130         d->uiWidget.comboBoxStaticUrlFormat->addItem( QString( i.next() ) );
131     }
132     
133     connect( this, SIGNAL( currentIdChanged( int ) ), this, SLOT( pageEntered( int ) ) );
134
135     connect( &( d->xmlAccessManager ), SIGNAL( finished( QNetworkReply* ) ), this, SLOT( parseServerCapabilities( QNetworkReply* ) ) );
136     connect( &( d->legendAccessManager ), SIGNAL( finished( QNetworkReply* ) ), this, SLOT( createWmsLegend( QNetworkReply* ) ) );
137     connect( &( d->levelZeroAccessManager ), SIGNAL( finished( QNetworkReply* ) ), this, SLOT( createLevelZero( QNetworkReply* ) ) );
138
139     connect( d->uiWidget.pushButtonSource, SIGNAL( clicked( bool ) ), this, SLOT( querySourceImage() ) );
140     connect( d->uiWidget.pushButtonPreview, SIGNAL( clicked( bool ) ), this, SLOT( queryPreviewImage() ) );
141     connect( d->uiWidget.pushButtonLegend_2, SIGNAL( clicked( bool ) ), this, SLOT( queryLegendImage() ) );
142
143     connect( d->uiWidget.comboBoxWmsServer, SIGNAL( currentIndexChanged( QString ) ), d->uiWidget.lineEditWmsUrl, SLOT( setText( QString ) ) );
144     connect( d->uiWidget.comboBoxWmsMap, SIGNAL( currentIndexChanged( QString ) ), this, SLOT( autoFillDetails() ) );
145     
146     connect( d->uiWidget.lineEditTitle, SIGNAL( textChanged( QString ) ), d->uiWidget.labelSumMName, SLOT( setText( QString ) ) );
147     connect( d->uiWidget.lineEditTheme, SIGNAL( textChanged( QString ) ), d->uiWidget.labelSumMTheme, SLOT( setText( QString ) ) );
148 }
149
150 MapWizard::~MapWizard()
151 {
152     delete d;
153 }
154
155 void MapWizard::queryServerCapabilities()
156 {
157     QUrl url( d->uiWidget.lineEditWmsUrl->text() );
158     url.addQueryItem( "service", "WMS" );
159     url.addQueryItem( "request", "GetCapabilities" );
160
161     QNetworkRequest request;
162     request.setUrl( url );
163
164     d->xmlAccessManager.get( request );
165 }
166
167 void MapWizard::parseServerCapabilities( QNetworkReply* reply )
168 {
169     button( MapWizard::NextButton )->setEnabled( true );
170
171     QString result( reply->readAll() );
172     QDomDocument xml;
173     if( !xml.setContent( result ) )
174     {
175         QMessageBox::critical( this, tr( "Error while parsing" ), tr( "Wizard cannot parse server's response" ) );
176         return;
177     }
178
179     if( xml.documentElement().firstChildElement().tagName().isNull() )
180     {
181         QMessageBox::critical( this, tr( "Error while parsing" ), tr( "Server is not a Web Map Server." ) );
182         return;
183     }
184
185     QDomElement firstLayer = xml.documentElement().firstChildElement( "Capability" ).firstChildElement( "Layer" );
186     QDomNodeList layers = firstLayer.elementsByTagName( "Layer" );
187
188     d->wmsProjection = firstLayer.firstChildElement( "SRS" ).text();
189     d->uiWidget.comboBoxWmsMap->clear();
190
191     for( int i = 0; i < layers.size(); ++i )
192     {
193         QString theme = layers.at( i ).firstChildElement( "Name" ).text();
194         QString title = layers.at( i ).firstChildElement( "Title" ).text();
195         QDomElement legendUrl = layers.at( i ).firstChildElement( "Style" ).firstChildElement( "LegendURL" );
196         d->uiWidget.comboBoxWmsMap->addItem( title, theme );
197
198         d->wmsLegends.clear();
199         if( legendUrl.isNull() ) {
200             d->wmsLegends.append( QString() );
201         } else {
202             d->wmsLegends.append( legendUrl.firstChildElement( "OnlineResource" ).attribute( "xlink:href" ) );
203         }
204     }
205
206     QDomElement format = xml.documentElement().firstChildElement( "Capability" ).firstChildElement( "Request" )
207                          .firstChildElement( "GetMap" ).firstChildElement( "Format" );
208
209     d->format = format.text().right( format.text().length() - format.text().indexOf( '/' ) - 1 ).toLower();
210
211     if( d->format == "jpeg" ) {
212         d->format = "jpg";
213     }
214
215     if( !d->uiWidget.comboBoxWmsMap->currentText().isEmpty() && !d->wmsServerList.contains( d->uiWidget.lineEditWmsUrl->text() ) ) {
216         d->wmsServerList.append( d->uiWidget.lineEditWmsUrl->text() );
217         setWmsServers( d->wmsServerList );
218     }
219
220     d->m_serverCapabilitiesValid = true;
221     next();
222 }
223
224 void MapWizard::createWmsLegend( QNetworkReply* reply )
225 {
226     QByteArray result( reply->readAll() );
227     QDir map( QString( "%1/maps/earth/%2" ).arg( MarbleDirs::localPath() ).arg( d->mapTheme ) );
228     if( !map.exists( "legend" ) ) {
229         map.mkdir( "legend" );
230     }
231
232     QFile image( QString( "%1/legend/legend.png" ).arg( map.absolutePath() ) );
233     image.open( QIODevice::ReadWrite );
234     image.write( result );
235     image.close();
236
237     createLegendHtml();
238     createLegendFile();
239 }
240
241 void MapWizard::setWmsServers( const QStringList& uris )
242 {
243     d->wmsServerList = uris;
244
245     d->uiWidget.comboBoxWmsServer->clear();
246     d->uiWidget.comboBoxWmsServer->addItems( d->wmsServerList );
247     d->uiWidget.comboBoxWmsServer->addItem( tr( "Custom" ), "http://" );
248 }
249
250 QStringList MapWizard::wmsServers() const
251 {
252     return d->wmsServerList;
253 }
254
255 QStringList MapWizard::staticUrlServers() const
256 {
257     return d->staticUrlServerList;
258 }
259
260 void MapWizard::setStaticUrlServers( const QStringList& uris )
261 {
262     d->staticUrlServerList = uris;
263 }
264
265 void MapWizard::autoFillDetails()
266 {
267     int selected = d->uiWidget.comboBoxWmsMap->currentIndex();
268     d->uiWidget.lineEditTitle->setText( d->uiWidget.comboBoxWmsMap->currentText() );
269     d->uiWidget.lineEditTheme->setText( d->uiWidget.comboBoxWmsMap->itemData( selected ).toString() );
270 }
271
272 bool MapWizard::createFiles( const GeoSceneDocument* document )
273 {
274     // Create directories
275     QDir maps( MarbleDirs::localPath() + "/maps/earth/" );
276     if( !maps.exists( document->head()->theme() ) )
277     {
278         maps.mkdir( document->head()->theme() );
279
280         if( d->mapProviderType == MapWizardPrivate::StaticImageMap )
281         {
282             // Source image
283             QFile sourceImage( d->sourceImage );
284             d->format = d->sourceImage.right( d->sourceImage.length() - d->sourceImage.lastIndexOf( '.' ) - 1 ).toLower();
285             sourceImage.copy( QString( "%1/%2/%2.%3" ).arg( maps.absolutePath() )
286                                                       .arg( document->head()->theme() )
287                                                       .arg( d->format ) );
288         }
289
290         else if( d->mapProviderType == MapWizardPrivate::WmsMap )
291         {
292             maps.mkdir( QString( "%1/0/" ).arg( document->head()->theme() ) );
293             maps.mkdir( QString( "%1/0/0" ).arg( document->head()->theme() ) );
294             const QString path = QString( "%1/%2/0/0/0.%3" ).arg( maps.absolutePath() )
295                                                             .arg( document->head()->theme() )
296                                                             .arg( d->format );
297             QFile baseTile( path );
298             baseTile.open( QFile::WriteOnly );
299             baseTile.write( d->levelZero );
300         }
301
302         else if( d->mapProviderType == MapWizardPrivate::StaticUrlMap )
303         {
304             maps.mkdir( QString( "%1/0/" ).arg( document->head()->theme() ) );
305             maps.mkdir( QString( "%1/0/0" ).arg( document->head()->theme() ) );
306             const QString path = QString( "%1/%2/0/0/0.%3" ).arg( maps.absolutePath() )
307                                                             .arg( document->head()->theme() )
308                                                             .arg( d->uiWidget.comboBoxStaticUrlFormat->currentText() );
309             QFile baseTile( path );
310             baseTile.open( QFile::WriteOnly );
311             baseTile.write( d->levelZero );
312         }
313
314         // Preview image
315         QString pixmapPath = QString( "%1/%2/%3" ).arg( maps.absolutePath() )
316                                                   .arg( document->head()->theme() )
317                                                   .arg( document->head()->icon()->pixmap() );
318         d->previewImage.save( pixmapPath );
319
320         // DGML
321         QFile file( QString( "%1/%2/%2.dgml" ).arg( maps.absolutePath() )
322                                               .arg( document->head()->theme() ) );
323         file.open( QIODevice::ReadWrite );
324         GeoWriter geoWriter;
325         geoWriter.setDocumentType( dgml::dgmlTag_nameSpace20 );
326         geoWriter.write( &file, document );
327         file.close();
328
329         return true;
330     }
331
332     else
333         return false;
334 }
335
336 void MapWizard::createLegendHtml( QString image )
337 {
338     QString htmlOutput;
339     QXmlStreamWriter stream( &htmlOutput );
340     stream.writeStartDocument();
341     stream.writeStartElement( "html" );
342     stream.writeStartElement( "head" );
343
344     stream.writeTextElement( "title", "Marble: Legend" );
345     stream.writeStartElement( "link" );
346     stream.writeAttribute( "href", "legend.css" );
347     stream.writeAttribute( "rel", "stylesheet" );
348     stream.writeAttribute( "type", "text/css" );
349     stream.writeEndElement();
350
351     stream.writeStartElement( "body" );
352     stream.writeStartElement( "img" );
353     stream.writeAttribute( "src", image );
354     stream.writeEndElement();
355     stream.writeComment( " ##customLegendEntries:all## " );
356     stream.writeEndElement();
357     stream.writeEndElement();
358     d->legendHtml = htmlOutput;
359 }
360
361 void MapWizard::createLegendFile()
362 {
363     QDir map( QString( "%1/maps/earth/%2" ).arg( MarbleDirs::localPath() ).arg( d->mapTheme ) );
364     
365     QFile html( QString( "%1/legend.html" ).arg( map.absolutePath() ) );
366     html.open( QIODevice::ReadWrite );
367     html.write( d->legendHtml.toAscii().data() );
368     html.close();
369 }
370
371 void MapWizard::downloadLegend( const QString& url )
372 {
373     QUrl downloadUrl( url );
374     QNetworkRequest request( downloadUrl );
375     d->legendAccessManager.get( request );
376 }
377
378 void MapWizard::downloadLevelZero()
379 {
380     if( d->mapProviderType == MapWizardPrivate::WmsMap )
381     {
382         int selected = d->uiWidget.comboBoxWmsMap->currentIndex();
383         
384         QUrl downloadUrl( d->uiWidget.lineEditWmsUrl->text() );
385         downloadUrl.addQueryItem( "request", "GetMap" );
386         downloadUrl.addQueryItem( "version", "1.1.1" );
387         downloadUrl.addQueryItem( "layers", d->uiWidget.comboBoxWmsMap->itemData( selected ).toString() );
388         downloadUrl.addQueryItem( "srs", "EPSG:4326" );
389         downloadUrl.addQueryItem( "width", "400" );
390         downloadUrl.addQueryItem( "height", "200" );
391         downloadUrl.addQueryItem( "bbox", "-180,-90,180,90" );
392         downloadUrl.addQueryItem( "format", "image/jpeg" );
393         downloadUrl.addQueryItem( "styles", "" );
394         
395         QNetworkRequest request( downloadUrl );
396         d->levelZeroAccessManager.get( request );
397     }
398     
399     else if( d->mapProviderType == MapWizardPrivate::StaticUrlMap )
400     {
401         QString server = d->uiWidget.comboBoxStaticUrlServer->currentText();
402         QString format = d->uiWidget.comboBoxStaticUrlFormat->currentText();
403         QUrl downloadUrl;
404
405         if( server.indexOf( "{x}" ) != -1 && server.indexOf( "{y}" ) != -1 )
406         {
407             server.replace( server.indexOf( "{x}" ), 3,  QString::number( 0 ) );
408             server.replace( server.indexOf( "{y}" ), 3,  QString::number( 0 ) );
409             server.replace( server.indexOf( "{zoomLevel}" ), 11,  QString::number( 0 ) );
410             downloadUrl.setUrl( server );
411         } else {
412             downloadUrl.setUrl( QString( "%1/0/0/0.%2" ).arg( server ).arg( format ) );
413         }
414
415         QNetworkRequest request( downloadUrl );
416         d->levelZeroAccessManager.get( request );
417     }
418 }
419
420 void MapWizard::createLevelZero( QNetworkReply* reply )
421 {
422     button( MapWizard::NextButton )->setEnabled( true );
423
424     d->levelZero = reply->readAll();
425     QImage testImage = QImage::fromData( d->levelZero );
426
427     if ( d->levelZero.isNull() ) {
428         QMessageBox::information( this,
429                                     tr( "Base Tile" ),
430                                     tr( "The base tile could not be downloaded." ) );
431         return;
432     }
433
434     if ( testImage.isNull() ) {
435         QMessageBox::information( this,
436                                     tr( "Base Tile" ),
437                                     tr( "The base tile could not be downloaded successfully. The server replied:\n\n%1" ).arg( QString( d->levelZero ) ) );
438         d->levelZero.clear();
439         return;
440     }
441
442     if ( d->mapProviderType == MapWizardPrivate::StaticUrlMap ) {
443         const QString url = d->uiWidget.comboBoxStaticUrlServer->currentText();
444         d->staticUrlServerList.removeAll( url );
445         d->staticUrlServerList.prepend( url );
446     }
447
448     next();
449 }
450
451 void MapWizard::createLegend()
452 {
453     QDir map( QString( "%1/maps/earth/%2" ).arg( MarbleDirs::localPath() ).arg( d->mapTheme ) );
454     if( !map.exists( "legend" ) ) {
455         map.mkdir( "legend" );
456     }
457
458     QFile image;
459     image.setFileName( d->uiWidget.lineEditLegend_2->text() );
460     image.copy( QString( "%1/legend/legend.png" ).arg( map.absolutePath() ) );
461
462     createLegendHtml();
463     createLegendFile();
464 }
465
466 void MapWizard::querySourceImage()
467 {
468     d->uiWidget.lineEditSource->setText( QFileDialog::getOpenFileName() );
469 }
470
471 void MapWizard::queryPreviewImage()
472 {
473     QString fileName = QFileDialog::getOpenFileName();
474     d->previewImage = QImage( fileName );
475
476     QPixmap preview = QPixmap::fromImage( d->previewImage );
477     d->uiWidget.labelThumbnail->setPixmap( preview );
478     d->uiWidget.labelThumbnail->resize( preview.width(), preview.height() );
479 }
480
481 void MapWizard::queryLegendImage()
482 {
483     QString fileName = QFileDialog::getOpenFileName();
484     d->uiWidget.lineEditLegend_2->setText( fileName );
485     createLegendHtml( d->uiWidget.lineEditLegend_2->text() );
486     d->uiWidget.textBrowserLegend->setHtml( d->legendHtml );
487 }
488
489 QString MapWizard::createArchive( QString mapId )
490 {
491     QStringList splitMapId( mapId.split("/") );
492     QString body = splitMapId[0];
493     QString theme = splitMapId[1];
494     QDir themeDir;
495
496     QStringList tarArgs;
497     tarArgs.append( "--create" );
498     tarArgs.append( "--gzip" );
499     tarArgs.append( "--file" );
500     tarArgs.append( QString( "%1/%2.tar.gz" ).arg( QDir::tempPath() ).arg( theme ) );
501     tarArgs.append( "--directory" );
502
503     if( QFile::exists( QString( "%1/maps/%2" ).arg( MarbleDirs::localPath() ).arg( mapId ) ) )
504     {
505         tarArgs.append( QString( "%1/maps/" ).arg( MarbleDirs::localPath() ) );
506         themeDir.cd( QString( "%1/maps/%2/%3" ).arg( MarbleDirs::localPath() ).arg( body ).arg( theme ) );
507     }
508     
509     else if( QFile::exists( QString( "%1/maps/%2" ).arg( MarbleDirs::systemPath() ).arg( mapId ) ) )
510     {
511         tarArgs.append( QString( "%1/maps/" ).arg( MarbleDirs::systemPath() ) );
512         themeDir.cd( QString( "%1/maps/%2/%3" ).arg( MarbleDirs::systemPath() ).arg( body ).arg( theme ) );
513     }
514     
515     tarArgs.append( QString( "%1/%2/%3.dgml" ).arg( body ).arg( theme ).arg( theme ) );
516     tarArgs.append( QString( "%1/%2/legend.html" ).arg( body ).arg( theme ) );
517     tarArgs.append( QString( "%1/%2/legend" ).arg( body ).arg( theme ) );
518     tarArgs.append( QString( "%1/%2/0" ).arg( body ).arg( theme ) );
519     
520     QStringList previewFilters;
521     previewFilters << "preview.*";
522     QStringList preview = themeDir.entryList( previewFilters );
523     if( !preview.isEmpty() ) {
524         tarArgs.append( QString( "%1/%2/%3" ).arg( body ).arg( theme ).arg( preview[0] ) );
525     }
526     
527     QStringList sourceImgFilters;
528     sourceImgFilters << QString( "%1.jpg" ).arg( theme ) << QString( "%1.png" ).arg( theme ) << QString( "%1.jpeg" ).arg( theme );
529     QStringList sourceImg = themeDir.entryList( sourceImgFilters );
530     if( !sourceImg.isEmpty() ) {
531         tarArgs.append( QString( "%1/%2/%3" ).arg( body ).arg( theme ).arg( sourceImg[0] ) );
532     }
533     
534     QProcess archiver;
535     switch( archiver.execute( "tar", tarArgs ) )
536     {
537     case -2:
538         QMessageBox::critical( this, tr( "Archiving failed" ), tr( "Archiving process cannot be started." ) );
539         break;
540     case -1:
541         QMessageBox::critical( this, tr( "Archiving failed" ), tr( "Archiving process crashed." ) );
542         break;
543     case 0:
544         mDebug() << "Archived the theme sucessfully.";
545         break;
546     }
547     archiver.waitForFinished();
548     return QString( "%1/%2.tar.gz" ).arg( QDir::tempPath() ).arg( theme ); 
549 }
550
551 void MapWizard::deleteArchive( QString mapId )
552 {
553     QStringList splitMapId( mapId.split("/") );
554     QString theme = splitMapId[1];
555     QFile::remove( QString( "%1/%2.tar.gz" ).arg( QDir::tempPath() ).arg( theme ) );
556 }
557
558 bool MapWizard::validateCurrentPage()
559 {
560     if ( currentId() == 1 && !d->m_serverCapabilitiesValid ) {
561         queryServerCapabilities();
562         button( MapWizard::NextButton )->setEnabled( false );
563         return false;
564     }
565
566     if ( ( currentId() == 2 || currentId() == 4 ) && d->levelZero.isNull() ) {
567         downloadLevelZero();
568         button( MapWizard::NextButton )->setEnabled( false );
569         return false;
570     }
571
572     if ( currentId() == 3 ) {
573         d->sourceImage = d->uiWidget.lineEditSource->text();
574         if ( d->sourceImage.isEmpty() ) {
575             QMessageBox::information( this,
576                                       tr( "Source Image" ),
577                                       tr( "Please specify a source image." ) );
578             d->uiWidget.lineEditSource->setFocus();
579             return false;
580         }
581
582         if ( !QFileInfo( d->sourceImage ).exists() ) {
583             QMessageBox::information( this,
584                                       tr( "Source Image" ),
585                                       tr( "The source image you specified does not exist. Please specify a different one." ) );
586             d->uiWidget.lineEditSource->setFocus();
587             d->uiWidget.lineEditSource->selectAll();
588             return false;
589         }
590
591         if ( QImage( d->sourceImage ).isNull() ) {
592             QMessageBox::information( this,
593                                       tr( "Source Image" ),
594                                       tr( "The source image you specified does not seem to be an image. Please specify a different image file." ) );
595             d->uiWidget.lineEditSource->setFocus();
596             d->uiWidget.lineEditSource->selectAll();
597             return false;
598         }
599     }
600
601     if ( currentId() == 6 ) {
602         if ( d->uiWidget.lineEditTitle->text().isEmpty() ) {
603             QMessageBox::information( this, tr( "Map Title" ), tr( "Please specify a map title." ) );
604             d->uiWidget.lineEditTitle->setFocus();
605             return false;
606         }
607
608         d->mapTheme = d->uiWidget.lineEditTheme->text();
609         if ( d->mapTheme.isEmpty() ) {
610             QMessageBox::information( this, tr( "Map Name" ), tr( "Please specify a map name." ) );
611             d->uiWidget.lineEditTheme->setFocus();
612             return false;
613         }
614
615         const QDir destinationDir( QString( "%1/maps/earth/%2" ).arg( MarbleDirs::localPath() ).arg( d->mapTheme ) );
616         if ( destinationDir.exists() ) {
617             QMessageBox::information( this,
618                                     tr( "Map Name" ),
619                                     tr( "Please specify another map name, since there is already a map named \"%1\"." ).arg( d->mapTheme ) );
620             d->uiWidget.lineEditTheme->setFocus();
621             d->uiWidget.lineEditTheme->selectAll();
622             return false;
623         }
624
625         if ( d->previewImage.isNull() ) {
626             QMessageBox::information( this, tr( "Preview Image" ), tr( "Please specify a preview image." ) );
627             d->uiWidget.pushButtonPreview->setFocus();
628             return false;
629         }
630     }
631
632     return QWizard::validateCurrentPage();
633 }
634
635 int MapWizard::nextId() const
636 {
637     switch( currentId() )
638     {
639     case 0:
640         if( d->uiWidget.radioButtonWms->isChecked() ) {
641             d->mapProviderType = MapWizardPrivate::WmsMap;
642             return 1;
643         } else if( d->uiWidget.radioButtonBitmap->isChecked() ) {
644             d->mapProviderType = MapWizardPrivate::StaticImageMap;
645             return 3;
646         } else if( d->uiWidget.radioButtonStaticUrl->isChecked() ) {
647             d->mapProviderType = MapWizardPrivate::StaticUrlMap;
648             return 4;
649         }
650         break;
651
652     case 2: // WMS
653         return 5;
654         break;
655
656     case 3: // Static Image
657         return 5;
658         break;
659
660     case 7: // Finish
661         return -1;
662         break;
663
664     default:
665         break;
666
667     }
668     
669     return currentId() + 1;
670 }
671
672 GeoSceneDocument* MapWizard::createDocument()
673 {
674     GeoSceneDocument *document = new GeoSceneDocument;
675        
676     GeoSceneHead *head = document->head();
677     head->setName( d->uiWidget.lineEditTitle->text() );
678     head->setTheme( d->uiWidget.lineEditTheme->text() );
679     head->setTarget( "earth" );
680     head->setDescription( d->uiWidget.textEditDesc->document()->toHtml() );
681     head->setVisible( true );
682         
683     GeoSceneIcon *icon = head->icon();
684     icon->setPixmap( QString( "preview.png" ) );
685     
686     GeoSceneZoom *zoom = head->zoom();
687     zoom->setMinimum( 900 );
688     zoom->setMaximum( 3500 );
689     zoom->setDiscrete( false );
690     
691     GeoSceneTexture *texture = new GeoSceneTexture( "map" );
692     texture->setExpire( 31536000 );
693     texture->setSourceDir( "earth/" + document->head()->theme() ); 
694     if( d->mapProviderType == MapWizardPrivate::WmsMap )
695     {
696         texture->setFileFormat( d->format );
697         QString layer = d->uiWidget.comboBoxWmsMap->itemData( d->uiWidget.comboBoxWmsMap->currentIndex() ).toString();
698         QUrl downloadUrl = QUrl( d->uiWidget.lineEditWmsUrl->text() );
699         downloadUrl.addQueryItem( "layers", layer );
700         texture->addDownloadUrl( downloadUrl );
701         texture->setMaximumTileLevel( 20 );
702         texture->setLevelZeroRows( 1 );
703         texture->setLevelZeroColumns( 1 );
704         texture->setServerLayout( new WmsServerLayout( texture ) );
705         texture->setProjection( GeoSceneTexture::Equirectangular );
706     }
707     
708     else if( d->mapProviderType == MapWizardPrivate::StaticUrlMap )
709     {
710         texture->setFileFormat( d->uiWidget.comboBoxStaticUrlFormat->currentText() );
711         QUrl downloadUrl = QUrl( d->uiWidget.comboBoxStaticUrlServer->currentText() );
712         texture->addDownloadPolicy( DownloadBrowse, 20 );
713         texture->addDownloadPolicy( DownloadBulk, 2 );
714         texture->addDownloadUrl( downloadUrl );
715         texture->setMaximumTileLevel( 20 );
716         texture->setLevelZeroRows( 1 );
717         texture->setLevelZeroColumns( 1 );
718         texture->setServerLayout( new CustomServerLayout( texture ) );
719         texture->setProjection( GeoSceneTexture::Mercator );
720     }
721     
722     else if( d->mapProviderType == MapWizardPrivate::StaticImageMap )
723     {
724         QString image = d->uiWidget.lineEditSource->text();
725         d->format = image.right( image.length() - image.lastIndexOf( '.' ) - 1 ).toLower();
726         texture->setFileFormat( d->format.toUpper() );
727         texture->setInstallMap( document->head()->theme() + "." + d->format );
728         texture->setServerLayout( new MarbleServerLayout( texture ) );
729         texture->setProjection( GeoSceneTexture::Equirectangular );
730         int imageWidth = QImage( image ).width();
731         int tileSize = c_defaultTileSize;
732         
733         float approxMaxTileLevel = log( imageWidth / ( 2.0 * tileSize ) ) / log( 2.0 );
734         int  maxTileLevel = 0;
735         if ( approxMaxTileLevel == int( approxMaxTileLevel ) ) {
736             maxTileLevel = static_cast<int>( approxMaxTileLevel );
737         } else {
738             maxTileLevel = static_cast<int>( approxMaxTileLevel + 1 );
739         }
740         texture->setMaximumTileLevel( maxTileLevel );
741     }
742     
743     GeoSceneLayer *layer = new GeoSceneLayer( d->uiWidget.lineEditTheme->text() );
744     layer->setBackend( "texture" );
745     layer->addDataset( texture );
746     
747     GeoSceneLayer* secondLayer = new GeoSceneLayer( "standardplaces" );    
748     secondLayer->setBackend( "geodata" );
749   
750     GeoSceneGeodata* cityplacemarks = new GeoSceneGeodata( "cityplacemarks" );
751     cityplacemarks->setSourceFile( "cityplacemarks.kml" );
752     cityplacemarks->setSourceFileFormat( "KML" );
753     secondLayer->addDataset( cityplacemarks );
754     
755     GeoSceneGeodata* baseplacemarks = new GeoSceneGeodata( "baseplacemarks" );
756     baseplacemarks->setSourceFile( "baseplacemarks.kml" );
757     baseplacemarks->setSourceFileFormat( "KML" );
758     secondLayer->addDataset( baseplacemarks );
759     
760     GeoSceneGeodata* elevplacemarks = new GeoSceneGeodata( "elevplacemarks" );
761     elevplacemarks->setSourceFile( "elevplacemarks.kml" );
762     elevplacemarks->setSourceFileFormat( "KML" );
763     secondLayer->addDataset( elevplacemarks );
764     
765     GeoSceneGeodata* observatoryplacemarks = new GeoSceneGeodata( "observatoryplacemarks" );
766     observatoryplacemarks->setSourceFile( "observatoryplacemarks.kml" );
767     observatoryplacemarks->setSourceFileFormat( "KML" );
768     secondLayer->addDataset( observatoryplacemarks );
769     
770     GeoSceneGeodata* otherplacemarks = new GeoSceneGeodata( "otherplacemarks" );
771     otherplacemarks->setSourceFile( "otherplacemarks.kml" );
772     otherplacemarks->setSourceFileFormat( "KML" );
773     secondLayer->addDataset( otherplacemarks );
774     
775     GeoSceneGeodata* boundaryplacemarks = new GeoSceneGeodata( "boundaryplacemarks" );
776     boundaryplacemarks->setSourceFile( "boundaryplacemarks.kml" );
777     boundaryplacemarks->setSourceFileFormat( "KML" );
778     secondLayer->addDataset( boundaryplacemarks );
779     
780     GeoSceneMap *map = document->map();
781     map->addLayer( layer );
782     map->addLayer( secondLayer );
783     
784     GeoSceneSettings *settings = document->settings();
785     GeoSceneLegend *legend = document->legend();
786     
787     if( d->uiWidget.checkBoxCoord->checkState() == Qt::Checked )
788     {
789         GeoSceneProperty *coorGrid = new GeoSceneProperty( "coordinate-grid" );
790         coorGrid->setValue( true );
791         coorGrid->setAvailable( true );
792         settings->addProperty( coorGrid );
793         
794         GeoSceneSection *coorSection = new GeoSceneSection( "coordinate-grid" );
795         coorSection->setHeading( "Coordinate Grid" );
796         coorSection->setCheckable( true );
797         coorSection->setConnectTo( "coordinate-grid" );
798         coorSection->setSpacing( 12 );
799         legend->addSection( coorSection );
800     }
801     
802     if( d->uiWidget.checkBoxInterest->checkState() == Qt::Checked )
803     {
804         GeoSceneProperty *poiProperty = new GeoSceneProperty( "otherplaces" );
805         poiProperty->setValue( true );
806         poiProperty->setAvailable( true );
807         settings->addProperty( poiProperty );
808         
809         GeoSceneSection *poiSection = new GeoSceneSection( "otherplaces" );
810         poiSection->setHeading( "Places of Interest" );
811         poiSection->setCheckable( true );
812         poiSection->setConnectTo( "otherplaces" );
813         poiSection->setSpacing( 12 );
814         
815         GeoSceneItem *geoPole = new GeoSceneItem( "geographic-pole" );
816         GeoSceneIcon *geoPoleIcon = geoPole->icon();
817         geoPole->setText( tr("Geographic Pole") );
818         geoPoleIcon->setPixmap( "bitmaps/pole_1.png" );    
819         poiSection->addItem( geoPole );
820         
821         GeoSceneItem *magPole = new GeoSceneItem( "magnetic-pole" );
822         GeoSceneIcon *magPoleIcon = magPole->icon();
823         magPole->setText( tr("Magnetic Pole") );
824         magPoleIcon->setPixmap( "bitmaps/pole_2.png" );    
825         poiSection->addItem( magPole );
826         
827         GeoSceneItem *airport = new GeoSceneItem( "airport" );
828         GeoSceneIcon *airportIcon = airport->icon();
829         airport->setText( tr("Airport") );
830         airportIcon->setPixmap( "bitmaps/airport.png" );    
831         poiSection->addItem( airport );
832         
833         GeoSceneItem *shipwreck = new GeoSceneItem( "shipwreck" );
834         GeoSceneIcon *shipwreckIcon = shipwreck->icon();
835         shipwreck->setText( tr("Shipwreck") );
836         shipwreckIcon->setPixmap( "bitmaps/shipwreck.png" );    
837         poiSection->addItem( shipwreck );
838         
839         GeoSceneItem *observatory = new GeoSceneItem( "observatory" );
840         GeoSceneIcon *observatoryIcon = observatory->icon();
841         observatory->setText( tr("Observatory") );
842         observatoryIcon->setPixmap( "bitmaps/observatory.png" );    
843         poiSection->addItem( observatory );
844         
845         legend->addSection( poiSection );
846     }
847     
848     if( d->uiWidget.checkBoxTer->checkState() == Qt::Checked )
849     {
850         GeoSceneProperty *terrainProperty = new GeoSceneProperty( "terrain" );
851         terrainProperty->setValue( true );
852         terrainProperty->setAvailable( true );
853         settings->addProperty( terrainProperty );     
854         
855         GeoSceneSection *terrainSection = new GeoSceneSection( "terrain" );
856         terrainSection->setHeading( "Terrain" );
857         terrainSection->setCheckable( true );
858         terrainSection->setConnectTo( "terrain" );
859         terrainSection->setSpacing( 12 );    
860         
861         GeoSceneItem *mountain = new GeoSceneItem( "mountain" );
862         GeoSceneIcon *mountainIcon = mountain->icon();
863         mountain->setText( tr("Mountain") );
864         mountainIcon->setPixmap( "bitmaps/mountain_1.png" );    
865         terrainSection->addItem( mountain );
866         
867         GeoSceneItem *volcano = new GeoSceneItem( "volcano" );
868         GeoSceneIcon *volcanoIcon = volcano->icon();
869         volcano->setText( tr("Volcano") );
870         volcanoIcon->setPixmap( "bitmaps/volcano_1.png" );    
871         terrainSection->addItem( volcano );   
872         
873         legend->addSection( terrainSection );
874         
875     }
876     
877     if( d->uiWidget.checkBoxPop->checkState() == Qt::Checked )
878     {
879         GeoSceneProperty *placesProperty = new GeoSceneProperty( "places" );
880         placesProperty->setValue( true );
881         placesProperty->setAvailable( true );
882         settings->addProperty( placesProperty );
883         
884         GeoSceneProperty *citiesProperty = new GeoSceneProperty( "cities" );
885         citiesProperty->setValue( true );
886         citiesProperty->setAvailable( true );
887         settings->addProperty( citiesProperty );
888     }
889     
890     if( d->uiWidget.checkBoxBorder->checkState() == Qt::Checked )
891     {
892         GeoSceneSection *bordersSection = new GeoSceneSection( "borders" );
893         bordersSection->setHeading( "Boundaries" );
894         bordersSection->setCheckable( true );
895         bordersSection->setConnectTo( "borders" );
896         bordersSection->setSpacing( 12 );
897         
898         GeoSceneItem *internationalBoundary = new GeoSceneItem( "international-boundary" );
899         GeoSceneIcon *internationalBoundaryIcon = internationalBoundary->icon();
900         internationalBoundary->setText( tr("International") );
901         internationalBoundaryIcon->setPixmap( "bitmaps/border_1.png" );    
902         bordersSection->addItem( internationalBoundary ); 
903         
904         GeoSceneItem *stateBoundary = new GeoSceneItem( "state" );
905         GeoSceneIcon *stateBoundaryIcon = stateBoundary->icon();
906         stateBoundary->setText( tr("State") );
907         stateBoundaryIcon->setPixmap( "bitmaps/border_2.png" );
908         bordersSection->addItem( stateBoundary );
909         
910         GeoSceneProperty *bordersProperty = new GeoSceneProperty( "borders" );
911         bordersProperty->setValue( false );
912         bordersProperty->setAvailable( true );
913         settings->addProperty( bordersProperty );
914         
915         GeoSceneProperty *intBoundariesProperty = new GeoSceneProperty( "international-boundaries" );
916         intBoundariesProperty->setValue( false );
917         intBoundariesProperty->setAvailable( true );
918         settings->addProperty( intBoundariesProperty );
919         
920         GeoSceneProperty *stateBounderiesProperty = new GeoSceneProperty( "state-boundaries" );
921         stateBounderiesProperty->setValue( false );
922         stateBounderiesProperty->setAvailable( true );
923         settings->addProperty( stateBounderiesProperty );
924         
925         legend->addSection( bordersSection );
926         
927         GeoSceneLayer* mwdbii = new GeoSceneLayer( "mwdbii" );
928         mwdbii->setBackend( "vector" );
929         mwdbii->setRole( "polyline" ); 
930         
931         GeoSceneVector* vector = new GeoSceneVector( "pdiffborder" );
932         vector->setFeature( "border" );
933         vector->setFileFormat( "PNT" );
934         vector->setSourceFile( "earth/mwdbii/PDIFFBORDER.PNT" );
935         vector->pen().setColor( "#ffe300" );
936         mwdbii->addDataset( vector );
937         map->addLayer( mwdbii );
938     }
939     
940     GeoSceneProperty *overviewmap = new GeoSceneProperty( "overviewmap" );
941     overviewmap->setValue( true );
942     overviewmap->setAvailable( true );
943     settings->addProperty( overviewmap );
944     
945     GeoSceneProperty *compass = new GeoSceneProperty( "compass" );
946     compass->setValue( true );
947     compass->setAvailable( true );
948     settings->addProperty( compass );
949     
950     GeoSceneProperty *scalebar = new GeoSceneProperty( "scalebar" );
951     scalebar->setValue( true );
952     scalebar->setAvailable( true );
953     settings->addProperty( scalebar );
954     
955     return document;
956 }
957
958 void MapWizard::accept()
959 {
960     Q_ASSERT( d->mapProviderType != MapWizardPrivate::NoMap );
961
962     Q_ASSERT( d->format == d->format.toLower() );
963     Q_ASSERT( !d->mapTheme.isEmpty() );
964
965     if ( d->mapProviderType == MapWizardPrivate::StaticImageMap )
966     {
967         d->sourceImage = d->uiWidget.lineEditSource->text();
968         Q_ASSERT( !d->sourceImage.isEmpty() );
969         Q_ASSERT( QFile( d->sourceImage ).exists() );
970     }
971     else if ( d->mapProviderType == MapWizardPrivate::WmsMap )
972     {
973         Q_ASSERT( !d->uiWidget.comboBoxWmsMap->currentText().isEmpty() );
974
975         QUrl wmsUrl( d->uiWidget.lineEditWmsUrl->text() );
976         d->protocol = wmsUrl.toString().left( wmsUrl.toString().indexOf( ':' ) );
977         d->host =  QString( wmsUrl.encodedHost() );
978         d->path =  QString( wmsUrl.encodedPath() );
979         d->query = QString( "layers=%1&%2" ).arg( d->uiWidget.comboBoxWmsMap->itemData( d->uiWidget.comboBoxWmsMap->currentIndex() ).toString() )
980                       .arg( QString( wmsUrl.encodedQuery() ) );
981
982         Q_ASSERT( !d->levelZero.isNull() );
983         Q_ASSERT( !QImage::fromData( d->levelZero ).isNull() );
984     }
985     else if ( d->mapProviderType == MapWizardPrivate::StaticImageMap )
986     {
987         QUrl staticImageUrl( d->uiWidget.comboBoxStaticUrlServer->currentText() );
988         d->protocol = staticImageUrl.toString().left( staticImageUrl.toString().indexOf( ':' ) );
989         d->host =  QString( staticImageUrl.encodedHost() );
990         d->path =  QUrl::fromPercentEncoding( staticImageUrl.encodedPath() );
991
992         Q_ASSERT( !d->levelZero.isNull() );
993         Q_ASSERT( !QImage::fromData( d->levelZero ).isNull() );
994     }
995
996     QSharedPointer<GeoSceneDocument> document( createDocument() );
997     Q_ASSERT( !document->head()->description().isEmpty() );
998     Q_ASSERT( !document->head()->name().isEmpty() );
999
1000     if( createFiles( document.data() ) )
1001     {
1002         if( d->mapProviderType == MapWizardPrivate::WmsMap )
1003         {
1004             if( d->wmsLegends.isEmpty() && d->wmsLegends.at( d->uiWidget.comboBoxWmsMap->currentIndex() ).isEmpty() )
1005                 downloadLegend( d->wmsLegends.at( d->uiWidget.comboBoxWmsMap->currentIndex() ) );
1006         } else if( d->mapProviderType == MapWizardPrivate::StaticImageMap || d->mapProviderType == MapWizardPrivate::StaticUrlMap ) {
1007             createLegend();
1008         }
1009
1010         QDialog::accept();
1011         d->uiWidget.lineEditTitle->clear();
1012         d->uiWidget.lineEditTheme->clear();
1013         d->uiWidget.textEditDesc->clear();
1014         d->uiWidget.labelPreview->clear();
1015         d->uiWidget.lineEditSource->clear();
1016         d->dgmlOutput = QString();
1017         QTimer::singleShot( 0, this, SLOT( restart() ) );
1018     }
1019
1020     else
1021     {
1022         QMessageBox::critical( this, tr( "Problem while creating files" ), tr( "Check if a theme with the same name exists." ) );
1023         return;
1024     }
1025 }
1026
1027 }
1028
1029 #include "MapWizard.moc"