void PlaylistView::selectSongsByRegExp() { // We can't use selectItemsByRegExp here, because it matches ListModelItemData::text, // but for PlaylistModel its value doesn't correspond to what actually displyed, as // it uses SongDisplayFormatParser for this job. auto resultCallback = [this](const std::string& pattern, LineEdit::Result result) { if (result == LineEdit::Result::Accepted) { GRegex *regex = g_regex_new(pattern.c_str(), G_REGEX_OPTIMIZE, (GRegexMatchFlags)0, nullptr); if (!regex) return; PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); PlaylistItemDelegate *delegate = static_cast<PlaylistItemDelegate*>(itemDelegate()); selectItems([plsModel, delegate, regex](int item){ return delegate->matchFormattedString(plsModel->song(item), regex); }); g_regex_unref(regex); StatusArea::showMessage("%d items selected", selectedItems().size()); } }; StatusArea::askQuestion("Select items: ", resultCallback, ".*"); }
bool PlaylistManager::show( const Tomahawk::album_ptr& album ) { PlaylistView* view; if ( !m_albumViews.contains( album ) ) { view = new PlaylistView(); PlaylistModel* model = new PlaylistModel(); view->setModel( model ); view->setFrameShape( QFrame::NoFrame ); view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); model->append( album ); m_albumViews.insert( album, view ); } else { view = m_albumViews.value( album ); } setPage( view ); emit numSourcesChanged( 1 ); return true; }
void FilterPlaylistModel::setCurrentIndex(int presentIndex) { QModelIndex i = index(presentIndex, 0); PlaylistModel *playlistmodel = static_cast<PlaylistModel*>(sourceModel()); playlistmodel->setCurrentIndex(mapToSource(i).row()); emit currentIndexChanged(); }
void PlaylistView::addFile(const std::string& path) { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); const std::string::size_type slashPos = path.rfind('/'); const std::string fileName = slashPos != std::string::npos ? path.substr(slashPos + 1) : path; const Utils::FileType fileType = Utils::getFileType(path); switch (fileType) { case Utils::FileType::Media: m_xmmsClient->playlistAddUrl(plsModel->playlist(), std::string("file://").append(path)); StatusArea::showMessage("Adding \"%s\" file to \"%s\" playlist", fileName, plsModel->playlist()); break; case Utils::FileType::Playlist: m_xmmsClient->playlistAddPlaylistFile(plsModel->playlist(), std::string("file://").append(path)); StatusArea::showMessage("Adding \"%s\" playlist to \"%s\" playlist", fileName, plsModel->playlist()); break; case Utils::FileType::Unknown: StatusArea::showMessage("Unknown file type!"); break; } }
bool PlaylistManager::show( const Tomahawk::playlist_ptr& playlist ) { PlaylistView* view; if ( !m_playlistViews.contains( playlist ) ) { view = new PlaylistView(); PlaylistModel* model = new PlaylistModel(); view->setModel( model ); view->setFrameShape( QFrame::NoFrame ); view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); model->loadPlaylist( playlist ); playlist->resolve(); m_playlistViews.insert( playlist, view ); } else { view = m_playlistViews.value( playlist ); } setPage( view ); TomahawkSettings::instance()->appendRecentlyPlayedPlaylist( playlist ); emit numSourcesChanged( SourceList::instance()->count() ); return true; }
QueueView::QueueView( AnimatedSplitter* parent ) : AnimatedWidget( parent ) , ui( new Ui::QueueView ) , m_dragTimer( 0 ) { ui->setupUi( this ); TomahawkUtils::unmarginLayout( layout() ); setContentsMargins( 0, 0, 0, 0 ); setHiddenSize( QSize( 0, 22 ) ); ui->queue->setProxyModel( new QueueProxyModel( ui->queue ) ); ui->queue->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); PlaylistModel* queueModel = new PlaylistModel( this ); queueModel->setStyle( PlaylistModel::Short ); queueModel->finishLoading(); ui->queue->setPlaylistModel( queueModel ); queueModel->setReadOnly( false ); // ui->queue->setEmptyTip( tr( "The queue is currently empty. Drop something to enqueue it!" ) ); ui->queue->setEmptyTip( QString() ); connect( queueModel, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( updateLabel() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); connect( this, SIGNAL( animationFinished() ), SLOT( onAnimationFinished() ) ); ui->toggleButton->installEventFilter( this ); ui->toggleButton->setCursor( Qt::PointingHandCursor ); }
void PlaylistView::addUrl(const std::string& url) { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); m_xmmsClient->playlistAddUrl(plsModel->playlist(), url); // FIXME: Url may be too long to display StatusArea::showMessage("Adding \"%s\" to \"%s\" playlist", url, plsModel->playlist()); }
PlaylistView* ViewManager::createPageForPlaylist( const playlist_ptr& pl ) { PlaylistView* view = new PlaylistView(); PlaylistModel* model = new PlaylistModel(); view->setPlaylistModel( model ); model->loadPlaylist( pl ); pl->resolve(); m_playlistViews.insert( pl, view ); return view; }
PlaylistView* ViewManager::createPageForPlaylist( const playlist_ptr& pl ) { PlaylistView* view = new PlaylistView(); PlaylistModel* model = new PlaylistModel(); view->setPlaylistModel( model ); model->loadPlaylist( pl ); view->setFrameShape( QFrame::NoFrame ); view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); pl->resolve(); m_playlistViews.insert( pl, view ); return view; }
PlaylistViewPage* ViewManager::createPageForPlaylist( const playlist_ptr& playlist ) { PlaylistViewPage* view = new PlaylistViewPage(); PlaylistModel* model = new PlaylistModel(); // We need to set the model on the view before loading the playlist, so spinners & co are connected view->view()->trackView()->setPlayableModel( model ); model->loadPlaylist( playlist ); playlist->resolve(); return view; }
PlaylistViewPage* ViewManager::createPageForList( const QString& title, const QList< query_ptr >& queries ) { PlaylistViewPage* view = new PlaylistViewPage(); PlaylistModel* model = new PlaylistModel(); view->setTemporaryPage( true ); // We need to set the model on the view before loading the playlist, so spinners & co are connected view->view()->trackView()->setPlayableModel( model ); model->setTitle( title ); model->appendQueries( queries ); return view; }
FlexibleView* ViewManager::createPageForPlaylist( const playlist_ptr& playlist ) { FlexibleView* view = new FlexibleView(); PlaylistModel* model = new PlaylistModel(); PlaylistView* pv = new PlaylistView(); pv->setPlaylistModel( model ); view->setDetailedView( pv ); view->setPixmap( pv->pixmap() ); model->loadPlaylist( playlist ); view->setPlayableModel( model ); playlist->resolve(); return view; }
void PlaylistView::openContainingFolder() { PlaylistModel *playlistModel = dynamic_cast<PlaylistModel *>(this->model()); if (playlistModel == nullptr) { return; } QModelIndex i = this->currentIndex(); if (i.isValid()) { int row = i.row(); const Song *s = playlistModel->getPlaylist()->getSong(row); QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(::mydirname(s->Filename)))); } }
void PlaylistView::removeSelectedSongs() { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); if (plsModel->itemsCount() && !isCurrentItemHidden()) { // Actually we don't have to make copy of selectedItems, since removeEntry // doesn't modify it immediately, but this is not obvious and may lead to // problems in the future. const std::vector<int> selectedSongs = selectedItems(); if (!selectedSongs.empty()) { assert(std::is_sorted(selectedSongs.begin(), selectedSongs.end())); std::for_each(selectedSongs.rbegin(), selectedSongs.rend(), [&](int item){ m_xmmsClient->playlistRemoveEntry(plsModel->playlist(), item); }); } else { m_xmmsClient->playlistRemoveEntry(plsModel->playlist(), currentItem()); } showCurrentItem(); } }
FlexibleView* ViewManager::createPageForPlaylist( const playlist_ptr& playlist ) { FlexibleView* view = new FlexibleView(); PlaylistModel* model = new PlaylistModel(); PlaylistView* pv = new PlaylistView(); view->setDetailedView( pv ); view->setPixmap( pv->pixmap() ); // We need to set the model on the view before loading the playlist, so spinners & co are connected view->setPlaylistModel( model ); pv->setPlaylistModel( model ); model->loadPlaylist( playlist ); playlist->resolve(); return view; }
void PlaylistView::showInspector() { PlaylistModel *playlistModel = dynamic_cast<PlaylistModel *>(this->model()); if (playlistModel == nullptr) { return; } QModelIndex i = this->currentIndex(); if (i.isValid()) { int row = i.row(); const Song *s = playlistModel->getPlaylist()->getSong(row); SongInspector *insp = new SongInspector(s, this); insp->setAttribute(Qt::WA_DeleteOnClose); insp->show(); } }
playlist_ptr ViewManager::playlistForPage( ViewPage* page ) const { playlist_ptr p; PlaylistViewPage* fv = dynamic_cast< PlaylistViewPage* >( page ); if ( fv && fv->view()->trackView()->model() ) { PlaylistModel* m = dynamic_cast< PlaylistModel* >( fv->view()->trackView()->model() ); if ( m && m->playlist() ) { p = m->playlist(); } } else if ( dynamic_cast< DynamicWidget* >( page ) ) p = dynamic_cast< DynamicWidget* >( page )->playlist(); return p; }
FlexibleView* ViewManager::createPageForList( const QString& title, const QList< query_ptr >& queries ) { FlexibleView* view = new FlexibleView(); PlaylistModel* model = new PlaylistModel(); PlaylistView* pv = new PlaylistView(); view->setDetailedView( pv ); view->setPixmap( pv->pixmap() ); view->setTemporaryPage( true ); // We need to set the model on the view before loading the playlist, so spinners & co are connected view->setPlaylistModel( model ); pv->setPlaylistModel( model ); model->setTitle( title ); model->appendQueries( queries ); return view; }
void PlaylistView::moveSelectedSongs() { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); const std::vector<int> selectedSongs = selectedItems(); assert(std::is_sorted(selectedSongs.begin(), selectedSongs.end())); if (isCurrentItemHidden() || selectedSongs.empty()) return; const int moveTo = currentItem(); auto it = std::lower_bound(selectedSongs.begin(), selectedSongs.end(), moveTo); int to = moveTo; for (size_t i = it - selectedSongs.begin(); i < selectedSongs.size(); ++i, ++to) { m_xmmsClient->playlistMoveEntry(plsModel->playlist(), selectedSongs[i], to); } to = it == selectedSongs.end() ? moveTo : moveTo - 1; for (ptrdiff_t i = it - selectedSongs.begin() - 1; i >= 0; --i, --to) { m_xmmsClient->playlistMoveEntry(plsModel->playlist(), selectedSongs[i], to); } }
void PlaylistView::addPath(const std::string& path) { // TODO: Introduce FileInfo class instead of using glib functions, // maybe simple stat call wrapper if (!g_file_test(path.c_str(), G_FILE_TEST_EXISTS)) { StatusArea::showMessage("File doesn't exist!"); return; } if (g_file_test(path.c_str(), G_FILE_TEST_IS_REGULAR)) { addFile(path); } else if (g_file_test(path.c_str(), G_FILE_TEST_IS_DIR)) { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); m_xmmsClient->playlistAddRecursive(plsModel->playlist(), std::string("file://").append(path)); // FIXME: Path may be too long to display StatusArea::showMessage("Adding \"%s\" directory to \"%s\" playlist", path, plsModel->playlist()); } else { StatusArea::showMessage("File is neither a directory nor regular file!"); } }
void PlaylistView::unselectSongsByRegExp() { // The same story here... auto resultCallback = [this](const std::string& pattern, LineEdit::Result result) { if (result == LineEdit::Result::Accepted) { GRegex *regex = g_regex_new(pattern.c_str(), G_REGEX_OPTIMIZE, (GRegexMatchFlags)0, nullptr); if (!regex) return; PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); PlaylistItemDelegate *delegate = static_cast<PlaylistItemDelegate*>(itemDelegate()); unselectItems([plsModel, delegate, regex](int item){ return delegate->matchFormattedString(plsModel->song(item), regex); }); g_regex_unref(regex); StatusArea::showMessage("%d items selected", selectedItems().size()); } }; StatusArea::askQuestion("Unselect items: ", resultCallback, ".*"); }
void PlaylistView::moveItems(int steps) { PlaylistModel *playlistModel = dynamic_cast<PlaylistModel *>(this->model()); if (playlistModel == nullptr) { return; } QItemSelection indexList = this->selectionModel()->selection(); std::sort(indexList.begin(), indexList.end(), steps > 0 ? sortQItemSelectionDesc : sortQItemSelectionAsc); for (QItemSelection::const_iterator i = indexList.cbegin(); i != indexList.cend(); ++i) { int top = i->top(); int btm = i->bottom(); int count = abs(top - btm); int srcRow = min(top, btm); int destRow = srcRow + steps; QModelIndex newIdx = steps > 0 ? playlistModel->index(destRow + count, 0) : playlistModel->index(srcRow - 1, 0); QModelIndex oldIdx = steps > 0 ? playlistModel->index(srcRow, 0) : playlistModel->index(srcRow + count, 0); if (newIdx.isValid()) { this->selectionModel()->select(newIdx, QItemSelectionModel::SelectionFlag::Select | QItemSelectionModel::SelectionFlag::Rows); this->selectionModel()->select(oldIdx, QItemSelectionModel::SelectionFlag::Deselect | QItemSelectionModel::SelectionFlag::Rows); playlistModel->moveRows(playlistModel->index(0, 0), srcRow, count, playlistModel->index(playlistModel->rowCount(QModelIndex()) - 1, playlistModel->columnCount(QModelIndex()) - 1), destRow); } } }
void WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) { if ( requestData.caller != s_whatsHotIdentifier ) return; if ( output.isNull() ) { tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Info came back empty"; return; } if ( !output.canConvert< QVariantMap >() ) { tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "WhatsHot: Could not parse output into a map"; return; } QVariantMap returnedData = output.toMap(); switch ( requestData.type ) { case InfoSystem::InfoChartCapabilities: { setViewData( returnedData ); } case InfoSystem::InfoChart: { if ( returnedData.contains( "chart_error" ) ) { tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Info came back with error!"; Tomahawk::InfoSystem::InfoStringHash criteria; criteria.insert( "chart_refetch", returnedData[ "chart_source" ].value< QString >() ); Tomahawk::InfoSystem::InfoRequestData requestData; requestData.caller = s_whatsHotIdentifier; requestData.customData = QVariantMap(); requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( criteria ); requestData.type = Tomahawk::InfoSystem::InfoChartCapabilities; requestData.timeoutMillis = 20000; requestData.allSources = false; Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); tDebug( LOGVERBOSE ) << "WhatsHot: re-requesting InfoChartCapabilities"; break; } if ( !returnedData.contains( "type" ) ) break; const QString type = returnedData[ "type" ].toString(); if ( !returnedData.contains( type ) ) break; const QString chartId = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >().value( "chart_id" ); m_queuedFetches.remove( chartId ); ChartDataLoader* loader = new ChartDataLoader(); loader->setProperty( "chartid", chartId ); loader->moveToThread( m_workerThread ); if ( type == "artists" ) { loader->setType( ChartDataLoader::Artist ); loader->setData( returnedData[ "artists" ].value< QStringList >() ); connect( loader, SIGNAL( artists( Tomahawk::ChartDataLoader*, QList< Tomahawk::artist_ptr > ) ), SLOT( chartArtistsLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::artist_ptr > ) ) ); TreeModel* artistsModel = new TreeModel( ui->artistsViewLeft ); artistsModel->setMode( InfoSystemMode ); artistsModel->startLoading(); m_artistModels[ chartId ] = artistsModel; if ( m_queueItemToShow == chartId ) setLeftViewArtists( artistsModel ); } else if ( type == "albums" ) { loader->setType( ChartDataLoader::Album ); loader->setData( returnedData[ "albums" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); connect( loader, SIGNAL( albums( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ), SLOT( chartAlbumsLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ) ); PlayableModel* albumModel = new PlayableModel( ui->albumsView ); albumModel->startLoading(); m_albumModels[ chartId ] = albumModel; if ( m_queueItemToShow == chartId ) setLeftViewAlbums( albumModel ); } else if ( type == "tracks" ) { loader->setType( ChartDataLoader::Track ); loader->setData( returnedData[ "tracks" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); connect( loader, SIGNAL( tracks( Tomahawk::ChartDataLoader*, QList< Tomahawk::query_ptr > ) ), SLOT( chartTracksLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::query_ptr > ) ) ); PlaylistModel* trackModel = new PlaylistModel( ui->tracksViewLeft ); trackModel->startLoading(); m_trackModels[ chartId ] = trackModel; if ( m_queueItemToShow == chartId ) setLeftViewTracks( trackModel ); } QMetaObject::invokeMethod( loader, "go", Qt::QueuedConnection ); break; } default: return; } }
void PlaylistView::keyPressEvent(QKeyEvent *event) { PlaylistModel *playlistModel = dynamic_cast<PlaylistModel *>(this->model()); if (playlistModel == nullptr) { return; } QModelIndex bot = playlistModel->index(playlistModel->rowCount(QModelIndex()) - 1, 0); QModelIndex top = playlistModel->index(0, 0); int key = event->key(); switch (key) { case Qt::Key_Delete: { QItemSelection indexList = this->selectionModel()->selection(); int lastCount = 0; for (QItemSelection::const_iterator i = indexList.cbegin(); i != indexList.cend(); ++i) { int btm = i->bottom(); int top = i->top(); if (btm < 0 || top < 0) { break; } lastCount = abs(top - btm) + 1; playlistModel->removeRows(min(btm, top), lastCount); } } break; case Qt::Key_W: this->moveItems(-1); break; case Qt::Key_S: this->moveItems(1); break; case Qt::Key_Home: case Qt::Key_End: if ((event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier) { QModelIndex cur = this->currentIndex(); QItemSelectionRange aboveCur(top, cur); QItemSelection selection; selection.append(aboveCur); this->selectionModel()->select(selection, ((key == Qt::Key_Home) ? QItemSelectionModel::Select : QItemSelectionModel::Deselect) | QItemSelectionModel::Rows); selection.clear(); QItemSelectionRange belowCur(cur, bot); selection.append(belowCur); this->selectionModel()->select(selection, ((key == Qt::Key_Home) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select) | QItemSelectionModel::Rows); // make sure the current index is selected this->selectionModel()->select(this->currentIndex(), QItemSelectionModel::Select | QItemSelectionModel::Rows); break; } else if ((event->modifiers() & Qt::NoModifier) == Qt::NoModifier) { this->setCurrentIndex((key == Qt::Key_Home) ? top : bot); break; } else { [[fallthrough]]; } default: QTableView::keyPressEvent(event); break; } }
void PlaylistView::setPlaylist(const std::string& playlist) { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); plsModel->setPlaylist(playlist); }
int FilterPlaylistModel::currentIndex() const { PlaylistModel *playlistmodel = static_cast<PlaylistModel*>(sourceModel()); return mapFromSource(sourceModel()->index(playlistmodel->currentIndex(), 0)).row(); }
void PlaylistView::setLazyLoadPlaylist(bool enable) { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); plsModel->setLazyLoadPlaylist(enable); }
void FilterPlaylistModel::playFromSourceModel(int indexInFilterModel) { PlaylistModel *playlistmodel = static_cast<PlaylistModel*>(sourceModel()); playlistmodel->play(mapToSource(index(indexInFilterModel, 0)).row()); }
void PlaylistView::onItemEntered(int item) { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); m_xmmsClient->playlistPlayItem(plsModel->playlist(), item); }
void PlaylistView::keyPressedEvent(const KeyEvent& keyEvent) { PlaylistModel *plsModel = static_cast<PlaylistModel*>(model()); switch (keyEvent.key()) { case Hotkeys::PlaylistView::RemoveEntry: removeSelectedSongs(); break; case Hotkeys::PlaylistView::ClearPlaylist: m_xmmsClient->playlistClear(plsModel->playlist()); break; case Hotkeys::PlaylistView::ShufflePlaylist: m_xmmsClient->playlistShuffle(plsModel->playlist()); break; case Hotkeys::PlaylistView::GoToCurrentlyPlayingSong: setCurrentItem(plsModel->currentSongItem()); break; case Hotkeys::PlaylistView::MoveSelectedSongs: moveSelectedSongs(); break; case Hotkeys::PlaylistView::AddFileOrDirectory: { auto resultCallback = [this](const std::string& path, LineEdit::Result result) { if (result == LineEdit::Result::Accepted) addPath(path); }; StatusArea::askQuestion("Add path: ", resultCallback); break; } case Hotkeys::PlaylistView::AddUrl: { auto resultCallback = [this](const std::string& url, LineEdit::Result result) { if (result == LineEdit::Result::Accepted) addUrl(url); }; StatusArea::askQuestion("Add url: ", resultCallback); break; } case Hotkeys::PlaylistView::ShowSongInfo: if (plsModel->itemsCount() && !isCurrentItemHidden()) { int id = plsModel->song(currentItem()).id(); if (id > 0) showSongInfo(id); } break; case '+': // Select be regexp selectSongsByRegExp(); break; case '\\': // Unselect be regexp unselectSongsByRegExp(); break; default: ListViewAppIntegrated::keyPressedEvent(keyEvent); } }