mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 02:50:46 -06:00
Rewrite export to CSV dialog
Rewrite the dialog to export tables as CSV file using Qt Designer. Move the entire export functionality to this dialog instead of generating the file in the main window. Add some options for the user to change the layout of the CSV file.
This commit is contained in:
96
src/ExportCsvDialog.cpp
Normal file
96
src/ExportCsvDialog.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include "ExportCsvDialog.h"
|
||||
#include "ui_ExportCsvDialog.h"
|
||||
#include "sqlitedb.h"
|
||||
|
||||
ExportCsvDialog::ExportCsvDialog(DBBrowserDB* db, QString deflocation, QWidget* parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::ExportCsvDialog),
|
||||
pdb(db),
|
||||
defaultLocation(deflocation)
|
||||
{
|
||||
// Create UI
|
||||
ui->setupUi(this);
|
||||
|
||||
// Get list of tables to export
|
||||
objectMap objects = pdb->getBrowsableObjects();
|
||||
for(objectMap::ConstIterator i=objects.begin();i!=objects.end();++i)
|
||||
ui->comboTable->addItem(QIcon(QString(":icons/%1").arg(i.value().gettype())), i.value().getname());
|
||||
}
|
||||
|
||||
ExportCsvDialog::~ExportCsvDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ExportCsvDialog::accept()
|
||||
{
|
||||
// Get filename
|
||||
QString fileName = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
"Choose a filename to export data",
|
||||
defaultLocation,
|
||||
"Text files(*.csv *.txt)");
|
||||
|
||||
// Only if the user hasn't clicked the cancel button
|
||||
if(fileName.size() > 0)
|
||||
{
|
||||
// Get data from selected table
|
||||
pdb->browseTable(ui->comboTable->currentText());
|
||||
|
||||
// Prepare the quote and separating characters
|
||||
QString quoteChar = ui->comboQuoteCharacter->currentText();
|
||||
QString quotequoteChar = quoteChar + quoteChar;
|
||||
QString sepChar = ui->comboFieldSeparator->currentText();
|
||||
if(sepChar == "Tab") sepChar = "\t";
|
||||
QString newlineChar = "\n";
|
||||
|
||||
// Open file
|
||||
QFile file(fileName);
|
||||
if(file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
// Open text stream to the file
|
||||
QTextStream stream(&file);
|
||||
|
||||
// Put field names in first row if user wants to have them
|
||||
if(ui->checkHeader->isChecked())
|
||||
{
|
||||
QStringList fields = pdb->browseFields;
|
||||
for(int i=0;i<fields.count();i++)
|
||||
{
|
||||
stream << quoteChar << fields.at(i) << quoteChar;
|
||||
if(i < fields.count() - 1)
|
||||
stream << sepChar;
|
||||
else
|
||||
stream << newlineChar;
|
||||
}
|
||||
}
|
||||
|
||||
// Get and write actual data
|
||||
rowList data = pdb->browseRecs;
|
||||
for(int i=0;i<data.size();i++)
|
||||
{
|
||||
QStringList& row = data[i];
|
||||
for(int j=1;j<row.size();j++)
|
||||
{
|
||||
QString content = row[j];
|
||||
stream << quoteChar << content.replace(quoteChar, quotequoteChar) << quoteChar;
|
||||
if(j < row.count() - 1)
|
||||
stream << sepChar;
|
||||
else
|
||||
stream << newlineChar;
|
||||
}
|
||||
}
|
||||
|
||||
// Done writing the file
|
||||
file.close();
|
||||
QMessageBox::information(this, QApplication::applicationName(), "Export completed.");
|
||||
QDialog::accept();
|
||||
} else {
|
||||
QMessageBox::warning(this, QApplication::applicationName(), "Could not open output file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/ExportCsvDialog.h
Normal file
28
src/ExportCsvDialog.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef __EXPORTCSVDIALOG_H__
|
||||
#define __EXPORTCSVDIALOG_H__
|
||||
|
||||
#include <QDialog>
|
||||
class DBBrowserDB;
|
||||
|
||||
namespace Ui {
|
||||
class ExportCsvDialog;
|
||||
}
|
||||
|
||||
class ExportCsvDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportCsvDialog(DBBrowserDB* db, QString deflocation, QWidget* parent = 0);
|
||||
~ExportCsvDialog();
|
||||
|
||||
public slots:
|
||||
virtual void accept();
|
||||
|
||||
private:
|
||||
Ui::ExportCsvDialog* ui;
|
||||
DBBrowserDB* pdb;
|
||||
QString defaultLocation;
|
||||
};
|
||||
|
||||
#endif
|
||||
166
src/ExportCsvDialog.ui
Normal file
166
src/ExportCsvDialog.ui
Normal file
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ExportCsvDialog</class>
|
||||
<widget class="QDialog" name="ExportCsvDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>331</width>
|
||||
<height>141</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Export table to CSV</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelTable">
|
||||
<property name="text">
|
||||
<string>&Table</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>comboTable</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboTable"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelHeader">
|
||||
<property name="text">
|
||||
<string>&Column names in first line</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>checkHeader</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="checkHeader">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelFieldSeparator">
|
||||
<property name="text">
|
||||
<string>Field &separator</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>comboFieldSeparator</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboFieldSeparator">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>,</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>;</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Tab</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="labelQuoteCharacter">
|
||||
<property name="text">
|
||||
<string>&Quote character</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>comboQuoteCharacter</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="comboQuoteCharacter">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>"</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>'</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
<tabstops>
|
||||
<tabstop>comboTable</tabstop>
|
||||
<tabstop>checkHeader</tabstop>
|
||||
<tabstop>comboFieldSeparator</tabstop>
|
||||
<tabstop>comboQuoteCharacter</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ExportCsvDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>252</x>
|
||||
<y>136</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>140</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ExportCsvDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>320</x>
|
||||
<y>136</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>140</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,44 +0,0 @@
|
||||
#include "ExportTableCSVForm.h"
|
||||
|
||||
/*
|
||||
* Constructs a exportTableCSVForm as a child of 'parent', with the
|
||||
* name 'name' and widget flags set to 'f'.
|
||||
*
|
||||
* The dialog will by default be modeless, unless you set 'modal' to
|
||||
* true to construct a modal dialog.
|
||||
*/
|
||||
exportTableCSVForm::exportTableCSVForm(QWidget* parent, Qt::WindowFlags fl)
|
||||
: QDialog(parent, fl)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys the object and frees any allocated resources
|
||||
*/
|
||||
exportTableCSVForm::~exportTableCSVForm()
|
||||
{
|
||||
// no need to delete child widgets, Qt does it all for us
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the strings of the subwidgets using the current
|
||||
* language.
|
||||
*/
|
||||
void exportTableCSVForm::languageChange()
|
||||
{
|
||||
retranslateUi(this);
|
||||
}
|
||||
|
||||
void exportTableCSVForm::exportPressed()
|
||||
{
|
||||
option = comboOptions->currentText();
|
||||
accept();
|
||||
}
|
||||
|
||||
void exportTableCSVForm::populateOptions(QStringList entries)
|
||||
{
|
||||
comboOptions->clear();
|
||||
comboOptions->addItems(entries);
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
#ifndef EXPORTTABLECSVFORM_H
|
||||
#define EXPORTTABLECSVFORM_H
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QComboBox>
|
||||
#include <QtGui/QDialog>
|
||||
#include <QtGui/QHBoxLayout>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QtGui/QSpacerItem>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
|
||||
class Ui_exportTableCSVForm
|
||||
{
|
||||
public:
|
||||
QVBoxLayout *vboxLayout;
|
||||
QHBoxLayout *hboxLayout;
|
||||
QLabel *textLabel2;
|
||||
QComboBox *comboOptions;
|
||||
QSpacerItem *spacer13;
|
||||
QHBoxLayout *hboxLayout1;
|
||||
QSpacerItem *spacer11;
|
||||
QPushButton *buttonCancel;
|
||||
QPushButton *buttonExport;
|
||||
|
||||
void setupUi(QDialog *exportTableCSVForm)
|
||||
{
|
||||
if (exportTableCSVForm->objectName().isEmpty())
|
||||
exportTableCSVForm->setObjectName(QString::fromUtf8("exportTableCSVForm"));
|
||||
exportTableCSVForm->resize(365, 150);
|
||||
vboxLayout = new QVBoxLayout(exportTableCSVForm);
|
||||
vboxLayout->setSpacing(6);
|
||||
vboxLayout->setContentsMargins(11, 11, 11, 11);
|
||||
vboxLayout->setObjectName(QString::fromUtf8("vboxLayout"));
|
||||
hboxLayout = new QHBoxLayout();
|
||||
hboxLayout->setSpacing(6);
|
||||
hboxLayout->setObjectName(QString::fromUtf8("hboxLayout"));
|
||||
textLabel2 = new QLabel(exportTableCSVForm);
|
||||
textLabel2->setObjectName(QString::fromUtf8("textLabel2"));
|
||||
textLabel2->setWordWrap(false);
|
||||
|
||||
hboxLayout->addWidget(textLabel2);
|
||||
|
||||
comboOptions = new QComboBox(exportTableCSVForm);
|
||||
comboOptions->setObjectName(QString::fromUtf8("comboOptions"));
|
||||
|
||||
hboxLayout->addWidget(comboOptions);
|
||||
|
||||
|
||||
vboxLayout->addLayout(hboxLayout);
|
||||
|
||||
spacer13 = new QSpacerItem(20, 41, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
|
||||
vboxLayout->addItem(spacer13);
|
||||
|
||||
hboxLayout1 = new QHBoxLayout();
|
||||
hboxLayout1->setSpacing(6);
|
||||
hboxLayout1->setObjectName(QString::fromUtf8("hboxLayout1"));
|
||||
spacer11 = new QSpacerItem(29, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
|
||||
hboxLayout1->addItem(spacer11);
|
||||
|
||||
buttonCancel = new QPushButton(exportTableCSVForm);
|
||||
buttonCancel->setObjectName(QString::fromUtf8("buttonCancel"));
|
||||
buttonCancel->setDefault(false);
|
||||
|
||||
hboxLayout1->addWidget(buttonCancel);
|
||||
|
||||
buttonExport = new QPushButton(exportTableCSVForm);
|
||||
buttonExport->setObjectName(QString::fromUtf8("buttonExport"));
|
||||
|
||||
hboxLayout1->addWidget(buttonExport);
|
||||
|
||||
|
||||
vboxLayout->addLayout(hboxLayout1);
|
||||
|
||||
|
||||
retranslateUi(exportTableCSVForm);
|
||||
QObject::connect(buttonExport, SIGNAL(clicked()), exportTableCSVForm, SLOT(exportPressed()));
|
||||
QObject::connect(buttonCancel, SIGNAL(clicked()), exportTableCSVForm, SLOT(reject()));
|
||||
|
||||
QMetaObject::connectSlotsByName(exportTableCSVForm);
|
||||
} // setupUi
|
||||
|
||||
void retranslateUi(QDialog *exportTableCSVForm)
|
||||
{
|
||||
exportTableCSVForm->setWindowTitle(QApplication::translate("exportTableCSVForm", "Choose table to export as CSV text", 0, QApplication::UnicodeUTF8));
|
||||
textLabel2->setText(QApplication::translate("exportTableCSVForm", "Table name:", 0, QApplication::UnicodeUTF8));
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
comboOptions->setProperty("toolTip", QVariant(QApplication::translate("exportTableCSVForm", "Choose the table to delete", 0, QApplication::UnicodeUTF8)));
|
||||
#endif // QT_NO_TOOLTIP
|
||||
#ifndef QT_NO_WHATSTHIS
|
||||
comboOptions->setProperty("whatsThis", QVariant(QApplication::translate("exportTableCSVForm", "Use this control to select the name of the table to be deleted", 0, QApplication::UnicodeUTF8)));
|
||||
#endif // QT_NO_WHATSTHIS
|
||||
buttonCancel->setText(QApplication::translate("exportTableCSVForm", "Cancel", 0, QApplication::UnicodeUTF8));
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
buttonCancel->setProperty("toolTip", QVariant(QApplication::translate("exportTableCSVForm", "Cancel and close dialog box", 0, QApplication::UnicodeUTF8)));
|
||||
#endif // QT_NO_TOOLTIP
|
||||
buttonExport->setText(QApplication::translate("exportTableCSVForm", "Export", 0, QApplication::UnicodeUTF8));
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
buttonExport->setProperty("toolTip", QVariant(QApplication::translate("exportTableCSVForm", "Delete the selected table", 0, QApplication::UnicodeUTF8)));
|
||||
#endif // QT_NO_TOOLTIP
|
||||
} // retranslateUi
|
||||
|
||||
};
|
||||
|
||||
namespace Ui {
|
||||
class exportTableCSVForm: public Ui_exportTableCSVForm {};
|
||||
} // namespace Ui
|
||||
|
||||
class exportTableCSVForm : public QDialog, public Ui::exportTableCSVForm
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
exportTableCSVForm(QWidget* parent = 0, Qt::WindowFlags fl = Qt::Window);
|
||||
~exportTableCSVForm();
|
||||
|
||||
QString option;
|
||||
|
||||
public slots:
|
||||
virtual void exportPressed();
|
||||
virtual void populateOptions( QStringList entries );
|
||||
|
||||
protected slots:
|
||||
virtual void languageChange();
|
||||
|
||||
};
|
||||
|
||||
#endif // EXPORTTABLECSVFORM_H
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "EditTableDialog.h"
|
||||
#include "EditFieldDialog.h"
|
||||
#include "ImportCSVForm.h"
|
||||
#include "ExportTableCSVForm.h"
|
||||
#include "ExportCsvDialog.h"
|
||||
#include "PreferencesDialog.h"
|
||||
#include "EditDialog.h"
|
||||
#include "FindDialog.h"
|
||||
@@ -838,80 +838,8 @@ void MainWindow::importTableFromCSV()
|
||||
|
||||
void MainWindow::exportTableToCSV()
|
||||
{
|
||||
exportTableCSVForm dialog(this);
|
||||
dialog.populateOptions(db.getBrowsableObjectNames());
|
||||
if(dialog.exec())
|
||||
{
|
||||
//load our table
|
||||
db.browseTable(dialog.option);
|
||||
|
||||
QString fileName = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
"Choose a filename to export data",
|
||||
defaultlocation,
|
||||
"Text files(*.csv *.txt)");
|
||||
|
||||
if (fileName.size() > 0)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if ( file.open( QIODevice::WriteOnly ) )
|
||||
{
|
||||
char quote = '"';
|
||||
char sep = ',';
|
||||
char feed = 10;
|
||||
int colNum = 0;
|
||||
int colCount = 0;
|
||||
QTextStream stream( &file );
|
||||
//fieldnames on first row
|
||||
QStringList fields = db.browseFields;
|
||||
colCount = fields.count();
|
||||
for ( QStringList::Iterator ct = fields.begin(); ct != fields.end(); ++ct ) {
|
||||
stream << quote;
|
||||
stream << *ct;
|
||||
stream << quote;
|
||||
colNum++;
|
||||
if (colNum<colCount)
|
||||
{
|
||||
stream << sep;
|
||||
} else {
|
||||
stream << feed;
|
||||
colNum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//now export data
|
||||
rowList tab = db.browseRecs;
|
||||
|
||||
//int dcols =0;
|
||||
QString rowLabel;
|
||||
for ( int i=0; i<tab.size(); ++i )
|
||||
{
|
||||
QStringList& rt = tab[i];
|
||||
for ( int e=1; e<rt.size(); ++e ) {
|
||||
QString content = rt[e];
|
||||
stream<< quote;
|
||||
QChar qquote = quote;
|
||||
content.replace(quote, QString(qquote).append(qquote));
|
||||
stream<< content;
|
||||
stream<< quote;
|
||||
colNum++;
|
||||
if (colNum<colCount)
|
||||
{
|
||||
stream << sep;
|
||||
} else {
|
||||
stream << feed;
|
||||
colNum = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
QMessageBox::information( this, QApplication::applicationName(), "Export completed" );
|
||||
}
|
||||
}
|
||||
populateStructure();
|
||||
resetBrowser();
|
||||
}
|
||||
ExportCsvDialog dialog(&db, defaultlocation, this);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void MainWindow::dbState( bool dirty )
|
||||
|
||||
11
src/src.pro
11
src/src.pro
@@ -14,7 +14,6 @@ HEADERS += \
|
||||
sqlitedb.h \
|
||||
sqlbrowser_util.h \
|
||||
SQLLogDock.h \
|
||||
ExportTableCSVForm.h \
|
||||
ImportCSVForm.h \
|
||||
MainWindow.h \
|
||||
SQLiteSyntaxHighlighter.h \
|
||||
@@ -24,14 +23,14 @@ HEADERS += \
|
||||
EditTableDialog.h \
|
||||
PreferencesDialog.h \
|
||||
FindDialog.h \
|
||||
EditDialog.h
|
||||
EditDialog.h \
|
||||
ExportCsvDialog.h
|
||||
|
||||
SOURCES += \
|
||||
sqlitedb.cpp \
|
||||
sqlbrowser_util.c \
|
||||
SQLLogDock.cpp \
|
||||
main.cpp \
|
||||
ExportTableCSVForm.cpp \
|
||||
ImportCSVForm.cpp \
|
||||
MainWindow.cpp \
|
||||
SQLiteSyntaxHighlighter.cpp \
|
||||
@@ -41,7 +40,8 @@ SOURCES += \
|
||||
PreferencesDialog.cpp \
|
||||
AboutDialog.cpp \
|
||||
FindDialog.cpp \
|
||||
EditDialog.cpp
|
||||
EditDialog.cpp \
|
||||
ExportCsvDialog.cpp
|
||||
|
||||
QMAKE_CXXFLAGS += -DAPP_VERSION=\\\"`cd $$PWD;git log -n1 --format=%h_git`\\\"
|
||||
|
||||
@@ -70,4 +70,5 @@ FORMS += \
|
||||
EditTableDialog.ui \
|
||||
PreferencesDialog.ui \
|
||||
FindDialog.ui \
|
||||
EditDialog.ui
|
||||
EditDialog.ui \
|
||||
ExportCsvDialog.ui
|
||||
|
||||
Reference in New Issue
Block a user