Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgspointcloudattributemodel.cpp 3 : : --------------------- 4 : : begin : November 2020 5 : : copyright : (C) 2020 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : 18 : : #include "qgspointcloudattributemodel.h" 19 : : #include "qgspointcloudlayer.h" 20 : : #include "qgspointcloudindex.h" 21 : : #include "qgsapplication.h" 22 : : 23 : 0 : QgsPointCloudAttributeModel::QgsPointCloudAttributeModel( QObject *parent ) 24 : 0 : : QAbstractItemModel( parent ) 25 : 0 : { 26 : : 27 : 0 : } 28 : : 29 : 0 : void QgsPointCloudAttributeModel::setLayer( QgsPointCloudLayer *layer ) 30 : : { 31 : 0 : if ( layer ) 32 : : { 33 : 0 : mLayer = layer; 34 : 0 : setAttributes( layer->attributes() ); 35 : 0 : } 36 : : else 37 : 0 : setAttributes( QgsPointCloudAttributeCollection() ); 38 : 0 : } 39 : : 40 : 0 : QgsPointCloudLayer *QgsPointCloudAttributeModel::layer() 41 : : { 42 : 0 : return mLayer; 43 : : } 44 : : 45 : 0 : void QgsPointCloudAttributeModel::setAttributes( const QgsPointCloudAttributeCollection &attributes ) 46 : : { 47 : 0 : beginResetModel(); 48 : 0 : mAttributes = attributes; 49 : 0 : endResetModel(); 50 : 0 : } 51 : : 52 : 0 : void QgsPointCloudAttributeModel::setAllowEmptyAttributeName( bool allowEmpty ) 53 : : { 54 : 0 : if ( allowEmpty == mAllowEmpty ) 55 : 0 : return; 56 : : 57 : 0 : if ( allowEmpty ) 58 : : { 59 : 0 : beginInsertRows( QModelIndex(), 0, 0 ); 60 : 0 : mAllowEmpty = true; 61 : 0 : endInsertRows(); 62 : 0 : } 63 : : else 64 : : { 65 : 0 : beginRemoveRows( QModelIndex(), 0, 0 ); 66 : 0 : mAllowEmpty = false; 67 : 0 : endRemoveRows(); 68 : : } 69 : 0 : } 70 : : 71 : 0 : QModelIndex QgsPointCloudAttributeModel::indexFromName( const QString &name ) 72 : : { 73 : 0 : if ( !name.isEmpty() ) 74 : : { 75 : 0 : int idx = mAttributes.indexOf( name ); 76 : 0 : if ( idx >= 0 ) 77 : : { 78 : 0 : if ( mAllowEmpty ) 79 : 0 : return index( 1 + idx, 0 ); 80 : : else 81 : 0 : return index( idx, 0 ); 82 : : } 83 : 0 : } 84 : : 85 : 0 : if ( mAllowEmpty && name.isEmpty() ) 86 : 0 : return index( 0, 0 ); 87 : : 88 : 0 : return QModelIndex(); 89 : 0 : } 90 : : 91 : 0 : QModelIndex QgsPointCloudAttributeModel::index( int row, int column, const QModelIndex &parent ) const 92 : : { 93 : 0 : if ( hasIndex( row, column, parent ) ) 94 : : { 95 : 0 : return createIndex( row, column, row ); 96 : : } 97 : : 98 : 0 : return QModelIndex(); 99 : 0 : } 100 : : 101 : 0 : QModelIndex QgsPointCloudAttributeModel::parent( const QModelIndex &child ) const 102 : : { 103 : 0 : Q_UNUSED( child ) 104 : 0 : return QModelIndex(); 105 : : } 106 : : 107 : 0 : int QgsPointCloudAttributeModel::rowCount( const QModelIndex &parent ) const 108 : : { 109 : 0 : if ( parent.isValid() ) 110 : : { 111 : 0 : return 0; 112 : : } 113 : : 114 : 0 : return ( mAllowEmpty ? 1 : 0 ) + mAttributes.count(); 115 : 0 : } 116 : : 117 : 0 : int QgsPointCloudAttributeModel::columnCount( const QModelIndex &parent ) const 118 : : { 119 : 0 : Q_UNUSED( parent ) 120 : 0 : return 1; 121 : : } 122 : : 123 : 0 : QVariant QgsPointCloudAttributeModel::data( const QModelIndex &index, int role ) const 124 : : { 125 : 0 : if ( !index.isValid() ) 126 : 0 : return QVariant(); 127 : : 128 : 0 : const bool isEmpty = mAllowEmpty && index.row() == 0; 129 : 0 : const int fieldOffset = mAllowEmpty ? 1 : 0; 130 : : 131 : 0 : if ( !isEmpty && ( index.row() - fieldOffset >= mAttributes.count() ) ) 132 : 0 : return QVariant(); 133 : : 134 : 0 : switch ( role ) 135 : : { 136 : : case AttributeNameRole: 137 : : { 138 : 0 : if ( isEmpty ) 139 : : { 140 : 0 : return QVariant(); 141 : : } 142 : 0 : return mAttributes.at( index.row() - fieldOffset ).name(); 143 : : } 144 : : 145 : : case AttributeIndexRole: 146 : : { 147 : 0 : if ( isEmpty ) 148 : : { 149 : 0 : return QVariant(); 150 : : } 151 : 0 : return index.row() - fieldOffset; 152 : : } 153 : : 154 : : case AttributeSizeRole: 155 : : { 156 : 0 : if ( isEmpty ) 157 : : { 158 : 0 : return QVariant(); 159 : : } 160 : 0 : return static_cast< int >( mAttributes.at( index.row() - fieldOffset ).size() ); 161 : : } 162 : : 163 : : case AttributeTypeRole: 164 : : { 165 : 0 : if ( isEmpty ) 166 : : { 167 : 0 : return QVariant(); 168 : : } 169 : 0 : return static_cast< int >( mAttributes.at( index.row() - fieldOffset ).type() ); 170 : : } 171 : : 172 : : case IsEmptyRole: 173 : : { 174 : 0 : return isEmpty; 175 : : } 176 : : 177 : : case IsNumericRole: 178 : : { 179 : 0 : if ( isEmpty ) 180 : : { 181 : 0 : return QVariant(); 182 : 0 : } 183 : 0 : return QgsPointCloudAttribute::isNumeric( mAttributes.at( index.row() - fieldOffset ).type() ); 184 : : } 185 : : 186 : : case Qt::DisplayRole: 187 : : case Qt::EditRole: 188 : : case Qt::ToolTipRole: 189 : : { 190 : 0 : if ( isEmpty ) 191 : : { 192 : 0 : return QVariant(); 193 : : } 194 : 0 : else if ( role == Qt::ToolTipRole ) 195 : : { 196 : 0 : return attributeToolTip( mAttributes.at( index.row() - fieldOffset ) ); 197 : : } 198 : : else 199 : 0 : return mAttributes.at( index.row() - fieldOffset ).name(); 200 : : } 201 : : 202 : : case Qt::DecorationRole: 203 : : { 204 : 0 : if ( !isEmpty ) 205 : : { 206 : 0 : return iconForAttributeType( mAttributes.at( index.row() - fieldOffset ).type() ); 207 : : } 208 : 0 : return QIcon(); 209 : : } 210 : : 211 : : default: 212 : 0 : return QVariant(); 213 : : } 214 : 0 : } 215 : : 216 : 0 : QString QgsPointCloudAttributeModel::attributeToolTip( const QgsPointCloudAttribute &attribute ) 217 : : { 218 : 0 : QString toolTip = QStringLiteral( "<b>%1</b>" ).arg( attribute.name() ); 219 : : 220 : 0 : toolTip += QStringLiteral( "<br><font style='font-family:monospace; white-space: nowrap;'>%3</font>" ).arg( attribute.displayType() ); 221 : : 222 : 0 : return toolTip; 223 : 0 : } 224 : : 225 : 0 : QIcon QgsPointCloudAttributeModel::iconForAttributeType( QgsPointCloudAttribute::DataType type ) 226 : : { 227 : 0 : switch ( type ) 228 : : { 229 : : case QgsPointCloudAttribute::Short: 230 : : case QgsPointCloudAttribute::UShort: 231 : : case QgsPointCloudAttribute::Int32: 232 : : { 233 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldInteger.svg" ); 234 : : } 235 : : case QgsPointCloudAttribute::Float: 236 : : case QgsPointCloudAttribute::Double: 237 : : { 238 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldFloat.svg" ); 239 : : } 240 : : case QgsPointCloudAttribute::Char: 241 : : { 242 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldText.svg" ); 243 : : } 244 : : 245 : : } 246 : 0 : return QIcon(); 247 : 0 : } 248 : : 249 : : // 250 : : // QgsPointCloudAttributeProxyModel 251 : : // 252 : : 253 : 0 : QgsPointCloudAttributeProxyModel::QgsPointCloudAttributeProxyModel( QgsPointCloudAttributeModel *source, QObject *parent ) 254 : 0 : : QSortFilterProxyModel( parent ) 255 : 0 : , mModel( source ) 256 : 0 : { 257 : 0 : setSourceModel( mModel ); 258 : 0 : } 259 : : 260 : 0 : QgsPointCloudAttributeProxyModel *QgsPointCloudAttributeProxyModel::setFilters( QgsPointCloudAttributeProxyModel::Filters filters ) 261 : : { 262 : 0 : mFilters = filters; 263 : 0 : invalidateFilter(); 264 : 0 : return this; 265 : : } 266 : : 267 : 0 : bool QgsPointCloudAttributeProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const 268 : : { 269 : 0 : QModelIndex index = sourceModel()->index( source_row, 0, source_parent ); 270 : : 271 : 0 : if ( mFilters.testFlag( AllTypes ) ) 272 : 0 : return true; 273 : : 274 : 0 : const QVariant typeVar = mModel->data( index, QgsPointCloudAttributeModel::AttributeTypeRole ); 275 : 0 : if ( typeVar.isNull() ) 276 : 0 : return true; 277 : : 278 : : bool ok; 279 : 0 : const QgsPointCloudAttribute::DataType type = static_cast< QgsPointCloudAttribute::DataType >( typeVar.toInt( &ok ) ); 280 : 0 : if ( !ok ) 281 : 0 : return true; 282 : : 283 : 0 : if ( ( mFilters.testFlag( Char ) && type == QgsPointCloudAttribute::Char ) || 284 : 0 : ( mFilters.testFlag( Short ) && type == QgsPointCloudAttribute::Short ) || 285 : 0 : ( mFilters.testFlag( Short ) && type == QgsPointCloudAttribute::UShort ) || 286 : 0 : ( mFilters.testFlag( Int32 ) && type == QgsPointCloudAttribute::Int32 ) || 287 : 0 : ( mFilters.testFlag( Float ) && type == QgsPointCloudAttribute::Float ) || 288 : 0 : ( mFilters.testFlag( Double ) && type == QgsPointCloudAttribute::Double ) ) 289 : 0 : return true; 290 : : 291 : 0 : return false; 292 : 0 : } 293 : : 294 : 0 : bool QgsPointCloudAttributeProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const 295 : : { 296 : : // empty field is always first 297 : 0 : if ( sourceModel()->data( left, QgsPointCloudAttributeModel::IsEmptyRole ).toBool() ) 298 : 0 : return true; 299 : 0 : else if ( sourceModel()->data( right, QgsPointCloudAttributeModel::IsEmptyRole ).toBool() ) 300 : 0 : return false; 301 : : 302 : : // order is attribute order 303 : : bool lok, rok; 304 : 0 : int leftId = sourceModel()->data( left, QgsPointCloudAttributeModel::AttributeIndexRole ).toInt( &lok ); 305 : 0 : int rightId = sourceModel()->data( right, QgsPointCloudAttributeModel::AttributeIndexRole ).toInt( &rok ); 306 : : 307 : 0 : if ( !lok ) 308 : 0 : return false; 309 : 0 : if ( !rok ) 310 : 0 : return true; 311 : : 312 : 0 : return leftId < rightId; 313 : 0 : }