Skip to content

Commit 25470f2

Browse files
author
g_j_m
committedMar 16, 2006
Further progress on dealing with slowness in populating the database
layer selection dialog box. Changes to code for selecting layer type icon git-svn-id: http://svn.osgeo.org/qgis/trunk@5040 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent b22661e commit 25470f2

File tree

2 files changed

+216
-68
lines changed

2 files changed

+216
-68
lines changed
 

‎src/gui/qgsdbsourceselect.cpp

Lines changed: 165 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,13 @@ email : sherman at mrcc.com
3030
#include <QSettings>
3131
#include <QTextOStream>
3232
#include <QTableWidgetItem>
33-
#include <QIcon>
3433
#include <QHeaderView>
3534

3635
#include <cassert>
3736
#include <iostream>
3837

3938
QgsDbSourceSelect::QgsDbSourceSelect(QgisApp *app, Qt::WFlags fl)
40-
: QDialog(app, fl), qgisApp(app)
39+
: QDialog(app, fl), qgisApp(app), mColumnTypeThread(NULL)
4140
{
4241
setupUi(this);
4342
btnAdd->setEnabled(false);
@@ -105,9 +104,9 @@ QgsDbSourceSelect::QgsDbSourceSelect(QgisApp *app, Qt::WFlags fl)
105104

106105
// Do some things that couldn't be done in designer
107106
lstTables->horizontalHeader()->setStretchLastSection(true);
107+
QStringList labels;
108108
// Set the column count to 3 for the type, name, and sql
109109
lstTables->setColumnCount(3);
110-
QStringList labels;
111110
labels += tr("Type"); labels += tr("Name"); labels += tr("Sql");
112111
lstTables->setHorizontalHeaderLabels(labels);
113112
lstTables->verticalHeader()->hide();
@@ -148,6 +147,59 @@ void QgsDbSourceSelect::on_btnHelp_clicked()
148147
}
149148
/** End Autoconnected SLOTS **/
150149

150+
void QgsDbSourceSelect::setLayerType(QString schema,
151+
QString table, QString column,
152+
QString type)
153+
{
154+
#ifdef QGISDEBUG
155+
std::cerr << "Received layer type of " << type.toLocal8Bit().data()
156+
<< " for "
157+
<< (schema+'.'+table+'.'+column).toLocal8Bit().data()
158+
<< '\n';
159+
#endif
160+
161+
// Find the right row in the table by searching for the text that
162+
// was put into the Name column.
163+
QString full_desc = fullDescription(schema, table, column);
164+
165+
QList<QTableWidgetItem*> ii = lstTables->findItems(full_desc,
166+
Qt::MatchExactly);
167+
168+
if (ii.count() > 0)
169+
{
170+
int row = lstTables->row(ii.at(0)); // just use the first one
171+
QTableWidgetItem* iconItem = lstTables->item(row, 0);
172+
173+
// Get the icon and tooltip text
174+
const QIcon* p;
175+
QString toolTipText;
176+
if (mLayerIcons.contains(type))
177+
{
178+
p = &(mLayerIcons.value(type).second);
179+
toolTipText = mLayerIcons.value(type).first;
180+
}
181+
else
182+
{
183+
qDebug(("Unknown geometry type of " + type).toLocal8Bit().data());
184+
p = &(mLayerIcons.value("UNKNOWN").second);
185+
toolTipText = mLayerIcons.value("UNKNOWN").first;
186+
}
187+
188+
iconItem->setIcon(*p);
189+
iconItem->setToolTip(toolTipText);
190+
}
191+
}
192+
193+
QString QgsDbSourceSelect::makeGeomQuery(QString schema,
194+
QString table, QString column)
195+
{
196+
QString query = "select GeometryType(" + column + ") from ";
197+
if (schema.length() > 0)
198+
query += "\"" + schema + "\".";
199+
query += "\"" + table + "\" where " + column + " is not null limit 1";
200+
return query;
201+
}
202+
151203
QgsDbSourceSelect::~QgsDbSourceSelect()
152204
{
153205
PQfinish(pd);
@@ -278,13 +330,31 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
278330
{
279331
// create the pixmaps for the layer types
280332
QString myThemePath = QgsApplication::themePath();
281-
QIcon pxPoint(myThemePath+"/mIconPointLayer.png");
282-
QIcon pxLine(myThemePath+"/mIconLineLayer.png");
283-
QIcon pxPoly(myThemePath+"/mIconPolygonLayer.png");
284-
QIcon pxWaiting(myThemePath+"/mIconWaitingForLayerType.png");
285-
QIcon pxUnknown(myThemePath+"/mIconUnknownLayerType.png");
333+
mLayerIcons.insert(QString("POINT"),
334+
qMakePair(tr("Point layer"),
335+
QIcon(myThemePath+"/mIconPointLayer.png")));
336+
mLayerIcons.insert(QString("MULTIPOINT"),
337+
qMakePair(tr("Multi-point layer"),
338+
QIcon(myThemePath+"/mIconPointLayer.png")));
339+
mLayerIcons.insert(QString("LINESTRING"),
340+
qMakePair(tr("Linestring layer"),
341+
QIcon(myThemePath+"/mIconLineLayer.png")));
342+
mLayerIcons.insert(QString("MULTILINESTRING"),
343+
qMakePair(tr("Multi-linestring layer"),
344+
QIcon(myThemePath+"/mIconLineLayer.png")));
345+
mLayerIcons.insert(QString("POLYGON"),
346+
qMakePair(tr("Polygon layer"),
347+
QIcon(myThemePath+"/mIconPolygonLayer.png")));
348+
mLayerIcons.insert(QString("MULTIPOLYGON"),
349+
qMakePair(tr("Multi-polygon layer"),
350+
QIcon(myThemePath+"/mIconPolygonLayer.png")));
351+
mLayerIcons.insert(QString("WAITING"),
352+
qMakePair(tr("Waiting for layer type"),
353+
QIcon(myThemePath+"/mIconWaitingForLayerType.png")));
354+
mLayerIcons.insert(QString("UNKNOWN"),
355+
qMakePair(tr("Unknown layer type"),
356+
QIcon(myThemePath+"/mIconUnknownLayerType.png")));
286357

287-
assert (!pxPoint.isNull());
288358
//qDebug("Connection succeeded");
289359
// tell the DB that we want text encoded in UTF8
290360
PQsetClientEncoding(pd, "UNICODE");
@@ -299,47 +369,18 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
299369
for (; iter != details.end(); ++iter)
300370
{
301371
QString toolTipText;
302-
QIcon *p = 0;
303-
if (iter->second == "POINT")
304-
{
305-
p = &pxPoint;
306-
toolTipText = tr("Point layer");
307-
}
308-
else if (iter->second == "MULTIPOINT")
309-
{
310-
p = &pxPoint;
311-
toolTipText = tr("Multi-point layer");
312-
}
313-
else if (iter->second == "MULTIPOLYGON")
314-
{
315-
p = &pxPoly;
316-
toolTipText = tr("Multi-polygon layer");
317-
}
318-
else if (iter->second == "POLYGON")
319-
{
320-
p = &pxPoly;
321-
toolTipText = tr("Polygon layer");
322-
}
323-
else if (iter->second == "LINESTRING")
324-
{
325-
p = &pxLine;
326-
toolTipText = tr("Linestring layer");
327-
}
328-
else if (iter->second == "MULTILINESTRING")
329-
{
330-
p = &pxLine;
331-
toolTipText = tr("Multi-linestring layer");
332-
}
333-
else if (iter->second == "WAITING")
372+
const QIcon* p;
373+
374+
if (mLayerIcons.contains(iter->second))
334375
{
335-
p = &pxWaiting;
336-
toolTipText = tr("Waiting for layer type");
376+
p = &(mLayerIcons.value(iter->second).second);
377+
toolTipText = mLayerIcons.value(iter->second).first;
337378
}
338379
else
339380
{
340381
qDebug(("Unknown geometry type of " + iter->second).toLocal8Bit().data());
341-
toolTipText = tr("Unknown layer type");
342-
p = &pxUnknown;
382+
p = &(mLayerIcons.value("UNKNOWN").second);
383+
toolTipText = mLayerIcons.value("UNKNOWN").first;
343384
}
344385

345386
if (p != 0)
@@ -349,11 +390,6 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
349390
iconItem->setToolTip(toolTipText);
350391
QTableWidgetItem *textItem = new QTableWidgetItem(iter->first);
351392
int row = lstTables->rowCount();
352-
std::cerr << "Adding database table with name '"
353-
<< iter->first.toLocal8Bit().data()
354-
<< "' and tooltip '"
355-
<< toolTipText.toLocal8Bit().data()
356-
<< "' at row " << row+1 << ".\n";
357393
lstTables->setRowCount(row+1);
358394
lstTables->setItem(row, 0, iconItem);
359395
lstTables->setItem(row, 1, textItem);
@@ -370,6 +406,25 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
370406
// And tidy up the columns & rows
371407
lstTables->resizeColumnsToContents();
372408
lstTables->resizeRowsToContents();
409+
410+
// Start the thread that gets the geometry type for relations that
411+
// may take a long time to return
412+
if (mColumnTypeThread != NULL)
413+
{
414+
connect(mColumnTypeThread,
415+
SIGNAL(setLayerType(QString,QString,QString,QString)),
416+
this,
417+
SLOT(setLayerType(QString,QString,QString,QString)));
418+
// Do it in a thread. Does not yet cope correctly with the
419+
// layer selection dialog box closing before the thread
420+
// completes, nor the qgis process ending before the
421+
// thread completes, nor does the thread know to stop working
422+
// when the user chooses a layer.
423+
// mColumnTypeThread->run();
424+
425+
// do it in this process for the moment.
426+
mColumnTypeThread->getLayerTypes();
427+
}
373428
}
374429
else
375430
{
@@ -522,40 +577,35 @@ bool QgsDbSourceSelect::getGeometryColumnInfo(PGconn *pg,
522577
QString column = PQgetvalue(result, i, 2); // attname
523578
QString relkind = PQgetvalue(result, i, 3); // relation kind
524579

525-
QString type = "WAITING";
526-
if (relkind == "r" || relkind == "v")
527-
{
528-
QString query = "select GeometryType(" + column + ") from ";
529-
if (schema.length() > 0)
530-
query += "\"" + schema + "\".";
531-
query += "\"" + table + "\" where " + column + " is not null limit 1";
580+
QString full_desc = fullDescription(schema, table, column);
532581

582+
QString type = "UNKNOWN";
583+
if (relkind == "r")
584+
{
585+
QString query = makeGeomQuery(schema, table, column);
533586
PGresult* gresult = PQexec(pg, query.toLocal8Bit().data());
534587
if (PQresultStatus(gresult) != PGRES_TUPLES_OK)
535588
{
536589
QString myError = (tr("Access to relation ") + table + tr(" using sql;\n") + query +
537590
tr("\nhas failed. The database said:\n"));
538591
qDebug(myError + QString(PQresultErrorMessage(gresult)));
539-
type = "UNKNOWN";
540592
}
541593
else
542594
type = PQgetvalue(gresult, 0, 0); // GeometryType
543595
PQclear(gresult);
544596
}
545-
/*
546-
// Commented out temporarily...
547597
else // view
548598
{
549599
// store the column details and do the query in a thread
550-
std::cout << "Doing " << (schema+'.'+table+'.'+column).toLocal8Bit().data()
551-
<< " later" << std::endl;
600+
if (mColumnTypeThread == NULL)
601+
{
602+
mColumnTypeThread = new QgsGeomColumnTypeThread();
603+
mColumnTypeThread->setConnInfo(m_connInfo);
604+
}
605+
mColumnTypeThread->setGeometryColumn(schema, table, column);
606+
type = "WAITING";
552607
}
553-
*/
554608

555-
QString full_desc = "";
556-
if (schema.length() > 0)
557-
full_desc = schema + ".";
558-
full_desc += table + " (" + column + ")";
559609
details.push_back(geomPair(full_desc, type));
560610
}
561611
ok = true;
@@ -572,13 +622,23 @@ void QgsDbSourceSelect::showHelp()
572622
{
573623
QgsContextHelp::run(context_id);
574624
}
625+
QString QgsDbSourceSelect::fullDescription(QString schema, QString table,
626+
QString column)
627+
{
628+
QString full_desc = "";
629+
if (schema.length() > 0)
630+
full_desc = schema + ".";
631+
full_desc += table + " (" + column + ")";
632+
return full_desc;
633+
}
575634
void QgsDbSourceSelect::dbChanged()
576635
{
577636
// Remember which database was selected.
578637
QSettings settings;
579638
settings.writeEntry("/PostgreSQL/connections/selected",
580639
cmbConnections->currentText());
581640
}
641+
582642
void QgsDbSourceSelect::setConnectionListPosition()
583643
{
584644
QSettings settings;
@@ -609,3 +669,41 @@ void QgsDbSourceSelect::setConnectionListPosition()
609669
cmbConnections->setCurrentItem(cmbConnections->count()-1);
610670
}
611671
}
672+
673+
void QgsGeomColumnTypeThread::setConnInfo(QString s)
674+
{
675+
mConnInfo = s;
676+
}
677+
678+
void QgsGeomColumnTypeThread::setGeometryColumn(QString schema, QString table, QString column)
679+
{
680+
schemas.push_back(schema);
681+
tables.push_back(table);
682+
columns.push_back(column);
683+
}
684+
685+
void QgsGeomColumnTypeThread::getLayerTypes()
686+
{
687+
PGconn *pd = PQconnectdb(mConnInfo.toLocal8Bit().data());
688+
if (PQstatus(pd) == CONNECTION_OK)
689+
{
690+
PQsetClientEncoding(pd, "UNICODE");
691+
692+
for (int i = 0; i < schemas.size(); ++i)
693+
{
694+
QString query = QgsDbSourceSelect::makeGeomQuery(schemas[i],
695+
tables[i],
696+
columns[i]);
697+
PGresult* gresult = PQexec(pd, query.toLocal8Bit().data());
698+
QString type;
699+
if (PQresultStatus(gresult) == PGRES_TUPLES_OK)
700+
type = PQgetvalue(gresult, 0, 0);
701+
PQclear(gresult);
702+
703+
// Now tell the layer list dialog box...
704+
emit setLayerType(schemas[i], tables[i], columns[i], type);
705+
}
706+
}
707+
708+
PQfinish(pd);
709+
}

‎src/gui/qgsdbsourceselect.h

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,17 @@ extern "C"
2424
#include <libpq-fe.h>
2525
}
2626

27+
#include <QThread>
28+
2729
#include <vector>
2830
#include <utility>
2931

32+
#include <QMap>
33+
#include <QPair>
34+
#include <QIcon>
35+
3036
class QTableWidgetItem;
37+
class QgsGeomColumnTypeThread;
3138
class QgisApp;
3239
/*! \class QgsDbSourceSelect
3340
* \brief Dialog to create connections and add tables from PostgresQL.
@@ -63,6 +70,10 @@ class QgsDbSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
6370
QString encoding();
6471
// Store the selected database
6572
void dbChanged();
73+
// Utility function to construct the query for finding out the
74+
// geometry type of a column
75+
static QString makeGeomQuery(QString schema, QString table, QString column);
76+
6677
public slots:
6778
/*! Connects to the database using the stored connection parameters.
6879
* Once connected, available layers are displayed.
@@ -75,6 +86,8 @@ class QgsDbSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
7586
void on_lstTables_itemDoubleClicked(QTableWidgetItem *);
7687
void setSql(QTableWidgetItem *);
7788
void on_btnHelp_clicked();
89+
void setLayerType(QString schema, QString table, QString column,
90+
QString type);
7891
private:
7992

8093
typedef std::pair<QString, QString> geomPair;
@@ -87,14 +100,51 @@ class QgsDbSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
87100
void setConnectionListPosition();
88101
// Show the context help for the dialog
89102
void showHelp();
90-
103+
// Combine the schema, table and column data into a single string
104+
// useful for display to the user
105+
QString fullDescription(QString schema, QString table, QString column);
106+
// Our thread for doing long running queries
107+
QgsGeomColumnTypeThread* mColumnTypeThread;
91108
QString m_connInfo;
92109
QStringList m_selectedTables;
110+
// Storage for the range of layer type icons
111+
QMap<QString, QPair<QString, QIcon> > mLayerIcons;
93112
//! Pointer to the qgis application mainwindow
94113
QgisApp *qgisApp;
95114
PGconn *pd;
96115
static const int context_id = 1244423922;
97116
};
98117

99118

119+
// Perhaps this class should be in its own file??
120+
//
121+
// A class that determines the geometry type of a given database
122+
// schema.table.column, with the option of doing so in a separate
123+
// thread.
124+
125+
class QgsGeomColumnTypeThread : public QThread
126+
{
127+
Q_OBJECT
128+
public:
129+
130+
void setConnInfo(QString s);
131+
void setGeometryColumn(QString schema, QString table, QString column);
132+
133+
// These functions get the layer types and pass that information out
134+
// by emitting the setLayerType() signal. The getLayerTypes()
135+
// function does the actual work, but use the run() function if you
136+
// want the work to be done as a separate thread from the calling
137+
// process.
138+
virtual void run() { getLayerTypes(); }
139+
void getLayerTypes();
140+
141+
signals:
142+
void setLayerType(QString schema, QString table, QString column,
143+
QString type);
144+
145+
private:
146+
QString mConnInfo;
147+
std::vector<QString> schemas, tables, columns;
148+
};
149+
100150
#endif // QGSDBSOURCESELECT_H

0 commit comments

Comments
 (0)
Please sign in to comment.