We now have a current svn snapshot of libqxt in our contrib dir, and
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / core / qxtcsvmodel.cpp
diff --git a/src/contrib/libqxt-2007-10-24/src/core/qxtcsvmodel.cpp b/src/contrib/libqxt-2007-10-24/src/core/qxtcsvmodel.cpp
new file mode 100644 (file)
index 0000000..99054a9
--- /dev/null
@@ -0,0 +1,375 @@
+/****************************************************************************
+**
+** 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);
+}