Quantum GIS API Documentation  master-693a1fe
src/gui/symbology-ng/qgsstylev2exportimportdialog.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsstylev2exportimportdialog.cpp
00003     ---------------------
00004     begin                : Jan 2011
00005     copyright            : (C) 2011 by Alexander Bruy
00006     email                : alexander dot bruy at gmail dot com
00007 
00008  ***************************************************************************
00009  *                                                                         *
00010  *   This program is free software; you can redistribute it and/or modify  *
00011  *   it under the terms of the GNU General Public License as published by  *
00012  *   the Free Software Foundation; either version 2 of the License, or     *
00013  *   (at your option) any later version.                                   *
00014  *                                                                         *
00015  ***************************************************************************/
00016 #include "qgsstylev2exportimportdialog.h"
00017 
00018 #include "qgsstylev2.h"
00019 #include "qgssymbolv2.h"
00020 #include "qgssymbollayerv2utils.h"
00021 #include "qgsvectorcolorrampv2.h"
00022 #include "qgslogger.h"
00023 
00024 #include <QInputDialog>
00025 #include <QCloseEvent>
00026 #include <QFileDialog>
00027 #include <QMessageBox>
00028 #include <QPushButton>
00029 #include <QStandardItemModel>
00030 
00031 QgsStyleV2ExportImportDialog::QgsStyleV2ExportImportDialog( QgsStyleV2* style, QWidget *parent, Mode mode )
00032     : QDialog( parent )
00033     , mDialogMode( mode )
00034     , mQgisStyle( style )
00035 {
00036   setupUi( this );
00037 
00038   // additional buttons
00039   QPushButton *pb;
00040   pb = new QPushButton( tr( "Select all" ) );
00041   buttonBox->addButton( pb, QDialogButtonBox::ActionRole );
00042   connect( pb, SIGNAL( clicked() ), this, SLOT( selectAll() ) );
00043 
00044   pb = new QPushButton( tr( "Clear selection" ) );
00045   buttonBox->addButton( pb, QDialogButtonBox::ActionRole );
00046   connect( pb, SIGNAL( clicked() ), this, SLOT( clearSelection() ) );
00047 
00048   QStandardItemModel* model = new QStandardItemModel( listItems );
00049   listItems->setModel( model );
00050 
00051   mTempStyle = new QgsStyleV2();
00052   // TODO validate
00053   mFileName = "";
00054   mProgressDlg = NULL;
00055   mTempFile = NULL;
00056   mNetManager = new QNetworkAccessManager( this );
00057   mNetReply = NULL;
00058 
00059   if ( mDialogMode == Import )
00060   {
00061     setWindowTitle( tr( "Import style(s)" ) );
00062     // populate the import types
00063     importTypeCombo->addItem( "file specified below", QVariant( "file" ) );
00064     // importTypeCombo->addItem( "official QGIS repo online", QVariant( "official" ) );
00065     importTypeCombo->addItem( "URL specified below", QVariant( "url" ) );
00066     connect( importTypeCombo, SIGNAL( currentIndexChanged( int ) ), this, SLOT( importTypeChanged( int ) ) );
00067 
00068     QStringList groups = mQgisStyle->groupNames();
00069     groupCombo->addItem( "imported", QVariant( "new" ) );
00070     foreach ( QString gName, groups )
00071     {
00072       groupCombo->addItem( gName );
00073     }
00074 
00075     btnBrowse->setText( "Browse" );
00076     connect( btnBrowse, SIGNAL( clicked() ), this, SLOT( browse() ) );
00077 
00078     label->setText( tr( "Select symbols to import" ) );
00079     buttonBox->button( QDialogButtonBox::Ok )->setText( tr( "Import" ) );
00080   }
00081   else
00082   {
00083     setWindowTitle( tr( "Export style(s)" ) );
00084     // hide import specific controls when exporting
00085     btnBrowse->setHidden( true );
00086     fromLabel->setHidden( true );
00087     importTypeCombo->setHidden( true );
00088     locationLabel->setHidden( true );
00089     locationLineEdit->setHidden( true );
00090     groupLabel->setHidden( true );
00091     groupCombo->setHidden( true );
00092 
00093     buttonBox->button( QDialogButtonBox::Ok )->setText( tr( "Export" ) );
00094     if ( !populateStyles( mQgisStyle ) )
00095     {
00096       QApplication::postEvent( this, new QCloseEvent() );
00097     }
00098   }
00099 
00100   // use Ok button for starting import and export operations
00101   disconnect( buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
00102   connect( buttonBox, SIGNAL( accepted() ), this, SLOT( doExportImport() ) );
00103 }
00104 
00105 void QgsStyleV2ExportImportDialog::doExportImport()
00106 {
00107   QModelIndexList selection = listItems->selectionModel()->selectedIndexes();
00108   if ( selection.isEmpty() )
00109   {
00110     QMessageBox::warning( this, tr( "Export/import error" ),
00111                           tr( "You should select at least one symbol/color ramp." ) );
00112     return;
00113   }
00114 
00115   if ( mDialogMode == Export )
00116   {
00117     QString fileName = QFileDialog::getSaveFileName( this, tr( "Save styles" ), ".",
00118                        tr( "XML files (*.xml *.XML)" ) );
00119     if ( fileName.isEmpty() )
00120     {
00121       return;
00122     }
00123 
00124     // ensure the user never ommited the extension from the file name
00125     if ( !fileName.toLower().endsWith( ".xml" ) )
00126     {
00127       fileName += ".xml";
00128     }
00129 
00130     mFileName = fileName;
00131 
00132     moveStyles( &selection, mQgisStyle, mTempStyle );
00133     if ( !mTempStyle->exportXML( mFileName ) )
00134     {
00135       QMessageBox::warning( this, tr( "Export/import error" ),
00136                             tr( "Error when saving selected symbols to file:\n%1" )
00137                             .arg( mTempStyle->errorString() ) );
00138       return;
00139     }
00140   }
00141   else // import
00142   {
00143     moveStyles( &selection, mTempStyle, mQgisStyle );
00144 
00145     // clear model
00146     QStandardItemModel* model = qobject_cast<QStandardItemModel*>( listItems->model() );
00147     model->clear();
00148     accept();
00149   }
00150 
00151   mFileName = "";
00152   mTempStyle->clear();
00153 }
00154 
00155 bool QgsStyleV2ExportImportDialog::populateStyles( QgsStyleV2* style )
00156 {
00157   // load symbols and color ramps from file
00158   if ( mDialogMode == Import )
00159   {
00160     // NOTE mTempStyle is style here
00161     if ( !style->importXML( mFileName ) )
00162     {
00163       QMessageBox::warning( this, tr( "Import error" ),
00164                             tr( "An error occured during import:\n%1" ).arg( style->errorString() ) );
00165       return false;
00166     }
00167   }
00168 
00169   QStandardItemModel* model = qobject_cast<QStandardItemModel*>( listItems->model() );
00170   model->clear();
00171 
00172   // populate symbols
00173   QStringList styleNames = style->symbolNames();
00174   QString name;
00175 
00176   for ( int i = 0; i < styleNames.count(); ++i )
00177   {
00178     name = styleNames[i];
00179     QgsSymbolV2* symbol = style->symbol( name );
00180     QStandardItem* item = new QStandardItem( name );
00181     QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( symbol, listItems->iconSize() );
00182     item->setIcon( icon );
00183     model->appendRow( item );
00184     delete symbol;
00185   }
00186 
00187   // and color ramps
00188   styleNames = style->colorRampNames();
00189 
00190   for ( int i = 0; i < styleNames.count(); ++i )
00191   {
00192     name = styleNames[i];
00193     QgsVectorColorRampV2* ramp = style->colorRamp( name );
00194 
00195     QStandardItem* item = new QStandardItem( name );
00196     QIcon icon = QgsSymbolLayerV2Utils::colorRampPreviewIcon( ramp, listItems->iconSize() );
00197     item->setIcon( icon );
00198     model->appendRow( item );
00199     delete ramp;
00200   }
00201   return true;
00202 }
00203 
00204 void QgsStyleV2ExportImportDialog::moveStyles( QModelIndexList* selection, QgsStyleV2* src, QgsStyleV2* dst )
00205 {
00206   QString symbolName;
00207   QgsSymbolV2* symbol;
00208   QgsVectorColorRampV2 *ramp = 0;
00209   QModelIndex index;
00210   bool isSymbol = true;
00211   bool prompt = true;
00212   bool overwrite = true;
00213   int groupid = 0;
00214 
00215   // get the groupid when going for import
00216   if ( mDialogMode == Import )
00217   {
00218     int index = groupCombo->currentIndex();
00219     QString name = groupCombo->itemText( index );
00220     if ( name.isEmpty() )
00221     {
00222       // get name of the group
00223       bool nameInvalid = true;
00224       while ( nameInvalid )
00225       {
00226         bool ok;
00227         name = QInputDialog::getText( this, tr( "Group Name" ),
00228                                       tr( "Please enter a name for new group:" ),
00229                                       QLineEdit::Normal,
00230                                       tr( "imported" ),
00231                                       &ok );
00232         if ( !ok )
00233         {
00234           QMessageBox::warning( this, tr( "New Group" ),
00235                                 tr( "New group cannot be created without a name. Kindly enter a name." ) );
00236           continue;
00237         }
00238         // validate name
00239         if ( name.isEmpty() )
00240         {
00241           QMessageBox::warning( this, tr( "New group" ),
00242                                 tr( "Cannot create a group without name. Enter a name." ) );
00243         }
00244         else
00245         {
00246           // valid name
00247           nameInvalid = false;
00248         }
00249       }
00250       groupid = dst->addGroup( name );
00251     }
00252     else if ( dst->groupNames().contains( name ) )
00253     {
00254       groupid = dst->groupId( name );
00255     }
00256     else
00257     {
00258       groupid = dst->addGroup( name );
00259     }
00260   }
00261 
00262   for ( int i = 0; i < selection->size(); ++i )
00263   {
00264     index = selection->at( i );
00265     symbolName = index.model()->data( index, 0 ).toString();
00266     symbol = src->symbol( symbolName );
00267     if ( symbol == NULL )
00268     {
00269       isSymbol = false;
00270       ramp = src->colorRamp( symbolName );
00271     }
00272 
00273     if ( isSymbol )
00274     {
00275       if ( dst->symbolNames().contains( symbolName ) && prompt )
00276       {
00277         int res = QMessageBox::warning( this, tr( "Duplicate names" ),
00278                                         tr( "Symbol with name '%1' already exists.\nOverwrite?" )
00279                                         .arg( symbolName ),
00280                                         QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
00281         switch ( res )
00282         {
00283           case QMessageBox::Cancel:
00284             return;
00285           case QMessageBox::No:
00286             continue;
00287           case QMessageBox::Yes:
00288             dst->addSymbol( symbolName, symbol );
00289             if ( mDialogMode == Import )
00290               dst->saveSymbol( symbolName, symbol, groupid, QStringList() );
00291             continue;
00292           case QMessageBox::YesToAll:
00293             prompt = false;
00294             overwrite = true;
00295             break;
00296           case QMessageBox::NoToAll:
00297             prompt = false;
00298             overwrite = false;
00299             break;
00300         }
00301       }
00302 
00303       if ( dst->symbolNames().contains( symbolName ) && overwrite )
00304       {
00305         dst->addSymbol( symbolName, symbol );
00306         if ( mDialogMode == Import )
00307           dst->saveSymbol( symbolName, symbol, groupid, QStringList() );
00308       }
00309       else if ( dst->symbolNames().contains( symbolName ) && !overwrite )
00310       {
00311         continue;
00312       }
00313       else
00314       {
00315         dst->addSymbol( symbolName, symbol );
00316         if ( mDialogMode == Import )
00317           dst->saveSymbol( symbolName, symbol, groupid, QStringList() );
00318       }
00319     }
00320     else
00321     {
00322       if ( dst->colorRampNames().contains( symbolName ) && prompt )
00323       {
00324         int res = QMessageBox::warning( this, tr( "Duplicate names" ),
00325                                         tr( "Color ramp with name '%1' already exists.\nOverwrite?" )
00326                                         .arg( symbolName ),
00327                                         QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
00328         switch ( res )
00329         {
00330           case QMessageBox::Cancel:
00331             return;
00332           case QMessageBox::No:
00333             continue;
00334           case QMessageBox::Yes:
00335             dst->addColorRamp( symbolName, ramp );
00336             if ( mDialogMode == Import )
00337               dst->saveColorRamp( symbolName, ramp, groupid, QStringList() );
00338             continue;
00339           case QMessageBox::YesToAll:
00340             prompt = false;
00341             overwrite = true;
00342             break;
00343           case QMessageBox::NoToAll:  prompt = false;
00344             overwrite = false;
00345             break;
00346         }
00347       }
00348 
00349       if ( dst->colorRampNames().contains( symbolName ) && overwrite )
00350       {
00351         dst->addColorRamp( symbolName, ramp );
00352         if ( mDialogMode == Import )
00353           dst->saveColorRamp( symbolName, ramp, groupid, QStringList() );
00354       }
00355       else if ( dst->colorRampNames().contains( symbolName ) && !overwrite )
00356       {
00357         continue;
00358       }
00359       else
00360       {
00361         dst->addColorRamp( symbolName, ramp );
00362         if ( mDialogMode == Import )
00363           dst->saveColorRamp( symbolName, ramp, groupid, QStringList() );
00364       }
00365     }
00366   }
00367 }
00368 
00369 QgsStyleV2ExportImportDialog::~QgsStyleV2ExportImportDialog()
00370 {
00371   delete mTempFile;
00372   delete mTempStyle;
00373 }
00374 
00375 void QgsStyleV2ExportImportDialog::selectAll()
00376 {
00377   listItems->selectAll();
00378 }
00379 
00380 void QgsStyleV2ExportImportDialog::clearSelection()
00381 {
00382   listItems->clearSelection();
00383 }
00384 
00385 void QgsStyleV2ExportImportDialog::importTypeChanged( int index )
00386 {
00387   QString type = importTypeCombo->itemData( index ).toString();
00388 
00389   locationLineEdit->setText( "" );
00390 
00391   if ( type == "file" )
00392   {
00393     locationLineEdit->setEnabled( true );
00394     btnBrowse->setText( "Browse" );
00395   }
00396   else if ( type == "official" )
00397   {
00398     btnBrowse->setText( "Fetch Symbols" );
00399     locationLineEdit->setEnabled( false );
00400   }
00401   else
00402   {
00403     btnBrowse->setText( "Fetch Symbols" );
00404     locationLineEdit->setEnabled( true );
00405   }
00406 }
00407 
00408 void QgsStyleV2ExportImportDialog::browse()
00409 {
00410   QString type = importTypeCombo->itemData( importTypeCombo->currentIndex() ).toString();
00411 
00412   if ( type == "file" )
00413   {
00414     mFileName = QFileDialog::getOpenFileName( this, tr( "Load styles" ), ".",
00415                 tr( "XML files (*.xml *XML)" ) );
00416     if ( mFileName.isEmpty() )
00417     {
00418       return;
00419     }
00420     QFileInfo pathInfo( mFileName );
00421     QString groupName = pathInfo.fileName().replace( ".xml", "" );
00422     groupCombo->setItemText( 0, groupName );
00423     locationLineEdit->setText( mFileName );
00424     populateStyles( mTempStyle );
00425   }
00426   else if ( type == "official" )
00427   {
00428     // TODO set URL
00429     // downloadStyleXML( QUrl( "http://...." ) );
00430   }
00431   else
00432   {
00433     downloadStyleXML( QUrl( locationLineEdit->text() ) );
00434   }
00435 }
00436 
00437 void QgsStyleV2ExportImportDialog::downloadStyleXML( QUrl url )
00438 {
00439   // XXX Try to move this code to some core Network interface,
00440   // HTTP downloading is a generic functionality that might be used elsewhere
00441 
00442   mTempFile = new QTemporaryFile();
00443   if ( mTempFile->open() )
00444   {
00445     mFileName = mTempFile->fileName();
00446 
00447     if ( mProgressDlg )
00448     {
00449       QProgressDialog *dummy = mProgressDlg;
00450       mProgressDlg = NULL;
00451       delete dummy;
00452     }
00453     mProgressDlg = new QProgressDialog();
00454     mProgressDlg->setLabelText( tr( "Downloading style ... " ) );
00455     mProgressDlg->setAutoClose( true );
00456 
00457     connect( mProgressDlg, SIGNAL( canceled() ), this, SLOT( downloadCanceled() ) );
00458 
00459     // open the network connection and connect the respective slots
00460     if ( mNetReply )
00461     {
00462       QNetworkReply *dummyReply = mNetReply;
00463       mNetReply = NULL;
00464       delete dummyReply;
00465     }
00466     mNetReply = mNetManager->get( QNetworkRequest( url ) );
00467 
00468     connect( mNetReply, SIGNAL( finished() ), this, SLOT( httpFinished() ) );
00469     connect( mNetReply, SIGNAL( readyRead() ), this, SLOT( fileReadyRead() ) );
00470     connect( mNetReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( updateProgress( qint64, qint64 ) ) );
00471   }
00472 }
00473 
00474 void QgsStyleV2ExportImportDialog::httpFinished()
00475 {
00476   if ( mNetReply->error() )
00477   {
00478     mTempFile->remove();
00479     mFileName = "";
00480     mProgressDlg->hide();
00481     QMessageBox::information( this, tr( "HTTP Error!" ),
00482                               tr( "Download failed: %1." ).arg( mNetReply->errorString() ) );
00483     return;
00484   }
00485   else
00486   {
00487     mTempFile->flush();
00488     mTempFile->close();
00489     populateStyles( mTempStyle );
00490   }
00491 }
00492 
00493 void QgsStyleV2ExportImportDialog::fileReadyRead()
00494 {
00495   mTempFile->write( mNetReply->readAll() );
00496 }
00497 
00498 void QgsStyleV2ExportImportDialog::updateProgress( qint64 bytesRead, qint64 bytesTotal )
00499 {
00500   mProgressDlg->setMaximum( bytesTotal );
00501   mProgressDlg->setValue( bytesRead );
00502 }
00503 
00504 void QgsStyleV2ExportImportDialog::downloadCanceled()
00505 {
00506   mNetReply->abort();
00507   mTempFile->remove();
00508   mFileName = "";
00509 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines