~ubuntu-branches/ubuntu/wily/qgis/wily

« back to all changes in this revision

Viewing changes to src/app/attributetable/qgsattributetabledialog.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
  QgsAttributeTableDialog.cpp
 
3
  -------------------
 
4
         date                 : Feb 2009
 
5
         copyright            : Vita Cizek
 
6
         email                : weetya (at) gmail.com
 
7
 
 
8
 ***************************************************************************
 
9
 *                                                                         *
 
10
 *   This program is free software; you can redistribute it and/or modify  *
 
11
 *   it under the terms of the GNU General Public License as published by  *
 
12
 *   the Free Software Foundation; either version 2 of the License, or     *
 
13
 *   (at your option) any later version.                                   *
 
14
 *                                                                         *
 
15
 ***************************************************************************/
 
16
 
 
17
#include <QtGui>
 
18
 
 
19
#include "qgsattributetabledialog.h"
 
20
#include "qgsattributetablemodel.h"
 
21
#include "qgsattributetablefiltermodel.h"
 
22
#include "qgsattributetableview.h"
 
23
 
 
24
#include <qgsapplication.h>
 
25
#include <qgsvectordataprovider.h>
 
26
#include <qgsvectorlayer.h>
 
27
#include <qgssearchstring.h>
 
28
#include <qgssearchtreenode.h>
 
29
 
 
30
#include "qgisapp.h"
 
31
#include "qgsaddattrdialog.h"
 
32
#include "qgsdelattrdialog.h"
 
33
#include "qgssearchquerybuilder.h"
 
34
#include "qgslogger.h"
 
35
#include "qgsmapcanvas.h"
 
36
#include "qgsfieldcalculator.h"
 
37
 
 
38
class QgsAttributeTableDock : public QDockWidget
 
39
{
 
40
  public:
 
41
    QgsAttributeTableDock( const QString & title, QWidget * parent = 0, Qt::WindowFlags flags = 0 )
 
42
        : QDockWidget( title, parent, flags )
 
43
    {
 
44
      setObjectName( "AttributeTable" ); // set object name so the position can be saved
 
45
    }
 
46
 
 
47
    virtual void closeEvent( QCloseEvent * ev )
 
48
    {
 
49
      deleteLater();
 
50
    }
 
51
};
 
52
 
 
53
 
 
54
QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWidget *parent, Qt::WindowFlags flags )
 
55
    : QDialog( parent, flags ), mDock( NULL )
 
56
{
 
57
  mLayer = theLayer;
 
58
 
 
59
  setupUi( this );
 
60
 
 
61
  setAttribute( Qt::WA_DeleteOnClose );
 
62
 
 
63
  QSettings settings;
 
64
  restoreGeometry( settings.value( "/Windows/BetterAttributeTable/geometry" ).toByteArray() );
 
65
 
 
66
  mView->setLayer( mLayer );
 
67
  mFilterModel = ( QgsAttributeTableFilterModel * ) mView->model();
 
68
  mModel = ( QgsAttributeTableModel * )(( QgsAttributeTableFilterModel * )mView->model() )->sourceModel();
 
69
 
 
70
  mQuery = query;
 
71
  mColumnBox = columnBox;
 
72
  columnBoxInit();
 
73
 
 
74
  QSettings mySettings;
 
75
  bool myDockFlag = mySettings.value( "/qgis/dockAttributeTable", false ).toBool();
 
76
  if ( myDockFlag )
 
77
  {
 
78
    mDock = new QgsAttributeTableDock( tr( "Attribute table - %1" ).arg( mLayer->name() ), QgisApp::instance() );
 
79
    mDock->setAllowedAreas( Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea );
 
80
    mDock->setWidget( this );
 
81
    connect( this, SIGNAL( destroyed() ), mDock, SLOT( close() ) );
 
82
    QgisApp::instance()->addDockWidget( Qt::BottomDockWidgetArea, mDock );
 
83
  }
 
84
 
 
85
  setWindowTitle( tr( "Attribute table - %1" ).arg( mLayer->name() ) );
 
86
 
 
87
  mRemoveSelectionButton->setIcon( getThemeIcon( "/mActionUnselectAttributes.png" ) );
 
88
  mSelectedToTopButton->setIcon( getThemeIcon( "/mActionSelectedToTop.png" ) );
 
89
  mCopySelectedRowsButton->setIcon( getThemeIcon( "/mActionCopySelected.png" ) );
 
90
  mZoomMapToSelectedRowsButton->setIcon( getThemeIcon( "/mActionZoomToSelected.png" ) );
 
91
  mInvertSelectionButton->setIcon( getThemeIcon( "/mActionInvertSelection.png" ) );
 
92
  mToggleEditingButton->setIcon( getThemeIcon( "/mActionToggleEditing.png" ) );
 
93
  mDeleteSelectedButton->setIcon( getThemeIcon( "/mActionDeleteSelected.png" ) );
 
94
  mOpenFieldCalculator->setIcon( getThemeIcon( "/mActionCalculateField.png" ) );
 
95
  mAddAttribute->setIcon( getThemeIcon( "/mActionNewAttribute.png" ) );
 
96
  mRemoveAttribute->setIcon( getThemeIcon( "/mActionDeleteAttribute.png" ) );
 
97
 
 
98
  // toggle editing
 
99
  bool canChangeAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
 
100
  bool canDeleteFeatures = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures;
 
101
  bool canAddAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::AddAttributes;
 
102
  bool canDeleteAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteAttributes;
 
103
  mToggleEditingButton->setCheckable( true );
 
104
  mToggleEditingButton->setChecked( mLayer->isEditable() );
 
105
  mToggleEditingButton->setEnabled( canChangeAttributes );
 
106
  mOpenFieldCalculator->setEnabled( canChangeAttributes && mLayer->isEditable() );
 
107
  mDeleteSelectedButton->setEnabled( canDeleteFeatures && mLayer->isEditable() );
 
108
  mAddAttribute->setEnabled( canAddAttributes && mLayer->isEditable() );
 
109
  mRemoveAttribute->setEnabled( canDeleteAttributes && mLayer->isEditable() );
 
110
 
 
111
  // info from table to application
 
112
  connect( this, SIGNAL( editingToggled( QgsMapLayer * ) ), QgisApp::instance(), SLOT( toggleEditing( QgsMapLayer * ) ) );
 
113
  // info from layer to table
 
114
  connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) );
 
115
  connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
 
116
 
 
117
  connect( searchButton, SIGNAL( clicked() ), this, SLOT( search() ) );
 
118
 
 
119
  connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
 
120
  connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( close() ) );
 
121
  connect( mView->verticalHeader(), SIGNAL( sectionClicked( int ) ), this, SLOT( updateRowSelection( int ) ) );
 
122
  connect( mView->verticalHeader(), SIGNAL( sectionPressed( int ) ), this, SLOT( updateRowPressed( int ) ) );
 
123
  connect( mModel, SIGNAL( modelChanged() ), this, SLOT( updateSelection() ) );
 
124
 
 
125
  mLastClickedHeaderIndex = 0;
 
126
  mSelectionModel = new QItemSelectionModel( mFilterModel );
 
127
  updateSelectionFromLayer();
 
128
 
 
129
  //make sure to show all recs on first load
 
130
  on_cbxShowSelectedOnly_toggled( false );
 
131
}
 
132
 
 
133
QgsAttributeTableDialog::~QgsAttributeTableDialog()
 
134
{
 
135
  delete mSelectionModel;
 
136
}
 
137
 
 
138
void QgsAttributeTableDialog::closeEvent( QCloseEvent* event )
 
139
{
 
140
  QDialog::closeEvent( event );
 
141
 
 
142
  if ( mDock == NULL )
 
143
  {
 
144
    QSettings settings;
 
145
    settings.setValue( "/Windows/BetterAttributeTable/geometry", saveGeometry() );
 
146
  }
 
147
}
 
148
 
 
149
 
 
150
QIcon QgsAttributeTableDialog::getThemeIcon( const QString theName )
 
151
{
 
152
  // copied from QgisApp::getThemeIcon. To be removed when merged to SVN
 
153
 
 
154
  QString myPreferredPath = QgsApplication::activeThemePath() + QDir::separator() + theName;
 
155
  QString myDefaultPath = QgsApplication::defaultThemePath() + QDir::separator() + theName;
 
156
  if ( QFile::exists( myPreferredPath ) )
 
157
  {
 
158
    return QIcon( myPreferredPath );
 
159
  }
 
160
  else if ( QFile::exists( myDefaultPath ) )
 
161
  {
 
162
    //could still return an empty icon if it
 
163
    //doesnt exist in the default theme either!
 
164
    return QIcon( myDefaultPath );
 
165
  }
 
166
  else
 
167
  {
 
168
    return QIcon();
 
169
  }
 
170
}
 
171
 
 
172
void QgsAttributeTableDialog::showAdvanced()
 
173
{
 
174
  mMenuActions->exec( QCursor::pos() );
 
175
}
 
176
 
 
177
void QgsAttributeTableDialog::on_mSelectedToTopButton_clicked()
 
178
{
 
179
  int freeIndex = 0;
 
180
 
 
181
  //QgsFeatureIds fids = mSelectedFeatures;
 
182
  //QgsFeatureIds::Iterator it = fids.begin();
 
183
 
 
184
  mModel->incomingChangeLayout();
 
185
 
 
186
  QgsFeatureIds::Iterator it = mSelectedFeatures.begin();
 
187
  for ( ; it != mSelectedFeatures.end(); ++it, ++freeIndex )
 
188
  {
 
189
    QModelIndex sourceIndex = mFilterModel->mapToSource( mFilterModel->index( freeIndex, 0 ) );
 
190
    mModel->swapRows( mModel->rowToId( sourceIndex.row() ), *it );
 
191
  }
 
192
 
 
193
  /*
 
194
    while (it != fids.end())
 
195
    { //map!!!!
 
196
      //mModel->swapRows(mModel->rowToId(freeIndex), *it);
 
197
      //QModelIndex index = mFilterModel->mapFromSource(mModel->index(mModel->idToRow(*it), 0));
 
198
      QModelIndex sourceIndex = mFilterModel->mapToSource(mFilterModel->index(freeIndex, 0));
 
199
      mModel->swapRows(mModel->rowToId(sourceIndex.row()), *it);
 
200
      //mModel->swapRows(freeIndex, *it);
 
201
 
 
202
      if (fids.empty())
 
203
        break;
 
204
      else
 
205
        ++it;
 
206
 
 
207
      ++freeIndex;
 
208
    }
 
209
  */
 
210
  // just select proper rows
 
211
  //mModel->reload(mModel->index(0,0), mModel->index(mModel->rowCount(), mModel->columnCount()));
 
212
  //mModel->changeLayout();
 
213
  mModel->resetModel();
 
214
  updateSelection();
 
215
}
 
216
 
 
217
void QgsAttributeTableDialog::on_mCopySelectedRowsButton_clicked()
 
218
{
 
219
  QgisApp::instance()->editCopy( mLayer );
 
220
}
 
221
 
 
222
void QgsAttributeTableDialog::on_mZoomMapToSelectedRowsButton_clicked()
 
223
{
 
224
  QgisApp::instance()->mapCanvas()->zoomToSelected( mLayer );
 
225
}
 
226
 
 
227
void QgsAttributeTableDialog::on_mInvertSelectionButton_clicked()
 
228
{
 
229
  mLayer->invertSelection();
 
230
}
 
231
 
 
232
void QgsAttributeTableDialog::on_mRemoveSelectionButton_clicked()
 
233
{
 
234
  mLayer->removeSelection();
 
235
}
 
236
 
 
237
void QgsAttributeTableDialog::on_mDeleteSelectedButton_clicked()
 
238
{
 
239
  QgisApp::instance()->deleteSelected( mLayer );
 
240
}
 
241
 
 
242
void QgsAttributeTableDialog::on_cbxShowSelectedOnly_toggled( bool theFlag )
 
243
{
 
244
  mFilterModel->setHideUnselected( theFlag );
 
245
  mFilterModel->invalidate();
 
246
  //TODO: weird
 
247
  //mModel->changeLayout();
 
248
  updateSelection();
 
249
}
 
250
 
 
251
void QgsAttributeTableDialog::columnBoxInit()
 
252
{
 
253
  QgsFieldMap fieldMap = mLayer->dataProvider()->fields();
 
254
  QgsFieldMap::Iterator it = fieldMap.begin();
 
255
 
 
256
  for ( ; it != fieldMap.end(); ++it )
 
257
    mColumnBox->addItem( it.value().name() );
 
258
}
 
259
 
 
260
int QgsAttributeTableDialog::columnBoxColumnId()
 
261
{
 
262
  QgsFieldMap fieldMap = mLayer->dataProvider()->fields();
 
263
  QgsFieldMap::Iterator it = fieldMap.begin();
 
264
 
 
265
  for ( ; it != fieldMap.end(); ++it )
 
266
    if ( it.value().name() == mColumnBox->currentText() )
 
267
      return it.key();
 
268
 
 
269
  return 0;
 
270
}
 
271
 
 
272
void QgsAttributeTableDialog::updateSelection()
 
273
{
 
274
  QModelIndex index;
 
275
  QItemSelection selection;
 
276
 
 
277
  QgsFeatureIds::Iterator it = mSelectedFeatures.begin();
 
278
  for ( ; it != mSelectedFeatures.end(); ++it )
 
279
  {
 
280
    QModelIndex leftUpIndex = mFilterModel->mapFromSource( mModel->index( mModel->idToRow( *it ), 0 ) );
 
281
    QModelIndex rightBottomIndex = mFilterModel->mapFromSource( mModel->index( mModel->idToRow( *it ), mModel->columnCount() - 1 ) );
 
282
    selection.append( QItemSelectionRange( leftUpIndex, rightBottomIndex ) );
 
283
    //selection.append(QItemSelectionRange(leftUpIndex, leftUpIndex));
 
284
  }
 
285
 
 
286
  mSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect );// | QItemSelectionModel::Columns);
 
287
  mView->setSelectionModel( mSelectionModel );
 
288
 
 
289
  /*for (int i = 0; i < mModel->rowCount(); ++i)
 
290
  {
 
291
  int id = mModel->rowToId(i);
 
292
    QgsDebugMsg(id);
 
293
  }
 
294
  QgsDebugMsg("--------------");
 
295
  */
 
296
}
 
297
 
 
298
void QgsAttributeTableDialog::updateRowPressed( int index )
 
299
{
 
300
  mView->setSelectionMode( QAbstractItemView::ExtendedSelection );
 
301
  mIndexPressed = index;
 
302
}
 
303
 
 
304
void QgsAttributeTableDialog::updateRowSelection( int index )
 
305
{
 
306
  bool bDrag;
 
307
 
 
308
  if ( mIndexPressed == index )
 
309
    bDrag = false;
 
310
  else
 
311
    bDrag = true;
 
312
 
 
313
  QString key = "";
 
314
  if ( QApplication::keyboardModifiers() == Qt::ControlModifier )
 
315
    key = "Control";
 
316
  else if ( QApplication::keyboardModifiers() == Qt::ShiftModifier )
 
317
    key = "Shift";
 
318
 
 
319
  int first, last;
 
320
 
 
321
  if ( bDrag )
 
322
  {
 
323
    if ( mIndexPressed < index )
 
324
    {
 
325
      first = mIndexPressed;
 
326
      mLastClickedHeaderIndex = last = index;
 
327
    }
 
328
    else
 
329
    {
 
330
      last = mIndexPressed;
 
331
      mLastClickedHeaderIndex = first = index;
 
332
    }
 
333
 
 
334
    updateRowSelection( first, last, 3 );
 
335
    mView->setSelectionMode( QAbstractItemView::NoSelection );
 
336
    return;
 
337
  }
 
338
  else // No drag
 
339
  {
 
340
    if ( key == "Shift" )
 
341
    {
 
342
      QgsDebugMsg( "shift" );
 
343
      // get the first and last index of the rows to be selected/deselected
 
344
      first = last = 0;
 
345
 
 
346
      if ( index > mLastClickedHeaderIndex )
 
347
      {
 
348
        first = mLastClickedHeaderIndex;
 
349
        last = index;
 
350
      }
 
351
      else if ( index == mLastClickedHeaderIndex )
 
352
      {
 
353
        // row was selected and now it is shift-clicked
 
354
        first = last = index;
 
355
      }
 
356
      else
 
357
      {
 
358
        first = index;
 
359
        last = mLastClickedHeaderIndex;
 
360
      }
 
361
 
 
362
      // for all the rows update the selection, without starting a new selection
 
363
      if ( first <= last )
 
364
        updateRowSelection( first, last, 1 );
 
365
    }
 
366
    else if ( key == "Control" )
 
367
    {
 
368
      QgsDebugMsg( "ctrl" );
 
369
      // update the single row selection, without starting a new selection
 
370
      updateRowSelection( index, index, 2 );
 
371
 
 
372
      // the next shift would start from here
 
373
      mLastClickedHeaderIndex = index;
 
374
    }
 
375
    else // Single click
 
376
    {
 
377
      // Start a new selection if the row was not selected
 
378
      updateRowSelection( index, index, 0 );
 
379
 
 
380
      // the next shift would start from here
 
381
      mLastClickedHeaderIndex = index;
 
382
    }
 
383
  }
 
384
  mView->setSelectionMode( QAbstractItemView::NoSelection );
 
385
}
 
386
 
 
387
void QgsAttributeTableDialog::updateRowSelection( int first, int last, int clickType )
 
388
{
 
389
  // clickType= 0:Single click, 1:Shift, 2:Ctrl, 3: Dragged click
 
390
  disconnect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
 
391
 
 
392
  // Id must be mapped to table/view row
 
393
  QModelIndex index = mFilterModel->mapToSource( mFilterModel->index( first, 0 ) );
 
394
  int fid = mModel->rowToId( index.row() );
 
395
  bool wasSelected = mSelectedFeatures.contains( fid );
 
396
 
 
397
  // new selection should be created
 
398
  if ( clickType == 0 ) // Single click
 
399
  {
 
400
    if ( mSelectedFeatures.size() == 1 && wasSelected ) // One item selected
 
401
      return; // Click over a selected item doesn't do anything
 
402
 
 
403
    mView->setCurrentIndex( mFilterModel->index( first, 0 ) );
 
404
    mView->selectRow( first );
 
405
 
 
406
    mSelectedFeatures.clear();
 
407
    mSelectedFeatures.insert( fid );
 
408
    mLayer->removeSelection();
 
409
    mLayer->select( fid );
 
410
    connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
 
411
    return;
 
412
  }
 
413
  else if ( clickType == 1 ) // Shift
 
414
  {
 
415
    QgsFeatureIds newSelection;
 
416
 
 
417
    for ( int i = first; i <= last; ++i )
 
418
    {
 
419
      if ( i >= first )
 
420
      {
 
421
        // Id must be mapped to table/view row
 
422
        index = mFilterModel->mapToSource( mFilterModel->index( i, 0 ) );
 
423
        fid = mModel->rowToId( index.row() );
 
424
      }
 
425
      newSelection.insert( fid );
 
426
    }
 
427
 
 
428
    // Remove items in mSelectedFeatures if they aren't in mNewSelection
 
429
    QgsFeatureIds::Iterator it = mSelectedFeatures.begin();
 
430
    while ( it != mSelectedFeatures.end() )
 
431
    {
 
432
      if ( !newSelection.contains( *it ) )
 
433
      {
 
434
        it = mSelectedFeatures.erase( it );
 
435
      }
 
436
      else
 
437
      {
 
438
        ++it;
 
439
      }
 
440
    }
 
441
 
 
442
    // Append the other fids in range first-last to mSelectedFeatures
 
443
    QgsFeatureIds::Iterator itNew = newSelection.begin();
 
444
    for ( ; itNew != newSelection.end(); ++itNew )
 
445
    {
 
446
      if ( !mSelectedFeatures.contains( *itNew ) )
 
447
      {
 
448
        mSelectedFeatures.insert( *itNew );
 
449
      }
 
450
    }
 
451
  }
 
452
  else if ( clickType == 2 ) // Ctrl
 
453
  {
 
454
    // existing selection should be updated
 
455
    if ( wasSelected )
 
456
      mSelectedFeatures.remove( fid );
 
457
    else
 
458
      mSelectedFeatures.insert( fid );
 
459
  }
 
460
  else if ( clickType == 3 ) // Dragged click
 
461
  {
 
462
    QgsFeatureIds newSelection;
 
463
 
 
464
    for ( int i = first; i <= last; ++i )
 
465
    {
 
466
      if ( i >= first )
 
467
      {
 
468
        // Id must be mapped to table/view row
 
469
        index = mFilterModel->mapToSource( mFilterModel->index( i, 0 ) );
 
470
        fid = mModel->rowToId( index.row() );
 
471
      }
 
472
      newSelection.insert( fid );
 
473
    }
 
474
 
 
475
    // Remove items in mSelectedFeatures if they aren't in mNewSelection
 
476
    QgsFeatureIds::Iterator it = mSelectedFeatures.begin();
 
477
    while ( it != mSelectedFeatures.end() )
 
478
    {
 
479
      if ( !newSelection.contains( *it ) )
 
480
      {
 
481
        it = mSelectedFeatures.erase( it );
 
482
      }
 
483
      else
 
484
      {
 
485
        ++it;
 
486
      }
 
487
    }
 
488
 
 
489
    // Append the other fids in range first-last to mSelectedFeatures
 
490
    QgsFeatureIds::Iterator itNew = newSelection.begin();
 
491
    for ( ; itNew != newSelection.end(); ++itNew )
 
492
    {
 
493
      if ( !mSelectedFeatures.contains( *itNew ) )
 
494
      {
 
495
        mSelectedFeatures.insert( *itNew );
 
496
      }
 
497
    }
 
498
  }
 
499
 
 
500
  updateSelection();
 
501
  mLayer->setSelectedFeatures( mSelectedFeatures );
 
502
  connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
 
503
}
 
504
 
 
505
void QgsAttributeTableDialog::updateSelectionFromLayer()
 
506
{
 
507
  QgsDebugMsg( "updateFromLayer" );
 
508
  mSelectedFeatures = mLayer->selectedFeaturesIds();
 
509
 
 
510
  if ( cbxShowSelectedOnly->isChecked() )
 
511
    mFilterModel->invalidate();
 
512
 
 
513
  updateSelection();
 
514
}
 
515
 
 
516
void QgsAttributeTableDialog::doSearch( QString searchString )
 
517
{
 
518
  // parse search string and build parsed tree
 
519
  QgsSearchString search;
 
520
  if ( !search.setString( searchString ) )
 
521
  {
 
522
    QMessageBox::critical( this, tr( "Search string parsing error" ), search.parserErrorMsg() );
 
523
    return;
 
524
  }
 
525
 
 
526
  QgsSearchTreeNode* searchTree = search.tree();
 
527
  if ( searchTree == NULL )
 
528
  {
 
529
    QMessageBox::information( this, tr( "Search results" ), tr( "You've supplied an empty search string." ) );
 
530
    return;
 
531
  }
 
532
 
 
533
  QApplication::setOverrideCursor( Qt::WaitCursor );
 
534
  mSelectedFeatures.clear();
 
535
 
 
536
  if ( cbxSearchSelectedOnly->isChecked() )
 
537
  {
 
538
    QgsFeatureList selectedFeatures = mLayer->selectedFeatures();
 
539
    for ( QgsFeatureList::ConstIterator it = selectedFeatures.begin(); it != selectedFeatures.end(); ++it )
 
540
    {
 
541
      if ( searchTree->checkAgainst( mLayer->pendingFields(), it->attributeMap() ) )
 
542
        mSelectedFeatures << it->id();
 
543
 
 
544
      // check if there were errors during evaluating
 
545
      if ( searchTree->hasError() )
 
546
        break;
 
547
    }
 
548
  }
 
549
  else
 
550
  {
 
551
    mLayer->select( mLayer->pendingAllAttributesList(), QgsRectangle(), false );
 
552
    QgsFeature f;
 
553
 
 
554
    while ( mLayer->nextFeature( f ) )
 
555
    {
 
556
      if ( searchTree->checkAgainst( mLayer->pendingFields(), f.attributeMap() ) )
 
557
        mSelectedFeatures << f.id();
 
558
 
 
559
      // check if there were errors during evaluating
 
560
      if ( searchTree->hasError() )
 
561
        break;
 
562
    }
 
563
  }
 
564
 
 
565
  QApplication::restoreOverrideCursor();
 
566
 
 
567
  if ( searchTree->hasError() )
 
568
  {
 
569
    QMessageBox::critical( this, tr( "Error during search" ), searchTree->errorMsg() );
 
570
    return;
 
571
  }
 
572
 
 
573
  // update view
 
574
  updateSelection();
 
575
 
 
576
  disconnect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
 
577
  mLayer->setSelectedFeatures( mSelectedFeatures );
 
578
  connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
 
579
 
 
580
  QString str;
 
581
  if ( mSelectedFeatures.size() )
 
582
    str.sprintf( tr( "Found %d matching features.", "", mSelectedFeatures.size() ).toUtf8(), mSelectedFeatures.size() );
 
583
  else
 
584
    str = tr( "No matching features found." );
 
585
 
 
586
  QgisApp::instance()->statusBar()->showMessage( str );
 
587
}
 
588
 
 
589
void QgsAttributeTableDialog::search()
 
590
{
 
591
 
 
592
  QString str = mColumnBox->currentText();
 
593
 
 
594
  const QgsFieldMap& flds = mLayer->dataProvider()->fields();
 
595
  int fldIndex = mLayer->dataProvider()->fieldNameIndex( str );
 
596
  QVariant::Type fldType = flds[fldIndex].type();
 
597
  bool numeric = ( fldType == QVariant::Int || fldType == QVariant::Double );
 
598
 
 
599
  if ( numeric )
 
600
    str += " = '";
 
601
  else
 
602
    str += " ~ '";
 
603
 
 
604
  str += mQuery->displayText();
 
605
  str += "'";
 
606
 
 
607
  doSearch( str );
 
608
}
 
609
 
 
610
void QgsAttributeTableDialog::on_mAdvancedSearchButton_clicked()
 
611
{
 
612
  QgsSearchQueryBuilder dlg( mLayer, this );
 
613
  dlg.setSearchString( mQuery->displayText() );
 
614
 
 
615
  if ( dlg.exec() )
 
616
    doSearch( dlg.searchString() );
 
617
}
 
618
 
 
619
void QgsAttributeTableDialog::on_mToggleEditingButton_toggled()
 
620
{
 
621
  emit editingToggled( mLayer );
 
622
}
 
623
 
 
624
void QgsAttributeTableDialog::editingToggled()
 
625
{
 
626
  mToggleEditingButton->blockSignals( true );
 
627
  mToggleEditingButton->setChecked( mLayer->isEditable() );
 
628
  mToggleEditingButton->blockSignals( false );
 
629
 
 
630
  bool canChangeAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
 
631
  bool canDeleteFeatures = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures;
 
632
  bool canAddAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::AddAttributes;
 
633
  bool canDeleteAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteAttributes;
 
634
  mOpenFieldCalculator->setEnabled( canChangeAttributes && mLayer->isEditable() );
 
635
  mDeleteSelectedButton->setEnabled( canDeleteFeatures && mLayer->isEditable() );
 
636
  mAddAttribute->setEnabled( canAddAttributes && mLayer->isEditable() );
 
637
  mRemoveAttribute->setEnabled( canDeleteAttributes && mLayer->isEditable() );
 
638
 
 
639
  // (probably reload data if user stopped editing - possible revert)
 
640
  mModel->reload( mModel->index( 0, 0 ), mModel->index( mModel->rowCount(), mModel->columnCount() ) );
 
641
 
 
642
  // not necessary to set table read only if layer is not editable
 
643
  // because model always reflects actual state when returning item flags
 
644
}
 
645
 
 
646
// not used now
 
647
void QgsAttributeTableDialog::startEditing()
 
648
{
 
649
  mLayer->startEditing();
 
650
}
 
651
 
 
652
// not used now
 
653
void QgsAttributeTableDialog::submit()
 
654
{
 
655
  mLayer->commitChanges();
 
656
}
 
657
 
 
658
// not used now
 
659
void QgsAttributeTableDialog::revert()
 
660
{
 
661
  mLayer->rollBack();
 
662
  mModel->revert();
 
663
  mModel->reload( mModel->index( 0, 0 ), mModel->index( mModel->rowCount(), mModel->columnCount() ) );
 
664
}
 
665
 
 
666
void QgsAttributeTableDialog::on_mAddAttribute_clicked()
 
667
{
 
668
  if ( !mLayer )
 
669
  {
 
670
    return;
 
671
  }
 
672
 
 
673
  QgsAddAttrDialog dialog( mLayer->dataProvider(), this );
 
674
  if ( dialog.exec() == QDialog::Accepted )
 
675
  {
 
676
    mLayer->beginEditCommand( tr( "Attribute added" ) );
 
677
    if ( mLayer->addAttribute( dialog.field() ) )
 
678
    {
 
679
      mLayer->endEditCommand();
 
680
    }
 
681
    else
 
682
    {
 
683
      QMessageBox::critical( 0, tr( "Attribute Error" ), tr( "The attribute could not be added to the layer" ) );
 
684
      mLayer->destroyEditCommand();
 
685
    }
 
686
    // update model - a field has been added or updated
 
687
    mModel->reload( mModel->index( 0, 0 ), mModel->index( mModel->rowCount(), mModel->columnCount() ) );
 
688
  }
 
689
}
 
690
 
 
691
void QgsAttributeTableDialog::on_mRemoveAttribute_clicked()
 
692
{
 
693
  if ( !mLayer )
 
694
  {
 
695
    return;
 
696
  }
 
697
 
 
698
  QgsDelAttrDialog dialog( mLayer );
 
699
  if ( dialog.exec() == QDialog::Accepted )
 
700
  {
 
701
    QList<int> attributes = dialog.selectedAttributes();
 
702
    if ( attributes.size() < 1 )
 
703
    {
 
704
      return;
 
705
    }
 
706
 
 
707
    mLayer->beginEditCommand( tr( "Deleted attribute" ) );
 
708
    bool deleted = false;
 
709
    QList<int>::const_iterator it = attributes.constBegin();
 
710
    for ( ; it != attributes.constEnd(); ++it )
 
711
    {
 
712
      if ( mLayer->deleteAttribute( *it ) )
 
713
      {
 
714
        deleted = true;
 
715
      }
 
716
    }
 
717
 
 
718
    if ( deleted )
 
719
    {
 
720
      mLayer->endEditCommand();
 
721
    }
 
722
    else
 
723
    {
 
724
      QMessageBox::critical( 0, tr( "Attribute Error" ), tr( "The attribute(s) could not be deleted" ) );
 
725
      mLayer->destroyEditCommand();
 
726
    }
 
727
    // update model - a field has been added or updated
 
728
    mModel->reload( mModel->index( 0, 0 ), mModel->index( mModel->rowCount(), mModel->columnCount() ) );
 
729
  }
 
730
}
 
731
 
 
732
void QgsAttributeTableDialog::on_mOpenFieldCalculator_clicked()
 
733
{
 
734
  QgsFieldCalculator calc( mLayer );
 
735
  if ( calc.exec() == QDialog::Accepted )
 
736
  {
 
737
    // update model - a field has been added or updated
 
738
    mModel->reload( mModel->index( 0, 0 ), mModel->index( mModel->rowCount(), mModel->columnCount() ) );
 
739
  }
 
740
}