TTKMusicPlayer  4.2.0.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_functionWidget(nullptr),
31  m_songSearchWidget(nullptr)
32 {
33  m_instance = this;
34 
35  setAcceptDrops(true);
36 
39 
40  connect(m_topMaskWidget, 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_topMaskWidget;
51  delete m_functionWidget;
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 *it = &m_containerItems[index];
84  it->m_sort = item.m_sort;
85  it->m_songs = item.m_songs;
86  it->m_itemName = item.m_itemName;
89  setItemTitle(it);
90 
92  {
95  }
96  }
97 }
98 
99 bool MusicSongsContainerWidget::addSongItemList(const MusicSongItemList &items)
100 {
101  TTKIntSet inNeed;
103  for(const MusicSongItem &item : qAsConst(items))
104  {
105  inNeed.remove(item.m_itemIndex);
106  }
107  //
108  if(!inNeed.isEmpty())
109  {
110  //if less than four count(0, 1, 2, 3), find and add default items
112  //
113  for(const int item : qAsConst(inNeed))
114  {
115  MusicSongItem it;
116  switch(item)
117  {
118  case MUSIC_NORMAL_LIST:
119  {
120  it.m_itemIndex = item;
121  it.m_itemName = tr("Default Item");
122  break;
123  }
124  case MUSIC_LOVEST_LIST:
125  {
126  it.m_itemIndex = item;
127  it.m_itemName = tr("Lovest Item");
128  break;
129  }
130  case MUSIC_NETWORK_LIST:
131  {
132  it.m_itemIndex = item;
133  it.m_itemName = tr("Net Item");
134  break;
135  }
136  case MUSIC_RECENT_LIST:
137  {
138  it.m_itemIndex = item;
139  it.m_itemName = tr("Recent Item");
140  break;
141  }
142  default: break;
143  }
144  m_containerItems << it;
145  }
146  std::sort(m_containerItems.begin(), m_containerItems.end());
147  }
148  else
149  {
151  }
152 
153  for(int i = 0; i < m_containerItems.count(); ++i)
154  {
156  }
157 
158  return inNeed.isEmpty();
159 }
160 
161 void MusicSongsContainerWidget::appendSongItemList(const MusicSongItemList &items)
162 {
163  for(int i = 0; i < items.count(); ++i)
164  {
165  MusicSongItem item = items[i];
167  createContainerItem(item);
168  }
169 }
170 
171 void MusicSongsContainerWidget::importSongsByUrl(const QString &path, int playlistRow)
172 {
173  if(path.isEmpty())
174  {
175  return;
176  }
177 
178  if(playlistRow < 0)
179  {
180  playlistRow = makeValidIndex();
181  }
182 
183  const QFileInfo fin(path);
184  if(fin.isDir())
185  {
186  QStringList files;
187  for(const QFileInfo &fin : TTK::File::fileInfoListByPath(path))
188  {
190  {
191  files << fin.absoluteFilePath();
192  }
193  }
194 
195  importSongsByPath(files, playlistRow);
196  }
197  else if(TTK::String::isNetworkUrl(path))
198  {
200 
202  const QString &prefix = TTK::String::splitToken(path, TTK_SEPARATOR, "?");
203  const QByteArray &md5 = TTK::Algorithm::md5(path.toUtf8());
204  const MusicSong song(path + "#" + md5 + "." + TTK::String::splitToken(path), TTK_DEFAULT_STR, TTK::String::pefix(prefix));
205 
206  if(item->m_songs.contains(song))
207  {
208  return;
209  }
210 
211  item->m_songs << song;
212  item->m_itemWidget->updateSongsList(item->m_songs);
213  setItemTitle(item);
214  }
215  else
216  {
217  QStringList files;
219  {
220  files << fin.absoluteFilePath();
221  }
222 
223  importSongsByPath(files, playlistRow);
224  }
225 }
226 
227 void MusicSongsContainerWidget::importSongsByPath(const QStringList &files, int playlistRow)
228 {
229  if(files.isEmpty())
230  {
231  return;
232  }
233 
234  if(playlistRow < 0)
235  {
236  playlistRow = makeValidIndex();
237  }
238 
240 
241  MusicProgressWidget progress;
242  progress.setTitle(tr("Import file mode"));
243  progress.setRange(0, files.count());
244  progress.show();
245 
246  MusicSongItem *item = &m_containerItems[playlistRow];
247 
248  int i = 0;
249  for(const QString &path : qAsConst(files))
250  {
251  if(item->m_songs.contains(MusicSong(path)))
252  {
253  continue;
254  }
255 
256  progress.setValue(++i);
257  item->m_songs << TTK::generateSongList(path);
258  }
259 
260  if(i != 0)
261  {
262  item->m_itemWidget->updateSongsList(item->m_songs);
263  setItemTitle(item);
264  setCurrentIndex(playlistRow);
265  }
266 
267  MusicToastLabel::popup(tr("Import music songs done"));
268 }
269 
270 QStringList MusicSongsContainerWidget::songsFileName(int index) const
271 {
272  QStringList list;
273 
274  if(index < 0 || index >= m_containerItems.count())
275  {
276  return list;
277  }
278 
279  for(const MusicSong &song : qAsConst(m_containerItems[index].m_songs))
280  {
281  list << song.name();
282  }
283  return list;
284 }
285 
286 QStringList MusicSongsContainerWidget::songsFilePath(int index) const
287 {
288  QStringList list;
289  if(index < 0 || index >= m_containerItems.count())
290  {
291  return list;
292  }
293 
294  for(const MusicSong &song : qAsConst(m_containerItems[index].m_songs))
295  {
296  list << song.path();
297  }
298  return list;
299 }
300 
301 int MusicSongsContainerWidget::mapSongIndexByFilePath(int playlistRow, const QString &path) const
302 {
303  if(playlistRow < 0 || playlistRow >= m_containerItems.count() || path.isEmpty())
304  {
305  return -1;
306  }
307 
308  const MusicSongList *songs = &m_containerItems[playlistRow].m_songs;
309  for(int i = 0; i < songs->count(); ++i)
310  {
311  if(MusicSong(path) == songs->at(i))
312  {
313  return i;
314  }
315  }
316  return -1;
317 }
318 
319 QString MusicSongsContainerWidget::mapFilePathBySongIndex(int playlistRow, int index) const
320 {
321  if(playlistRow < 0 || playlistRow >= m_containerItems.count())
322  {
323  return {};
324  }
325 
326  const MusicSongList *songs = &m_containerItems[playlistRow].m_songs;
327  if(index < 0 || index >= songs->count())
328  {
329  return {};
330  }
331 
332  return songs->at(index).path();
333 }
334 
336 {
338  {
339  return;
340  }
341 
342  const TTKIntList &result = m_searchResultItems.value(m_searchResultLevel);
343  if(row >= result.count() || row < 0)
344  {
345  row = -1;
346  return;
347  }
348 
349  row = result[row];
350 
353 }
354 
356 {
357  const int before = m_playRowIndex;
358  m_playRowIndex = index;
359 
360  if(before >= 0)
361  {
363  if(widget && !m_containerItems[before].m_songs.isEmpty())
364  {
365  widget->adjustPlayWidgetRow();
366  }
367  }
368 }
369 
371 {
372  if(!hasSearchResult())
373  {
374  selectRow(index);
375  resizeScrollIndex(index * 30);
376  }
377 }
378 
380 {
382  if(m_playRowIndex < 0)
383  {
384  return;
385  }
386 
388  m_containerItems[m_playRowIndex].m_itemWidget->selectRow(index);
389 }
390 
391 void MusicSongsContainerWidget::updateDurationLabel(const QString &current, const QString &total) const
392 {
393  if(m_playRowIndex < 0)
394  {
395  return;
396  }
397  TTKObjectCast(MusicSongsListPlayTableWidget*, m_containerItems[m_playRowIndex].m_itemWidget)->updateDurationLabel(current, total);
398 }
399 
401 {
402  if(m_containerItems.count() <= ITEM_MAX_COUNT)
403  {
404  int id = 0;
405  for(const MusicSongItem &item : qAsConst(m_containerItems))
406  {
407  if(id < item.m_id)
408  {
409  id = item.m_id;
410  }
411  }
412 
413  MusicSongItem item;
414  item.m_id = id + 1;
415  item.m_itemName = tr("Default Item");
416 
418  createContainerItem(item);
419  }
420  else
421  {
422  MusicToastLabel::popup(tr("Exceeded the maximum number limit"));
423  }
424 }
425 
427 {
428  const int id = foundMappedIndex(index);
429  if(id == -1)
430  {
431  return;
432  }
433 
434  MusicMessageBox message;
435  message.setText(tr("Are you sure to delete?"));
436  if(!message.exec())
437  {
438  return;
439  }
440 
441  const MusicSongItem *item = &m_containerItems[id];
443 
444  if(m_playRowIndex == id)
445  {
447  m_items.front().m_itemWidget->setExpand(false);
449  }
450  else if(m_playRowIndex > id)
451  {
453  }
454 
455  m_containerItems.takeAt(id);
456  removeItem(item->m_itemWidget);
457  delete item->m_itemWidget;
458 
459  updatePlayedList(id, -1);
460 }
461 
463 {
464  MusicMessageBox message;
465  message.setText(tr("Are you sure to delete?"));
466  if(!message.exec())
467  {
468  return;
469  }
470 
472  {
474  m_items.front().m_itemWidget->setExpand(false);
476  }
477 
478  for(int i = m_containerItems.count() - 1; i > 3; --i)
479  {
480  MusicSongItem item = m_containerItems.takeLast();
481  removeItem(item.m_itemWidget);
482  delete item.m_itemWidget;
483  }
484 }
485 
487 {
488  const int id = foundMappedIndex(index);
489  if(id == -1)
490  {
491  return;
492  }
493 
495 
496  m_selectDeleteIndex = id;
497  //
499  if(widget->rowCount() > 0)
500  {
501  widget->setCurrentCell(0, 1);
502  widget->clearItems();
503  }
504  //
506 
507  if(m_containerItems[id].m_songs.isEmpty() && m_playRowIndex == id)
508  {
510  }
511 }
512 
513 void MusicSongsContainerWidget::changRowItemName(int index, const QString &name)
514 {
515  const int id = foundMappedIndex(index);
516  if(id == -1)
517  {
518  return;
519  }
520 
521  bool found = false;
522  for(int i = 0; i < m_containerItems.count(); ++i)
523  {
524  if(i == id)
525  {
526  continue;
527  }
528 
529  if(m_containerItems[i].m_itemName == name)
530  {
531  found = true;
532  }
533  }
534 
535  MusicSongItem *item = &m_containerItems[id];
536  if(found)
537  {
538  MusicToastLabel::popup(tr("Item name is already exists"));
539  setItemTitle(item);
540  return;
541  }
542 
543  item->m_itemName = name;
544  setItemTitle(item);
545 }
546 
548 {
549  start = foundMappedIndex(start);
550  end = foundMappedIndex(end);
551  if(start == end)
552  {
553  return;
554  }
555 
556  //adjust the m_playRowIndex while the item has dragged and dropped
557  if(start < end)
558  {
559  if((start < m_playRowIndex && m_playRowIndex < end) || m_playRowIndex == end)
560  {
562  }
563  else if(m_playRowIndex == start)
564  {
566  }
567  }
568  else
569  {
570  if((end < m_playRowIndex && m_playRowIndex < start) || m_playRowIndex == end)
571  {
573  }
574  else if(m_playRowIndex == start)
575  {
577  }
578  }
579 
580  swapItem(start, end);
581  const MusicSongItem &item = m_containerItems.takeAt(start);
582  m_containerItems.insert(end, item);
583 
584  updatePlayedList(start, end);
585 }
586 
588 {
589  const int id = foundMappedIndex(index);
590  if(id == -1)
591  {
592  return;
593  }
594 
595  const MusicSongItem *item = &m_containerItems[id];
597 }
598 
600 {
601  const int id = foundMappedIndex(index);
602  if(id == -1)
603  {
604  return;
605  }
606 
607  const MusicSongItem *item = &m_containerItems[id];
609 }
610 
612 {
613  if(index == TTK_LOW_LEVEL)
614  {
615  index = m_currentIndex;
616  }
617  else
618  {
619  const int id = foundMappedIndex(index);
620  if(id == -1)
621  {
622  return;
623  }
624 
625  index = id;
626  }
627 
629 }
630 
632 {
633  if(index == TTK_LOW_LEVEL)
634  {
635  index = m_currentIndex;
636  }
637  else
638  {
639  const int id = foundMappedIndex(index);
640  if(id == -1)
641  {
642  return;
643  }
644 
645  index = id;
646  }
647 
649 }
650 
652 {
654 }
655 
657 {
659 }
660 
662 {
663  if(m_currentIndex == -1)
664  {
665  return;
666  }
667 
668  if(!isSearchedPlayIndex())
669  {
670  const QStringList searchedSongs(songsFileName(m_lastSearchIndex));
671  TTKIntList result;
672  for(int i = 0; i < searchedSongs.count(); ++i)
673  {
674  result << i;
675  }
676 
678  TTKObjectCast(MusicSongsListPlayTableWidget*, item->m_itemWidget)->updateSearchFileName(&item->m_songs, result);
679 
680  if(item->m_songs.isEmpty())
681  {
682  item->m_itemWidget->updateSongsList(item->m_songs);
683  }
684 
687  }
688 
689  const QString &text = m_songSearchWidget->text();
690  const QStringList searchedSongs(songsFileName(m_currentIndex));
691 
692  TTKIntList result;
693  for(int i = 0; i < searchedSongs.count(); ++i)
694  {
695  if(searchedSongs[i].contains(text, Qt::CaseInsensitive))
696  {
697  result << i;
698  }
699  }
700 
701  m_searchResultLevel = column;
702  m_searchResultItems.insert(column, result);
703 
705  TTKObjectCast(MusicSongsListPlayTableWidget*, item->m_itemWidget)->updateSearchFileName(&item->m_songs, result);
706 
707  if(column == 0)
708  {
709  if(item->m_songs.isEmpty())
710  {
711  item->m_itemWidget->updateSongsList(item->m_songs);
712  }
713 
715  }
716 }
717 
719 {
720  const QStringList &lastPlayIndex = G_SETTING_PTR->value(MusicSettingManager::LastPlayIndex).toStringList();
721  if(lastPlayIndex.count() != 3)
722  {
723  return;
724  }
725 
726  m_playRowIndex = lastPlayIndex[1].toInt();
727  const int index = lastPlayIndex[2].toInt();
728  setCurrentIndex(index);
729  setSongPlayCount(index);
730 
732 }
733 
735 {
736  if(m_playRowIndex < 0 || m_playRowIndex >= m_containerItems.count())
737  {
738  return;
739  }
740 
741  const MusicSong &song = m_containerItems[m_playRowIndex].m_songs[row];
743 
745  if(state)
746  {
747  item->m_songs << song;
748  widget->updateSongsList(item->m_songs);
749  setItemTitle(item);
750  }
751  else
752  {
753  if(item->m_songs.removeOne(song))
754  {
755  widget->removeItems();
756  widget->updateSongsList(item->m_songs);
757  setItemTitle(item);
759  }
760  }
761 }
762 
764 {
765  if(m_currentIndex < 0 || m_currentIndex >= m_containerItems.count() || hasSearchResult())
766  {
767  return;
768  }
769 
770  const MusicSong &song = m_containerItems[m_currentIndex].m_songs[row];
772 
774  if(MusicSong(MusicApplication::instance()->currentFilePath()) == song)
775  {
777  return;
778  }
779 
781  if(state)
782  {
783  item->m_songs << song;
784  widget->updateSongsList(item->m_songs);
785  setItemTitle(item);
786  }
787  else
788  {
789  if(item->m_songs.removeOne(song))
790  {
791  widget->removeItems();
792  widget->updateSongsList(item->m_songs);
793  setItemTitle(item);
795  }
796  }
797 }
798 
800 {
802  const QByteArray &md5 = TTK::Algorithm::md5(item.m_id.toUtf8());
803  MusicSong song(item.m_nickName + "#" + md5 + "." + item.m_description, item.m_time, item.m_name);
804  song.setFormat(item.m_description);
805  song.setSizeStr(item.m_count);
806 
807  int index = it->m_songs.indexOf(song);
808  if(index == -1)
809  {
810  it->m_songs << song;
812  setItemTitle(it);
813  index = it->m_songs.count() - 1;
814  }
815 
816  if(item.m_title == MUSIC_PLAY_NOW)
817  {
821  }
822 }
823 
824 void MusicSongsContainerWidget::addSongToPlaylist(const QStringList &items)
825 {
826  if(items.isEmpty())
827  {
828  MusicToastLabel::popup(tr("Import music songs is empty"));
829  return;
830  }
831 
832  QStringList files(items);
833  const int row = makeValidIndex();
834  importSongsByPath(files, row);
835 
836  const MusicSongItem *item = &m_containerItems[row];
837  const MusicSongList *musicSongs = &item->m_songs;
838  const MusicSong &song = MusicSong(items.back());
839 
840  int index = musicSongs->count() - 1;
841  if(musicSongs->contains(song))
842  {
843  index = musicSongs->indexOf(song);
844  }
845 
847  setCurrentIndex(row);
849 }
850 
851 void MusicSongsContainerWidget::removeItemAt(const TTKIntList &index, bool fileRemove)
852 {
853  if(index.isEmpty() || hasSearchResult())
854  {
855  return;
856  }
857 
860  QStringList deleteFiles;
861  for(int i = index.count() - 1; i >= 0; --i)
862  {
863  const MusicSong &song = item->m_songs.takeAt(index[i]);
864  deleteFiles << song.path();
865  if(currentIndex != m_playRowIndex && currentIndex == MUSIC_LOVEST_LIST)
866  {
867  const int playIndex = m_containerItems[m_playRowIndex].m_itemWidget->playRowIndex();
868  const MusicSongList &songs = m_containerItems[m_playRowIndex].m_songs;
869  if(playIndex > -1 && playIndex < songs.count())
870  {
871  if(songs[playIndex] == song)
872  {
874  }
875  }
876  }
877 
878  if(fileRemove)
879  {
880  QFile::remove(currentIndex == MUSIC_NETWORK_LIST ? TTK::generateNetworkSongPath(song.path()) : song.path());
881  }
882  }
883 
884  MusicApplication::instance()->removeItemAt(deleteFiles, fileRemove, currentIndex == m_playRowIndex, currentIndex);
885 
886  setItemTitle(item);
887  //create upload file widget if current items is all been deleted
888  TTKObjectCast(MusicSongsListPlayTableWidget*, item->m_itemWidget)->createUploadFileModule();
889 }
890 
891 void MusicSongsContainerWidget::itemIndexSwaped(int start, int end, int play, MusicSongList &songs)
892 {
893  MusicSongList *names = &m_containerItems[m_currentIndex].m_songs;
894  if(start > end)
895  {
896  for(int i = start; i > end; --i)
897  {
898  QtContainerSwap(names, i, i - 1);
899  }
900  }
901  else
902  {
903  for(int i = start; i < end; ++i)
904  {
905  QtContainerSwap(names, i, i + 1);
906  }
907  }
908 
909  songs = *names;
910 
912  {
914  }
915 }
916 
918 {
920  state = (currentIndex == m_playRowIndex);
921 }
922 
924 {
925  empty = !hasSearchResult();
926 }
927 
929 {
930  if(index < 0 || m_playRowIndex < 0)
931  {
932  return;
933  }
934 
935  MusicSongList &songs = m_containerItems[m_playRowIndex].m_songs;
936  if(!songs.isEmpty() && index < songs.count())
937  {
938  MusicSong &song = songs[index];
939  song.setPlayCount(song.playCount() + 1);
940  }
941 }
942 
944 {
946  {
947  return;
948  }
949 
950  MusicSongList *songs = &m_containerItems[m_playRowIndex].m_songs;
951  if(songs->isEmpty() || index >= songs->count())
952  {
953  return;
954  }
955 
957  MusicSong recentSong(songs->at(index));
958  MusicSongList *recentSongs = &item->m_songs;
960  if(!recentSongs->contains(recentSong))
961  {
962  if(recentSongs->count() >= RECENT_ITEM_MAX_COUNT)
963  {
964  recentSongs->takeFirst();
965  widget->removeItems();
966  }
967 
968  recentSong.setPlayCount(recentSong.playCount() + 1);
969  recentSongs->append(recentSong);
970  widget->updateSongsList(*recentSongs);
971 
972  const QString title(QString("%1[%2]").arg(item->m_itemName).arg(recentSongs->count()));
973  setTitle(widget, title);
974  }
975  else
976  {
977  for(MusicSong &song : *recentSongs)
978  {
979  if(recentSong == song)
980  {
981  song.setPlayCount(song.playCount() + 1);
982  break;
983  }
984  }
985  }
986 }
987 
988 void MusicSongsContainerWidget::querySongItemList(MusicSongItemList &songs)
989 {
990  songs = m_containerItems;
991 }
992 
994 {
995  if(m_playRowIndex < 0)
996  {
997  return;
998  }
999 
1000  TTKObjectCast(MusicSongsListPlayTableWidget*, m_containerItems[m_playRowIndex].m_itemWidget)->updateCurrentArtist();
1001 }
1002 
1004 {
1005  if(m_functionWidget == nullptr)
1006  {
1008  connect(m_functionWidget, SIGNAL(deleteSelfObject()), SLOT(deleteFunctionWidget()));
1009  resizeWindow();
1010  m_functionWidget->show();
1011  }
1012  else
1013  {
1014  resizeWindow();
1016  }
1017 }
1018 
1020 {
1021  const int id = foundMappedIndex(index);
1022  if(id == -1)
1023  {
1024  return;
1025  }
1026 
1028 
1031  index = m_containerItems[id].m_sort.m_type;
1032  if(index != -1)
1033  {
1034  sort = TTKStaticCast(MusicSong::Sort, index);
1035  }
1036 
1037  MusicSongList *songs = &m_containerItems[id].m_songs;
1038  const MusicSong song(MusicApplication::instance()->currentFilePath());
1039 
1040  for(int i = 0; i < songs->count(); ++i)
1041  {
1042  (*songs)[i].setSort(sort);
1043  }
1044 
1045  if(m_containerItems[id].m_sort.m_order == Qt::DescendingOrder)
1046  {
1047  std::sort(songs->begin(), songs->end());
1048  }
1049  else
1050  {
1051  std::sort(songs->begin(), songs->end(), std::greater<MusicSong>());
1052  }
1053 
1054  widget->removeItems();
1055  widget->setSongsList(songs);
1056 
1057  index = songs->indexOf(song);
1059  {
1061  }
1062 }
1063 
1065 {
1066  if(m_songSearchWidget == nullptr)
1067  {
1069  resizeWindow();
1070  }
1071 
1073 }
1074 
1076 {
1077  if(value >= 40 * (m_currentIndex + 1) && m_currentIndex > -1 && m_currentIndex < m_containerItems.count())
1078  {
1082  m_topMaskWidget->setTitle(QString("%1[%2]").arg(item->m_itemName).arg(item->m_songs.count()));
1083  m_topMaskWidget->setExpand(true);
1084  m_topMaskWidget->raise();
1085  m_topMaskWidget->show();
1086  }
1087  else
1088  {
1089  m_topMaskWidget->hide();
1090  }
1091 }
1092 
1094 {
1095  delete m_functionWidget;
1096  m_functionWidget = nullptr;
1097 }
1098 
1100 {
1101  MusicSongsToolBoxWidget::resizeEvent(event);
1102  resizeWindow();
1103 }
1104 
1105 void MusicSongsContainerWidget::dragEnterEvent(QDragEnterEvent *event)
1106 {
1107  MusicSongsToolBoxWidget::dragEnterEvent(event);
1108  event->setDropAction(Qt::IgnoreAction);
1109  event->accept();
1110 }
1111 
1112 void MusicSongsContainerWidget::dragMoveEvent(QDragMoveEvent *event)
1113 {
1114  MusicSongsToolBoxWidget::dragMoveEvent(event);
1115 
1116  for(const MusicToolBoxWidgetItem &item : qAsConst(m_items))
1117  {
1118  if(!TTK::playlistRowValid(item.m_itemIndex))
1119  {
1120  continue;
1121  }
1122 
1123  item.m_itemWidget->isActive();
1124  }
1125 
1126  event->setDropAction(Qt::CopyAction);
1127  event->accept();
1128 }
1129 
1131 {
1132  MusicSongsToolBoxWidget::dropEvent(event);
1133 
1134  QStringList dirs, files;
1135  const QMimeData *data = event->mimeData();
1136 
1137  for(const QUrl &url : data->urls())
1138  {
1139  const QString &path = url.toLocalFile();
1140  if(QFileInfo(path).isDir())
1141  {
1142  dirs << path;
1143  }
1144  else
1145  {
1146  files << path;
1147  }
1148  }
1149 
1150  bool contains = false;
1151  for(const MusicToolBoxWidgetItem &item : qAsConst(m_items))
1152  {
1153  if(!TTK::playlistRowValid(item.m_itemIndex))
1154  {
1155  continue;
1156  }
1157 
1158  if(item.m_itemWidget->isExpand() || item.m_itemWidget->isActive())
1159  {
1160  contains = true;
1161  importSongsByPath(files, foundMappedIndex(item.m_itemIndex));
1162  break;
1163  }
1164  }
1165 
1166  if(!contains)
1167  {
1169  }
1170 
1171  for(const QString &dir : qAsConst(dirs))
1172  {
1173  MusicSongItem item;
1174  item.m_itemName = QFileInfo(dir).baseName();
1175 
1177  item = *createContainerItem(item);
1178 
1181  }
1182 }
1183 
1184 void MusicSongsContainerWidget::contextMenuEvent(QContextMenuEvent *event)
1185 {
1186  MusicSongsToolBoxWidget::contextMenuEvent(event);
1187 
1188  QMenu menu(this);
1189  menu.setStyleSheet(TTK::UI::MenuStyle02);
1190  menu.addAction(tr("Create Item"), this, SLOT(addNewRowItem()));
1191  menu.addAction(tr("Import Item"), MusicApplication::instance(), SLOT(importSongsItemList()));
1192  menu.addAction(tr("Export Items"), MusicApplication::instance(), SLOT(exportSongsItemList()));
1193  menu.addAction(tr("Delete All"), this, SLOT(deleteRowItems()))->setEnabled(m_containerItems.count() > ITEM_MIN_COUNT);
1194  menu.addAction(tr("Music Test Tools"), this, SLOT(showSongCheckToolsWidget()));
1195  menu.addAction(tr("Lrc Batch Download"), this, SLOT(showLrcDownloadBatchWidget()));
1196 
1198  menu.exec(QCursor::pos());
1199 }
1200 
1202 {
1203  if(m_songSearchWidget)
1204  {
1206  }
1207 }
1208 
1210 {
1211  if(hasSearchResult())
1212  {
1214  }
1215 }
1216 
1218 {
1219  QString check = name;
1220  for(int i = 1; i <= ITEM_MAX_COUNT; ++i)
1221  {
1222  bool found = false;
1223  for(const MusicSongItem &item : qAsConst(m_containerItems))
1224  {
1225  if(check == item.m_itemName)
1226  {
1227  found = true;
1228  check = name + QString::number(i);
1229  break;
1230  }
1231  }
1232 
1233  if(!found)
1234  {
1235  name = check;
1236  break;
1237  }
1238  }
1239 }
1240 
1242 {
1244  widget->setMovedScrollBar(m_scrollArea->verticalScrollBar());
1245  widget->setSongSort(&item->m_sort);
1246 
1247  item->m_itemWidget = widget;
1248  item->m_itemIndex = m_itemIndexRaise;
1249 
1250  addCellItem(widget, item->m_itemName);
1251  setSongSort(widget, &item->m_sort);
1253 
1254  connect(widget, SIGNAL(isCurrentPlaylistRow(bool&)), SLOT(isCurrentPlaylistRow(bool&)));
1255  connect(widget, SIGNAL(isSearchedResultEmpty(bool&)), SLOT(isSearchedResultEmpty(bool&)));
1256  connect(widget, SIGNAL(deleteItemAt(TTKIntList,bool)), SLOT(removeItemAt(TTKIntList,bool)));
1257  connect(widget, SIGNAL(itemIndexSwaped(int,int,int,MusicSongList&)), SLOT(itemIndexSwaped(int,int,int,MusicSongList&)));
1258  connect(widget, SIGNAL(addSongToLovestList(bool,int)), SLOT(addSongToLovestList(bool,int)));
1259  connect(widget, SIGNAL(showFloatWidget()), SLOT(showFloatWidget()));
1260  connect(widget, SIGNAL(songListSortBy(int)), SLOT(songListSortBy(int)));
1261 
1263  setInputModule(m_items.back().m_itemWidget);
1264 
1265  widget->setSongsList(&item->m_songs);
1266  setTitle(widget, QString("%1[%2]").arg(item->m_itemName).arg(item->m_songs.count()));
1267 }
1268 
1270 {
1271  m_containerItems << item;
1272  MusicSongItem *it = &m_containerItems.back();
1273  createWidgetItem(it);
1274  return it;
1275 }
1276 
1278 {
1279  const QString title(QString("%1[%2]").arg(item->m_itemName).arg(item->m_songs.count()));
1280  setTitle(item->m_itemWidget, title);
1281 
1282  if(m_topMaskWidget->isVisible() && m_topMaskWidget->index() == item->m_itemIndex)
1283  {
1284  m_topMaskWidget->setTitle(title);
1285  }
1286 }
1287 
1289 {
1290  connect(object, SIGNAL(addNewRowItem()), SLOT(addNewRowItem()));
1291  connect(object, SIGNAL(deleteRowItem(int)), SLOT(deleteRowItem(int)));
1292  connect(object, SIGNAL(deleteAllItems(int)), SLOT(deleteAllItems(int)));
1293  connect(object, SIGNAL(changRowItemName(int,QString)), SLOT(changRowItemName(int,QString)));
1294  connect(object, SIGNAL(addNewFiles(int)), SLOT(importSongsByFiles(int)));
1295  connect(object, SIGNAL(addNewDir(int)), SLOT(importSongsByDir(int)));
1296  connect(object, SIGNAL(songListSortBy(int)), SLOT(songListSortBy(int)));
1297  connect(object, SIGNAL(swapDragItemIndex(int,int)), SLOT(swapDragItemIndex(int,int)));
1298  connect(object, SIGNAL(addToPlayLater(int)), SLOT(addToPlayLater(int)));
1299  connect(object, SIGNAL(addToPlayedList(int)), SLOT(addToPlayedList(int)));
1300 }
1301 
1303 {
1304  if(m_functionWidget)
1305  {
1306  m_functionWidget->move(width() - m_functionWidget->width() - 15, height() - 40 - m_functionWidget->height());
1307  }
1308 
1309  if(m_songSearchWidget)
1310  {
1311  m_songSearchWidget->move(0, height() - m_songSearchWidget->height());
1312  }
1313 }
1314 
1316 {
1317  for(const MusicSongItem &item : qAsConst(m_containerItems))
1318  {
1319  const int index = foundMappedIndex(item.m_itemIndex);
1320  item.m_itemWidget->setPlaylistRow(index);
1321  }
1322 
1323  TTK::IndexPropertyList items;
1324  if(end == -1)
1325  {
1326  for(int i = begin + 1; i < m_containerItems.count(); ++i)
1327  {
1328  items << TTK::IndexProperty(i + 1, i);
1329  }
1330  }
1331  else
1332  {
1333  items << TTK::IndexProperty(begin, end);
1334 
1335  if(begin > end)
1336  {
1337  for(int i = begin; i < end; ++i)
1338  {
1339  items << TTK::IndexProperty(i + 1, i);
1340  }
1341  }
1342  else
1343  {
1344  for(int i = end; i > begin; --i)
1345  {
1346  items << TTK::IndexProperty(i, i - 1);
1347  }
1348  }
1349  }
1350 
1352 }
1353 
void setTitle(QWidget *item, const QString &text)
#define TTKStaticCast(x, y)
Definition: ttkglobal.h:231
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
virtual void contextMenuEvent(QContextMenuEvent *event) overridefinal
#define TTK_DEFAULT_STR
Definition: ttkglobal.h:276
#define QtContainerSwap(p, i, j)
Container swap.
Definition: ttkqtcompat.h:52
#define TTK_LOW_LEVEL
Definition: ttkglobal.h:332
The class of the show progress widget.
void setSongSort(MusicSongSort *sort) noexcept
void addSongToLovestList(bool state=true)
QString path() const noexcept
Definition: musicsong.h:90
static QStringList supportMusicInputFilterFormats() noexcept
void setSongSort(MusicSongSort *sort) noexcept
void songToLovestListAt(bool state, int row)
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:218
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)
MusicSongsListFunctionWidget * m_functionWidget
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
const MusicSongItemList & items() const noexcept
The class of the songs list function widget.
QList< int > TTKIntList
Definition: ttkqtglobal.h:200
#define qAsConst
Definition: ttkqtglobal.h:57
const char * name
Definition: http_parser.c:458
TTK_MODULE_EXPORT bool isNetworkUrl(const QString &path) noexcept
void setInputModule(QObject *object) const
void removeItemAt(const TTKIntList &del, bool fileRemove)
TTK_MODULE_EXPORT bool playlistRowValid(int index) noexcept
Definition: musicsong.cpp:95
virtual void setSongsList(MusicSongList *songs)
void importSongsByFiles(int index=TTK_LOW_LEVEL)
MusicAbstractSongsListTableWidget * m_itemWidget
Definition: musicsong.h:168
void addSongToLovestList(bool state, int row)
static QStringList supportMusicFormats() noexcept
void addCellItem(QWidget *item, const QString &text)
#define TTK_NORMAL_LEVEL
Definition: ttkglobal.h:333
void importSongsByPath(const QStringList &files, int playlistRow)
MusicSongsToolBoxMaskWidget * m_topMaskWidget
#define TTK_SEPARATOR
Definition: ttkglobal.h:269
void changRowItemName(int index, const QString &name)
QSet< int > TTKIntSet
Definition: ttkqtglobal.h:199
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)
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
MusicToolBoxWidgetItemList m_items
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 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
TTK_MODULE_EXPORT QStringList fileListByPath(const QString &dpath, const QStringList &filter={}, bool recursively=true)
#define TTK_FILE_SUFFIX(fin)
Definition: ttkqtglobal.h:185
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
MusicSongItem * createContainerItem(const MusicSongItem &item)
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)
bool isSearchedPlayIndex() const noexcept
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.
#define G_SETTING_PTR
TTK_MODULE_EXPORT MusicSongList generateSongList(const QString &path)
Definition: musicsong.cpp:132
#define TTKObjectCast(x, y)
Definition: ttkqtglobal.h:82