QGIS API Documentation  master-3f58142
src/gui/symbology-ng/qgssymbolv2selectordialog.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgssymbolv2selectordialog.cpp
00003     ---------------------
00004     begin                : November 2009
00005     copyright            : (C) 2009 by Martin Dobias
00006     email                : wonder dot sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 #include "qgssymbolv2selectordialog.h"
00017 
00018 #include "qgsstylev2.h"
00019 #include "qgssymbolv2.h"
00020 #include "qgssymbollayerv2.h"
00021 #include "qgssymbollayerv2utils.h"
00022 #include "qgssymbollayerv2registry.h"
00023 
00024 // the widgets
00025 #include "qgssymbolslistwidget.h"
00026 #include "qgslayerpropertieswidget.h"
00027 #include "qgssymbollayerv2widget.h"
00028 #include "qgsellipsesymbollayerv2widget.h"
00029 #include "qgsvectorfieldsymbollayerwidget.h"
00030 
00031 #include "qgslogger.h"
00032 #include "qgsapplication.h"
00033 
00034 #include <QColorDialog>
00035 #include <QPainter>
00036 #include <QStandardItemModel>
00037 #include <QInputDialog>
00038 #include <QMessageBox>
00039 #include <QKeyEvent>
00040 #include <QMenu>
00041 
00042 #include <QWidget>
00043 #include <QFile>
00044 #include <QStandardItem>
00045 
00046 static const int SymbolLayerItemType = QStandardItem::UserType + 1;
00047 
00048 // Hybrid item which may represent a symbol or a layer
00049 // Check using item->isLayer()
00050 class SymbolLayerItem : public QStandardItem
00051 {
00052   public:
00053     SymbolLayerItem( QgsSymbolLayerV2* layer )
00054     {
00055       setLayer( layer );
00056     }
00057 
00058     SymbolLayerItem( QgsSymbolV2* symbol )
00059     {
00060       setSymbol( symbol );
00061     }
00062 
00063     void setLayer( QgsSymbolLayerV2* layer )
00064     {
00065       mLayer = layer;
00066       mIsLayer = true;
00067       mSymbol = NULL;
00068       updatePreview();
00069     }
00070 
00071     void setSymbol( QgsSymbolV2* symbol )
00072     {
00073       mSymbol = symbol;
00074       mIsLayer = false;
00075       mLayer = NULL;
00076       updatePreview();
00077     }
00078 
00079     void updatePreview()
00080     {
00081       QIcon icon;
00082       if ( mIsLayer )
00083         icon = QgsSymbolLayerV2Utils::symbolLayerPreviewIcon( mLayer, QgsSymbolV2::MM, QSize( 16, 16 ) ); //todo: make unit a parameter
00084       else
00085         icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( mSymbol, QSize( 16, 16 ) );
00086       setIcon( icon );
00087 
00088       if ( parent() )
00089         static_cast<SymbolLayerItem*>( parent() )->updatePreview();
00090     }
00091 
00092     int type() const { return SymbolLayerItemType; }
00093     bool isLayer() { return mIsLayer; }
00094 
00095     // returns the symbol pointer; helpful in determining a layer's parent symbol
00096     QgsSymbolV2* symbol()
00097     {
00098       if ( mIsLayer )
00099         return NULL;
00100       return mSymbol;
00101     }
00102 
00103     QgsSymbolLayerV2* layer()
00104     {
00105       if ( mIsLayer )
00106         return mLayer;
00107       return NULL;
00108     }
00109 
00110     QVariant data( int role ) const
00111     {
00112       if ( role == Qt::DisplayRole || role == Qt::EditRole )
00113       {
00114         if ( mIsLayer )
00115           return QgsSymbolLayerV2Registry::instance()->symbolLayerMetadata( mLayer->layerType() )->visibleName();
00116         else
00117         {
00118           switch ( mSymbol->type() )
00119           {
00120             case QgsSymbolV2::Marker : return "Marker";
00121             case QgsSymbolV2::Fill   : return "Fill";
00122             case QgsSymbolV2::Line   : return "Line";
00123             default: return "Symbol";
00124           }
00125         }
00126       }
00127       if ( role == Qt::SizeHintRole )
00128         return QVariant( QSize( 32, 32 ) );
00129       if ( role == Qt::CheckStateRole )
00130         return QVariant(); // could be true/false
00131       return QStandardItem::data( role );
00132     }
00133 
00134   protected:
00135     QgsSymbolLayerV2* mLayer;
00136     QgsSymbolV2* mSymbol;
00137     bool mIsLayer;
00138 };
00139 
00141 
00142 QgsSymbolV2SelectorDialog::QgsSymbolV2SelectorDialog( QgsSymbolV2* symbol, QgsStyleV2* style, const QgsVectorLayer* vl, QWidget* parent, bool embedded )
00143     : QDialog( parent ), mAdvancedMenu( NULL ), mVectorLayer( vl )
00144 {
00145 #ifdef Q_WS_MAC
00146   setWindowModality( Qt::WindowModal );
00147 #endif
00148   mStyle = style;
00149   mSymbol = symbol;
00150   mPresentWidget = NULL;
00151 
00152   setupUi( this );
00153   // can be embedded in renderer properties dialog
00154   if ( embedded )
00155   {
00156     buttonBox->hide();
00157     layout()->setContentsMargins( 0, 0, 0, 0 );
00158   }
00159   // setup icons
00160   btnAddLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.png" ) ) );
00161   btnRemoveLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.png" ) ) );
00162   QIcon iconLock;
00163   iconLock.addFile( QgsApplication::iconPath( "locked.png" ), QSize(), QIcon::Normal, QIcon::On );
00164   iconLock.addFile( QgsApplication::iconPath( "unlocked.png" ), QSize(), QIcon::Normal, QIcon::Off );
00165   btnLock->setIcon( iconLock );
00166   btnUp->setIcon( QIcon( QgsApplication::iconPath( "symbologyUp.png" ) ) );
00167   btnDown->setIcon( QIcon( QgsApplication::iconPath( "symbologyDown.png" ) ) );
00168 
00169   model = new QStandardItemModel();
00170   // Set the symbol
00171   layersTree->setModel( model );
00172   layersTree->setHeaderHidden( true );
00173 
00174   QItemSelectionModel* selModel = layersTree->selectionModel();
00175   connect( selModel, SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), this, SLOT( layerChanged() ) );
00176 
00177   loadSymbol( symbol, static_cast<SymbolLayerItem*>( model->invisibleRootItem() ) );
00178   updatePreview();
00179 
00180   connect( btnUp, SIGNAL( clicked() ), this, SLOT( moveLayerUp() ) );
00181   connect( btnDown, SIGNAL( clicked() ), this, SLOT( moveLayerDown() ) );
00182   connect( btnAddLayer, SIGNAL( clicked() ), this, SLOT( addLayer() ) );
00183   connect( btnRemoveLayer, SIGNAL( clicked() ), this, SLOT( removeLayer() ) );
00184   connect( btnLock, SIGNAL( clicked() ), this, SLOT( lockLayer() ) );
00185 
00186   updateUi();
00187 
00188   // set symbol as active item in the tree
00189   QModelIndex newIndex = layersTree->model()->index( 0, 0 );
00190   layersTree->setCurrentIndex( newIndex );
00191 }
00192 
00193 void QgsSymbolV2SelectorDialog::keyPressEvent( QKeyEvent * e )
00194 {
00195   // Ignore the ESC key to avoid close the dialog without the properties window
00196   if ( !isWindow() && e->key() == Qt::Key_Escape )
00197   {
00198     e->ignore();
00199   }
00200   else
00201   {
00202     QDialog::keyPressEvent( e );
00203   }
00204 }
00205 
00206 QMenu* QgsSymbolV2SelectorDialog::advancedMenu()
00207 {
00208   if ( mAdvancedMenu == NULL )
00209   {
00210     mAdvancedMenu = new QMenu;
00211     // Brute force method to activate the Advanced menu
00212     layerChanged();
00213   }
00214   return mAdvancedMenu;
00215 }
00216 
00217 void QgsSymbolV2SelectorDialog::loadSymbol( QgsSymbolV2* symbol, SymbolLayerItem* parent )
00218 {
00219   SymbolLayerItem* symbolItem = new SymbolLayerItem( symbol );
00220   QFont boldFont = symbolItem->font();
00221   boldFont.setBold( true );
00222   symbolItem->setFont( boldFont );
00223   parent->appendRow( symbolItem );
00224 
00225   int count = symbol->symbolLayerCount();
00226   for ( int i = count - 1; i >= 0; i-- )
00227   {
00228     SymbolLayerItem *layerItem = new SymbolLayerItem( symbol->symbolLayer( i ) );
00229     layerItem->setEditable( false );
00230     symbolItem->appendRow( layerItem );
00231     if ( symbol->symbolLayer( i )->subSymbol() )
00232     {
00233       loadSymbol( symbol->symbolLayer( i )->subSymbol(), layerItem );
00234     }
00235   }
00236   layersTree->setExpanded( symbolItem->index(), true );
00237 }
00238 
00239 
00240 void QgsSymbolV2SelectorDialog::loadSymbol()
00241 {
00242   model->clear();
00243   loadSymbol( mSymbol, static_cast<SymbolLayerItem*>( model->invisibleRootItem() ) );
00244 }
00245 
00246 void QgsSymbolV2SelectorDialog::updateUi()
00247 {
00248   QModelIndex currentIdx =  layersTree->currentIndex();
00249   if ( !currentIdx.isValid() )
00250     return;
00251 
00252   SymbolLayerItem *item = static_cast<SymbolLayerItem*>( model->itemFromIndex( currentIdx ) );
00253   if ( !item->isLayer() )
00254   {
00255     btnUp->setEnabled( false );
00256     btnDown->setEnabled( false );
00257     btnRemoveLayer->setEnabled( false );
00258     btnLock->setEnabled( false );
00259     btnAddLayer->setEnabled( true );
00260     return;
00261   }
00262 
00263   int rowCount = item->parent()->rowCount();
00264   int currentRow = item->row();
00265 
00266   btnUp->setEnabled( currentRow > 0 );
00267   btnDown->setEnabled( currentRow < rowCount - 1 );
00268   btnRemoveLayer->setEnabled( rowCount > 1 );
00269   btnLock->setEnabled( true );
00270   btnAddLayer->setEnabled( false );
00271 }
00272 
00273 void QgsSymbolV2SelectorDialog::updatePreview()
00274 {
00275   QImage preview = mSymbol->bigSymbolPreviewImage();
00276   lblPreview->setPixmap( QPixmap::fromImage( preview ) );
00277   // Hope this is a appropriate place
00278   emit symbolModified();
00279 }
00280 
00281 void QgsSymbolV2SelectorDialog::updateLayerPreview()
00282 {
00283   // get current layer item and update its icon
00284   SymbolLayerItem* item = currentLayerItem();
00285   if ( item )
00286     item->updatePreview();
00287   // update also preview of the whole symbol
00288   updatePreview();
00289 }
00290 
00291 SymbolLayerItem* QgsSymbolV2SelectorDialog::currentLayerItem()
00292 {
00293   QModelIndex idx = layersTree->currentIndex();
00294   if ( !idx.isValid() )
00295     return NULL;
00296 
00297   SymbolLayerItem *item = static_cast<SymbolLayerItem*>( model->itemFromIndex( idx ) );
00298   if ( !item->isLayer() )
00299     return NULL;
00300 
00301   return item;
00302 }
00303 
00304 QgsSymbolLayerV2* QgsSymbolV2SelectorDialog::currentLayer()
00305 {
00306   QModelIndex idx = layersTree->currentIndex();
00307   if ( !idx.isValid() )
00308     return NULL;
00309 
00310   SymbolLayerItem *item = static_cast<SymbolLayerItem*>( model->itemFromIndex( idx ) );
00311   if ( item->isLayer() )
00312     return item->layer();
00313 
00314   return NULL;
00315 }
00316 
00317 void QgsSymbolV2SelectorDialog::layerChanged()
00318 {
00319   updateUi();
00320 
00321   SymbolLayerItem *currentItem = static_cast<SymbolLayerItem*>( model->itemFromIndex( layersTree->currentIndex() ) );
00322   if ( currentItem == NULL )
00323     return;
00324 
00325   if ( currentItem->isLayer() )
00326   {
00327     SymbolLayerItem *parent = static_cast<SymbolLayerItem*>( currentItem->parent() );
00328     QWidget *layerProp = new QgsLayerPropertiesWidget( currentItem->layer(), parent->symbol(), mVectorLayer );
00329     setWidget( layerProp );
00330     connect( layerProp, SIGNAL( changed() ), this, SLOT( updateLayerPreview() ) );
00331     // This connection when layer type is changed
00332     connect( layerProp, SIGNAL( changeLayer( QgsSymbolLayerV2* ) ), this, SLOT( changeLayer( QgsSymbolLayerV2* ) ) );
00333   }
00334   else
00335   {
00336     // then it must be a symbol
00337     // Now populate symbols of that type using the symbols list widget:
00338     QWidget *symbolsList = new QgsSymbolsListWidget( currentItem->symbol(), mStyle, mAdvancedMenu, this );
00339     setWidget( symbolsList );
00340     connect( symbolsList, SIGNAL( changed() ), this, SLOT( symbolChanged() ) );
00341   }
00342   updateLockButton();
00343 }
00344 
00345 void QgsSymbolV2SelectorDialog::symbolChanged()
00346 {
00347   SymbolLayerItem *currentItem = static_cast<SymbolLayerItem*>( model->itemFromIndex( layersTree->currentIndex() ) );
00348   if ( currentItem == NULL || currentItem->isLayer() )
00349     return;
00350   // disconnect to avoid recreating widget
00351   disconnect( layersTree->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), this, SLOT( layerChanged() ) );
00352   if ( currentItem->parent() )
00353   {
00354     // it is a sub-symbol
00355     QgsSymbolV2* symbol = currentItem->symbol();
00356     SymbolLayerItem *parent = static_cast<SymbolLayerItem*>( currentItem->parent() );
00357     parent->removeRow( 0 );
00358     loadSymbol( symbol, parent );
00359     layersTree->setCurrentIndex( parent->child( 0 )->index() );
00360     parent->updatePreview();
00361   }
00362   else
00363   {
00364     //it is the symbol itself
00365     loadSymbol();
00366     QModelIndex newIndex = layersTree->model()->index( 0, 0 );
00367     layersTree->setCurrentIndex( newIndex );
00368   }
00369   updatePreview();
00370   // connect it back once things are set
00371   connect( layersTree->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), this, SLOT( layerChanged() ) );
00372 }
00373 
00374 void QgsSymbolV2SelectorDialog::setWidget( QWidget* widget )
00375 {
00376   int index = stackedWidget->addWidget( widget );
00377   stackedWidget->setCurrentIndex( index );
00378   if ( mPresentWidget )
00379   {
00380     stackedWidget->removeWidget( mPresentWidget );
00381     QWidget *dummy = mPresentWidget;
00382     mPresentWidget = widget;
00383     delete dummy; // auto disconnects all signals
00384   }
00385 }
00386 
00387 void QgsSymbolV2SelectorDialog::updateLockButton()
00388 {
00389   QgsSymbolLayerV2* layer = currentLayer();
00390   if ( !layer )
00391     return;
00392   btnLock->setChecked( layer->isLocked() );
00393 }
00394 
00395 void QgsSymbolV2SelectorDialog::addLayer()
00396 {
00397   QModelIndex idx = layersTree->currentIndex();
00398   if ( !idx.isValid() )
00399     return;
00400 
00401   SymbolLayerItem *item = static_cast<SymbolLayerItem*>( model->itemFromIndex( idx ) );
00402   if ( item->isLayer() )
00403   {
00404     QMessageBox::critical( this, tr( "Invalid Selection!" ), tr( "Kindly select a symbol to add layer." ) );
00405     return;
00406   }
00407 
00408   QgsSymbolV2* parentSymbol = item->symbol();
00409   QgsSymbolLayerV2* newLayer = QgsSymbolLayerV2Registry::instance()->defaultSymbolLayer( parentSymbol->type() );
00410   parentSymbol->appendSymbolLayer( newLayer );
00411   // XXX Insane behaviour of the appendSymbolLayer, it actually "pushes" into the list
00412   SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer );
00413   item->insertRow( 0, newLayerItem );
00414   item->updatePreview();
00415 
00416   layersTree->setCurrentIndex( model->indexFromItem( newLayerItem ) );
00417   updateUi();
00418   updatePreview();
00419 }
00420 
00421 void QgsSymbolV2SelectorDialog::removeLayer()
00422 {
00423   SymbolLayerItem *item = currentLayerItem();
00424   int row = item->row();
00425   SymbolLayerItem *parent = static_cast<SymbolLayerItem*>( item->parent() );
00426 
00427   int layerIdx = parent->rowCount() - row - 1; // IMPORTANT
00428   QgsSymbolV2* parentSymbol = parent->symbol();
00429   QgsSymbolLayerV2 *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
00430 
00431   parent->removeRow( row );
00432   parent->updatePreview();
00433 
00434   QModelIndex newIdx = parent->child( 0 )->index();
00435   layersTree->setCurrentIndex( newIdx );
00436 
00437   updateUi();
00438   updatePreview();
00439   //finally delete the removed layer pointer
00440   delete tmpLayer;
00441 }
00442 
00443 void QgsSymbolV2SelectorDialog::moveLayerDown()
00444 {
00445   moveLayerByOffset( + 1 );
00446 }
00447 
00448 void QgsSymbolV2SelectorDialog::moveLayerUp()
00449 {
00450   moveLayerByOffset( -1 );
00451 }
00452 
00453 void QgsSymbolV2SelectorDialog::moveLayerByOffset( int offset )
00454 {
00455   SymbolLayerItem *item = currentLayerItem();
00456   if ( item == NULL )
00457     return;
00458   int row = item->row();
00459 
00460   SymbolLayerItem *parent = static_cast<SymbolLayerItem*>( item->parent() );
00461   QgsSymbolV2* parentSymbol = parent->symbol();
00462 
00463   int layerIdx = parent->rowCount() - row - 1;
00464   // switch layers
00465   QgsSymbolLayerV2* tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
00466   parentSymbol->insertSymbolLayer( layerIdx - offset, tmpLayer );
00467 
00468   QList<QStandardItem*> rowItems = parent->takeRow( row );
00469   parent->insertRows( row + offset, rowItems );
00470   parent->updatePreview();
00471 
00472   QModelIndex newIdx = rowItems[ 0 ]->index();
00473   layersTree->setCurrentIndex( newIdx );
00474 
00475   updatePreview();
00476   updateUi();
00477 }
00478 
00479 void QgsSymbolV2SelectorDialog::lockLayer()
00480 {
00481   QgsSymbolLayerV2* layer = currentLayer();
00482   if ( !layer )
00483     return;
00484   layer->setLocked( btnLock->isChecked() );
00485 }
00486 
00487 void QgsSymbolV2SelectorDialog::changeLayer( QgsSymbolLayerV2* newLayer )
00488 {
00489   SymbolLayerItem *item = currentLayerItem();
00490   QgsSymbolLayerV2* layer = item->layer();
00491 
00492   if ( layer->subSymbol() )
00493   {
00494     item->removeRow( 0 );
00495   }
00496   // update symbol layer item
00497   item->setLayer( newLayer );
00498   // When it is a marker symbol
00499   if ( newLayer->subSymbol() )
00500   {
00501     loadSymbol( newLayer->subSymbol(), item );
00502     layersTree->setExpanded( item->index(), true );
00503   }
00504 
00505   // Change the symbol at last to avoid deleting item's layer
00506   QgsSymbolV2* symbol = static_cast<SymbolLayerItem*>( item->parent() )->symbol();
00507   int layerIdx = item->parent()->rowCount() - item->row() - 1;
00508   symbol->changeSymbolLayer( layerIdx, newLayer );
00509 
00510   item->updatePreview();
00511   updatePreview();
00512   // Important: This lets the layer to have its own layer properties widget
00513   layerChanged();
00514 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines