/*************************************************************************** * qxtcsvmodel.cpp: a table model onto a CSV file * * Copyright (C) 2005-2007 by Adam Higerd * * ahigerd@stratitec.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation; either version 2.1 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "QxtCsvModel.h" #include #include class QxtCsvModelPrivate : public QxtPrivate { public: QxtCsvModelPrivate() : csvData(), header(), maxColumn(0) {} QXT_DECLARE_PUBLIC(QxtCsvModel); QStringList csvData; QStringList header; int maxColumn; } QxtCsvModel::QxtCsvModel(QObject *parent) : QAbstractTableModel(parent) { QXT_INIT_PRIVATE(QxtCsvModel); } QxtCsvModel::QxtCsvModel(QIODevice *file, QObject *parent, bool withHeader, QChar separator) : QAbstractTableModel(parent) { QXT_INIT_PRIVATE(QxtCsvModel); setSource(file, withHeader, separator); } QxtCsvModel::QxtCsvModel(const QString filename, QObject *parent, bool withHeader, QChar separator) : QAbstractTableModel(parent) { QXT_INIT_PRIVATE(QxtCsvModel); QFile src(filename); setSource(&src, withHeader, separator); } QxtCsvModel::~QxtCsvModel() { } int QxtCsvModel::rowCount(const QModelIndex& parent) const { if(parent.row()!=-1 && parent.column()!=-1) return 0; return qxt_d().csvData.count(); } int QxtCsvModel::columnCount(const QModelIndex& parent) const { if(parent.row()!=-1 && parent.column()!=-1) return 0; return qxt_d().maxColumn; } QVariant QxtCsvModel::data(const QModelIndex& index, int role) const { if(index.parent()!=QModelIndex()) return QVariant(); if(role==Qt::DisplayRole || role==Qt::EditRole || role==Qt::UserRole) return qxt_d().csvData[index.row()].section(QChar(1),index.column(),index.column()); else { //QVariant v; return QVariant(); } } QVariant QxtCsvModel::headerData(int section, Qt::Orientation orientation, int role) const { if(section < qxt_d().header.count() && orientation==Qt::Horizontal && (role==Qt::DisplayRole || role==Qt::EditRole || role==Qt::UserRole)) { return qxt_d().header[section]; } else return QAbstractTableModel::headerData(section, orientation, role); } void QxtCsvModel::setSource(const QString filename, bool withHeader, QChar separator) { QFile src(filename); setSource(&src, withHeader, separator); } void QxtCsvModel::setSource(QIODevice *file, bool withHeader, QChar separator) { QxtCsvModelPrivate* d_ptr = &qxt_d(); QString l; int size; bool isQuoted, headerSet = false; if(!file->isOpen()) file->open(QIODevice::ReadOnly); if(withHeader) d_ptr->maxColumn = 0; else d_ptr->maxColumn = d_ptr->header.size(); d_ptr->csvData.clear(); while(!file->atEnd()) { l = file->readLine(); l.replace(QChar('\n'),""); l.replace(QChar('\r'),""); size = l.length(); isQuoted = false; for(int i=0;i0) { if(l[i]=='"' && l[i-1]!='\\') isQuoted=!isQuoted; else if(!isQuoted && l[i]==separator) l[i]=QChar(1); } else { if(l[i]=='"') isQuoted=!isQuoted; else if(!isQuoted && l[i]==separator) l[i]=QChar(1); } } if(l.count(QChar(1))+1 > d_ptr->maxColumn) d_ptr->maxColumn = l.count(QChar(1))+1; if(withHeader && !headerSet) { d_ptr->header = l.split(QChar(1)); headerSet=true; } else d_ptr->csvData.append(l); } file->close(); } void QxtCsvModel::setHeaderData(const QStringList data) { qxt_d().header = data; emit headerDataChanged(Qt::Horizontal, 0, data.count()); } bool QxtCsvModel::setData(const QModelIndex& index, const QVariant& data, int role) { if(index.parent()!=QModelIndex()) return false; QString before, after; if(role==Qt::DisplayRole || role==Qt::EditRole || role==Qt::UserRole) { if(index.row()>=rowCount() || index.column()>=columnCount() || index.row()<0 || index.column()<0) return false; if(index.column()!=0) before = qxt_d().csvData[index.row()].section(QChar(1),0,index.column()-1) + QChar(1); else before = ""; after = qxt_d().csvData[index.row()].section(QChar(1),index.column()+1); qxt_d().csvData[index.row()] = before + data.toString() + QChar(1) + after; emit dataChanged(index, index); return true; } else { return false; } } bool QxtCsvModel::insertRow(int row, const QModelIndex& parent) { return insertRows(row, 1, parent); } bool QxtCsvModel::insertRows(int row, int count, const QModelIndex& parent) { if(parent!=QModelIndex() || row<0) return false; emit beginInsertRows(parent, row, row+count); QxtCsvModelPrivate* d_ptr = qxt_d(); if(row>=rowCount()) { for(int i=0;icsvData << ""; } else { for(int i=0;icsvData.insert(row, ""); } emit endInsertRows(); return true; } bool QxtCsvModel::removeRow(int row, const QModelIndex& parent) { return removeRows(row, 1, parent); } bool QxtCsvModel::removeRows(int row, int count, const QModelIndex& parent) { if(parent!=QModelIndex() || row<0) return false; if(row>=rowCount()) return false; if(row+count>=rowCount()) count = rowCount()-row; emit beginRemoveRows(parent, row, row+count); QxtCsvModelPrivate* d_ptr = qxt_d(); for(int i=0;icsvData.removeAt(row); emit endRemoveRows(); return true; } bool QxtCsvModel::insertColumn(int col, const QModelIndex& parent) { return insertColumns(col, 1, parent); } bool QxtCsvModel::insertColumns(int col, int count, const QModelIndex& parent) { if(parent!=QModelIndex() || col<0) return false; emit beginInsertColumns(parent, col, col+count); QxtCsvModelPrivate* d_ptr = qxt_d(); if(col0) before = d_ptr->csvData[i].section(QChar(1),0,col-1)+QChar(1); else before = ""; after = d_ptr->csvData[i].section(QChar(1),col); d_ptr->csvData[i] = before + QString(count, QChar(1)) + after; } } for(int i=0;iheader.insert(col,""); d_ptr->maxColumn+=count; emit endInsertColumns(); return true; } bool QxtCsvModel::removeColumn(int col, const QModelIndex& parent) { return removeColumns(col, 1, parent); } bool QxtCsvModel::removeColumns(int col, int count, const QModelIndex& parent) { if(parent!=QModelIndex() || col<0) return false; if(col>=columnCount()) return false; if(col+count>=columnCount()) count = columnCount()-col; emit beginRemoveColumns(parent, col, col+count); QxtCsvModelPrivate* d_ptr = qxt_d(); QString before, after; for(int i=0;i0) before = d_ptr->csvData[i].section(QChar(1),0,col-1)+QChar(1); else before = ""; after = d_ptr->csvData[i].section(QChar(1),col+count); d_ptr->csvData[i] = before + after; } for(int i=0;iheader.removeAt(col); emit endRemoveColumns(); return true; } void QxtCsvModel::toCSV(QIODevice* dest, bool withHeader, QChar separator) { QxtCsvModelPrivate* d_ptr = qxt_d(); int row, col, rows, cols; rows = rowCount(); cols = columnCount(); QString data; if(!dest->isOpen()) dest->open(QIODevice::WriteOnly | QIODevice::Truncate); if(withHeader) { data = ""; for(col = 0; col < cols; col++) { data += '"' + d_ptr->header.at(col) + '"'; if(colwrite(data.toLatin1()); } for(row = 0; row < rows; row++) { data = ""; for(col = 0; col < cols; col++) { data += '"' + d_ptr->csvData[row].section(QChar(1),col,col) + '"'; if(colwrite(data.toLatin1()); } dest->close(); } void QxtCsvModel::toCSV(const QString filename, bool withHeader, QChar separator) { QFile dest(filename); toCSV(&dest, withHeader, separator); } Qt::ItemFlags QxtCsvModel::flags(const QModelIndex& index) const { return Qt::ItemIsEditable | QAbstractTableModel::flags(index); }