📄 qmplaylist.cpp
字号:
/*! \returns True if \a e can be decoded (i.e. dropped), false otherwise.*/boolQmPlayList::canDecode( QDragMoveEvent *e){ return QUriDrag::canDecode(e) || QmListView::canDecode(e);}/*! Sets the column width of \a col to \a w. */voidQmPlayList::setColumnWidth( int col, int w){ QmListView::setColumnWidth(col, w); if(col == 1) QmListView::setColumnWidth(0, viewport()->width() - w);}/*! Reads the song info for all entries in the playlist. For MP3s, for example, the ID3 tags will be read.*/voidQmPlayList::readSongInfo(){ if (m_DeletingItems || QmMainWindow::mainwin->state() == QmMainWindow::Busy) return; QmMainWindow::mainwin->setState( QmMainWindow::Busy ); QString format = QmConfig::instance()->getString("stuff", "display-format"); QString formatMulti = QmConfig::instance()->getString("stuff", "display-format-multi"); const char *cformat = format.latin1(); const char *cformatMulti = formatMulti.latin1(); long len; long start_time = time(0); updateSongIndex(); int i; for(unsigned i = 0; i < m_SongIndex.size(); ++i) { m_SongIndex[i]->readInfo(cformat, cformatMulti); if(i % 50 == 49) { len = time(0) - start_time; if(len) { QmMainWindow::mainwin->statusUpdate(new Message(Message::Update, "Read id3 info for %d songs (%ld seconds)", i+1, len)); } else { QmMainWindow::mainwin->statusUpdate(new Message(Message::Update, "Read id3 info for %d songs", i+1)); } } } len = time(0) - start_time; if (len) { QmMainWindow::mainwin->statusUpdate(new Message(Message::Status, "Read id3 info for %d songs (%ld seconds)", i+1, len)); } else { QmMainWindow::mainwin->statusUpdate(new Message(Message::Status, "Read id3 info for %d songs", i+1)); } triggerUpdate(); setDirty(); QmMainWindow::mainwin->setState(QmMainWindow::Ready);}/*! Generates a playlist for each artist and album Also generates a PlayListTree if alsoPlayListTree. */voidQmPlayList::generatePlayListForEachArtistAndAlbum( int alsoPlayListTree) { QmMainWindow::mainwin->setState(QmMainWindow::Busy); QmConfig *conf = QmConfig::instance(); updateSongIndex(); // use a copy for sorting std::vector<QmSongItem*> si = m_SongIndex; std::sort(si.begin(), si.end(), compareSongs<>(&QmSongItem::m_Artist, &QmSongItem::m_Album, &QmSongItem::m_CdPosition)); QString pldir = QFileDialog::getExistingDirectory ( conf->getString("path", "playlist"), this, 0, tr("Choose directory to generate playlists in"), true ); if (pldir.isEmpty()) { QmMainWindow::mainwin->statusUpdate(new Message(Message::Status, tr("Canceled, no playlists saved"))); QmMainWindow::mainwin->setState(QmMainWindow::Ready); return; } conf->set("path", "playlist", pldir); QString plt; QFile tree; QTextStream tout; QString enc = conf->getString("stuff", "encoding"); bool utf8 = QString("utf-8") == enc; if (alsoPlayListTree) { plt = QFileDialog::getSaveFileName(conf->getString("path", "playlisttree"), QString::null, this, 0, tr("Name of Playlist tree")); if (plt.isEmpty()) alsoPlayListTree = false; else { tree.setName(plt); if (!tree.open( IO_WriteOnly ) ) { QmMainWindow::mainwin->statusUpdate(new Message(Message::Error, tr("Could not write playlist tree to \"%s\""), plt.latin1())); alsoPlayListTree = false; } else { tout.setDevice( &tree ); if (utf8) tout.setEncoding(QTextStream::UnicodeUTF8); tout << "<?xml version='1.0' encoding=\"" << enc << "\"?>\n" << "<!DOCTYPE APOLLO-PLAYLISTTREE>\n" << "<apollo-playlisttree>\n"; } } } // ar = artist, al = album QFile arfile; QFile alfile; QString artist; QString album; bool first = true; bool firstAlbum = true; QTextStream arout; QTextStream alout; int count = 0; QString arfilename; QString alfilename; QString arclean; // artist name without special characters removed QString alclean; for (uint i = 1; i < si.size(); i++) { if (si[i]->artist().isEmpty() || si[i]->album().isEmpty()) continue; if (si[i]->album() != album) { if (si[i]->artist() != artist) { artist = si[i]->artist(); if (!first) { if (!firstAlbum) arout << "</dir>\n"; arout << "</dir>\n</apollo-playlist>\n"; arfile.close(); } firstAlbum = true; /// \todo clean this loop up and put it in a function arclean.truncate(0); QChar c; for (uint j=0; j<artist.length(); ++j) { c = artist[j]; if (c.isLetterOrNumber() || c == ' ' || c == '_' || c == "-") arclean += c; } arfilename = pldir + arclean + ".xml"; arfile.setName( arfilename ); if ( !arfile.open( IO_WriteOnly ) ) { QmMainWindow::mainwin->statusUpdate(new Message(Message::Error, tr("Error: Could not write to \"%s\""), arfile.name().latin1())); QmMainWindow::mainwin->setState(QmMainWindow::Ready); return; } if (alsoPlayListTree) { if (!first) tout << "</dir>\n"; tout << "<dir><name><![CDATA[" << artist << "]]></name>\n"; } QmMainWindow::mainwin->statusUpdate(new Message(Message::Update, tr("Saving %s (%i)"), si[i]->artist().latin1(), ++count)); arout.setDevice( &arfile ); if (utf8) arout.setEncoding(QTextStream::UnicodeUTF8); arout << "<?xml version='1.0' encoding=\"" << enc << "\"?>\n" << "<!DOCTYPE APOLLO-PLAYLIST>\n" << "<apollo-playlist>\n"; arout << "<dir>\n" << "<name><![CDATA[" << artist << "]]></name>\n"; } album = si[i]->album(); alclean.truncate(0); QChar c; for (uint j=0; j<album.length(); ++j) { c = album[j]; if (c.isLetterOrNumber() || c.isSpace() || c == '_' || c == "-") alclean += c; } alfilename = pldir + arclean + " " + alclean + ".xml"; if (!first) { alout << "</dir></dir>\n"; alout << "</apollo-playlist>\n"; alfile.close(); } alfile.setName( alfilename ); if ( !alfile.open( IO_WriteOnly ) ) { QmMainWindow::mainwin->statusUpdate(new Message(Message::Error, tr("*Error: Could not write to \"%s\""), alfile.name().latin1())); QmMainWindow::mainwin->setState(QmMainWindow::Ready); return; } alout.setDevice( &alfile ); if (utf8) alout.setEncoding(QTextStream::UnicodeUTF8); alout << "<?xml version='1.0' encoding=\"" << enc << "\"?>\n" << "<!DOCTYPE APOLLO-PLAYLIST>\n" << "<apollo-playlist>\n"; if (alsoPlayListTree) { tout << "<playlist>\n" << "<name><![CDATA[" << album << "]]></name>\n" << "<path><![CDATA[" << alfilename << "]]></path>\n" << "</playlist>\n"; } if (!firstAlbum) arout << "</dir>\n"; arout << "<dir>\n" << "<name><![CDATA[" << album << "]]></name>\n"; alout << "<dir>\n" << "<name><![CDATA[" << artist << "]]></name>\n"; alout << "<dir>\n" << "<name><![CDATA[" << album << "]]></name>\n"; first = firstAlbum = false; } si[i]->writeXml(arout); si[i]->writeXml(alout); } if (alsoPlayListTree) tout << "</dir>\n" << "</apollo-playlisttree>\n"; QmMainWindow::mainwin->statusUpdate(new Message(Message::Status, "Generated %i playlists", count)); QmMainWindow::mainwin->setState(QmMainWindow::Ready);}/*! Called when the selection has changed. Updates status info.*/voidQmPlayList::newSelection(){ if (m_DeletingItems || QmMainWindow::mainwin->state() == QmMainWindow::Busy) return; m_Delay.start(1000);}voidQmPlayList::newSelectionHandler(){ if (m_DeletingItems) return; updateSongIndex(); long len = 0; int songs = 0; int notCounted = 0; // songs lacking play length are not counted for (uint i = 0; i < m_SongIndex.size(); i++) { if (m_SongIndex[i]->isSong() && isSelected(m_SongIndex[i])) { if (m_SongIndex[i]->length()) len += m_SongIndex[i]->length(); else notCounted++; songs++; } } if(songs > 1) { QString time; secondsToTimeString(len, time); if (notCounted) { QmMainWindow::mainwin->statusUpdate(new Message(Message::Status, "Selected %d songs (%s %d not counted)", songs, time.latin1(), notCounted)); } else { QmMainWindow::mainwin->statusUpdate(new Message(Message::Status, "Selected %d songs (%s)", songs, time.latin1())); } } else { setDefaultStatus(); }}/*! Generates the default status message showing information about the current playlist. This is the message that is shown when there is no "special" selection. */voidQmPlayList::setDefaultStatus(){ if (m_DeletingItems || QmMainWindow::mainwin->state() == QmMainWindow::Busy) return; int songs = 0; int folders = 0; for(QListViewItemIterator it(this); it.current(); ++it) { if(reinterpret_cast<QmPlayListItem*>(it.current())->isSong()) songs++; else folders++; } QmMainWindow::mainwin->statusUpdate(new Message(Message::Status, "%d songs, %d folders", songs, folders));}/*! Regenerates the song index. Unless \a force is true, the index will only be updated if necessary. The song index is a std::vector of pointers to the non-bad songs to allow easy indexed access and iteration of non-bad songs, as well as temporary storage while reorganising the play list. */voidQmPlayList::updateSongIndex( bool force) { if (m_SongIndexDirty || force) { m_SongIndex.clear(); for (QListViewItemIterator it(this); it.current(); ++it) { if (static_cast<QmPlayListItem*>(it.current())->isSong()) if (!static_cast<QmPlayListItem*>(it.current())->isBad()) m_SongIndex.push_back(static_cast<QmSongItem*>(it.current())); } m_SongIndexDirty = false; } if (m_pCurrentSong==0 && !m_SongIndex.empty()) m_pCurrentSong = m_SongIndex[0];}/*! Show properties for the selected item. */voidQmPlayList::showItemProperties(){ QmSongItem *song = dynamic_cast<QmSongItem*>(currentItem()); if(song == 0) return; if(m_pPropertyDlg != 0) delete m_pPropertyDlg; m_pPropertyDlg = new QmPropertyDialog; m_pPropertyDlg->addPage(tr("Info"), new QmSongInfoPropertyPage(song)); m_pPropertyDlg->show();}/*! Get a song by it's linear position in the playlist. Automatically updates the song index when needed. */QmSongItem*QmPlayList::getSong( int index) { updateSongIndex(); return m_SongIndex[index];}#ifndef DOXYGEN_SKIP_THIS/*! Compare function for songs, used to sort the song index.*/template<typename t1, typename t2, typename t3>boolcompareSongs<t1,t2,t3>::operator()( const QmSongItem *a, const QmSongItem *b) const{ CHECK_PTR(a); CHECK_PTR(b); if (depth == 2) { if (a->*sort_on1 == b->*sort_on1) return a->*sort_on2 < b->*sort_on2; } else if (depth == 3) { if (a->*sort_on1 == b->*sort_on1) { if (a->*sort_on2 == b->*sort_on2) return a->*sort_on3 < b->*sort_on3; else return a->*sort_on2 < b->*sort_on2; } } return a->*sort_on1 < b->*sort_on1;}#endif // DOXYGEN_SKIP_THIS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -