Ok, the long awaited config wizard is here (at least in a very basic state). There...
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / core / qxtcsvmodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
4 **
5 ** This file is part of the QxtCore module of the Qt eXTension library
6 **
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
9 ** IBM.
10 **
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.
15 **
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.
20 **
21 ** <http://libqxt.sourceforge.net>  <foundation@libqxt.org>
22 **
23 ****************************************************************************/
24
25 /*!
26 \class QxtCsvModel QxtCsvModel
27 \ingroup QxtCore
28 \brief Provides a QAbstractTableModel for CSV Files
29  */
30
31 /*!
32 \fn QxtCsvModel::QxtCsvModel(QObject *parent = 0);
33 default Constructor
34 */
35
36 /*!
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' ';'
41 */
42
43 /*!
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' ';'
48 */
49
50 /*!
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' ';'
55 */
56
57
58 /*!
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' ';'
63 */
64
65
66
67 /*!
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' ';'
72 */
73
74
75 /*!
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' ';'
80 */
81
82
83
84 #include "qxtcsvmodel.h"
85 #include <QFile>
86 #include <QDebug>
87
88 class QxtCsvModelPrivate : public QxtPrivate<QxtCsvModel>
89 {
90 public:
91     QxtCsvModelPrivate() : csvData(), header(), maxColumn(0)
92     {}
93     QXT_DECLARE_PUBLIC(QxtCsvModel);
94
95     QStringList csvData;
96     QStringList header;
97     int maxColumn;
98 };
99
100 QxtCsvModel::QxtCsvModel(QObject *parent) : QAbstractTableModel(parent)
101 {
102     QXT_INIT_PRIVATE(QxtCsvModel);
103 }
104
105 QxtCsvModel::QxtCsvModel(QIODevice *file, QObject *parent, bool withHeader, QChar separator) : QAbstractTableModel(parent)
106 {
107     QXT_INIT_PRIVATE(QxtCsvModel);
108     setSource(file, withHeader, separator);
109 }
110
111 QxtCsvModel::QxtCsvModel(const QString filename, QObject *parent, bool withHeader, QChar separator) : QAbstractTableModel(parent)
112 {
113     QXT_INIT_PRIVATE(QxtCsvModel);
114     QFile src(filename);
115     setSource(&src, withHeader, separator);
116 }
117
118 QxtCsvModel::~QxtCsvModel()
119 {}
120
121 int QxtCsvModel::rowCount(const QModelIndex& parent) const
122 {
123     if (parent.row()!=-1 && parent.column()!=-1) return 0;
124     return qxt_d().csvData.count();
125 }
126
127 int QxtCsvModel::columnCount(const QModelIndex& parent) const
128 {
129     if (parent.row()!=-1 && parent.column()!=-1) return 0;
130     return qxt_d().maxColumn;
131 }
132
133 QVariant QxtCsvModel::data(const QModelIndex& index, int role) const
134 {
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());
138     else
139     {
140         //QVariant v;
141         return QVariant();
142     }
143 }
144
145 QVariant QxtCsvModel::headerData(int section, Qt::Orientation orientation, int role) const
146 {
147     if (section < qxt_d().header.count() && orientation==Qt::Horizontal && (role==Qt::DisplayRole || role==Qt::EditRole || role==Qt::UserRole))
148     {
149         return qxt_d().header[section];
150     }
151     else
152         return QAbstractTableModel::headerData(section, orientation, role);
153 }
154
155 void QxtCsvModel::setSource(const QString filename, bool withHeader, QChar separator)
156 {
157     QFile src(filename);
158     setSource(&src, withHeader, separator);
159 }
160
161 void QxtCsvModel::setSource(QIODevice *file, bool withHeader, QChar separator)
162 {
163     QxtCsvModelPrivate* d_ptr = &qxt_d();
164     QString l;
165     int size;
166     bool isQuoted, headerSet = false;
167     if (!file->isOpen()) file->open(QIODevice::ReadOnly);
168     if (withHeader)
169         d_ptr->maxColumn = 0;
170     else
171         d_ptr->maxColumn = d_ptr->header.size();
172     d_ptr->csvData.clear();
173     while (!file->atEnd())
174     {
175         l = file->readLine();
176         l.replace(QChar('\n'),"");
177         l.replace(QChar('\r'),"");
178         size = l.length();
179         isQuoted = false;
180         for (int i=0;i<size;i++)
181         {
182             if (i>0)
183             {
184                 if (l[i]=='"' && l[i-1]!='\\') isQuoted=!isQuoted;
185                 else if (!isQuoted && l[i]==separator) l[i]=QChar(1);
186             }
187             else
188             {
189                 if (l[i]=='"') isQuoted=!isQuoted;
190                 else if (!isQuoted && l[i]==separator) l[i]=QChar(1);
191             }
192         }
193         if (l.count(QChar(1))+1 > d_ptr->maxColumn) d_ptr->maxColumn = l.count(QChar(1))+1;
194         if (withHeader && !headerSet)
195         {
196             d_ptr->header = l.split(QChar(1));
197             headerSet=true;
198         }
199         else
200             d_ptr->csvData.append(l);
201     }
202     file->close();
203 }
204
205 void QxtCsvModel::setHeaderData(const QStringList data)
206 {
207     qxt_d().header = data;
208     emit headerDataChanged(Qt::Horizontal, 0, data.count());
209 }
210
211 bool QxtCsvModel::setData(const QModelIndex& index, const QVariant& data, int role)
212 {
213     if (index.parent()!=QModelIndex()) return false;
214
215     QString before, after;
216     if (role==Qt::DisplayRole || role==Qt::EditRole || role==Qt::UserRole)
217     {
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);
221         else
222             before = "";
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);
226         return true;
227     }
228     else
229     {
230         return false;
231     }
232 }
233
234 bool QxtCsvModel::insertRow(int row, const QModelIndex& parent)
235 {
236     return insertRows(row, 1, parent);
237 }
238
239 bool QxtCsvModel::insertRows(int row, int count, const QModelIndex& parent)
240 {
241     if (parent!=QModelIndex() || row<0) return false;
242     emit beginInsertRows(parent, row, row+count);
243     QxtCsvModelPrivate& d_ptr = qxt_d();
244     if (row>=rowCount())
245     {
246         for (int i=0;i<count;i++) d_ptr.csvData << "";
247     }
248     else
249     {
250         for (int i=0;i<count;i++) d_ptr.csvData.insert(row, "");
251     }
252     emit endInsertRows();
253     return true;
254 }
255
256 bool QxtCsvModel::removeRow(int row, const QModelIndex& parent)
257 {
258     return removeRows(row, 1, parent);
259 }
260
261 bool QxtCsvModel::removeRows(int row, int count, const QModelIndex& parent)
262 {
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();
271     return true;
272 }
273
274 bool QxtCsvModel::insertColumn(int col, const QModelIndex& parent)
275 {
276     return insertColumns(col, 1, parent);
277 }
278
279 bool QxtCsvModel::insertColumns(int col, int count, const QModelIndex& parent)
280 {
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())
285     {
286         QString before, after;
287         for (int i=0;i<rowCount();i++)
288         {
289             if (col>0)
290                 before = d_ptr.csvData[i].section(QChar(1),0,col-1)+QChar(1);
291             else
292                 before = "";
293             after = d_ptr.csvData[i].section(QChar(1),col);
294             d_ptr.csvData[i] = before + QString(count, QChar(1)) + after;
295         }
296     }
297     for (int i=0;i<count;i++)
298         d_ptr.header.insert(col,"");
299     d_ptr.maxColumn+=count;
300     emit endInsertColumns();
301     return true;
302 }
303
304 bool QxtCsvModel::removeColumn(int col, const QModelIndex& parent)
305 {
306     return removeColumns(col, 1, parent);
307 }
308
309 bool QxtCsvModel::removeColumns(int col, int count, const QModelIndex& parent)
310 {
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++)
318     {
319         if (col>0)
320             before = d_ptr.csvData[i].section(QChar(1),0,col-1)+QChar(1);
321         else
322             before = "";
323         after = d_ptr.csvData[i].section(QChar(1),col+count);
324         d_ptr.csvData[i] = before + after;
325     }
326     for (int i=0;i<count;i++)
327         d_ptr.header.removeAt(col);
328     emit endRemoveColumns();
329     return true;
330 }
331
332
333 void QxtCsvModel::toCSV(QIODevice* dest, bool withHeader, QChar separator)
334 {
335     QxtCsvModelPrivate& d_ptr = qxt_d();
336     int row, col, rows, cols;
337     rows = rowCount();
338     cols = columnCount();
339     QString data;
340     if (!dest->isOpen()) dest->open(QIODevice::WriteOnly | QIODevice::Truncate);
341     if (withHeader)
342     {
343         data = "";
344         for (col = 0; col < cols; col++)
345         {
346             data += '"' + d_ptr.header.at(col) + '"';
347             if (col<cols-1) data += separator;
348         }
349         data += QChar(10);
350         dest->write(data.toLatin1());
351     }
352     for (row = 0; row < rows; row++)
353     {
354         data = "";
355         for (col = 0; col < cols; col++)
356         {
357             data += '"' + d_ptr.csvData[row].section(QChar(1),col,col) + '"';
358             if (col<cols-1) data += separator;
359         }
360         data += QChar(10);
361         dest->write(data.toLatin1());
362     }
363     dest->close();
364 }
365
366 void QxtCsvModel::toCSV(const QString filename, bool withHeader, QChar separator)
367 {
368     QFile dest(filename);
369     toCSV(&dest, withHeader, separator);
370 }
371
372 Qt::ItemFlags QxtCsvModel::flags(const QModelIndex& index) const
373 {
374     return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
375 }