~ubuntu-branches/ubuntu/quantal/qgis/quantal

« back to all changes in this revision

Viewing changes to src/gui/qgsattributetable.cpp

  • Committer: Bazaar Package Importer
  • Author(s): William Grant
  • Date: 2007-05-06 13:42:32 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070506134232-pyli6t388w5asd8x
Tags: 0.8.0-3ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - debian/rules, debian/qgis.install, debian/qgis.dirs debian/qgis.desktop:
    Add and install .desktop.
* debian/qgis.desktop: Remove Applications category; it's not real.
* Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                          qgsattributetable.cpp  -  description
 
3
                             -------------------
 
4
    begin                : Sat Nov 23 2002
 
5
    copyright            : (C) 2002 by Gary E.Sherman
 
6
    email                : sherman at mrcc dot com
 
7
       Romans 3:23=>Romans 6:23=>Romans 5:8=>Romans 10:9,10=>Romans 12
 
8
 ***************************************************************************/
 
9
 
 
10
/***************************************************************************
 
11
 *                                                                         *
 
12
 *   This program is free software; you can redistribute it and/or modify  *
 
13
 *   it under the terms of the GNU General Public License as published by  *
 
14
 *   the Free Software Foundation; either version 2 of the License, or     *
 
15
 *   (at your option) any later version.                                   *
 
16
 *                                                                         *
 
17
 ***************************************************************************/
 
18
/* $Id: qgsattributetable.cpp 5720 2006-08-21 14:12:55Z mhugent $ */
 
19
#include <QApplication>
 
20
#include <QMouseEvent>
 
21
#include <QKeyEvent>
 
22
#include <QLabel>
 
23
#include <QFont>
 
24
#include <QClipboard>
 
25
#include <QAction>
 
26
#include <QMenu>
 
27
 
 
28
#include "qgsattributetable.h"
 
29
#include "qgsfeature.h"
 
30
#include "qgsfield.h"
 
31
#include "qgsvectordataprovider.h"
 
32
#include "qgsvectorlayer.h"
 
33
 
 
34
#include <iostream>
 
35
#include <stdlib.h>
 
36
 
 
37
QgsAttributeTable::QgsAttributeTable(QWidget * parent, const char *name):
 
38
        Q3Table(parent, name),
 
39
        lockKeyPressed(false),
 
40
        sort_ascending(true),
 
41
        mEditable(false),
 
42
        mEdited(false),
 
43
        mActionPopup(0)
 
44
{
 
45
  QFont f(font());
 
46
  f.setFamily("Helvetica");
 
47
  f.setPointSize(11);
 
48
  setFont(f);
 
49
  setSelectionMode(Q3Table::MultiRow);
 
50
  QObject::connect(this, SIGNAL(selectionChanged()), this, SLOT(handleChangedSelections()));
 
51
  connect(this, SIGNAL(contextMenuRequested(int, int, const QPoint&)), this, SLOT(popupMenu(int, int, const QPoint&)));
 
52
  connect(this, SIGNAL(valueChanged(int, int)), this, SLOT(storeChangedValue(int,int)));
 
53
  connect(verticalHeader(), SIGNAL(released(int)), this, SLOT(rowClicked(int))); 
 
54
  setReadOnly(true);
 
55
  setFocus();
 
56
}
 
57
 
 
58
QgsAttributeTable::~QgsAttributeTable()
 
59
{
 
60
 
 
61
}
 
62
void QgsAttributeTable::columnClicked(int col)
 
63
{
 
64
  QApplication::setOverrideCursor(Qt::waitCursor);
 
65
 
 
66
  //store the ids of the selected rows in a list
 
67
  QList < int >idsOfSelected;
 
68
  for (int i = 0; i < numSelections(); i++)
 
69
    {
 
70
      for (int j = selection(i).topRow(); j <= selection(i).bottomRow(); j++)
 
71
        {
 
72
          idsOfSelected.append(text(j, 0).toInt());
 
73
        }
 
74
    }
 
75
 
 
76
  sortColumn(col, sort_ascending, true);
 
77
 
 
78
  //clear and rebuild rowIdMap. Overwrite sortColumn later and sort rowIdMap there
 
79
  rowIdMap.clear();
 
80
  int id;
 
81
  for (int i = 0; i < numRows(); i++)
 
82
    {
 
83
      id = text(i, 0).toInt();
 
84
      rowIdMap.insert(id, i);
 
85
    }
 
86
 
 
87
  QObject::disconnect(this, SIGNAL(selectionChanged()), this, SLOT(handleChangedSelections()));
 
88
  clearSelection(true);
 
89
 
 
90
  //select the rows again after sorting
 
91
 
 
92
  QList < int >::iterator it;
 
93
  for (it = idsOfSelected.begin(); it != idsOfSelected.end(); ++it)
 
94
    {
 
95
      selectRowWithId((*it));
 
96
    }
 
97
  QObject::connect(this, SIGNAL(selectionChanged()), this, SLOT(handleChangedSelections()));
 
98
 
 
99
  //change the sorting order after each sort
 
100
  (sort_ascending == true) ? sort_ascending = false : sort_ascending = true;
 
101
 
 
102
  QApplication::restoreOverrideCursor();
 
103
}
 
104
 
 
105
void QgsAttributeTable::keyPressEvent(QKeyEvent * ev)
 
106
{
 
107
  if (ev->key() == Qt::Key_Control || ev->key() == Qt::Key_Shift)
 
108
    {
 
109
      lockKeyPressed = true;
 
110
    }
 
111
}
 
112
 
 
113
void QgsAttributeTable::keyReleaseEvent(QKeyEvent * ev)
 
114
{
 
115
  if (ev->key() == Qt::Key_Control || ev->key() == Qt::Key_Shift)
 
116
    {
 
117
      lockKeyPressed = false;
 
118
    }
 
119
}
 
120
 
 
121
void QgsAttributeTable::handleChangedSelections()
 
122
{
 
123
  Q3TableSelection cselection;
 
124
  if (lockKeyPressed == false)
 
125
    {
 
126
      //clear the list and evaluate the last selection
 
127
      emit selectionRemoved();
 
128
    }
 
129
  //if there is no current selection, there is nothing to do
 
130
  if (currentSelection() == -1)
 
131
    {
 
132
      return;
 
133
    }
 
134
 
 
135
  cselection = selection(currentSelection());
 
136
 
 
137
  for (int index = cselection.topRow(); index <= cselection.bottomRow(); index++)
 
138
    {
 
139
      emit selected(text(index, 0).toInt());
 
140
    }
 
141
 
 
142
  //don't send the signal repaintRequested() from here
 
143
  //but in contentsMouseReleaseEvent() and rowClicked(int)
 
144
  //todo: don't repaint in case of double clicks
 
145
}
 
146
 
 
147
void QgsAttributeTable::insertFeatureId(int id, int row)
 
148
{
 
149
  rowIdMap.insert(id, row);
 
150
}
 
151
 
 
152
void QgsAttributeTable::selectRowWithId(int id)
 
153
{
 
154
  QMap < int, int >::iterator it = rowIdMap.find(id);
 
155
  selectRow(it.data());
 
156
}
 
157
 
 
158
void QgsAttributeTable::sortColumn(int col, bool ascending, bool wholeRows)
 
159
{
 
160
  //if the first entry contains a letter, sort alphanumerically, otherwise numerically
 
161
  QString firstentry = text(0, col);
 
162
  bool containsletter = false;
 
163
  for (uint i = 0; i < firstentry.length(); i++)
 
164
    {
 
165
      if (firstentry.ref(i).isLetter())
 
166
        {
 
167
          containsletter = true;
 
168
        }
 
169
    }
 
170
 
 
171
  if (containsletter)
 
172
    {
 
173
      qsort(0, numRows() - 1, col, ascending, true);
 
174
  } else
 
175
    {
 
176
      qsort(0, numRows() - 1, col, ascending, false);
 
177
    }
 
178
 
 
179
  repaintContents();
 
180
}
 
181
 
 
182
 
 
183
/**
 
184
  XXX Doesn't QString have something ilke this already?
 
185
*/
 
186
int QgsAttributeTable::compareItems(QString s1, QString s2, bool ascending, bool alphanumeric)
 
187
{
 
188
  if (alphanumeric)
 
189
    {
 
190
      if (s1 > s2)
 
191
        {
 
192
          if (ascending)
 
193
            {
 
194
              return 1;
 
195
          } else
 
196
            {
 
197
              return -1;
 
198
            }
 
199
      } else if (s1 < s2)
 
200
        {
 
201
          if (ascending)
 
202
            {
 
203
              return -1;
 
204
          } else
 
205
            {
 
206
              return 1;
 
207
            }
 
208
      } else if (s1 == s2)
 
209
        {
 
210
          return 0;
 
211
        }
 
212
  } else                        //numeric
 
213
    {
 
214
      double d1 = s1.toDouble();
 
215
      double d2 = s2.toDouble();
 
216
      if (d1 > d2)
 
217
        {
 
218
          if (ascending)
 
219
            {
 
220
              return 1;
 
221
          } else
 
222
            {
 
223
              return -1;
 
224
            }
 
225
      } else if (d1 < d2)
 
226
        {
 
227
          if (ascending)
 
228
            {
 
229
              return -1;
 
230
          } else
 
231
            {
 
232
              return 1;
 
233
            }
 
234
      } else if (d1 == d2)
 
235
        {
 
236
          return 0;
 
237
        }
 
238
    }
 
239
 
 
240
  return 0;                     // XXX has to return something; is this reasonable?
 
241
 
 
242
}
 
243
 
 
244
void QgsAttributeTable::qsort(int lower, int upper, int col, bool ascending, bool alphanumeric)
 
245
{
 
246
  int i, j;
 
247
  QString v;
 
248
  if (upper > lower)
 
249
    {
 
250
      //chose a random element (this avoids n^2 worst case)
 
251
      int element = int ( (double)rand() / (double)RAND_MAX * (upper - lower) + lower);
 
252
      swapRows(element, upper);
 
253
      v = text(upper, col);
 
254
      i = lower - 1;
 
255
      j = upper;
 
256
      for (;;)
 
257
      {
 
258
          while (compareItems(text(++i, col), v, ascending, alphanumeric) == -1);
 
259
          while (compareItems(text(--j, col), v, ascending, alphanumeric) == 1 && j > 0); //make sure that j does not get negative
 
260
          if (i >= j)
 
261
            {
 
262
              break;
 
263
            }
 
264
          swapRows(i, j);
 
265
        }
 
266
      swapRows(i, upper);
 
267
      qsort(lower, i - 1, col, ascending, alphanumeric);
 
268
      qsort(i + 1, upper, col, ascending, alphanumeric);
 
269
    }
 
270
}
 
271
 
 
272
void QgsAttributeTable::popupMenu(int row, int col, const QPoint& pos)
 
273
{
 
274
  // Duplication of code in qgsidentufyresults.cpp. Consider placing
 
275
  // in a seperate class
 
276
  if (mActionPopup == 0)
 
277
  {
 
278
    mActionPopup = new QMenu();
 
279
    QAction *a = mActionPopup->addAction( tr("Run action") );
 
280
    mActionPopup->addSeparator();
 
281
 
 
282
    QgsAttributeAction::aIter   iter = mActions.begin();
 
283
    for (int j = 0; iter != mActions.end(); ++iter, ++j)
 
284
    {
 
285
      QAction* a = mActionPopup->addAction(iter->name());
 
286
      // The menu action stores an integer that is used later on to
 
287
      // associate an menu action with an actual qgis action.
 
288
      a->setData(QVariant::fromValue(j));
 
289
    }
 
290
    connect(mActionPopup, SIGNAL(triggered(QAction*)),
 
291
            this, SLOT(popupItemSelected(QAction*)));
 
292
  }
 
293
 
 
294
  // Get and store the attribute values and their column names are
 
295
  // these are needed for substituting into the actions if the user
 
296
  // chooses one.
 
297
  mActionValues.clear();
 
298
  Q3Header* header = horizontalHeader();
 
299
 
 
300
#ifdef QGISDEBUG
 
301
  if (header->count() != numCols())
 
302
    std::cerr << "Something wrong with the table (file " 
 
303
              << __FILE__<< ", line " << __LINE__ 
 
304
              << ")." << std::endl;
 
305
#endif
 
306
 
 
307
  for (int i = 0; i < numCols(); ++i)
 
308
    mActionValues.push_back(std::make_pair(header->label(i), text(row, i)));
 
309
 
 
310
  // The item that was clicked on, stored as an index into the
 
311
  // mActionValues vector.
 
312
  mClickedOnValue = col;
 
313
 
 
314
  if (mActions.size() > 0)
 
315
    mActionPopup->popup(pos);  
 
316
}
 
317
 
 
318
void QgsAttributeTable::popupItemSelected(QAction* menuAction)
 
319
{
 
320
  int id = menuAction->data().toInt();
 
321
  mActions.doAction(id, mActionValues, mClickedOnValue);
 
322
}
 
323
 
 
324
bool QgsAttributeTable::addAttribute(const QString& name, const QString& type)
 
325
{
 
326
    //first test if an attribute with the same name is already in the table
 
327
    for(int i=0;i<horizontalHeader()->count();++i)
 
328
    {
 
329
        if(horizontalHeader()->label(i)==name)
 
330
        {
 
331
            //name conflict
 
332
            return false;
 
333
        }
 
334
    }
 
335
    mAddedAttributes.insert(std::make_pair(name,type));
 
336
#ifdef QGISDEBUG
 
337
    qWarning(("inserting attribute "+name+" of type "+type).toLocal8Bit().data());
 
338
    //add a new column at the end of the table
 
339
    qWarning(("numCols: "+QString::number(numCols())).toLocal8Bit().data());
 
340
#endif
 
341
    insertColumns(numCols());
 
342
    horizontalHeader()->setLabel(numCols()-1,name);
 
343
    mEdited=true;
 
344
    return true;
 
345
}
 
346
 
 
347
void QgsAttributeTable::deleteAttribute(const QString& name)
 
348
{
 
349
    //check, if there is already an attribute with this name in mAddedAttributes
 
350
    std::map<QString,QString>::iterator iter=mAddedAttributes.find(name);
 
351
    if(iter!=mAddedAttributes.end())
 
352
    {
 
353
        mAddedAttributes.erase(iter);
 
354
        removeAttrColumn(name);
 
355
    }
 
356
    else
 
357
    {
 
358
#ifdef QGISDEBUG
 
359
        qWarning(("QgsAttributeTable: deleteAttribute "+name).toLocal8Bit().data());
 
360
#endif
 
361
        mDeletedAttributes.insert(name);
 
362
        removeAttrColumn(name);
 
363
    }
 
364
    mEdited=true;
 
365
}
 
366
 
 
367
 
 
368
/* Deprecated: See QgisApp::editCopy() instead */
 
369
void QgsAttributeTable::copySelectedRows()
 
370
{
 
371
  // Copy selected rows to the clipboard
 
372
 
 
373
  QString toClipboard;
 
374
  const char fieldSep = '\t';
 
375
 
 
376
  // Pick up the headers first
 
377
  Q3Header* header = horizontalHeader();
 
378
  for (int i = 0; i < header->count(); ++i)
 
379
    toClipboard += header->label(i) + fieldSep;
 
380
  toClipboard += '\n';
 
381
 
 
382
  // Then populate with the cell contents
 
383
  for (int i = 0; i < numSelections(); ++i)
 
384
  {
 
385
    Q3TableSelection sel = selection(i);
 
386
    for (int row = sel.topRow(); row < sel.topRow()+sel.numRows(); ++row)
 
387
    {
 
388
      for (int column = 0; column < numCols(); ++column)
 
389
        toClipboard += text(row, column) + fieldSep;
 
390
      toClipboard += '\n';
 
391
    }
 
392
  }
 
393
#ifdef QGISDEBUG
 
394
  std::cerr << "Selected data in table is:\n" << toClipboard.data();
 
395
#endif
 
396
  // And then copy to the clipboard
 
397
  QClipboard* clipboard = QApplication::clipboard();
 
398
 
 
399
  // With qgis running under Linux, but with a Windows based X
 
400
  // server (Xwin32), ::Selection was necessary to get the data into
 
401
  // the Windows clipboard (which seems contrary to the Qt
 
402
  // docs). With a Linux X server, ::Clipboard was required.
 
403
  // The simple solution was to put the text into both clipboards.
 
404
 
 
405
  // The ::Selection setText() below one may need placing inside so
 
406
  // #ifdef so that it doesn't get compiled under Windows.
 
407
  clipboard->setText(toClipboard, QClipboard::Selection);
 
408
  clipboard->setText(toClipboard, QClipboard::Clipboard);
 
409
}
 
410
 
 
411
bool QgsAttributeTable::commitChanges(QgsVectorLayer* layer)
 
412
{
 
413
  bool isSuccessful = FALSE;
 
414
 
 
415
  if(layer)
 
416
  {
 
417
    isSuccessful = layer->commitAttributeChanges(
 
418
                            mDeletedAttributes,
 
419
                            mAddedAttributes,
 
420
                            mChangedValues);
 
421
  }
 
422
 
 
423
  if (isSuccessful)
 
424
  {
 
425
    mEdited=false;
 
426
    clearEditingStructures();
 
427
  }
 
428
 
 
429
  return isSuccessful;
 
430
}
 
431
 
 
432
bool QgsAttributeTable::rollBack(QgsVectorLayer* layer)
 
433
{
 
434
  if(layer)
 
435
  {
 
436
    fillTable(layer);
 
437
  }
 
438
  mEdited=false;
 
439
  clearEditingStructures();
 
440
  return true;
 
441
}
 
442
 
 
443
 
 
444
void QgsAttributeTable::fillTable(QgsVectorLayer* layer)
 
445
{
 
446
  QgsVectorDataProvider* provider=layer->getDataProvider();
 
447
  if(provider)
 
448
  {
 
449
    QgsFeature *fet;
 
450
    int row = 0;
 
451
  
 
452
    std::vector<QgsFeature*>& addedFeatures = layer->addedFeatures();
 
453
    std::set<int>& deletedFeatures = layer->deletedFeatureIds();
 
454
 
 
455
    // set up the column headers
 
456
    Q3Header *colHeader = horizontalHeader();
 
457
    std::vector < QgsField > fields = provider->fields();
 
458
    int fieldcount=provider->fieldCount();
 
459
#ifdef QGISDEBUG
 
460
    for (int l = 0; l < fields.size(); l++)
 
461
      std::cout << "field: " << fields[l].name().toLocal8Bit().data() << " | " << fields[l].isNumeric() << " | " << fields[l].type().toLocal8Bit().data() << std::endl;
 
462
#endif
 
463
  
 
464
    setNumRows(provider->featureCount() + addedFeatures.size() - deletedFeatures.size());
 
465
    setNumCols(fieldcount+1);
 
466
    colHeader->setLabel(0, "id"); //label for the id-column
 
467
 
 
468
    for (int h = 1; h <= fieldcount; h++)
 
469
    {
 
470
        colHeader->setLabel(h, fields[h - 1].name());
 
471
#ifdef QGISDEBUG
 
472
        qWarning("Setting column label "+fields[h - 1].name());
 
473
#endif
 
474
    }
 
475
 
 
476
    //go through the features and fill the values into the table
 
477
    provider->reset();
 
478
    while ((fet = provider->getNextFeature(true)))
 
479
    {
 
480
      if(deletedFeatures.find(fet->featureId()) == deletedFeatures.end())
 
481
      {
 
482
        putFeatureInTable(row, fet);
 
483
        row++;
 
484
      }
 
485
      delete fet;
 
486
    }
 
487
 
 
488
    //also consider the not commited features
 
489
    for(std::vector<QgsFeature*>::iterator it = addedFeatures.begin(); it != addedFeatures.end(); it++)
 
490
    {
 
491
      putFeatureInTable(row, *it);
 
492
      row++;
 
493
    }
 
494
 
 
495
    provider->reset();
 
496
  }
 
497
}
 
498
 
 
499
void QgsAttributeTable::putFeatureInTable(int row, QgsFeature* fet)
 
500
{
 
501
  if(row >= numRows())//prevent a crash if a provider doesn't update the feature count properly
 
502
    {
 
503
      setNumRows(row+1);
 
504
    }
 
505
  
 
506
  //id-field
 
507
  int id = fet->featureId();
 
508
  setText(row, 0, QString::number(id));
 
509
  insertFeatureId(id, row);  //insert the id into the search tree of qgsattributetable
 
510
  const std::vector < QgsFeatureAttribute >& attr = fet->attributeMap();
 
511
  for (int i = 0; i < attr.size(); i++)
 
512
  {
 
513
    // get the field values
 
514
    setText(row, i + 1, attr[i].fieldValue());
 
515
  }
 
516
}
 
517
 
 
518
void QgsAttributeTable::storeChangedValue(int row, int column)
 
519
{
 
520
    //id column is not editable
 
521
    if(column>0)
 
522
    {
 
523
        //find feature id
 
524
        int id=text(row,0).toInt();
 
525
        QString attribute=horizontalHeader()->label(column);
 
526
#ifdef QGISDEBUG
 
527
        qWarning(("feature id: "+QString::number(id)).toLocal8Bit().data());
 
528
        qWarning(("attribute: "+attribute).toLocal8Bit().data());
 
529
#endif
 
530
        std::map<int,std::map<QString,QString> >::iterator iter=mChangedValues.find(id);
 
531
        if(iter==mChangedValues.end())
 
532
        {
 
533
            std::map<QString,QString> themap;
 
534
            mChangedValues.insert(std::make_pair(id,themap));
 
535
            iter=mChangedValues.find(id);
 
536
        }
 
537
        iter->second.erase(attribute);
 
538
        iter->second.insert(std::make_pair(attribute,text(row,column)));
 
539
#ifdef QGISDEBUG
 
540
        qWarning(("value: "+text(row,column)).toLocal8Bit().data());
 
541
#endif  
 
542
        mEdited=true;
 
543
    }
 
544
}
 
545
 
 
546
void QgsAttributeTable::clearEditingStructures()
 
547
{
 
548
    mDeletedAttributes.clear();
 
549
    mAddedAttributes.clear();
 
550
    for(std::map<int,std::map<QString,QString> >::iterator iter=mChangedValues.begin();iter!=mChangedValues.end();++iter)
 
551
    {
 
552
        iter->second.clear();
 
553
    }
 
554
    mChangedValues.clear();
 
555
}
 
556
 
 
557
void QgsAttributeTable::removeAttrColumn(const QString& name)
 
558
{
 
559
    Q3Header* header=horizontalHeader();
 
560
    for(int i=0;i<header->count();++i)
 
561
    {
 
562
        if(header->label(i)==name)
 
563
        {
 
564
            removeColumn(i);
 
565
            break;
 
566
        }
 
567
    }
 
568
}
 
569
 
 
570
void QgsAttributeTable::bringSelectedToTop()
 
571
{
 
572
    blockSignals(true);
 
573
    int swaptorow=0;
 
574
    std::list<Q3TableSelection> selections;
 
575
    bool removeselection;
 
576
 
 
577
    for(int i=0;i<numSelections();++i)
 
578
    {
 
579
        selections.push_back(selection(i));
 
580
    }
 
581
 
 
582
    Q3TableSelection sel;  
 
583
 
 
584
    for(std::list<Q3TableSelection>::iterator iter=selections.begin();iter!=selections.end();++iter)
 
585
    {
 
586
        removeselection=true;
 
587
        while(isRowSelected(swaptorow, true))//selections are not necessary stored in ascending order
 
588
            {
 
589
                ++swaptorow;
 
590
            }
 
591
        
 
592
        for(int j=iter->topRow();j<=iter->bottomRow();++j)
 
593
        {   
 
594
            if(j>swaptorow)//selections are not necessary stored in ascending order
 
595
            {
 
596
                swapRows(j,swaptorow);
 
597
                selectRow(swaptorow);
 
598
                ++swaptorow;    
 
599
                
 
600
            }
 
601
            else
 
602
            {
 
603
                removeselection=false;//keep selection
 
604
            }
 
605
        }
 
606
        if(removeselection)
 
607
        {           
 
608
            removeSelection(*iter);
 
609
        }
 
610
    }
 
611
 
 
612
    //clear and rebuild rowIdMap.
 
613
    rowIdMap.clear();
 
614
    int id;
 
615
    for (int i = 0; i < numRows(); i++)
 
616
    {
 
617
      id = text(i, 0).toInt();
 
618
      rowIdMap.insert(id, i);
 
619
    }
 
620
 
 
621
    blockSignals(false);
 
622
 
 
623
}
 
624
 
 
625
void QgsAttributeTable::selectRowsWithId(const std::vector<int>& ids)
 
626
{
 
627
  // to select more rows at once effectively, we stop sending signals to handleChangedSelections()
 
628
  // otherwise it will repaint map everytime row is selected
 
629
  
 
630
  QObject::disconnect(this, SIGNAL(selectionChanged()), this, SLOT(handleChangedSelections()));
 
631
    
 
632
  clearSelection(false);
 
633
  for (int i = 0; i < ids.size(); i++)
 
634
  {
 
635
    selectRowWithId(ids[i]);
 
636
    emit selected(ids[i]);
 
637
  }
 
638
  
 
639
  QObject::connect(this, SIGNAL(selectionChanged()), this, SLOT(handleChangedSelections()));
 
640
 
 
641
  emit repaintRequested();
 
642
}
 
643
 
 
644
void QgsAttributeTable::showRowsWithId(const std::vector<int>& ids)
 
645
{
 
646
  setUpdatesEnabled(false);
 
647
  
 
648
  // hide all rows first
 
649
  for (int i = 0; i < numRows(); i++)
 
650
    hideRow(i);
 
651
  
 
652
  // show only matching rows
 
653
  for (int i = 0; i < ids.size(); i++)
 
654
    showRow(rowIdMap[ids[i]]);
 
655
  
 
656
  clearSelection(); // deselect all
 
657
  setUpdatesEnabled(true);
 
658
  repaintContents();
 
659
}
 
660
 
 
661
void QgsAttributeTable::showAllRows()
 
662
{
 
663
  for (int i = 0; i < numRows(); i++)
 
664
    showRow(i);
 
665
}
 
666
 
 
667
void QgsAttributeTable::rowClicked(int row)
 
668
{
 
669
  if(checkSelectionChanges())//only repaint the canvas if the selection has changed
 
670
    {
 
671
      emit repaintRequested();
 
672
    }
 
673
}
 
674
 
 
675
void QgsAttributeTable::contentsMouseReleaseEvent(QMouseEvent* e)
 
676
{
 
677
  Q3Table::contentsMouseReleaseEvent(e);
 
678
  if(checkSelectionChanges())//only repaint the canvas if the selection has changed
 
679
    {
 
680
      emit repaintRequested();
 
681
    }
 
682
}
 
683
 
 
684
bool QgsAttributeTable::checkSelectionChanges()
 
685
{
 
686
  std::set<int> theCurrentSelection;
 
687
  Q3TableSelection cselection;
 
688
  cselection = selection(currentSelection());
 
689
  for (int index = cselection.topRow(); index <= cselection.bottomRow(); index++)
 
690
    {
 
691
      theCurrentSelection.insert(index);
 
692
    }
 
693
 
 
694
  if(theCurrentSelection == mLastSelectedRows)
 
695
    {
 
696
      return false;
 
697
    }
 
698
  else
 
699
    {
 
700
      mLastSelectedRows = theCurrentSelection;
 
701
      return true;
 
702
    }
 
703
}