Page MenuHomePhabricator (Chris)

No OneTemporary

Size
34 KB
Referenced Files
None
Subscribers
None
diff --git a/dialogs/uploaddialog.cpp b/dialogs/uploaddialog.cpp
new file mode 100644
index 0000000..034e76d
--- /dev/null
+++ b/dialogs/uploaddialog.cpp
@@ -0,0 +1,219 @@
+#include "uploaddialog.h"
+#include "ui_uploaddialog.h"
+
+#include "../tools/os.h"
+#include "../tools/qxtcsvmodel.h"
+#include "../tools/uploader.h"
+#include "../tools/screenshotmanager.h"
+
+#include <QMessageBox>
+#include <QFile>
+#include <QDesktopServices>
+#include <QFileSystemWatcher>
+#include <QUrl>
+#include <QMenu>
+#include <QFileInfo>
+#include <QClipboard>
+#include <QDir>
+#include <QSortFilterProxyModel>
+#include <QDebug>
+
+UploadDialog::UploadDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::UploadDialog)
+{
+ ui->setupUi(this);
+
+ if (os::aeroGlass(this)) {
+ layout()->setMargin(2);
+ }
+
+ ui->filterEdit->setText(tr("Filter.."));
+ ui->filterEdit->installEventFilter(this);
+
+ QFile historyFile(ScreenshotManager::instance()->historyPath());
+
+ if (!historyFile.exists())
+ {
+ ui->tableView->setEnabled(false);
+ return;
+ }
+
+ QFileSystemWatcher *watcher = new QFileSystemWatcher(QStringList() << historyFile.fileName(), this);
+ connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(reloadHistory()));
+
+ reloadHistory();
+
+ ui->tableView->setTextElideMode(Qt::ElideLeft);
+ ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ ui->tableView->setAlternatingRowColors(true);
+ ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
+ ui->tableView->setSortingEnabled(true);
+
+ if (ui->tableView->model()->rowCount() > 0)
+ {
+ ui->clearButton->setEnabled(true);
+ ui->filterEdit->setEnabled(true);
+ }
+
+ connect(ui->uploadButton, SIGNAL(clicked()), this, SLOT(upload()));
+ connect(ui->clearButton , SIGNAL(clicked()), this, SLOT(clear()));
+ connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
+ connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(open(QModelIndex)));
+ connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenu(QPoint)));
+
+}
+
+UploadDialog::~UploadDialog()
+{
+ delete ui;
+}
+
+void UploadDialog::contextMenu(QPoint point)
+{
+ mContextIndex = ui->tableView->indexAt(point);;
+
+ QMenu contextMenu(ui->tableView);
+
+ QAction copyAction((mContextIndex.column() == 0) ? tr("Copy Path") : tr("Copy URL"), &contextMenu);
+ connect(&copyAction, SIGNAL(triggered()), this, SLOT(copy()));
+ contextMenu.addAction(&copyAction);
+
+ QAction locationAction(tr("Open Location"), &contextMenu);
+
+ if (mContextIndex.column() == 0)
+ {
+ connect(&locationAction, SIGNAL(triggered()), this, SLOT(location()));
+ contextMenu.addAction(&locationAction);
+ }
+ else if (mContextIndex.data().toString() == QObject::tr("- not uploaded -")) {
+ copyAction.setEnabled(false);
+ }
+
+ contextMenu.exec(QCursor::pos());
+}
+
+void UploadDialog::copy()
+{
+ qApp->clipboard()->setText(mContextIndex.data().toString());
+}
+
+void UploadDialog::location()
+{
+ QDesktopServices::openUrl("file:///" + QFileInfo(mContextIndex.data().toString()).absolutePath());
+}
+
+void UploadDialog::selectionChanged(QItemSelection selected, QItemSelection deselected)
+{
+ Q_UNUSED(deselected);
+
+ QModelIndex index = selected.indexes().at(0);
+
+ QString screenshot, url;
+
+ if (index.column() == 0) {
+ screenshot = index.data().toString();
+ url = ui->tableView->model()->index(index.row(), 1).data().toString();
+ }
+ else {
+ screenshot = ui->tableView->model()->index(index.row(), 0).data().toString();
+ url = index.data().toString();
+ }
+
+ mSelectedScreenshot = screenshot;
+
+ ui->uploadButton->setEnabled((url == QObject::tr("- not uploaded -") && QFile::exists(screenshot)));
+}
+
+void UploadDialog::open(QModelIndex index)
+{
+ if (index.column() == 0) {
+ QDesktopServices::openUrl(QUrl("file:///" + index.data().toString()));
+ }
+ else {
+ QDesktopServices::openUrl(index.data().toUrl());
+ }
+}
+
+void UploadDialog::reloadHistory()
+{
+ if (ui->tableView->model()) {
+ ui->tableView->model()->deleteLater();
+ }
+
+ QFile historyFile(ScreenshotManager::instance()->historyPath());
+
+ QxtCsvModel *model = new QxtCsvModel(&historyFile, this, false, '|');
+ model->setHeaderData(QStringList() << tr("Screenshot") << tr("URL"));
+
+ mFilterModel = new QSortFilterProxyModel(model);
+ mFilterModel->setSourceModel(model);
+ mFilterModel->setDynamicSortFilter(true);
+
+ ui->tableView->setModel(mFilterModel);
+
+ ui->tableView->horizontalHeader()->setClickable(false);
+ ui->tableView->horizontalHeader()->setMovable(false);
+
+ ui->tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);
+ ui->tableView->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents);
+
+ ui->tableView->verticalHeader()->hide();
+
+ ui->tableView->scrollToBottom();
+}
+
+void UploadDialog::upload()
+{
+ Uploader::instance()->upload(mSelectedScreenshot);
+ ui->uploadButton->setEnabled(false);
+}
+
+void UploadDialog::clear()
+{
+ if (QMessageBox::question(this,
+ tr("Clearing the screenshot history"),
+ tr("Are you sure you want to clear your entire screenshot history?\nThis cannot be undone."),
+ tr("Clear History"),
+ tr("Don't Clear")) == 1) {
+ return;
+ }
+
+ QFile::remove(ScreenshotManager::instance()->historyPath());
+
+ ui->tableView->model()->deleteLater();
+ ui->tableView->setEnabled(false);
+ ui->clearButton->setEnabled(false);
+}
+
+bool UploadDialog::eventFilter(QObject *object, QEvent *event)
+{
+ if (object == ui->filterEdit) {
+ if (event->type() == QEvent::FocusIn)
+ {
+ if (ui->filterEdit->text() == tr("Filter..")) {
+ ui->filterEdit->setStyleSheet("");
+ ui->filterEdit->setText("");
+ mFilterModel->setFilterWildcard("");
+ }
+ }
+ else if (event->type() == QEvent::FocusOut)
+ {
+ if (ui->filterEdit->text() == "") {
+ ui->filterEdit->setStyleSheet("color: palette(mid);");
+ ui->filterEdit->setText(tr("Filter.."));
+ }
+ }
+ else if (event->type() == QEvent::KeyRelease)
+ {
+ if (ui->filterEdit->text() != tr("Filter..") && !ui->filterEdit->text().isEmpty()) {
+ mFilterModel->setFilterWildcard(ui->filterEdit->text());
+ }
+ else {
+ mFilterModel->setFilterWildcard("");
+ }
+ }
+ }
+ return QDialog::eventFilter(object, event);
+}
diff --git a/dialogs/uploaddialog.h b/dialogs/uploaddialog.h
new file mode 100644
index 0000000..2e372ee
--- /dev/null
+++ b/dialogs/uploaddialog.h
@@ -0,0 +1,41 @@
+#ifndef UPLOADDIALOG_H
+#define UPLOADDIALOG_H
+
+#include <QDialog>
+#include <QItemSelection>
+
+
+namespace Ui {
+ class UploadDialog;
+}
+
+class QSortFilterProxyModel;
+class UploadDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit UploadDialog(QWidget *parent = 0);
+ ~UploadDialog();
+
+private slots:
+ void copy();
+ void location();
+ void contextMenu(QPoint point);
+ void selectionChanged(QItemSelection selected, QItemSelection deselected);
+ void open(QModelIndex index);
+ void reloadHistory();
+ void upload();
+ void clear();
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event);
+
+private:
+ Ui::UploadDialog *ui;
+ QSortFilterProxyModel *mFilterModel;
+ QString mSelectedScreenshot;
+ QModelIndex mContextIndex;
+};
+
+#endif // UPLOADDIALOG_H
diff --git a/dialogs/uploaddialog.ui b/dialogs/uploaddialog.ui
new file mode 100644
index 0000000..5edf09a
--- /dev/null
+++ b/dialogs/uploaddialog.ui
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UploadDialog</class>
+ <widget class="QDialog" name="UploadDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>327</width>
+ <height>252</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Screenshot History</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="../lightscreen.qrc">
+ <normaloff>:/icons/view-history</normaloff>:/icons/view-history</iconset>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QLineEdit" name="filterEdit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: palette(mid);</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTableView" name="tableView"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="clearButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="uploadButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Upload</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../lightscreen.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>closeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>UploadDialog</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>279</x>
+ <y>230</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>163</x>
+ <y>125</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tools/qxtcsvmodel.cpp b/tools/qxtcsvmodel.cpp
new file mode 100644
index 0000000..e61f539
--- /dev/null
+++ b/tools/qxtcsvmodel.cpp
@@ -0,0 +1,552 @@
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+/*!
+\class QxtCsvModel
+\inmodule QxtCore
+\brief The QxtCsvModel class provides a QAbstractTableModel for CSV Files
+ */
+
+
+
+#include "qxtcsvmodel.h"
+#include <QFile>
+#include <QTextStream>
+#include <QDebug>
+
+class QxtCsvModelPrivate : public QxtPrivate<QxtCsvModel>
+{
+public:
+ QxtCsvModelPrivate() : csvData(), header(), maxColumn(0), quoteMode(QxtCsvModel::DefaultQuoteMode)
+ {}
+ friend class QxtCsvModel;
+
+ QList<QStringList> csvData;
+ QStringList header;
+ int maxColumn;
+ QxtCsvModel::QuoteMode quoteMode;
+};
+
+/*!
+ Creates an empty QxtCsvModel with parent \a parent.
+ */
+QxtCsvModel::QxtCsvModel(QObject *parent) : QAbstractTableModel(parent)
+{
+ QXT_INIT_PRIVATE(QxtCsvModel);
+}
+
+/*!
+ Creates a QxtCsvModel with the parent \a parent and content loaded from \a file.
+
+ See \a setSource for information on the \a withHeader and \a separator properties, or
+ if you need control over the quoting method or codec used to parse the file.
+
+ \sa setSource
+ */
+QxtCsvModel::QxtCsvModel(QIODevice *file, QObject *parent, bool withHeader, QChar separator) : QAbstractTableModel(parent)
+{
+ QXT_INIT_PRIVATE(QxtCsvModel);
+ setSource(file, withHeader, separator);
+}
+
+/*!
+ \overload
+
+ Creates a QxtCsvModel with the parent \a parent and content loaded from \a file.
+
+ See \a setSource for information on the \a withHeader and \a separator properties, or
+ if you need control over the quoting method or codec used to parse the file.
+
+ \sa setSource
+ */
+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()
+{}
+
+/*!
+ \reimp
+ */
+int QxtCsvModel::rowCount(const QModelIndex& parent) const
+{
+ if (parent.row() != -1 && parent.column() != -1) return 0;
+ return qxt_d().csvData.count();
+}
+
+/*!
+ \reimp
+ */
+int QxtCsvModel::columnCount(const QModelIndex& parent) const
+{
+ if (parent.row() != -1 && parent.column() != -1) return 0;
+ return qxt_d().maxColumn;
+}
+
+/*!
+ \reimp
+ */
+QVariant QxtCsvModel::data(const QModelIndex& index, int role) const
+{
+ if(index.parent() != QModelIndex()) return QVariant();
+ if(role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole || role == Qt::UserRole) {
+ if(index.row() < 0 || index.column() < 0 || index.row() >= rowCount())
+ return QVariant();
+ const QStringList& row = qxt_d().csvData[index.row()];
+ if(index.column() >= row.length())
+ return QVariant();
+ return row[index.column()];
+ }
+ return QVariant();
+}
+
+/*!
+ \reimp
+ */
+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);
+}
+
+/*!
+ \overload
+
+ Reads in a CSV file from the provided \a file using \a codec.
+ */
+void QxtCsvModel::setSource(const QString filename, bool withHeader, QChar separator, QTextCodec* codec)
+{
+ QFile src(filename);
+ setSource(&src, withHeader, separator, codec);
+}
+
+/*!
+ Reads in a CSV file from the provided \a file using \a codec.
+
+ The value of \a separator will be used to delimit fields, subject to the specified \a quoteMode.
+ If \a withHeader is set to true, the first line of the file will be used to populate the model's
+ horizontal header.
+
+ \sa quoteMode
+ */
+void QxtCsvModel::setSource(QIODevice *file, bool withHeader, QChar separator, QTextCodec* codec)
+{
+ QxtCsvModelPrivate* d_ptr = &qxt_d();
+ bool headerSet = !withHeader;
+ 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();
+ QStringList row;
+ QString field;
+ QChar quote;
+ QChar ch, buffer(0);
+ bool readCR = false;
+ QTextStream stream(file);
+ if(codec) {
+ stream.setCodec(codec);
+ } else {
+ stream.setAutoDetectUnicode(true);
+ }
+ while(!stream.atEnd()) {
+ if(buffer != QChar(0)) {
+ ch = buffer;
+ buffer = QChar(0);
+ } else {
+ stream >> ch;
+ }
+ if(ch == '\n' && readCR)
+ continue;
+ else if(ch == '\r')
+ readCR = true;
+ else
+ readCR = false;
+ if(ch != separator && (ch.category() == QChar::Separator_Line || ch.category() == QChar::Separator_Paragraph || ch.category() == QChar::Other_Control)) {
+ row << field;
+ field.clear();
+ if(!row.isEmpty()) {
+ if(!headerSet) {
+ d_ptr->header = row;
+ headerSet = true;
+ } else {
+ d_ptr->csvData.append(row);
+ }
+ if(row.length() > d_ptr->maxColumn) {
+ d_ptr->maxColumn = row.length();
+ }
+ }
+ row.clear();
+ } else if((d_ptr->quoteMode & DoubleQuote && ch == '"') || (d_ptr->quoteMode & SingleQuote && ch == '\'')) {
+ quote = ch;
+ do {
+ stream >> ch;
+ if(ch == '\\' && d_ptr->quoteMode & BackslashEscape) {
+ stream >> ch;
+ } else if(ch == quote) {
+ if(d_ptr->quoteMode & TwoQuoteEscape) {
+ stream >> buffer;
+ if(buffer == quote) {
+ buffer = QChar(0);
+ field.append(ch);
+ continue;
+ }
+ }
+ break;
+ }
+ field.append(ch);
+ } while(!stream.atEnd());
+ } else if(ch == separator) {
+ row << field;
+ field.clear();
+ } else {
+ field.append(ch);
+ }
+ }
+ if(!field.isEmpty())
+ row << field;
+ if(!row.isEmpty()) {
+ if(!headerSet)
+ d_ptr->header = row;
+ else
+ d_ptr->csvData.append(row);
+ }
+ file->close();
+}
+
+/*!
+ Sets the horizontal headers of the model to the values provided in \a data.
+ */
+void QxtCsvModel::setHeaderData(const QStringList& data)
+{
+ qxt_d().header = data;
+ emit headerDataChanged(Qt::Horizontal, 0, data.count());
+}
+
+/*!
+ \reimp
+ */
+bool QxtCsvModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant& value, int role)
+{
+ if(orientation != Qt::Horizontal) return false; // We don't support the vertical header
+ if(role != Qt::DisplayRole || role != Qt::EditRole) return false; // We don't support any other roles
+ if(section < 0) return false; // Bogus input
+ while(section > qxt_d().header.size()) {
+ qxt_d().header << QString();
+ }
+ qxt_d().header[section] = value.toString();
+ emit headerDataChanged(Qt::Horizontal, section, section);
+ return true;
+}
+
+/*!
+ \reimp
+ */
+bool QxtCsvModel::setData(const QModelIndex& index, const QVariant& data, int role)
+{
+ if (index.parent() != QModelIndex()) return false;
+
+ 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;
+ QStringList& row = qxt_d().csvData[index.row()];
+ while(row.length() <= index.column())
+ row << QString();
+ row[index.column()] = data.toString();
+ emit dataChanged(index, index);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \reimp
+ */
+bool QxtCsvModel::insertRow(int row, const QModelIndex& parent)
+{
+ return insertRows(row, 1, parent);
+}
+
+/*!
+ \reimp
+ */
+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 << QStringList();
+ } else {
+ for(int i = 0; i < count; i++) d_ptr.csvData.insert(row, QStringList());
+ }
+ emit endInsertRows();
+ return true;
+}
+
+/*!
+ \reimp
+ */
+bool QxtCsvModel::removeRow(int row, const QModelIndex& parent)
+{
+ return removeRows(row, 1, parent);
+}
+
+/*!
+ \reimp
+ */
+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;
+}
+
+/*!
+ \reimp
+ */
+bool QxtCsvModel::insertColumn(int col, const QModelIndex& parent)
+{
+ return insertColumns(col, 1, parent);
+}
+
+/*!
+ \reimp
+ */
+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();
+ for(int i = 0; i < rowCount(); i++) {
+ QStringList& row = d_ptr.csvData[i];
+ while(col >= row.length()) row.append(QString());
+ for(int j = 0; j < count; j++) {
+ row.insert(col, QString());
+ }
+ }
+ for(int i = 0; i < count ;i++)
+ d_ptr.header.insert(col, QString());
+ d_ptr.maxColumn += count;
+ emit endInsertColumns();
+ return true;
+}
+
+/*!
+ \reimp
+ */
+bool QxtCsvModel::removeColumn(int col, const QModelIndex& parent)
+{
+ return removeColumns(col, 1, parent);
+}
+
+/*!
+ \reimp
+ */
+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++) {
+ for(int j = 0; j < count; j++) {
+ d_ptr.csvData[i].removeAt(col);
+ }
+ }
+ for(int i = 0; i < count; i++)
+ d_ptr.header.removeAt(col);
+ emit endRemoveColumns();
+ return true;
+}
+
+static QString qxt_addCsvQuotes(QxtCsvModel::QuoteMode mode, QString field)
+{
+ bool addDoubleQuotes = ((mode & QxtCsvModel::DoubleQuote) && field.contains('"'));
+ bool addSingleQuotes = ((mode & QxtCsvModel::SingleQuote) && field.contains('\''));
+ bool quoteField = (mode & QxtCsvModel::AlwaysQuoteOutput) || addDoubleQuotes || addSingleQuotes;
+ if(quoteField && !addDoubleQuotes && !addSingleQuotes) {
+ if(mode & QxtCsvModel::DoubleQuote)
+ addDoubleQuotes = true;
+ else if(mode & QxtCsvModel::SingleQuote)
+ addSingleQuotes = true;
+ }
+ if(mode & QxtCsvModel::BackslashEscape) {
+ if(addDoubleQuotes)
+ return '"' + field.replace("\\", "\\\\").replace("\"", "\\\"") + '"';
+ if(addSingleQuotes)
+ return '\'' + field.replace("\\", "\\\\").replace("'", "\\'") + '\'';
+ } else {
+ if(addDoubleQuotes)
+ return '"' + field.replace("\"", "\"\"") + '"';
+ if(addSingleQuotes)
+ return '\'' + field.replace("'", "''") + '\'';
+ }
+ return field;
+}
+
+/*!
+ Outputs the content of the model as a CSV file to the device \a dest using \a codec.
+
+ Fields in the output file will be separated by \a separator. Set \a withHeader to true
+ to output a row of headers at the top of the file.
+ */
+void QxtCsvModel::toCSV(QIODevice* dest, bool withHeader, QChar separator, QTextCodec* codec)
+{
+ 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);
+ QTextStream stream(dest);
+ if(codec) stream.setCodec(codec);
+ if(withHeader) {
+ data = "";
+ for(col = 0; col < cols; ++col) {
+ if(col > 0) data += separator;
+ data += qxt_addCsvQuotes(d_ptr.quoteMode, d_ptr.header.at(col));
+ }
+ stream << data << endl;
+ }
+ for(row = 0; row < rows; ++row)
+ {
+ const QStringList& rowData = d_ptr.csvData[row];
+ data = "";
+ for(col = 0; col < cols; ++col) {
+ if(col > 0) data += separator;
+ if(col < rowData.length())
+ data += qxt_addCsvQuotes(d_ptr.quoteMode, rowData.at(col));
+ else
+ data += qxt_addCsvQuotes(d_ptr.quoteMode, QString());;
+ }
+ stream << data << endl;
+ }
+ stream << flush;
+ dest->close();
+}
+
+/*!
+ \overload
+
+ Outputs the content of the model as a CSV file to the file specified by \a filename using \a codec.
+
+ Fields in the output file will be separated by \a separator. Set \a withHeader to true
+ to output a row of headers at the top of the file.
+ */
+void QxtCsvModel::toCSV(const QString filename, bool withHeader, QChar separator, QTextCodec* codec)
+{
+ QFile dest(filename);
+ toCSV(&dest, withHeader, separator, codec);
+}
+
+/*!
+ \reimp
+ */
+Qt::ItemFlags QxtCsvModel::flags(const QModelIndex& index) const
+{
+ return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
+}
+
+/*!
+ * Returns the current quoting mode.
+ * \sa setQuoteMode
+ */
+QxtCsvModel::QuoteMode QxtCsvModel::quoteMode() const
+{
+ return qxt_d().quoteMode;
+}
+
+/*!
+ * Sets the current quoting mode. The default quoting mode is BothQuotes | BackslashEscape.
+ *
+ * The quoting mode determines what kinds of quoting is used for reading and writing CSV files.
+ * \sa quoteMode
+ * \sa QuoteOption
+ */
+void QxtCsvModel::setQuoteMode(QuoteMode mode)
+{
+ qxt_d().quoteMode = mode;
+}
+
+/*!
+ Sets the content of the cell at row \a row and column \a column to \a value.
+
+ \sa text
+ */
+void QxtCsvModel::setText(int row, int column, const QString& value)
+{
+ setData(index(row, column), value);
+}
+
+/*!
+ Fetches the content of the cell at row \a row and column \a column.
+
+ \sa setText
+ */
+QString QxtCsvModel::text(int row, int column) const
+{
+ return data(index(row, column)).toString();
+}
+
+/*!
+ Sets the content of the header for column \a column to \a value.
+
+ \sa headerText
+ */
+void QxtCsvModel::setHeaderText(int column, const QString& value)
+{
+ setHeaderData(column, Qt::Horizontal, value);
+}
+
+/*!
+ Fetches the content of the cell at row \a row and column \a column.
+
+ \sa setText
+ */
+QString QxtCsvModel::headerText(int column) const
+{
+ return headerData(column, Qt::Horizontal).toString();
+}
diff --git a/tools/qxtcsvmodel.h b/tools/qxtcsvmodel.h
new file mode 100644
index 0000000..d3ad26f
--- /dev/null
+++ b/tools/qxtcsvmodel.h
@@ -0,0 +1,172 @@
+#ifndef QXTCSVMODEL_H
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#define QXTCSVMODEL_H
+
+#include <QAbstractTableModel>
+#include <QVariant>
+#include <QIODevice>
+#include <QChar>
+#include <QString>
+#include <QStringList>
+#include <QModelIndex>
+class QTextCodec;
+
+// From qxtglobal.h
+/****************************************************************************
+** This file is derived from code bearing the following notice:
+** The sole author of this file, Adam Higerd, has explicitly disclaimed all
+** copyright interest and protection for the content within. This file has
+** been placed in the public domain according to United States copyright
+** statute and case law. In jurisdictions where this public domain dedication
+** is not legally recognized, anyone who receives a copy of this file is
+** permitted to use, modify, duplicate, and redistribute this file, in whole
+** or in part, with no restrictions or conditions. In these jurisdictions,
+** this file shall be copyright (C) 2006-2008 by Adam Higerd.
+****************************************************************************/
+
+#define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface<PUB, PUB##Private> qxt_d;
+#define QXT_DECLARE_PUBLIC(PUB) friend class PUB;
+#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this);
+#define QXT_D(PUB) PUB##Private& d = qxt_d()
+#define QXT_P(PUB) PUB& p = qxt_p()
+
+template <typename PUB>
+class QxtPrivate
+{
+public:
+ virtual ~QxtPrivate()
+ {}
+ inline void QXT_setPublic(PUB* pub)
+ {
+ qxt_p_ptr = pub;
+ }
+
+protected:
+ inline PUB& qxt_p()
+ {
+ return *qxt_p_ptr;
+ }
+ inline const PUB& qxt_p() const
+ {
+ return *qxt_p_ptr;
+ }
+
+private:
+ PUB* qxt_p_ptr;
+};
+
+template <typename PUB, typename PVT>
+class QxtPrivateInterface
+{
+ friend class QxtPrivate<PUB>;
+public:
+ QxtPrivateInterface()
+ {
+ pvt = new PVT;
+ }
+ ~QxtPrivateInterface()
+ {
+ delete pvt;
+ }
+
+ inline void setPublic(PUB* pub)
+ {
+ pvt->QXT_setPublic(pub);
+ }
+ inline PVT& operator()()
+ {
+ return *static_cast<PVT*>(pvt);
+ }
+ inline const PVT& operator()() const
+ {
+ return *static_cast<PVT*>(pvt);
+ }
+private:
+ QxtPrivateInterface(const QxtPrivateInterface&) { }
+ QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
+ QxtPrivate<PUB>* pvt;
+};
+//
+
+class QxtCsvModelPrivate;
+class QxtCsvModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ QxtCsvModel(QObject *parent = 0);
+ explicit QxtCsvModel(QIODevice *file, QObject *parent = 0, bool withHeader = false, QChar separator = ',');
+ explicit QxtCsvModel(const QString filename, QObject *parent = 0, bool withHeader = false, QChar separator = ',');
+ ~QxtCsvModel();
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const;
+ int columnCount(const QModelIndex& parent = QModelIndex()) const;
+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex& index, const QVariant& data, int role = Qt::EditRole);
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ bool setHeaderData(int section, Qt::Orientation orientation, const QVariant& value, int role = Qt::DisplayRole);
+ void setHeaderData(const QStringList& data);
+ QString text(int row, int column) const;
+ void setText(int row, int column, const QString& value);
+ QString headerText(int column) const;
+ void setHeaderText(int column, const QString& value);
+
+
+ bool insertRow(int row, const QModelIndex& parent = QModelIndex());
+ bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex());
+ bool removeRow(int row, const QModelIndex& parent = QModelIndex());
+ bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex());
+ bool insertColumn(int col, const QModelIndex& parent = QModelIndex());
+ bool insertColumns(int col, int count, const QModelIndex& parent = QModelIndex());
+ bool removeColumn(int col, const QModelIndex& parent = QModelIndex());
+ bool removeColumns(int col, int count, const QModelIndex& parent = QModelIndex());
+
+ void setSource(QIODevice *file, bool withHeader = false, QChar separator = ',', QTextCodec* codec = 0);
+ void setSource(const QString filename, bool withHeader = false, QChar separator = ',', QTextCodec* codec = 0);
+
+ void toCSV(QIODevice *file, bool withHeader = false, QChar separator = ',', QTextCodec* codec = 0);
+ void toCSV(const QString filename, bool withHeader = false, QChar separator = ',', QTextCodec* codec = 0);
+
+ enum QuoteOption { NoQuotes = 0, SingleQuote = 1, DoubleQuote = 2, BothQuotes = 3,
+ NoEscape = 0, TwoQuoteEscape = 4, BackslashEscape = 8,
+ AlwaysQuoteOutput = 16, DefaultQuoteMode = BothQuotes | BackslashEscape | AlwaysQuoteOutput };
+ Q_DECLARE_FLAGS(QuoteMode, QuoteOption)
+ QuoteMode quoteMode() const;
+ void setQuoteMode(QuoteMode mode);
+
+ Qt::ItemFlags flags(const QModelIndex& index) const;
+
+private:
+ QXT_DECLARE_PRIVATE(QxtCsvModel)
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QxtCsvModel::QuoteMode)
+
+#endif

File Metadata

Mime Type
text/x-diff
Expires
Fri, Jan 30, 2:49 PM (5 d, 11 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55393
Default Alt Text
(34 KB)

Event Timeline