diff --git a/src/dvb/dvbchanneldialog.cpp b/src/dvb/dvbchanneldialog.cpp index d6abe26..d6b736e 100644 --- a/src/dvb/dvbchanneldialog.cpp +++ b/src/dvb/dvbchanneldialog.cpp @@ -1,1040 +1,1059 @@ /* * dvbchanneldialog.cpp * * Copyright (C) 2007-2011 Christoph Pfister * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "../log.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dvbchanneldialog.h" #include "dvbchanneldialog_p.h" #include "dvbsi.h" #include "../iso-codes.h" bool DvbChannelLessThan::operator()(const DvbSharedChannel &x, const DvbSharedChannel &y) const { switch (sortOrder) { case ChannelNameAscending: if (x->name != y->name) { return (x->name.localeAwareCompare(y->name) < 0); } break; case ChannelNameDescending: if (x->name != y->name) { return (x->name.localeAwareCompare(y->name) > 0); } break; case ChannelNumberAscending: if (x->number != y->number) { return (x->number < y->number); } break; case ChannelNumberDescending: if (x->number != y->number) { return (x->number > y->number); } break; } return (x < y); } DvbChannelTableModel::DvbChannelTableModel(QObject *parent) : TableModel(parent), channelModel(NULL), dndInsertBeforeNumber(-1), dndEventPosted(false) { } DvbChannelTableModel::~DvbChannelTableModel() { } void DvbChannelTableModel::setChannelModel(DvbChannelModel *channelModel_) { if (channelModel != NULL) { qCWarning(logDvb, "Channel model already set"); return; } channelModel = channelModel_; connect(channelModel, SIGNAL(channelAdded(DvbSharedChannel)), this, SLOT(channelAdded(DvbSharedChannel))); connect(channelModel, SIGNAL(channelAboutToBeUpdated(DvbSharedChannel)), this, SLOT(channelAboutToBeUpdated(DvbSharedChannel))); connect(channelModel, SIGNAL(channelUpdated(DvbSharedChannel)), this, SLOT(channelUpdated(DvbSharedChannel))); connect(channelModel, SIGNAL(channelRemoved(DvbSharedChannel)), this, SLOT(channelRemoved(DvbSharedChannel))); reset(channelModel->getChannels()); } QVariant DvbChannelTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole)) { switch (section) { case 0: return i18nc("@title:column tv show", "Channel"); case 1: return i18nc("@title:column tv channel", "Number"); } } return QVariant(); } QVariant DvbChannelTableModel::data(const QModelIndex &index, int role) const { const DvbSharedChannel &channel = value(index); if (channel.isValid()) { switch (role) { case Qt::DecorationRole: if (index.column() == 0) { if (channel->hasVideo) { if (!channel->isScrambled) { return QIcon::fromTheme(QLatin1String("video-television"), QIcon(":video-television")); } else { return QIcon::fromTheme(QLatin1String("video-television-encrypted"), QIcon(":video-television-encrypted")); } } else { if (!channel->isScrambled) { return QIcon::fromTheme(QLatin1String("text-speak"), QIcon(":text-speak")); } else { return QIcon::fromTheme(QLatin1String("audio-radio-encrypted"), QIcon(":audio-radio-encrypted")); } } } break; case Qt::DisplayRole: switch (index.column()) { case 0: return channel->name; case 1: return channel->number; } break; } } return QVariant(); } void DvbChannelTableModel::sort(int column, Qt::SortOrder order) { DvbChannelLessThan::SortOrder sortOrder; if (order == Qt::AscendingOrder) { if (column == 0) { sortOrder = DvbChannelLessThan::ChannelNameAscending; } else { sortOrder = DvbChannelLessThan::ChannelNumberAscending; } } else { if (column == 0) { sortOrder = DvbChannelLessThan::ChannelNameDescending; } else { sortOrder = DvbChannelLessThan::ChannelNumberDescending; } } internalSort(sortOrder); } Qt::ItemFlags DvbChannelTableModel::flags(const QModelIndex &index) const { if (index.isValid()) { return (QAbstractTableModel::flags(index) | Qt::ItemIsDragEnabled); } else { return (QAbstractTableModel::flags(index) | Qt::ItemIsDropEnabled); } } QMimeData *DvbChannelTableModel::mimeData(const QModelIndexList &indexes) const { QList selectedChannels; foreach (const QModelIndex &index, indexes) { if (index.column() == 0) { selectedChannels.append(value(index)); } } QMimeData *mimeData = new QMimeData(); mimeData->setData(QLatin1String("application/x-org.kde.kaffeine-selectedchannels"), QByteArray()); // this way the list will be properly deleted once drag and drop ends mimeData->setProperty("SelectedChannels", QVariant::fromValue(selectedChannels)); return mimeData; } QStringList DvbChannelTableModel::mimeTypes() const { return QStringList(QLatin1String("application/x-org.kde.kaffeine-selectedchannels")); } Qt::DropActions DvbChannelTableModel::supportedDropActions() const { return Qt::MoveAction; } bool DvbChannelTableModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(column) Q_UNUSED(parent) dndSelectedChannels.clear(); dndInsertBeforeNumber = -1; if (action == Qt::MoveAction) { dndSelectedChannels = data->property("SelectedChannels").value >(); const DvbSharedChannel &dndInsertBeforeChannel = value(row); if (dndInsertBeforeChannel.isValid()) { dndInsertBeforeNumber = dndInsertBeforeChannel->number; } if (!dndSelectedChannels.isEmpty() && !dndEventPosted) { dndEventPosted = true; QCoreApplication::postEvent(this, new QEvent(QEvent::User)); } } return false; } void DvbChannelTableModel::setFilter(const QString &filter) { // Qt::CaseSensitive == no filtering helper.filter.setCaseSensitivity( filter.isEmpty() ? Qt::CaseSensitive : Qt::CaseInsensitive); helper.filter.setPattern(filter); reset(channelModel->getChannels()); } void DvbChannelTableModel::channelAdded(const DvbSharedChannel &channel) { insert(channel); } void DvbChannelTableModel::channelAboutToBeUpdated(const DvbSharedChannel &channel) { aboutToUpdate(channel); } void DvbChannelTableModel::channelUpdated(const DvbSharedChannel &channel) { update(channel); } void DvbChannelTableModel::channelRemoved(const DvbSharedChannel &channel) { remove(channel); } void DvbChannelTableModel::customEvent(QEvent *event) { Q_UNUSED(event) bool ok = true; emit checkChannelDragAndDrop(&ok); if (ok && !dndSelectedChannels.isEmpty()) { channelModel->dndMoveChannels(dndSelectedChannels, dndInsertBeforeNumber); } dndSelectedChannels.clear(); dndEventPosted = false; } DvbChannelView::DvbChannelView(QWidget *parent) : QTreeView(parent), tableModel(NULL) { } DvbChannelView::~DvbChannelView() { } QAction *DvbChannelView::addEditAction() { QAction *action = new QAction(QIcon::fromTheme(QLatin1String("configure"), QIcon(":configure")), i18nc("@action", "Edit"), this); connect(action, SIGNAL(triggered()), this, SLOT(editChannel())); addAction(action); return action; } QAction *DvbChannelView::addRemoveAction() { QAction *action = new QAction(QIcon::fromTheme(QLatin1String("edit-delete"), QIcon(":edit-delete")), i18nc("@action", "Remove"), this); connect(action, SIGNAL(triggered()), this, SLOT(removeChannel())); addAction(action); return action; } void DvbChannelView::setModel(DvbChannelTableModel *tableModel_) { tableModel = tableModel_; QTreeView::setModel(tableModel); } void DvbChannelView::checkChannelDragAndDrop(bool *ok) { if ((*ok) && ((header()->sortIndicatorSection() != 1) || (header()->sortIndicatorOrder() != Qt::AscendingOrder))) { if (KMessageBox::warningContinueCancel(this, i18nc("@info", "The channels will be sorted by number to allow drag and drop.\n" "Do you want to continue?")) == KMessageBox::Continue) { sortByColumn(1, Qt::AscendingOrder); } else { *ok = false; } } } +void DvbChannelView::channelPidsChanged(const DvbSharedChannel &channel) +{ + emit channelPidsUpdated(channel); +} + void DvbChannelView::editChannel() { QModelIndex index = currentIndex(); if (index.isValid()) { QDialog *dialog = new DvbChannelEditor(tableModel, tableModel->value(index), this); dialog->setAttribute(Qt::WA_DeleteOnClose, true); dialog->setModal(true); + connect(dialog, SIGNAL(channelPidsChanged(DvbSharedChannel)), + this, SLOT(channelPidsChanged(DvbSharedChannel))); dialog->show(); } } void DvbChannelView::removeChannel() { QList selectedChannels; foreach (const QModelIndex &index, selectionModel()->selectedIndexes()) { if (index.column() == 0) { selectedChannels.append(tableModel->value(index)); } } DvbChannelModel *channelModel = tableModel->getChannelModel(); foreach (const DvbSharedChannel &channel, selectedChannels) { channelModel->removeChannel(channel); } } void DvbChannelView::removeAllChannels() { DvbChannelModel *channelModel = tableModel->getChannelModel(); foreach (const DvbSharedChannel &channel, channelModel->getChannels().values()) { channelModel->removeChannel(channel); } } static QLatin1String enumToString(DvbTransponderBase::FecRate fecRate) { const char *text = ""; switch (fecRate) { case DvbTransponderBase::FecNone: text = "NONE"; break; case DvbTransponderBase::Fec1_2: text = "1/2"; break; case DvbTransponderBase::Fec1_3: text = "1/3"; break; case DvbTransponderBase::Fec1_4: text = "1/4"; break; case DvbTransponderBase::Fec2_3: text = "2/3"; break; case DvbTransponderBase::Fec2_5: text = "2/5"; break; case DvbTransponderBase::Fec3_4: text = "3/4"; break; case DvbTransponderBase::Fec3_5: text = "3/5"; break; case DvbTransponderBase::Fec4_5: text = "4/5"; break; case DvbTransponderBase::Fec5_6: text = "5/6"; break; case DvbTransponderBase::Fec6_7: text = "6/7"; break; case DvbTransponderBase::Fec7_8: text = "7/8"; break; case DvbTransponderBase::Fec8_9: text = "8/9"; break; case DvbTransponderBase::Fec9_10: text = "9/10"; break; case DvbTransponderBase::FecAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbCTransponder::Modulation modulation) { const char *text = ""; switch (modulation) { case DvbCTransponder::Qam16: text = "16-QAM"; break; case DvbCTransponder::Qam32: text = "32-QAM"; break; case DvbCTransponder::Qam64: text = "64-QAM"; break; case DvbCTransponder::Qam128: text = "128-QAM"; break; case DvbCTransponder::Qam256: text = "256-QAM"; break; case DvbCTransponder::ModulationAuto: text = "AUTO"; break; } return QLatin1String(text); } static QString enumToString(DvbSTransponder::Polarization polarization) { switch (polarization) { case DvbSTransponder::Horizontal: return i18n("Horizontal"); case DvbSTransponder::Vertical: return i18n("Vertical"); case DvbSTransponder::CircularLeft: return i18n("Circular left"); case DvbSTransponder::CircularRight: return i18n("Circular right"); case DvbSTransponder::Off: return i18n("Off"); } return QString(); } static QLatin1String enumToString(DvbS2Transponder::Modulation modulation) { const char *text = ""; switch (modulation) { case DvbS2Transponder::Qpsk: text = "QPSK"; break; case DvbS2Transponder::Psk8: text = "8-PSK"; break; case DvbS2Transponder::Apsk16: text = "16-APSK"; break; case DvbS2Transponder::Apsk32: text = "32-APSK"; break; case DvbS2Transponder::ModulationAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbS2Transponder::RollOff rollOff) { const char *text = ""; switch (rollOff) { case DvbS2Transponder::RollOff20: text = "0.20"; break; case DvbS2Transponder::RollOff25: text = "0.25"; break; case DvbS2Transponder::RollOff35: text = "0.35"; break; case DvbS2Transponder::RollOffAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbTTransponder::Bandwidth bandwidth) { const char *text = ""; switch (bandwidth) { case DvbTTransponder::Bandwidth5MHz: text = "5MHz"; break; case DvbTTransponder::Bandwidth6MHz: text = "6MHz"; break; case DvbTTransponder::Bandwidth7MHz: text = "7MHz"; break; case DvbTTransponder::Bandwidth8MHz: text = "8MHz"; break; case DvbTTransponder::BandwidthAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbT2Transponder::Bandwidth bandwidth) { const char *text = ""; switch (bandwidth) { case DvbT2Transponder::Bandwidth1_7MHz: text = "1.7MHz"; break; case DvbT2Transponder::Bandwidth5MHz: text = "5MHz"; break; case DvbT2Transponder::Bandwidth6MHz: text = "6MHz"; break; case DvbT2Transponder::Bandwidth7MHz: text = "7MHz"; break; case DvbT2Transponder::Bandwidth8MHz: text = "8MHz"; break; case DvbT2Transponder::Bandwidth10MHz: text = "10MHz"; break; case DvbT2Transponder::BandwidthAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbTTransponder::Modulation modulation) { const char *text = ""; switch (modulation) { case DvbTTransponder::Qpsk: text = "QPSK"; break; case DvbTTransponder::Qam16: text = "16-QAM"; break; case DvbTTransponder::Qam64: text = "64-QAM"; break; case DvbTTransponder::ModulationAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbT2Transponder::Modulation modulation) { const char *text = ""; switch (modulation) { case DvbT2Transponder::Qpsk: text = "QPSK"; break; case DvbT2Transponder::Qam16: text = "16-QAM"; break; case DvbT2Transponder::Qam64: text = "64-QAM"; break; case DvbT2Transponder::Qam256: text = "256-QAM"; break; case DvbT2Transponder::ModulationAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbTTransponder::TransmissionMode transmissionMode) { const char *text = ""; switch (transmissionMode) { case DvbTTransponder::TransmissionMode2k: text = "2k"; break; case DvbTTransponder::TransmissionMode4k: text = "4k"; break; case DvbTTransponder::TransmissionMode8k: text = "8k"; break; case DvbTTransponder::TransmissionModeAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbT2Transponder::TransmissionMode transmissionMode) { const char *text = ""; switch (transmissionMode) { case DvbT2Transponder::TransmissionMode1k: text = "1k"; break; case DvbT2Transponder::TransmissionMode2k: text = "2k"; break; case DvbT2Transponder::TransmissionMode4k: text = "4k"; break; case DvbT2Transponder::TransmissionMode8k: text = "8k"; break; case DvbT2Transponder::TransmissionMode16k: text = "16k"; break; case DvbT2Transponder::TransmissionMode32k: text = "32k"; break; case DvbT2Transponder::TransmissionModeAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(IsdbTTransponder::TransmissionMode transmissionMode) { const char *text = ""; switch (transmissionMode) { case IsdbTTransponder::TransmissionMode2k: text = "2k"; break; case IsdbTTransponder::TransmissionMode4k: text = "4k"; break; case IsdbTTransponder::TransmissionMode8k: text = "8k"; break; case IsdbTTransponder::TransmissionModeAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbTTransponder::GuardInterval guardInterval) { const char *text = ""; switch (guardInterval) { case DvbTTransponder::GuardInterval1_4: text = "1/4"; break; case DvbTTransponder::GuardInterval1_8: text = "1/8"; break; case DvbTTransponder::GuardInterval1_16: text = "1/16"; break; case DvbTTransponder::GuardInterval1_32: text = "1/32"; break; case DvbTTransponder::GuardIntervalAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbT2Transponder::GuardInterval guardInterval) { const char *text = ""; switch (guardInterval) { case DvbT2Transponder::GuardInterval1_4: text = "1/4"; break; case DvbT2Transponder::GuardInterval19_128: text = "19/128"; break; case DvbT2Transponder::GuardInterval1_8: text = "1/8"; break; case DvbT2Transponder::GuardInterval19_256: text = "19/256"; break; case DvbT2Transponder::GuardInterval1_16: text = "1/16"; break; case DvbT2Transponder::GuardInterval1_32: text = "1/32"; break; case DvbT2Transponder::GuardInterval1_128: text = "1/128"; break; case DvbT2Transponder::GuardIntervalAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbTTransponder::Hierarchy hierarchy) { const char *text = ""; switch (hierarchy) { case DvbTTransponder::HierarchyNone: text = "NONE"; break; case DvbTTransponder::Hierarchy1: text = "1"; break; case DvbTTransponder::Hierarchy2: text = "2"; break; case DvbTTransponder::Hierarchy4: text = "4"; break; case DvbTTransponder::HierarchyAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(DvbT2Transponder::Hierarchy hierarchy) { const char *text = ""; switch (hierarchy) { case DvbT2Transponder::HierarchyNone: text = "NONE"; break; case DvbT2Transponder::Hierarchy1: text = "1"; break; case DvbT2Transponder::Hierarchy2: text = "2"; break; case DvbT2Transponder::Hierarchy4: text = "4"; break; case DvbT2Transponder::HierarchyAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(AtscTransponder::Modulation modulation) { const char *text = ""; switch (modulation) { case AtscTransponder::Qam64: text = "64-QAM"; break; case AtscTransponder::Qam256: text = "256-QAM"; break; case AtscTransponder::Vsb8: text = "8-VSB"; break; case AtscTransponder::Vsb16: text = "16-VSB"; break; case AtscTransponder::ModulationAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(IsdbTTransponder::Bandwidth bandwidth) { const char *text = ""; switch (bandwidth) { case IsdbTTransponder::Bandwidth6MHz: text = "6MHz"; break; case IsdbTTransponder::Bandwidth7MHz: text = "7MHz"; break; case IsdbTTransponder::Bandwidth8MHz: text = "8MHz"; break; } return QLatin1String(text); } static QLatin1String enumToString(IsdbTTransponder::Modulation modulation) { const char *text = ""; switch (modulation) { case IsdbTTransponder::Dqpsk: text = "DQPSK"; break; case IsdbTTransponder::Qpsk: text = "QPSK"; break; case IsdbTTransponder::Qam16: text = "16-QAM"; break; case IsdbTTransponder::Qam64: text = "64-QAM"; break; case IsdbTTransponder::ModulationAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(IsdbTTransponder::GuardInterval guardInterval) { const char *text = ""; switch (guardInterval) { case IsdbTTransponder::GuardInterval1_4: text = "1/4"; break; case IsdbTTransponder::GuardInterval1_8: text = "1/8"; break; case IsdbTTransponder::GuardInterval1_16: text = "1/16"; break; case IsdbTTransponder::GuardInterval1_32: text = "1/32"; break; case IsdbTTransponder::GuardIntervalAuto: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(IsdbTTransponder::PartialReception partialReception) { const char *text = ""; switch (partialReception) { case IsdbTTransponder::PR_disabled: text = "No"; break; case IsdbTTransponder::PR_enabled: text = "Yes"; break; case IsdbTTransponder::PR_AUTO: text = "AUTO"; break; } return QLatin1String(text); } static QLatin1String enumToString(IsdbTTransponder::SoundBroadcasting soundBroadcasting) { const char *text = ""; switch (soundBroadcasting) { case IsdbTTransponder::SB_disabled: text = "No"; break; case IsdbTTransponder::SB_enabled: text = "Yes"; break; case IsdbTTransponder::SB_AUTO: text = "AUTO"; break; } return QLatin1String(text); } DvbChannelEditor::DvbChannelEditor(DvbChannelTableModel *model_, const DvbSharedChannel &channel_, QWidget *parent) : QDialog(parent), model(model_), channel(channel_) { setWindowTitle(i18nc("@title:window", "Edit Channel")); QWidget *widget = new QWidget(this); QBoxLayout *mainLayout = new QVBoxLayout(widget); QGridLayout *gridLayout = new QGridLayout(); audioStreamBox = NULL; nameEdit = new QLineEdit(widget); nameEdit->setText(channel->name); gridLayout->addWidget(nameEdit, 0, 1); QLabel *label = new QLabel(i18nc("@label tv channel", "Name:"), widget); label->setBuddy(nameEdit); gridLayout->addWidget(label, 0, 0); numberBox = new QSpinBox(widget); numberBox->setRange(1, 99999); numberBox->setValue(channel->number); gridLayout->addWidget(numberBox, 0, 3); label = new QLabel(i18nc("@label tv channel", "Number:"), widget); label->setBuddy(numberBox); gridLayout->addWidget(label, 0, 2); mainLayout->addLayout(gridLayout); QBoxLayout *boxLayout = new QHBoxLayout(); QGroupBox *groupBox = new QGroupBox(widget); gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(new QLabel(i18nc("@label tv channel", "Source:")), 0, 0); gridLayout->addWidget(new QLabel(channel->source), 0, 1); int row = 11; switch (channel->transponder.getTransmissionType()) { case DvbTransponderBase::Invalid: break; case DvbTransponderBase::DvbC: { const DvbCTransponder *tp = channel->transponder.as(); gridLayout->addWidget(new QLabel(i18n("Frequency (MHz):")), 1, 0); gridLayout->addWidget( new QLabel(QString::number(tp->frequency / 1000000.0)), 1, 1); gridLayout->addWidget(new QLabel(i18n("Symbol rate (kS/s):")), 2, 0); gridLayout->addWidget(new QLabel(QString::number(tp->symbolRate / 1000.0)), 2, 1); gridLayout->addWidget(new QLabel(i18n("Modulation:")), 3, 0); gridLayout->addWidget(new QLabel(enumToString(tp->modulation)), 3, 1); gridLayout->addWidget(new QLabel(i18n("FEC rate:")), 4, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRate)), 4, 1); break; } case DvbTransponderBase::DvbS: case DvbTransponderBase::DvbS2: { const DvbS2Transponder *tp2 = channel->transponder.as(); const DvbSTransponder *tp = channel->transponder.as(); if (tp == NULL) { tp = tp2; } gridLayout->addWidget(new QLabel(i18n("Polarization:")), 1, 0); gridLayout->addWidget(new QLabel(enumToString(tp->polarization)), 1, 1); gridLayout->addWidget(new QLabel(i18n("Frequency (MHz):")), 2, 0); gridLayout->addWidget(new QLabel(QString::number(tp->frequency / 1000.0)), 2, 1); gridLayout->addWidget(new QLabel(i18n("Symbol rate (kS/s):")), 3, 0); gridLayout->addWidget(new QLabel(QString::number(tp->symbolRate / 1000.0)), 3, 1); gridLayout->addWidget(new QLabel(i18n("FEC rate:")), 4, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRate)), 4, 1); if (tp2 != NULL) { gridLayout->addWidget(new QLabel(i18n("Modulation:")), 5, 0); gridLayout->addWidget(new QLabel(enumToString(tp2->modulation)), 5, 1); gridLayout->addWidget(new QLabel(i18n("Roll-off:")), 6, 0); gridLayout->addWidget(new QLabel(enumToString(tp2->rollOff)), 6, 1); } break; } case DvbTransponderBase::DvbT: { const DvbTTransponder *tp = channel->transponder.as(); gridLayout->addWidget(new QLabel(i18n("Frequency (MHz):")), 1, 0); gridLayout->addWidget( new QLabel(QString::number(tp->frequency / 1000000.0)), 1, 1); gridLayout->addWidget(new QLabel(i18n("Bandwidth:")), 2, 0); gridLayout->addWidget(new QLabel(enumToString(tp->bandwidth)), 2, 1); gridLayout->addWidget(new QLabel(i18n("Modulation:")), 3, 0); gridLayout->addWidget(new QLabel(enumToString(tp->modulation)), 3, 1); gridLayout->addWidget(new QLabel(i18n("FEC rate:")), 4, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRateHigh)), 4, 1); gridLayout->addWidget(new QLabel(i18n("FEC rate LP:")), 5, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRateLow)), 5, 1); gridLayout->addWidget(new QLabel(i18n("Transmission mode:")), 6, 0); gridLayout->addWidget(new QLabel(enumToString(tp->transmissionMode)), 6, 1); gridLayout->addWidget(new QLabel(i18n("Guard interval:")), 7, 0); gridLayout->addWidget(new QLabel(enumToString(tp->guardInterval)), 7, 1); gridLayout->addWidget(new QLabel(i18n("Hierarchy:")), 8, 0); gridLayout->addWidget(new QLabel(enumToString(tp->hierarchy)), 8, 1); break; } case DvbTransponderBase::DvbT2: { const DvbT2Transponder *tp = channel->transponder.as(); gridLayout->addWidget(new QLabel(i18n("Frequency (MHz):")), 1, 0); gridLayout->addWidget( new QLabel(QString::number(tp->frequency / 1000000.0)), 1, 1); gridLayout->addWidget(new QLabel(i18n("Bandwidth:")), 2, 0); gridLayout->addWidget(new QLabel(enumToString(tp->bandwidth)), 2, 1); gridLayout->addWidget(new QLabel(i18n("Modulation:")), 3, 0); gridLayout->addWidget(new QLabel(enumToString(tp->modulation)), 3, 1); gridLayout->addWidget(new QLabel(i18n("FEC rate:")), 4, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRateHigh)), 4, 1); gridLayout->addWidget(new QLabel(i18n("FEC rate LP:")), 5, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRateLow)), 5, 1); gridLayout->addWidget(new QLabel(i18n("Transmission mode:")), 6, 0); gridLayout->addWidget(new QLabel(enumToString(tp->transmissionMode)), 6, 1); gridLayout->addWidget(new QLabel(i18n("Guard interval:")), 7, 0); gridLayout->addWidget(new QLabel(enumToString(tp->guardInterval)), 7, 1); gridLayout->addWidget(new QLabel(i18n("Hierarchy:")), 8, 0); gridLayout->addWidget(new QLabel(enumToString(tp->hierarchy)), 8, 1); gridLayout->addWidget(new QLabel(i18n("PLP (stream ID):")), 9, 0); gridLayout->addWidget( new QLabel(QString::number(tp->streamId)), 9, 1); break; } case DvbTransponderBase::IsdbT: { const IsdbTTransponder *tp = channel->transponder.as(); row= 1; gridLayout->addWidget(new QLabel(i18n("Frequency (MHz):")), row, 0); gridLayout->addWidget( new QLabel(QString::number(tp->frequency / 1000000.0)), row++, 1); gridLayout->addWidget(new QLabel(i18n("Bandwidth:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->bandwidth)), row++, 1); gridLayout->addWidget(new QLabel(i18n("Transmission mode:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->transmissionMode)), row++, 1); gridLayout->addWidget(new QLabel(i18n("Guard interval:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->guardInterval)), row++, 1); gridLayout->addWidget(new QLabel(i18n("Partial reception:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->partialReception)), row++, 1); gridLayout->addWidget(new QLabel(i18n("Sound broadcasting:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->soundBroadcasting)), row++, 1); if (tp->soundBroadcasting == 1) { gridLayout->addWidget(new QLabel(i18n("SB channel ID:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->subChannelId)), row++, 1); gridLayout->addWidget(new QLabel(i18n("SB index:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->subChannelId)), row++, 1); gridLayout->addWidget(new QLabel(i18n("SB count:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->sbSegmentCount)), row++, 1); } if (tp->layerEnabled[0]) { gridLayout->addWidget(new QLabel(i18n("Layer A Modulation:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->modulation[0])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer A FEC rate:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRate[0])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer A segments:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->segmentCount[0])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer A interleaving:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->interleaving[0])), row++, 1); } if (tp->layerEnabled[1]) { gridLayout->addWidget(new QLabel(i18n("Layer B Modulation:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->modulation[1])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer B FEC rate:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRate[1])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer B segments:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->segmentCount[1])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer B interleaving:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->interleaving[1])), row++, 1); } if (tp->layerEnabled[2]) { gridLayout->addWidget(new QLabel(i18n("Layer C Modulation:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->modulation[2])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer C FEC rate:")), row, 0); gridLayout->addWidget(new QLabel(enumToString(tp->fecRate[2])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer C segments:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->segmentCount[2])), row++, 1); gridLayout->addWidget(new QLabel(i18n("Layer C interleaving:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(tp->interleaving[2])), row++, 1); } break; } case DvbTransponderBase::Atsc: { const AtscTransponder *tp = channel->transponder.as(); gridLayout->addWidget(new QLabel(i18n("Frequency (MHz):")), 1, 0); gridLayout->addWidget( new QLabel(QString::number(tp->frequency / 1000000.0)), 1, 1); gridLayout->addWidget(new QLabel(i18n("Modulation:")), 2, 0); gridLayout->addWidget(new QLabel(enumToString(tp->modulation)), 2, 1); break; } } gridLayout->addWidget(new QLabel(), 10, 0, 1, 2); gridLayout->addItem(new QSpacerItem(0, 0), row, 0, 1, 2); gridLayout->setRowStretch(row, 1); boxLayout->addWidget(groupBox); groupBox = new QGroupBox(widget); gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(new QLabel(i18n("Network ID:")), 0, 0); row = 1; networkIdBox = new QSpinBox(groupBox); networkIdBox->setRange(-1, (1 << 16) - 1); networkIdBox->setValue(channel->networkId); gridLayout->addWidget(networkIdBox, 0, 1); gridLayout->addWidget(new QLabel(i18n("Transport stream ID:")), row, 0); transportStreamIdBox = new QSpinBox(groupBox); transportStreamIdBox->setRange(0, (1 << 16) - 1); transportStreamIdBox->setValue(channel->transportStreamId); gridLayout->addWidget(transportStreamIdBox, row++, 1); gridLayout->addWidget(new QLabel(i18n("Service ID:")), row, 0); serviceIdBox = new QSpinBox(groupBox); serviceIdBox->setRange(0, (1 << 16) - 1); serviceIdBox->setValue(channel->serviceId); gridLayout->addWidget(serviceIdBox, row++, 1); DvbPmtSection pmtSection(channel->pmtSectionData); DvbPmtParser pmtParser(pmtSection); gridLayout->addWidget(new QLabel(i18n("Audio channel:")), row, 0); if (pmtParser.audioPids.count() > 1) { audioStreamBox = new QComboBox(groupBox); for (int i = 0; i < pmtParser.audioPids.size(); ++i) { const QPair &it = pmtParser.audioPids.at(i); QString text = QString::number(it.first); if (!it.second.isEmpty()) { QString languageString; if (!IsoCodes::getLanguage(it.second, &languageString)) languageString = it.second; text = text + QLatin1String(" (") + languageString + QLatin1Char(')'); } audioStreamBox->addItem(text); audioPids.append(it.first); } audioStreamBox->setCurrentIndex(audioPids.indexOf(channel->audioPid)); gridLayout->addWidget(audioStreamBox, row++, 1); } else { const QPair &it = pmtParser.audioPids.at(0); QString text = QString::number(it.first); if (!it.second.isEmpty()) { QString languageString; if (!IsoCodes::getLanguage(it.second, &languageString)) languageString = it.second; text = text + QLatin1String(" (") + languageString + QLatin1Char(')'); } gridLayout->addWidget(new QLabel(text), row++, 1); } gridLayout->addWidget(new QLabel(i18n("Scrambled:")), row, 0); scrambledBox = new QCheckBox(groupBox); scrambledBox->setChecked(channel->isScrambled); gridLayout->addWidget(scrambledBox, row++, 1); row++; gridLayout->addWidget(new QLabel(i18n("PMT PID:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(channel->pmtPid)), row++, 1); if (pmtParser.videoPid >= 0) { gridLayout->addWidget(new QLabel(i18n("Video PID:")), row, 0); gridLayout->addWidget(new QLabel(QString::number(pmtParser.videoPid)), row++, 1); } if (!pmtParser.subtitlePids.isEmpty()) { gridLayout->addWidget(new QLabel(i18n("Subtitle PID:")), row, 0); } for (int i = 0; i < pmtParser.subtitlePids.size(); ++i) { const QPair &it = pmtParser.subtitlePids.at(i); QString languageString; if (!IsoCodes::getLanguage(it.second, &languageString)) languageString = it.second; gridLayout->addWidget(new QLabel(QString(QLatin1String("%1 (%2)")).arg(it.first).arg(languageString)), row++, 1); } if (pmtParser.teletextPid != -1) { gridLayout->addWidget(new QLabel(i18n("Teletext PID:")), row, 0); gridLayout->addWidget( new QLabel(QString::number(pmtParser.teletextPid)), row++, 1); } gridLayout->addItem(new QSpacerItem(0, 0), 5, 0, 1, 2); gridLayout->setRowStretch(5, 1); boxLayout->addWidget(groupBox); mainLayout->addLayout(boxLayout); mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(widget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); } DvbChannelEditor::~DvbChannelEditor() { } void DvbChannelEditor::accept() { DvbChannel updatedChannel = *channel; + int oldAudioPid = channel->audioPid; + updatedChannel.name = nameEdit->text(); updatedChannel.number = numberBox->value(); updatedChannel.networkId = networkIdBox->value(); updatedChannel.transportStreamId = transportStreamIdBox->value(); updatedChannel.serviceId = serviceIdBox->value(); if (audioStreamBox && audioStreamBox->currentIndex() != -1) { updatedChannel.audioPid = audioPids.at(audioStreamBox->currentIndex()); } updatedChannel.isScrambled = scrambledBox->isChecked(); model->getChannelModel()->updateChannel(channel, updatedChannel); + + /* + * If a channel is being played, a change at a PID should + * be reflected at the played channel. + * + * TODO: add support for videos with multiple PIDs + */ + if (updatedChannel.audioPid != oldAudioPid) + emit channelPidsChanged(channel); + QDialog::accept(); } diff --git a/src/dvb/dvbchanneldialog.h b/src/dvb/dvbchanneldialog.h index 5b08c19..4687a01 100644 --- a/src/dvb/dvbchanneldialog.h +++ b/src/dvb/dvbchanneldialog.h @@ -1,156 +1,162 @@ /* * dvbchanneldialog.h * * Copyright (C) 2007-2011 Christoph Pfister * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef DVBCHANNELDIALOG_H #define DVBCHANNELDIALOG_H #include #include "../tablemodel.h" #include "dvbchannel.h" class QAction; class DvbChannelLessThan { public: DvbChannelLessThan() : sortOrder(ChannelNameAscending) { } ~DvbChannelLessThan() { } enum SortOrder { ChannelNameAscending, ChannelNameDescending, ChannelNumberAscending, ChannelNumberDescending }; SortOrder getSortOrder() const { return sortOrder; } void setSortOrder(SortOrder sortOrder_) { sortOrder = sortOrder_; } bool operator()(const DvbSharedChannel &x, const DvbSharedChannel &y) const; private: SortOrder sortOrder; }; class DvbChannelTableModelHelper { public: DvbChannelTableModelHelper() { } ~DvbChannelTableModelHelper() { } typedef DvbSharedChannel ItemType; typedef DvbChannelLessThan LessThanType; int columnCount() const { return 2; } bool filterAcceptsItem(const DvbSharedChannel &channel) const { // Qt::CaseSensitive == no filtering return ((filter.caseSensitivity() == Qt::CaseSensitive) || (filter.indexIn(channel->name) >= 0)); } QStringMatcher filter; private: Q_DISABLE_COPY(DvbChannelTableModelHelper) }; class DvbChannelTableModel : public TableModel { Q_OBJECT public: explicit DvbChannelTableModel(QObject *parent); ~DvbChannelTableModel(); void setChannelModel(DvbChannelModel *channelModel_); DvbChannelModel *getChannelModel() const { return channelModel; } QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant data(const QModelIndex &index, int role) const; void sort(int column, Qt::SortOrder order); Qt::ItemFlags flags(const QModelIndex &index) const; QMimeData *mimeData(const QModelIndexList &indexes) const; QStringList mimeTypes() const; Qt::DropActions supportedDropActions() const; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); public slots: void setFilter(const QString &filter); signals: void checkChannelDragAndDrop(bool *ok); private slots: void channelAdded(const DvbSharedChannel &channel); void channelAboutToBeUpdated(const DvbSharedChannel &channel); void channelUpdated(const DvbSharedChannel &channel); void channelRemoved(const DvbSharedChannel &channel); private: void customEvent(QEvent *event); DvbChannelModel *channelModel; QList dndSelectedChannels; int dndInsertBeforeNumber; bool dndEventPosted; }; class DvbChannelView : public QTreeView { Q_OBJECT public: explicit DvbChannelView(QWidget *parent); ~DvbChannelView(); QAction *addEditAction(); QAction *addRemoveAction(); void setModel(DvbChannelTableModel *tableModel_); public slots: void checkChannelDragAndDrop(bool *ok); void editChannel(); void removeChannel(); void removeAllChannels(); +signals: + void channelPidsUpdated(const DvbSharedChannel &channel); + +private slots: + void channelPidsChanged(const DvbSharedChannel &channel); + private: void setModel(QAbstractItemModel *) { } DvbChannelTableModel *tableModel; }; #endif /* DVBCHANNELDIALOG_H */ diff --git a/src/dvb/dvbchanneldialog_p.h b/src/dvb/dvbchanneldialog_p.h index 4722b53..803d13e 100644 --- a/src/dvb/dvbchanneldialog_p.h +++ b/src/dvb/dvbchanneldialog_p.h @@ -1,57 +1,61 @@ /* * dvbchanneldialog_p.h * * Copyright (C) 2007-2011 Christoph Pfister * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef DVBCHANNELDIALOG_P_H #define DVBCHANNELDIALOG_P_H #include #include "dvbchannel.h" class QCheckBox; class QSpinBox; class QComboBox; class QLineEdit; class DvbChannelTableModel; Q_DECLARE_METATYPE(QList) class DvbChannelEditor : public QDialog { +Q_OBJECT public: DvbChannelEditor(DvbChannelTableModel *model_, const DvbSharedChannel &channel_, QWidget *parent); ~DvbChannelEditor(); private: void accept(); DvbChannelTableModel *model; DvbSharedChannel channel; QLineEdit *nameEdit; QSpinBox *numberBox; QSpinBox *networkIdBox; QSpinBox *transportStreamIdBox; QSpinBox *serviceIdBox; QComboBox *audioStreamBox; QList audioPids; QCheckBox *scrambledBox; + +signals: + void channelPidsChanged(const DvbSharedChannel &channel); }; #endif /* DVBCHANNELDIALOG_P_H */ diff --git a/src/dvb/dvbtab.cpp b/src/dvb/dvbtab.cpp index 405e156..1da26e4 100644 --- a/src/dvb/dvbtab.cpp +++ b/src/dvb/dvbtab.cpp @@ -1,567 +1,622 @@ /* * dvbtab.cpp * * Copyright (C) 2007-2011 Christoph Pfister * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "../log.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../osdwidget.h" #include "dvbchanneldialog.h" #include "dvbconfigdialog.h" #include "dvbepg.h" #include "dvbepgdialog.h" #include "dvbliveview.h" #include "dvbmanager.h" #include "dvbrecordingdialog.h" #include "dvbscandialog.h" #include "dvbtab.h" class DvbTimeShiftCleaner : public QThread { public: explicit DvbTimeShiftCleaner(QObject *parent) : QThread(parent) { } ~DvbTimeShiftCleaner() { wait(); } void remove(const QString &path_, const QStringList &files_); private: void run(); QString path; QStringList files; }; void DvbTimeShiftCleaner::remove(const QString &path_, const QStringList &files_) { path = path_; files = files_; start(); } void DvbTimeShiftCleaner::run() { // delete files asynchronously because it may block for several seconds foreach (const QString &file, files) { QFile::remove(path + QLatin1Char('/') + file); } } DvbTab::DvbTab(QMenu *menu, KActionCollection *collection, MediaWidget *mediaWidget_) : mediaWidget(mediaWidget_) { manager = new DvbManager(mediaWidget, this); mediaRecordIcon = QIcon::fromTheme(QLatin1String("media-record"), QIcon(":media-record")); documentSaveIcon = QIcon::fromTheme(QLatin1String("document-save"), QIcon(":document-save")); QAction *channelsAction = new QAction(QIcon::fromTheme(QLatin1String("video-television"), QIcon(":video-television")), i18n("Channels"), this); channelsAction->setShortcut(Qt::Key_C); connect(channelsAction, SIGNAL(triggered(bool)), this, SLOT(showChannelDialog())); menu->addAction(collection->addAction(QLatin1String("dvb_channels"), channelsAction)); QAction *epgAction = new QAction(QIcon::fromTheme(QLatin1String("view-list-details"), QIcon(":view-list-details")), i18n("Program Guide"), this); epgAction->setShortcut(Qt::Key_G); connect(epgAction, SIGNAL(triggered(bool)), this, SLOT(toggleEpgDialog())); menu->addAction(collection->addAction(QLatin1String("dvb_epg"), epgAction)); QAction *osdAction = new QAction(QIcon::fromTheme(QLatin1String("dialog-information"), QIcon(":dialog-information")), i18n("OSD"), this); osdAction->setShortcut(Qt::Key_O); connect(osdAction, SIGNAL(triggered(bool)), manager->getLiveView(), SLOT(toggleOsd())); menu->addAction(collection->addAction(QLatin1String("dvb_osd"), osdAction)); QAction *recordingsAction = new QAction(QIcon::fromTheme(QLatin1String("view-pim-calendar"), QIcon(":view-pim-calendar")), i18nc("dialog", "Recording Schedule"), this); recordingsAction->setShortcut(Qt::Key_R); connect(recordingsAction, SIGNAL(triggered(bool)), this, SLOT(showRecordingDialog())); menu->addAction(collection->addAction(QLatin1String("dvb_recordings"), recordingsAction)); menu->addSeparator(); instantRecordAction = new QAction(documentSaveIcon, i18n("Instant Record"), this); instantRecordAction->setCheckable(true); connect(instantRecordAction, SIGNAL(triggered(bool)), this, SLOT(instantRecord(bool))); menu->addAction(collection->addAction(QLatin1String("dvb_instant_record"), instantRecordAction)); menu->addSeparator(); QAction *configureAction = new QAction(QIcon::fromTheme(QLatin1String("configure"), QIcon(":configure")), i18nc("@action:inmenu", "Configure Television..."), this); connect(configureAction, SIGNAL(triggered()), this, SLOT(configureDvb())); menu->addAction(collection->addAction(QLatin1String("settings_dvb"), configureAction)); connect(manager->getLiveView(), SIGNAL(previous()), this, SLOT(previousChannel())); connect(manager->getLiveView(), SIGNAL(next()), this, SLOT(nextChannel())); connect(manager->getRecordingModel(), SIGNAL(recordingRemoved(DvbSharedRecording)), this, SLOT(recordingRemoved(DvbSharedRecording))); QBoxLayout *boxLayout = new QHBoxLayout(this); boxLayout->setMargin(0); splitter = new QSplitter(this); boxLayout->addWidget(splitter); leftWidget = new QWidget(splitter); QBoxLayout *leftLayout = new QVBoxLayout(leftWidget); boxLayout = new QHBoxLayout(); boxLayout->addWidget(new QLabel(i18n("Search:"))); QLineEdit *lineEdit = new QLineEdit(leftWidget); lineEdit->setClearButtonEnabled(true); boxLayout->addWidget(lineEdit); leftLayout->addLayout(boxLayout); channelView = new DvbChannelView(leftWidget); channelView->setContextMenuPolicy(Qt::ActionsContextMenu); channelProxyModel = new DvbChannelTableModel(this); channelView->setModel(channelProxyModel); channelView->setRootIsDecorated(false); if (!channelView->header()->restoreState(QByteArray::fromBase64( KSharedConfig::openConfig()->group("DVB").readEntry("ChannelViewState", QByteArray())))) { channelView->sortByColumn(0, Qt::AscendingOrder); } channelView->setSortingEnabled(true); channelView->addEditAction(); connect(channelView, SIGNAL(activated(QModelIndex)), this, SLOT(playChannel(QModelIndex))); + connect(channelView, SIGNAL(channelPidsUpdated(DvbSharedChannel)), this, SLOT(channelPidsUpdated(DvbSharedChannel))); + channelProxyModel->setChannelModel(manager->getChannelModel()); connect(lineEdit, SIGNAL(textChanged(QString)), channelProxyModel, SLOT(setFilter(QString))); manager->setChannelView(channelView); leftLayout->addWidget(channelView); boxLayout = new QHBoxLayout(); const QSize BUTTON_SIZE = QSize(22, 22); QToolButton *toolButton = new QToolButton(leftWidget); toolButton->setDefaultAction(configureAction); toolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); toolButton->setFixedSize(BUTTON_SIZE); boxLayout->addWidget(toolButton); toolButton = new QToolButton(leftWidget); toolButton->setDefaultAction(channelsAction); toolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); toolButton->setFixedSize(BUTTON_SIZE); boxLayout->addWidget(toolButton); toolButton = new QToolButton(leftWidget); toolButton->setDefaultAction(epgAction); toolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); toolButton->setFixedSize(BUTTON_SIZE); boxLayout->addWidget(toolButton); toolButton = new QToolButton(leftWidget); toolButton->setDefaultAction(recordingsAction); toolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); toolButton->setFixedSize(BUTTON_SIZE); boxLayout->addWidget(toolButton); toolButton = new QToolButton(leftWidget); toolButton->setDefaultAction(instantRecordAction); toolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); toolButton->setFixedSize(BUTTON_SIZE); boxLayout->addWidget(toolButton); leftLayout->addLayout(boxLayout); QWidget *mediaContainer = new QWidget(splitter); mediaLayout = new QHBoxLayout(mediaContainer); mediaLayout->setMargin(0); splitter->setStretchFactor(1, 1); connect(mediaWidget, SIGNAL(osdKeyPressed(int)), this, SLOT(osdKeyPressed(int))); connect(&osdChannelTimer, SIGNAL(timeout()), this, SLOT(tuneOsdChannel())); lastChannel = KSharedConfig::openConfig()->group("DVB").readEntry("LastChannel"); splitter->restoreState(QByteArray::fromBase64( KSharedConfig::openConfig()->group("DVB").readEntry("TabSplitterState", QByteArray()))); timeShiftCleaner = new DvbTimeShiftCleaner(this); QTimer *timer = new QTimer(this); timer->start(30000); connect(timer, SIGNAL(timeout()), this, SLOT(cleanTimeShiftFiles())); autoHideMenu = false; cursorHideTimer = new QTimer(this); cursorHideTimer->setInterval(1500); cursorHideTimer->setSingleShot(true); connect(cursorHideTimer, SIGNAL(timeout()), this, SLOT(hideCursor())); } DvbTab::~DvbTab() { KSharedConfig::openConfig()->group("DVB").writeEntry("TabSplitterState", splitter->saveState().toBase64()); KSharedConfig::openConfig()->group("DVB").writeEntry("ChannelViewState", channelView->header()->saveState().toBase64()); if (!currentChannel.isEmpty()) { lastChannel = currentChannel; } KSharedConfig::openConfig()->group("DVB").writeEntry("LastChannel", lastChannel); } void DvbTab::playChannel(const QString &nameOrNumber) { DvbChannelModel *channelModel = manager->getChannelModel(); DvbSharedChannel channel; int number = nameOrNumber.toInt(); if (number > 0) { channel = channelModel->findChannelByNumber(number); } if (!channel.isValid()) { channel = channelModel->findChannelByName(nameOrNumber); } if (channel.isValid()) { playChannel(channel, channelProxyModel->find(channel)); } } void DvbTab::playLastChannel() { if (!manager->getLiveView()->getChannel().isValid() && !currentChannel.isEmpty()) { lastChannel = currentChannel; } DvbSharedChannel channel = manager->getChannelModel()->findChannelByName(lastChannel); if (channel.isValid()) { playChannel(channel, channelProxyModel->find(channel)); } } +void DvbTab::channelPidsUpdated(const DvbSharedChannel &updatedChannel) +{ + DvbSharedChannel channel = manager->getChannelModel()->findChannelByName(lastChannel); + MediaWidget::PlaybackStatus status; + + /* + * This slot is called when a channel is played and + * a channel configuration that would require to reload + * the Digital TV filtering was changed at the editor, + * e. g. if a PID has changed. + * The common reason is if someone wants to change the + * audio PID, in order to select a different language or + * enable/disable narration. + */ + + // Do nothing if the edited channel is not the active one + if (updatedChannel != channel) + return; + + status = mediaWidget->getPlaybackStatus(); + + // Ignore channels that are not being played + if (status == MediaWidget::Idle) + return; + + // Re-run the channel play, in order to update the + // PID filters + playLastChannel(); + +#if 0 + /* + * TODO: ideally, if the channel is paused, editing it should + * preserve it. However, togglePause() will only work after + * the channel starts to play, with takes some time. So, + * the code below won't work. + * Also, now the old pause status data is not valid anymore, + * as it contains a different PID, so we need to flush the + * data anyway - or implement a way more complex logic that + * would be handling a paused off-line file, and a new + * on-line paused file. + * + * So, for now, let's just assume that changing the PIDs + * while pausing a video would flush the old pause stuff + * and un-pause the channel. + */ + if (status == MediaWidget::Paused) { + qInfo() << "Toggling pause"; + mediaWidget->togglePause(); + } +#endif +} + + void DvbTab::toggleOsd() { manager->getLiveView()->toggleOsd(); } void DvbTab::toggleInstantRecord() { instantRecordAction->trigger(); } void DvbTab::enableDvbDump() { manager->enableDvbDump(); } void DvbTab::mouse_move(int x, int) { if (!autoHideMenu) return; cursorHideTimer->stop(); unsetCursor(); leftWidget->setVisible(x >= 0 && x < 120); if (leftWidget->isHidden()) { cursorHideTimer->start(); } } void DvbTab::toggleDisplayMode(MediaWidget::DisplayMode displayMode) { switch (displayMode) { case MediaWidget::FullScreenMode: case MediaWidget::FullScreenReturnToMinimalMode: case MediaWidget::MinimalMode: leftWidget->hide(); autoHideMenu = true; cursorHideTimer->start(); break; case MediaWidget::NormalMode: leftWidget->show(); autoHideMenu = false; cursorHideTimer->stop(); break; } } void DvbTab::osdKeyPressed(int key) { if ((key >= Qt::Key_0) && (key <= Qt::Key_9)) { osdChannel += QString::number(key - Qt::Key_0); osdChannelTimer.start(1500); mediaWidget->getOsdWidget()->showText(i18nc("osd", "Channel: %1_", osdChannel), 1500); } } void DvbTab::mayCloseApplication(bool *ok, QWidget *parent) { if (*ok) { DvbRecordingModel *recordingModel = manager->getRecordingModel(); if (recordingModel->hasActiveRecordings()) { if (KMessageBox::warningYesNo(parent, i18nc("message box", "Kaffeine is currently recording programs.\n" "Do you really want to close the application?")) != KMessageBox::Yes) { *ok = false; } return; } if (recordingModel->hasRecordings()) { if (KMessageBox::questionYesNo(parent, i18nc("message box", "Kaffeine has scheduled recordings.\n" "Do you really want to close the application?"), QString(), KStandardGuiItem::yes(), KStandardGuiItem::no(), QLatin1String("ScheduledRecordings")) != KMessageBox::Yes) { *ok = false; } return; } } } void DvbTab::showChannelDialog() { QDialog *dialog = new DvbScanDialog(manager, this); dialog->setAttribute(Qt::WA_DeleteOnClose, true); dialog->setModal(true); dialog->show(); } void DvbTab::showRecordingDialog() { DvbRecordingDialog::showDialog(manager, this); } void DvbTab::toggleEpgDialog() { if (epgDialog.isNull()) { epgDialog = new DvbEpgDialog(manager, this); epgDialog->setAttribute(Qt::WA_DeleteOnClose, true); epgDialog->setCurrentChannel(manager->getLiveView()->getChannel()); epgDialog->setModal(false); epgDialog->show(); } else { epgDialog->deleteLater(); epgDialog = NULL; } } void DvbTab::instantRecord(bool checked) { if (checked) { const DvbSharedChannel &channel = manager->getLiveView()->getChannel(); if (!channel.isValid()) { instantRecordAction->setChecked(false); return; } DvbRecording recording; QList epgEntries = manager->getEpgModel()->getCurrentNext(channel); if (!epgEntries.isEmpty()) { recording.name = epgEntries.at(0)->title(); } if (recording.name.isEmpty()) { recording.name = (channel->name + QTime::currentTime().toString(QLatin1String("-hhmmss"))); } recording.channel = channel; recording.begin = QDateTime::currentDateTime().toUTC(); recording.duration = QTime(12, 0); instantRecording = manager->getRecordingModel()->addRecording(recording); instantRecordings.push_back(instantRecording); instantRecordAction->setIcon(mediaRecordIcon); mediaWidget->getOsdWidget()->showText(i18nc("osd", "Instant Record Started"), 1500); } else { manager->getRecordingModel()->removeRecording(instantRecording); instantRecordings.removeOne(instantRecording); instantRecordAction->setIcon(documentSaveIcon); mediaWidget->getOsdWidget()->showText(i18nc("osd", "Instant Record Stopped"), 1500); } } void DvbTab::recordingRemoved(const DvbSharedRecording &recording) { if (instantRecording == recording) { instantRecording = DvbSharedRecording(); instantRecordAction->setChecked(false); instantRecordAction->setIcon(documentSaveIcon); mediaWidget->getOsdWidget()->showText(i18nc("osd", "Instant Record Stopped"), 1500); } instantRecordings.removeOne(recording); } void DvbTab::configureDvb() { QDialog *dialog = new DvbConfigDialog(manager, this); dialog->setAttribute(Qt::WA_DeleteOnClose, true); dialog->setModal(true); dialog->show(); } void DvbTab::tuneOsdChannel() { int number = osdChannel.toInt(); osdChannel.clear(); osdChannelTimer.stop(); DvbSharedChannel channel = manager->getChannelModel()->findChannelByNumber(number); if (channel.isValid()) { playChannel(channel, channelProxyModel->find(channel)); } } void DvbTab::playChannel(const QModelIndex &index) { if (index.isValid()) { playChannel(channelProxyModel->value(index), index); } } void DvbTab::previousChannel() { QModelIndex index = channelView->currentIndex(); if (index.isValid()) { playChannel(index.sibling(index.row() - 1, index.column())); } } void DvbTab::nextChannel() { QModelIndex index = channelView->currentIndex(); if (index.isValid()) { playChannel(index.sibling(index.row() + 1, index.column())); } } void DvbTab::cleanTimeShiftFiles() { if (timeShiftCleaner->isRunning()) { return; } QDir dir(manager->getTimeShiftFolder()); QStringList entries = dir.entryList(QStringList(QLatin1String("TimeShift-*.m2t")), QDir::Files, QDir::Name); if (entries.count() < 2) { return; } entries.removeLast(); timeShiftCleaner->remove(dir.path(), entries); } void DvbTab::activate() { mediaLayout->addWidget(mediaWidget); mediaWidget->setFocus(); } void DvbTab::playChannel(const DvbSharedChannel &channel, const QModelIndex &index) { QIcon *icon; DvbSharedRecording *recording; bool isRecording; if (!channel.isValid()) { qCWarning(logDvb, "Channel is invalid"); return; } if (!currentChannel.isEmpty()) { lastChannel = currentChannel; } recording = getInstantRecording(channel); if (recording) { instantRecording = *recording; isRecording = true; icon = &mediaRecordIcon; } else { isRecording = false; icon = &documentSaveIcon; } instantRecordAction->setChecked(isRecording); instantRecordAction->setIcon(*icon); channelView->setCurrentIndex(index); currentChannel = channel->name; manager->getLiveView()->playChannel(channel); if (!epgDialog.isNull()) { epgDialog->setCurrentChannel(manager->getLiveView()->getChannel()); } } DvbSharedRecording *DvbTab::getInstantRecording(DvbSharedChannel ch) { DvbSharedRecording *ret = NULL; QListIterator i(instantRecordings); while (i.hasNext()) { DvbSharedRecording r = i.next(); if(r.constData()->channel == ch) { ret = &r; break; } } return ret; } diff --git a/src/dvb/dvbtab.h b/src/dvb/dvbtab.h index bae0693..d6f9ff1 100644 --- a/src/dvb/dvbtab.h +++ b/src/dvb/dvbtab.h @@ -1,123 +1,124 @@ /* * dvbtab.h * * Copyright (C) 2007-2011 Christoph Pfister * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef DVBTAB_H #define DVBTAB_H #include #include #include #include #include #include "../tabbase.h" #include "../mediawidget.h" #include "dvbrecording.h" class QModelIndex; class QSplitter; class QAction; class KActionCollection; class QMenu; class DvbChannelTableModel; class DvbChannelView; class DvbEpgDialog; class DvbTimeShiftCleaner; class MediaWidget; class DvbTab : public TabBase { Q_OBJECT public: DvbTab(QMenu *menu, KActionCollection *collection, MediaWidget *mediaWidget_); ~DvbTab(); void playChannel(const QString &nameOrNumber); void playLastChannel(); void toggleOsd(); void toggleInstantRecord(); void toggleDisplayMode(MediaWidget::DisplayMode displayMode); void mouse_move(int x, int y); DvbManager *getManager() const { return manager; } void enableDvbDump(); public slots: void osdKeyPressed(int key); void mayCloseApplication(bool *ok, QWidget *parent); private slots: void showChannelDialog(); void toggleEpgDialog(); void showRecordingDialog(); void instantRecord(bool checked); void recordingRemoved(const DvbSharedRecording &recording); void configureDvb(); void tuneOsdChannel(); void playChannel(const QModelIndex &index); void previousChannel(); void nextChannel(); void cleanTimeShiftFiles(); + void channelPidsUpdated(const DvbSharedChannel &updatedChannel); private: void activate(); void playChannel(const DvbSharedChannel &channel, const QModelIndex &index); DvbSharedRecording *getInstantRecording(DvbSharedChannel ch); MediaWidget *mediaWidget; DvbManager *manager; QAction *instantRecordAction; QList instantRecordings; DvbSharedRecording instantRecording; QSplitter *splitter; QWidget *leftWidget; DvbChannelTableModel *channelProxyModel; DvbChannelView *channelView; QPointer epgDialog; QLayout *mediaLayout; QString osdChannel; QTimer osdChannelTimer; QString currentChannel; QString lastChannel; QIcon mediaRecordIcon; QIcon documentSaveIcon; bool autoHideMenu; QTimer *cursorHideTimer; DvbTimeShiftCleaner *timeShiftCleaner; }; #ifndef HAVE_DVB #error HAVE_DVB must be defined #endif /* HAVE_DVB */ #if HAVE_DVB == 0 inline void DvbTab::playChannel(QString const &) { } inline void DvbTab::playLastChannel() { } inline void DvbTab::toggleOsd() { } inline void DvbTab::toggleInstantRecord() { } inline void DvbTab::osdKeyPressed(int) { } #endif /* HAVE_DVB == 0 */ #endif /* DVBTAB_H */