|
QGIS API Documentation
master-3f58142
|
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 }