ticket897patch.diff

Fernando Pacheco -, 2008-01-10 07:00 PM

Download (20.9 KB)

View differences:

src/app/qgspgquerybuilder.cpp (copia de trabajo)
14 14
 ***************************************************************************/
15 15
/* $Id$ */
16 16
#include <iostream>
17
#include <q3listbox.h>
18 17
#include <QMessageBox>
18
#include <QListView>
19 19
#include "qgspgquerybuilder.h"
20 20
#include <qgslogger.h>
21 21
#include <QRegExp>
......
24 24
: QDialog(parent, fl)
25 25
{
26 26
  setupUi(this);
27
  setupListViews();
27 28
}
28 29
// constructor used when the query builder must make its own
29 30
// connection to the database
......
32 33
: QDialog(parent, fl), mUri(uri)
33 34
{
34 35
  setupUi(this);
36
  setupListViews();
35 37
  // The query builder must make its own connection to the database when
36 38
  // using this constructor
37 39
  QString connInfo = mUri->connInfo();
......
69 71
: QDialog(parent, fl), mPgConnection(con)
70 72
{
71 73
  setupUi(this);
74
  setupListViews();
72 75
  mOwnConnection = false; // we don't own this connection since it was passed to us
73 76
  mUri = new QgsDataSourceURI( "table=" + tableName);
74 77
  QString datasource = QString(tr("Table <b>%1</b> in database <b>%2</b> on host <b>%3</b>, user <b>%4</b>"))
......
133 136
#endif
134 137
      QVariant::Type type = QVariant::String; // TODO: should be set correctly [MD]
135 138
      mFieldMap[fieldName] = QgsField(fieldName, type, fieldType);
136
      lstFields->insertItem(fieldName);
139
      QStandardItem *myItem = new QStandardItem(fieldName);
140
      myItem->setEditable(false);
141
      mModelFields->insertRow(mModelFields->rowCount(),myItem);
137 142
    }
138 143
  }
139 144
  else
......
143 148
  PQclear(result);
144 149
}
145 150

  
151
void QgsPgQueryBuilder::setupListViews()
152
{
153
  //Models
154
  mModelFields = new QStandardItemModel();
155
  mModelValues = new QStandardItemModel();
156
  lstFields->setModel(mModelFields);
157
  lstValues->setModel(mModelValues);
158
  // Modes
159
  lstFields->setViewMode(QListView::ListMode);
160
  lstValues->setViewMode(QListView::ListMode);
161
  lstFields->setSelectionBehavior(QAbstractItemView::SelectRows);
162
  lstValues->setSelectionBehavior(QAbstractItemView::SelectRows);
163
  // Performance tip since Qt 4.1
164
  lstFields->setUniformItemSizes(true);
165
  lstValues->setUniformItemSizes(true);
166
}
167

  
146 168
void QgsPgQueryBuilder::on_btnSampleValues_clicked()
147 169
{
148
  if (lstFields->currentText().isEmpty())
170
  QString myFieldName = mModelFields->data(lstFields->currentIndex()).toString();
171
  if (myFieldName.isEmpty())
149 172
      return;
150 173

  
151
  QString sql = "SELECT DISTINCT \"" + lstFields->currentText() + "\" " +
152
      "FROM (SELECT \"" + lstFields->currentText() + "\" " +
174
  QString sql = "SELECT DISTINCT \"" + myFieldName + "\" " +
175
      "FROM (SELECT \"" + myFieldName + "\" " +
153 176
      "FROM " + mUri->quotedTablename() + " " +
154 177
      "LIMIT 5000) AS foo " +
155
      "ORDER BY \"" + lstFields->currentText() + "\" "+
178
      "ORDER BY \"" + myFieldName + "\" "+
156 179
      "LIMIT 25";
157 180
  // clear the values list 
158
  lstValues->clear();
181
  mModelValues->clear();
159 182
  // determine the field type
160
  QgsField field = mFieldMap[lstFields->currentText()];
183
  QgsField field = mFieldMap[myFieldName];
161 184
  bool isCharField = field.typeName().find("char") > -1;
162 185
  PGresult *result = PQexec(mPgConnection, (const char *) (sql.utf8()));
163 186

  
......
169 192
      QString value = QString::fromUtf8(PQgetvalue(result, i, 0));
170 193
      if(isCharField)
171 194
      {
172
        lstValues->insertItem("'" + value + "'");
195
        value = "'" + value + "'";
173 196
      }
174
      else
175
      {
176
        lstValues->insertItem(value);
177
      }
197
      QStandardItem *myItem = new QStandardItem(value);
198
      myItem->setEditable(false);
199
      mModelValues->insertRow(mModelValues->rowCount(),myItem);
178 200
    }
179

  
180 201
  }else
181 202
  {
182 203
    QMessageBox::warning(this, tr("Database error"), tr("<p>Failed to get sample of field values using SQL:</p><p>") + sql + "</p><p>Error message was: "+ QString(PQerrorMessage(mPgConnection)) + "</p>");
......
187 208

  
188 209
void QgsPgQueryBuilder::on_btnGetAllValues_clicked()
189 210
{
190
  if (lstFields->currentText().isEmpty())
211
  QString myFieldName = mModelFields->data(lstFields->currentIndex()).toString();
212
  if (myFieldName.isEmpty())
191 213
      return;
192 214

  
193
  QString sql = "select distinct \"" + lstFields->currentText() 
194
    + "\" from " + mUri->quotedTablename() + " order by \"" + lstFields->currentText() + "\"";
215
  QString sql = "select distinct \"" + myFieldName
216
      + "\" from " + mUri->quotedTablename() + " order by \"" + myFieldName + "\"";
195 217
  // clear the values list 
196
  lstValues->clear();
218
  mModelValues->clear();
197 219
  // determine the field type
198
  QgsField field = mFieldMap[lstFields->currentText()];
220
  QgsField field = mFieldMap[myFieldName];
199 221
  bool isCharField = field.typeName().find("char") > -1;
200 222

  
201 223
  PGresult *result = PQexec(mPgConnection, (const char *) (sql.utf8()));
......
203 225
  if (PQresultStatus(result) == PGRES_TUPLES_OK) 
204 226
  {
205 227
    int rowCount =  PQntuples(result);
228
    
229
    lstValues->setCursor(Qt::WaitCursor);
230
    // Block for better performance
231
    mModelValues->blockSignals(true);
232
    lstValues->setUpdatesEnabled(false);
233
    
206 234
    for(int i=0; i < rowCount; i++)
207 235
    {
208 236
      QString value = QString::fromUtf8(PQgetvalue(result, i, 0));
209

  
210 237
      if(isCharField)
211 238
      {
212
        lstValues->insertItem("'" + value + "'");
239
        value = "'" + value + "'";
213 240
      }
214
      else
215
      {
216
        lstValues->insertItem(value);
217
      }
241
      QStandardItem *myItem = new QStandardItem(value);
242
      myItem->setEditable(false);
243
      mModelValues->insertRow(mModelValues->rowCount(),myItem);
218 244
    }
219

  
245
    
246
    // Unblock for normal use
247
    mModelValues->blockSignals(false);
248
    lstValues->setUpdatesEnabled(true);
249
    // TODO: already sorted, signal emit to refresh model 
250
    mModelValues->sort(0);
251
    lstValues->setCursor(Qt::ArrowCursor);
252
    
220 253
  }else
221 254
  {
222 255
    QMessageBox::warning(this, tr("Database error"), tr("Failed to get sample of field values") + QString(PQerrorMessage(mPgConnection)) );
......
365 398
  txtSQL->setText(sqlStatement);
366 399
}
367 400

  
368
void QgsPgQueryBuilder::on_lstFields_doubleClicked( Q3ListBoxItem *item )
401
void QgsPgQueryBuilder::on_lstFields_doubleClicked( const QModelIndex &index )
369 402
{
370
  txtSQL->insert("\"" + item->text() + "\"");
403
  txtSQL->insert("\"" + mModelFields->data(index).toString() + "\"");
371 404
}
372 405

  
373
void QgsPgQueryBuilder::on_lstValues_doubleClicked( Q3ListBoxItem *item )
406
void QgsPgQueryBuilder::on_lstValues_doubleClicked( const QModelIndex &index )
374 407
{
375
  txtSQL->insert(item->text());
408
  txtSQL->insert(mModelValues->data(index).toString());
376 409
}
377 410

  
378 411
void QgsPgQueryBuilder::on_btnLessEqual_clicked()
src/app/qgspgquerybuilder.h (copia de trabajo)
20 20
{
21 21
#include <libpq-fe.h>
22 22
}
23

  
23
#include <QStandardItemModel>
24
#include <QStandardItem>
25
#include <QModelIndex>
24 26
#include "ui_qgspgquerybuilderbase.h"
25 27
#include "qgisgui.h"
26 28
#include "qgsfield.h"
......
85 87
    void on_btnILike_clicked();
86 88
    QString sql();
87 89
    void setSql( QString sqlStatement);
88
    void on_lstFields_doubleClicked( Q3ListBoxItem *item );
89
    void on_lstValues_doubleClicked( Q3ListBoxItem *item );
90
    void on_lstFields_doubleClicked( const QModelIndex &index );
91
    void on_lstValues_doubleClicked( const QModelIndex &index );
90 92
    void on_btnLessEqual_clicked();
91 93
    void on_btnGreaterEqual_clicked();
92 94
    void on_btnNotEqual_clicked();
......
118 120
   * Populate the field list for the selected table
119 121
   */ 
120 122
  void populateFields();
123
  /*! 
124
   * Setup models for listviews
125
   */ 
126
  void setupListViews();
121 127

  
122 128
  /*! Get the number of records that would be returned by the current SQL
123 129
   * @return Number of records or -1 if an error was encountered
......
139 145
  QString mPgErrorMessage;
140 146
  //! Flag to indicate if the class owns the connection to the pg database
141 147
  bool mOwnConnection;
142

  
148
  //! Model for fields ListView
149
  QStandardItemModel *mModelFields;
150
  //! Model for values ListView
151
  QStandardItemModel *mModelValues;
143 152
};
144 153
#endif //QGSPGQUERYBUILDER_H
src/app/qgssearchquerybuilder.cpp (copia de trabajo)
15 15
/* $Id$ */
16 16

  
17 17
#include <iostream>
18
#include <q3listbox.h>
18
#include <QListView>
19 19
#include <QMessageBox>
20
#include <QStandardItem>
20 21
#include "qgsfeature.h"
21 22
#include "qgsfield.h"
22 23
#include "qgssearchquerybuilder.h"
......
31 32
  : QDialog(parent, fl), mLayer(layer)
32 33
{
33 34
  setupUi(this);
35
  setupListViews();
34 36
  
35 37
  setWindowTitle(tr("Search query builder"));
36 38
  
......
53 55

  
54 56
void QgsSearchQueryBuilder::populateFields()
55 57
{
58
#ifdef QGISDEBUG
59
  std::cout << "QgsSearchQueryBuilder::populateFields" << std::endl;
60
#endif
56 61
  const QgsFieldMap& fields = mLayer->getDataProvider()->fields();
57 62
  for (QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it)
58 63
  {
59 64
    QString fieldName = it->name();
60
    
61 65
    mFieldMap[fieldName] = it.key();
62
    lstFields->insertItem(fieldName);
66
    QStandardItem *myItem = new QStandardItem(fieldName);
67
    myItem->setEditable(false);
68
    mModelFields->insertRow(mModelFields->rowCount(),myItem);
63 69
  }
64 70
}
65 71

  
72
void QgsSearchQueryBuilder::setupListViews()
73
{
74
#ifdef QGISDEBUG
75
  std::cout << "QgsSearchQueryBuilder::setupListViews" << std::endl;
76
#endif
77
  //Models
78
  mModelFields = new QStandardItemModel();
79
  mModelValues = new QStandardItemModel();
80
  lstFields->setModel(mModelFields);
81
  lstValues->setModel(mModelValues);
82
  // Modes
83
  lstFields->setViewMode(QListView::ListMode);
84
  lstValues->setViewMode(QListView::ListMode);
85
  lstFields->setSelectionBehavior(QAbstractItemView::SelectRows);
86
  lstValues->setSelectionBehavior(QAbstractItemView::SelectRows);
87
  // Performance tip since Qt 4.1
88
  lstFields->setUniformItemSizes(true);
89
  lstValues->setUniformItemSizes(true);
90
}
91

  
66 92
void QgsSearchQueryBuilder::getFieldValues(uint limit)
67 93
{
68 94
  // clear the values list 
69
  lstValues->clear();
95
  mModelValues->clear();
70 96
  
71 97
  QgsVectorDataProvider* provider = mLayer->getDataProvider();
72 98
  
73 99
  // determine the field type
74
  QString fieldName = lstFields->currentText();
100
  QString fieldName = mModelFields->data(lstFields->currentIndex()).toString();
75 101
  int fieldIndex = mFieldMap[fieldName];
76 102
  QgsField field = provider->fields()[fieldIndex];
77 103
  bool numeric = (field.type() == QVariant::Int || field.type() == QVariant::Double);
......
84 110
  
85 111
  provider->select(attrs, QgsRect(), false);
86 112
  
113
  lstValues->setCursor(Qt::WaitCursor);
114
  // Block for better performance
115
  mModelValues->blockSignals(true);
116
  lstValues->setUpdatesEnabled(false);
117
  
87 118
  while (provider->getNextFeature(feat) &&
88
         (limit == 0 || lstValues->count() != limit))
119
         (limit == 0 || mModelValues->rowCount() != limit))
89 120
  {
90 121
    const QgsAttributeMap& attributes = feat.attributeMap();
91 122
    value = attributes[fieldIndex].toString();
......
97 128
    }
98 129
    
99 130
    // add item only if it's not there already
100
    if (lstValues->findItem(value) == 0)
101
      lstValues->insertItem(value);
102
    
131
    QList<QStandardItem *> items = mModelValues->findItems(value);
132
    if (items.isEmpty())
133
    {
134
      QStandardItem *myItem = new QStandardItem(value);
135
      myItem->setEditable(false);
136
      mModelValues->insertRow(mModelValues->rowCount(),myItem);
137
    }
103 138
  }
139
  // Unblock for normal use
140
  mModelValues->blockSignals(false);
141
  lstValues->setUpdatesEnabled(true);
142
  // TODO: already sorted, signal emit to refresh model 
143
  mModelValues->sort(0);
144
  lstValues->setCursor(Qt::ArrowCursor);
104 145
}
105 146

  
106 147
void QgsSearchQueryBuilder::on_btnSampleValues_clicked()
......
245 286
  txtSQL->setText(searchString);
246 287
}
247 288

  
248
void QgsSearchQueryBuilder::on_lstFields_doubleClicked( Q3ListBoxItem *item )
289
void QgsSearchQueryBuilder::on_lstFields_doubleClicked( const QModelIndex &index )
249 290
{
250
  txtSQL->insert(item->text());
291
  txtSQL->insert(mModelFields->data(index).toString());
251 292
}
252 293

  
253
void QgsSearchQueryBuilder::on_lstValues_doubleClicked( Q3ListBoxItem *item )
294
void QgsSearchQueryBuilder::on_lstValues_doubleClicked( const QModelIndex &index )
254 295
{
255
  txtSQL->insert(item->text());
296
  txtSQL->insert(mModelValues->data(index).toString());
256 297
}
257 298

  
258 299
void QgsSearchQueryBuilder::on_btnLessEqual_clicked()
src/app/qgssearchquerybuilder.h (copia de trabajo)
19 19

  
20 20
#include <map>
21 21
#include <vector>
22
#include <QStandardItemModel>
23
#include <QModelIndex>
22 24

  
23 25
#include "ui_qgspgquerybuilderbase.h"
24 26
#include "qgisgui.h"
......
59 61
    void on_btnLike_clicked();
60 62
    void on_btnILike_clicked();
61 63
    
62
    void on_lstFields_doubleClicked( Q3ListBoxItem *item );
63
    void on_lstValues_doubleClicked( Q3ListBoxItem *item );
64
    void on_lstFields_doubleClicked( const QModelIndex &index );
65
    void on_lstValues_doubleClicked( const QModelIndex &index );
64 66
    void on_btnLessEqual_clicked();
65 67
    void on_btnGreaterEqual_clicked();
66 68
    void on_btnNotEqual_clicked();
......
93 95
    /*! 
94 96
    * Populate the field list for the selected table
95 97
    */ 
96
    void populateFields();  
98
    void populateFields();
99
  /*! 
100
     * Setup models for listviews
101
   */ 
102
    void setupListViews();
97 103

  
98 104
    /*! Get the number of records that would be returned by the current SQL
99 105
     * @return Number of records or -1 if an error was encountered
......
109 115
  private:
110 116
    
111 117
    //! Layer for which is the query builder opened
112
    QgsVectorLayer* mLayer;
113
    
118
    QgsVectorLayer* mLayer;    
114 119
    //! Map that holds field information, keyed by field name
115 120
    QMap<QString, int> mFieldMap;
116

  
121
    //! Model for fields ListView
122
    QStandardItemModel *mModelFields;
123
    //! Model for values ListView
124
    QStandardItemModel *mModelValues;
117 125
};
118 126
#endif //QGSSEARCHQUERYBUILDER_H
src/ui/qgspgquerybuilderbase.ui (copia de trabajo)
12 12
   </rect>
13 13
  </property>
14 14
  <property name="sizePolicy" >
15
   <sizepolicy>
16
    <hsizetype>7</hsizetype>
17
    <vsizetype>7</vsizetype>
15
   <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
18 16
    <horstretch>0</horstretch>
19 17
    <verstretch>0</verstretch>
20 18
   </sizepolicy>
......
29 27
   <bool>true</bool>
30 28
  </property>
31 29
  <layout class="QGridLayout" >
32
   <property name="margin" >
30
   <property name="leftMargin" >
33 31
    <number>9</number>
34 32
   </property>
35
   <property name="spacing" >
33
   <property name="topMargin" >
34
    <number>9</number>
35
   </property>
36
   <property name="rightMargin" >
37
    <number>9</number>
38
   </property>
39
   <property name="bottomMargin" >
40
    <number>9</number>
41
   </property>
42
   <property name="horizontalSpacing" >
36 43
    <number>6</number>
37 44
   </property>
45
   <property name="verticalSpacing" >
46
    <number>6</number>
47
   </property>
38 48
   <item row="2" column="0" colspan="2" >
39 49
    <widget class="QGroupBox" name="groupBox4" >
40 50
     <property name="title" >
41 51
      <string>Operators</string>
42 52
     </property>
43 53
     <layout class="QGridLayout" >
44
      <property name="margin" >
54
      <property name="leftMargin" >
45 55
       <number>11</number>
46 56
      </property>
47
      <property name="spacing" >
57
      <property name="topMargin" >
58
       <number>11</number>
59
      </property>
60
      <property name="rightMargin" >
61
       <number>11</number>
62
      </property>
63
      <property name="bottomMargin" >
64
       <number>11</number>
65
      </property>
66
      <property name="horizontalSpacing" >
48 67
       <number>10</number>
49 68
      </property>
69
      <property name="verticalSpacing" >
70
       <number>10</number>
71
      </property>
50 72
      <item row="0" column="0" >
51 73
       <widget class="QPushButton" name="btnEqual" >
52 74
        <property name="text" >
......
150 172
   </item>
151 173
   <item row="4" column="0" colspan="2" >
152 174
    <layout class="QHBoxLayout" >
153
     <property name="margin" >
154
      <number>0</number>
155
     </property>
156 175
     <property name="spacing" >
157 176
      <number>6</number>
158 177
     </property>
178
     <property name="leftMargin" >
179
      <number>0</number>
180
     </property>
181
     <property name="topMargin" >
182
      <number>0</number>
183
     </property>
184
     <property name="rightMargin" >
185
      <number>0</number>
186
     </property>
187
     <property name="bottomMargin" >
188
      <number>0</number>
189
     </property>
159 190
     <item>
160 191
      <spacer>
161 192
       <property name="orientation" >
......
230 261
   <item row="1" column="1" >
231 262
    <widget class="QGroupBox" name="groupBox2" >
232 263
     <property name="sizePolicy" >
233
      <sizepolicy>
234
       <hsizetype>7</hsizetype>
235
       <vsizetype>7</vsizetype>
264
      <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
236 265
       <horstretch>0</horstretch>
237 266
       <verstretch>0</verstretch>
238 267
      </sizepolicy>
......
241 270
      <string>Values</string>
242 271
     </property>
243 272
     <layout class="QGridLayout" >
244
      <property name="margin" >
273
      <property name="leftMargin" >
245 274
       <number>10</number>
246 275
      </property>
247
      <property name="spacing" >
276
      <property name="topMargin" >
277
       <number>10</number>
278
      </property>
279
      <property name="rightMargin" >
280
       <number>10</number>
281
      </property>
282
      <property name="bottomMargin" >
283
       <number>10</number>
284
      </property>
285
      <property name="horizontalSpacing" >
248 286
       <number>6</number>
249 287
      </property>
250
      <item row="1" column="1" >
288
      <property name="verticalSpacing" >
289
       <number>6</number>
290
      </property>
291
      <item row="2" column="1" >
251 292
       <widget class="QPushButton" name="btnGetAllValues" >
252 293
        <property name="text" >
253 294
         <string>All</string>
254 295
        </property>
255 296
       </widget>
256 297
      </item>
257
      <item row="0" column="0" colspan="2" >
258
       <widget class="Q3ListBox" name="lstValues" />
259
      </item>
260
      <item row="1" column="0" >
298
      <item row="2" column="0" >
261 299
       <widget class="QPushButton" name="btnSampleValues" >
262 300
        <property name="text" >
263 301
         <string>Sample</string>
264 302
        </property>
265 303
       </widget>
266 304
      </item>
305
      <item rowspan="2" row="0" column="0" colspan="2" >
306
       <widget class="QListView" name="lstValues" />
307
      </item>
267 308
     </layout>
268 309
    </widget>
269 310
   </item>
......
273 314
      <string>Fields</string>
274 315
     </property>
275 316
     <layout class="QGridLayout" >
276
      <property name="margin" >
317
      <property name="leftMargin" >
277 318
       <number>10</number>
278 319
      </property>
279
      <property name="spacing" >
320
      <property name="topMargin" >
321
       <number>10</number>
322
      </property>
323
      <property name="rightMargin" >
324
       <number>10</number>
325
      </property>
326
      <property name="bottomMargin" >
327
       <number>10</number>
328
      </property>
329
      <property name="horizontalSpacing" >
280 330
       <number>6</number>
281 331
      </property>
332
      <property name="verticalSpacing" >
333
       <number>6</number>
334
      </property>
282 335
      <item row="0" column="0" >
283
       <widget class="Q3ListBox" name="lstFields" />
336
       <widget class="QListView" name="lstFields" />
284 337
      </item>
285 338
     </layout>
286 339
    </widget>
......
304 357
      <string>SQL where clause</string>
305 358
     </property>
306 359
     <layout class="QGridLayout" >
307
      <property name="margin" >
360
      <property name="leftMargin" >
308 361
       <number>10</number>
309 362
      </property>
310
      <property name="spacing" >
363
      <property name="topMargin" >
364
       <number>10</number>
365
      </property>
366
      <property name="rightMargin" >
367
       <number>10</number>
368
      </property>
369
      <property name="bottomMargin" >
370
       <number>10</number>
371
      </property>
372
      <property name="horizontalSpacing" >
311 373
       <number>6</number>
312 374
      </property>
375
      <property name="verticalSpacing" >
376
       <number>6</number>
377
      </property>
313 378
      <item row="0" column="0" >
314
       <widget class="Q3TextEdit" name="txtSQL" />
379
       <widget class="QTextEdit" name="txtSQL" />
315 380
      </item>
316 381
     </layout>
317 382
    </widget>
......
319 384
  </layout>
320 385
 </widget>
321 386
 <layoutdefault spacing="6" margin="11" />
322
 <customwidgets>
323
  <customwidget>
324
   <class>Q3ListBox</class>
325
   <extends>Q3Frame</extends>
326
   <header>q3listbox.h</header>
327
  </customwidget>
328
  <customwidget>
329
   <class>Q3TextEdit</class>
330
   <extends>Q3Frame</extends>
331
   <header>q3textedit.h</header>
332
  </customwidget>
333
 </customwidgets>
334 387
 <tabstops>
335
  <tabstop>lstFields</tabstop>
336
  <tabstop>lstValues</tabstop>
337 388
  <tabstop>btnSampleValues</tabstop>
338 389
  <tabstop>btnGetAllValues</tabstop>
339 390
  <tabstop>btnEqual</tabstop>
......
350 401
  <tabstop>btnAnd</tabstop>
351 402
  <tabstop>btnOr</tabstop>
352 403
  <tabstop>btnNot</tabstop>
353
  <tabstop>txtSQL</tabstop>
354 404
  <tabstop>btnClear</tabstop>
355 405
  <tabstop>btnTest</tabstop>
356 406
  <tabstop>btnOk</tabstop>