1 /***************************************************************************
2 qgsreportsectionmodel.cpp
3 ---------------------
4 begin : December 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgsreportsectionmodel.h"
17 #include "functional"
18 #include "qgsguiutils.h"
19
20 #ifdef ENABLE_MODELTEST
21 #include "modeltest.h"
22 #endif
23
QgsReportSectionModel(QgsReport * report,QObject * parent)24 QgsReportSectionModel::QgsReportSectionModel( QgsReport *report, QObject *parent )
25 : QAbstractItemModel( parent )
26 , mReport( report )
27 {
28 }
29
flags(const QModelIndex & index) const30 Qt::ItemFlags QgsReportSectionModel::flags( const QModelIndex &index ) const
31 {
32 if ( !index.isValid() )
33 return Qt::ItemFlags();
34
35 return QAbstractItemModel::flags( index );
36 }
37
data(const QModelIndex & index,int role) const38 QVariant QgsReportSectionModel::data( const QModelIndex &index, int role ) const
39 {
40 if ( !index.isValid() )
41 return QVariant();
42
43 QgsAbstractReportSection *section = sectionForIndex( index );
44 if ( !section )
45 return QVariant();
46
47 switch ( role )
48 {
49 case Qt::DisplayRole:
50 case Qt::ToolTipRole:
51 {
52 switch ( index.column() )
53 {
54 case 0:
55 return section->description();
56 default:
57 return QVariant();
58 }
59 break;
60 }
61
62 case Qt::DecorationRole:
63 switch ( index.column() )
64 {
65 case 0:
66 {
67 QIcon icon = section->icon();
68
69 if ( section == mEditedSection )
70 {
71 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
72 QPixmap pixmap( icon.pixmap( iconSize, iconSize ) );
73
74 QPainter painter( &pixmap );
75 painter.drawPixmap( 0, 0, iconSize, iconSize, QgsApplication::getThemePixmap( QStringLiteral( "/mActionToggleEditing.svg" ) ) );
76 painter.end();
77
78 return QIcon( pixmap );
79 }
80 else
81 {
82 return icon;
83 }
84 }
85
86 default:
87 return QVariant();
88 }
89 break;
90
91 case Qt::TextAlignmentRole:
92 {
93 return ( index.column() == 2 || index.column() == 3 ) ? Qt::AlignRight : Qt::AlignLeft;
94 }
95
96 case Qt::EditRole:
97 {
98 switch ( index.column() )
99 {
100 case 0:
101 return section->type();
102
103 default:
104 return QVariant();
105 }
106 break;
107 }
108
109 default:
110 return QVariant();
111 }
112
113 #ifndef _MSC_VER
114 return QVariant();
115 #endif
116 }
117
headerData(int section,Qt::Orientation orientation,int role) const118 QVariant QgsReportSectionModel::headerData( int section, Qt::Orientation orientation, int role ) const
119 {
120 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section <= 0 )
121 {
122 QStringList lst;
123 lst << tr( "Section" );
124 return lst[section];
125 }
126
127 return QVariant();
128 }
129
rowCount(const QModelIndex & parent) const130 int QgsReportSectionModel::rowCount( const QModelIndex &parent ) const
131 {
132 if ( !parent.isValid() )
133 return 1; // report
134
135 QgsAbstractReportSection *parentSection = sectionForIndex( parent );
136 return parentSection ? parentSection->childCount() : 0;
137 }
138
hasChildren(const QModelIndex & parent) const139 bool QgsReportSectionModel::hasChildren( const QModelIndex &parent ) const
140 {
141 if ( !parent.isValid() )
142 return true; // root item: its children are top level items
143
144 QgsAbstractReportSection *parentSection = sectionForIndex( parent );
145 return parentSection && parentSection->childCount() > 0;
146 }
147
columnCount(const QModelIndex &) const148 int QgsReportSectionModel::columnCount( const QModelIndex & ) const
149 {
150 return 1;
151 }
152
index(int row,int column,const QModelIndex & parent) const153 QModelIndex QgsReportSectionModel::index( int row, int column, const QModelIndex &parent ) const
154 {
155 if ( !hasIndex( row, column, parent ) )
156 return QModelIndex();
157
158 QgsAbstractReportSection *parentSection = sectionForIndex( parent );
159 if ( parentSection )
160 {
161 QgsAbstractReportSection *item = parentSection->childSections().value( row, nullptr );
162 return item ? createIndex( row, column, item ) : QModelIndex();
163 }
164 else
165 {
166 if ( row == 0 )
167 return createIndex( row, column, nullptr );
168 else
169 return QModelIndex();
170 }
171 }
172
parent(const QModelIndex & index) const173 QModelIndex QgsReportSectionModel::parent( const QModelIndex &index ) const
174 {
175 QgsAbstractReportSection *childSection = sectionForIndex( index );
176 if ( !childSection )
177 return QModelIndex();
178
179 QgsAbstractReportSection *parentSection = childSection->parentSection();
180
181 if ( !parentSection )
182 return QModelIndex();
183 else
184 return createIndex( parentSection->row(), 0, parentSection != mReport ? parentSection : nullptr );
185 }
186
sectionForIndex(const QModelIndex & index) const187 QgsAbstractReportSection *QgsReportSectionModel::sectionForIndex( const QModelIndex &index ) const
188 {
189 if ( !index.isValid() )
190 return nullptr;
191
192 if ( !index.internalPointer() ) // top level item
193 return mReport; // IMPORTANT - QgsReport uses multiple inheritance, so cannot static cast the void*!
194
195 return static_cast<QgsAbstractReportSection *>( index.internalPointer() );
196 }
197
indexForSection(QgsAbstractReportSection * section) const198 QModelIndex QgsReportSectionModel::indexForSection( QgsAbstractReportSection *section ) const
199 {
200 if ( !section )
201 return QModelIndex();
202
203 std::function< QModelIndex( const QModelIndex &parent, QgsAbstractReportSection *section ) > findIndex = [&]( const QModelIndex & parent, QgsAbstractReportSection * section )->QModelIndex
204 {
205 for ( int row = 0; row < rowCount( parent ); ++row )
206 {
207 QModelIndex current = index( row, 0, parent );
208 if ( sectionForIndex( current ) == section )
209 return current;
210
211 QModelIndex checkChildren = findIndex( current, section );
212 if ( checkChildren.isValid() )
213 return checkChildren;
214 }
215 return QModelIndex();
216 };
217
218 return findIndex( QModelIndex(), section );
219 }
220
setEditedSection(QgsAbstractReportSection * section)221 void QgsReportSectionModel::setEditedSection( QgsAbstractReportSection *section )
222 {
223 QModelIndex oldSection;
224 if ( mEditedSection )
225 {
226 oldSection = indexForSection( mEditedSection );
227 }
228
229 mEditedSection = section;
230 if ( oldSection.isValid() )
231 emit dataChanged( oldSection, oldSection, QVector<int>() << Qt::DecorationRole );
232
233 if ( mEditedSection )
234 {
235 QModelIndex newSection = indexForSection( mEditedSection );
236 emit dataChanged( newSection, newSection, QVector<int>() << Qt::DecorationRole );
237 }
238
239 }
240
removeRows(int row,int count,const QModelIndex & parent)241 bool QgsReportSectionModel::removeRows( int row, int count, const QModelIndex &parent )
242 {
243 QgsAbstractReportSection *parentSection = sectionForIndex( parent );
244
245 if ( row < 0 || row >= parentSection->childCount() )
246 return false;
247
248 beginRemoveRows( parent, row, row + count - 1 );
249
250 for ( int i = 0; i < count; i++ )
251 {
252 if ( row < parentSection->childCount() )
253 {
254 parentSection->removeChildAt( row );
255 }
256 }
257
258 endRemoveRows();
259
260 return true;
261 }
262
addSection(const QModelIndex & parent,std::unique_ptr<QgsAbstractReportSection> section)263 void QgsReportSectionModel::addSection( const QModelIndex &parent, std::unique_ptr<QgsAbstractReportSection> section )
264 {
265 QgsAbstractReportSection *parentSection = sectionForIndex( parent );
266 if ( !parentSection )
267 parentSection = mReport;
268
269 beginInsertRows( parent, parentSection->childCount(), parentSection->childCount() );
270 parentSection->appendChild( section.release() );
271 endInsertRows();
272 }
273
274