bool QgsMapRendererJob::needTemporaryImage( QgsMapLayer* ml ) { if ( ml->type() == QgsMapLayer::VectorLayer ) { QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml ); if ( vl->renderer() && vl->renderer()->forceRasterRender() ) { //raster rendering is forced for this layer return true; } if ( mSettings.testFlag( QgsMapSettings::UseAdvancedEffects ) && (( vl->blendMode() != QPainter::CompositionMode_SourceOver ) || ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver ) || ( vl->layerTransparency() != 0 ) ) ) { //layer properties require rasterization return true; } } else if ( ml->type() == QgsMapLayer::RasterLayer ) { // preview of intermediate raster rendering results requires a temporary output image if ( mSettings.testFlag( QgsMapSettings::RenderPartialOutput ) ) return true; } return false; }
void QgsSymbolLegendNode::checkAll( bool state ) { QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ); if ( !vlayer || !vlayer->renderer() ) return; QgsLegendSymbolList symbolList = vlayer->renderer()->legendSymbolItems(); Q_FOREACH ( const QgsLegendSymbolItem &item, symbolList ) { vlayer->renderer()->checkLegendSymbolItem( item.ruleKey(), state ); }
void QgsSymbolLegendNode::checkAll( bool state ) { QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ); if ( !vlayer || !vlayer->renderer() ) return; const QgsLegendSymbolList symbolList = vlayer->renderer()->legendSymbolItems(); for ( const auto &item : symbolList ) { vlayer->renderer()->checkLegendSymbolItem( item.ruleKey(), state ); } emit dataChanged(); vlayer->triggerRepaint(); }
static QString _getLayerSvgMarkerPath( const QgsProject &prj, const QString &layerName ) { QList<QgsMapLayer *> layers = prj.mapLayersByName( layerName ); Q_ASSERT( layers.count() == 1 ); Q_ASSERT( layers[0]->type() == QgsMapLayerType::VectorLayer ); QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( layers[0] ); Q_ASSERT( layer->renderer() ); Q_ASSERT( layer->renderer()->type() == "singleSymbol" ); QgsSingleSymbolRenderer *r = static_cast<QgsSingleSymbolRenderer *>( layer->renderer() ); QgsSymbol *s = r->symbol(); Q_ASSERT( s && s->symbolLayerCount() == 1 ); Q_ASSERT( s->symbolLayer( 0 )->layerType() == "SvgMarker" ); QgsSvgMarkerSymbolLayer *sl = static_cast<QgsSvgMarkerSymbolLayer *>( s->symbolLayer( 0 ) ); return sl->path(); }
void QgsSymbolLegendNode::setSymbol( QgsSymbol *symbol ) { if ( !symbol ) return; QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ); if ( !vlayer || !vlayer->renderer() ) return; mItem.setSymbol( symbol ); vlayer->renderer()->setLegendSymbolItem( mItem.ruleKey(), symbol ); mPixmap = QPixmap(); emit dataChanged(); vlayer->triggerRepaint(); }
void QgsSymbolLegendNode::setSymbol( QgsSymbol *symbol ) { if ( !symbol ) return; std::unique_ptr< QgsSymbol > s( symbol ); // this method takes ownership of symbol QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ); if ( !vlayer || !vlayer->renderer() ) return; mItem.setSymbol( s.get() ); // doesn't transfer ownership vlayer->renderer()->setLegendSymbolItem( mItem.ruleKey(), s.release() ); // DOES transfer ownership! mPixmap = QPixmap(); emit dataChanged(); vlayer->triggerRepaint(); }
bool QgsSymbolLegendNode::setData( const QVariant &value, int role ) { if ( role != Qt::CheckStateRole ) return false; if ( !mItem.isCheckable() ) return false; QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ); if ( !vlayer || !vlayer->renderer() ) return false; vlayer->renderer()->checkLegendSymbolItem( mItem.ruleKey(), value == Qt::Checked ); emit dataChanged(); vlayer->emitStyleChanged(); vlayer->triggerRepaint(); return true; }
void QgsLayerStylingWidget::apply() { if ( !mCurrentLayer ) return; disconnect( mCurrentLayer, SIGNAL( styleChanged() ), this, SLOT( updateCurrentWidgetLayer() ) ); QString undoName = "Style Change"; QWidget* current = mWidgetStack->mainPanel(); bool styleWasChanged = false; if ( QgsLabelingWidget* widget = qobject_cast<QgsLabelingWidget*>( current ) ) { widget->apply(); styleWasChanged = true; undoName = "Label Change"; } if ( QgsPanelWidgetWrapper* wrapper = qobject_cast<QgsPanelWidgetWrapper*>( current ) ) { if ( QgsRendererPropertiesDialog* widget = qobject_cast<QgsRendererPropertiesDialog*>( wrapper->widget() ) ) { widget->apply(); QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( mCurrentLayer ); QgsRendererAbstractMetadata* m = QgsRendererRegistry::instance()->rendererMetadata( layer->renderer()->type() ); undoName = QString( "Style Change - %1" ).arg( m->visibleName() ); styleWasChanged = true; } } else if ( QgsRasterTransparencyWidget* widget = qobject_cast<QgsRasterTransparencyWidget*>( current ) ) { widget->apply(); styleWasChanged = true; } else if ( qobject_cast<QgsRasterHistogramWidget*>( current ) ) { mRasterStyleWidget->apply(); styleWasChanged = true; } else if ( QgsMapLayerConfigWidget* widget = qobject_cast<QgsMapLayerConfigWidget*>( current ) ) { widget->apply(); styleWasChanged = true; } pushUndoItem( undoName ); if ( styleWasChanged ) { emit styleChanged( mCurrentLayer ); QgsProject::instance()->setDirty( true ); mCurrentLayer->triggerRepaint(); } connect( mCurrentLayer, SIGNAL( styleChanged() ), this, SLOT( updateCurrentWidgetLayer() ) ); }
void QgsQuickPrint::scalePointSymbols( int theScaleFactor, SymbolScalingType theDirection ) { if ( 0 >= theScaleFactor ) { QgsDebugMsg( "invalid scale factor" ); return; } QStringList myLayerSet = mpMapRenderer->layerSet(); QStringListIterator myLayerIterator( myLayerSet ); while ( myLayerIterator.hasNext() ) { QString myLayerId = myLayerIterator.next(); QgsDebugMsg( "Scaling point symbols for print for " + myLayerId ); QgsMapLayer * mypLayer = QgsMapLayerRegistry::instance()->mapLayer( myLayerId ); if ( mypLayer ) { QgsVectorLayer *mypVectorLayer = qobject_cast<QgsVectorLayer *>( mypLayer ); if ( mypVectorLayer ) { const QgsRenderer* mypRenderer = mypVectorLayer->renderer(); const QList<QgsSymbol*> mySymbolList = mypRenderer->symbols(); // // Single symbol // if ( 1 == mySymbolList.size() ) { QgsSymbol * mypSymbol = mySymbolList.at( 0 ); if ( mypSymbol->type() == QGis::Point ) { if ( theDirection == ScaleUp ) { mypSymbol->setPointSize( mypSymbol->pointSize() * theScaleFactor ); } else //Scale Down { mypSymbol->setPointSize( mypSymbol->pointSize() / theScaleFactor ); } } } else //class breaks { QListIterator<QgsSymbol *> myIterator( mySymbolList ); while ( myIterator.hasNext() ) { QgsSymbol * mypSymbol = myIterator.next(); if ( mypSymbol->type() == QGis::Point ) { if ( theDirection == ScaleUp ) { mypSymbol->setPointSize( mypSymbol->pointSize() * theScaleFactor ); } else //Scale Down { mypSymbol->setPointSize( mypSymbol->pointSize() / theScaleFactor ); } } } //symbol loop } //class breaks } //if vectorlayer } //if maplayer } //layer iterator }
void QgsQuickPrint::printMap() { if ( mOutputFileName.isEmpty() ) { return; } if ( mpMapRenderer == NULL ) { return; } //ensure the user never omitted the extension from the file name if ( !mOutputFileName.toUpper().endsWith( ".PDF" ) ) { mOutputFileName += ".pdf"; } // Initialising the printer this way lets us find out what // the screen resolution is which we store and then // reset the resolution of the printer after that... QPrinter myPrinter( QPrinter::ScreenResolution ); // Try to force the printer resolution to 300dpi // to get past platform specific defaults in printer // resolution... // int myPrintResolutionDpi = 300; myPrinter.setResolution( myPrintResolutionDpi ); myPrinter.setOutputFormat( QPrinter::PdfFormat ); QgsDebugMsg( QString( "Printing to page size %1" ).arg( pageSizeToString( mPageSize ) ) ); myPrinter.setPageSize( mPageSize ); myPrinter.setOutputFileName( mOutputFileName ); myPrinter.setOrientation( QPrinter::Landscape ); myPrinter.setDocName( "quickprint Report" ); QPainter myPrintPainter( &myPrinter ); myPrintPainter.setPen( Qt::gray ); myPrintPainter.setBrush( Qt::white ); // This is what we are aiming for: // a // +-(1)------ Acme Maps (2) --------------------------------------+ // |b 12/01/2007 (3) | // | Earthquakes (4) | // | +--(5)--------------------------------------------------------+ | // | |c | | // | | +-(6)---------------------------------------+ +~(7)~~~~~~+ | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | +-------------------------------------------+ +~~~~~~~~~~+ | | // | | | | // | +-------------------------------------------------------------+ | // | | // | +-(8)-----+ +-(9-)----+ +-(10)----+ /|\ | // | | | |Copyright| | | / | \ | // | | | | 2008 | | | |(11) | // | +---------+ +---------+ +---------+ | // | +~(12)~~~~~~+ | // +-----------------------------------------------------------------+ // // 1) PageBorder 8) Logo1 // 2) PageTitle 9) CopyrightText // 3) MapDate 10) Logo2 // 4) MapTitle 11) NorthArrow // 5) MapFrame 12) ScaleBar // 6) MapPixmap // 7) LegendPixmap // a OriginXY // b HorizontalSpacing // c VerticalSpacing // // Note: Different operating systems will use different // page resolutions for QPrinter::HighResolution so I'm // working all coordinates out as percentages of page // size so that we can hopefully get comarable print // results on all platforms. // // // Note #2: Im defining all measurements here as my plan // is to later support templates with different page // layouts and paper sizes etc. // //set the top left origin for the print layout int myOriginX = myPrinter.pageRect().left(); int myOriginY = myPrinter.pageRect().top(); int myDrawableWidth = myPrinter.pageRect().width() - myOriginX; int myDrawableHeight = myPrinter.pageRect().height() - myOriginY; //define the spacing between layout elements int myHorizontalSpacing = myDrawableWidth / 100; // 1% int myVerticalSpacing = myDrawableHeight / 100; // 1% //define the proportions for the page layout int myMapWidthPercent = 65; int myMapHeightPercent = 71; int myLegendWidthPercent = 25; int myLegendHeightPercent = 65; int myLogoWidthPercent = 23; int myLogoHeightPercent = 17; // // Remember the size and dpi of the maprender // so we can restore it properly // int myOriginalDpi = mpMapRenderer->outputDpi(); //sensible default to prevent divide by zero if ( 0 == myOriginalDpi ) myOriginalDpi = 96; QSize myOriginalSize = mpMapRenderer->outputSize(); //define the font sizes and family int myMapTitleFontSize = 24; int myMapDateFontSize = 16; int myMapNameFontSize = 32; int myLegendFontSize = 12; #ifdef Q_OS_LINUX//this sucks... myLegendFontSize -= 2; #endif #ifdef WIN32 //this sucks too... myMapTitleFontSize /= 2; myMapDateFontSize /= 2; myMapNameFontSize /= 2; myLegendFontSize /= 2; #endif QString myFontFamily = "Arial"; // // Draw the PageBorder // myPrintPainter.drawRect( myOriginX, myOriginY, myDrawableWidth, myDrawableHeight ); // // Draw the PageTitle // QFont myTitleFont( myFontFamily, myMapTitleFontSize ); myPrintPainter.setFont( myTitleFont ); QFontMetrics myTitleMetrics( myTitleFont, &myPrinter ); int myPageTitleHeight = myTitleMetrics.height(); int myPageTitleWidth = myTitleMetrics.width( mTitleText ); myOriginX += myHorizontalSpacing; myOriginY -= ( myPageTitleHeight / 2 ); QRect myPageTitleRect( myOriginX, myOriginY, myPageTitleWidth, myPageTitleHeight ); // make sure the title goes onto a white background myPrintPainter.setPen( Qt::white ); myPrintPainter.drawRect( myPageTitleRect ); myPrintPainter.setPen( Qt::black ); myPrintPainter.drawText( myPageTitleRect, Qt::AlignCenter, mTitleText ); // // Draw the MapDate // QFont myDateFont( myFontFamily, myMapDateFontSize ); QString myDateText( QDate::currentDate().toString( Qt::LocalDate ) ); myPrintPainter.setFont( myDateFont ); QFontMetrics myDateMetrics( myDateFont, &myPrinter ); int myDateHeight = myDateMetrics.height(); //int myDateWidth = myDateMetrics.width(myDateText); myOriginX += myHorizontalSpacing; myOriginY += myPageTitleHeight + myVerticalSpacing ; QRect myDateRect( myOriginX, myOriginY, myPageTitleWidth, //use same width as page title for centering myDateHeight ); // make sure the title goes onto a white background myPrintPainter.setPen( Qt::white ); myPrintPainter.drawRect( myDateRect ); myPrintPainter.setPen( Qt::black ); myPrintPainter.drawText( myDateRect, Qt::AlignCenter, myDateText ); // // Draw the MapName // QFont myNameFont( myFontFamily, myMapNameFontSize ); myPrintPainter.setFont( myNameFont ); QFontMetrics myNameMetrics( myNameFont, &myPrinter ); int myNameHeight = myNameMetrics.height(); int myNameWidth = myNameMetrics.width( mNameText ); myOriginX = myPrinter.pageRect().left() + myDrawableWidth / 2; //page center myOriginX -= myNameWidth / 2; myOriginY = myPrinter.pageRect().top() + ( myPageTitleHeight / 2 ) + myVerticalSpacing ; QRect myNameRect( myOriginX, myOriginY, myNameWidth, myNameHeight ); // make sure the title goes onto a white background myPrintPainter.setPen( Qt::white ); myPrintPainter.drawRect( myNameRect ); myPrintPainter.setPen( Qt::black ); myPrintPainter.drawText( myNameRect, Qt::AlignCenter, mNameText ); // // Draw the MapFrame (top) // int myMapFrameWidth = myDrawableWidth ; myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing; myOriginY += myNameHeight + myVerticalSpacing; QLine myMapFrameTopLine( myOriginX, myOriginY, myMapFrameWidth, myOriginY ); myPrintPainter.setPen( Qt::black ); myPrintPainter.drawLine( myMapFrameTopLine ); // Draw the map onto a pixmap // @TODO: we need to save teh extent of the screen map and // then set them again for the print map so that the map scales // properly in the print int myMapDimensionX = ( myDrawableWidth / 100 ) * myMapHeightPercent; int myMapDimensionY = ( myDrawableHeight / 100 ) * myMapWidthPercent; QImage myMapImage( QSize( myMapDimensionX, myMapDimensionY ), QImage::Format_ARGB32 ); myMapImage.setDotsPerMeterX(( double )( myPrinter.logicalDpiX() ) / 25.4 * 1000.0 ); myMapImage.setDotsPerMeterY(( double )( myPrinter.logicalDpiY() ) / 25.4 * 1000.0 ); myMapImage.fill( 0 ); QPainter myMapPainter; myMapPainter.begin( &myMapImage ); // Now resize for print mpMapRenderer->setOutputSize( QSize( myMapDimensionX, myMapDimensionY ), ( myPrinter.logicalDpiX() + myPrinter.logicalDpiY() ) / 2 ); mpMapRenderer->render( &myMapPainter ); myMapPainter.end(); //draw the map pixmap onto our pdf print device myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing; myOriginY += myVerticalSpacing * 2; myPrintPainter.drawImage( myOriginX, myOriginY, myMapImage ); // // Draw the legend // QFont myLegendFont( myFontFamily, myLegendFontSize ); //myPrintPainter.setFont(myLegendFont); int myLegendDimensionX = ( myDrawableWidth / 100 ) * myLegendWidthPercent; int myLegendDimensionY = ( myDrawableHeight / 100 ) * myLegendHeightPercent; // Create a viewport to make coordinate conversions easier // The viewport has the same dimensions as the page(otherwise items // drawn into it will appear squashed), but a different origin. QRect myOriginalViewport = myPrintPainter.viewport(); //for restoring later myOriginX += myMapDimensionX + myHorizontalSpacing; myPrintPainter.setViewport( myOriginX, myOriginY, myOriginalViewport.width(), myOriginalViewport.height() ); //draw a rectangale around the legend frame //@TODO make this user settable if ( 0 == 1 ) //put some real logic here { myPrintPainter.drawRect( 0, 0, myLegendDimensionX, myLegendDimensionY ); } //get font metric and other vars needed QFontMetrics myLegendFontMetrics( myLegendFont, &myPrinter ); int myLegendFontHeight = myLegendFontMetrics.height(); int myLegendXPos = 0; int myLegendYPos = 0; int myLegendSpacer = myLegendFontHeight / 2; //for vertical and horizontal spacing int myLegendVerticalSpacer = myLegendFontHeight / 3; //for vertical between rows int myIconWidth = myLegendFontHeight; myPrintPainter.setFont( myLegendFont ); QStringList myLayerSet = mpMapRenderer->layerSet(); QStringListIterator myLayerIterator( myLayerSet ); //second clause below is to prevent legend spilling out the bottom while ( myLayerIterator.hasNext() && myLegendYPos < myLegendDimensionY ) { QString myLayerId = myLayerIterator.next(); QgsMapLayer * mypLayer = QgsMapLayerRegistry::instance()->mapLayer( myLayerId ); if ( mypLayer ) { QgsVectorLayer *mypVectorLayer = qobject_cast<QgsVectorLayer *>( mypLayer ); // TODO: add support for symbology-ng renderers if ( mypVectorLayer && mypVectorLayer->renderer() ) { QString myLayerName = mypVectorLayer->name(); QIcon myIcon; QPixmap myPixmap( QSize( myIconWidth, myIconWidth ) ); //square //based on code from qgslegendlayer.cpp - see that file for more info const QgsRenderer* mypRenderer = mypVectorLayer->renderer(); const QList<QgsSymbol*> mySymbolList = mypRenderer->symbols(); // // Single symbol // double widthScale = ( myPrinter.logicalDpiX() + myPrinter.logicalDpiY() ) / 2.0 / 25.4; if ( 1 == mySymbolList.size() ) { QgsSymbol * mypSymbol = mySymbolList.at( 0 ); myPrintPainter.setPen( mypSymbol->pen() ); myPrintPainter.setBrush( mypSymbol->brush() ); myLegendXPos = 0 ; if ( mypSymbol->type() == QGis::Point ) { QImage myImage; myImage = mypSymbol->getPointSymbolAsImage( widthScale ); myPrintPainter.drawImage( myLegendXPos, myLegendYPos, myImage ); } else if ( mypSymbol->type() == QGis::Line ) { myPrintPainter.drawLine( myLegendXPos, myLegendYPos, myLegendXPos + myIconWidth, myLegendYPos + myIconWidth ); } else //polygon { myPrintPainter.drawRect( myLegendXPos, myLegendYPos, myIconWidth, myIconWidth ); } myLegendXPos += myIconWidth + myLegendSpacer; myPrintPainter.setPen( Qt::black ); QStringList myWrappedLayerNameList = wordWrap( myLayerName, myLegendFontMetrics, myLegendDimensionX - myIconWidth ); // // Loop through wrapped legend label lines // QStringListIterator myLineWrapIterator( myWrappedLayerNameList ); while ( myLineWrapIterator.hasNext() ) { QString myLine = myLineWrapIterator.next(); QRect myLegendItemRect( myLegendXPos, myLegendYPos, myLegendDimensionX - myIconWidth, myLegendFontHeight ); myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine ); myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight; } } else //class breaks { // draw in the layer name first, after we loop for the class breaks QStringList myWrappedLayerNameList = wordWrap( myLayerName, myLegendFontMetrics, myLegendDimensionX - myIconWidth ); // Check the wrapped layer name wont overrun the space we have // for the legend ... int myLabelHeight = myLegendFontHeight * myWrappedLayerNameList.count(); if ( myLegendYPos + myLabelHeight > myLegendDimensionY ) { continue; } // // Loop through wrapped legend label lines // QStringListIterator myLineWrapIterator( myWrappedLayerNameList ); while ( myLineWrapIterator.hasNext() ) { QString myLine = myLineWrapIterator.next(); myLegendXPos = myIconWidth; QRect myLegendItemRect( myLegendXPos, myLegendYPos, myLegendFontMetrics.width( myLine ), myLegendFontHeight ); myPrintPainter.setPen( Qt::black ); myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine ); myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight; } // // Loop through the class breaks // QListIterator<QgsSymbol *> myIterator( mySymbolList ); while ( myIterator.hasNext() && myLegendYPos < myLegendDimensionY ) { QgsSymbol * mypSymbol = myIterator.next(); myPrintPainter.setPen( mypSymbol->pen() ); myPrintPainter.setBrush( mypSymbol->brush() ); myLegendXPos = myLegendSpacer * 3; //extra indent for class breaks if ( mypSymbol->type() == QGis::Point ) { QImage myImage; myImage = mypSymbol->getPointSymbolAsImage( widthScale ); myPrintPainter.drawImage( myLegendXPos, myLegendYPos, myImage ); } else if ( mypSymbol->type() == QGis::Line ) { myPrintPainter.drawLine( myLegendXPos, myLegendYPos, myLegendXPos + myIconWidth, myLegendYPos + myIconWidth ); } else //polygon { myPrintPainter.drawRect( myLegendXPos, myLegendYPos, myIconWidth, myIconWidth ); } // // Now work out the class break label // QString myLabel; QString myLower = mypSymbol->lowerValue(); if ( !myLower.isEmpty() ) { myLabel = myLower; } QString myUpper = mypSymbol->upperValue(); if ( !myUpper.isEmpty() ) { myLabel += " - "; myLabel += myUpper; } QString myText = mypSymbol->label(); if ( !myText.isEmpty() ) { myLabel += " "; myLabel += myText; } myLabel = myLabel.trimmed(); myLegendXPos += myIconWidth + myLegendSpacer; myPrintPainter.setPen( Qt::black ); QStringList myWrappedLayerNameList = wordWrap( myLabel, myLegendFontMetrics, myLegendDimensionX - myLegendXPos ); // // Loop through wrapped legend label lines // QStringListIterator myLineWrapIterator( myWrappedLayerNameList ); while ( myLineWrapIterator.hasNext() ) { QString myLine = myLineWrapIterator.next(); // check if the text will overflow the space we have QRect myLegendItemRect( myLegendXPos, myLegendYPos, myLegendDimensionX - myIconWidth, myLegendFontHeight ); myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine ); myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight; } //wordwrap loop } //symbol loop } //class breaks } //if vectorlayer } //if maplayer } //layer iterator //reinstate the viewport myPrintPainter.setViewport( myOriginalViewport ); // // Draw the MapFrame (bottom) // myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing; myOriginY += myMapDimensionY + ( myVerticalSpacing * 2 ); QLine myMapFrameBottomLine( myOriginX, myOriginY, myMapFrameWidth, myOriginY ); myPrintPainter.setPen( Qt::black ); myPrintPainter.drawLine( myMapFrameBottomLine ); // // Draw logo 1 // int myLogoXDim = ( myDrawableWidth / 100 ) * myLogoWidthPercent; int myLogoYDim = ( myDrawableHeight / 100 ) * myLogoHeightPercent; QPixmap myLogo1; QgsDebugMsg( QString( "Logo1: %1" ).arg( mLogo1File ) ); myLogo1.fill( Qt::white ); myLogo1.load( mLogo1File ); myLogo1 = myLogo1.scaled( myLogoXDim, myLogoYDim, Qt::KeepAspectRatio ); myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing; myOriginY += myVerticalSpacing ; myPrintPainter.drawPixmap( myOriginX, myOriginY, myLogo1 ); // // Draw Copyright Text // myOriginX += myHorizontalSpacing + myLogoXDim; QRect myCopyrightRect( myOriginX, myOriginY, myLogoXDim, myLogoYDim ); myPrintPainter.setPen( Qt::black ); QFont myCopyrightFont( myFontFamily, myMapDateFontSize ); myPrintPainter.setFont( myCopyrightFont ); //myPrintPainter.drawRect( myCopyrightRect ); myPrintPainter.drawText( myCopyrightRect, Qt::AlignCenter | Qt::TextWordWrap, mCopyrightText ); // // Draw logo 2 // QPixmap myLogo2; myLogo2.fill( Qt::white ); myLogo2.load( mLogo2File ); myLogo2 = myLogo2.scaled( myLogoXDim, myLogoYDim, Qt::KeepAspectRatio ); myOriginX += myHorizontalSpacing + myLogoXDim; myPrintPainter.drawPixmap( myOriginX, myOriginY, myLogo2 ); // // Draw the north arrow // myOriginX += myHorizontalSpacing + myLogoXDim; // use half the available space for the n.arrow // and the rest for the scale bar (see below) QPixmap myNorthArrow( myLogoYDim / 2, myLogoYDim / 2 ); myNorthArrow.fill( Qt::white ); QPainter myNorthPainter( &myNorthArrow ); QSvgRenderer mySvgRenderer( mNorthArrowFile ); mySvgRenderer.render( &myNorthPainter ); myPrintPainter.drawPixmap( myOriginX + (( myLogoXDim / 2 ) ), myOriginY, myNorthArrow ); // // Draw the scale bar // myOriginY += myLogoYDim / 2 + myVerticalSpacing; myPrintPainter.setViewport( myOriginX, myOriginY, myOriginalViewport.width(), myOriginalViewport.height() ); renderPrintScaleBar( &myPrintPainter, mpMapRenderer, myLogoXDim ); myPrintPainter.setViewport( myOriginalViewport ); // // Finish up // myPrintPainter.end(); #if 0 mProgressDialog.setValue( 0 ); mProgressDialog.setLabelText( tr( "Please wait while your report is generated", "COMMENTED OUT" ) ); mProgressDialog.show(); mProgressDialog.setWindowModality( Qt::WindowModal ); mProgressDialog.setAutoClose( true ); #endif // // Restore the map render to its former glory // mpMapRenderer->setOutputSize( myOriginalSize, myOriginalDpi ); }
QVariant QgsSymbolLegendNode::data( int role ) const { if ( role == Qt::DisplayRole ) { return mLabel; } else if ( role == Qt::EditRole ) { return mUserLabel.isEmpty() ? mItem.label() : mUserLabel; } else if ( role == Qt::DecorationRole ) { if ( mPixmap.isNull() || mPixmap.size() != mIconSize ) { QPixmap pix; if ( mItem.symbol() ) { std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() ); pix = QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), mIconSize, 0, context.get() ); if ( !mTextOnSymbolLabel.isEmpty() && context ) { QPainter painter( &pix ); painter.setRenderHint( QPainter::Antialiasing ); context->setPainter( &painter ); QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( *context ) ); qreal yBaselineVCenter = ( mIconSize.height() + fm.ascent() - fm.descent() ) / 2; QgsTextRenderer::drawText( QPointF( mIconSize.width() / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter, QStringList() << mTextOnSymbolLabel, *context, mTextOnSymbolTextFormat ); } } else { pix = QPixmap( mIconSize ); pix.fill( Qt::transparent ); } if ( mItem.level() == 0 || ( model() && model()->testFlag( QgsLayerTreeModel::ShowLegendAsTree ) ) ) mPixmap = pix; else { // ident the symbol icon to make it look like a tree structure QPixmap pix2( pix.width() + mItem.level() * INDENT_SIZE, pix.height() ); pix2.fill( Qt::transparent ); QPainter p( &pix2 ); p.drawPixmap( mItem.level() * INDENT_SIZE, 0, pix ); p.end(); mPixmap = pix2; } } return mPixmap; } else if ( role == Qt::CheckStateRole ) { if ( !mItem.isCheckable() ) return QVariant(); QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ); if ( !vlayer || !vlayer->renderer() ) return QVariant(); return vlayer->renderer()->legendSymbolItemChecked( mItem.ruleKey() ) ? Qt::Checked : Qt::Unchecked; } else if ( role == RuleKeyRole ) { return mItem.ruleKey(); } else if ( role == ParentRuleKeyRole ) { return mItem.parentRuleKey(); } return QVariant(); }
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( QStringLiteral( "/mActionExpandTree.svg" ) ), tr( "&Expand All" ), mView, SLOT( expandAll() ) ); menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionCollapseTree.svg" ) ), tr( "&Collapse All" ), mView, SLOT( collapseAll() ) ); menu->addSeparator(); if ( QgisApp::instance()->clipboard()->hasFormat( QGSCLIPBOARD_MAPLAYER_MIME ) ) { QAction *actionPasteLayerOrGroup = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionEditPaste.svg" ) ), tr( "Paste Layer/Group" ), menu ); connect( actionPasteLayerOrGroup, &QAction::triggered, QgisApp::instance(), &QgisApp::pasteLayer ); menu->addAction( actionPasteLayerOrGroup ); } // 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( tr( "Copy Group" ), QgisApp::instance(), SLOT( copyLayer() ) ); if ( QgisApp::instance()->clipboard()->hasFormat( QGSCLIPBOARD_MAPLAYER_MIME ) ) { QAction *actionPasteLayerOrGroup = new QAction( tr( "Paste Layer/Group" ), menu ); connect( actionPasteLayerOrGroup, &QAction::triggered, QgisApp::instance(), &QgisApp::pasteLayer ); menu->addAction( actionPasteLayerOrGroup ); } menu->addAction( actions->actionRenameGroupOrLayer( menu ) ); menu->addSeparator(); menu->addAction( actions->actionAddGroup( menu ) ); QAction *removeAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRemoveLayer.svg" ) ), tr( "&Remove Group…" ), QgisApp::instance(), SLOT( removeLayer() ) ); removeAction->setEnabled( removeActionEnabled() ); menu->addSeparator(); menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSetCRS.png" ) ), tr( "&Set Group CRS…" ), QgisApp::instance(), SLOT( legendGroupSetCrs() ) ); menu->addAction( tr( "&Set Group WMS Data…" ), QgisApp::instance(), SLOT( legendGroupSetWmsData() ) ); menu->addSeparator(); menu->addAction( actions->actionMutuallyExclusiveGroup( menu ) ); menu->addAction( actions->actionCheckAndAllChildren( menu ) ); menu->addAction( actions->actionUncheckAndAllChildren( menu ) ); if ( !( mView->selectedNodes( true ).count() == 1 && idx.row() == 0 ) ) { menu->addAction( actions->actionMoveToTop( menu ) ); } menu->addSeparator(); 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->addSeparator(); QMenu *menuExportGroup = new QMenu( tr( "Export" ), menu ); QAction *actionSaveAsDefinitionGroup = new QAction( tr( "Save as Layer Definition File…" ), menuExportGroup ); connect( actionSaveAsDefinitionGroup, &QAction::triggered, QgisApp::instance(), &QgisApp::saveAsLayerDefinition ); menuExportGroup->addAction( actionSaveAsDefinitionGroup ); menu->addMenu( menuExportGroup ); } else if ( QgsLayerTree::isLayer( node ) ) { QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer(); QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer *>( layer ); QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer ); if ( layer && layer->isSpatial() ) { menu->addAction( actions->actionZoomToLayer( mCanvas, menu ) ); if ( vlayer ) { QAction *actionZoomSelected = actions->actionZoomToSelection( mCanvas, menu ); actionZoomSelected->setEnabled( !vlayer->selectedFeatures().isEmpty() ); menu->addAction( actionZoomSelected ); } menu->addAction( actions->actionShowInOverview( menu ) ); } if ( vlayer ) menu->addAction( actions->actionShowFeatureCount( menu ) ); QAction *actionCopyLayer = new QAction( tr( "Copy Layer" ), menu ); connect( actionCopyLayer, &QAction::triggered, QgisApp::instance(), &QgisApp::copyLayer ); menu->addAction( actionCopyLayer ); menu->addAction( actions->actionRenameGroupOrLayer( menu ) ); if ( rlayer ) { menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/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() ) ); } addCustomLayerActions( menu, layer ); if ( layer && layer->type() == QgsMapLayer::VectorLayer && static_cast<QgsVectorLayer *>( layer )->providerType() == QLatin1String( "virtual" ) ) { menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddVirtualLayer.svg" ) ), tr( "Edit Virtual Layer…" ), QgisApp::instance(), SLOT( addVirtualLayer() ) ); } menu->addSeparator(); // duplicate layer QAction *duplicateLayersAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDuplicateLayer.svg" ) ), tr( "&Duplicate Layer" ), QgisApp::instance(), SLOT( duplicateLayers() ) ); QAction *removeAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRemoveLayer.svg" ) ), tr( "&Remove Layer…" ), QgisApp::instance(), SLOT( removeLayer() ) ); removeAction->setEnabled( removeActionEnabled() ); menu->addSeparator(); if ( node->parent() != mView->layerTreeModel()->rootGroup() ) menu->addAction( actions->actionMoveOutOfGroup( menu ) ); if ( !( mView->selectedNodes( true ).count() == 1 && idx.row() == 0 ) ) { menu->addAction( actions->actionMoveToTop( menu ) ); } QAction *checkAll = actions->actionCheckAndAllParents( menu ); if ( checkAll ) menu->addAction( checkAll ); if ( mView->selectedNodes( true ).count() >= 2 ) menu->addAction( actions->actionGroupSelected( menu ) ); menu->addSeparator(); if ( vlayer ) { QAction *toggleEditingAction = QgisApp::instance()->actionToggleEditing(); QAction *saveLayerEditsAction = QgisApp::instance()->actionSaveActiveLayerEdits(); QAction *allEditsAction = QgisApp::instance()->actionAllEdits(); // attribute table menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ), tr( "&Open Attribute Table" ), QgisApp::instance(), SLOT( attributeTable() ) ); // allow editing int cap = vlayer->dataProvider()->capabilities(); if ( cap & QgsVectorDataProvider::EditingCapabilities ) { if ( toggleEditingAction ) { menu->addAction( toggleEditingAction ); toggleEditingAction->setChecked( vlayer->isEditable() ); toggleEditingAction->setEnabled( true ); } if ( saveLayerEditsAction && vlayer->isModified() ) { menu->addAction( saveLayerEditsAction ); } } if ( allEditsAction->isEnabled() ) menu->addAction( allEditsAction ); // disable duplication of memory layers if ( vlayer->storageType() == QLatin1String( "Memory storage" ) && mView->selectedLayerNodes().count() == 1 ) duplicateLayersAction->setEnabled( false ); if ( vlayer->dataProvider()->supportsSubsetString() ) { QAction *action = menu->addAction( tr( "&Filter…" ), QgisApp::instance(), SLOT( layerSubsetString() ) ); action->setEnabled( !vlayer->isEditable() ); } } menu->addSeparator(); if ( layer && 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() ) ); QMenu *menuSetCRS = new QMenu( tr( "Set CRS" ), menu ); // set layer crs QAction *actionSetLayerCrs = new QAction( tr( "Set Layer CRS…" ), menuSetCRS ); connect( actionSetLayerCrs, &QAction::triggered, QgisApp::instance(), &QgisApp::setLayerCrs ); menuSetCRS->addAction( actionSetLayerCrs ); // assign layer crs to project QAction *actionSetProjectCrs = new QAction( tr( "Set &Project CRS from Layer" ), menuSetCRS ); connect( actionSetProjectCrs, &QAction::triggered, QgisApp::instance(), &QgisApp::setProjectCrsFromLayer ); menuSetCRS->addAction( actionSetProjectCrs ); menu->addMenu( menuSetCRS ); } menu->addSeparator(); if ( vlayer ) { // save as vector file QMenu *menuExportVector = new QMenu( tr( "Export" ), menu ); QAction *actionSaveAs = new QAction( tr( "Save Features As…" ), menuExportVector ); connect( actionSaveAs, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveAsFile(); } ); menuExportVector->addAction( actionSaveAs ); QAction *actionSaveSelectedFeaturesAs = new QAction( tr( "Save Selected Features As…" ), menuExportVector ); connect( actionSaveSelectedFeaturesAs, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveAsFile( nullptr, true ); } ); actionSaveSelectedFeaturesAs->setEnabled( vlayer->selectedFeatureCount() > 0 ); menuExportVector->addAction( actionSaveSelectedFeaturesAs ); QAction *actionSaveAsDefinitionLayer = new QAction( tr( "Save as Layer Definition File…" ), menuExportVector ); connect( actionSaveAsDefinitionLayer, &QAction::triggered, QgisApp::instance(), &QgisApp::saveAsLayerDefinition ); menuExportVector->addAction( actionSaveAsDefinitionLayer ); if ( vlayer->isSpatial() ) { QAction *actionSaveStyle = new QAction( tr( "Save as QGIS Layer Style File…" ), menuExportVector ); connect( actionSaveStyle, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveStyleFile(); } ); menuExportVector->addAction( actionSaveStyle ); } menu->addMenu( menuExportVector ); } else if ( rlayer ) { QMenu *menuExportRaster = new QMenu( tr( "Export" ), menu ); QAction *actionSaveAs = new QAction( tr( "Save As…" ), menuExportRaster ); QAction *actionSaveAsDefinitionLayer = new QAction( tr( "Save as Layer Definition File…" ), menuExportRaster ); QAction *actionSaveStyle = new QAction( tr( "Save as QGIS Layer Style File…" ), menuExportRaster ); connect( actionSaveAs, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveAsFile(); } ); menuExportRaster->addAction( actionSaveAs ); connect( actionSaveAsDefinitionLayer, &QAction::triggered, QgisApp::instance(), &QgisApp::saveAsLayerDefinition ); menuExportRaster->addAction( actionSaveAsDefinitionLayer ); connect( actionSaveStyle, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveStyleFile(); } ); menuExportRaster->addAction( actionSaveStyle ); menu->addMenu( menuExportRaster ); } else if ( layer && layer->type() == QgsMapLayer::PluginLayer && mView->selectedLayerNodes().count() == 1 ) { // disable duplication of plugin layers duplicateLayersAction->setEnabled( false ); } menu->addSeparator(); // style-related actions if ( layer && mView->selectedLayerNodes().count() == 1 ) { menu->addSeparator(); 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 ) { const QgsSingleSymbolRenderer *singleRenderer = dynamic_cast< const QgsSingleSymbolRenderer * >( vlayer->renderer() ); if ( !singleRenderer && vlayer->renderer() && vlayer->renderer()->embeddedRenderer() ) { singleRenderer = dynamic_cast< const QgsSingleSymbolRenderer * >( vlayer->renderer()->embeddedRenderer() ); } 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, &QgsColorWidgetAction::colorChanged, this, &QgsAppLayerTreeViewMenuProvider::setVectorSymbolColor ); //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; QgsApplication::colorSchemeRegistry()->schemes( recentSchemes ); if ( !recentSchemes.isEmpty() ) { QgsColorSwatchGridAction *recentColorAction = new QgsColorSwatchGridAction( recentSchemes.at( 0 ), menuStyleManager, QStringLiteral( "symbology" ), menuStyleManager ); recentColorAction->setProperty( "layerId", vlayer->id() ); recentColorAction->setDismissOnColorSelection( false ); menuStyleManager->addAction( recentColorAction ); connect( recentColorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsAppLayerTreeViewMenuProvider::setVectorSymbolColor ); } 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, &QAction::triggered, this, &QgsAppLayerTreeViewMenuProvider::editVectorSymbol ); menuStyleManager->addAction( editSymbolAction ); } } menu->addMenu( menuStyleManager ); } else { if ( QgisApp::instance()->clipboard()->hasFormat( QGSCLIPBOARD_STYLE_MIME ) ) { menu->addAction( tr( "Paste Style" ), QgisApp::instance(), SLOT( applyStyleToGroup() ) ); } } if ( layer && QgsProject::instance()->layerIsEmbedded( layer->id() ).isEmpty() ) menu->addAction( tr( "&Properties…" ), QgisApp::instance(), SLOT( layerProperties() ) ); } } else if ( QgsLayerTreeModelLegendNode *node = mView->layerTreeModel()->index2legendNode( idx ) ) { if ( QgsSymbolLegendNode *symbolNode = dynamic_cast< QgsSymbolLegendNode * >( node ) ) { // symbology item if ( symbolNode->flags() & Qt::ItemIsUserCheckable ) { menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), tr( "&Show All Items" ), symbolNode, SLOT( checkAllItems() ) ); menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionHideAllLayers.svg" ) ), tr( "&Hide All Items" ), symbolNode, SLOT( uncheckAllItems() ) ); menu->addSeparator(); } if ( symbolNode->symbol() ) { QgsColorWheel *colorWheel = new QgsColorWheel( menu ); colorWheel->setColor( symbolNode->symbol()->color() ); QgsColorWidgetAction *colorAction = new QgsColorWidgetAction( colorWheel, menu, menu ); colorAction->setDismissOnColorSelection( false ); connect( colorAction, &QgsColorWidgetAction::colorChanged, this, &QgsAppLayerTreeViewMenuProvider::setSymbolLegendNodeColor ); //store the layer id and rule key in action, so we can later retrieve the corresponding //legend node, if it still exists colorAction->setProperty( "layerId", symbolNode->layerNode()->layerId() ); colorAction->setProperty( "ruleKey", symbolNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() ); menu->addAction( colorAction ); //add recent colors action QList<QgsRecentColorScheme *> recentSchemes; QgsApplication::colorSchemeRegistry()->schemes( recentSchemes ); if ( !recentSchemes.isEmpty() ) { QgsColorSwatchGridAction *recentColorAction = new QgsColorSwatchGridAction( recentSchemes.at( 0 ), menu, QStringLiteral( "symbology" ), menu ); recentColorAction->setProperty( "layerId", symbolNode->layerNode()->layerId() ); recentColorAction->setProperty( "ruleKey", symbolNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() ); recentColorAction->setDismissOnColorSelection( false ); menu->addAction( recentColorAction ); connect( recentColorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsAppLayerTreeViewMenuProvider::setSymbolLegendNodeColor ); } menu->addSeparator(); } QAction *editSymbolAction = new QAction( tr( "Edit Symbol…" ), menu ); //store the layer id and rule key in action, so we can later retrieve the corresponding //legend node, if it still exists editSymbolAction->setProperty( "layerId", symbolNode->layerNode()->layerId() ); editSymbolAction->setProperty( "ruleKey", symbolNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() ); connect( editSymbolAction, &QAction::triggered, this, &QgsAppLayerTreeViewMenuProvider::editSymbolLegendNodeSymbol ); menu->addAction( editSymbolAction ); } } return menu; }
QgsFeatureIds QgsMapToolSelectUtils::getMatchingFeatures( QgsMapCanvas *canvas, const QgsGeometry &selectGeometry, bool doContains, bool singleSelect ) { QgsFeatureIds newSelectedFeatures; if ( selectGeometry.type() != QgsWkbTypes::PolygonGeometry ) return newSelectedFeatures; QgsVectorLayer *vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( canvas ); if ( !vlayer ) return newSelectedFeatures; // toLayerCoordinates will throw an exception for any 'invalid' points in // the rubber band. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. QgsGeometry selectGeomTrans = selectGeometry; try { QgsCoordinateTransform ct( canvas->mapSettings().destinationCrs(), vlayer->crs(), QgsProject::instance() ); if ( !ct.isShortCircuited() && selectGeomTrans.type() == QgsWkbTypes::PolygonGeometry ) { // convert add more points to the edges of the rectangle // improve transformation result QgsPolygonXY poly( selectGeomTrans.asPolygon() ); if ( poly.size() == 1 && poly.at( 0 ).size() == 5 ) { const QgsPolylineXY &ringIn = poly.at( 0 ); QgsPolygonXY newpoly( 1 ); newpoly[0].resize( 41 ); QgsPolylineXY &ringOut = newpoly[0]; ringOut[ 0 ] = ringIn.at( 0 ); int i = 1; for ( int j = 1; j < 5; j++ ) { QgsVector v( ( ringIn.at( j ) - ringIn.at( j - 1 ) ) / 10.0 ); for ( int k = 0; k < 9; k++ ) { ringOut[ i ] = ringOut[ i - 1 ] + v; i++; } ringOut[ i++ ] = ringIn.at( j ); } selectGeomTrans = QgsGeometry::fromPolygonXY( newpoly ); } } selectGeomTrans.transform( ct ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and leave existing selection unchanged QgsDebugMsg( QStringLiteral( "Caught CRS exception " ) ); QgisApp::instance()->messageBar()->pushMessage( QObject::tr( "CRS Exception" ), QObject::tr( "Selection extends beyond layer's coordinate system" ), Qgis::Warning, QgisApp::instance()->messageTimeout() ); return newSelectedFeatures; } QgsDebugMsgLevel( "Selection layer: " + vlayer->name(), 3 ); QgsDebugMsgLevel( "Selection polygon: " + selectGeomTrans.asWkt(), 3 ); QgsDebugMsgLevel( "doContains: " + QString( doContains ? "T" : "F" ), 3 ); QgsRenderContext context = QgsRenderContext::fromMapSettings( canvas->mapSettings() ); context.expressionContext() << QgsExpressionContextUtils::layerScope( vlayer ); std::unique_ptr< QgsFeatureRenderer > r; if ( vlayer->renderer() ) { r.reset( vlayer->renderer()->clone() ); r->startRender( context, vlayer->fields() ); } QgsFeatureRequest request; request.setFilterRect( selectGeomTrans.boundingBox() ); request.setFlags( QgsFeatureRequest::ExactIntersect ); if ( r ) request.setSubsetOfAttributes( r->usedAttributes( context ), vlayer->fields() ); else request.setNoAttributes(); QgsFeatureIterator fit = vlayer->getFeatures( request ); QgsFeature f; QgsFeatureId closestFeatureId = 0; bool foundSingleFeature = false; double closestFeatureDist = std::numeric_limits<double>::max(); while ( fit.nextFeature( f ) ) { context.expressionContext().setFeature( f ); // make sure to only use features that are visible if ( r && !r->willRenderFeature( f, context ) ) continue; QgsGeometry g = f.geometry(); if ( doContains ) { if ( !selectGeomTrans.contains( g ) ) continue; } else { if ( !selectGeomTrans.intersects( g ) ) continue; } if ( singleSelect ) { foundSingleFeature = true; double distance = g.distance( selectGeomTrans ); if ( distance <= closestFeatureDist ) { closestFeatureDist = distance; closestFeatureId = f.id(); } } else { newSelectedFeatures.insert( f.id() ); } } if ( singleSelect && foundSingleFeature ) { newSelectedFeatures.insert( closestFeatureId ); } if ( r ) r->stopRender( context ); QgsDebugMsg( "Number of new selected features: " + QString::number( newSelectedFeatures.size() ) ); return newSelectedFeatures; }