File indexing completed on 2024-05-19 04:21:55

0001 /**
0002  * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
0003  *
0004  * This file is part of the KD Chart library.
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "TableModel.h"
0010 
0011 #include <QtGlobal>
0012 #include <QtDebug>
0013 #include <QFile>
0014 #include <QByteArray>
0015 #include <QString>
0016 
0017 TableModel::TableModel( QObject* parent )
0018     : QAbstractTableModel( parent ),
0019       m_dataHasHorizontalHeaders( true ),
0020       m_dataHasVerticalHeaders( true ),
0021       m_supplyHeaderData( true )
0022 {
0023 }
0024 
0025 TableModel::~TableModel()
0026 {
0027 }
0028 
0029 int TableModel::rowCount( const QModelIndex& ) const
0030 {
0031     return m_rows.size();
0032 }
0033 
0034 int TableModel::columnCount( const QModelIndex& ) const
0035 {
0036     return m_rows.isEmpty() ? 0 : m_rows.first().size();
0037 }
0038 
0039 QVariant TableModel::data( const QModelIndex& index, int role ) const
0040 {
0041     // FIXME kchart queries (-1, -1) for empty models
0042     if ( index.row() == -1 || index.column() == -1 ) {
0043         qDebug() << "TableModel::data: row:"
0044                  << index.row() << ", column:" << index.column()
0045                  << ", rowCount:" << rowCount() << ", columnCount:"
0046                  << columnCount()
0047                  << "\nTableModel::data: FIXME fix kchart views to not query"
0048                     " model data for invalid indices!";
0049         return QVariant();
0050     }
0051 
0052 /*    qDebug () << "TableModel::data: row: "<< index.row() << ", column: "
0053               << index.column() << endl;*/
0054     Q_ASSERT( index.row() >= 0 && index.row() < rowCount() );
0055     Q_ASSERT( index.column() >= 0 && index.column() < columnCount() );
0056 
0057     if ( role == Qt::DisplayRole || role == Qt::EditRole ) {
0058         return m_rows[ index.row() ][ index.column() ];
0059     } else {
0060         return QVariant();
0061     }
0062 }
0063 
0064 QVariant TableModel::headerData( int section, Qt::Orientation orientation, int role ) const
0065 {
0066     QVariant result;
0067 
0068     switch ( role ) {
0069     case Qt::DisplayRole:
0070     case Qt::EditRole:
0071         if ( m_supplyHeaderData ) {
0072             if ( orientation == Qt::Horizontal ) {
0073                 // column header data
0074                 if ( !m_horizontalHeaderData.isEmpty() )
0075                     result = m_horizontalHeaderData[ section ];
0076             } else {
0077                 // row header data:
0078                 if ( !m_verticalHeaderData.isEmpty() )
0079                     result = m_verticalHeaderData[ section ];
0080             }
0081         }
0082     break;
0083     case Qt::TextAlignmentRole:
0084 //        result = QVariant ( Qt::AlignHCenter | Qt::AlignHCenter );
0085         break;
0086     case Qt::DecorationRole:
0087     case Qt::ToolTipRole:
0088         break;
0089     default:
0090 //        qDebug () << "TableModel::headerData: unknown role " << role << "." << endl;
0091         break;
0092     }
0093     return result;
0094 }
0095 
0096 
0097 bool TableModel::setData( const QModelIndex& index, const QVariant& value, int role/* = Qt::EditRole */ )
0098 {
0099     Q_ASSERT( index.row() >= 0 && index.row() < rowCount() );
0100     Q_ASSERT( index.column() >= 0 && index.column() < columnCount() );
0101 
0102     if ( role == Qt::EditRole ) {
0103         m_rows[ index.row() ][ index.column() ] = value;
0104         Q_EMIT dataChanged( index, index );
0105         return true;
0106     } else {
0107         return false;
0108     }
0109 }
0110 
0111 static QStringList splitLine( const QString& line )
0112 {
0113     QStringList sl = line.split( QChar( ',' ) );
0114     QStringList ret;
0115     for ( int i = 0; i < sl.size(); i++ ) {
0116         // get rid of leading and trailing whitespace and quotes
0117         QString s = sl.at( i ).simplified();
0118         if ( s.startsWith( '\"') ) {
0119             s.remove( 0, 1 );
0120         }
0121         if ( s.endsWith( '\"') ) {
0122               s.remove( s.length() - 1, 1 );
0123         }
0124         ret.append( s );
0125     }
0126     return ret;
0127 }
0128 
0129 bool TableModel::loadFromCSV( const QString& filename )
0130 {
0131     QFile file( filename );
0132     if ( !file.exists() || !file.open ( QIODevice::ReadOnly ) ) {
0133         qDebug() << "TableModel::loadFromCSV: file" << filename
0134                  << "does not exist or could not be opened";
0135         return false;
0136     }
0137 
0138     QStringList lines;
0139     while ( !file.atEnd() ) {
0140         lines.append( QString::fromUtf8( file.readLine() ) );
0141     }
0142 
0143     setTitleText( QString() );
0144     m_rows.clear();
0145     m_rows.resize( qMax( 0, lines.size() - ( m_dataHasHorizontalHeaders ? 1 : 0 ) ) );
0146 
0147     for ( int row = 0; row < lines.size(); ++row ) {
0148         QStringList cells = splitLine( lines.at( row ) );
0149 
0150         QVector<QVariant> values( qMax( 0, cells.size() - ( m_dataHasVerticalHeaders ? 1 : 0 ) ) );
0151 
0152         for ( int column = 0; column < cells.size(); ++column ) {
0153             QString cell = cells.at( column );
0154 
0155             if ( row == 0 && m_dataHasHorizontalHeaders ) {
0156                 // interpret the first row as column headers:
0157                 // the first one is an exception: interpret that as title
0158                 if ( column == 0 && m_dataHasVerticalHeaders ) {
0159                     setTitleText( cell );
0160                 } else {
0161                     m_horizontalHeaderData.append( cell );
0162                 }
0163             } else {
0164                 if ( column == 0 && m_dataHasVerticalHeaders ) {
0165                     // interpret first column as row headers:
0166                     m_verticalHeaderData.append( cell );
0167                 } else {
0168                     // try to interpret cell values as floating point
0169                     bool convertedOk = false;
0170                     qreal numeric = cell.toDouble( &convertedOk );
0171                     const int destColumn = column - ( m_dataHasVerticalHeaders ? 1 : 0 );
0172                     values[ destColumn ] = convertedOk ? numeric : ( cell.isEmpty() ? QVariant() : cell );
0173                 }
0174             }
0175         }
0176         const int destRow = row - ( m_dataHasHorizontalHeaders ? 1 : 0 );
0177         if ( destRow >= 0 ) {
0178             m_rows[ destRow ] = values;
0179         }
0180     }
0181 
0182     beginResetModel();
0183     endResetModel();
0184 
0185     if ( m_rows.isEmpty() ) {
0186         qDebug() << "TableModel::loadFromCSV: table loaded, but no "
0187                     "model data found.";
0188     }
0189     return true;
0190 }
0191 
0192 void TableModel::clear()
0193 {
0194     beginResetModel();
0195     m_rows.clear();
0196     endResetModel();
0197 }