fixes to meta table handling and other bugs

git-svn-id: http://svn.osgeo.org/qgis/trunk@790 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
gsherman 2004-02-11 05:46:39 +00:00
parent 20c9cb2f5f
commit 8e4322817c
3 changed files with 428 additions and 289 deletions

View File

@ -29,200 +29,225 @@
#include "qgsshapefile.h"
QgsShapeFile::QgsShapeFile(QString name){
filename = name;
features = 0;
OGRRegisterAll();
ogrDataSource = OGRSFDriverRegistrar::Open((const char *) filename);
if (ogrDataSource != NULL){
valid = true;
ogrLayer = ogrDataSource->GetLayer(0);
features = ogrLayer->GetFeatureCount();
}
else
valid = false;
setDefaultTable();
QgsShapeFile::QgsShapeFile(QString name)
{
filename = name;
features = 0;
OGRRegisterAll();
ogrDataSource = OGRSFDriverRegistrar::Open((const char *) filename);
if (ogrDataSource != NULL) {
valid = true;
ogrLayer = ogrDataSource->GetLayer(0);
features = ogrLayer->GetFeatureCount();
} else
valid = false;
setDefaultTable();
}
QgsShapeFile::~QgsShapeFile(){
delete ogrLayer;
delete ogrDataSource;
delete filename;
delete geom_type;
QgsShapeFile::~QgsShapeFile()
{
delete ogrLayer;
delete ogrDataSource;
delete filename;
delete geom_type;
}
int QgsShapeFile::getFeatureCount(){
return features;
int QgsShapeFile::getFeatureCount()
{
return features;
}
QString QgsShapeFile::getFeatureClass(){
OGRFeature *feat = ogrLayer->GetNextFeature();
if(feat){
OGRGeometry *geom = feat->GetGeometryRef();
if(geom){
geom_type = QString(geom->getGeometryName());
QString file(filename);
file.replace(file.length()-3, 3, "dbf");
// open the dbf file
std::ifstream dbf((const char*)file, std::ios::in | std::ios::binary);
// read header
DbaseHeader dbh;
dbf.read((char *)&dbh, sizeof(dbh));
Fda fda;
QString str_type = "varchar(";
for(int field_count = 0, bytes_read = sizeof(dbh); bytes_read < dbh.size_hdr-1; field_count++, bytes_read += sizeof(fda)){
dbf.read((char *)&fda, sizeof(fda));
switch(fda.field_type){
case 'N': if((int)fda.field_decimal>0)
column_types.push_back("float");
else
column_types.push_back("int");
break;
case 'F': column_types.push_back("float");
break;
case 'D': column_types.push_back("date");
break;
case 'C':
str_type= QString("varchar(%1)").arg(fda.field_length);
column_types.push_back(str_type);
break;
case 'L': column_types.push_back("boolean");
break;
default:
column_types.push_back("varchar(256)");
break;
}
}
dbf.close();
int numFields = feat->GetFieldCount();
for(int n=0; n<numFields; n++)
column_names.push_back(feat->GetFieldDefnRef(n)->GetNameRef());
}else valid = false;
delete feat;
}else valid = false;
ogrLayer->ResetReading();
return valid?geom_type:NULL;
}
bool QgsShapeFile::is_valid(){
return valid;
}
QString QgsShapeFile::getName(){
return filename;
}
QString QgsShapeFile::getTable(){
return table_name;
}
void QgsShapeFile::setTable(QString new_table){
new_table.replace("\'","\\'");
new_table.replace("\\","\\\\");
table_name = new_table;
}
void QgsShapeFile::setDefaultTable(){
QString name(filename);
name = name.section('/', -1);
table_name = name.section('.', 0, 0);
}
bool QgsShapeFile::insertLayer(QString dbname, QString geom_col, QString srid, PGconn * conn, QProgressDialog * pro, bool &fin){
connect(pro, SIGNAL(cancelled()), this, SLOT(cancelImport()));
import_cancelled = false;
bool result = true;
QString message;
QString query = "CREATE TABLE "+table_name+"(gid int4, ";
for(int n=0; n<column_names.size() && result; n++){
if(!column_names[n][0].isLetter())
result = false;
query += column_names[n].lower();
query += " ";
query += column_types[n];
query += ", ";
}
query += " PRIMARY KEY (gid))";
PGresult *res = PQexec(conn, (const char *)query);
message = PQresultErrorMessage(res);
if(message != ""){
// flag error and send query and error message to stdout on debug
result = false;
qWarning(query);
qWarning(PQresultErrorMessage(res));
}
PQclear(res);
query = "SELECT AddGeometryColumn(\'" + dbname + "\', \'" + table_name + "\', \'"+geom_col+"\', " + srid +
", \'" + QString(geom_type) + "\', 2)";
if(result) res = PQexec(conn, (const char *)query);
message = PQresultErrorMessage(res);
if(message != "") result = false;
//adding the data into the table
for(int m=0;m<features && result; m++){
if(import_cancelled){
fin = true;
break;
}
QString QgsShapeFile::getFeatureClass()
{
OGRFeature *feat = ogrLayer->GetNextFeature();
if(feat){
OGRGeometry *geom = feat->GetGeometryRef();
if(geom){
query = "INSERT INTO "+table_name+QString(" VALUES( %1, ").arg(m);
int num = geom->WkbSize();
char * geo_temp = new char[num*3];
geom->exportToWkt(&geo_temp);
QString geometry(geo_temp);
if (feat) {
OGRGeometry *geom = feat->GetGeometryRef();
if (geom) {
geom_type = QString(geom->getGeometryName());
QString quotes;
for(int n=0; n<column_types.size(); n++){
if(column_types[n] == "int" || column_types[n] == "float")
quotes = " ";
else
quotes = "\'";
query += quotes;
// escape single quotes to prevent sql syntax error (no effect for numerics)
QString val = feat->GetFieldAsString(n);
val.replace("\'","\\'");
val.replace("\\","\\\\");
// add escaped value to the query
query += val;
query += QString(quotes + ", ");
QString file(filename);
file.replace(file.length() - 3, 3, "dbf");
// open the dbf file
std::ifstream dbf((const char *) file, std::ios::in | std::ios::binary);
// read header
DbaseHeader dbh;
dbf.read((char *) &dbh, sizeof(dbh));
}
query += QString("GeometryFromText(\'")+geometry+QString("\', ")+srid+QString("))");
PQclear(res);
if(result) res = PQexec(conn, (const char *)query);
message = PQresultErrorMessage(res);
if(message != ""){
// flag error and send query and error message to stdout on debug
result = false;
qWarning(query);
qWarning(PQresultErrorMessage(res));
}
pro->setProgress(pro->progress()+1);
qApp->processEvents();
delete[] geo_temp;
}
delete feat;
Fda fda;
QString str_type = "varchar(";
for (int field_count = 0, bytes_read = sizeof(dbh); bytes_read < dbh.size_hdr - 1;
field_count++, bytes_read += sizeof(fda)) {
dbf.read((char *) &fda, sizeof(fda));
switch (fda.field_type) {
case 'N':
if ((int) fda.field_decimal > 0)
column_types.push_back("float");
else
column_types.push_back("int");
break;
case 'F':
column_types.push_back("float");
break;
case 'D':
column_types.push_back("date");
break;
case 'C':
str_type = QString("varchar(%1)").arg(fda.field_length);
column_types.push_back(str_type);
break;
case 'L':
column_types.push_back("boolean");
break;
default:
column_types.push_back("varchar(256)");
break;
}
}
dbf.close();
int numFields = feat->GetFieldCount();
for (int n = 0; n < numFields; n++)
column_names.push_back(feat->GetFieldDefnRef(n)->GetNameRef());
} else
valid = false;
delete feat;
} else
valid = false;
ogrLayer->ResetReading();
return valid ? geom_type : NULL;
}
bool QgsShapeFile::is_valid()
{
return valid;
}
QString QgsShapeFile::getName()
{
return filename;
}
QString QgsShapeFile::getTable()
{
return table_name;
}
void QgsShapeFile::setTable(QString new_table)
{
new_table.replace("\'", "\\'");
new_table.replace("\\", "\\\\");
table_name = new_table;
}
void QgsShapeFile::setDefaultTable()
{
QString name(filename);
name = name.section('/', -1);
table_name = name.section('.', 0, 0);
}
bool QgsShapeFile::insertLayer(QString dbname, QString geom_col, QString srid, PGconn * conn, QProgressDialog * pro, bool & fin)
{
connect(pro, SIGNAL(cancelled()), this, SLOT(cancelImport()));
import_cancelled = false;
bool result = true;
QString query = "CREATE TABLE " + table_name + "(gid int4 PRIMARY KEY, ";
for (int n = 0; n < column_names.size() && result; n++) {
if (!column_names[n][0].isLetter())
result = false;
query += column_names[n].lower();
query += " ";
query += column_types[n];
if (n < column_names.size() - 1)
query += ", ";
}
}
ogrLayer->ResetReading();
PQclear(res);
return result;
query += " )";
PGresult *res = PQexec(conn, (const char *) query);
qWarning(query);
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
// flag error and send query and error message to stdout on debug
result = false;
qWarning(PQresultErrorMessage(res));
} else {
PQclear(res);
}
query = "SELECT AddGeometryColumn(\'" + dbname + "\', \'" + table_name + "\', \'" + geom_col + "\', " + srid +
", \'" + QString(geom_type) + "\', 2)";
if (result)
res = PQexec(conn, (const char *) query);
std::cout << PQresStatus(PQresultStatus(res)) << std::endl;
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
result = false;
} else {
qWarning(query);
qWarning(PQresultErrorMessage(res));
PQclear(res);
}
//adding the data into the table
for (int m = 0; m < features && result; m++) {
if (import_cancelled) {
fin = true;
break;
}
OGRFeature *feat = ogrLayer->GetNextFeature();
if (feat) {
OGRGeometry *geom = feat->GetGeometryRef();
if (geom) {
query = "INSERT INTO " + table_name + QString(" VALUES( %1, ").arg(m);
int num = geom->WkbSize();
char *geo_temp = new char[num * 3];
geom->exportToWkt(&geo_temp);
QString geometry(geo_temp);
QString quotes;
for (int n = 0; n < column_types.size(); n++) {
if (column_types[n] == "int" || column_types[n] == "float")
quotes = " ";
else
quotes = "\'";
query += quotes;
// escape single quotes to prevent sql syntax error (no effect for numerics)
QString val = feat->GetFieldAsString(n);
val.replace("\'", "\\'");
val.replace("\\", "\\\\");
// add escaped value to the query
query += val;
query += QString(quotes + ", ");
}
query += QString("GeometryFromText(\'") + geometry + QString("\', ") + srid + QString("))");
if (result)
res = PQexec(conn, (const char *) query);
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
// flag error and send query and error message to stdout on debug
result = false;
qWarning(PQresultErrorMessage(res));
} else {
PQclear(res);
}
pro->setProgress(pro->progress() + 1);
qApp->processEvents();
delete[]geo_temp;
}
delete feat;
}
}
ogrLayer->ResetReading();
return result;
}
void QgsShapeFile::cancelImport(){
import_cancelled = true;
void QgsShapeFile::cancelImport()
{
import_cancelled = true;
}

View File

@ -14,7 +14,7 @@
* (at your option) any later version. *
* *
***************************************************************************/
/* $Id$ */
#include <qsettings.h>
#include <qlistbox.h>
@ -149,6 +149,7 @@ void QgsSpit::addFile()
tblShapefiles->setText(row, 1, file->getFeatureClass());
tblShapefiles->setText(row, 2, QString("%1").arg(file->getFeatureCount()));
tblShapefiles->setText(row, 3, file->getTable());
tblShapefiles->setText(row, 4, "public");
total_features += file->getFeatureCount();
}
else{
@ -237,101 +238,209 @@ void QgsSpit::helpInfo(){
void QgsSpit::import(){
tblShapefiles->setCurrentCell(-1, 0);
QString connName = cmbConnections->currentText();
bool finished = false;
bool cancelled = false;
QString connName = cmbConnections->currentText();
PGresult *res;
if (!connName.isEmpty()) {
QString query;
if (connName.isEmpty()){
QMessageBox::warning(this, "Import Shapefiles", "You need to specify a Connection first");
}
else if(total_features==0){
QMessageBox::warning(this, "Import Shapefiles", "You need to add shapefiles to the list first");
}
else{
QSettings settings;
QString key = "/Qgis/connections/" + connName;
QString connInfo = "host=" + settings.readEntry(key + "/host") + " dbname=" + settings.readEntry(key + "/database") +
" user=" + settings.readEntry(key + "/username") + " password=" + settings.readEntry(key + "/password");
PGconn *pd = PQconnectdb((const char *) connInfo);
if (PQstatus(pd) == CONNECTION_OK) {
if (PQstatus(pd) != CONNECTION_OK) {
QMessageBox::warning(this, "Import Shapefiles", "Connection failed - Check settings and try again");
}
else { // if connection is ok
QProgressDialog * pro = new QProgressDialog("Importing files", "Cancel", total_features, this, "Progress", true);
pro->setProgress(0);
pro->setAutoClose(true);
pro->show();
qApp->processEvents();
//pro->setAutoReset(true);
for(int i=0; i<fileList.size() ; i++){
QString error = "Problem inserting features from file:\n"+tblShapefiles->text(i,0);
// if a name starts with invalid character
if(!(fileList[i]->getTable()[0]).isLetter()){
QMessageBox::warning(pro, "Import Shapefiles",
"Problem inserting file:\n"+fileList[i]->getName()+"\nInvalid table name.");
std::cout<<i<<std::endl;
if(!(tblShapefiles->text(i,3))[0].isLetter()){
QMessageBox::warning(pro, "Import Shapefiles", "Problem inserting file:\n"+tblShapefiles->text(i,0)+"\nInvalid table name.");
pro->setProgress(pro->progress()+(tblShapefiles->text(i,2)).toInt());
continue;
}
PQexec(pd, "BEGIN");
fileList[i]->setTable(tblShapefiles->text(i, 3));
pro->show();
pro->setLabelText("Importing files\n"+fileList[i]->getName());
int rel_exists1 = 0;
int rel_exists2 = 0;
QMessageBox *del_confirm;
QString query = "SELECT f_table_name FROM geometry_columns WHERE f_table_name=\'"+fileList[i]->getTable()+"\'";
pro->setLabelText("Importing files\n"+tblShapefiles->text(i,0));
bool rel_exists1 = false;
bool rel_exists2 = false;
query = "SELECT f_table_name FROM geometry_columns WHERE f_table_name=\'"+tblShapefiles->text(i,3)+"\'";
res = PQexec(pd, (const char *)query);
rel_exists1 = PQntuples(res);
PQclear(res);
query = "SELECT relname FROM pg_stat_all_tables WHERE relname=\'"+fileList[i]->getTable()+"\'";
res = PQexec(pd, (const char *)query);
rel_exists2 = PQntuples(res);
PQclear(res);
rel_exists1 = (PQntuples(res)>0);
if(PQresultStatus(res)!=PGRES_TUPLES_OK){
qWarning(PQresultErrorMessage(res));
QMessageBox::warning(pro, "Import Shapefiles", error);
pro->setProgress(pro->progress()+(tblShapefiles->text(i,2)).toInt());
continue;
}
else {
PQclear(res);
}
query = "SELECT tablename FROM pg_tables WHERE tablename=\'"+tblShapefiles->text(i,3)+"\'";
res = PQexec(pd, (const char *)query);
qWarning(query);
rel_exists2 = (PQntuples(res)>0);
if(PQresultStatus(res)!=PGRES_TUPLES_OK){
qWarning(PQresultErrorMessage(res));
QMessageBox::warning(pro, "Import Shapefiles", error);
pro->setProgress(pro->progress()+(tblShapefiles->text(i,2)).toInt());
continue;
}
else {
PQclear(res);
}
// begin session
query = "BEGIN";
res = PQexec(pd, query);
if(PQresultStatus(res)!=PGRES_COMMAND_OK){
qWarning(PQresultErrorMessage(res));
QMessageBox::warning(pro, "Import Shapefiles", error);
pro->setProgress(pro->progress()+(tblShapefiles->text(i,2)).toInt());
continue;
}
else {
PQclear(res);
}
query = "SET SEARCH_PATH TO \'"+tblShapefiles->text(i,4)+"\'";
res = PQexec(pd, query);
qWarning(query);
if(PQresultStatus(res)!=PGRES_COMMAND_OK){
qWarning(PQresultErrorMessage(res));
qWarning(PQresStatus(PQresultStatus(res)));
QMessageBox::warning(pro, "Import Shapefiles", error);
pro->setProgress(pro->progress()+(tblShapefiles->text(i,2)).toInt());
continue;
}
else {
PQclear(res);
}
QMessageBox *del_confirm;
if(rel_exists1 || rel_exists2){
del_confirm = new QMessageBox("Import Shapefiles - Relation Exists",
"The Shapefile:\n"+fileList[i]->getName()+"\nwill use ["+
QString(fileList[i]->getTable())+"] relation for its data,\nwhich already exists and possibly contains data.\n"+
"The Shapefile:\n"+tblShapefiles->text(i,0)+"\nwill use ["+
tblShapefiles->text(i,3)+"] relation for its data,\nwhich already exists and possibly contains data.\n"+
"To avoid data loss change the \"DB Relation Name\" \nfor this Shapefile in the main dialog file list.\n\n"+
"Do you want to overwrite the ["+fileList[i]->getTable()+"] relation?",
"Do you want to overwrite the ["+tblShapefiles->text(i,3)+"] relation?",
QMessageBox::Warning,
QMessageBox::Yes | QMessageBox::Default,
QMessageBox::No | QMessageBox::Escape,
QMessageBox::NoButton, pro, "Relation Exists");
QMessageBox::NoButton, this, "Relation Exists");
if(del_confirm->exec() == QMessageBox::Yes){
if (rel_exists2){
query = "DROP TABLE " + tblShapefiles->text(i,3);
qWarning(query);
res = PQexec(pd, (const char *)query);
if(PQresultStatus(res)!=PGRES_COMMAND_OK){
qWarning(PQresultErrorMessage(res));
QMessageBox::warning(pro, "Import Shapefiles", error);
pro->setProgress(pro->progress()+(tblShapefiles->text(i,2)).toInt());
continue;
}
else {
PQclear(res);
}
}
if(rel_exists1){
/*query = "SELECT DropGeometryColumn(\'"+QString(settings.readEntry(key + "/database"))+"\', \'"+
fileList[i]->getTable()+"\', \'"+txtGeomName->text()+"')";*/
query = "DELETE FROM geometry_columns WHERE f_table_schema=\'"+tblShapefiles->text(i,4)+"\' AND "+
"f_table_name=\'"+tblShapefiles->text(i,3)+"\'";
qWarning(query);
res = PQexec(pd, (const char *)query);
if(PQresultStatus(res)!=PGRES_COMMAND_OK){
qWarning(PQresultErrorMessage(res));
QMessageBox::warning(pro, "Import Shapefiles", error);
pro->setProgress(pro->progress()+(tblShapefiles->text(i,2)).toInt());
continue;
}
else {
PQclear(res);
}
}
}
else {
query = "ROLLBACK";
res = PQexec(pd, query);
if(PQresultStatus(res)!=PGRES_COMMAND_OK){
qWarning(PQresultErrorMessage(res));
QMessageBox::warning(pro, "Import Shapefiles", error);
}
else {
PQclear(res);
}
pro->setProgress(pro->progress()+(tblShapefiles->text(i,2)).toInt());
continue;
}
}
if ((!rel_exists1 && !rel_exists2) || del_confirm->exec() == QMessageBox::Yes){
if(rel_exists1){
query = "SELECT DropGeometryColumn(\'"+QString(settings.readEntry(key + "/database"))+"\', \'"+
fileList[i]->getTable()+"\', \'"+txtGeomName->text()+"')";
res = PQexec(pd, (const char *)query);
// importing file here
int temp_progress = pro->progress();
cancelled = false;
if(fileList[i]->insertLayer(settings.readEntry(key + "/database"), txtGeomName->text(),
QString("%1").arg(spinSrid->value()), pd, pro, cancelled) && !cancelled)
{ // if file has been imported successfully
query = "COMMIT";
res = PQexec(pd, query);
if(PQresultStatus(res)!=PGRES_COMMAND_OK){
qWarning(PQresultErrorMessage(res));
QMessageBox::warning(pro, "Import Shapefiles", error);
continue;
}
else {
PQclear(res);
}
if(rel_exists2){
query = "DROP TABLE " + fileList[i]->getTable();
res = PQexec(pd, (const char *)query);
PQclear(res);
}
if(!fileList[i]->insertLayer(settings.readEntry(key + "/database"), txtGeomName->text(),
QString("%1").arg(spinSrid->value()), pd, pro, finished)){
if(!finished){
QMessageBox::warning(pro, "Import Shapefiles",
"Problem inserting features from file:\n"+fileList[i]->getName());
PQexec(pd, "ROLLBACK");
// remove file
for(int j=0; j<tblShapefiles->numRows(); j++){
if(tblShapefiles->text(j,0)==QString(fileList[i]->getName())){
tblShapefiles->selectRow(j);
removeFile();
i--;
break;
}
}
else{ // if file has been imported, remove it from the list
PQexec(pd, "COMMIT");
for(int j=0; j<tblShapefiles->numRows(); j++)
if(tblShapefiles->text(j,0)==QString(fileList[i]->getName())){
tblShapefiles->selectRow(j);
removeFile();
i--;
break;
}
}
}
else{
pro->setProgress(pro->progress()+fileList[i]->getFeatureCount());
}
else if(!cancelled){ // if problem importing file occured
pro->setProgress(temp_progress+(tblShapefiles->text(i,2)).toInt());
QMessageBox::warning(this, "Import Shapefiles", error);
query = "ROLLBACK";
res = PQexec(pd, query);
if(PQresultStatus(res)!=PGRES_COMMAND_OK){
qWarning(PQresultErrorMessage(res));
QMessageBox::warning(pro, "Import Shapefiles", error);
}
else {
PQclear(res);
}
}
else{ // if import was actually cancelled
delete pro;
break;
}
}
}
else
QMessageBox::warning(this, "Import Shapefiles", "Connection failed - Check settings and try again");
PQfinish(pd);
}
else
QMessageBox::warning(this, "Import Shapefiles", "You need to specify a Connection first");
}

View File

@ -198,30 +198,6 @@
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QPushButton" row="0" column="0">
<property name="name">
<cstring>btnAddFile</cstring>
</property>
<property name="text">
<string>Add ...</string>
</property>
</widget>
<widget class="QPushButton" row="0" column="1">
<property name="name">
<cstring>btnRemoveFile</cstring>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
<widget class="QPushButton" row="0" column="2" rowspan="1" colspan="2">
<property name="name">
<cstring>btnRemoveAll</cstring>
</property>
<property name="text">
<string>Remove All</string>
</property>
</widget>
<widget class="QTable" row="4" column="0" rowspan="1" colspan="6">
<column>
<property name="text">
@ -243,6 +219,11 @@
<string>DB Relation Name</string>
</property>
</column>
<column>
<property name="text">
<string>Schema</string>
</property>
</column>
<property name="name">
<cstring>tblShapefiles</cstring>
</property>
@ -250,7 +231,7 @@
<number>0</number>
</property>
<property name="numCols">
<number>4</number>
<number>5</number>
</property>
<property name="showGrid">
<bool>false</bool>
@ -265,7 +246,7 @@
<enum>FollowStyle</enum>
</property>
</widget>
<widget class="QSpinBox" row="2" column="1">
<widget class="QSpinBox" row="2" column="1" rowspan="1" colspan="2">
<property name="name">
<cstring>spinSrid</cstring>
</property>
@ -311,23 +292,6 @@
<string>SRID</string>
</property>
</widget>
<spacer row="0" column="4" rowspan="1" colspan="2">
<property name="name">
<cstring>spacer8</cstring>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>241</width>
<height>31</height>
</size>
</property>
</spacer>
<widget class="QLineEdit" row="2" column="5">
<property name="name">
<cstring>txtGeomName</cstring>
@ -347,6 +311,47 @@
<enum>Horizontal</enum>
</property>
</widget>
<widget class="QPushButton" row="0" column="0" rowspan="1" colspan="2">
<property name="name">
<cstring>btnAddFile</cstring>
</property>
<property name="text">
<string>Add ...</string>
</property>
</widget>
<widget class="QPushButton" row="0" column="2" rowspan="1" colspan="2">
<property name="name">
<cstring>btnRemoveFile</cstring>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
<widget class="QPushButton" row="0" column="4">
<property name="name">
<cstring>btnRemoveAll</cstring>
</property>
<property name="text">
<string>Remove All</string>
</property>
</widget>
<spacer row="0" column="5">
<property name="name">
<cstring>spacer7</cstring>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>201</width>
<height>41</height>
</size>
</property>
</spacer>
</grid>
</widget>
</grid>