Resolved issue #409. New feature: Export measurement file to Excel .csv.
--HG-- branch : develop
This commit is contained in:
parent
8e3f3a4cd8
commit
32d391c587
|
@ -24,6 +24,7 @@
|
|||
- [#472] Add 'Full Name' column to Formula dialog.
|
||||
- [#487] True dart point always goes to origin when the label is moved.
|
||||
- [#128] New Tool: Slash and Spread.
|
||||
- [#409] New feature: Export measurement file to Excel .csv.
|
||||
|
||||
# Version 0.4.5
|
||||
- [#435] Valentina doesn't change the cursor.
|
||||
|
|
|
@ -41,7 +41,7 @@ class DialogAboutTape : public QDialog
|
|||
|
||||
public:
|
||||
explicit DialogAboutTape(QWidget *parent = 0);
|
||||
~DialogAboutTape();
|
||||
virtual ~DialogAboutTape();
|
||||
|
||||
protected:
|
||||
virtual void changeEvent(QEvent* event) Q_DECL_OVERRIDE;
|
||||
|
|
154
src/app/tape/dialogs/dialogexporttocsv.cpp
Normal file
154
src/app/tape/dialogs/dialogexporttocsv.cpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
/************************************************************************
|
||||
**
|
||||
** @file dialogexporttocsv.cpp
|
||||
** @author Roman Telezhynskyi <dismine(at)gmail.com>
|
||||
** @date 1 6, 2016
|
||||
**
|
||||
** @brief
|
||||
** @copyright
|
||||
** This source code is part of the Valentine project, a pattern making
|
||||
** program, whose allow create and modeling patterns of clothing.
|
||||
** Copyright (C) 2016 Valentina project
|
||||
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
|
||||
**
|
||||
** Valentina is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Valentina is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
*************************************************************************/
|
||||
|
||||
#include "dialogexporttocsv.h"
|
||||
#include "ui_dialogexporttocsv.h"
|
||||
|
||||
#include "../vmisc/vtapesettings.h"
|
||||
#include "../mapplication.h"
|
||||
|
||||
#include <QShowEvent>
|
||||
#include <QTextCodec>
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
DialogExportToCSV::DialogExportToCSV(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::DialogExportToCSV),
|
||||
isInitialized(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->checkBoxWithHeader->setChecked(qApp->TapeSettings()->GetCSVWithHeader());
|
||||
|
||||
foreach (int mib, QTextCodec::availableMibs())
|
||||
{
|
||||
ui->comboBoxCodec->addItem(QTextCodec::codecForMib(mib)->name(), mib);
|
||||
}
|
||||
|
||||
ui->comboBoxCodec->setCurrentIndex(ui->comboBoxCodec->findData(qApp->TapeSettings()->GetCSVCodec()));
|
||||
|
||||
SetSeparator(qApp->TapeSettings()->GetCSVSeparator());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
DialogExportToCSV::~DialogExportToCSV()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
bool DialogExportToCSV::WithHeader() const
|
||||
{
|
||||
return ui->checkBoxWithHeader->isChecked();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
int DialogExportToCSV::SelectedMib() const
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
|
||||
return ui->comboBoxCodec->itemData(ui->comboBoxCodec->currentIndex()).toInt();
|
||||
#else
|
||||
return ui->comboBoxCodec->currentData().toInt();
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
QChar DialogExportToCSV::Separator() const
|
||||
{
|
||||
if (ui->radioButtonTab->isChecked())
|
||||
{
|
||||
return QChar('\t');
|
||||
}
|
||||
else if (ui->radioButtonSemicolon->isChecked())
|
||||
{
|
||||
return QChar(';');
|
||||
}
|
||||
else if (ui->radioButtonSpace->isChecked())
|
||||
{
|
||||
return QChar(' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
return QChar(',');
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void DialogExportToCSV::changeEvent(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::LanguageChange)
|
||||
{
|
||||
// retranslate designer form (single inheritance approach)
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
// remember to call base class implementation
|
||||
QDialog::changeEvent(event);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void DialogExportToCSV::showEvent(QShowEvent *event)
|
||||
{
|
||||
QDialog::showEvent( event );
|
||||
if ( event->spontaneous() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// do your init stuff here
|
||||
|
||||
setMaximumSize(size());
|
||||
setMinimumSize(size());
|
||||
|
||||
isInitialized = true;//first show windows are held
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void DialogExportToCSV::SetSeparator(const QChar &separator)
|
||||
{
|
||||
switch(separator.toLatin1())
|
||||
{
|
||||
case '\t':
|
||||
ui->radioButtonTab->setChecked(true);
|
||||
break;
|
||||
case ';':
|
||||
ui->radioButtonSemicolon->setChecked(true);
|
||||
break;
|
||||
case ' ':
|
||||
ui->radioButtonSpace->setChecked(true);
|
||||
break;
|
||||
case ',':
|
||||
default:
|
||||
ui->radioButtonComma->setChecked(true);
|
||||
break;
|
||||
}
|
||||
}
|
62
src/app/tape/dialogs/dialogexporttocsv.h
Normal file
62
src/app/tape/dialogs/dialogexporttocsv.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/************************************************************************
|
||||
**
|
||||
** @file dialogexporttocsv.h
|
||||
** @author Roman Telezhynskyi <dismine(at)gmail.com>
|
||||
** @date 1 6, 2016
|
||||
**
|
||||
** @brief
|
||||
** @copyright
|
||||
** This source code is part of the Valentine project, a pattern making
|
||||
** program, whose allow create and modeling patterns of clothing.
|
||||
** Copyright (C) 2016 Valentina project
|
||||
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
|
||||
**
|
||||
** Valentina is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Valentina is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef DIALOGEXPORTTOCSV_H
|
||||
#define DIALOGEXPORTTOCSV_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class DialogExportToCSV;
|
||||
}
|
||||
|
||||
class DialogExportToCSV : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogExportToCSV(QWidget *parent = nullptr);
|
||||
virtual ~DialogExportToCSV();
|
||||
|
||||
bool WithHeader() const;
|
||||
int SelectedMib() const;
|
||||
QChar Separator() const;
|
||||
|
||||
protected:
|
||||
virtual void changeEvent(QEvent* event) Q_DECL_OVERRIDE;
|
||||
virtual void showEvent(QShowEvent *event) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(DialogExportToCSV)
|
||||
Ui::DialogExportToCSV *ui;
|
||||
bool isInitialized;
|
||||
|
||||
void SetSeparator(const QChar &separator);
|
||||
};
|
||||
|
||||
#endif // DIALOGEXPORTTOCSV_H
|
165
src/app/tape/dialogs/dialogexporttocsv.ui
Normal file
165
src/app/tape/dialogs/dialogexporttocsv.ui
Normal file
|
@ -0,0 +1,165 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DialogExportToCSV</class>
|
||||
<widget class="QDialog" name="DialogExportToCSV">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>298</width>
|
||||
<height>292</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Export options</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>:/tapeicon/64x64/logo.png</normaloff>:/tapeicon/64x64/logo.png</iconset>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoxExport">
|
||||
<property name="title">
|
||||
<string>Export</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxWithHeader">
|
||||
<property name="text">
|
||||
<string>With header</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBoxCodec"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoxSeparator">
|
||||
<property name="title">
|
||||
<string>Separator</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonTab">
|
||||
<property name="text">
|
||||
<string>Tab</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonComma">
|
||||
<property name="text">
|
||||
<string>Comma</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonSemicolon">
|
||||
<property name="text">
|
||||
<string>Semicolon</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonSpace">
|
||||
<property name="text">
|
||||
<string>Space</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>DialogExportToCSV</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>DialogExportToCSV</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="buttonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
|
@ -11,6 +11,7 @@ SOURCES += \
|
|||
$$PWD/dialogs/tapeconfigdialog.cpp \
|
||||
$$PWD/dialogs/configpages/tapeconfigurationpage.cpp \
|
||||
$$PWD/dialogs/configpages/tapepathpage.cpp \
|
||||
$$PWD/dialogs/dialogexporttocsv.cpp \
|
||||
$$PWD/vlitepattern.cpp \
|
||||
$$PWD/vtablesearch.cpp
|
||||
|
||||
|
@ -27,6 +28,7 @@ HEADERS += \
|
|||
$$PWD/dialogs/tapeconfigdialog.h \
|
||||
$$PWD/dialogs/configpages/tapeconfigurationpage.h \
|
||||
$$PWD/dialogs/configpages/tapepathpage.h \
|
||||
$$PWD/dialogs/dialogexporttocsv.h \
|
||||
$$PWD/vlitepattern.h \
|
||||
$$PWD/vtablesearch.h
|
||||
|
||||
|
@ -34,4 +36,5 @@ FORMS += \
|
|||
$$PWD/tmainwindow.ui \
|
||||
$$PWD/dialogs/dialogabouttape.ui \
|
||||
$$PWD/dialogs/dialognewmeasurements.ui \
|
||||
$$PWD/dialogs/dialogmdatabase.ui
|
||||
$$PWD/dialogs/dialogmdatabase.ui \
|
||||
$$PWD/dialogs/dialogexporttocsv.ui
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "dialogs/dialognewmeasurements.h"
|
||||
#include "dialogs/dialogmdatabase.h"
|
||||
#include "dialogs/tapeconfigdialog.h"
|
||||
#include "dialogs/dialogexporttocsv.h"
|
||||
#include "../vpatterndb/calculator.h"
|
||||
#include "../ifc/ifcdef.h"
|
||||
#include "../ifc/xml/vvitconverter.h"
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include "../ifc/xml/vpatternconverter.h"
|
||||
#include "../vmisc/vlockguard.h"
|
||||
#include "../vmisc/vsysexits.h"
|
||||
#include "../vmisc/qxtcsvmodel.h"
|
||||
#include "vlitepattern.h"
|
||||
#include "../qmuparser/qmudef.h"
|
||||
#include "../vtools/dialogs/support/dialogeditwrongformula.h"
|
||||
|
@ -51,6 +53,7 @@
|
|||
#include <QComboBox>
|
||||
#include <QProcess>
|
||||
#include <QtNumeric>
|
||||
#include <QTextCodec>
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
#include <QMimeData>
|
||||
|
@ -679,6 +682,80 @@ void TMainWindow::FileSaveAs()
|
|||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void TMainWindow::ExportToCSV()
|
||||
{
|
||||
const QString filters = tr("Comma-Separated Values (*.cvs)");
|
||||
const QString suffix("csv");
|
||||
const QString path = QDir::homePath() + "/" + tr("measurements"); + "." + suffix;
|
||||
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Export to CSV"), path, filters);
|
||||
|
||||
if (fileName.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QFileInfo f( fileName );
|
||||
if (f.suffix().isEmpty() && f.suffix() != suffix)
|
||||
{
|
||||
fileName += "." + suffix;
|
||||
}
|
||||
|
||||
DialogExportToCSV dialog(this);
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
QxtCsvModel csv;
|
||||
const int columns = ui->tableWidget->columnCount();
|
||||
{
|
||||
int colCount = 0;
|
||||
for (int column = 0; column < columns; ++column)
|
||||
{
|
||||
if (not ui->tableWidget->isColumnHidden(column))
|
||||
{
|
||||
csv.insertColumn(colCount++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dialog.WithHeader())
|
||||
{
|
||||
int colCount = 0;
|
||||
for (int column = 0; column < columns; ++column)
|
||||
{
|
||||
if (not ui->tableWidget->isColumnHidden(column))
|
||||
{
|
||||
QTableWidgetItem *header = ui->tableWidget->horizontalHeaderItem(colCount);
|
||||
csv.setHeaderText(colCount, header->text());
|
||||
++colCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int rows = ui->tableWidget->rowCount();
|
||||
for (int row = 0; row < rows; ++row)
|
||||
{
|
||||
csv.insertRow(row);
|
||||
int colCount = 0;
|
||||
for (int column = 0; column < columns; ++column)
|
||||
{
|
||||
if (not ui->tableWidget->isColumnHidden(column))
|
||||
{
|
||||
QTableWidgetItem *item = ui->tableWidget->item(row, column);
|
||||
csv.setText(row, colCount, item->text());
|
||||
++colCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
csv.toCSV(fileName, dialog.WithHeader(), dialog.Separator(), QTextCodec::codecForMib(dialog.SelectedMib()));
|
||||
|
||||
qApp->TapeSettings()->SetCSVSeparator(dialog.Separator());
|
||||
qApp->TapeSettings()->SetCSVCodec(dialog.SelectedMib());
|
||||
qApp->TapeSettings()->SetCSVWithHeader(dialog.WithHeader());
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void TMainWindow::AboutToShowWindowMenu()
|
||||
{
|
||||
|
@ -863,6 +940,8 @@ void TMainWindow::Remove()
|
|||
{
|
||||
MFields(false);
|
||||
|
||||
ui->actionExportToCSV->setEnabled(false);
|
||||
|
||||
ui->lineEditName->blockSignals(true);
|
||||
ui->lineEditName->setText("");
|
||||
ui->lineEditName->blockSignals(false);
|
||||
|
@ -1060,13 +1139,15 @@ void TMainWindow::AddCustom()
|
|||
|
||||
ui->tableWidget->selectRow(currentRow);
|
||||
|
||||
ui->actionExportToCSV->setEnabled(true);
|
||||
|
||||
MeasurementsWasSaved(false);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void TMainWindow::AddKnown()
|
||||
{
|
||||
DialogMDataBase *dialog = new DialogMDataBase(m->ListKnown(), this);
|
||||
QScopedPointer<DialogMDataBase> dialog (new DialogMDataBase(m->ListKnown(), this));
|
||||
if (dialog->exec() == QDialog::Accepted)
|
||||
{
|
||||
qint32 currentRow;
|
||||
|
@ -1114,9 +1195,10 @@ void TMainWindow::AddKnown()
|
|||
|
||||
ui->tableWidget->selectRow(currentRow);
|
||||
|
||||
ui->actionExportToCSV->setEnabled(true);
|
||||
|
||||
MeasurementsWasSaved(false);
|
||||
}
|
||||
delete dialog;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -1732,6 +1814,7 @@ void TMainWindow::SetupMenu()
|
|||
connect(ui->actionSaveAs, &QAction::triggered, this, &TMainWindow::FileSaveAs);
|
||||
ui->actionSaveAs->setShortcuts(QKeySequence::SaveAs);
|
||||
|
||||
connect(ui->actionExportToCSV, &QAction::triggered, this, &TMainWindow::ExportToCSV);
|
||||
connect(ui->actionReadOnly, &QAction::triggered, this, &TMainWindow::ReadOnly);
|
||||
connect(ui->actionPreferences, &QAction::triggered, this, &TMainWindow::Preferences);
|
||||
|
||||
|
@ -2302,6 +2385,11 @@ void TMainWindow::RefreshTable()
|
|||
ui->tableWidget->resizeRowsToContents();
|
||||
ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
|
||||
ui->tableWidget->blockSignals(false);
|
||||
|
||||
if (ui->tableWidget->rowCount() > 0)
|
||||
{
|
||||
ui->actionExportToCSV->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -79,6 +79,7 @@ protected:
|
|||
private slots:
|
||||
void FileSave();
|
||||
void FileSaveAs();
|
||||
void ExportToCSV();
|
||||
void AboutToShowWindowMenu();
|
||||
void ShowWindow();
|
||||
void AboutApplication();
|
||||
|
|
|
@ -913,6 +913,7 @@
|
|||
<addaction name="separator"/>
|
||||
<addaction name="actionSave"/>
|
||||
<addaction name="actionSaveAs"/>
|
||||
<addaction name="actionExportToCSV"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionReadOnly"/>
|
||||
<addaction name="separator"/>
|
||||
|
@ -1249,6 +1250,14 @@
|
|||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExportToCSV">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Export to CSV</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
|
|
|
@ -632,4 +632,95 @@ static inline bool VFuzzyComparePossibleNulls(double p1, double p2)
|
|||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
** 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:
|
||||
QxtPrivate(): qxt_p_ptr(nullptr)
|
||||
{}
|
||||
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;
|
||||
}
|
||||
inline PUB* qxt_ptr()
|
||||
{
|
||||
return qxt_p_ptr;
|
||||
}
|
||||
inline const PUB* qxt_ptr() const
|
||||
{
|
||||
return qxt_p_ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QxtPrivate)
|
||||
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);
|
||||
}
|
||||
inline PVT * operator->()
|
||||
{
|
||||
return static_cast<PVT*>(pvt);
|
||||
}
|
||||
inline const PVT * operator->() const
|
||||
{
|
||||
return static_cast<PVT*>(pvt);
|
||||
}
|
||||
private:
|
||||
Q_DISABLE_COPY(QxtPrivateInterface)
|
||||
QxtPrivate<PUB>* pvt;
|
||||
};
|
||||
|
||||
#endif // DEF_H
|
||||
|
|
729
src/libs/vmisc/qxtcsvmodel.cpp
Normal file
729
src/libs/vmisc/qxtcsvmodel.cpp
Normal file
|
@ -0,0 +1,729 @@
|
|||
/****************************************************************************
|
||||
** 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
|
||||
\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)
|
||||
{}
|
||||
QXT_DECLARE_PUBLIC(QxtCsvModel)
|
||||
|
||||
QList<QStringList> csvData;
|
||||
QStringList header;
|
||||
int maxColumn;
|
||||
QxtCsvModel::QuoteMode quoteMode;
|
||||
};
|
||||
|
||||
#ifdef Q_CC_GNU
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#endif
|
||||
|
||||
/*!
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef Q_CC_GNU
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
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::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 (not 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 (not 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 (not row.isEmpty())
|
||||
{
|
||||
if (not 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 (not field.isEmpty())
|
||||
{
|
||||
row << field;
|
||||
}
|
||||
if (not row.isEmpty())
|
||||
{
|
||||
if (not 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;
|
||||
}
|
||||
beginInsertColumns(parent, col, col + count - 1);
|
||||
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;
|
||||
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) const
|
||||
{
|
||||
const QxtCsvModelPrivate& d_ptr = qxt_d();
|
||||
int row, col, rows, cols;
|
||||
rows = rowCount();
|
||||
cols = columnCount();
|
||||
QString data;
|
||||
if (not 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) const
|
||||
{
|
||||
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();
|
||||
}
|
113
src/libs/vmisc/qxtcsvmodel.h
Normal file
113
src/libs/vmisc/qxtcsvmodel.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
/****************************************************************************
|
||||
** 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>
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QXTCSVMODEL_H
|
||||
#define QXTCSVMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QVariant>
|
||||
#include <QIODevice>
|
||||
#include <QChar>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QModelIndex>
|
||||
#include <def.h>
|
||||
class QTextCodec;
|
||||
|
||||
class QxtCsvModelPrivate;
|
||||
class QxtCsvModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QxtCsvModel(QObject *parent = nullptr);
|
||||
explicit QxtCsvModel(QIODevice *file, QObject *parent = nullptr, bool withHeader = false, QChar separator = ',');
|
||||
explicit QxtCsvModel(const QString filename, QObject *parent = nullptr, bool withHeader = false,
|
||||
QChar separator = ',');
|
||||
virtual ~QxtCsvModel();
|
||||
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
|
||||
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
|
||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
|
||||
virtual bool setData(const QModelIndex& index, const QVariant& data, int role = Qt::EditRole) Q_DECL_OVERRIDE;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
|
||||
virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant& value,
|
||||
int role = Qt::DisplayRole) Q_DECL_OVERRIDE;
|
||||
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());
|
||||
virtual bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) Q_DECL_OVERRIDE;
|
||||
|
||||
bool removeRow(int row, const QModelIndex& parent = QModelIndex());
|
||||
virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) Q_DECL_OVERRIDE;
|
||||
|
||||
bool insertColumn(int col, const QModelIndex& parent = QModelIndex());
|
||||
virtual bool insertColumns(int col, int count, const QModelIndex& parent = QModelIndex()) Q_DECL_OVERRIDE;
|
||||
|
||||
bool removeColumn(int col, const QModelIndex& parent = QModelIndex());
|
||||
virtual bool removeColumns(int col, int count, const QModelIndex& parent = QModelIndex()) Q_DECL_OVERRIDE;
|
||||
|
||||
void setSource(QIODevice *file, bool withHeader = false, QChar separator = ',', QTextCodec* codec = nullptr);
|
||||
void setSource(const QString filename, bool withHeader = false, QChar separator = ',', QTextCodec* codec = nullptr);
|
||||
|
||||
void toCSV(QIODevice *file, bool withHeader = false, QChar separator = ',', QTextCodec* codec = nullptr) const;
|
||||
void toCSV(const QString filename, bool withHeader = false, QChar separator = ',',
|
||||
QTextCodec* codec = nullptr) const;
|
||||
|
||||
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);
|
||||
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QxtCsvModel)
|
||||
QXT_DECLARE_PRIVATE(QxtCsvModel)
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QxtCsvModel::QuoteMode)
|
||||
|
||||
#endif // QXTCSVMODEL_H
|
|
@ -9,7 +9,8 @@ SOURCES += \
|
|||
$$PWD/projectversion.cpp \
|
||||
$$PWD/vcommonsettings.cpp \
|
||||
$$PWD/vtapesettings.cpp \
|
||||
$$PWD/commandoptions.cpp
|
||||
$$PWD/commandoptions.cpp \
|
||||
$$PWD/qxtcsvmodel.cpp
|
||||
|
||||
win32-msvc*:SOURCES += $$PWD/stable.cpp
|
||||
|
||||
|
@ -27,7 +28,8 @@ HEADERS += \
|
|||
$$PWD/debugbreak.h \
|
||||
$$PWD/vlockguard.h \
|
||||
$$PWD/vsysexits.h \
|
||||
$$PWD/commandoptions.h
|
||||
$$PWD/commandoptions.h \
|
||||
$$PWD/qxtcsvmodel.h
|
||||
|
||||
# Qt's versions
|
||||
# 5.0.0, 5.0.1, 5.0.2
|
||||
|
|
|
@ -30,12 +30,17 @@
|
|||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QTextCodec>
|
||||
|
||||
const QString VTapeSettings::SettingDataBaseGeometry = QStringLiteral("database/geometry");
|
||||
|
||||
const QString VTapeSettings::SettingDefHeight = QStringLiteral("gradation/defHeight");
|
||||
const QString VTapeSettings::SettingDefSize = QStringLiteral("gradation/defHeight");
|
||||
|
||||
const QString VTapeSettings::SettingCSVWithHeader = QStringLiteral("csv/withHeader");
|
||||
const QString VTapeSettings::SettingCSVCodec = QStringLiteral("csv/withCodec");
|
||||
const QString VTapeSettings::SettingCSVSeparator = QStringLiteral("csv/withSeparator");
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
VTapeSettings::VTapeSettings(Format format, Scope scope, const QString &organization, const QString &application,
|
||||
QObject *parent)
|
||||
|
@ -78,3 +83,70 @@ int VTapeSettings::GetDefSize() const
|
|||
{
|
||||
return value(SettingDefSize, 50).toInt();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void VTapeSettings::SetCSVWithHeader(bool withHeader)
|
||||
{
|
||||
setValue(SettingCSVWithHeader, withHeader);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
bool VTapeSettings::GetCSVWithHeader() const
|
||||
{
|
||||
return value(SettingCSVWithHeader, false).toBool();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void VTapeSettings::SetCSVCodec(int mib)
|
||||
{
|
||||
setValue(SettingCSVCodec, mib);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
int VTapeSettings::GetCSVCodec() const
|
||||
{
|
||||
return value(SettingCSVCodec, QTextCodec::codecForLocale()->mibEnum()).toInt();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
void VTapeSettings::SetCSVSeparator(const QChar &separator)
|
||||
{
|
||||
switch(separator.toLatin1())
|
||||
{
|
||||
case '\t':
|
||||
setValue(SettingCSVSeparator, 0);
|
||||
break;
|
||||
case ';':
|
||||
setValue(SettingCSVSeparator, 1);
|
||||
break;
|
||||
case ' ':
|
||||
setValue(SettingCSVSeparator, 2);
|
||||
break;
|
||||
case ',':
|
||||
default:
|
||||
setValue(SettingCSVSeparator, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
QChar VTapeSettings::GetCSVSeparator() const
|
||||
{
|
||||
const quint8 separator = static_cast<quint8>(value(SettingCSVSeparator, 3).toUInt());
|
||||
switch(separator)
|
||||
{
|
||||
case 0:
|
||||
return QChar('\t');
|
||||
break;
|
||||
case 1:
|
||||
return QChar(';');
|
||||
break;
|
||||
case 2:
|
||||
return QChar(' ');
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
return QChar(',');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,12 +47,24 @@ public:
|
|||
void SetDefSize(int value);
|
||||
int GetDefSize() const;
|
||||
|
||||
void SetCSVWithHeader(bool withHeader);
|
||||
bool GetCSVWithHeader() const;
|
||||
|
||||
void SetCSVCodec(int mib);
|
||||
int GetCSVCodec() const;
|
||||
|
||||
void SetCSVSeparator(const QChar &separator);
|
||||
QChar GetCSVSeparator() const;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(VTapeSettings)
|
||||
|
||||
static const QString SettingDataBaseGeometry;
|
||||
static const QString SettingDefHeight;
|
||||
static const QString SettingDefSize;
|
||||
static const QString SettingCSVWithHeader;
|
||||
static const QString SettingCSVCodec;
|
||||
static const QString SettingCSVSeparator;
|
||||
};
|
||||
|
||||
#endif // VTAPESETTINGS_H
|
||||
|
|
Loading…
Reference in New Issue
Block a user