void QgsVectorLayerRenderer::drawRendererV2Levels( QgsFeatureIterator& fit ) { QHash< QgsSymbolV2*, QList<QgsFeature> > features; // key = symbol, value = array of features QgsSingleSymbolRendererV2* selRenderer = nullptr; if ( !mSelectedFeatureIds.isEmpty() ) { selRenderer = new QgsSingleSymbolRendererV2( QgsSymbolV2::defaultSymbol( mGeometryType ) ); selRenderer->symbol()->setColor( mContext.selectionColor() ); selRenderer->setVertexMarkerAppearance( mVertexMarkerStyle, mVertexMarkerSize ); selRenderer->startRender( mContext, mFields ); } QgsExpressionContextScope* symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr ); mContext.expressionContext().appendScope( symbolScope ); // 1. fetch features QgsFeature fet; while ( fit.nextFeature( fet ) ) { if ( !fet.constGeometry() ) continue; // skip features without geometry if ( mContext.renderingStopped() ) { qDebug( "rendering stop!" ); stopRendererV2( selRenderer ); mContext.expressionContext().popScope(); return; } mContext.expressionContext().setFeature( fet ); QgsSymbolV2* sym = mRendererV2->symbolForFeature( fet, mContext ); if ( !sym ) { continue; } if ( !features.contains( sym ) ) { features.insert( sym, QList<QgsFeature>() ); } features[sym].append( fet ); if ( mCache ) { // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry. mCache->cacheGeometry( fet.id(), *fet.constGeometry() ); } if ( mContext.labelingEngine() ) { mContext.expressionContext().setFeature( fet ); if ( mLabeling ) { mContext.labelingEngine()->registerFeature( mLayerID, fet, mContext ); } if ( mDiagrams ) { mContext.labelingEngine()->registerDiagramFeature( mLayerID, fet, mContext ); } } // new labeling engine if ( mContext.labelingEngineV2() ) { QScopedPointer<QgsGeometry> obstacleGeometry; QgsSymbolV2List symbols = mRendererV2->originalSymbolsForFeature( fet, mContext ); if ( !symbols.isEmpty() && fet.constGeometry()->type() == QGis::Point ) { obstacleGeometry.reset( QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, mContext, symbols ) ); } if ( !symbols.isEmpty() ) { QgsExpressionContextUtils::updateSymbolScope( symbols.at( 0 ), symbolScope ); } if ( mLabelProvider ) { mLabelProvider->registerFeature( fet, mContext, obstacleGeometry.data() ); } if ( mDiagramProvider ) { mDiagramProvider->registerFeature( fet, mContext, obstacleGeometry.data() ); } } } mContext.expressionContext().popScope(); // find out the order QgsSymbolV2LevelOrder levels; QgsSymbolV2List symbols = mRendererV2->symbols( mContext ); for ( int i = 0; i < symbols.count(); i++ ) { QgsSymbolV2* sym = symbols[i]; for ( int j = 0; j < sym->symbolLayerCount(); j++ ) { int level = sym->symbolLayer( j )->renderingPass(); if ( level < 0 || level >= 1000 ) // ignore invalid levels continue; QgsSymbolV2LevelItem item( sym, j ); while ( level >= levels.count() ) // append new empty levels levels.append( QgsSymbolV2Level() ); levels[level].append( item ); } } // 2. draw features in correct order for ( int l = 0; l < levels.count(); l++ ) { QgsSymbolV2Level& level = levels[l]; for ( int i = 0; i < level.count(); i++ ) { QgsSymbolV2LevelItem& item = level[i]; if ( !features.contains( item.symbol() ) ) { QgsDebugMsg( "level item's symbol not found!" ); continue; } int layer = item.layer(); QList<QgsFeature>& lst = features[item.symbol()]; QList<QgsFeature>::iterator fit; for ( fit = lst.begin(); fit != lst.end(); ++fit ) { if ( mContext.renderingStopped() ) { stopRendererV2( selRenderer ); return; } bool sel = mSelectedFeatureIds.contains( fit->id() ); // maybe vertex markers should be drawn only during the last pass... bool drawMarker = ( mDrawVertexMarkers && mContext.drawEditingInformation() && ( !mVertexMarkerOnlyForSelection || sel ) ); mContext.expressionContext().setFeature( *fit ); try { mRendererV2->renderFeature( *fit, mContext, layer, sel, drawMarker ); } catch ( const QgsCsException &cse ) { Q_UNUSED( cse ); QgsDebugMsg( QString( "Failed to transform a point while drawing a feature with ID '%1'. Ignoring this feature. %2" ) .arg( fet.id() ).arg( cse.what() ) ); } } } } stopRendererV2( selRenderer ); }
QMenu* QgsAppLayerTreeViewMenuProvider::createContextMenu() { QMenu* menu = new QMenu; QgsLayerTreeViewDefaultActions* actions = mView->defaultActions(); QModelIndex idx = mView->currentIndex(); if ( !idx.isValid() ) { // global menu menu->addAction( actions->actionAddGroup( menu ) ); menu->addAction( QgsApplication::getThemeIcon( "/mActionExpandTree.svg" ), tr( "&Expand All" ), mView, SLOT( expandAll() ) ); menu->addAction( QgsApplication::getThemeIcon( "/mActionCollapseTree.svg" ), tr( "&Collapse All" ), mView, SLOT( collapseAll() ) ); // TODO: update drawing order } else if ( QgsLayerTreeNode* node = mView->layerTreeModel()->index2node( idx ) ) { // layer or group selected if ( QgsLayerTree::isGroup( node ) ) { menu->addAction( actions->actionZoomToGroup( mCanvas, menu ) ); menu->addAction( QgsApplication::getThemeIcon( "/mActionRemoveLayer.svg" ), tr( "&Remove" ), QgisApp::instance(), SLOT( removeLayer() ) ); menu->addAction( QgsApplication::getThemeIcon( "/mActionSetCRS.png" ), tr( "&Set Group CRS" ), QgisApp::instance(), SLOT( legendGroupSetCRS() ) ); menu->addAction( actions->actionRenameGroupOrLayer( menu ) ); menu->addAction( tr( "&Set Group WMS data" ), QgisApp::instance(), SLOT( legendGroupSetWMSData() ) ); menu->addAction( actions->actionMutuallyExclusiveGroup( menu ) ); if ( mView->selectedNodes( true ).count() >= 2 ) menu->addAction( actions->actionGroupSelected( menu ) ); if ( QgisApp::instance()->clipboard()->hasFormat( QGSCLIPBOARD_STYLE_MIME ) ) { menu->addAction( tr( "Paste Style" ), QgisApp::instance(), SLOT( applyStyleToGroup() ) ); } menu->addAction( tr( "Save As Layer Definition File..." ), QgisApp::instance(), SLOT( saveAsLayerDefinition() ) ); menu->addAction( actions->actionAddGroup( menu ) ); } else if ( QgsLayerTree::isLayer( node ) ) { QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer(); QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer *>( layer ); QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer ); menu->addAction( actions->actionZoomToLayer( mCanvas, menu ) ); menu->addAction( actions->actionShowInOverview( menu ) ); if ( rlayer ) { menu->addAction( QgsApplication::getThemeIcon( "/mActionZoomActual.svg" ), tr( "&Zoom to Native Resolution (100%)" ), QgisApp::instance(), SLOT( legendLayerZoomNative() ) ); if ( rlayer->rasterType() != QgsRasterLayer::Palette ) menu->addAction( tr( "&Stretch Using Current Extent" ), QgisApp::instance(), SLOT( legendLayerStretchUsingCurrentExtent() ) ); } menu->addAction( QgsApplication::getThemeIcon( "/mActionRemoveLayer.svg" ), tr( "&Remove" ), QgisApp::instance(), SLOT( removeLayer() ) ); // duplicate layer QAction* duplicateLayersAction = menu->addAction( QgsApplication::getThemeIcon( "/mActionDuplicateLayer.svg" ), tr( "&Duplicate" ), QgisApp::instance(), SLOT( duplicateLayers() ) ); if ( layer->isSpatial() ) { // set layer scale visibility menu->addAction( tr( "&Set Layer Scale Visibility" ), QgisApp::instance(), SLOT( setLayerScaleVisibility() ) ); if ( !layer->isInScaleRange( mCanvas->scale() ) ) menu->addAction( tr( "Zoom to &Visible Scale" ), QgisApp::instance(), SLOT( zoomToLayerScale() ) ); // set layer crs menu->addAction( QgsApplication::getThemeIcon( "/mActionSetCRS.png" ), tr( "Set Layer CRS" ), QgisApp::instance(), SLOT( setLayerCRS() ) ); // assign layer crs to project menu->addAction( QgsApplication::getThemeIcon( "/mActionSetProjectCRS.png" ), tr( "Set &Project CRS from Layer" ), QgisApp::instance(), SLOT( setProjectCRSFromLayer() ) ); } // style-related actions if ( layer && mView->selectedLayerNodes().count() == 1 ) { QMenu *menuStyleManager = new QMenu( tr( "Styles" ), menu ); QgisApp *app = QgisApp::instance(); menuStyleManager->addAction( tr( "Copy Style" ), app, SLOT( copyStyle() ) ); if ( app->clipboard()->hasFormat( QGSCLIPBOARD_STYLE_MIME ) ) { menuStyleManager->addAction( tr( "Paste Style" ), app, SLOT( pasteStyle() ) ); } menuStyleManager->addSeparator(); QgsMapLayerStyleGuiUtils::instance()->addStyleManagerActions( menuStyleManager, layer ); if ( vlayer ) { QgsSingleSymbolRendererV2* singleRenderer = dynamic_cast< QgsSingleSymbolRendererV2* >( vlayer->rendererV2() ); if ( singleRenderer && singleRenderer->symbol() ) { //single symbol renderer, so add set color/edit symbol actions menuStyleManager->addSeparator(); QgsColorWheel* colorWheel = new QgsColorWheel( menuStyleManager ); colorWheel->setColor( singleRenderer->symbol()->color() ); QgsColorWidgetAction* colorAction = new QgsColorWidgetAction( colorWheel, menuStyleManager, menuStyleManager ); colorAction->setDismissOnColorSelection( false ); connect( colorAction, SIGNAL( colorChanged( const QColor& ) ), this, SLOT( setVectorSymbolColor( const QColor& ) ) ); //store the layer id in action, so we can later retrieve the corresponding layer colorAction->setProperty( "layerId", vlayer->id() ); menuStyleManager->addAction( colorAction ); //add recent colors action QList<QgsRecentColorScheme *> recentSchemes; QgsColorSchemeRegistry::instance()->schemes( recentSchemes ); if ( !recentSchemes.isEmpty() ) { QgsColorSwatchGridAction* recentColorAction = new QgsColorSwatchGridAction( recentSchemes.at( 0 ), menuStyleManager, "symbology", menuStyleManager ); recentColorAction->setProperty( "layerId", vlayer->id() ); recentColorAction->setDismissOnColorSelection( false ); menuStyleManager->addAction( recentColorAction ); connect( recentColorAction, SIGNAL( colorChanged( const QColor& ) ), this, SLOT( setVectorSymbolColor( const QColor& ) ) ); } menuStyleManager->addSeparator(); QAction* editSymbolAction = new QAction( tr( "Edit Symbol..." ), menuStyleManager ); //store the layer id in action, so we can later retrieve the corresponding layer editSymbolAction->setProperty( "layerId", vlayer->id() ); connect( editSymbolAction, SIGNAL( triggered() ), this, SLOT( editVectorSymbol() ) ); menuStyleManager->addAction( editSymbolAction ); } } menu->addMenu( menuStyleManager ); }