--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) Qxt Foundation. Some rights reserved.
+**
+** This file is part of the QxtCore module of the Qt eXTension library
+**
+** This library is free software; you can redistribute it and/or modify it
+** under the terms of th Common Public License, version 1.0, as published by
+** IBM.
+**
+** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
+** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
+** FITNESS FOR A PARTICULAR PURPOSE.
+**
+** You should have received a copy of the CPL along with this file.
+** See the LICENSE file and the cpl1.0.txt file included with the source
+** distribution for more information. If you did not receive a copy of the
+** license, contact the Qxt Foundation.
+**
+** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
+**
+****************************************************************************/
+
+/*!
+\class QxtCsvModel QxtCsvModel
+\ingroup QxtCore
+\brief Provides a QAbstractTableModel for CSV Files
+ */
+
+/*!
+\fn QxtCsvModel::QxtCsvModel(QObject *parent = 0);
+default Constructor
+*/
+
+/*!
+\fn QxtCsvModel::QxtCsvModel(QIODevice *file, QObject *parent=0, bool withHeader = false, QChar separator= ',')
+constructs a QxtCsvModel from a QIODevice as source \n
+\p withHeader specifies if the data on the device contains a header or not.
+\p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
+*/
+
+/*!
+\fn QxtCsvModel::QxtCsvModel(const QString filename, QObject *parent = 0, bool withHeader = false, QChar separator = ',')
+constructs a QxtCsvModel from a filename as source \n
+\p withHeader specifies if the data in the file contains a header or not.
+\p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
+*/
+
+/*!
+\fn void QxtCsvModel::setSource(QIODevice *file, bool withHeader = false, QChar separator = ',');
+reads the cvs data from \p file
+\p withHeader specifies if the data on the device contains a header or not.
+\p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
+*/
+
+
+/*!
+\fn void QxtCsvModel::setSource(const QString filename, bool withHeader = false, QChar separator = ',');
+reads the cvs data from \p filename
+\p withHeader specifies if the data in the file contains a header or not.
+\p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
+*/
+
+
+
+/*!
+\fn void QxtCsvModel::toCSV(QIODevice *file, bool withHeader = false, QChar separator = ',');
+writes the cvs data to \p file
+\p withHeader specifies if to write the header or not
+\p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
+*/
+
+
+/*!
+\fn void QxtCsvModel::toCSV(const QString filename, bool withHeader = false, QChar separator = ',');
+writes the cvs data to \p filename
+\p withHeader specifies if to write the header or not
+\p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
+*/
+
+
+
+#include "qxtcsvmodel.h"
+#include <QFile>
+#include <QDebug>
+
+class QxtCsvModelPrivate : public QxtPrivate<QxtCsvModel>
+{
+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;i<size;i++)
+ {
+ if (i>0)
+ {
+ 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;i<count;i++) d_ptr.csvData << "";
+ }
+ else
+ {
+ for (int i=0;i<count;i++) d_ptr.csvData.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;i<count;i++)
+ d_ptr.csvData.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 (col<columnCount())
+ {
+ QString before, after;
+ for (int i=0;i<rowCount();i++)
+ {
+ if (col>0)
+ 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;i<count;i++)
+ d_ptr.header.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;i<rowCount();i++)
+ {
+ if (col>0)
+ 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;i<count;i++)
+ d_ptr.header.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 (col<cols-1) data += separator;
+ }
+ data += QChar(10);
+ dest->write(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 (col<cols-1) data += separator;
+ }
+ data += QChar(10);
+ dest->write(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);
+}