Skip to content

Commit

Permalink
use a model for select map layer style categories (#7907)
Browse files Browse the repository at this point in the history
this avoids cluttering QgsMapLayer and reduces a bit code redundancy
  • Loading branch information
3nids committed Sep 14, 2018
1 parent efa7277 commit 3724f9e
Show file tree
Hide file tree
Showing 13 changed files with 357 additions and 196 deletions.
34 changes: 0 additions & 34 deletions python/core/auto_generated/qgsmaplayer.sip.in
Expand Up @@ -94,31 +94,6 @@ This is the base class for all map layer types (vector, raster).
typedef QFlags<QgsMapLayer::StyleCategory> StyleCategories;


struct ReadableStyleCategory
{
public:
ReadableStyleCategory( const QString &name, const QString &toolTip = QString() );
%Docstring
Create a ReadableStyleCategory
%End
ReadableStyleCategory( const QString &name, const QIcon &icon, const QString &toolTip = QString() );
%Docstring
Create a ReadableStyleCategory
%End
QString name() const;
%Docstring
Return the translated name of the category
%End
QString toolTip() const;
%Docstring
Return the translated tooltip of the category
%End
QIcon icon() const;
%Docstring
Return the icon of the category
%End
};

QgsMapLayer( QgsMapLayer::LayerType type = VectorLayer, const QString &name = QString(), const QString &source = QString() );
%Docstring
Constructor for QgsMapLayer
Expand Down Expand Up @@ -181,15 +156,6 @@ Returns the extension of a Property.
.. versionadded:: 3.0
%End

static ReadableStyleCategory readableStyleCategory( StyleCategory category );
%Docstring
Readable and Translated category

.. versionadded:: 3.4
%End



QString id() const;
%Docstring
Returns the layer's unique ID, which is used to access this layer from :py:class:`QgsProject`.
Expand Down
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -61,6 +61,7 @@ SET(QGIS_APP_SRCS
qgslayertreeviewmemoryindicator.cpp
qgslayertreeviewnonremovableindicator.cpp
qgsmapcanvasdockwidget.cpp
qgsmaplayerstylecategoriesmodel.cpp
qgsmaplayerstyleguiutils.cpp
qgsmapsavedialog.cpp
qgspuzzlewidget.cpp
Expand Down Expand Up @@ -285,6 +286,7 @@ SET (QGIS_APP_MOC_HDRS
qgslayertreeviewfilterindicator.h
qgslayertreeviewnonremovableindicator.h
qgsmapcanvasdockwidget.h
qgsmaplayerstylecategoriesmodel.h
qgsmaplayerstyleguiutils.h
qgsmapsavedialog.h
qgspuzzlewidget.h
Expand Down
46 changes: 29 additions & 17 deletions src/app/qgsapplayertreeviewmenuprovider.cpp
Expand Up @@ -12,6 +12,7 @@
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsapplayertreeviewmenuprovider.h"


Expand All @@ -37,6 +38,8 @@
#include "qgslayertreeregistrybridge.h"
#include "qgssymbolselectordialog.h"
#include "qgssinglesymbolrenderer.h"
#include "qgsmaplayerstylecategoriesmodel.h"


QgsAppLayerTreeViewMenuProvider::QgsAppLayerTreeViewMenuProvider( QgsLayerTreeView *view, QgsMapCanvas *canvas )
: mView( view )
Expand Down Expand Up @@ -320,13 +323,17 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
{
QMenu *copyStyleMenu = menuStyleManager->addMenu( tr( "Copy Style" ) );
copyStyleMenu->setToolTipsVisible( true );
QList<QgsMapLayer::StyleCategory> categories = qgsEnumMap<QgsMapLayer::StyleCategory>().keys();
categories.move( categories.indexOf( QgsMapLayer::AllStyleCategories ), 0 ); // move All categories to top
for ( QgsMapLayer::StyleCategory category : categories )
QgsMapLayerStyleCategoriesModel *model = new QgsMapLayerStyleCategoriesModel( copyStyleMenu );
model->setShowAllCategories( true );
for ( int row = 0; row < model->rowCount(); ++row )
{
QgsMapLayer::ReadableStyleCategory readableCategory = QgsMapLayer::readableStyleCategory( category );
QAction *copyAction = new QAction( readableCategory.icon(), readableCategory.name(), copyStyleMenu );
copyAction->setToolTip( readableCategory.toolTip() );
QModelIndex index = model->index( row, 0 );
QString name = model->data( index, Qt::DisplayRole ).toString();
QString tooltip = model->data( index, Qt::ToolTipRole ).toString();
QIcon icon = model->data( index, Qt::DecorationRole ).value<QIcon>();
QgsMapLayer::StyleCategory category = model->index2category( index );
QAction *copyAction = new QAction( icon, name, copyStyleMenu );
copyAction->setToolTip( tooltip );
connect( copyAction, &QAction::triggered, this, [ = ]() {app->copyStyle( layer, category );} );
copyStyleMenu->addAction( copyAction );
if ( category == QgsMapLayer::AllStyleCategories )
Expand All @@ -342,19 +349,24 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
{
if ( layer->type() == QgsMapLayer::VectorLayer )
{
QMenu *copyStyleMenu = menuStyleManager->addMenu( tr( "Paste Style" ) );
copyStyleMenu->setToolTipsVisible( true );
QList<QgsMapLayer::StyleCategory> categories = qgsEnumMap<QgsMapLayer::StyleCategory>().keys();
categories.move( categories.indexOf( QgsMapLayer::AllStyleCategories ), 0 ); // move All categories to top
for ( QgsMapLayer::StyleCategory category : categories )
QMenu *pasteStyleMenu = menuStyleManager->addMenu( tr( "Paste Style" ) );
pasteStyleMenu->setToolTipsVisible( true );

QgsMapLayerStyleCategoriesModel *model = new QgsMapLayerStyleCategoriesModel( pasteStyleMenu );
model->setShowAllCategories( true );
for ( int row = 0; row < model->rowCount(); ++row )
{
QgsMapLayer::ReadableStyleCategory readableCategory = QgsMapLayer::readableStyleCategory( category );
QAction *copyAction = new QAction( readableCategory.icon(), readableCategory.name() );
copyAction->setToolTip( readableCategory.toolTip() );
connect( copyAction, &QAction::triggered, this, [ = ]() {app->pasteStyle( layer, category );} );
copyStyleMenu->addAction( copyAction );
QModelIndex index = model->index( row, 0 );
QString name = model->data( index, Qt::DisplayRole ).toString();
QString tooltip = model->data( index, Qt::ToolTipRole ).toString();
QIcon icon = model->data( index, Qt::DecorationRole ).value<QIcon>();
QgsMapLayer::StyleCategory category = model->index2category( index );
QAction *copyAction = new QAction( icon, name, pasteStyleMenu );
copyAction->setToolTip( tooltip );
connect( copyAction, &QAction::triggered, this, [ = ]() {app->copyStyle( layer, category );} );
pasteStyleMenu->addAction( copyAction );
if ( category == QgsMapLayer::AllStyleCategories )
copyStyleMenu->addSeparator();
pasteStyleMenu->addSeparator();
}
}
else
Expand Down
237 changes: 237 additions & 0 deletions src/app/qgsmaplayerstylecategoriesmodel.cpp
@@ -0,0 +1,237 @@
/***************************************************************************
qgsmaplayerstylecategoriesmodel.cpp
--------------------------------------
Date : September 2018
Copyright : (C) 2018 by Denis Rouzaud
Email : denis@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsmaplayerstylecategoriesmodel.h"

QgsMapLayerStyleCategoriesModel::QgsMapLayerStyleCategoriesModel( QObject *parent )
: QAbstractListModel( parent )
{
mCategoryList = qgsEnumMap<QgsMapLayer::StyleCategory>().keys();
// move All categories to top
mCategoryList.move( mCategoryList.indexOf( QgsMapLayer::AllStyleCategories ), 0 );
}

void QgsMapLayerStyleCategoriesModel::setCategories( QgsMapLayer::StyleCategories categories )
{
if ( mCategories == categories )
return;

beginResetModel();
mCategories = categories;
endResetModel();
}

QgsMapLayer::StyleCategories QgsMapLayerStyleCategoriesModel::categories() const
{
return mCategories;
}

void QgsMapLayerStyleCategoriesModel::setShowAllCategories( bool showAll )
{
beginResetModel();
mShowAllCategories = showAll;
endResetModel();
}

QgsMapLayer::StyleCategory QgsMapLayerStyleCategoriesModel::index2category( const QModelIndex &index ) const
{
return mCategoryList.at( index.row() - ( mShowAllCategories ? 0 : 1 ) );
}

int QgsMapLayerStyleCategoriesModel::rowCount( const QModelIndex & ) const
{
int count = mCategoryList.count();
if ( !mShowAllCategories )
count--;
return count;
}

int QgsMapLayerStyleCategoriesModel::columnCount( const QModelIndex & ) const
{
return 1;
}

QVariant QgsMapLayerStyleCategoriesModel::data( const QModelIndex &index, int role ) const
{
if ( !index.isValid() || index.row() >= rowCount() )
return QVariant();

QgsMapLayer::StyleCategory category = index2category( index );

switch ( category )
{
case QgsMapLayer::LayerConfiguration:
switch ( role )
{
case Qt::DisplayRole:
return tr( "Layer Configuration" );
case Qt::ToolTipRole:
return tr( "Identifiable, removable, searchable, display expression, read-only" );
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/system.svg" ) );
}
case QgsMapLayer::Symbology :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Symbology" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/symbology.svg" ) );
}
case QgsMapLayer::Symbology3D:
switch ( role )
{
case Qt::DisplayRole:
return tr( "3D Symbology" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/3d.svg" ) );
}
case QgsMapLayer::Labeling :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Labels" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/labels.svg" ) );
}
case QgsMapLayer::Fields :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Fields" );
case Qt::ToolTipRole:
return tr( "Aliases, widgets, WMS/WFS, expressions, constraints, virtual fields" );
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/mSourceFields" ) );
}
case QgsMapLayer::Forms :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Forms" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/mActionFormView" ) );
}
case QgsMapLayer::Actions :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Actions" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/action.svg" ) );
}
case QgsMapLayer::MapTips :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Map Tips" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/display.svg" ) );
}
case QgsMapLayer::Diagrams :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Diagrams" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/diagram.svg" ) );
}
case QgsMapLayer::AttributeTable :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Attribute Table Settings" );
case Qt::ToolTipRole:
return tr( "Choice and order of columns, conditional styling" );
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable" ) );
}
case QgsMapLayer::Rendering :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Rendering" );
case Qt::ToolTipRole:
return tr( "Scale visibility, simplify method, opacity" );
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/rendering.svg" ) );
}
case QgsMapLayer::CustomProperties :
switch ( role )
{
case Qt::DisplayRole:
return tr( "Custom Properties" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/mActionOptions.svg" ) );
}
case QgsMapLayer::AllStyleCategories :
switch ( role )
{
case Qt::DisplayRole:
return tr( "All Style Categories" );
case Qt::ToolTipRole:
return QVariant();
case Qt::DecorationRole:
return QVariant();
}
}
return QVariant();
}

bool QgsMapLayerStyleCategoriesModel::setData( const QModelIndex &index, const QVariant &value, int role )
{
if ( !index.isValid() || index.row() >= rowCount() )
return false;

if ( role == Qt::CheckStateRole )
{
QgsMapLayer::StyleCategory category = index2category( index );
if ( value.value<Qt::CheckState>() == Qt::Checked )
{
mCategories |= category;
emit dataChanged( index, index );
return true;
}
else if ( value.value<Qt::CheckState>() == Qt::Unchecked )
{
mCategories &= category;
emit dataChanged( index, index );
return true;
}
}
return false;
}


Qt::ItemFlags QgsMapLayerStyleCategoriesModel::flags( const QModelIndex & ) const
{
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
}

0 comments on commit 3724f9e

Please sign in to comment.