1
/** ===========================================================
4
* This file is a part of kipi-plugins project
5
* <a href="http://www.kipi-plugins.org">http://www.kipi-plugins.org</a>
8
* @brief A widget to search for places.
10
* @author Copyright (C) 2010, 2011 by Michael G. Hansen
11
* <a href="mailto:mike at mghansen dot de">mike at mghansen dot de</a>
13
* This program is free software; you can redistribute it
14
* and/or modify it under the terms of the GNU General
15
* Public License as published by the Free Software Foundation;
16
* either version 2, or (at your option) any later version.
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* ============================================================ */
25
#include "searchwidget.moc"
29
#include <QContextMenuEvent>
32
#include <QPushButton>
33
#include <QToolButton>
35
#include <QVBoxLayout>
41
#include <kcombobox.h>
42
#include <kconfiggroup.h>
44
#include <klineedit.h>
47
#include <kmessagebox.h>
48
#include <kstandarddirs.h>
51
// Libkgeomap includes
53
#include <libkgeomap/kgeomap_widget.h>
57
#include "searchbackend.h"
58
#include "gpssync_common.h"
59
#include "gpsbookmarkowner.h"
60
#include "gpsundocommand.h"
61
#include "kipiimagemodel.h"
63
#ifdef GPSSYNC_MODELTEST
64
#include <modeltest.h>
65
#endif /* GPSSYNC_MODELTEST */
67
namespace KIPIGPSSyncPlugin
70
static int QItemSelectionModel_selectedRowsCount(const QItemSelectionModel* const selectionModel)
72
if (!selectionModel->hasSelection())
77
return selectionModel->selectedRows().count();
80
class SearchWidgetPrivate
85
// TODO: initialize in initializer list
86
searchInProgress = false;
87
actionToggleAllResultsVisibilityIconUnchecked=KIcon(SmallIcon("layer-visible-off"));
88
actionToggleAllResultsVisibilityIconChecked=KIcon(SmallIcon("layer-visible-on"));
92
KGeoMap::KGeoMapWidget *mapWidget;
93
GPSBookmarkOwner *gpsBookmarkOwner;
94
KipiImageModel *kipiImageModel;
95
QItemSelectionModel *kipiImageSelectionModel;
96
KLineEdit *searchTermLineEdit;
97
QPushButton *searchButton;
100
SearchBackend *searchBackend;
101
SearchResultModel *searchResultsModel;
102
QItemSelectionModel *searchResultsSelectionModel;
103
SearchResultModelHelper *searchResultModelHelper;
107
QVBoxLayout *mainVBox;
108
KComboBox *backendSelectionBox;
109
KAction *actionClearResultsList;
110
KAction *actionKeepOldResults;
111
KAction *actionToggleAllResultsVisibility;
112
bool searchInProgress;
113
KIcon actionToggleAllResultsVisibilityIconUnchecked;
114
KIcon actionToggleAllResultsVisibilityIconChecked;
115
KAction *actionCopyCoordinates;
116
KAction *actionBookmark;
117
KAction *actionMoveImagesToThisResult;
118
KAction *actionRemovedSelectedSearchResultsFromList;
121
SearchWidget::SearchWidget(GPSBookmarkOwner* const gpsBookmarkOwner,
122
KipiImageModel* const kipiImageModel,
123
QItemSelectionModel* const kipiImageSelectionModel,
124
QWidget* const parent)
125
: QWidget(parent), d(new SearchWidgetPrivate())
127
d->gpsBookmarkOwner = gpsBookmarkOwner;
128
d->kipiImageModel = kipiImageModel;
129
d->kipiImageSelectionModel = kipiImageSelectionModel;
130
d->searchBackend = new SearchBackend(this);
131
d->searchResultsModel = new SearchResultModel(this);
132
#ifdef GPSSYNC_MODELTEST
133
new ModelTest(d->searchResultsModel, this);
134
#endif /* GPSSYNC_MODELTEST */
135
d->searchResultsSelectionModel = new QItemSelectionModel(d->searchResultsModel);
136
d->searchResultsModel->setSelectionModel(d->searchResultsSelectionModel);
137
d->searchResultModelHelper = new SearchResultModelHelper(d->searchResultsModel, d->searchResultsSelectionModel, d->kipiImageModel, this);
139
d->mainVBox = new QVBoxLayout(this);
140
setLayout(d->mainVBox);
142
KHBox* const topHBox = new KHBox(this);
143
d->mainVBox->addWidget(topHBox);
144
d->searchTermLineEdit = new KLineEdit(topHBox);
145
d->searchTermLineEdit->setClearButtonShown(true);
146
d->searchButton = new QPushButton(i18nc("Start the search", "Search"), topHBox);
148
KHBox* const actionHBox = new KHBox(this);
149
d->mainVBox->addWidget(actionHBox);
151
d->actionClearResultsList = new KAction(this);
152
d->actionClearResultsList->setIcon(SmallIcon("edit-clear-list"));
153
d->actionClearResultsList->setToolTip(i18n("Clear the search results."));
154
QToolButton* const tbClearResultsList = new QToolButton(actionHBox);
155
tbClearResultsList->setDefaultAction(d->actionClearResultsList);
157
d->actionKeepOldResults = new KAction(this);
158
d->actionKeepOldResults->setIcon(SmallIcon("flag"));
159
d->actionKeepOldResults->setCheckable(true);
160
d->actionKeepOldResults->setChecked(false);
161
d->actionKeepOldResults->setToolTip(i18n("Keep the results of old searches when doing a new search."));
162
QToolButton* const tbKeepOldResults = new QToolButton(actionHBox);
163
tbKeepOldResults->setDefaultAction(d->actionKeepOldResults);
165
d->actionToggleAllResultsVisibility = new KAction(this);
166
d->actionToggleAllResultsVisibility->setCheckable(true);
167
d->actionToggleAllResultsVisibility->setChecked(true);
168
d->actionToggleAllResultsVisibility->setToolTip(i18n("Toggle the visibility of the search results on the map."));
169
QToolButton* const tbToggleAllVisibility = new QToolButton(actionHBox);
170
tbToggleAllVisibility->setDefaultAction(d->actionToggleAllResultsVisibility);
172
d->actionCopyCoordinates = new KAction(i18n("Copy coordinates"), this);
173
d->actionCopyCoordinates->setIcon(SmallIcon("edit-copy"));
175
d->actionMoveImagesToThisResult = new KAction(i18n("Move selected images to this position"), this);
177
d->actionRemovedSelectedSearchResultsFromList = new KAction(i18n("Remove from results list"), this);
178
d->actionRemovedSelectedSearchResultsFromList->setIcon(SmallIcon("list-remove"));
180
d->backendSelectionBox = new KComboBox(actionHBox);
181
d->backendSelectionBox->setToolTip(i18n("Select which service you would like to use."));
182
const QList<QPair<QString, QString> > backendList = d->searchBackend->getBackends();
183
for (int i=0; i<backendList.count(); ++i)
185
d->backendSelectionBox->addItem(backendList.at(i).first, backendList.at(i).second);
188
// add stretch after the controls:
189
QHBoxLayout* const hBoxLayout = reinterpret_cast<QHBoxLayout*>(actionHBox->layout());
192
hBoxLayout->addStretch();
195
d->treeView = new QTreeView(this);
196
d->mainVBox->addWidget(d->treeView);
197
d->treeView->setRootIsDecorated(false);
198
d->treeView->setModel(d->searchResultsModel);
199
d->treeView->setSelectionModel(d->searchResultsSelectionModel);
200
d->treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
202
d->actionBookmark = new KAction(i18n("Bookmarks"), this);
203
d->actionBookmark->setMenu(d->gpsBookmarkOwner->getMenu());
205
connect(d->actionMoveImagesToThisResult, SIGNAL(triggered(bool)),
206
this, SLOT(slotMoveSelectedImagesToThisResult()));
208
connect(d->searchButton, SIGNAL(clicked()),
209
this, SLOT(slotTriggerSearch()));
211
connect(d->searchBackend, SIGNAL(signalSearchCompleted()),
212
this, SLOT(slotSearchCompleted()));
214
connect(d->searchTermLineEdit, SIGNAL(returnPressed()),
215
this, SLOT(slotTriggerSearch()));
217
connect(d->searchTermLineEdit, SIGNAL(textChanged(QString)),
218
this, SLOT(slotUpdateActionAvailability()));
220
connect(d->searchResultsSelectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
221
this, SLOT(slotCurrentlySelectedResultChanged(QModelIndex,QModelIndex)));
223
connect(d->actionClearResultsList, SIGNAL(triggered(bool)),
224
this, SLOT(slotClearSearchResults()));
226
connect(d->actionToggleAllResultsVisibility, SIGNAL(triggered(bool)),
227
this, SLOT(slotVisibilityChanged(bool)));
229
connect(d->actionCopyCoordinates, SIGNAL(triggered(bool)),
230
this, SLOT(slotCopyCoordinates()));
232
connect(d->searchResultModelHelper, SIGNAL(signalUndoCommand(GPSUndoCommand*)),
233
this, SIGNAL(signalUndoCommand(GPSUndoCommand*)));
235
connect(d->actionRemovedSelectedSearchResultsFromList, SIGNAL(triggered(bool)),
236
this, SLOT(slotRemoveSelectedFromResultsList()));
238
d->treeView->installEventFilter(this);
240
slotUpdateActionAvailability();
243
SearchWidget::~SearchWidget()
248
void SearchWidget::slotSearchCompleted()
250
d->searchInProgress = false;
252
const QString errorString = d->searchBackend->getErrorMessage();
253
if (!errorString.isEmpty())
255
KMessageBox::error(this, i18n("Your search failed:\n%1", errorString), i18n("Search failed"));
256
slotUpdateActionAvailability();
260
const SearchBackend::SearchResult::List searchResults = d->searchBackend->getResults();
261
d->searchResultsModel->addResults(searchResults);
263
slotUpdateActionAvailability();
266
void SearchWidget::slotTriggerSearch()
268
// this is necessary since this slot is also connected to QLineEdit::returnPressed
269
if (d->searchTermLineEdit->text().isEmpty() || d->searchInProgress)
274
if (!d->actionKeepOldResults->isChecked())
276
slotClearSearchResults();
279
d->searchInProgress = true;
281
const QString searchBackendName = d->backendSelectionBox->itemData(d->backendSelectionBox->currentIndex()).toString();
282
d->searchBackend->search(searchBackendName, d->searchTermLineEdit->text());
284
slotUpdateActionAvailability();
287
class SearchResultModelPrivate
290
SearchResultModelPrivate()
292
markerNormalUrl = KStandardDirs::locate("data", "gpssync/searchmarker-normal.png");
293
markerNormal = QPixmap(markerNormalUrl.toLocalFile());
295
markerSelectedUrl = KStandardDirs::locate("data", "gpssync/searchmarker-selected.png");
296
markerSelected = QPixmap(markerSelectedUrl.toLocalFile());
299
QList<SearchResultModel::SearchResultItem> searchResults;
300
KUrl markerNormalUrl;
301
KUrl markerSelectedUrl;
302
QPixmap markerNormal;
303
QPixmap markerSelected;
304
QItemSelectionModel* selectionModel;
307
SearchResultModel::SearchResultModel(QObject* const parent)
308
: QAbstractItemModel(parent), d(new SearchResultModelPrivate())
312
SearchResultModel::~SearchResultModel()
317
int SearchResultModel::columnCount(const QModelIndex& parent) const
324
bool SearchResultModel::setData(const QModelIndex& index, const QVariant& value, int role)
333
QVariant SearchResultModel::data(const QModelIndex& index, int role) const
335
const int rowNumber = index.row();
336
if ((rowNumber<0)||(rowNumber>=d->searchResults.count()))
341
const int columnNumber = index.column();
347
case Qt::DisplayRole:
348
return d->searchResults.at(rowNumber).result.name;
350
case Qt::DecorationRole:
353
getMarkerIcon(index, 0, 0, &markerIcon, 0);
365
QModelIndex SearchResultModel::index(int row, int column, const QModelIndex& parent) const
367
if (parent.isValid())
369
// there are no child items, only top level items
370
return QModelIndex();
373
if ( (column<0) || (column>=1)
374
|| (row<0) || (row>=d->searchResults.count()) )
376
return QModelIndex();
379
return createIndex(row, column, 0);
382
QModelIndex SearchResultModel::parent(const QModelIndex& index) const
386
// we have only top level items
387
return QModelIndex();
390
int SearchResultModel::rowCount(const QModelIndex& parent) const
392
if (parent.isValid())
397
return d->searchResults.count();
400
bool SearchResultModel::setHeaderData(int section, Qt::Orientation orientation,
401
const QVariant& value, int role)
404
Q_UNUSED(orientation)
411
QVariant SearchResultModel::headerData(int section, Qt::Orientation orientation, int role) const
415
if ((section >= 1) || (orientation != Qt::Horizontal))
420
return QVariant("Name");
423
Qt::ItemFlags SearchResultModel::flags(const QModelIndex& index) const
425
return QAbstractItemModel::flags(index);
428
void SearchResultModel::addResults(const SearchBackend::SearchResult::List& results)
430
// first check which items are not duplicates
431
QList<int> nonDuplicates;
432
for (int i=0; i<results.count(); ++i)
434
const SearchBackend::SearchResult& currentResult = results.at(i);
435
bool isDuplicate = false;
436
for (int j=0; j<d->searchResults.count(); ++j)
438
if (currentResult.internalId==d->searchResults.at(j).result.internalId)
450
if (nonDuplicates.isEmpty())
455
beginInsertRows(QModelIndex(), d->searchResults.count(), d->searchResults.count()+nonDuplicates.count()-1);
456
for (int i=0; i<nonDuplicates.count(); ++i)
458
SearchResultItem item;
459
item.result = results.at(nonDuplicates.at(i));
460
d->searchResults << item;
465
class SearchResultModelHelperPrivate
468
SearchResultModelHelperPrivate()
476
SearchResultModel* model;
477
QItemSelectionModel* selectionModel;
478
KipiImageModel* imageModel;
482
SearchResultModelHelper::SearchResultModelHelper(SearchResultModel* const resultModel,
483
QItemSelectionModel* const selectionModel,
484
KipiImageModel* const imageModel,
485
QObject* const parent)
486
: KGeoMap::ModelHelper(parent), d(new SearchResultModelHelperPrivate())
488
d->model = resultModel;
489
d->selectionModel = selectionModel;
490
d->imageModel = imageModel;
493
SearchResultModelHelper::~SearchResultModelHelper()
498
QAbstractItemModel* SearchResultModelHelper::model() const
503
QItemSelectionModel* SearchResultModelHelper::selectionModel() const
505
return d->selectionModel;
508
bool SearchResultModelHelper::itemCoordinates(const QModelIndex& index, KGeoMap::GeoCoordinates* const coordinates) const
510
const SearchResultModel::SearchResultItem item = d->model->resultItem(index);
512
*coordinates = item.result.coordinates;
517
bool SearchResultModelHelper::itemIcon(const QModelIndex& index, QPoint* const offset, QSize* const size, QPixmap* const pixmap, KUrl* const url) const
519
return d->model->getMarkerIcon(index, offset, size, pixmap, url);
522
SearchResultModel::SearchResultItem SearchResultModel::resultItem(const QModelIndex& index) const
524
if (!index.isValid())
526
return SearchResultItem();
529
return d->searchResults.at(index.row());
532
KGeoMap::ModelHelper* SearchWidget::getModelHelper()
534
return d->searchResultModelHelper;
537
bool SearchResultModel::getMarkerIcon(const QModelIndex& index, QPoint* const offset, QSize* const size, QPixmap* const pixmap, KUrl* const url) const
539
// determine the id of the marker
540
const int markerNumber = index.row();
542
const bool itemIsSelected = d->selectionModel ? d->selectionModel->isSelected(index) : false;
543
QPixmap markerPixmap = itemIsSelected ? d->markerSelected : d->markerNormal;
545
// if the caller requests a URL and the marker will not get
546
// a special label, return a URL. Otherwise, return a pixmap.
547
const bool returnViaUrl = url && markerNumber>26;
550
*url = itemIsSelected ? d->markerSelectedUrl : d->markerNormalUrl;
554
*size = markerPixmap.size();
559
if (markerNumber<=26)
561
const QString markerId = QChar('A'+markerNumber);
563
QPainter painter(&markerPixmap);
564
painter.setRenderHint(QPainter::Antialiasing);
565
painter.setPen(Qt::black);
566
QRect textRect(0,2,markerPixmap.width(),markerPixmap.height());
567
painter.drawText(textRect, Qt::AlignHCenter, markerId);
570
*pixmap = markerPixmap;
575
*offset = QPoint(markerPixmap.width()/2, markerPixmap.height()-1);
581
void SearchResultModel::setSelectionModel(QItemSelectionModel* const selectionModel)
583
d->selectionModel = selectionModel;
586
void SearchWidget::slotCurrentlySelectedResultChanged(const QModelIndex& current, const QModelIndex& previous)
590
if (!current.isValid())
595
const SearchResultModel::SearchResultItem currentItem = d->searchResultsModel->resultItem(current);
599
d->mapWidget->setCenter(currentItem.result.coordinates);
603
void SearchWidget::slotClearSearchResults()
605
d->searchResultsModel->clearResults();
607
slotUpdateActionAvailability();
610
void SearchResultModel::clearResults()
613
d->searchResults.clear();
617
void SearchWidget::slotVisibilityChanged(bool state)
619
d->searchResultModelHelper->setVisibility(state);
620
slotUpdateActionAvailability();
623
void SearchResultModelHelper::setVisibility(const bool state)
626
emit(signalVisibilityChanged());
629
void SearchWidget::slotUpdateActionAvailability()
631
const int nSelectedResults = QItemSelectionModel_selectedRowsCount(d->searchResultsSelectionModel);
632
const bool haveOneSelectedResult = nSelectedResults == 1;
633
const bool haveSelectedImages = !d->kipiImageSelectionModel->selectedRows().isEmpty();
635
d->actionCopyCoordinates->setEnabled(haveOneSelectedResult);
636
d->actionMoveImagesToThisResult->setEnabled(haveOneSelectedResult && haveSelectedImages);
637
d->actionRemovedSelectedSearchResultsFromList->setEnabled(nSelectedResults>=1);
639
const bool haveSearchText = !d->searchTermLineEdit->text().isEmpty();
641
d->searchButton->setEnabled(haveSearchText&&!d->searchInProgress);
642
d->actionClearResultsList->setEnabled(d->searchResultsModel->rowCount()>0);
643
d->actionToggleAllResultsVisibility->setIcon(
644
d->actionToggleAllResultsVisibility->isChecked() ?
645
d->actionToggleAllResultsVisibilityIconChecked :
646
d->actionToggleAllResultsVisibilityIconUnchecked
650
bool SearchWidget::eventFilter(QObject *watched, QEvent *event)
652
if (watched==d->treeView)
654
// we are only interested in context-menu events:
655
if (event->type()==QEvent::ContextMenu)
657
if (d->searchResultsSelectionModel->hasSelection())
659
const QModelIndex currentIndex = d->searchResultsSelectionModel->currentIndex();
660
const SearchResultModel::SearchResultItem searchResult = d->searchResultsModel->resultItem(currentIndex);
661
d->gpsBookmarkOwner->setPositionAndTitle(searchResult.result.coordinates, searchResult.result.name);
664
slotUpdateActionAvailability();
666
// construct the context-menu:
667
KMenu* const menu = new KMenu(d->treeView);
668
menu->addAction(d->actionCopyCoordinates);
669
menu->addAction(d->actionMoveImagesToThisResult);
670
menu->addAction(d->actionRemovedSelectedSearchResultsFromList);
671
// menu->addAction(d->actionBookmark);
672
d->gpsBookmarkOwner->changeAddBookmark(true);
674
QContextMenuEvent* const e = static_cast<QContextMenuEvent*>(event);
675
menu->exec(e->globalPos());
680
return QObject::eventFilter(watched, event);
683
void SearchWidget::slotCopyCoordinates()
685
const QModelIndex currentIndex = d->searchResultsSelectionModel->currentIndex();
686
const SearchResultModel::SearchResultItem currentItem = d->searchResultsModel->resultItem(currentIndex);
688
CoordinatesToClipboard(currentItem.result.coordinates, KUrl(), currentItem.result.name);
691
void SearchWidget::saveSettingsToGroup(KConfigGroup* const group)
693
group->writeEntry("Keep old results", d->actionKeepOldResults->isChecked());
694
group->writeEntry("Search backend", d->backendSelectionBox->itemData(d->backendSelectionBox->currentIndex()).toString());
696
slotUpdateActionAvailability();
699
void SearchWidget::readSettingsFromGroup(const KConfigGroup* const group)
701
d->actionKeepOldResults->setChecked(group->readEntry("Keep old results", false));
702
const QString backendId = group->readEntry("Search backend", "osm");
703
for (int i=0; i<d->backendSelectionBox->count(); ++i)
705
if (d->backendSelectionBox->itemData(i).toString()==backendId)
707
d->backendSelectionBox->setCurrentIndex(i);
713
KGeoMap::ModelHelper::Flags SearchResultModelHelper::modelFlags() const
715
return FlagSnaps|(d->visible?FlagVisible:FlagNull);
718
KGeoMap::ModelHelper::Flags SearchResultModelHelper::itemFlags(const QModelIndex& /*index*/) const
720
return FlagVisible|FlagSnaps;
723
void SearchResultModelHelper::snapItemsTo(const QModelIndex& targetIndex, const QList<QModelIndex>& snappedIndices)
725
GPSUndoCommand* const undoCommand = new GPSUndoCommand();
727
SearchResultModel::SearchResultItem targetItem = d->model->resultItem(targetIndex);
728
const KGeoMap::GeoCoordinates& targetCoordinates = targetItem.result.coordinates;
729
for (int i=0; i<snappedIndices.count(); ++i)
731
const QPersistentModelIndex itemIndex = snappedIndices.at(i);
732
KipiImageItem* const item = d->imageModel->itemFromIndex(itemIndex);
734
GPSUndoCommand::UndoInfo undoInfo(itemIndex);
735
undoInfo.readOldDataFromItem(item);
737
GPSDataContainer newData;
738
newData.setCoordinates(targetCoordinates);
739
item->setGPSData(newData);
741
undoInfo.readNewDataFromItem(item);
743
undoCommand->addUndoInfo(undoInfo);
745
undoCommand->setText(i18np("1 image snapped to '%2'",
746
"%1 images snapped to '%2'", snappedIndices.count(), targetItem.result.name));
748
emit(signalUndoCommand(undoCommand));
751
void SearchWidget::slotMoveSelectedImagesToThisResult()
753
const QModelIndex currentIndex = d->searchResultsSelectionModel->currentIndex();
754
const SearchResultModel::SearchResultItem currentItem = d->searchResultsModel->resultItem(currentIndex);
755
const KGeoMap::GeoCoordinates& targetCoordinates = currentItem.result.coordinates;
757
const QModelIndexList selectedImageIndices = d->kipiImageSelectionModel->selectedRows();
758
if (selectedImageIndices.isEmpty())
763
GPSUndoCommand* const undoCommand = new GPSUndoCommand();
764
for (int i=0; i<selectedImageIndices.count(); ++i)
766
const QPersistentModelIndex itemIndex = selectedImageIndices.at(i);
767
KipiImageItem* const item = d->kipiImageModel->itemFromIndex(itemIndex);
769
GPSUndoCommand::UndoInfo undoInfo(itemIndex);
770
undoInfo.readOldDataFromItem(item);
772
GPSDataContainer newData;
773
newData.setCoordinates(targetCoordinates);
774
item->setGPSData(newData);
776
undoInfo.readNewDataFromItem(item);
778
undoCommand->addUndoInfo(undoInfo);
780
undoCommand->setText(i18np("1 image moved to '%2'",
781
"%1 images moved to '%2'", selectedImageIndices.count(), currentItem.result.name));
783
emit(signalUndoCommand(undoCommand));
786
void SearchWidget::setPrimaryMapWidget(KGeoMap::KGeoMapWidget* const mapWidget)
788
d->mapWidget = mapWidget;
791
void SearchResultModel::removeRowsByIndexes(const QModelIndexList& rowsList)
793
// extract the row numbers first:
794
QList<int> rowNumbers;
795
Q_FOREACH(const QModelIndex& index, rowsList)
799
rowNumbers << index.row();
802
if (rowNumbers.isEmpty())
807
qSort(rowNumbers.begin(), rowNumbers.end());
809
// now delete the rows, starting with the last row:
810
for (int i=rowNumbers.count()-1; i>=0; i--)
812
const int rowNumber = rowNumbers.at(i);
814
/// @todo This is very slow for several indexes, because the views update after every removal
815
beginRemoveRows(QModelIndex(), rowNumber, rowNumber);
816
d->searchResults.removeAt(rowNumber);
821
static bool RowRangeLessThan(const QPair<int, int>& a, const QPair<int, int>& b)
823
return a.first < b.first;
826
void SearchResultModel::removeRowsBySelection(const QItemSelection& selectionList)
828
// extract the row numbers first:
829
QList<QPair<int, int> > rowRanges;
830
Q_FOREACH(const QItemSelectionRange& range, selectionList)
832
rowRanges << QPair<int, int>(range.top(), range.bottom());
835
// we expect the ranges to be sorted here
836
qSort(rowRanges.begin(), rowRanges.end(), RowRangeLessThan);
838
// now delete the rows, starting with the last row:
839
for (int i=rowRanges.count()-1; i>=0; i--)
841
const QPair<int, int> currentRange = rowRanges.at(i);
843
/// @todo This is very slow for several indexes, because the views update after every removal
844
beginRemoveRows(QModelIndex(), currentRange.first, currentRange.second);
845
for (int j=currentRange.second; j>=currentRange.first; j--)
847
d->searchResults.removeAt(j);
853
void SearchWidget::slotRemoveSelectedFromResultsList()
855
const QItemSelection selectedRows = d->searchResultsSelectionModel->selection();
856
if (selectedRows.isEmpty())
861
d->searchResultsModel->removeRowsBySelection(selectedRows);
863
slotUpdateActionAvailability();
866
} /* KIPIGPSSyncPlugin */