1 /***************************************************************************
2 gamelist.cpp - Game List window
3 -------------------
4 begin : Sun 23 Jul 2006
5 copyright : (C) 2006 Michal Rudolf <mrudolf@kdewebdev.org>
6 ***************************************************************************/
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 "database.h"
18 #include "filter.h"
19 #include "filtermodel.h"
20 #include "gamelist.h"
21 #include "gamelistsortmodel.h"
22 #include "GameMimeData.h"
23 #include "numbersearch.h"
24 #include "quicksearch.h"
25 #include "settings.h"
26 #include "tags.h"
27 #include "tagsearch.h"
28
29 #include "gamex.h"
30 #include "output.h"
31 #include "boardview.h"
32
33 #include <qevent.h>
34 #include <QDrag>
35 #include <QHeaderView>
36 #include <QMenu>
37 #include <QPixmap>
38
39 #if defined(_MSC_VER) && defined(_DEBUG)
40 #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
41 #define new DEBUG_NEW
42 #endif // _MSC_VER
43
GameList(FilterX * filter,QWidget * parent)44 GameList::GameList(FilterX* filter, QWidget* parent) : TableView(parent)
45 {
46 setSelectionMode(QAbstractItemView::ExtendedSelection);
47 setObjectName("GameList");
48 setWindowTitle(tr("Game list"));
49 m_model = new FilterModel(filter);
50 connect(m_model, SIGNAL(searchProgress(int)), SIGNAL(searchProgress(int)));
51 connect(m_model, SIGNAL(searchFinished()), SIGNAL(searchFinished()));
52
53 sortModel = new GameListSortModel(nullptr);
54 sortModel->setFilter(filter);
55 sortModel->setSourceModel(m_model);
56 sortModel->setDynamicSortFilter(true);
57 setModel(sortModel);
58
59 connect(this, SIGNAL(clicked(const QModelIndex&)), SLOT(itemSelected(const QModelIndex&)));
60 connect(this, SIGNAL(activated(const QModelIndex&)), SLOT(itemSelected(const QModelIndex&)));
61 connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(slotContextMenu(const QPoint&)));
62 connect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
63 this, SLOT(slotItemSelected(QModelIndex)));
64 #if QT_VERSION < 0x050000
65 horizontalHeader()->setClickable(true);
66 #else
67 horizontalHeader()->setSectionsClickable(true);
68 #endif
69
70 horizontalHeader()->setSortIndicatorShown(true);
71 setSortingEnabled(true);
72
73 setDragEnabled(true);
74 setAcceptDrops(true);
75 }
76
77
~GameList()78 GameList::~GameList()
79 {
80 setModel(nullptr);
81 delete sortModel;
82 delete m_model;
83 }
84
startUpdate()85 void GameList::startUpdate()
86 {
87 if (m_model)
88 {
89 m_model->startUpdate();
90 }
91 }
92
endUpdate()93 void GameList::endUpdate()
94 {
95 if (m_model)
96 {
97 m_model->endUpdate();
98 }
99 }
100
slotReconfigure()101 void GameList::slotReconfigure()
102 {
103 if (m_model)
104 {
105 m_model->updateColumns();
106 }
107 TableView::slotReconfigure();
108 }
109
ShowContextMenu(const QPoint & pos)110 void GameList::ShowContextMenu(const QPoint& pos)
111 {
112 QMenu headerMenu;
113 QAction* filterTag = headerMenu.addAction(tr("Find tag..."));
114 headerMenu.addSeparator();
115 QAction* hide = headerMenu.addAction(tr("Hide Column"));
116 headerMenu.addSeparator();
117 QAction* resizeAll = headerMenu.addAction(tr("Resize visible Columns"));
118 QAction* showAll = headerMenu.addAction(tr("Show all Columns"));
119
120 QAction* selectedItem = headerMenu.exec(mapToGlobal(pos));
121 int column = columnAt(pos.x());
122 if (selectedItem == filterTag)
123 {
124 simpleSearch(column);
125 }
126 else if(selectedItem == hide)
127 {
128 if(column > 0)
129 {
130 hideColumn(column);
131 }
132 }
133 else if(selectedItem == showAll)
134 {
135 for(int i = 0; i < model()->columnCount(); ++i)
136 {
137 showColumn(i);
138 }
139 }
140 else if (selectedItem == resizeAll)
141 {
142 resizeColumnsToContents();
143 }
144 }
145
removeSelection()146 void GameList::removeSelection()
147 {
148 clearSelection();
149 emit signalFirstGameLoaded(true);
150 emit signalLastGameLoaded(true);
151 }
152
slotItemSelected(const QModelIndex & index)153 void GameList::slotItemSelected(const QModelIndex& index)
154 {
155 scrollTo(index, EnsureVisible);
156 }
157
filterInvert()158 void GameList::filterInvert()
159 {
160 m_model->invert();
161 }
162
filterSetAll(int value)163 void GameList::filterSetAll(int value)
164 {
165 m_model->setAll(value);
166 }
167
NewSortIndex(int row) const168 QModelIndex GameList::NewSortIndex(int row) const
169 {
170 QModelIndex m = sortModel->index(row,0);
171 return m;
172 }
173
GetSourceIndex(const QModelIndex & index) const174 QModelIndex GameList::GetSourceIndex(const QModelIndex& index) const
175 {
176 QModelIndex m = sortModel->mapToSource(index);
177 return m;
178 }
179
GetSortModelIndex(const QModelIndex & index) const180 QModelIndex GameList::GetSortModelIndex(const QModelIndex& index) const
181 {
182 QModelIndex m = sortModel->mapFromSource(index);
183 return m;
184 }
185
itemSelected(const QModelIndex & index)186 void GameList::itemSelected(const QModelIndex& index)
187 {
188 if (selectionModel()->selectedRows().size() == 1)
189 {
190 QModelIndex m = GetSourceIndex(index);
191 GameId n = m.row();
192 if (VALID_INDEX(n))
193 {
194 emit gameSelected(n);
195 }
196 }
197 }
198
triggerGameSelection(int sortRow)199 bool GameList::triggerGameSelection(int sortRow)
200 {
201 QModelIndex sortIndex = NewSortIndex(sortRow);
202 QModelIndex sourceIndex = GetSourceIndex(sortIndex);
203 GameId game = sourceIndex.row();
204 if (VALID_INDEX(game))
205 {
206 emit gameSelected(sourceIndex.row());
207 return true;
208 }
209 return false;
210 }
211
selectPreviousGame()212 void GameList::selectPreviousGame()
213 {
214 QModelIndex sortIndex = currentIndex();
215 int oldRow = sortIndex.row();
216 int row = std::max(0, sortIndex.row()-1);
217 if (row != oldRow)
218 {
219 triggerGameSelection(row);
220 }
221 }
222
selectNextGame()223 bool GameList::selectNextGame()
224 {
225 QModelIndex sortIndex = currentIndex();
226 int oldRow = sortIndex.row();
227 int row = std::min(m_model->filter()->count()-1, oldRow+1);
228 if (row != oldRow)
229 {
230 return triggerGameSelection(row);
231 }
232 return false;
233 }
234
selectRandomGame()235 void GameList::selectRandomGame()
236 {
237 if(m_model->filter()->count()>1)
238 {
239 QModelIndex sortIndex = currentIndex();
240 int oldRow = sortIndex.row();
241 int randomSortRow = rand() % (m_model->filter()->count()-1); // The last game is represented by current game
242 if (oldRow == randomSortRow)
243 {
244 randomSortRow = m_model->filter()->count()-1;
245 }
246 QModelIndex sourceIndex = GetSourceIndex(NewSortIndex(randomSortRow));
247 GameId game = sourceIndex.row();
248 if (VALID_INDEX(game))
249 {
250 emit gameSelected(game);
251 }
252 }
253 }
254
setFilter(FilterX * filter)255 void GameList::setFilter(FilterX* filter)
256 {
257 if (filter)
258 {
259 m_model->startUpdate();
260 sortModel->setFilter(filter);
261 m_model->setFilter(filter);
262 sortByColumn(0, Qt::AscendingOrder); // Hack to ensure fast opening after loading DB
263 m_model->endUpdate();
264 }
265 if (AppSettings->value("/MainWindow/AutoRaise").toBool())
266 {
267 emit raiseRequest();
268 }
269 }
270
keyPressEvent(QKeyEvent * event)271 void GameList::keyPressEvent(QKeyEvent* event)
272 {
273 if ((event->modifiers() & Qt::KeyboardModifierMask) == Qt::MetaModifier)
274 {
275 switch (event->key())
276 {
277 case Qt::Key_A: selectAll(); break;
278 case Qt::Key_C: slotCopyGame(); break;
279 case Qt::Key_X: slotDeleteGame(); break;
280 case Qt::Key_H: slotHideGame(); break;
281 }
282 update();
283 }
284 TableView::keyPressEvent(event);
285 }
286
slotContextMenu(const QPoint & pos)287 void GameList::slotContextMenu(const QPoint& pos)
288 {
289 QModelIndex cell = indexAt(pos);
290 QModelIndexList selection = selectedIndexes();
291 QMenu menu(tr("Game list"), this);
292 if(cell.isValid() && selection.contains(cell))
293 {
294 // Right click occured on a cell!
295 menu.addAction(tr("Copy games..."), this, SLOT(slotCopyGame()));
296 menu.addAction(tr("Filter twins"), this, SLOT(slotFindDuplicate()));
297 QMenu* mergeMenu = menu.addMenu(tr("Merge into current game"));
298 mergeMenu->addAction(tr("All Games"), this, SLOT(slotMergeAllGames()));
299 mergeMenu->addAction(tr("Filter"), this, SLOT(slotMergeFilter()));
300 mergeMenu->addAction(tr("Selected games"), this, SLOT(slotMergeSelectedGames()));
301 menu.addSeparator();
302
303 int deleted = 0;
304 int activated = 0;
305 QModelIndexList list = selectionModel()->selectedRows();
306 foreach(QModelIndex index, list)
307 {
308 QModelIndex source = GetSourceIndex(index);
309 GameId n = source.row();
310 if (VALID_INDEX(n))
311 {
312 if (m_model->filter()->database()->deleted(n))
313 {
314 ++deleted;
315 }
316 else
317 {
318 ++activated;
319 }
320 }
321 if (activated && deleted)
322 {
323 break;
324 }
325 }
326
327 QAction* deleteAction;
328 if (activated && deleted)
329 {
330 deleteAction = menu.addAction(tr("Toggle deletions"), this, SLOT(slotDeleteGame()));
331 }
332 else
333 {
334 QString deleteText;
335 if (deleted)
336 {
337 deleteText = selection.count()>1 ? tr("Undelete games") : tr("Undelete game");
338 }
339 else
340 {
341 deleteText = selection.count()>1 ? tr("Delete games") : tr("Delete game");
342 }
343 deleteAction = menu.addAction(deleteText, this, SLOT(slotDeleteGame()));
344 }
345 deleteAction->setEnabled(!m_model->filter()->database()->isReadOnly());
346
347 menu.addSeparator();
348 QString hideText = selection.count()>1 ? tr("Hide games") : tr("Hide game");
349 menu.addAction(hideText, this, SLOT(slotHideGame()));
350 deleteAction = menu.addAction(tr("Hide deleted games"), this, SLOT(slotHideDeletedGames()));
351 deleteAction->setEnabled(activated && deleted);
352 menu.addAction(tr("Select All"), this, SLOT(selectAll()));
353 menu.addSeparator();
354 }
355 menu.addAction(tr("Reset filter"), this, SLOT(filterSetAll()));
356 menu.addAction(tr("Reverse filter"), this, SLOT(filterInvert()));
357 menu.exec(mapToGlobal(pos));
358 }
359
executeSearch(Search * search,FilterOperator searchOperator)360 void GameList::executeSearch(Search* search, FilterOperator searchOperator)
361 {
362 m_model->executeSearch(search, searchOperator, 0);
363 }
364
simpleSearch(int tagid)365 void GameList::simpleSearch(int tagid)
366 {
367 QuickSearchDialog dlg(this);
368 for (int section = 0; section < m_model->columnCount(); ++section)
369 {
370 QString tag = m_model->headerData(section, Qt::Horizontal).toString();
371 dlg.addTag(tag);
372 }
373
374 dlg.setTag(tagid);
375 dlg.setMode(1);
376
377 if(dlg.exec() != QDialog::Accepted)
378 {
379 return;
380 }
381
382 QString tag = m_model->GetColumnTags().at(dlg.tag());
383 QString value = dlg.value();
384 if(value.isEmpty())
385 {
386 m_model->filter()->setAll(1);
387 }
388 else if(dlg.tag() == 0)
389 {
390 // filter by number
391 Search* ns = new NumberSearch(m_model->filter()->database(), value);
392 m_model->executeSearch(ns, FilterOperator(dlg.mode()));
393 }
394 else
395 {
396 QStringList list = value.split("-", QString::SkipEmptyParts);
397 if ((list.size() > 1) && (dlg.tag() != 9)) // Tag 9 is the Result
398 {
399 // Filter a range
400 Search* ts = (dlg.tag() == 11) ? // Tag 11 is number of moves
401 new TagSearch(m_model->filter()->database(), tag, list.at(0).toInt(), list.at(1).toInt()) :
402 new TagSearch(m_model->filter()->database(), tag, list.at(0), list.at(1));
403 if(dlg.mode())
404 {
405 m_model->executeSearch(ts, FilterOperator(dlg.mode()));
406 }
407 else
408 {
409 m_model->executeSearch(ts);
410 }
411 }
412 else
413 {
414 // Filter tag using partial values
415 Search* ts = new TagSearch(m_model->filter()->database(), tag, value);
416 m_model->executeSearch(ts, FilterOperator(dlg.mode()));
417 }
418 }
419 if (AppSettings->value("/MainWindow/AutoRaise").toBool())
420 {
421 emit raiseRequest();
422 }
423 }
424
slotFilterListByPlayer(QString s)425 void GameList::slotFilterListByPlayer(QString s)
426 {
427 FilterOperator op = FilterOperator::NullOperator;
428 if (s.startsWith("+"))
429 {
430 s.remove(0,1);
431 op = FilterOperator::Or;
432 }
433 QUrl url(s);
434 QString fragment = url.fragment();
435
436 if (fragment.isEmpty())
437 {
438 Search* ts = new TagSearch(m_model->filter()->database(), TagNameWhite, url.path());
439 Search* ts2 = new TagSearch(m_model->filter()->database(), TagNameBlack, url.path());
440 ts->AddSearch(ts2, FilterOperator::Or);
441 m_model->executeSearch(ts, op);
442 }
443 else
444 {
445 Search* ts = new TagSearch(m_model->filter()->database(), fragment, url.path());
446 m_model->executeSearch(ts, op);
447 }
448 if (AppSettings->value("/MainWindow/AutoRaise").toBool())
449 {
450 emit raiseRequest();
451 }
452 }
453
slotFilterListByEcoPlayer(QString tag,QString eco,QString player,QString result)454 void GameList::slotFilterListByEcoPlayer(QString tag, QString eco, QString player, QString result)
455 {
456 m_model->filter()->setAll(1); // ??
457 Search* ts = nullptr;
458 if (!player.isEmpty())
459 {
460 ts = new TagSearch(m_model->filter()->database(), tag, player);
461 }
462 Search* ts2 = ts;
463 if (!eco.isEmpty())
464 {
465 ts2 = new TagSearch(m_model->filter()->database(), TagNameECO, eco);
466 if (ts)
467 {
468 ts->AddSearch(ts2, FilterOperator::And);
469 }
470 else
471 {
472 ts = ts2;
473 }
474 }
475 if (!result.isEmpty())
476 {
477 Search* ts3 = new TagSearch(m_model->filter()->database(), TagNameResult, result);
478 if (ts2)
479 {
480 ts2->AddSearch(ts3, FilterOperator::And);
481 }
482 else // ts is also 0, as otherwise t2 is non-null
483 {
484 ts = ts3;
485 }
486 }
487 m_model->executeSearch(ts);
488 if (AppSettings->value("/MainWindow/AutoRaise").toBool())
489 {
490 emit raiseRequest();
491 }
492 }
493
slotFilterListByEvent(QString s)494 void GameList::slotFilterListByEvent(QString s)
495 {
496 FilterOperator op = FilterOperator::NullOperator;
497 if (s.startsWith("+"))
498 {
499 s.remove(0,1);
500 op = FilterOperator::Or;
501 }
502
503 Search* ts = new TagSearch(m_model->filter()->database(), TagNameEvent, s);
504 m_model->executeSearch(ts, op);
505 if (AppSettings->value("/MainWindow/AutoRaise").toBool())
506 {
507 emit raiseRequest();
508 }
509 }
510
slotFilterListByEventPlayer(QString player,QString event)511 void GameList::slotFilterListByEventPlayer(QString player, QString event)
512 {
513 m_model->filter()->setAll(1);
514 Search* ts = new TagSearch(m_model->filter()->database(), TagNameWhite, player);
515 Search* ts2 = new TagSearch(m_model->filter()->database(), TagNameBlack, player);
516 Search* ts3 = new TagSearch(m_model->filter()->database(), TagNameEvent, event);
517 ts->AddSearch(ts2, FilterOperator::Or);
518 ts2->AddSearch(ts3, FilterOperator::And);
519 m_model->executeSearch(ts);
520 if (AppSettings->value("/MainWindow/AutoRaise").toBool())
521 {
522 emit raiseRequest();
523 }
524 }
525
slotFilterListByEco(QString s)526 void GameList::slotFilterListByEco(QString s)
527 {
528 FilterOperator op = FilterOperator::NullOperator;
529 if (s.startsWith("+"))
530 {
531 s.remove(0,1);
532 op = FilterOperator::Or;
533 }
534 Search* ts = new TagSearch(m_model->filter()->database(), TagNameECO, s);
535 m_model->executeSearch(ts, op);
536 }
537
endSearch()538 void GameList::endSearch()
539 {
540 if (AppSettings->value("/MainWindow/AutoRaise").toBool())
541 {
542 emit raiseRequest();
543 }
544 }
545
selectGame(GameId index)546 void GameList::selectGame(GameId index)
547 {
548 if (VALID_INDEX(index))
549 {
550 QModelIndex filterModelIndex = m_model->index(index, 0);
551 QModelIndex sortModelIndex = GetSortModelIndex(filterModelIndex);
552 setCurrentIndex(sortModelIndex);
553 emit signalFirstGameLoaded(!m_model->filter()->count() || (sortModelIndex.row()==0));
554 emit signalLastGameLoaded(sortModelIndex.row()+1 >= m_model->filter()->count());
555 }
556 else
557 {
558 emit signalFirstGameLoaded(true);
559 emit signalLastGameLoaded(true);
560 }
561 emit signalFilterSize(m_model->filter()->count());
562 }
563
updateFilter(GameId index,int value)564 void GameList::updateFilter(GameId index, int value)
565 {
566 if (m_model->filter()->database()) // ?
567 {
568 if (VALID_INDEX(index))
569 {
570 m_model->set(index, value);
571 }
572 }
573 }
574
selectedGames()575 QList<GameId> GameList::selectedGames()
576 {
577 QList<GameId> gameIndexList;
578 foreach(QModelIndex index, selectionModel()->selectedRows())
579 {
580 QModelIndex m = GetSourceIndex(index);
581 GameId n = m.row();
582 if (VALID_INDEX(n))
583 {
584 gameIndexList.append(n);
585 }
586 }
587 return gameIndexList;
588 }
589
slotCopyGame()590 void GameList::slotCopyGame()
591 {
592 QList<GameId> gameIndexList = selectedGames();
593 emit requestCopyGame(gameIndexList);
594 }
595
slotFindDuplicate()596 void GameList::slotFindDuplicate()
597 {
598 QList<GameId> gameIndexList = selectedGames();
599 emit requestFindDuplicates(gameIndexList);
600 }
601
slotMergeAllGames()602 void GameList::slotMergeAllGames()
603 {
604 emit requestMergeAllGames();
605 }
606
slotMergeFilter()607 void GameList::slotMergeFilter()
608 {
609 emit requestMergeFilter();
610 }
611
slotMergeSelectedGames()612 void GameList::slotMergeSelectedGames()
613 {
614 QList<GameId> gameIndexList = selectedGames();
615 emit requestMergeGame(gameIndexList);
616 }
617
slotDeleteGame()618 void GameList::slotDeleteGame()
619 {
620 QList<GameId> gameIndexList = selectedGames();
621 emit requestDeleteGame(gameIndexList);
622 }
623
slotHideGame()624 void GameList::slotHideGame()
625 {
626 QList<GameId> gameIndexList = selectedGames();
627 foreach(GameId game, gameIndexList)
628 {
629 m_model->set(game, 0);
630 }
631 }
632
slotHideDeletedGames()633 void GameList::slotHideDeletedGames()
634 {
635 QList<GameId> gameIndexList = selectedGames();
636 if (!gameIndexList.isEmpty())
637 {
638 m_model->startUpdate();
639 foreach(GameId game, gameIndexList)
640 {
641 if (m_model->filter()->database()->deleted(game))
642 {
643 m_model->set(game,0);
644 }
645 }
646 m_model->endUpdate();
647 }
648 }
649
startDrag(Qt::DropActions supportedActions)650 void GameList::startDrag(Qt::DropActions supportedActions)
651 {
652 TableView::startDrag(supportedActions);
653
654 GameMimeData *mimeData = new GameMimeData;
655 mimeData->source = m_model->filter()->database()->filename();
656 foreach(QModelIndex index, selectionModel()->selectedRows())
657 {
658 QModelIndex m = GetSourceIndex(index);
659 int row = m.row();
660 GameId gameIndex = row;
661 if (VALID_INDEX(gameIndex))
662 {
663 mimeData->m_indexList.append(gameIndex);
664 }
665 }
666
667 if (mimeData->m_indexList.count() < 1000) // Avoid excessive size of clipboard
668 {
669 QString text;
670 foreach(GameId gameIndex, mimeData->m_indexList)
671 {
672 GameX g;
673 if(m_model->filter()->database()->loadGame(gameIndex, g))
674 {
675 Output textWriter(Output::Pgn, &BoardView::renderImageForBoard);
676 QString pgn = textWriter.output(&g);
677 if (!text.isEmpty())
678 {
679 text.append("\r\n");
680 }
681 text.append(pgn);
682 text.append("\r\n");
683 }
684 }
685 mimeData->setText(text);
686 }
687
688 QPixmap pixmap = style()->standardPixmap(QStyle::SP_FileIcon);
689
690 QDrag* pDrag = new QDrag(this);
691 pDrag->setMimeData(mimeData);
692 pDrag->setPixmap(pixmap);
693
694 pDrag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
695 }
696
dragEnterEvent(QDragEnterEvent * event)697 void GameList::dragEnterEvent(QDragEnterEvent *event)
698 {
699 TableView::dragEnterEvent(event);
700 const QMimeData *mimeData = event->mimeData();
701 const DbMimeData* dbMimeData = qobject_cast<const DbMimeData*>(mimeData);
702 const GameMimeData* gameMimeData = qobject_cast<const GameMimeData*>(mimeData);
703
704 if (gameMimeData && (m_model->filter()->database()->filename() == gameMimeData->source))
705 {
706 event->acceptProposedAction();
707 }
708 else if(dbMimeData || gameMimeData || (mimeData && mimeData->hasUrls()))
709 {
710 event->acceptProposedAction();
711 }
712 }
713
dragMoveEvent(QDragMoveEvent * event)714 void GameList::dragMoveEvent(QDragMoveEvent *event)
715 {
716 TableView::dragMoveEvent(event);
717 const QMimeData *mimeData = event->mimeData();
718 const DbMimeData* dbMimeData = qobject_cast<const DbMimeData*>(mimeData);
719 const GameMimeData* gameMimeData = qobject_cast<const GameMimeData*>(mimeData);
720
721 if (gameMimeData && (m_model->filter()->database()->filename() == gameMimeData->source))
722 {
723 event->ignore();
724 }
725 else if(dbMimeData || gameMimeData || (mimeData && mimeData->hasUrls()))
726 {
727 event->acceptProposedAction();
728 }
729 else
730 {
731 event->ignore();
732 }
733 }
734
dragLeaveEvent(QDragLeaveEvent * event)735 void GameList::dragLeaveEvent(QDragLeaveEvent *event)
736 {
737 TableView::dragLeaveEvent(event);
738 event->accept();
739 }
740
dropEvent(QDropEvent * event)741 void GameList::dropEvent(QDropEvent *event)
742 {
743 TableView::dropEvent(event);
744 if (event->dropAction())
745 {
746 const QMimeData *mimeData = event->mimeData();
747 const DbMimeData* dbMimeData = qobject_cast<const DbMimeData*>(mimeData);
748 const GameMimeData* gameMimeData = qobject_cast<const GameMimeData*>(mimeData);
749
750 if(dbMimeData || (mimeData && mimeData->hasUrls()))
751 {
752 m_model->startUpdate();
753 emit signalDropEvent(event);
754 m_model->endUpdate();
755 }
756 else if (gameMimeData)
757 {
758 emit requestAppendGames(m_model->filter()->database()->filename(), gameMimeData->m_indexList, gameMimeData->source);
759 }
760 else
761 {
762 event->ignore();
763 }
764 }
765 }
766