TTKMusicPlayer  4.1.3.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
musicsongscontainerwidget.cpp
Go to the documentation of this file.
5 #include "musicmessagebox.h"
6 #include "musicconnectionpool.h"
7 #include "musicprogresswidget.h"
11 #include "musicapplication.h"
12 #include "musictoastlabel.h"
13 #include "musicfileutils.h"
14 #include "musicformats.h"
15 
16 #include <QMimeData>
17 
18 static constexpr int ITEM_MIN_COUNT = MIN_ITEM_COUNT;
19 static constexpr int ITEM_MAX_COUNT = 10;
20 static constexpr int RECENT_ITEM_MAX_COUNT = 50;
21 
23 
25  : MusicSongsToolBoxWidget(parent),
27  m_playRowIndex(MUSIC_NORMAL_LIST),
28  m_lastSearchIndex(MUSIC_NORMAL_LIST),
29  m_selectDeleteIndex(MUSIC_NONE_LIST),
30  m_listFunctionWidget(nullptr),
31  m_songSearchWidget(nullptr)
32 {
33  m_instance = this;
34 
35  setAcceptDrops(true);
36 
39 
40  connect(m_listMaskWidget, SIGNAL(itemIndexChanged(int)), SLOT(itemIndexChanged(int)));
41  connect(m_scrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(sliderValueChanaged(int)));
42 
43  G_CONNECTION_PTR->setValue(className(), this);
44  G_CONNECTION_PTR->connect(MusicQueryTableWidget::className(), className());
45 }
46 
48 {
49  G_CONNECTION_PTR->removeValue(this);
50  delete m_listMaskWidget;
51  delete m_listFunctionWidget;
52  delete m_songSearchWidget;
53 
54  while(!m_containerItems.isEmpty())
55  {
56  delete m_containerItems.takeLast().m_itemWidget;
57  }
58 }
59 
61 {
62  return m_instance;
63 }
64 
66 {
67  int index = -1;
68  for(int i = 0; i < m_containerItems.count(); ++i)
69  {
70  if(item.m_id == m_containerItems[i].m_id)
71  {
72  index = i;
73  break;
74  }
75  }
76 
77  if(index == -1)
78  {
79  appendSongItemList({item});
80  }
81  else
82  {
83  MusicSongItem *songItem = &m_containerItems[index];
84  songItem->m_sort = item.m_sort;
85  songItem->m_songs =item.m_songs;
86  songItem->m_itemName = item.m_itemName;
87  songItem->m_itemWidget->removeItems();
88  songItem->m_itemWidget->updateSongsList(songItem->m_songs);
89  setItemTitle(songItem);
90 
92  {
95  }
96  }
97 }
98 
99 bool MusicSongsContainerWidget::addSongItemList(const MusicSongItemList &items)
100 {
101  TTKIntSet inDeed;
103  for(const MusicSongItem &item : qAsConst(items))
104  {
105  inDeed.remove(item.m_itemIndex);
106  }
107  //
108  if(!inDeed.isEmpty())
109  {
110  //if less than four count(0, 1, 2, 3), find and add default items
112  for(const int item : qAsConst(inDeed))
113  {
114  MusicSongItem songItem;
115  switch(item)
116  {
117  case MUSIC_NORMAL_LIST:
118  {
119  songItem.m_itemIndex = item;
120  songItem.m_itemName = tr("Default Item");
121  break;
122  }
123  case MUSIC_LOVEST_LIST:
124  {
125  songItem.m_itemIndex = item;
126  songItem.m_itemName = tr("Lovest Item");
127  break;
128  }
129  case MUSIC_NETWORK_LIST:
130  {
131  songItem.m_itemIndex = item;
132  songItem.m_itemName = tr("Net Item");
133  break;
134  }
135  case MUSIC_RECENT_LIST:
136  {
137  songItem.m_itemIndex = item;
138  songItem.m_itemName = tr("Recent Item");
139  break;
140  }
141  default: break;
142  }
143  m_containerItems << songItem;
144  }
145  std::sort(m_containerItems.begin(), m_containerItems.end());
146  }
147  else
148  {
150  }
151 
152  for(int i = 0; i < m_containerItems.count(); ++i)
153  {
155  }
156 
157  return inDeed.isEmpty();
158 }
159 
160 void MusicSongsContainerWidget::appendSongItemList(const MusicSongItemList &items)
161 {
162  for(int i = 0; i < items.count(); ++i)
163  {
164  m_containerItems << items[i];
165 
166  MusicSongItem *item = &m_containerItems.back();
167  item->m_itemIndex = ++m_itemIndexRaise;
168 
169  QString name = item->m_itemName;
170  item->m_itemName.clear();
171  checkTitleNameValid(name);
172  item->m_itemName = name;
173 
174  createWidgetItem(item);
175  }
176 }
177 
178 void MusicSongsContainerWidget::importSongsByUrl(const QString &path, int playlistRow)
179 {
180  if(path.isEmpty())
181  {
182  return;
183  }
184 
185  if(playlistRow < 0)
186  {
187  playlistRow = makeValidIndex();
188  }
189 
190  const QFileInfo fin(path);
191  if(fin.isDir())
192  {
193  QStringList files;
194  for(const QFileInfo &fin : TTK::File::fileInfoListByPath(path))
195  {
197  {
198  files << fin.absoluteFilePath();
199  }
200  }
201 
202  importSongsByPath(files, playlistRow);
203  }
204  else if(TTK::String::isNetworkUrl(path))
205  {
207 
209  const QString &prefix = TTK::String::splitToken(path, TTK_SEPARATOR, "?");
210  const QByteArray &md5 = TTK::Algorithm::md5(path.toUtf8());
211  const MusicSong song(path + "#" + md5 + "." + TTK::String::splitToken(path), TTK_DEFAULT_STR, TTK::String::pefix(prefix));
212 
213  if(item->m_songs.contains(song))
214  {
215  return;
216  }
217 
218  item->m_songs << song;
219  item->m_itemWidget->updateSongsList(item->m_songs);
220  setItemTitle(item);
221  }
222  else
223  {
224  QStringList files;
226  {
227  files << fin.absoluteFilePath();
228  }
229 
230  importSongsByPath(files, playlistRow);
231  }
232 }
233 
234 void MusicSongsContainerWidget::importSongsByPath(const QStringList &files, int playlistRow)
235 {
236  if(files.isEmpty())
237  {
238  return;
239  }
240 
241  if(playlistRow < 0)
242  {
243  playlistRow = makeValidIndex();
244  }
245 
247 
248  MusicProgressWidget progress;
249  progress.setTitle(tr("Import file mode"));
250  progress.setRange(0, files.count());
251  progress.show();
252 
253  MusicSongItem *item = &m_containerItems[playlistRow];
254 
255  int i = 0;
256  for(const QString &path : qAsConst(files))
257  {
258  if(item->m_songs.contains(MusicSong(path)))
259  {
260  continue;
261  }
262 
263  progress.setValue(++i);
264  item->m_songs << TTK::generateSongList(path);
265  }
266 
267  if(i != 0)
268  {
269  item->m_itemWidget->updateSongsList(item->m_songs);
270  setItemTitle(item);
271  setCurrentIndex(playlistRow);
272  }
273 
274  MusicToastLabel::popup(tr("Import music songs done"));
275 }
276 
277 QStringList MusicSongsContainerWidget::songsFileName(int index) const
278 {
279  QStringList list;
280 
281  if(index < 0 || index >= m_containerItems.count())
282  {
283  return list;
284  }
285 
286  for(const MusicSong &song : qAsConst(m_containerItems[index].m_songs))
287  {
288  list << song.name();
289  }
290  return list;
291 }
292 
293 QStringList MusicSongsContainerWidget::songsFilePath(int index) const
294 {
295  QStringList list;
296  if(index < 0 || index >= m_containerItems.count())
297  {
298  return list;
299  }
300 
301  for(const MusicSong &song : qAsConst(m_containerItems[index].m_songs))
302  {
303  list << song.path();
304  }
305  return list;
306 }
307 
308 int MusicSongsContainerWidget::mapSongIndexByFilePath(int playlistRow, const QString &path) const
309 {
310  if(playlistRow < 0 || playlistRow >= m_containerItems.count() || path.isEmpty())
311  {
312  return -1;
313  }
314 
315  const MusicSongList *songs = &m_containerItems[playlistRow].m_songs;
316  for(int i = 0; i < songs->count(); ++i)
317  {
318  if(MusicSong(path) == songs->at(i))
319  {
320  return i;
321  }
322  }
323  return -1;
324 }
325 
326 QString MusicSongsContainerWidget::mapFilePathBySongIndex(int playlistRow, int index) const
327 {
328  if(playlistRow < 0 || playlistRow >= m_containerItems.count())
329  {
330  return {};
331  }
332 
333  const MusicSongList *songs = &m_containerItems[playlistRow].m_songs;
334  if(index < 0 || index >= songs->count())
335  {
336  return {};
337  }
338 
339  return songs->at(index).path();
340 }
341 
343 {
345  {
346  return;
347  }
348 
349  const TTKIntList &result = m_searchResultItems.value(m_searchResultLevel);
350  if(row >= result.count() || row < 0)
351  {
352  row = -1;
353  return;
354  }
355 
356  row = result[row];
357 
360 }
361 
363 {
364  const int before = m_playRowIndex;
365  m_playRowIndex = index;
366 
367  if(before >= 0)
368  {
370  if(widget && !m_containerItems[before].m_songs.isEmpty())
371  {
372  widget->adjustPlayWidgetRow();
373  }
374  }
375 }
376 
378 {
379  if(!hasSearchResult())
380  {
381  selectRow(index);
382  resizeScrollIndex(index * 30);
383  }
384 }
385 
387 {
389  if(m_playRowIndex < 0)
390  {
391  return;
392  }
393 
395  m_containerItems[m_playRowIndex].m_itemWidget->selectRow(index);
396 }
397 
398 void MusicSongsContainerWidget::updateDurationLabel(const QString &current, const QString &total) const
399 {
400  if(m_playRowIndex < 0)
401  {
402  return;
403  }
404  TTKObjectCast(MusicSongsListPlayTableWidget*, m_containerItems[m_playRowIndex].m_itemWidget)->updateDurationLabel(current, total);
405 }
406 
408 {
409  if(m_containerItems.count() <= ITEM_MAX_COUNT)
410  {
411  QString name = tr("Default Item");
412  checkTitleNameValid(name);
413 
414  int id = 0;
415  for(const MusicSongItem &songItem : qAsConst(m_containerItems))
416  {
417  if(id < songItem.m_id)
418  {
419  id = songItem.m_id;
420  }
421  }
422 
423  MusicSongItem item;
424  item.m_id = id + 1;
425  item.m_itemName = name;
426  m_containerItems << item;
428  }
429  else
430  {
431  MusicToastLabel::popup(tr("Exceeded the maximum number limit"));
432  }
433 }
434 
436 {
437  const int id = foundMappedIndex(index);
438  if(id == -1)
439  {
440  return;
441  }
442 
443  MusicMessageBox message;
444  message.setText(tr("Are you sure to delete?"));
445  if(!message.exec())
446  {
447  return;
448  }
449 
450  const MusicSongItem *item = &m_containerItems[id];
452 
453  if(m_playRowIndex == id)
454  {
456  m_itemList.front().m_widgetItem->setExpand(false);
458  }
459  else if(m_playRowIndex > id)
460  {
462  }
463 
464  m_containerItems.takeAt(id);
465  removeItem(item->m_itemWidget);
466  delete item->m_itemWidget;
467 
468  updatePlayedList(id, -1);
469 }
470 
472 {
473  MusicMessageBox message;
474  message.setText(tr("Are you sure to delete?"));
475  if(!message.exec())
476  {
477  return;
478  }
479 
481  {
483  m_itemList.front().m_widgetItem->setExpand(false);
485  }
486 
487  for(int i = m_containerItems.count() - 1; i > 3; --i)
488  {
489  MusicSongItem item = m_containerItems.takeLast();
490  removeItem(item.m_itemWidget);
491  delete item.m_itemWidget;
492  }
493 }
494 
496 {
497  const int id = foundMappedIndex(index);
498  if(id == -1)
499  {
500  return;
501  }
502 
504 
505  m_selectDeleteIndex = id;
506  //
508  if(widget->rowCount() > 0)
509  {
510  widget->setCurrentCell(0, 1);
511  widget->clearItems();
512  }
513  //
515 
516  if(m_containerItems[id].m_songs.isEmpty() && m_playRowIndex == id)
517  {
519  }
520 }
521 
522 void MusicSongsContainerWidget::changRowItemName(int index, const QString &name)
523 {
524  const int id = foundMappedIndex(index);
525  if(id == -1)
526  {
527  return;
528  }
529 
530  bool found = false;
531  for(int i = 0; i < m_containerItems.count(); ++i)
532  {
533  if(i == id)
534  {
535  continue;
536  }
537 
538  if(m_containerItems[i].m_itemName == name)
539  {
540  found = true;
541  }
542  }
543 
544  MusicSongItem *item = &m_containerItems[id];
545  if(found)
546  {
547  MusicToastLabel::popup(tr("Item name is already exists"));
548  setItemTitle(item);
549  return;
550  }
551 
552  item->m_itemName = name;
553  setItemTitle(item);
554 }
555 
557 {
558  start = foundMappedIndex(start);
559  end = foundMappedIndex(end);
560  if(start == end)
561  {
562  return;
563  }
564 
565  //adjust the m_playRowIndex while the item has dragged and dropped
566  if(start < end)
567  {
568  if((start < m_playRowIndex && m_playRowIndex < end) || m_playRowIndex == end)
569  {
571  }
572  else if(m_playRowIndex == start)
573  {
575  }
576  }
577  else
578  {
579  if((end < m_playRowIndex && m_playRowIndex < start) || m_playRowIndex == end)
580  {
582  }
583  else if(m_playRowIndex == start)
584  {
586  }
587  }
588 
589  swapItem(start, end);
590  const MusicSongItem &item = m_containerItems.takeAt(start);
591  m_containerItems.insert(end, item);
592 
593  updatePlayedList(start, end);
594 }
595 
597 {
598  const int id = foundMappedIndex(index);
599  if(id == -1)
600  {
601  return;
602  }
603 
604  const MusicSongItem *item = &m_containerItems[id];
606 }
607 
609 {
610  const int id = foundMappedIndex(index);
611  if(id == -1)
612  {
613  return;
614  }
615 
616  const MusicSongItem *item = &m_containerItems[id];
618 }
619 
621 {
622  if(index == TTK_LOW_LEVEL)
623  {
624  index = m_currentIndex;
625  }
626  else
627  {
628  const int id = foundMappedIndex(index);
629  if(id == -1)
630  {
631  return;
632  }
633 
634  index = id;
635  }
636 
638 }
639 
641 {
642  if(index == TTK_LOW_LEVEL)
643  {
644  index = m_currentIndex;
645  }
646  else
647  {
648  const int id = foundMappedIndex(index);
649  if(id == -1)
650  {
651  return;
652  }
653 
654  index = id;
655  }
656 
658 }
659 
661 {
663 }
664 
666 {
668 }
669 
671 {
672  if(m_currentIndex == -1)
673  {
674  return;
675  }
676 
677  if(!isSearchedPlayIndex())
678  {
679  const QStringList searchedSongs(songsFileName(m_lastSearchIndex));
680  TTKIntList result;
681  for(int i = 0; i < searchedSongs.count(); ++i)
682  {
683  result << i;
684  }
685 
687  TTKObjectCast(MusicSongsListPlayTableWidget*, item->m_itemWidget)->updateSearchFileName(&item->m_songs, result);
688 
689  if(item->m_songs.isEmpty())
690  {
691  item->m_itemWidget->updateSongsList(item->m_songs);
692  }
693 
696  }
697 
698  const QString &text = m_songSearchWidget->text();
699  const QStringList searchedSongs(songsFileName(m_currentIndex));
700 
701  TTKIntList result;
702  for(int i = 0; i < searchedSongs.count(); ++i)
703  {
704  if(searchedSongs[i].contains(text, Qt::CaseInsensitive))
705  {
706  result << i;
707  }
708  }
709 
710  m_searchResultLevel = column;
711  m_searchResultItems.insert(column, result);
712 
714  TTKObjectCast(MusicSongsListPlayTableWidget*, item->m_itemWidget)->updateSearchFileName(&item->m_songs, result);
715 
716  if(column == 0)
717  {
718  if(item->m_songs.isEmpty())
719  {
720  item->m_itemWidget->updateSongsList(item->m_songs);
721  }
722 
724  }
725 }
726 
728 {
729  const QStringList &lastPlayIndex = G_SETTING_PTR->value(MusicSettingManager::LastPlayIndex).toStringList();
730  if(lastPlayIndex.count() != 3)
731  {
732  return;
733  }
734 
735  m_playRowIndex = lastPlayIndex[1].toInt();
736  const int index = lastPlayIndex[2].toInt();
737  setCurrentIndex(index);
738  setSongPlayCount(index);
739 
741 }
742 
744 {
745  if(m_playRowIndex < 0 || m_playRowIndex >= m_containerItems.count())
746  {
747  return;
748  }
749 
750  const MusicSong &song = m_containerItems[m_playRowIndex].m_songs[row];
752 
754  if(state)
755  {
756  item->m_songs << song;
757  widget->updateSongsList(item->m_songs);
758  setItemTitle(item);
759  }
760  else
761  {
762  if(item->m_songs.removeOne(song))
763  {
764  widget->removeItems();
765  widget->updateSongsList(item->m_songs);
766  setItemTitle(item);
768  }
769  }
770 }
771 
773 {
774  if(m_currentIndex < 0 || m_currentIndex >= m_containerItems.count() || hasSearchResult())
775  {
776  return;
777  }
778 
779  const MusicSong &song = m_containerItems[m_currentIndex].m_songs[row];
781 
783  if(MusicSong(MusicApplication::instance()->currentFilePath()) == song)
784  {
786  return;
787  }
788 
790  if(state)
791  {
792  item->m_songs << song;
793  widget->updateSongsList(item->m_songs);
794  setItemTitle(item);
795  }
796  else
797  {
798  if(item->m_songs.removeOne(song))
799  {
800  widget->removeItems();
801  widget->updateSongsList(item->m_songs);
802  setItemTitle(item);
804  }
805  }
806 }
807 
809 {
811  const QByteArray &md5 = TTK::Algorithm::md5(item.m_id.toUtf8());
812  MusicSong song(item.m_nickName + "#" + md5 + "." + item.m_description, item.m_time, item.m_name);
813  song.setFormat(item.m_description);
814  song.setSizeStr(item.m_count);
815 
816  int index = songItem->m_songs.indexOf(song);
817  if(index == -1)
818  {
819  songItem->m_songs << song;
820  songItem->m_itemWidget->updateSongsList(songItem->m_songs);
821  setItemTitle(songItem);
822  index = songItem->m_songs.count() - 1;
823  }
824 
825  if(item.m_title == MUSIC_PLAY_NOW)
826  {
830  }
831 }
832 
833 void MusicSongsContainerWidget::addSongToPlaylist(const QStringList &items)
834 {
835  if(items.isEmpty())
836  {
837  MusicToastLabel::popup(tr("Import music songs is empty"));
838  return;
839  }
840 
841  QStringList files(items);
842  const int row = makeValidIndex();
843  importSongsByPath(files, row);
844 
845  const MusicSongItem *item = &m_containerItems[row];
846  const MusicSongList *musicSongs = &item->m_songs;
847  const MusicSong &song = MusicSong(items.back());
848 
849  int index = musicSongs->count() - 1;
850  if(musicSongs->contains(song))
851  {
852  index = musicSongs->indexOf(song);
853  }
854 
856  setCurrentIndex(row);
858 }
859 
860 void MusicSongsContainerWidget::removeItemAt(const TTKIntList &index, bool fileRemove)
861 {
862  if(index.isEmpty() || hasSearchResult())
863  {
864  return;
865  }
866 
869  QStringList deleteFiles;
870  for(int i = index.count() - 1; i >= 0; --i)
871  {
872  const MusicSong &song = item->m_songs.takeAt(index[i]);
873  deleteFiles << song.path();
874  if(currentIndex != m_playRowIndex && currentIndex == MUSIC_LOVEST_LIST)
875  {
876  const int playIndex = m_containerItems[m_playRowIndex].m_itemWidget->playRowIndex();
877  const MusicSongList &songs = m_containerItems[m_playRowIndex].m_songs;
878  if(playIndex > -1 && playIndex < songs.count())
879  {
880  if(songs[playIndex] == song)
881  {
883  }
884  }
885  }
886 
887  if(fileRemove)
888  {
889  QFile::remove(currentIndex == MUSIC_NETWORK_LIST ? TTK::generateNetworkSongPath(song.path()) : song.path());
890  }
891  }
892 
893  MusicApplication::instance()->removeItemAt(deleteFiles, fileRemove, currentIndex == m_playRowIndex, currentIndex);
894 
895  setItemTitle(item);
896  //create upload file widget if current items is all been deleted
897  TTKObjectCast(MusicSongsListPlayTableWidget*, item->m_itemWidget)->createUploadFileModule();
898 }
899 
900 void MusicSongsContainerWidget::itemIndexSwaped(int start, int end, int play, MusicSongList &songs)
901 {
902  MusicSongList *names = &m_containerItems[m_currentIndex].m_songs;
903  if(start > end)
904  {
905  for(int i = start; i > end; --i)
906  {
907  QtContainerSwap(names, i, i - 1);
908  }
909  }
910  else
911  {
912  for(int i = start; i < end; ++i)
913  {
914  QtContainerSwap(names, i, i + 1);
915  }
916  }
917 
918  songs = *names;
919 
921  {
923  }
924 }
925 
927 {
929  state = (currentIndex == m_playRowIndex);
930 }
931 
933 {
934  empty = !hasSearchResult();
935 }
936 
938 {
939  if(index < 0 || m_playRowIndex < 0)
940  {
941  return;
942  }
943 
944  MusicSongList &songs = m_containerItems[m_playRowIndex].m_songs;
945  if(!songs.isEmpty() && index < songs.count())
946  {
947  MusicSong &song = songs[index];
948  song.setPlayCount(song.playCount() + 1);
949  }
950 }
951 
953 {
955  {
956  return;
957  }
958 
959  MusicSongList *songs = &m_containerItems[m_playRowIndex].m_songs;
960  if(songs->isEmpty() || index >= songs->count())
961  {
962  return;
963  }
964 
966  MusicSong recentSong(songs->at(index));
967  MusicSongList *recentSongs = &item->m_songs;
969  if(!recentSongs->contains(recentSong))
970  {
971  if(recentSongs->count() >= RECENT_ITEM_MAX_COUNT)
972  {
973  recentSongs->takeFirst();
974  widget->removeItems();
975  }
976 
977  recentSong.setPlayCount(recentSong.playCount() + 1);
978  recentSongs->append(recentSong);
979  widget->updateSongsList(*recentSongs);
980 
981  const QString title(QString("%1[%2]").arg(item->m_itemName).arg(recentSongs->count()));
982  setTitle(widget, title);
983  }
984  else
985  {
986  for(MusicSong &song : *recentSongs)
987  {
988  if(recentSong == song)
989  {
990  song.setPlayCount(song.playCount() + 1);
991  break;
992  }
993  }
994  }
995 }
996 
997 void MusicSongsContainerWidget::querySongItemList(MusicSongItemList &songs)
998 {
999  songs = m_containerItems;
1000 }
1001 
1003 {
1004  if(m_playRowIndex < 0)
1005  {
1006  return;
1007  }
1008 
1009  TTKObjectCast(MusicSongsListPlayTableWidget*, m_containerItems[m_playRowIndex].m_itemWidget)->updateCurrentArtist();
1010 }
1011 
1013 {
1014  if(m_listFunctionWidget == nullptr)
1015  {
1017  connect(m_listFunctionWidget, SIGNAL(deleteObject()), SLOT(deleteFloatWidget()));
1018  resizeWindow();
1019  m_listFunctionWidget->show();
1020  }
1021  else
1022  {
1023  resizeWindow();
1025  }
1026 }
1027 
1029 {
1030  const int id = foundMappedIndex(index);
1031  if(id == -1)
1032  {
1033  return;
1034  }
1035 
1037 
1040  index = m_containerItems[id].m_sort.m_type;
1041  if(index != -1)
1042  {
1043  sort = TTKStaticCast(MusicSong::Sort, index);
1044  }
1045 
1046  MusicSongList *songs = &m_containerItems[id].m_songs;
1047  const MusicSong song(MusicApplication::instance()->currentFilePath());
1048 
1049  for(int i = 0; i < songs->count(); ++i)
1050  {
1051  (*songs)[i].setSort(sort);
1052  }
1053 
1054  if(m_containerItems[id].m_sort.m_order == Qt::DescendingOrder)
1055  {
1056  std::sort(songs->begin(), songs->end());
1057  }
1058  else
1059  {
1060  std::sort(songs->begin(), songs->end(), std::greater<MusicSong>());
1061  }
1062 
1063  widget->removeItems();
1064  widget->setSongsList(songs);
1065 
1066  index = songs->indexOf(song);
1068  {
1070  }
1071 }
1072 
1074 {
1075  if(m_songSearchWidget == nullptr)
1076  {
1078  resizeWindow();
1079  }
1080 
1082 }
1083 
1085 {
1086  if(value >= 40 * (m_currentIndex + 1) && m_currentIndex > -1 && m_currentIndex < m_containerItems.count())
1087  {
1091  m_listMaskWidget->setTitle(QString("%1[%2]").arg(item->m_itemName).arg(item->m_songs.count()));
1092  m_listMaskWidget->setExpand(true);
1093  m_listMaskWidget->raise();
1094  m_listMaskWidget->show();
1095  }
1096  else
1097  {
1098  m_listMaskWidget->hide();
1099  }
1100 }
1101 
1103 {
1104  delete m_listFunctionWidget;
1105  m_listFunctionWidget = nullptr;
1106 }
1107 
1109 {
1110  MusicSongsToolBoxWidget::resizeEvent(event);
1111  resizeWindow();
1112 }
1113 
1114 void MusicSongsContainerWidget::dragEnterEvent(QDragEnterEvent *event)
1115 {
1116  MusicSongsToolBoxWidget::dragEnterEvent(event);
1117  event->setDropAction(Qt::IgnoreAction);
1118  event->accept();
1119 }
1120 
1121 void MusicSongsContainerWidget::dragMoveEvent(QDragMoveEvent *event)
1122 {
1123  MusicSongsToolBoxWidget::dragMoveEvent(event);
1124 
1125  bool contains = false;
1126  for(const MusicToolBoxWidgetItem &item : qAsConst(m_itemList))
1127  {
1128  if(!TTK::playlistRowValid(item.m_itemIndex))
1129  {
1130  continue;
1131  }
1132 
1133  QWidget *container = item.m_widgetItem->item();
1134  if(item.m_widgetItem->isActive() || (container && container->isVisible()))
1135  {
1136  contains = true;
1137  }
1138  }
1139 
1140  event->setDropAction(contains ? Qt::CopyAction : Qt::IgnoreAction);
1141  event->accept();
1142 }
1143 
1145 {
1146  MusicSongsToolBoxWidget::dropEvent(event);
1147 
1148  QStringList dirs, files;
1149  const QMimeData *data = event->mimeData();
1150 
1151  for(const QUrl &url : data->urls())
1152  {
1153  const QString &path = url.toLocalFile();
1154  if(QFileInfo(path).isDir())
1155  {
1156  dirs << path;
1157  }
1158  else
1159  {
1160  files << path;
1161  }
1162  }
1163 
1164  for(const MusicToolBoxWidgetItem &item : qAsConst(m_itemList))
1165  {
1166  if(!TTK::playlistRowValid(item.m_itemIndex))
1167  {
1168  continue;
1169  }
1170 
1171  QWidget *container = item.m_widgetItem->item();
1172  if(item.m_widgetItem->isActive() || (container && container->isVisible()))
1173  {
1174  importSongsByPath(files, foundMappedIndex(item.m_itemIndex));
1175  break;
1176  }
1177  }
1178 
1179  for(const QString &dir : qAsConst(dirs))
1180  {
1181  MusicSongItem item;
1182  item.m_itemName = QFileInfo(dir).baseName();
1184 
1186  for(const QString &path : qAsConst(files))
1187  {
1188  item.m_songs << TTK::generateSongList(path);
1189  }
1190 
1191  m_containerItems << item;
1193  }
1194 }
1195 
1196 void MusicSongsContainerWidget::contextMenuEvent(QContextMenuEvent *event)
1197 {
1198  MusicSongsToolBoxWidget::contextMenuEvent(event);
1199 
1200  QMenu menu(this);
1201  menu.setStyleSheet(TTK::UI::MenuStyle02);
1202  menu.addAction(tr("Create Item"), this, SLOT(addNewRowItem()));
1203  menu.addAction(tr("Import Item"), MusicApplication::instance(), SLOT(importSongsItemList()));
1204  menu.addAction(tr("Export Items"), MusicApplication::instance(), SLOT(exportSongsItemList()));
1205  menu.addAction(tr("Delete All"), this, SLOT(deleteRowItems()))->setEnabled(m_containerItems.count() > ITEM_MIN_COUNT);
1206  menu.addAction(tr("Music Test Tools"), this, SLOT(showSongCheckToolsWidget()));
1207  menu.addAction(tr("Lrc Batch Download"), this, SLOT(showLrcDownloadBatchWidget()));
1208 
1210  menu.exec(QCursor::pos());
1211 }
1212 
1214 {
1215  if(m_songSearchWidget)
1216  {
1218  }
1219 }
1220 
1222 {
1223  if(hasSearchResult())
1224  {
1226  }
1227 }
1228 
1230 {
1231  QString check = name;
1232  for(int i = 1; i <= ITEM_MAX_COUNT; ++i)
1233  {
1234  bool found = false;
1235  for(const MusicSongItem &songItem : qAsConst(m_containerItems))
1236  {
1237  if(check == songItem.m_itemName)
1238  {
1239  found = true;
1240  check = name + QString::number(i);
1241  break;
1242  }
1243  }
1244 
1245  if(!found)
1246  {
1247  name = check;
1248  break;
1249  }
1250  }
1251 }
1252 
1254 {
1256  widget->setMovedScrollBar(m_scrollArea->verticalScrollBar());
1257  widget->setSongSort(&item->m_sort);
1258 
1259  item->m_itemWidget = widget;
1260  item->m_itemIndex = m_itemIndexRaise;
1261 
1262  addCellItem(widget, item->m_itemName);
1263  setSongSort(widget, &item->m_sort);
1265 
1266  connect(widget, SIGNAL(isCurrentPlaylistRow(bool&)), SLOT(isCurrentPlaylistRow(bool&)));
1267  connect(widget, SIGNAL(isSearchedResultEmpty(bool&)), SLOT(isSearchedResultEmpty(bool&)));
1268  connect(widget, SIGNAL(deleteItemAt(TTKIntList,bool)), SLOT(removeItemAt(TTKIntList,bool)));
1269  connect(widget, SIGNAL(itemIndexSwaped(int,int,int,MusicSongList&)), SLOT(itemIndexSwaped(int,int,int,MusicSongList&)));
1270  connect(widget, SIGNAL(addSongToLovestList(bool,int)), SLOT(addSongToLovestList(bool,int)));
1271  connect(widget, SIGNAL(showFloatWidget()), SLOT(showFloatWidget()));
1272  connect(widget, SIGNAL(songListSortBy(int)), SLOT(songListSortBy(int)));
1273 
1275  setInputModule(m_itemList.back().m_widgetItem);
1276 
1277  widget->setSongsList(&item->m_songs);
1278  setTitle(widget, QString("%1[%2]").arg(item->m_itemName).arg(item->m_songs.count()));
1279 }
1280 
1282 {
1283  const QString title(QString("%1[%2]").arg(item->m_itemName).arg(item->m_songs.count()));
1284  setTitle(item->m_itemWidget, title);
1285 
1286  if(m_listMaskWidget->isVisible() && m_listMaskWidget->index() == item->m_itemIndex)
1287  {
1288  m_listMaskWidget->setTitle(title);
1289  }
1290 }
1291 
1293 {
1294  connect(object, SIGNAL(addNewRowItem()), SLOT(addNewRowItem()));
1295  connect(object, SIGNAL(deleteRowItem(int)), SLOT(deleteRowItem(int)));
1296  connect(object, SIGNAL(deleteAllItems(int)), SLOT(deleteAllItems(int)));
1297  connect(object, SIGNAL(changRowItemName(int,QString)), SLOT(changRowItemName(int,QString)));
1298  connect(object, SIGNAL(addNewFiles(int)), SLOT(importSongsByFiles(int)));
1299  connect(object, SIGNAL(addNewDir(int)), SLOT(importSongsByDir(int)));
1300  connect(object, SIGNAL(songListSortBy(int)), SLOT(songListSortBy(int)));
1301  connect(object, SIGNAL(swapDragItemIndex(int,int)), SLOT(swapDragItemIndex(int,int)));
1302  connect(object, SIGNAL(addToPlayLater(int)), SLOT(addToPlayLater(int)));
1303  connect(object, SIGNAL(addToPlayedList(int)), SLOT(addToPlayedList(int)));
1304 }
1305 
1307 {
1309  {
1310  m_listFunctionWidget->move(width() - m_listFunctionWidget->width() - 15, height() - 40 - m_listFunctionWidget->height());
1311  }
1312 
1313  if(m_songSearchWidget)
1314  {
1315  m_songSearchWidget->move(0, height() - m_songSearchWidget->height());
1316  }
1317 }
1318 
1320 {
1321  for(const MusicSongItem &item : qAsConst(m_containerItems))
1322  {
1323  const int index = foundMappedIndex(item.m_itemIndex);
1324  item.m_itemWidget->setPlaylistRow(index);
1325  }
1326 
1327  TTK::IndexPropertyList items;
1328  if(end == -1)
1329  {
1330  for(int i = begin + 1; i < m_containerItems.count(); ++i)
1331  {
1332  items << TTK::IndexProperty(i + 1, i);
1333  }
1334  }
1335  else
1336  {
1337  items << TTK::IndexProperty(begin, end);
1338 
1339  if(begin > end)
1340  {
1341  for(int i = begin; i < end; ++i)
1342  {
1343  items << TTK::IndexProperty(i + 1, i);
1344  }
1345  }
1346  else
1347  {
1348  for(int i = end; i > begin; --i)
1349  {
1350  items << TTK::IndexProperty(i, i - 1);
1351  }
1352  }
1353  }
1354 
1356 }
1357 
const MusicSongItemList & items() const
void setTitle(QWidget *item, const QString &text)
#define TTKStaticCast(x, y)
Definition: ttkglobal.h:159
void importSongsByDir(int index=TTK_LOW_LEVEL)
The class of the songs container widget.
TTK_MODULE_EXPORT QByteArray md5(const QByteArray &data)
The class of the search result data item.
void updateDurationLabel(const QString &current, const QString &total) const
static MusicApplication * instance()
virtual void setVisible(bool visible) overridefinal
virtual void dragEnterEvent(QDragEnterEvent *event) overridefinal
void setText(const QString &text) const
TTK_MODULE_EXPORT bool playlistRowValid(int index)
Definition: musicsong.cpp:95
virtual void contextMenuEvent(QContextMenuEvent *event) overridefinal
#define TTK_DEFAULT_STR
Definition: ttkglobal.h:203
#define QtContainerSwap(p, i, j)
Container swap.
Definition: ttkqtcompat.h:52
#define TTK_LOW_LEVEL
Definition: ttkglobal.h:258
The class of the show progress widget.
void addSongToLovestList(bool state=true)
QString path() const noexcept
Definition: musicsong.h:90
void songToLovestListAt(bool state, int row)
static QStringList supportMusicInputFilterFormats()
void importSongsByFiles(int index=TTK_LOW_LEVEL)
#define MUSIC_NONE_LIST
QStringList songsFilePath(int index) const
void updatePlayedList(const TTK::IndexPropertyList &indexs)
void playIndexBy(int row)
void playSortBy(int row)
QStringList songsFileName(int index) const
bool addSongItemList(const MusicSongItemList &items)
static constexpr int RECENT_ITEM_MAX_COUNT
The class of the messagebox widget.
#define MUSIC_RECENT_LIST
void updatePlayedList(int start, int end)
The class of the lrc batch download widget.
MusicSongSearchDialog * m_songSearchWidget
#define TTKGenerateSingleWidget(...)
static MusicPlayedListPopWidget * instance()
#define G_CONNECTION_PTR
void removeItemAt(const QStringList &path, bool remove, bool current, int playlistRow)
void setSongSort(QWidget *item, MusicSongSort *sort)
void importSongsByDir(int index=TTK_LOW_LEVEL)
The class of the index property.
Definition: musicobject.h:206
void updateSongItem(const MusicSongItem &item)
void setMovedScrollBar(QScrollBar *bar=nullptr)
int mapSongIndexByFilePath(int playlistRow, const QString &path) const
void swapDragItemIndex(int start, int end)
void setTitle(const QString &name)
The class of the tool box mask widget.
static void popup(const QString &text)
The class of the song check tools widget.
The class of the tool box widget item.
void addSongToPlaylist(const QStringList &items)
TTK_MODULE_EXPORT QString pefix(const QString &name)
TTK_MODULE_EXPORT QString generateNetworkSongPath(const QString &path)
Definition: musicsong.cpp:175
virtual void updateSongsList(const MusicSongList &songs) overridefinal
#define MUSIC_PLAY_NOW
static constexpr int ITEM_MAX_COUNT
The class of the songs list function widget.
QList< int > TTKIntList
Definition: ttkqtglobal.h:204
#define qAsConst
Definition: ttkqtglobal.h:51
const char * name
Definition: http_parser.c:458
void setInputModule(QObject *object) const
void removeItemAt(const TTKIntList &del, bool fileRemove)
virtual void setSongsList(MusicSongList *songs)
void importSongsByFiles(int index=TTK_LOW_LEVEL)
MusicSongsToolBoxMaskWidget * m_listMaskWidget
MusicAbstractSongsListTableWidget * m_itemWidget
Definition: musicsong.h:168
void addSongToLovestList(bool state, int row)
void addCellItem(QWidget *item, const QString &text)
#define TTK_NORMAL_LEVEL
Definition: ttkglobal.h:259
void importSongsByPath(const QStringList &files, int playlistRow)
static QStringList supportMusicFormats()
#define TTK_SEPARATOR
Definition: ttkglobal.h:196
void changRowItemName(int index, const QString &name)
QSet< int > TTKIntSet
Definition: ttkqtglobal.h:203
void playIndexClicked(int row, int column)
static MusicSongsContainerWidget * instance()
MusicSongsContainerWidget(QWidget *parent=nullptr)
TTK_MODULE_EXPORT QFileInfoList fileInfoListByPath(const QString &dpath, const QStringList &filter={}, bool recursively=true)
virtual void updateSongsList(const MusicSongList &songs)
MusicToolBoxWidgetItemList m_itemList
void importSongsByUrl(const QString &path, int playlistRow)
void addSongBufferToPlaylist(const MusicResultDataItem &item)
void setItemTitle(MusicSongItem *item)
void querySongItemList(MusicSongItemList &songs)
TTK_MODULE_EXPORT QString splitToken(const QString &name)
virtual void dropEvent(QDropEvent *event) overridefinal
static const QString MenuStyle02
void append(const MusicSongList &songs)
virtual void resizeEvent(QResizeEvent *event) overridefinal
The class of the tool box widget.
The class of the music song item.
Definition: musicsong.h:161
void itemIndexSwaped(int start, int end, int play, MusicSongList &songs)
MusicSongList m_songs
Definition: musicsong.h:167
#define MUSIC_NETWORK_LIST
#define MUSIC_LOVEST_LIST
void setSongSort(MusicSongSort *sort)
void setPlayCount(const int c) noexcept
Definition: musicsong.h:114
#define MIN_ITEM_COUNT
void insert(int playlistRow, const MusicSong &song)
QString m_itemName
Definition: musicsong.h:165
MusicSongsListFunctionWidget * m_listFunctionWidget
TTK_MODULE_EXPORT QStringList fileListByPath(const QString &dpath, const QStringList &filter={}, bool recursively=true)
#define TTK_FILE_SUFFIX(fin)
Definition: ttkqtglobal.h:189
The class of the music song info.
Definition: musicsong.h:28
The class of the song search widget.
static MusicSongsContainerWidget * m_instance
void removeLoveItemAt(const QString &path, bool current)
void appendSongItemList(const MusicSongItemList &items)
MusicSongSort m_sort
Definition: musicsong.h:166
#define MUSIC_NORMAL_LIST
int playCount() const noexcept
Definition: musicsong.h:118
TTK_MODULE_EXPORT void adjustMenuPosition(QMenu *menu)
virtual void dragMoveEvent(QDragMoveEvent *event) overridefinal
QString mapFilePathBySongIndex(int playlistRow, int index) const
void searchResultChanged(int row, int column)
static constexpr int ITEM_MIN_COUNT
void createWidgetItem(MusicSongItem *item)
state
Definition: http_parser.c:279
The class of the songs list play table widget.
TTK_MODULE_EXPORT bool isNetworkUrl(const QString &path)
#define G_SETTING_PTR
TTK_MODULE_EXPORT MusicSongList generateSongList(const QString &path)
Definition: musicsong.cpp:132
#define TTKObjectCast(x, y)
Definition: ttkqtglobal.h:76