File indexing completed on 2024-05-19 04:53:23
0001 /* 0002 * playlisttab.cpp 0003 * 0004 * Copyright (C) 2009-2011 Christoph Pfister <christophpfister@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License along 0017 * with this program; if not, write to the Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #include "../log.h" 0022 0023 #include <KActionCollection> 0024 #include <KFileWidget> 0025 #include <QAction> 0026 #include <QBoxLayout> 0027 #include <QFileDialog> 0028 #include <QKeyEvent> 0029 #include <QListView> 0030 #include <QMenu> 0031 #include <QSplitter> 0032 #include <QStandardPaths> 0033 #include <QTimer> 0034 #include <QToolButton> 0035 0036 #if QT_VERSION >= 0x050a00 0037 # include <QRandomGenerator> 0038 #endif 0039 0040 #include "playlistmodel.h" 0041 #include "playlisttab.h" 0042 0043 PlaylistBrowserModel::PlaylistBrowserModel(PlaylistModel *playlistModel_, 0044 Playlist *temporaryPlaylist, QObject *parent) : QAbstractListModel(parent), 0045 playlistModel(playlistModel_), currentPlaylist(-1) 0046 { 0047 playlists.append(temporaryPlaylist); 0048 0049 QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/playlistsK4")); 0050 0051 if (!file.open(QIODevice::ReadOnly)) { 0052 file.setFileName(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/playlists")); 0053 0054 if (!file.open(QIODevice::ReadOnly)) { 0055 qCWarning(logPlaylist, "Cannot open file %s", qPrintable(file.fileName())); 0056 return; 0057 } 0058 } 0059 0060 QDataStream stream(&file); 0061 stream.setVersion(QDataStream::Qt_4_4); 0062 0063 unsigned int version; 0064 stream >> version; 0065 bool hasMetadata = true; 0066 bool hasSubtitles = true; 0067 0068 if (version == 0xc39637a1) { 0069 // compatibility code 0070 hasMetadata = false; 0071 hasSubtitles = false; 0072 } else if (version == 0x2e00f3ea) { 0073 // compatibility code 0074 hasSubtitles = false; 0075 } else if (version != 0x361c4a3c) { 0076 qCWarning(logPlaylist, "Cannot read file %s", qPrintable(file.fileName())); 0077 return; 0078 } 0079 0080 while (!stream.atEnd()) { 0081 Playlist *playlist = new Playlist(); 0082 stream >> playlist->title; 0083 QString urlString; 0084 stream >> urlString; 0085 playlist->url = urlString; 0086 int count; 0087 stream >> count; 0088 0089 for (int i = 0; (i < count) && !stream.atEnd(); ++i) { 0090 PlaylistTrack track; 0091 stream >> urlString; 0092 track.url = urlString; 0093 0094 if (hasMetadata) { 0095 stream >> track.title; 0096 stream >> track.artist; 0097 stream >> track.album; 0098 stream >> track.trackNumber; 0099 stream >> track.length; 0100 } else { 0101 track.title = track.url.fileName(); 0102 } 0103 0104 if (hasSubtitles) { 0105 QStringList subtitleStrings; 0106 stream >> subtitleStrings; 0107 0108 foreach (const QString &subtitleString, subtitleStrings) { 0109 track.subtitles.append(subtitleString); 0110 } 0111 0112 stream >> track.currentSubtitle; 0113 } 0114 0115 playlist->tracks.append(track); 0116 } 0117 0118 if (stream.status() != QDataStream::Ok) { 0119 qCWarning(logPlaylist, "Cannot read file %s", qPrintable(file.fileName())); 0120 delete playlist; 0121 break; 0122 } 0123 0124 playlists.append(playlist); 0125 } 0126 } 0127 0128 PlaylistBrowserModel::~PlaylistBrowserModel() 0129 { 0130 QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/playlistsK4")); 0131 0132 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0133 qCWarning(logPlaylist, "Cannot open file %s", qPrintable(file.fileName())); 0134 return; 0135 } 0136 0137 QDataStream stream(&file); 0138 stream.setVersion(QDataStream::Qt_4_4); 0139 0140 int version = 0x361c4a3c; 0141 stream << version; 0142 0143 for (int i = 1; i < playlists.size(); ++i) { 0144 const Playlist *playlist = playlists.at(i); 0145 stream << playlist->title; 0146 stream << playlist->url.url(); 0147 stream << playlist->tracks.size(); 0148 0149 foreach (const PlaylistTrack &track, playlist->tracks) { 0150 stream << track.url.url(); 0151 stream << track.title; 0152 stream << track.artist; 0153 stream << track.album; 0154 stream << track.trackNumber; 0155 stream << track.length; 0156 0157 QStringList subtitleStrings; 0158 0159 for (int j = 0; j < track.subtitles.size(); ++j) { 0160 const QUrl &url = track.subtitles.at(j); 0161 subtitleStrings.append(url.url()); 0162 } 0163 0164 stream << subtitleStrings; 0165 stream << track.currentSubtitle; 0166 } 0167 } 0168 0169 qDeleteAll(playlists); 0170 } 0171 0172 int PlaylistBrowserModel::rowCount(const QModelIndex &parent) const 0173 { 0174 if (parent.isValid()) { 0175 return 0; 0176 } 0177 0178 return playlists.size(); 0179 } 0180 0181 QVariant PlaylistBrowserModel::data(const QModelIndex &index, int role) const 0182 { 0183 if (role == Qt::DecorationRole) { 0184 if (index.row() == currentPlaylist) { 0185 return QIcon::fromTheme(QLatin1String("arrow-right"), QIcon(":arrow-right")); 0186 } 0187 } else if (role == Qt::DisplayRole) { 0188 return playlists.at(index.row())->title; 0189 } 0190 0191 return QVariant(); 0192 } 0193 0194 bool PlaylistBrowserModel::removeRows(int row, int count, const QModelIndex &parent) 0195 { 0196 if (parent.isValid()) { 0197 return false; 0198 } 0199 0200 if (row == 0) { 0201 ++row; 0202 0203 if ((--count) == 0) { 0204 return false; 0205 } 0206 } 0207 0208 beginRemoveRows(QModelIndex(), row, row + count - 1); 0209 Playlist *visiblePlaylist = playlistModel->getVisiblePlaylist(); 0210 0211 for (int i = row; i < (row + count); ++i) { 0212 if (playlists.at(i) == visiblePlaylist) { 0213 if ((row + count) < playlists.size()) { 0214 playlistModel->setVisiblePlaylist(playlists.at(row + count)); 0215 } else { 0216 playlistModel->setVisiblePlaylist(playlists.at(row - 1)); 0217 } 0218 } 0219 } 0220 0221 QList<Playlist *>::Iterator begin = playlists.begin() + row; 0222 QList<Playlist *>::Iterator end = begin + count; 0223 qDeleteAll(begin, end); 0224 playlists.erase(begin, end); 0225 0226 if (currentPlaylist >= row) { 0227 if (currentPlaylist >= (row + count)) { 0228 currentPlaylist -= count; 0229 } else { 0230 currentPlaylist = -1; 0231 emit playTrack(NULL, -1); 0232 } 0233 } 0234 0235 endRemoveRows(); 0236 return true; 0237 } 0238 0239 Qt::ItemFlags PlaylistBrowserModel::flags(const QModelIndex &index) const 0240 { 0241 return QAbstractListModel::flags(index) | Qt::ItemIsEditable; 0242 } 0243 0244 bool PlaylistBrowserModel::setData(const QModelIndex &index, const QVariant &value, int role) 0245 { 0246 if (role == Qt::EditRole) { 0247 QString title = value.toString(); 0248 0249 if (title.isEmpty()) { 0250 return false; 0251 } 0252 0253 playlists.at(index.row())->title = title; 0254 emit dataChanged(index, index); 0255 return true; 0256 } 0257 0258 return false; 0259 } 0260 0261 void PlaylistBrowserModel::append(Playlist *playlist) 0262 { 0263 beginInsertRows(QModelIndex(), playlists.size(), playlists.size()); 0264 playlists.append(playlist); 0265 endInsertRows(); 0266 } 0267 0268 Playlist *PlaylistBrowserModel::getPlaylist(int row) const 0269 { 0270 return playlists.at(row); 0271 } 0272 0273 void PlaylistBrowserModel::setCurrentPlaylist(Playlist *playlist) 0274 { 0275 int oldPlaylist = currentPlaylist; 0276 currentPlaylist = playlists.indexOf(playlist); 0277 0278 if (oldPlaylist == currentPlaylist) { 0279 return; 0280 } 0281 0282 if (oldPlaylist != -1) { 0283 playlistModel->setCurrentTrack(playlists.at(oldPlaylist), -1); 0284 QModelIndex modelIndex = index(oldPlaylist, 0); 0285 emit dataChanged(modelIndex, modelIndex); 0286 } 0287 0288 if (currentPlaylist != -1) { 0289 QModelIndex modelIndex = index(currentPlaylist, 0); 0290 emit dataChanged(modelIndex, modelIndex); 0291 } 0292 } 0293 0294 Playlist *PlaylistBrowserModel::getCurrentPlaylist() const 0295 { 0296 if (currentPlaylist >= 0) { 0297 return playlists.at(currentPlaylist); 0298 } else { 0299 return playlistModel->getVisiblePlaylist(); 0300 } 0301 } 0302 0303 class PlaylistBrowserView : public QListView 0304 { 0305 public: 0306 explicit PlaylistBrowserView(QWidget *parent) : QListView(parent) { } 0307 ~PlaylistBrowserView() { } 0308 0309 protected: 0310 void keyPressEvent(QKeyEvent *event) override; 0311 }; 0312 0313 void PlaylistBrowserView::keyPressEvent(QKeyEvent *event) 0314 { 0315 if (event->key() == Qt::Key_Delete) { 0316 QModelIndexList selectedRows = selectionModel()->selectedRows(); 0317 std::sort(selectedRows.begin(), selectedRows.end()); 0318 0319 for (int i = selectedRows.size() - 1; i >= 0; --i) { 0320 // FIXME compress 0321 model()->removeRows(selectedRows.at(i).row(), 1); 0322 } 0323 0324 return; 0325 } 0326 0327 QListView::keyPressEvent(event); 0328 } 0329 0330 PlaylistView::PlaylistView(QWidget *parent) : QTreeView(parent) 0331 { 0332 } 0333 0334 PlaylistView::~PlaylistView() 0335 { 0336 } 0337 0338 void PlaylistView::removeSelectedRows() 0339 { 0340 QModelIndexList selectedRows = selectionModel()->selectedRows(); 0341 std::sort(selectedRows.begin(), selectedRows.end()); 0342 0343 for (int i = selectedRows.size() - 1; i >= 0; --i) { 0344 // FIXME compress 0345 model()->removeRows(selectedRows.at(i).row(), 1); 0346 } 0347 } 0348 0349 void PlaylistView::contextMenuEvent(QContextMenuEvent *event) 0350 { 0351 if (!currentIndex().isValid()) { 0352 return; 0353 } 0354 0355 QMenu::exec(actions(), event->globalPos()); 0356 } 0357 0358 void PlaylistView::keyPressEvent(QKeyEvent *event) 0359 { 0360 if (event->key() == Qt::Key_Delete) { 0361 removeSelectedRows(); 0362 return; 0363 } 0364 0365 QTreeView::keyPressEvent(event); 0366 } 0367 0368 PlaylistTab::PlaylistTab(QMenu *menu, KActionCollection *collection, MediaWidget *mediaWidget_) : 0369 mediaWidget(mediaWidget_) 0370 { 0371 Playlist *temporaryPlaylist = new Playlist(); 0372 temporaryPlaylist->title = i18nc("playlist browser", "Temporary Playlist"); 0373 0374 playlistModel = new PlaylistModel(temporaryPlaylist, this); 0375 connect(playlistModel, SIGNAL(playTrack(Playlist*,int)), 0376 this, SLOT(playTrack(Playlist*,int))); 0377 connect(playlistModel, SIGNAL(appendPlaylist(Playlist*,bool)), 0378 this, SLOT(appendPlaylist(Playlist*,bool))); 0379 0380 playlistBrowserModel = new PlaylistBrowserModel(playlistModel, temporaryPlaylist, this); 0381 playlistModel->setVisiblePlaylist(playlistBrowserModel->getPlaylist(0)); 0382 connect(playlistBrowserModel, SIGNAL(playTrack(Playlist*,int)), 0383 this, SLOT(playTrack(Playlist*,int))); 0384 0385 connect(mediaWidget, SIGNAL(playlistPrevious()), this, SLOT(playPreviousTrack())); 0386 connect(mediaWidget, SIGNAL(playlistNext()), this, SLOT(playNextTrack())); 0387 connect(mediaWidget, SIGNAL(playlistUrlsDropped(QList<QUrl>)), 0388 this, SLOT(appendUrls(QList<QUrl>))); 0389 connect(mediaWidget, SIGNAL(playlistTrackLengthChanged(int)), 0390 this, SLOT(updateTrackLength(int))); 0391 connect(mediaWidget, 0392 SIGNAL(playlistTrackMetadataChanged(QMap<MediaWidget::MetadataType,QString>)), 0393 this, SLOT(updateTrackMetadata(QMap<MediaWidget::MetadataType,QString>))); 0394 0395 repeatAction = new QAction(QIcon::fromTheme(QLatin1String("media-playlist-repeat"), QIcon(":media-playlist-repeat")), 0396 i18nc("playlist menu", "Repeat"), this); 0397 repeatAction->setCheckable(true); 0398 menu->addAction(collection->addAction(QLatin1String("playlist_repeat"), repeatAction)); 0399 0400 randomAction = new QAction(QIcon::fromTheme(QLatin1String("media-playlist-shuffle"), QIcon(":media-playlist-shuffle")), 0401 i18nc("playlist menu", "Random"), this); 0402 randomAction->setCheckable(true); 0403 menu->addAction(collection->addAction(QLatin1String("playlist_random"), randomAction)); 0404 0405 QAction *addSubtitleAction = 0406 new QAction(QIcon::fromTheme(QLatin1String("application-x-subrip"), QIcon(":application-x-subrip")), i18n("Add Subtitle"), this); 0407 collection->addAction(QLatin1String("playlist_add_subtitle"), addSubtitleAction); 0408 0409 QAction *removeTrackAction = 0410 new QAction(QIcon::fromTheme(QLatin1String("edit-delete"), QIcon(":edit-delete")), i18nc("@action", "Remove"), this); 0411 collection->addAction(QLatin1String("playlist_remove_track"), removeTrackAction); 0412 0413 QAction *clearAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear-list"), QIcon(":edit-clear-list")), 0414 i18nc("remove all items from a list", "Clear"), this); 0415 connect(clearAction, SIGNAL(triggered(bool)), playlistModel, SLOT(clearVisiblePlaylist())); 0416 menu->addAction(collection->addAction(QLatin1String("playlist_clear"), clearAction)); 0417 0418 menu->addSeparator(); 0419 0420 QAction *newAction = new QAction(QIcon::fromTheme(QLatin1String("list-add"), QIcon(":list-add")), i18nc("@action:inmenu playlist", "New"), this); 0421 connect(newAction, SIGNAL(triggered(bool)), this, SLOT(newPlaylist())); 0422 menu->addAction(collection->addAction(QLatin1String("playlist_new"), newAction)); 0423 0424 QAction *renameAction = new QAction(QIcon::fromTheme(QLatin1String("edit-rename"), QIcon(":edit-rename")), 0425 i18nc("rename an entry in a list", "Rename"), this); 0426 connect(renameAction, SIGNAL(triggered(bool)), this, SLOT(renamePlaylist())); 0427 menu->addAction(collection->addAction(QLatin1String("playlist_rename"), renameAction)); 0428 0429 QAction *removePlaylistAction = 0430 new QAction(QIcon::fromTheme(QLatin1String("edit-delete"), QIcon(":edit-delete")), i18nc("@action", "Remove"), this); 0431 connect(removePlaylistAction, SIGNAL(triggered(bool)), this, SLOT(removePlaylist())); 0432 menu->addAction(collection->addAction(QLatin1String("playlist_remove"), removePlaylistAction)); 0433 0434 QAction *savePlaylistAction = KStandardAction::save(this, SLOT(savePlaylist()), this); 0435 menu->addAction(collection->addAction(QLatin1String("playlist_save"), savePlaylistAction)); 0436 0437 QAction *savePlaylistAsAction = 0438 KStandardAction::saveAs(this, SLOT(savePlaylistAs()), this); 0439 menu->addAction(collection->addAction(QLatin1String("playlist_save_as"), savePlaylistAsAction)); 0440 0441 QBoxLayout *widgetLayout = new QHBoxLayout(this); 0442 widgetLayout->setMargin(0); 0443 0444 QSplitter *horizontalSplitter = new QSplitter(this); 0445 widgetLayout->addWidget(horizontalSplitter); 0446 0447 QSplitter *verticalSplitter = new QSplitter(Qt::Vertical, horizontalSplitter); 0448 0449 QWidget *widget = new QWidget(verticalSplitter); 0450 QBoxLayout *sideLayout = new QVBoxLayout(widget); 0451 sideLayout->setMargin(0); 0452 0453 QBoxLayout *boxLayout = new QHBoxLayout(); 0454 0455 QToolButton *toolButton = new QToolButton(widget); 0456 toolButton->setDefaultAction(newAction); 0457 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0458 boxLayout->addWidget(toolButton); 0459 0460 toolButton = new QToolButton(widget); 0461 toolButton->setDefaultAction(renameAction); 0462 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0463 boxLayout->addWidget(toolButton); 0464 0465 toolButton = new QToolButton(widget); 0466 toolButton->setDefaultAction(removePlaylistAction); 0467 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0468 boxLayout->addWidget(toolButton); 0469 0470 toolButton = new QToolButton(widget); 0471 toolButton->setDefaultAction(savePlaylistAction); 0472 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0473 boxLayout->addWidget(toolButton); 0474 0475 toolButton = new QToolButton(widget); 0476 toolButton->setDefaultAction(savePlaylistAsAction); 0477 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0478 boxLayout->addWidget(toolButton); 0479 0480 boxLayout->addStretch(); 0481 sideLayout->addLayout(boxLayout); 0482 0483 playlistBrowserView = new PlaylistBrowserView(widget); 0484 playlistBrowserView->addAction(newAction); 0485 playlistBrowserView->addAction(renameAction); 0486 playlistBrowserView->addAction(removePlaylistAction); 0487 playlistBrowserView->addAction(savePlaylistAction); 0488 playlistBrowserView->addAction(savePlaylistAsAction); 0489 playlistBrowserView->setContextMenuPolicy(Qt::ActionsContextMenu); 0490 playlistBrowserView->setModel(playlistBrowserModel); 0491 connect(playlistBrowserView, SIGNAL(activated(QModelIndex)), 0492 this, SLOT(playlistActivated(QModelIndex))); 0493 sideLayout->addWidget(playlistBrowserView); 0494 0495 // KFileWidget creates a local event loop which can cause bad side 0496 // effects (because the main window isn't fully constructed yet) 0497 fileWidgetSplitter = verticalSplitter; 0498 QTimer::singleShot(0, this, SLOT(createFileWidget())); 0499 0500 verticalSplitter = new QSplitter(Qt::Vertical, horizontalSplitter); 0501 0502 widget = new QWidget(verticalSplitter); 0503 sideLayout = new QVBoxLayout(widget); 0504 sideLayout->setMargin(0); 0505 0506 boxLayout = new QHBoxLayout(); 0507 0508 toolButton = new QToolButton(widget); 0509 toolButton->setDefaultAction(repeatAction); 0510 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0511 boxLayout->addWidget(toolButton); 0512 0513 toolButton = new QToolButton(widget); 0514 toolButton->setDefaultAction(randomAction); 0515 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0516 boxLayout->addWidget(toolButton); 0517 0518 toolButton = new QToolButton(widget); 0519 toolButton->setDefaultAction(removeTrackAction); 0520 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0521 boxLayout->addWidget(toolButton); 0522 0523 toolButton = new QToolButton(widget); 0524 toolButton->setDefaultAction(clearAction); 0525 toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0526 boxLayout->addWidget(toolButton); 0527 0528 boxLayout->addStretch(); 0529 sideLayout->addLayout(boxLayout); 0530 0531 playlistView = new PlaylistView(widget); 0532 playlistView->setAlternatingRowColors(true); 0533 playlistView->setDragDropMode(QAbstractItemView::DragDrop); 0534 playlistView->setRootIsDecorated(false); 0535 playlistView->setSelectionMode(QAbstractItemView::ExtendedSelection); 0536 playlistView->setModel(playlistModel); 0537 playlistView->sortByColumn(-1, Qt::AscendingOrder); 0538 playlistView->setSortingEnabled(true); 0539 playlistView->addAction(addSubtitleAction); 0540 connect(addSubtitleAction, SIGNAL(triggered(bool)), this, SLOT(addSubtitle())); 0541 playlistView->addAction(removeTrackAction); 0542 connect(removeTrackAction, SIGNAL(triggered(bool)), 0543 playlistView, SLOT(removeSelectedRows())); 0544 connect(playlistView, SIGNAL(activated(QModelIndex)), 0545 this, SLOT(playTrack(QModelIndex))); 0546 sideLayout->addWidget(playlistView); 0547 0548 QWidget *mediaContainer = new QWidget(verticalSplitter); 0549 mediaLayout = new QHBoxLayout(mediaContainer); 0550 mediaLayout->setMargin(0); 0551 0552 verticalSplitter->setStretchFactor(1, 1); 0553 horizontalSplitter->setStretchFactor(1, 1); 0554 } 0555 0556 PlaylistTab::~PlaylistTab() 0557 { 0558 } 0559 0560 void PlaylistTab::appendToCurrentPlaylist(const QList<QUrl> &urls, bool playImmediately) 0561 { 0562 playlistModel->appendUrls(playlistBrowserModel->getCurrentPlaylist(), urls, 0563 playImmediately); 0564 } 0565 0566 void PlaylistTab::appendToVisiblePlaylist(const QList<QUrl> &urls, bool playImmediately) 0567 { 0568 playlistModel->appendUrls(playlistModel->getVisiblePlaylist(), urls, playImmediately); 0569 } 0570 0571 void PlaylistTab::removeTrack(int row) 0572 { 0573 Playlist *currentPlaylist = playlistBrowserModel->getCurrentPlaylist(); 0574 0575 if ((row >= 0) && (row < currentPlaylist->tracks.size())) { 0576 playlistModel->removeRows(currentPlaylist, row, 1); 0577 } 0578 } 0579 0580 void PlaylistTab::setRandom(bool random) 0581 { 0582 randomAction->setChecked(random); 0583 } 0584 0585 void PlaylistTab::setRepeat(bool repeat) 0586 { 0587 repeatAction->setChecked(repeat); 0588 } 0589 0590 int PlaylistTab::getCurrentTrack() const 0591 { 0592 const Playlist *currentPlaylist = playlistBrowserModel->getCurrentPlaylist(); 0593 0594 if (currentPlaylist->currentTrack >= 0) { 0595 return currentPlaylist->currentTrack; 0596 } else { 0597 return 0; 0598 } 0599 } 0600 0601 int PlaylistTab::getTrackCount() const 0602 { 0603 return playlistBrowserModel->getCurrentPlaylist()->tracks.size(); 0604 } 0605 0606 bool PlaylistTab::getRandom() const 0607 { 0608 return randomAction->isChecked(); 0609 } 0610 0611 bool PlaylistTab::getRepeat() const 0612 { 0613 return repeatAction->isChecked(); 0614 } 0615 0616 void PlaylistTab::createFileWidget() 0617 { 0618 KFileWidget *fileWidget = new KFileWidget(QUrl(), fileWidgetSplitter); 0619 fileWidget->setFilter(MediaWidget::extensionFilter()); 0620 fileWidget->setMode(KFile::Files | KFile::ExistingOnly); 0621 fileWidgetSplitter->setStretchFactor(1, 1); 0622 0623 // KFileWidget creates a QUrlComboBox without layout (!), which steals the focus: 0624 // kDebug() << QApplication::focusWidget(); 0625 // kDebug() << QApplication::focusWidget()->layout(); 0626 // Let's reclaim the focus (and give it back to the main window). 0627 // FIXME report issue 0628 window()->setFocus(); 0629 } 0630 0631 void PlaylistTab::newPlaylist() 0632 { 0633 Playlist *playlist = new Playlist(); 0634 playlist->title = i18nc("playlist browser", "Unnamed Playlist"); 0635 playlistBrowserModel->append(playlist); 0636 } 0637 0638 void PlaylistTab::renamePlaylist() 0639 { 0640 QModelIndex index = playlistBrowserView->currentIndex(); 0641 0642 if (!index.isValid() || (index.row() == 0)) { 0643 return; 0644 } 0645 0646 playlistBrowserView->edit(index); 0647 } 0648 0649 void PlaylistTab::removePlaylist() 0650 { 0651 QModelIndexList selectedRows = playlistBrowserView->selectionModel()->selectedRows(); 0652 std::sort(selectedRows.begin(), selectedRows.end()); 0653 0654 for (int i = selectedRows.size() - 1; i >= 0; --i) { 0655 // FIXME compress 0656 playlistBrowserModel->removeRows(selectedRows.at(i).row(), 1); 0657 } 0658 } 0659 0660 void PlaylistTab::savePlaylist() 0661 { 0662 savePlaylist(false); 0663 } 0664 0665 void PlaylistTab::savePlaylistAs() 0666 { 0667 savePlaylist(true); 0668 } 0669 0670 void PlaylistTab::addSubtitle() 0671 { 0672 QModelIndexList selectedRows = playlistView->selectionModel()->selectedRows(); 0673 0674 if (selectedRows.size() != 1) { 0675 return; 0676 } 0677 0678 int row = selectedRows.at(0).row(); 0679 Playlist *playlist = playlistModel->getVisiblePlaylist(); 0680 QList<QUrl> urls = QFileDialog::getOpenFileUrls(this, "", QUrl(), subtitleExtensionFilter()); 0681 0682 if ((row < playlist->tracks.size()) && !urls.isEmpty()) { 0683 PlaylistTrack &track = playlist->tracks[row]; 0684 track.subtitles += urls; 0685 0686 if (track.subtitles.size() == urls.size()) { 0687 track.currentSubtitle = 0; 0688 } 0689 0690 if ((playlist == playlistBrowserModel->getCurrentPlaylist()) && 0691 (playlist->currentTrack == row)) { 0692 // FIXME ! 0693 } 0694 } 0695 } 0696 0697 void PlaylistTab::playlistActivated(const QModelIndex &index) 0698 { 0699 playlistModel->setVisiblePlaylist(playlistBrowserModel->getPlaylist(index.row())); 0700 } 0701 0702 void PlaylistTab::playPreviousTrack() 0703 { 0704 Playlist *currentPlaylist = playlistBrowserModel->getCurrentPlaylist(); 0705 playTrack(currentPlaylist, currentPlaylist->currentTrack - 1); 0706 } 0707 0708 void PlaylistTab::playCurrentTrack() 0709 { 0710 Playlist *currentPlaylist = playlistBrowserModel->getCurrentPlaylist(); 0711 0712 if (currentPlaylist->currentTrack >= 0) { 0713 playTrack(currentPlaylist, currentPlaylist->currentTrack); 0714 } else { 0715 playNextTrack(); 0716 } 0717 } 0718 0719 void PlaylistTab::playNextTrack() 0720 { 0721 Playlist *currentPlaylist = playlistBrowserModel->getCurrentPlaylist(); 0722 0723 if (randomAction->isChecked()) { 0724 int size = currentPlaylist->tracks.size(); 0725 0726 if (size < 2) { 0727 playTrack(currentPlaylist, 0); 0728 } else if (currentPlaylist->currentTrack != -1) { 0729 #if QT_VERSION >= 0x050a00 0730 quint32 rand = QRandomGenerator::global()->generate(); 0731 #else 0732 quint32 rand = qrand(); 0733 #endif 0734 int track = (rand % (size - 1)); 0735 0736 if (track >= currentPlaylist->currentTrack) { 0737 ++track; 0738 } 0739 0740 playTrack(currentPlaylist, track); 0741 } else { 0742 #if QT_VERSION >= 0x050a00 0743 quint32 rand = QRandomGenerator::global()->generate(); 0744 #else 0745 quint32 rand = qrand(); 0746 #endif 0747 playTrack(currentPlaylist, rand % size); 0748 } 0749 } else if (((currentPlaylist->currentTrack + 1) == currentPlaylist->tracks.size()) && 0750 repeatAction->isChecked()) { 0751 playTrack(currentPlaylist, 0); 0752 } else { 0753 playTrack(currentPlaylist, currentPlaylist->currentTrack + 1); 0754 } 0755 } 0756 0757 void PlaylistTab::activate() 0758 { 0759 mediaLayout->addWidget(mediaWidget); 0760 } 0761 0762 void PlaylistTab::playTrack(const QModelIndex &index) 0763 { 0764 playTrack(playlistModel->getVisiblePlaylist(), index.row()); 0765 } 0766 0767 void PlaylistTab::playTrack(Playlist *playlist, int track) 0768 { 0769 if ((track < 0) || (playlist == NULL) || (track >= playlist->tracks.size())) { 0770 track = -1; 0771 } 0772 0773 if (track != -1) { 0774 PlaylistTrack &playlistTrack = playlist->tracks[track]; 0775 QUrl subtitleUrl; 0776 0777 if ((playlistTrack.currentSubtitle >= 0) && 0778 (playlistTrack.currentSubtitle < playlistTrack.subtitles.size())) { 0779 subtitleUrl = playlistTrack.subtitles.at(playlistTrack.currentSubtitle); 0780 } else if (playlistTrack.subtitles.isEmpty()) { 0781 // check whether there's a possible subtitle file candidate 0782 QString localFile = playlistTrack.url.toLocalFile(); 0783 localFile.truncate(localFile.lastIndexOf(QLatin1Char('.'))); 0784 0785 if (!localFile.isEmpty()) { 0786 if (QFile::exists(localFile + QLatin1String(".asc"))) { 0787 subtitleUrl = QUrl::fromLocalFile(localFile + QLatin1String(".asc")); 0788 } else if (QFile::exists(localFile + QLatin1String(".smi"))) { 0789 subtitleUrl = QUrl::fromLocalFile(localFile + QLatin1String(".smi")); 0790 } else if (QFile::exists(localFile + QLatin1String(".srt"))) { 0791 subtitleUrl = QUrl::fromLocalFile(localFile + QLatin1String(".srt")); 0792 } else if (QFile::exists(localFile + QLatin1String(".ssa"))) { 0793 subtitleUrl = QUrl::fromLocalFile(localFile + QLatin1String(".ssa")); 0794 } else if (QFile::exists(localFile + QLatin1String(".sub"))) { 0795 subtitleUrl = QUrl::fromLocalFile(localFile + QLatin1String(".sub")); 0796 } else if (QFile::exists(localFile + QLatin1String(".txt"))) { 0797 subtitleUrl = QUrl::fromLocalFile(localFile + QLatin1String(".txt")); 0798 } 0799 } 0800 0801 if (subtitleUrl.isValid()) { 0802 playlistTrack.subtitles += subtitleUrl; 0803 playlistTrack.currentSubtitle = 0; 0804 } 0805 } 0806 0807 mediaWidget->play(playlistTrack.url, subtitleUrl); 0808 // FIXME ! 0809 playlistBrowserModel->setCurrentPlaylist(playlist); 0810 } else { 0811 mediaWidget->stop(); 0812 } 0813 0814 if (playlist != NULL) { 0815 playlistModel->setCurrentTrack(playlist, track); 0816 } 0817 } 0818 0819 void PlaylistTab::appendUrls(const QList<QUrl> &urls) 0820 { 0821 playlistModel->appendUrls(playlistModel->getVisiblePlaylist(), urls, true); 0822 } 0823 0824 void PlaylistTab::appendPlaylist(Playlist *playlist, bool playImmediately) 0825 { 0826 playlistBrowserModel->append(playlist); 0827 0828 if (playImmediately) { 0829 playlistBrowserModel->setCurrentPlaylist(playlist); 0830 playlistModel->setVisiblePlaylist(playlist); 0831 playNextTrack(); 0832 } 0833 } 0834 0835 void PlaylistTab::updateTrackLength(int length) 0836 { 0837 playlistModel->updateTrackLength(playlistBrowserModel->getCurrentPlaylist(), length); 0838 } 0839 0840 void PlaylistTab::updateTrackMetadata(const QMap<MediaWidget::MetadataType, QString> &metadata) 0841 { 0842 playlistModel->updateTrackMetadata(playlistBrowserModel->getCurrentPlaylist(), metadata); 0843 } 0844 0845 QString PlaylistTab::subtitleExtensionFilter() 0846 { 0847 return QString(QLatin1String("*.asc *.smi *.srt *.ssa *.sub *.txt|")) + 0848 i18nc("file filter", "Subtitle Files"); 0849 } 0850 0851 void PlaylistTab::savePlaylist(bool askName) 0852 { 0853 QModelIndex index = playlistBrowserView->currentIndex(); 0854 0855 if (!index.isValid()) { 0856 return; 0857 } 0858 0859 Playlist *playlist = playlistBrowserModel->getPlaylist(index.row()); 0860 QUrl url = playlist->url; 0861 0862 if (askName || !url.isValid() || 0863 url.fileName().endsWith(QLatin1String(".kaffeine"), Qt::CaseInsensitive)) { 0864 url = QFileDialog::getSaveFileUrl(this, "", QUrl(), i18nc("file filter", 0865 "*.xspf|XSPF Playlist\n*.m3u|M3U Playlist\n*.pls|PLS Playlist")); 0866 0867 if (!url.isValid()) { 0868 return; 0869 } 0870 0871 playlist->url = url; 0872 } 0873 0874 QString fileName = url.fileName(); 0875 Playlist::Format format = Playlist::Invalid; 0876 0877 if (fileName.endsWith(QLatin1String(".m3u"), Qt::CaseInsensitive)) { 0878 format = Playlist::M3U; 0879 } else if (fileName.endsWith(QLatin1String(".pls"), Qt::CaseInsensitive)) { 0880 format = Playlist::PLS; 0881 } else if (fileName.endsWith(QLatin1String(".xspf"), Qt::CaseInsensitive)) { 0882 format = Playlist::XSPF; 0883 } 0884 0885 if (format != Playlist::Invalid) { 0886 playlist->save(format); 0887 } 0888 } 0889 0890 #include "moc_playlisttab.cpp"