1 /****************************************************************************
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
5 ** This file is part of the QxtCore module of the Qt eXTension library
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
21 ** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
23 ****************************************************************************/
26 \class QxtCsvModel QxtCsvModel
28 \brief Provides a QAbstractTableModel for CSV Files
32 \fn QxtCsvModel::QxtCsvModel(QObject *parent = 0);
37 \fn QxtCsvModel::QxtCsvModel(QIODevice *file, QObject *parent=0, bool withHeader = false, QChar separator= ',')
38 constructs a QxtCsvModel from a QIODevice as source \n
39 \p withHeader specifies if the data on the device contains a header or not.
40 \p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
44 \fn QxtCsvModel::QxtCsvModel(const QString filename, QObject *parent = 0, bool withHeader = false, QChar separator = ',')
45 constructs a QxtCsvModel from a filename as source \n
46 \p withHeader specifies if the data in the file contains a header or not.
47 \p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
51 \fn void QxtCsvModel::setSource(QIODevice *file, bool withHeader = false, QChar separator = ',');
52 reads the cvs data from \p file
53 \p withHeader specifies if the data on the device contains a header or not.
54 \p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
59 \fn void QxtCsvModel::setSource(const QString filename, bool withHeader = false, QChar separator = ',');
60 reads the cvs data from \p filename
61 \p withHeader specifies if the data in the file contains a header or not.
62 \p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
68 \fn void QxtCsvModel::toCSV(QIODevice *file, bool withHeader = false, QChar separator = ',');
69 writes the cvs data to \p file
70 \p withHeader specifies if to write the header or not
71 \p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
76 \fn void QxtCsvModel::toCSV(const QString filename, bool withHeader = false, QChar separator = ',');
77 writes the cvs data to \p filename
78 \p withHeader specifies if to write the header or not
79 \p separator is the seperator to use for the columns. most widely used seperators are ',' '\\t' ';'
84 #include "qxtcsvmodel.h"
88 class QxtCsvModelPrivate : public QxtPrivate<QxtCsvModel>
91 QxtCsvModelPrivate() : csvData(), header(), maxColumn(0)
93 QXT_DECLARE_PUBLIC(QxtCsvModel);
100 QxtCsvModel::QxtCsvModel(QObject *parent) : QAbstractTableModel(parent)
102 QXT_INIT_PRIVATE(QxtCsvModel);
105 QxtCsvModel::QxtCsvModel(QIODevice *file, QObject *parent, bool withHeader, QChar separator) : QAbstractTableModel(parent)
107 QXT_INIT_PRIVATE(QxtCsvModel);
108 setSource(file, withHeader, separator);
111 QxtCsvModel::QxtCsvModel(const QString filename, QObject *parent, bool withHeader, QChar separator) : QAbstractTableModel(parent)
113 QXT_INIT_PRIVATE(QxtCsvModel);
115 setSource(&src, withHeader, separator);
118 QxtCsvModel::~QxtCsvModel()
121 int QxtCsvModel::rowCount(const QModelIndex& parent) const
123 if (parent.row()!=-1 && parent.column()!=-1) return 0;
124 return qxt_d().csvData.count();
127 int QxtCsvModel::columnCount(const QModelIndex& parent) const
129 if (parent.row()!=-1 && parent.column()!=-1) return 0;
130 return qxt_d().maxColumn;
133 QVariant QxtCsvModel::data(const QModelIndex& index, int role) const
135 if (index.parent()!=QModelIndex()) return QVariant();
136 if (role==Qt::DisplayRole || role==Qt::EditRole || role==Qt::UserRole)
137 return qxt_d().csvData[index.row()].section(QChar(1),index.column(),index.column());
145 QVariant QxtCsvModel::headerData(int section, Qt::Orientation orientation, int role) const
147 if (section < qxt_d().header.count() && orientation==Qt::Horizontal && (role==Qt::DisplayRole || role==Qt::EditRole || role==Qt::UserRole))
149 return qxt_d().header[section];
152 return QAbstractTableModel::headerData(section, orientation, role);
155 void QxtCsvModel::setSource(const QString filename, bool withHeader, QChar separator)
158 setSource(&src, withHeader, separator);
161 void QxtCsvModel::setSource(QIODevice *file, bool withHeader, QChar separator)
163 QxtCsvModelPrivate* d_ptr = &qxt_d();
166 bool isQuoted, headerSet = false;
167 if (!file->isOpen()) file->open(QIODevice::ReadOnly);
169 d_ptr->maxColumn = 0;
171 d_ptr->maxColumn = d_ptr->header.size();
172 d_ptr->csvData.clear();
173 while (!file->atEnd())
175 l = file->readLine();
176 l.replace(QChar('\n'),"");
177 l.replace(QChar('\r'),"");
180 for (int i=0;i<size;i++)
184 if (l[i]=='"' && l[i-1]!='\\') isQuoted=!isQuoted;
185 else if (!isQuoted && l[i]==separator) l[i]=QChar(1);
189 if (l[i]=='"') isQuoted=!isQuoted;
190 else if (!isQuoted && l[i]==separator) l[i]=QChar(1);
193 if (l.count(QChar(1))+1 > d_ptr->maxColumn) d_ptr->maxColumn = l.count(QChar(1))+1;
194 if (withHeader && !headerSet)
196 d_ptr->header = l.split(QChar(1));
200 d_ptr->csvData.append(l);
205 void QxtCsvModel::setHeaderData(const QStringList data)
207 qxt_d().header = data;
208 emit headerDataChanged(Qt::Horizontal, 0, data.count());
211 bool QxtCsvModel::setData(const QModelIndex& index, const QVariant& data, int role)
213 if (index.parent()!=QModelIndex()) return false;
215 QString before, after;
216 if (role==Qt::DisplayRole || role==Qt::EditRole || role==Qt::UserRole)
218 if (index.row()>=rowCount() || index.column()>=columnCount() || index.row()<0 || index.column()<0) return false;
219 if (index.column()!=0)
220 before = qxt_d().csvData[index.row()].section(QChar(1),0,index.column()-1) + QChar(1);
223 after = qxt_d().csvData[index.row()].section(QChar(1),index.column()+1);
224 qxt_d().csvData[index.row()] = before + data.toString() + QChar(1) + after;
225 emit dataChanged(index, index);
234 bool QxtCsvModel::insertRow(int row, const QModelIndex& parent)
236 return insertRows(row, 1, parent);
239 bool QxtCsvModel::insertRows(int row, int count, const QModelIndex& parent)
241 if (parent!=QModelIndex() || row<0) return false;
242 emit beginInsertRows(parent, row, row+count);
243 QxtCsvModelPrivate& d_ptr = qxt_d();
246 for (int i=0;i<count;i++) d_ptr.csvData << "";
250 for (int i=0;i<count;i++) d_ptr.csvData.insert(row, "");
252 emit endInsertRows();
256 bool QxtCsvModel::removeRow(int row, const QModelIndex& parent)
258 return removeRows(row, 1, parent);
261 bool QxtCsvModel::removeRows(int row, int count, const QModelIndex& parent)
263 if (parent!=QModelIndex() || row<0) return false;
264 if (row>=rowCount()) return false;
265 if (row+count>=rowCount()) count = rowCount()-row;
266 emit beginRemoveRows(parent, row, row+count);
267 QxtCsvModelPrivate& d_ptr = qxt_d();
268 for (int i=0;i<count;i++)
269 d_ptr.csvData.removeAt(row);
270 emit endRemoveRows();
274 bool QxtCsvModel::insertColumn(int col, const QModelIndex& parent)
276 return insertColumns(col, 1, parent);
279 bool QxtCsvModel::insertColumns(int col, int count, const QModelIndex& parent)
281 if (parent!=QModelIndex() || col<0) return false;
282 emit beginInsertColumns(parent, col, col+count);
283 QxtCsvModelPrivate& d_ptr = qxt_d();
284 if (col<columnCount())
286 QString before, after;
287 for (int i=0;i<rowCount();i++)
290 before = d_ptr.csvData[i].section(QChar(1),0,col-1)+QChar(1);
293 after = d_ptr.csvData[i].section(QChar(1),col);
294 d_ptr.csvData[i] = before + QString(count, QChar(1)) + after;
297 for (int i=0;i<count;i++)
298 d_ptr.header.insert(col,"");
299 d_ptr.maxColumn+=count;
300 emit endInsertColumns();
304 bool QxtCsvModel::removeColumn(int col, const QModelIndex& parent)
306 return removeColumns(col, 1, parent);
309 bool QxtCsvModel::removeColumns(int col, int count, const QModelIndex& parent)
311 if (parent!=QModelIndex() || col<0) return false;
312 if (col>=columnCount()) return false;
313 if (col+count>=columnCount()) count = columnCount()-col;
314 emit beginRemoveColumns(parent, col, col+count);
315 QxtCsvModelPrivate& d_ptr = qxt_d();
316 QString before, after;
317 for (int i=0;i<rowCount();i++)
320 before = d_ptr.csvData[i].section(QChar(1),0,col-1)+QChar(1);
323 after = d_ptr.csvData[i].section(QChar(1),col+count);
324 d_ptr.csvData[i] = before + after;
326 for (int i=0;i<count;i++)
327 d_ptr.header.removeAt(col);
328 emit endRemoveColumns();
333 void QxtCsvModel::toCSV(QIODevice* dest, bool withHeader, QChar separator)
335 QxtCsvModelPrivate& d_ptr = qxt_d();
336 int row, col, rows, cols;
338 cols = columnCount();
340 if (!dest->isOpen()) dest->open(QIODevice::WriteOnly | QIODevice::Truncate);
344 for (col = 0; col < cols; col++)
346 data += '"' + d_ptr.header.at(col) + '"';
347 if (col<cols-1) data += separator;
350 dest->write(data.toLatin1());
352 for (row = 0; row < rows; row++)
355 for (col = 0; col < cols; col++)
357 data += '"' + d_ptr.csvData[row].section(QChar(1),col,col) + '"';
358 if (col<cols-1) data += separator;
361 dest->write(data.toLatin1());
366 void QxtCsvModel::toCSV(const QString filename, bool withHeader, QChar separator)
368 QFile dest(filename);
369 toCSV(&dest, withHeader, separator);
372 Qt::ItemFlags QxtCsvModel::flags(const QModelIndex& index) const
374 return Qt::ItemIsEditable | QAbstractTableModel::flags(index);