File indexing completed on 2024-05-19 15:27:00

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