Clementine-audio-player-Mac.../src/devices/deviceproperties.cpp

307 lines
10 KiB
C++

/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
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/>.
*/
#include "deviceproperties.h"
#include <QScrollBar>
#include <QtConcurrentRun>
#include <functional>
#include <memory>
#include "connecteddevice.h"
#include "core/utilities.h"
#include "devicelister.h"
#include "devicemanager.h"
#include "transcoder/transcoder.h"
#include "ui/iconloader.h"
#include "ui_deviceproperties.h"
DeviceProperties::DeviceProperties(QWidget* parent)
: QDialog(parent),
ui_(new Ui_DeviceProperties),
manager_(nullptr),
updating_formats_(false) {
ui_->setupUi(this);
connect(ui_->open_device, SIGNAL(clicked()), SLOT(OpenDevice()));
// Maximum height of the icon widget
ui_->icon->setMaximumHeight(
ui_->icon->iconSize().height() +
ui_->icon->horizontalScrollBar()->sizeHint().height() +
ui_->icon->spacing() * 2 + 5);
}
DeviceProperties::~DeviceProperties() { delete ui_; }
void DeviceProperties::SetDeviceManager(DeviceManager* manager) {
manager_ = manager;
connect(manager_, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
SLOT(ModelChanged()));
connect(manager_, SIGNAL(rowsInserted(QModelIndex, int, int)),
SLOT(ModelChanged()));
connect(manager_, SIGNAL(rowsRemoved(QModelIndex, int, int)),
SLOT(ModelChanged()));
}
void DeviceProperties::ShowDevice(QModelIndex idx) {
if (ui_->icon->count() == 0) {
// Only load the icons the first time the dialog is shown
QStringList icon_names = QStringList()
<< "drive-removable-media-usb-pendrive"
<< "multimedia-player-ipod-mini-blue"
<< "multimedia-player-ipod-mini-gold"
<< "multimedia-player-ipod-mini-green"
<< "multimedia-player-ipod-mini-pink"
<< "multimedia-player-ipod-mini-silver"
<< "multimedia-player-ipod-nano-black"
<< "multimedia-player-ipod-nano-white"
<< "multimedia-player-ipod-nano-green"
<< "multimedia-player-ipod-shuffle"
<< "multimedia-player-ipod-standard-color"
<< "multimedia-player-ipod-standard-monochrome"
<< "multimedia-player-ipod-U2-color"
<< "multimedia-player-ipod-U2-monochrome"
<< "ipodtouchicon"
<< "phone"
<< "phone-google-nexus-one"
<< "phone-htc-g1-white"
<< "phone-nokia-n900"
<< "phone-palm-pre";
for (const QString& icon_name : icon_names) {
QListWidgetItem* item = new QListWidgetItem(
IconLoader::Load(icon_name, IconLoader::Base), QString(), ui_->icon);
item->setData(Qt::UserRole, icon_name);
}
// Load the transcode formats the first time the dialog is shown
for (const TranscoderPreset& preset : Transcoder::GetAllPresets()) {
ui_->transcode_format->addItem(preset.name_, preset.type_);
}
ui_->transcode_format->model()->sort(0);
}
index_ = idx;
// Basic information
ui_->name->setText(index_.data(DeviceManager::Role_FriendlyName).toString());
// Find the right icon
QString icon_name = index_.data(DeviceManager::Role_IconName).toString();
for (int i = 0; i < ui_->icon->count(); ++i) {
if (ui_->icon->item(i)->data(Qt::UserRole).toString() == icon_name) {
ui_->icon->setCurrentRow(i);
break;
}
}
UpdateHardwareInfo();
UpdateFormats();
show();
}
void DeviceProperties::AddHardwareInfo(int row, const QString& key,
const QString& value) {
ui_->hardware_info->setItem(row, 0, new QTableWidgetItem(key));
ui_->hardware_info->setItem(row, 1, new QTableWidgetItem(value));
}
void DeviceProperties::ModelChanged() {
if (!isVisible()) return;
if (!index_.isValid())
reject(); // Device went away
else {
UpdateHardwareInfo();
UpdateFormats();
}
}
void DeviceProperties::UpdateHardwareInfo() {
// Hardware information
QString id = index_.data(DeviceManager::Role_UniqueId).toString();
if (DeviceLister* lister = manager_->GetLister(index_)) {
QVariantMap info = lister->DeviceHardwareInfo(id);
// Remove empty items
for (const QString& key : info.keys()) {
if (info[key].isNull() || info[key].toString().isEmpty())
info.remove(key);
}
ui_->hardware_info_stack->setCurrentWidget(ui_->hardware_info_page);
ui_->hardware_info->clear();
ui_->hardware_info->setRowCount(2 + info.count());
int row = 0;
AddHardwareInfo(row++, tr("Model"), lister->DeviceModel(id));
AddHardwareInfo(row++, tr("Manufacturer"), lister->DeviceManufacturer(id));
for (const QString& key : info.keys()) {
AddHardwareInfo(row++, tr(key.toLatin1()), info[key].toString());
}
ui_->hardware_info->sortItems(0);
} else {
ui_->hardware_info_stack->setCurrentWidget(
ui_->hardware_info_not_connected_page);
}
// Size
quint64 total = index_.data(DeviceManager::Role_Capacity).toLongLong();
QVariant free_var = index_.data(DeviceManager::Role_FreeSpace);
if (free_var.isValid()) {
quint64 free = free_var.toLongLong();
ui_->free_space_bar->set_total_bytes(total);
ui_->free_space_bar->set_free_bytes(free);
ui_->free_space_bar->show();
} else {
ui_->free_space_bar->hide();
}
}
void DeviceProperties::UpdateFormats() {
QString id = index_.data(DeviceManager::Role_UniqueId).toString();
DeviceLister* lister = manager_->GetLister(index_);
std::shared_ptr<ConnectedDevice> device =
manager_->GetConnectedDevice(index_);
// Transcode mode
MusicStorage::TranscodeMode mode = MusicStorage::TranscodeMode(
index_.data(DeviceManager::Role_TranscodeMode).toInt());
switch (mode) {
case MusicStorage::Transcode_Always:
ui_->transcode_all->setChecked(true);
break;
case MusicStorage::Transcode_Never:
ui_->transcode_off->setChecked(true);
break;
case MusicStorage::Transcode_Unsupported:
default:
ui_->transcode_unsupported->setChecked(true);
break;
}
// If there's no lister then the device is physically disconnected
if (!lister) {
ui_->formats_stack->setCurrentWidget(ui_->formats_page_not_connected);
ui_->open_device->setEnabled(false);
return;
}
// If there's a lister but no device then the user just needs to open the
// device. This will cause a rescan so we don't do it automatically.
if (!device) {
ui_->formats_stack->setCurrentWidget(ui_->formats_page_not_connected);
ui_->open_device->setEnabled(true);
return;
}
if (!updating_formats_) {
// Get the device's supported formats list. This takes a long time and it
// blocks, so do it in the background.
supported_formats_.clear();
QFuture<bool> future = QtConcurrent::run(std::bind(
&ConnectedDevice::GetSupportedFiletypes, device, &supported_formats_));
NewClosure(future, this, SLOT(UpdateFormatsFinished(QFuture<bool>)),
future);
ui_->formats_stack->setCurrentWidget(ui_->formats_page_loading);
updating_formats_ = true;
}
}
void DeviceProperties::accept() {
QDialog::accept();
// Transcode mode
MusicStorage::TranscodeMode mode = MusicStorage::Transcode_Unsupported;
if (ui_->transcode_all->isChecked())
mode = MusicStorage::Transcode_Always;
else if (ui_->transcode_off->isChecked())
mode = MusicStorage::Transcode_Never;
else if (ui_->transcode_unsupported->isChecked())
mode = MusicStorage::Transcode_Unsupported;
// Transcode format
Song::FileType format = Song::FileType(
ui_->transcode_format->itemData(ui_->transcode_format->currentIndex())
.toInt());
// By default no icon is selected and thus no current item is selected
QString icon_name;
if (ui_->icon->currentItem() != nullptr) {
icon_name = ui_->icon->currentItem()->data(Qt::UserRole).toString();
}
manager_->SetDeviceOptions(index_, ui_->name->text(), icon_name, mode,
format);
}
void DeviceProperties::OpenDevice() { manager_->Connect(index_); }
void DeviceProperties::UpdateFormatsFinished(QFuture<bool> future) {
updating_formats_ = false;
// Check if the device was disconnected while the thread was running. In that
// case, ModelChanged would be called and the not connected page would be
// shown.
if (!manager_->IsConnected(index_)) {
return;
}
if (!future.result()) {
supported_formats_.clear();
}
// Hide widgets if there are no supported types
ui_->supported_formats_container->setVisible(!supported_formats_.isEmpty());
ui_->transcode_unsupported->setEnabled(!supported_formats_.isEmpty());
if (ui_->transcode_unsupported->isChecked() && supported_formats_.isEmpty()) {
ui_->transcode_off->setChecked(true);
}
// Populate supported types list
ui_->supported_formats->clear();
for (Song::FileType type : supported_formats_) {
QListWidgetItem* item = new QListWidgetItem(Song::TextForFiletype(type));
ui_->supported_formats->addItem(item);
}
ui_->supported_formats->sortItems();
// Set the format combobox item
TranscoderPreset preset = Transcoder::PresetForFileType(
Song::FileType(index_.data(DeviceManager::Role_TranscodeFormat).toInt()));
if (preset.type_ == Song::Type_Unknown) {
// The user hasn't chosen a format for this device yet, so work our way down
// a list of some preferred formats, picking the first one that is supported
preset = Transcoder::PresetForFileType(
Transcoder::PickBestFormat(supported_formats_));
}
ui_->transcode_format->setCurrentIndex(
ui_->transcode_format->findText(preset.name_));
ui_->formats_stack->setCurrentWidget(ui_->formats_page);
}