2010-05-20 16:12:15 +02:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-05-20 16:12:15 +02:00
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-07-17 14:47:59 +02:00
|
|
|
#include "playlist.h"
|
|
|
|
#include "playlistmanager.h"
|
2010-05-20 16:12:15 +02:00
|
|
|
#include "playlisttabbar.h"
|
2011-04-02 16:46:56 +02:00
|
|
|
#include "playlistview.h"
|
2010-07-17 14:47:59 +02:00
|
|
|
#include "songmimedata.h"
|
2011-04-22 19:07:57 +02:00
|
|
|
#include "core/logging.h"
|
2010-07-17 14:47:59 +02:00
|
|
|
#include "radio/radiomimedata.h"
|
2010-05-20 16:12:15 +02:00
|
|
|
#include "ui/iconloader.h"
|
2011-04-02 16:46:56 +02:00
|
|
|
#include "widgets/renametablineedit.h"
|
2010-05-20 16:12:15 +02:00
|
|
|
|
|
|
|
#include <QContextMenuEvent>
|
|
|
|
#include <QMenu>
|
2011-06-19 10:44:10 +02:00
|
|
|
#include <QMessageBox>
|
2010-05-20 16:12:15 +02:00
|
|
|
#include <QInputDialog>
|
2011-04-13 21:15:30 +02:00
|
|
|
#include <QToolTip>
|
2010-05-20 16:12:15 +02:00
|
|
|
|
|
|
|
PlaylistTabBar::PlaylistTabBar(QWidget *parent)
|
|
|
|
: QTabBar(parent),
|
2010-07-17 14:47:59 +02:00
|
|
|
manager_(NULL),
|
2010-05-20 16:12:15 +02:00
|
|
|
menu_(new QMenu(this)),
|
2010-05-21 12:29:17 +02:00
|
|
|
menu_index_(-1),
|
2011-04-02 16:46:56 +02:00
|
|
|
suppress_current_changed_(false),
|
2011-06-19 10:44:10 +02:00
|
|
|
rename_editor_(new RenameTabLineEdit(this)),
|
|
|
|
removing_from_menu_(true)
|
2010-05-20 16:12:15 +02:00
|
|
|
{
|
2010-07-17 14:47:59 +02:00
|
|
|
setAcceptDrops(true);
|
2011-04-02 16:46:56 +02:00
|
|
|
setElideMode(Qt::ElideRight);
|
2011-04-15 23:54:19 +02:00
|
|
|
setUsesScrollButtons(true);
|
2011-06-19 10:44:10 +02:00
|
|
|
setTabsClosable(true);
|
2010-07-17 14:47:59 +02:00
|
|
|
|
2010-05-20 16:12:15 +02:00
|
|
|
remove_ = menu_->addAction(IconLoader::Load("list-remove"), tr("Remove playlist"), this, SLOT(Remove()));
|
2010-05-23 00:20:00 +02:00
|
|
|
rename_ = menu_->addAction(IconLoader::Load("edit-rename"), tr("Rename playlist..."), this, SLOT(Rename()));
|
|
|
|
save_ = menu_->addAction(IconLoader::Load("document-save"), tr("Save playlist..."), this, SLOT(Save()));
|
2010-05-20 16:12:15 +02:00
|
|
|
menu_->addSeparator();
|
2010-05-21 12:29:17 +02:00
|
|
|
|
2011-04-02 16:46:56 +02:00
|
|
|
rename_editor_->setVisible(false);
|
|
|
|
connect(rename_editor_, SIGNAL(editingFinished()), SLOT(RenameInline()));
|
|
|
|
connect(rename_editor_, SIGNAL(EditingCanceled()), SLOT(HideEditor()));
|
|
|
|
|
2011-06-19 10:44:10 +02:00
|
|
|
connect(this, SIGNAL(currentChanged(int)), SLOT(CurrentIndexChanged(int)));
|
|
|
|
connect(this, SIGNAL(tabMoved(int,int)), SLOT(TabMoved()));
|
|
|
|
// We can't just emit Remove signal, we need to extract the playlist id first
|
|
|
|
connect(this, SIGNAL(tabCloseRequested(int)), SLOT(RemoveFromTabIndex(int)));
|
2010-05-20 16:12:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::SetActions(
|
2010-05-23 00:20:00 +02:00
|
|
|
QAction* new_playlist, QAction* load_playlist) {
|
2010-05-20 16:12:15 +02:00
|
|
|
menu_->insertAction(0, new_playlist);
|
|
|
|
menu_->insertAction(0, load_playlist);
|
2010-05-22 16:33:17 +02:00
|
|
|
|
|
|
|
new_ = new_playlist;
|
2010-05-20 16:12:15 +02:00
|
|
|
}
|
|
|
|
|
2010-07-17 14:47:59 +02:00
|
|
|
void PlaylistTabBar::SetManager(PlaylistManager *manager) {
|
|
|
|
manager_ = manager;
|
|
|
|
}
|
|
|
|
|
2010-05-20 16:12:15 +02:00
|
|
|
void PlaylistTabBar::contextMenuEvent(QContextMenuEvent* e) {
|
2011-04-02 16:46:56 +02:00
|
|
|
//we need to finish the renaming action before showing context menu
|
|
|
|
if (rename_editor_->isVisible()) {
|
|
|
|
//discard any change
|
|
|
|
HideEditor();
|
|
|
|
}
|
|
|
|
|
2010-05-20 16:12:15 +02:00
|
|
|
menu_index_ = tabAt(e->pos());
|
|
|
|
rename_->setEnabled(menu_index_ != -1);
|
2011-02-15 18:53:21 +01:00
|
|
|
remove_->setEnabled(menu_index_ != -1 && count() > 1);
|
2010-05-23 00:20:00 +02:00
|
|
|
save_->setEnabled(menu_index_ != -1);
|
2010-05-20 16:12:15 +02:00
|
|
|
|
|
|
|
menu_->popup(e->globalPos());
|
|
|
|
}
|
|
|
|
|
2010-05-22 16:33:17 +02:00
|
|
|
void PlaylistTabBar::mouseReleaseEvent(QMouseEvent* e) {
|
|
|
|
if (e->button() == Qt::MidButton) {
|
2011-06-19 10:44:10 +02:00
|
|
|
// Update menu index
|
|
|
|
menu_index_ = tabAt(e->pos());
|
|
|
|
// So we don't ask for confirmation
|
|
|
|
removing_from_menu_ = false;
|
|
|
|
Remove();
|
2010-05-22 16:33:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QTabBar::mouseReleaseEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::mouseDoubleClickEvent(QMouseEvent *e) {
|
|
|
|
int index = tabAt(e->pos());
|
2011-04-02 19:28:43 +02:00
|
|
|
|
|
|
|
//discard a double click with the middle button
|
2011-04-02 20:15:20 +02:00
|
|
|
if (e->button() != Qt::MidButton) {
|
2011-04-02 19:28:43 +02:00
|
|
|
if (index == -1) {
|
|
|
|
new_->activate(QAction::Trigger);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//update current tab
|
|
|
|
menu_index_ = index;
|
|
|
|
|
|
|
|
//set position
|
|
|
|
rename_editor_->setGeometry(tabRect(index));
|
|
|
|
rename_editor_->setText(tabText(index));
|
|
|
|
rename_editor_->setVisible(true);
|
|
|
|
rename_editor_->setFocus();
|
|
|
|
}
|
2011-04-02 16:46:56 +02:00
|
|
|
}
|
2010-05-22 16:33:17 +02:00
|
|
|
|
|
|
|
QTabBar::mouseDoubleClickEvent(e);
|
|
|
|
}
|
|
|
|
|
2010-05-20 16:12:15 +02:00
|
|
|
void PlaylistTabBar::Rename() {
|
|
|
|
if (menu_index_ == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QString name = tabText(menu_index_);
|
|
|
|
name = QInputDialog::getText(
|
|
|
|
this, tr("Rename playlist"), tr("Enter a new name for this playlist"),
|
|
|
|
QLineEdit::Normal, name);
|
|
|
|
|
|
|
|
if (name.isNull())
|
|
|
|
return;
|
|
|
|
|
2010-05-21 12:44:26 +02:00
|
|
|
emit Rename(tabData(menu_index_).toInt(), name);
|
2010-05-20 16:12:15 +02:00
|
|
|
}
|
|
|
|
|
2011-04-02 16:46:56 +02:00
|
|
|
void PlaylistTabBar::RenameInline() {
|
|
|
|
emit Rename(tabData(menu_index_).toInt(), rename_editor_->text());
|
|
|
|
HideEditor();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::HideEditor() {
|
|
|
|
//editingFinished() will be called twice due to Qt bug #40, so we reuse the same instance, don't delete it
|
|
|
|
rename_editor_->setVisible(false);
|
|
|
|
|
|
|
|
//hack to give back focus to playlist view
|
|
|
|
manager_->SetCurrentPlaylist(manager_->current()->id());
|
|
|
|
}
|
|
|
|
|
2010-05-20 16:12:15 +02:00
|
|
|
void PlaylistTabBar::Remove() {
|
|
|
|
if (menu_index_ == -1)
|
|
|
|
return;
|
|
|
|
|
2011-06-19 10:44:10 +02:00
|
|
|
// Ask for confirmation only when we arrive here by clicking in the menu
|
|
|
|
if (removing_from_menu_ && QMessageBox::question(this, tr("Remove playlist"),
|
|
|
|
tr("This playlist will be removed; the action can't be undone. "
|
|
|
|
"Are you sure you want to continue?"),
|
|
|
|
QMessageBox::Yes, QMessageBox::Cancel) != QMessageBox::Yes)
|
|
|
|
return;
|
|
|
|
|
|
|
|
removing_from_menu_ = true;
|
2010-05-21 12:44:26 +02:00
|
|
|
emit Remove(tabData(menu_index_).toInt());
|
2010-05-20 16:12:15 +02:00
|
|
|
}
|
2010-05-21 12:29:17 +02:00
|
|
|
|
2011-06-19 10:44:10 +02:00
|
|
|
void PlaylistTabBar::RemoveFromTabIndex(int index) {
|
|
|
|
// Update the global index
|
|
|
|
menu_index_ = index;
|
|
|
|
// So we don't ask for confirmation
|
|
|
|
removing_from_menu_ = false;
|
|
|
|
Remove();
|
|
|
|
}
|
|
|
|
|
2010-05-23 00:20:00 +02:00
|
|
|
void PlaylistTabBar::Save() {
|
|
|
|
if (menu_index_ == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
emit Save(tabData(menu_index_).toInt());
|
|
|
|
}
|
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
int PlaylistTabBar::current_id() const {
|
|
|
|
if (currentIndex() == -1)
|
|
|
|
return -1;
|
|
|
|
return tabData(currentIndex()).toInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int PlaylistTabBar::index_of(int id) const {
|
|
|
|
for (int i=0 ; i<count() ; ++i) {
|
|
|
|
if (tabData(i).toInt() == id) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::set_current_id(int id) {
|
|
|
|
setCurrentIndex(index_of(id));
|
|
|
|
}
|
|
|
|
|
2011-04-19 22:11:24 +02:00
|
|
|
int PlaylistTabBar::id_of(int index) const {
|
2011-04-22 19:07:57 +02:00
|
|
|
if (index < 0 || index >= count()) {
|
|
|
|
qLog(Warning) << "Playlist tab index requested is out of bounds!";
|
2011-04-19 22:11:24 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return tabData(index).toInt();
|
|
|
|
}
|
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
void PlaylistTabBar::set_icon_by_id(int id, const QIcon &icon) {
|
|
|
|
setTabIcon(index_of(id), icon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::RemoveTab(int id) {
|
|
|
|
removeTab(index_of(id));
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::set_text_by_id(int id, const QString &text) {
|
|
|
|
setTabText(index_of(id), text);
|
2011-04-11 18:29:36 +02:00
|
|
|
setTabToolTip(index_of(id), text);
|
2010-05-21 12:29:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::CurrentIndexChanged(int index) {
|
|
|
|
if (!suppress_current_changed_)
|
|
|
|
emit CurrentIdChanged(tabData(index).toInt());
|
|
|
|
}
|
|
|
|
|
2011-04-28 19:50:45 +02:00
|
|
|
void PlaylistTabBar::InsertTab(int id, int index, const QString& text,
|
|
|
|
const QIcon& icon) {
|
2010-05-21 12:29:17 +02:00
|
|
|
suppress_current_changed_ = true;
|
|
|
|
insertTab(index, text);
|
|
|
|
setTabData(index, id);
|
2011-04-11 18:29:36 +02:00
|
|
|
setTabToolTip(index, text);
|
2011-04-28 19:50:45 +02:00
|
|
|
setTabIcon(index, icon);
|
2010-05-21 12:29:17 +02:00
|
|
|
suppress_current_changed_ = false;
|
|
|
|
|
|
|
|
if (currentIndex() == index)
|
|
|
|
emit CurrentIdChanged(id);
|
|
|
|
}
|
2010-05-21 12:37:24 +02:00
|
|
|
|
|
|
|
void PlaylistTabBar::TabMoved() {
|
|
|
|
QList<int> ids;
|
|
|
|
for (int i=0 ; i<count() ; ++i) {
|
|
|
|
ids << tabData(i).toInt();
|
|
|
|
}
|
|
|
|
emit PlaylistOrderChanged(ids);
|
|
|
|
}
|
2010-07-17 14:47:59 +02:00
|
|
|
|
|
|
|
void PlaylistTabBar::dragEnterEvent(QDragEnterEvent* e) {
|
|
|
|
if (e->mimeData()->hasUrls() ||
|
|
|
|
e->mimeData()->hasFormat(Playlist::kRowsMimetype) ||
|
2011-02-09 19:48:31 +01:00
|
|
|
qobject_cast<const MimeData*>(e->mimeData())) {
|
2010-07-17 14:47:59 +02:00
|
|
|
e->acceptProposedAction();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::dragMoveEvent(QDragMoveEvent* e) {
|
|
|
|
drag_hover_tab_ = tabAt(e->pos());
|
|
|
|
|
2011-02-09 19:48:31 +01:00
|
|
|
if (drag_hover_tab_ != -1) {
|
2010-07-17 14:47:59 +02:00
|
|
|
e->setDropAction(Qt::CopyAction);
|
|
|
|
e->accept(tabRect(drag_hover_tab_));
|
|
|
|
|
|
|
|
if (!drag_hover_timer_.isActive())
|
|
|
|
drag_hover_timer_.start(kDragHoverTimeout, this);
|
2011-02-09 19:48:31 +01:00
|
|
|
} else {
|
|
|
|
drag_hover_timer_.stop();
|
2010-07-17 14:47:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::dragLeaveEvent(QDragLeaveEvent*) {
|
|
|
|
drag_hover_timer_.stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::timerEvent(QTimerEvent* e) {
|
|
|
|
QTabBar::timerEvent(e);
|
|
|
|
|
|
|
|
if (e->timerId() == drag_hover_timer_.timerId()) {
|
|
|
|
drag_hover_timer_.stop();
|
|
|
|
if (drag_hover_tab_ != -1)
|
|
|
|
setCurrentIndex(drag_hover_tab_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistTabBar::dropEvent(QDropEvent* e) {
|
|
|
|
if (drag_hover_tab_ == -1) {
|
2011-02-16 02:04:48 +01:00
|
|
|
const MimeData *mime_data = qobject_cast<const MimeData*>(e->mimeData());
|
|
|
|
if(mime_data && !mime_data->name_for_new_playlist_.isEmpty()) {
|
|
|
|
manager_->New(mime_data->name_for_new_playlist_);
|
2011-02-15 00:06:36 +01:00
|
|
|
} else {
|
2011-02-16 02:04:48 +01:00
|
|
|
manager_->New(tr("Playlist"));
|
2011-02-15 00:06:36 +01:00
|
|
|
}
|
2011-02-14 18:44:15 +01:00
|
|
|
setCurrentIndex(count() - 1);
|
2011-02-09 19:48:31 +01:00
|
|
|
} else {
|
|
|
|
setCurrentIndex(drag_hover_tab_);
|
2010-07-17 14:47:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
manager_->current()->dropMimeData(e->mimeData(), e->proposedAction(), -1, 0, QModelIndex());
|
|
|
|
}
|
2011-04-13 21:15:30 +02:00
|
|
|
|
|
|
|
bool PlaylistTabBar::event(QEvent* e) {
|
2011-04-15 23:54:19 +02:00
|
|
|
switch (e->type()) {
|
2011-04-13 21:15:30 +02:00
|
|
|
case QEvent::ToolTip: {
|
2011-04-15 23:54:19 +02:00
|
|
|
QHelpEvent *he = static_cast<QHelpEvent*>(e);
|
|
|
|
|
2011-04-13 21:15:30 +02:00
|
|
|
QRect displayed_tab;
|
|
|
|
QSize real_tab;
|
|
|
|
bool is_elided = false;
|
|
|
|
|
|
|
|
real_tab = tabSizeHint(tabAt(he->pos()));
|
|
|
|
displayed_tab = tabRect(tabAt(he->pos()));
|
|
|
|
// Check whether the tab is elided or not
|
|
|
|
is_elided = displayed_tab.width() < real_tab.width();
|
|
|
|
if(!is_elided) {
|
|
|
|
// If it's not elided, don't show the tooltip
|
|
|
|
QToolTip::hideText();
|
|
|
|
} else {
|
|
|
|
QToolTip::showText(he->globalPos(), tabToolTip(tabAt(he->pos())));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return QTabBar::event(e);
|
|
|
|
}
|
|
|
|
}
|