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