File indexing completed on 2024-05-12 04:52:11
0001 /* 0002 * dvbconfigdialog.cpp 0003 * 0004 * Copyright (C) 2007-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 <KLocalizedString> 0024 0025 #include <KConfigGroup> 0026 #include <KIO/Job> 0027 #include <QBoxLayout> 0028 #include <QButtonGroup> 0029 #include <QCheckBox> 0030 #include <QComboBox> 0031 #include <QDesktopServices> 0032 #include <QDialogButtonBox> 0033 #include <QFileDialog> 0034 #include <QLabel> 0035 #include <QLineEdit> 0036 #include <QLocale> 0037 #include <QProgressBar> 0038 #include <QPushButton> 0039 #include <QRadioButton> 0040 #include <QStyle> 0041 #include <QStyleOptionTab> 0042 #include <QSpinBox> 0043 #include <QStandardPaths> 0044 #include <QTabWidget> 0045 #include <QToolButton> 0046 #include <QTreeWidget> 0047 #include <QVBoxLayout> 0048 #include <QWidgetAction> 0049 0050 #include "dvbconfig.h" 0051 #include "dvbconfigdialog.h" 0052 #include "dvbdevice.h" 0053 #include "dvbmanager.h" 0054 #include "dvbrecording.h" 0055 0056 DvbConfigDialog::DvbConfigDialog(DvbManager *manager_, QWidget *parent) : QDialog(parent), 0057 manager(manager_) 0058 { 0059 setWindowTitle(i18nc("@title:window", "Configure Television")); 0060 0061 tabWidget = new QTabWidget(this); 0062 QVBoxLayout *mainLayout = new QVBoxLayout; 0063 setLayout(mainLayout); 0064 mainLayout->addWidget(tabWidget); 0065 0066 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0067 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); 0068 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); 0069 0070 QWidget *widget = new QWidget(tabWidget); 0071 mainLayout->addWidget(widget); 0072 QBoxLayout *boxLayout = new QVBoxLayout(widget); 0073 0074 int line = 0; 0075 0076 QGridLayout *gridLayout = new QGridLayout(); 0077 gridLayout->addWidget(new QLabel(i18n("Recording folder:")), line, 0); 0078 0079 recordingFolderEdit = new QLineEdit(widget); 0080 recordingFolderEdit->setText(manager->getRecordingFolder()); 0081 gridLayout->addWidget(recordingFolderEdit, line, 1); 0082 0083 QToolButton *toolButton = new QToolButton(widget); 0084 toolButton->setIcon(QIcon::fromTheme(QLatin1String("document-open-folder"), QIcon(":document-open-folder"))); 0085 toolButton->setToolTip(i18n("Select Folder")); 0086 connect(toolButton, SIGNAL(clicked()), this, SLOT(changeRecordingFolder())); 0087 gridLayout->addWidget(toolButton, line++, 2); 0088 0089 gridLayout->addWidget(new QLabel(i18n("Time shift folder:")), line, 0); 0090 0091 timeShiftFolderEdit = new QLineEdit(widget); 0092 timeShiftFolderEdit->setText(manager->getTimeShiftFolder()); 0093 gridLayout->addWidget(timeShiftFolderEdit, line, 1); 0094 0095 toolButton = new QToolButton(widget); 0096 toolButton->setIcon(QIcon::fromTheme(QLatin1String("document-open-folder"), QIcon(":document-open-folder"))); 0097 toolButton->setToolTip(i18n("Select Folder")); 0098 connect(toolButton, SIGNAL(clicked()), this, SLOT(changeTimeShiftFolder())); 0099 gridLayout->addWidget(toolButton, line++, 2); 0100 0101 gridLayout->addWidget(new QLabel(i18n("xmltv file name (optional):")), line, 0); 0102 0103 xmltvFileNameEdit = new QLineEdit(widget); 0104 xmltvFileNameEdit->setText(manager->getXmltvFileName()); 0105 gridLayout->addWidget(xmltvFileNameEdit, line, 1); 0106 0107 toolButton = new QToolButton(widget); 0108 toolButton->setIcon(QIcon::fromTheme(QLatin1String("document-open-folder"), QIcon(":document-open-folder"))); 0109 toolButton->setToolTip(i18n("Add optional file to allow reading EPG data from xmltv files")); 0110 connect(toolButton, SIGNAL(clicked()), this, SLOT(changeXmltvFileName())); 0111 gridLayout->addWidget(toolButton, line++, 2); 0112 0113 gridLayout->addWidget(new QLabel(i18n("Disable parsing EPG data from MPEG-TS tables:")), 0114 line, 0); 0115 toolButton->setToolTip(i18n("Use this if your TV provider doesn't broadcast reliable EPG data")); 0116 disableEpgBox = new QCheckBox(widget); 0117 disableEpgBox->setChecked(manager->disableEpg()); 0118 gridLayout->addWidget(disableEpgBox, line++, 1); 0119 0120 boxLayout->addLayout(gridLayout); 0121 0122 gridLayout = new QGridLayout(); 0123 gridLayout->addWidget(new QLabel(i18n("Begin margin (minutes):")), line, 0); 0124 0125 beginMarginBox = new QSpinBox(widget); 0126 beginMarginBox->setRange(0, 99); 0127 beginMarginBox->setValue(manager->getBeginMargin() / 60); 0128 gridLayout->addWidget(beginMarginBox, line++, 1); 0129 0130 gridLayout->addWidget(new QLabel(i18n("End margin (minutes):")), line, 0); 0131 0132 endMarginBox = new QSpinBox(widget); 0133 endMarginBox->setRange(0, 99); 0134 endMarginBox->setValue(manager->getEndMargin() / 60); 0135 gridLayout->addWidget(endMarginBox, line++, 1); 0136 0137 gridLayout->addWidget(new QLabel(i18n("Naming style for recordings:")), line, 0); 0138 0139 namingFormat = new QLineEdit(widget); 0140 namingFormat->setText(manager->getNamingFormat()); 0141 namingFormat->setToolTip(i18n("The following substitutions work: \"%year\" for year (YYYY) and the following: %month, %day, %hour, %min, %sec, %channel and %title")); 0142 connect(namingFormat, SIGNAL(textChanged(QString)), this, SLOT(namingFormatChanged(QString))); 0143 0144 gridLayout->addWidget(namingFormat, line, 1); 0145 0146 validPixmap = QIcon::fromTheme(QLatin1String("dialog-ok-apply"), QIcon(":dialog-ok-apply")).pixmap(22); 0147 invalidPixmap = QIcon::fromTheme(QLatin1String("dialog-cancel"), QIcon(":dialog-cancel")).pixmap(22); 0148 0149 namingFormatValidLabel = new QLabel(widget); 0150 namingFormatValidLabel->setPixmap(validPixmap); 0151 gridLayout->addWidget(namingFormatValidLabel, line++,2); 0152 0153 gridLayout->addWidget(new QLabel(i18n("Action after recording finishes:")), line, 0); 0154 0155 actionAfterRecordingLineEdit = new QLineEdit(widget); 0156 actionAfterRecordingLineEdit->setText(manager->getActionAfterRecording()); 0157 actionAfterRecordingLineEdit->setToolTip(i18n("Leave empty for no command.")); 0158 gridLayout->addWidget(actionAfterRecordingLineEdit, line++, 1); 0159 0160 boxLayout->addLayout(gridLayout); 0161 0162 gridLayout = new QGridLayout(); 0163 gridLayout->addWidget(new QLabel(i18n("Use ISO 8859-1 charset instead of ISO 6937:")), 0164 1, 0); 0165 0166 override6937CharsetBox = new QCheckBox(widget); 0167 override6937CharsetBox->setChecked(manager->override6937Charset()); 0168 gridLayout->addWidget(override6937CharsetBox, 1, 1); 0169 0170 gridLayout->addWidget(new QLabel(i18n("Create info files to accompany EPG recordings:")), 0171 2, 0); 0172 createInfoFileBox = new QCheckBox(widget); 0173 createInfoFileBox->setChecked(manager->createInfoFile()); 0174 gridLayout->addWidget(createInfoFileBox, 2, 1); 0175 0176 #if 0 0177 // FIXME: this functionality is not working. Comment it out 0178 0179 gridLayout->addWidget(new QLabel(i18n("Scan channels when idle to fetch fresh EPG data:")), 0180 3, 0); 0181 scanWhenIdleBox = new QCheckBox(widget); 0182 scanWhenIdleBox->setChecked(manager->isScanWhenIdle()); 0183 gridLayout->addWidget(scanWhenIdleBox, 3, 1); 0184 #endif 0185 0186 QFrame *frame = new QFrame(widget); 0187 frame->setFrameShape(QFrame::HLine); 0188 boxLayout->addWidget(frame); 0189 0190 boxLayout->addWidget(new QLabel(i18n("Scan data last updated on %1", 0191 QLocale().toString(manager->getScanDataDate(), QLocale::ShortFormat)))); 0192 0193 QPushButton *pushButton = new QPushButton(i18n("Update Scan Data over Internet"), widget); 0194 connect(pushButton, SIGNAL(clicked()), this, SLOT(updateScanFile())); 0195 boxLayout->addWidget(pushButton); 0196 0197 QPushButton *openScanFileButton = new QPushButton(i18n("Edit Scanfile"), widget); 0198 connect(openScanFileButton, SIGNAL(clicked()), this, SLOT(openScanFile())); 0199 boxLayout->addWidget(openScanFileButton); 0200 openScanFileButton->setToolTip(i18n("You can add channels manually to this file before scanning for them.")); 0201 0202 frame = new QFrame(widget); 0203 frame->setFrameShape(QFrame::HLine); 0204 boxLayout->addWidget(frame); 0205 0206 boxLayout->addLayout(gridLayout); 0207 0208 QStyleOptionTab option; 0209 option.initFrom(tabWidget); 0210 int metric = style()->pixelMetric(QStyle::PM_SmallIconSize, &option, tabWidget); 0211 0212 validPixmap = QIcon::fromTheme(QLatin1String("dialog-ok-apply"), QIcon(":dialog-ok-apply")).pixmap(metric); 0213 invalidPixmap = QIcon::fromTheme(QLatin1String("dialog-cancel"), QIcon(":dialog-cancel")).pixmap(metric); 0214 0215 boxLayout->addStretch(); 0216 0217 tabWidget->addTab(widget, QIcon::fromTheme(QLatin1String("configure"), QIcon(":configure")), i18n("General Options")); 0218 0219 QWidget *widgetAutomaticRecording = new QWidget(tabWidget); 0220 QBoxLayout *boxLayoutAutomaticRecording = new QVBoxLayout(widgetAutomaticRecording); 0221 0222 0223 QGridLayout *buttonGrid = new QGridLayout(); 0224 initRegexButtons(buttonGrid); 0225 0226 regexGrid = new QGridLayout(); 0227 int j = 0; 0228 foreach (const QString regex, manager->getRecordingRegexList()) { 0229 RegexInputLine *inputLine = new RegexInputLine(); 0230 inputLine->lineEdit = new QLineEdit(widget); 0231 inputLine->lineEdit->setText(regex); 0232 regexGrid->addWidget(inputLine->lineEdit, j, 0); 0233 inputLine->checkBox = new QCheckBox(widget); 0234 inputLine->checkBox->setChecked(false); 0235 regexGrid->addWidget(inputLine->checkBox, j, 2); 0236 inputLine->spinBox = new QSpinBox(); 0237 inputLine->spinBox->setValue(manager->getRecordingRegexPriorityList().value(j)); 0238 regexGrid->addWidget(inputLine->spinBox, j, 1); 0239 0240 inputLine->index = j; 0241 0242 regexInputList.append(inputLine); 0243 0244 j = j + 1; 0245 } 0246 0247 boxLayoutAutomaticRecording->addLayout(buttonGrid); 0248 boxLayoutAutomaticRecording->addLayout(regexGrid); 0249 0250 tabWidget->addTab(widgetAutomaticRecording, QIcon::fromTheme(QLatin1String("configure"), QIcon(":configure")), 0251 i18n("Automatic Recording")); 0252 // 0253 0254 int i = 1; 0255 0256 foreach (const DvbDeviceConfig &deviceConfig, manager->getDeviceConfigs()) { 0257 DvbConfigPage *configPage = new DvbConfigPage(tabWidget, manager, &deviceConfig); 0258 connect(configPage, SIGNAL(moveLeft(DvbConfigPage*)), 0259 this, SLOT(moveLeft(DvbConfigPage*))); 0260 connect(configPage, SIGNAL(moveRight(DvbConfigPage*)), 0261 this, SLOT(moveRight(DvbConfigPage*))); 0262 connect(configPage, SIGNAL(remove(DvbConfigPage*)), 0263 this, SLOT(remove(DvbConfigPage*))); 0264 tabWidget->addTab(configPage, QIcon::fromTheme(QLatin1String("video-television"), QIcon(":video-television")), i18n("Device %1", i)); 0265 configPages.append(configPage); 0266 ++i; 0267 } 0268 0269 // Use a size that would allow show multiple devices 0270 resize(100 * fontMetrics().averageCharWidth(), 28 * fontMetrics().height()); 0271 0272 if (!configPages.isEmpty()) { 0273 configPages.at(0)->setMoveLeftEnabled(false); 0274 configPages.at(configPages.size() - 1)->setMoveRightEnabled(false); 0275 } 0276 0277 mainLayout->addWidget(buttonBox); 0278 } 0279 0280 DvbConfigDialog::~DvbConfigDialog() 0281 { 0282 } 0283 0284 void DvbConfigDialog::changeRecordingFolder() 0285 { 0286 QString path = QFileDialog::getExistingDirectory(this, QString(), recordingFolderEdit->text()); 0287 0288 if (path.isEmpty()) { 0289 return; 0290 } 0291 0292 recordingFolderEdit->setText(path); 0293 } 0294 0295 void DvbConfigDialog::changeTimeShiftFolder() 0296 { 0297 QString path = QFileDialog::getExistingDirectory(this, QString(), timeShiftFolderEdit->text()); 0298 0299 if (path.isEmpty()) { 0300 return; 0301 } 0302 0303 timeShiftFolderEdit->setText(path); 0304 } 0305 0306 void DvbConfigDialog::changeXmltvFileName() 0307 { 0308 QString path = QFileDialog::getOpenFileName(this, QString(), xmltvFileNameEdit->text()); 0309 0310 if (path.isEmpty()) { 0311 return; 0312 } 0313 0314 xmltvFileNameEdit->setText(path); 0315 } 0316 0317 void DvbConfigDialog::updateScanFile() 0318 { 0319 QDialog *dialog = new DvbScanFileDownloadDialog(manager, this); 0320 dialog->setAttribute(Qt::WA_DeleteOnClose, true); 0321 dialog->setModal(true); 0322 dialog->show(); 0323 } 0324 0325 void DvbConfigDialog::newRegex() 0326 { 0327 RegexInputLine *inputLine = new RegexInputLine(); 0328 0329 inputLine->lineEdit = new QLineEdit(tabWidget); 0330 inputLine->lineEdit->setText(""); 0331 regexGrid->addWidget(inputLine->lineEdit, regexInputList.size(), 0); 0332 0333 inputLine->checkBox = new QCheckBox(tabWidget); 0334 inputLine->checkBox->setChecked(false); 0335 regexGrid->addWidget(inputLine->checkBox, regexInputList.size(), 2); 0336 0337 inputLine->spinBox = new QSpinBox(tabWidget); 0338 inputLine->spinBox->setRange(0, 99); 0339 inputLine->spinBox->setValue(5); 0340 regexGrid->addWidget(inputLine->spinBox, regexInputList.size(), 1); 0341 0342 regexInputList.append(inputLine); 0343 } 0344 0345 0346 0347 /** 0348 * Helper function. Deletes all child widgets of the given layout @a item. 0349 */ 0350 void deleteChildWidgets(QLayoutItem *item) { 0351 if (item->layout()) { 0352 // Process all child items recursively. 0353 for (int i = 0; i < item->layout()->count(); i++) { 0354 deleteChildWidgets(item->layout()->itemAt(i)); 0355 } 0356 } 0357 delete item->widget(); 0358 } 0359 0360 0361 /** 0362 * Helper function. Removes all layout items within the given @a layout 0363 * which either span the given @a row or @a column. If @a deleteWidgets 0364 * is true, all concerned child widgets become not only removed from the 0365 * layout, but also deleted. 0366 */ 0367 void DvbConfigDialog::removeWidgets(QGridLayout *layout, int row, int column, bool deleteWidgets) { 0368 // We avoid usage of QGridLayout::itemAtPosition() here to improve performance. 0369 for (int i = layout->count() - 1; i >= 0; i--) { 0370 int r, c, rs, cs; 0371 layout->getItemPosition(i, &r, &c, &rs, &cs); 0372 if ((r <= row && r + rs - 1 >= row) || (c <= column && c + cs - 1 >= column)) { 0373 // This layout item is subject to deletion. 0374 QLayoutItem *item = layout->takeAt(i); 0375 if (deleteWidgets) { 0376 deleteChildWidgets(item); 0377 } 0378 delete item; 0379 } 0380 } 0381 } 0382 0383 void DvbConfigDialog::initRegexButtons(QGridLayout *buttonGrid) 0384 { 0385 QWidgetAction *action = new QWidgetAction(tabWidget); 0386 action->setIcon(QIcon::fromTheme(QLatin1String("list-add"), QIcon(":list-add"))); 0387 action->setText(i18nc("@action", "Add new Regex")); 0388 0389 connect(action, SIGNAL(triggered()), this, SLOT(newRegex())); 0390 tabWidget->addAction(action); 0391 QPushButton *pushButtonAdd = new QPushButton(action->icon(), action->text(), tabWidget); 0392 connect(pushButtonAdd, SIGNAL(clicked()), this, SLOT(newRegex())); 0393 buttonGrid->addWidget(pushButtonAdd, 0, 0); 0394 pushButtonAdd->setToolTip(i18n("Add another regular expression.")); 0395 0396 action = new QWidgetAction(tabWidget); 0397 action->setIcon(QIcon::fromTheme(QLatin1String("edit-delete"), QIcon(":edit-delete"))); 0398 action->setText(i18nc("@action", "Remove Regex")); 0399 connect(action, SIGNAL(triggered()), this, SLOT(removeRegex())); 0400 tabWidget->addAction(action); 0401 QPushButton *pushButtonRemove = new QPushButton(action->icon(), action->text(), tabWidget); 0402 connect(pushButtonRemove, SIGNAL(clicked()), this, SLOT(removeRegex())); 0403 buttonGrid->addWidget(pushButtonRemove, 0, 1); 0404 pushButtonRemove->setToolTip(i18n("Remove checked regular expressions.")); 0405 } 0406 0407 void DvbConfigDialog::removeRegex() 0408 { 0409 //regexGrid = new QGridLayout(tabWidget); 0410 //regexBoxMap = QMap<QCheckBox *, QLineEdit *>(); 0411 QList<RegexInputLine *> copyList = QList<RegexInputLine *>(); 0412 foreach(RegexInputLine *inputLine, regexInputList) 0413 { 0414 copyList.append(inputLine); 0415 } 0416 foreach(RegexInputLine *inputLine, copyList) 0417 { 0418 qCDebug(logDvb, "list:"); 0419 if (inputLine->checkBox->isChecked()){ 0420 qCDebug(logDvb, "checked:"); 0421 if (regexInputList.removeOne(inputLine)) { 0422 qCDebug(logDvb, "removed:"); 0423 } 0424 } 0425 } 0426 0427 QWidget *widgetAutomaticRecording = new QWidget(tabWidget); 0428 QBoxLayout *boxLayoutAutomaticRecording = new QVBoxLayout(widgetAutomaticRecording); 0429 0430 QGridLayout *buttonGrid = new QGridLayout(); 0431 regexGrid = new QGridLayout(); 0432 0433 initRegexButtons(buttonGrid); 0434 0435 int j = 0; 0436 foreach (RegexInputLine *oldLine, regexInputList) { 0437 RegexInputLine *inputLine = new RegexInputLine(); 0438 inputLine->lineEdit = new QLineEdit(); 0439 inputLine->lineEdit->setText(oldLine->lineEdit->text()); 0440 regexGrid->addWidget(inputLine->lineEdit, j, 0); 0441 inputLine->checkBox = new QCheckBox(); 0442 inputLine->checkBox->setChecked(false); 0443 regexGrid->addWidget(inputLine->checkBox, j, 2); 0444 inputLine->spinBox = new QSpinBox(); 0445 inputLine->spinBox->setValue(oldLine->spinBox->value()); 0446 regexGrid->addWidget(inputLine->spinBox, j, 1); 0447 0448 inputLine->index = j; 0449 0450 j = j + 1; 0451 } 0452 0453 boxLayoutAutomaticRecording->addLayout(buttonGrid); 0454 boxLayoutAutomaticRecording->addLayout(regexGrid); 0455 tabWidget->removeTab(1); 0456 tabWidget->addTab(widgetAutomaticRecording, QIcon::fromTheme(QLatin1String("configure"), QIcon(":configure")), i18n("Automatic Recording")); 0457 tabWidget->move(tabWidget->count()-1, 1); 0458 tabWidget->setCurrentIndex(1); 0459 } 0460 0461 void DvbConfigDialog::openScanFile() 0462 { 0463 QString file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/scanfile.dvb")); 0464 QDesktopServices::openUrl(QUrl(file)); 0465 } 0466 0467 void DvbConfigDialog::namingFormatChanged(QString text) 0468 { 0469 QString temp = text.replace("%year", " "); 0470 temp = temp.replace("%month", " "); 0471 temp = temp.replace("%day", " "); 0472 temp = temp.replace("%hour", " "); 0473 temp = temp.replace("%min", " "); 0474 temp = temp.replace("%sec"," "); 0475 temp = temp.replace("%channel", " "); 0476 temp = temp.replace("%title", " "); 0477 0478 if (!temp.contains("%")) { 0479 namingFormatValidLabel->setPixmap(validPixmap); 0480 } else { 0481 namingFormatValidLabel->setPixmap(invalidPixmap); 0482 } 0483 } 0484 0485 void DvbConfigDialog::moveLeft(DvbConfigPage *configPage) 0486 { 0487 int index = configPages.indexOf(configPage); 0488 0489 if (index <= 0) { 0490 return; 0491 } 0492 0493 #if QT_VERSION < 0x050c00 0494 configPages.swap(index, index - 1); 0495 #else 0496 configPages.swapItemsAt(index, index - 1); 0497 #endif 0498 0499 if (index == 1) { 0500 configPages.at(0)->setMoveLeftEnabled(false); 0501 configPages.at(1)->setMoveLeftEnabled(true); 0502 } 0503 0504 if (index == (configPages.size() - 1)) { 0505 configPages.at(index)->setMoveRightEnabled(false); 0506 configPages.at(index - 1)->setMoveRightEnabled(true); 0507 } 0508 0509 // configPages and tabWidget indexes differ by two 0510 tabWidget->insertTab(index + 1, configPages.at(index - 1), QIcon::fromTheme(QLatin1String("video-television"), QIcon(":video-television")), 0511 i18n("Device %1", index)); 0512 tabWidget->setTabText(index + 2, i18n("Device %1", index + 1)); 0513 tabWidget->setCurrentIndex(index + 1); 0514 } 0515 0516 void DvbConfigDialog::moveRight(DvbConfigPage *configPage) 0517 { 0518 int index = configPages.indexOf(configPage) + 1; 0519 0520 if ((index <= 0) || (index == configPages.size())) { 0521 return; 0522 } 0523 0524 #if QT_VERSION < 0x050c00 0525 configPages.swap(index, index - 1); 0526 #else 0527 configPages.swapItemsAt(index, index - 1); 0528 #endif 0529 0530 if (index == 1) { 0531 configPages.at(0)->setMoveLeftEnabled(false); 0532 configPages.at(1)->setMoveLeftEnabled(true); 0533 } 0534 0535 if (index == (configPages.size() - 1)) { 0536 configPages.at(index)->setMoveRightEnabled(false); 0537 configPages.at(index - 1)->setMoveRightEnabled(true); 0538 } 0539 0540 // configPages and tabWidget indexes differ by two 0541 tabWidget->insertTab(index + 1, configPages.at(index - 1), QIcon::fromTheme(QLatin1String("video-television"), QIcon(":video-television")), 0542 i18n("Device %1", index)); 0543 tabWidget->setTabText(index + 2, i18n("Device %1", index + 1)); 0544 tabWidget->setCurrentIndex(index + 2); 0545 } 0546 0547 void DvbConfigDialog::remove(DvbConfigPage *configPage) 0548 { 0549 int index = configPages.indexOf(configPage); 0550 0551 if (index < 0) { 0552 return; 0553 } 0554 0555 delete configPages.takeAt(index); 0556 0557 if ((index == 0) && !configPages.isEmpty()) { 0558 configPages.at(0)->setMoveLeftEnabled(false); 0559 } 0560 0561 if ((index > 0) && (index == configPages.size())) { 0562 configPages.at(index - 1)->setMoveRightEnabled(false); 0563 } 0564 0565 for (; index < configPages.size(); ++index) { 0566 // configPages and tabWidget indexes differ by two 0567 tabWidget->setTabText(index + 2, i18n("Device %1", index + 1)); 0568 } 0569 } 0570 0571 void DvbConfigDialog::accept() 0572 { 0573 manager->setRecordingFolder(recordingFolderEdit->text()); 0574 manager->setTimeShiftFolder(timeShiftFolderEdit->text()); 0575 manager->setXmltvFileName(xmltvFileNameEdit->text()); 0576 manager->setNamingFormat(namingFormat->text()); 0577 manager->setActionAfterRecording(actionAfterRecordingLineEdit->text()); 0578 manager->setBeginMargin(beginMarginBox->value() * 60); 0579 manager->setEndMargin(endMarginBox->value() * 60); 0580 manager->setOverride6937Charset(override6937CharsetBox->isChecked()); 0581 manager->setCreateInfoFile(createInfoFileBox->isChecked()); 0582 manager->setDisableEpg(disableEpgBox->isChecked()); 0583 #if 0 0584 manager->setScanWhenIdle(scanWhenIdleBox->isChecked()); 0585 #endif 0586 manager->setRecordingRegexList(QStringList()); 0587 manager->setRecordingRegexPriorityList(QList<int>()); 0588 0589 foreach (RegexInputLine *regexInputLine, regexInputList) 0590 { 0591 manager->addRecordingRegex(regexInputLine->lineEdit->text()); 0592 qCDebug(logDvb, "saved regex: %s", qPrintable(regexInputLine->lineEdit->text())); 0593 manager->addRecordingRegexPriority(regexInputLine->spinBox->value()); 0594 qCDebug(logDvb, "saved priority: %i", regexInputLine->spinBox->value()); 0595 } 0596 0597 QList<DvbDeviceConfigUpdate> configUpdates; 0598 0599 foreach (DvbConfigPage *configPage, configPages) { 0600 DvbDeviceConfigUpdate configUpdate(configPage->getDeviceConfig()); 0601 configUpdate.configs = configPage->getConfigs(); 0602 configUpdates.append(configUpdate); 0603 } 0604 0605 manager->updateDeviceConfigs(configUpdates); 0606 manager->getRecordingModel()->findNewRecordings(); 0607 manager->getRecordingModel()->removeDuplicates(); 0608 manager->getRecordingModel()->disableConflicts(); 0609 //manager->getRecordingModel()->scanChannels(); 0610 manager->writeDeviceConfigs(); 0611 0612 QDialog::accept(); 0613 } 0614 0615 DvbScanFileDownloadDialog::DvbScanFileDownloadDialog(DvbManager *manager_, QWidget *parent) : 0616 QDialog(parent), manager(manager_) 0617 { 0618 setWindowTitle(i18n("Update Scan Data")); 0619 0620 QWidget *mainWidget = new QWidget(this); 0621 mainLayout = new QVBoxLayout; 0622 setLayout(mainLayout); 0623 mainLayout->addWidget(mainWidget); 0624 0625 errorMsg = "Scan data update aborted."; 0626 0627 buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0628 buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 0629 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); 0630 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); 0631 0632 QWidget *widget = new QWidget(this); 0633 mainLayout->addWidget(widget); 0634 0635 mainLayout->addWidget(widget); 0636 0637 label = new QLabel(i18n("Downloading scan data"), widget); 0638 mainLayout->addWidget(label); 0639 0640 progressBar = new QProgressBar(widget); 0641 mainLayout->addWidget(progressBar); 0642 progressBar->setRange(0, 100); 0643 0644 mainLayout->addWidget(buttonBox); 0645 0646 job = KIO::get(QUrl("https://autoconfig.kde.org/kaffeine/scantable.dvb.qz"), KIO::NoReload, 0647 KIO::HideProgressInfo); // FIXME NoReload or Reload? 0648 job->setAutoDelete(false); 0649 connect(job, SIGNAL(percent(KJob*,ulong)), 0650 this, SLOT(progressChanged(KJob*,ulong))); 0651 connect(job, SIGNAL(data(KIO::Job*,QByteArray)), 0652 this, SLOT(dataArrived(KIO::Job*,QByteArray))); 0653 connect(job, SIGNAL(result(KJob*)), this, SLOT(jobFinished())); 0654 } 0655 0656 DvbScanFileDownloadDialog::~DvbScanFileDownloadDialog() 0657 { 0658 delete job; 0659 } 0660 0661 void DvbScanFileDownloadDialog::progressChanged(KJob *, unsigned long percent) 0662 { 0663 progressBar->setValue(int(percent)); 0664 } 0665 0666 void DvbScanFileDownloadDialog::dataArrived(KIO::Job *, const QByteArray &data) 0667 { 0668 scanData.append(data); 0669 0670 /* 0671 * Current size in April, 2021 is 104KB. 0672 * Add an upper size limit here (1 MB), just in case, in order to 0673 * prevent potential issues. 0674 */ 0675 int maxLimit = 1024 * 1024; 0676 0677 if (scanData.size() > maxLimit) { 0678 errorMsg = i18n("Scan file is becoming bigger than %1 KB.\n" 0679 "Aborting, as something might be wrong...\n", 0680 QString::number(maxLimit / 1024., 'f', 2)); 0681 job->kill(KJob::EmitResult); 0682 } 0683 } 0684 0685 void DvbScanFileDownloadDialog::jobFinished() 0686 { 0687 progressBar->setValue(100); 0688 0689 if (job->error() != 0) { 0690 if (job->error() == KJob::KilledJobError) { 0691 label->setText(errorMsg); 0692 } else { 0693 label->setText(job->errorString()); 0694 } 0695 0696 return; 0697 } 0698 0699 if (manager->updateScanData(scanData)) { 0700 buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 0701 label->setText(i18n("Scan data successfully updated. %1 KB received.\n" 0702 "Changes take effect after you have closed\n" 0703 "the configuration dialog.", 0704 QString::number(scanData.size() / 1024., 'f', 2))); 0705 } else { 0706 label->setText(i18n("Scan data update failed.")); 0707 } 0708 } 0709 0710 DvbConfigPage::DvbConfigPage(QWidget *parent, DvbManager *manager, 0711 const DvbDeviceConfig *deviceConfig_) : QWidget(parent), deviceConfig(deviceConfig_), 0712 dvbSObject(NULL) 0713 { 0714 boxLayout = new QVBoxLayout(this); 0715 boxLayout->addWidget(new QLabel(i18n("Name: %1", deviceConfig->frontendName))); 0716 0717 QBoxLayout *horizontalLayout = new QHBoxLayout(); 0718 moveLeftButton = new QPushButton(QIcon::fromTheme(QLatin1String("arrow-left"), QIcon(":arrow-left")), i18n("Move Left"), this); 0719 connect(moveLeftButton, SIGNAL(clicked()), this, SLOT(moveLeft())); 0720 horizontalLayout->addWidget(moveLeftButton); 0721 0722 if (deviceConfig->device != NULL) { 0723 QPushButton *pushButton = new QPushButton(QIcon::fromTheme(QLatin1String("edit-undo"), QIcon(":edit-undo")), i18n("Reset"), this); 0724 connect(pushButton, SIGNAL(clicked()), this, SIGNAL(resetConfig())); 0725 horizontalLayout->addWidget(pushButton); 0726 } else { 0727 QPushButton *pushButton = 0728 new QPushButton(QIcon::fromTheme(QLatin1String("edit-delete"), QIcon(":edit-delete")), i18nc("@action", "Remove"), this); 0729 connect(pushButton, SIGNAL(clicked()), this, SLOT(removeConfig())); 0730 horizontalLayout->addWidget(pushButton); 0731 } 0732 0733 moveRightButton = new QPushButton(QIcon::fromTheme(QLatin1String("arrow-right"), QIcon(":arrow-right")), i18n("Move Right"), this); 0734 connect(moveRightButton, SIGNAL(clicked()), this, SLOT(moveRight())); 0735 horizontalLayout->addWidget(moveRightButton); 0736 boxLayout->addLayout(horizontalLayout); 0737 0738 if (deviceConfig->device == NULL) { 0739 addHSeparator(i18n("Device not connected.")); 0740 boxLayout->addStretch(); 0741 configs = deviceConfig->configs; 0742 return; 0743 } 0744 0745 DvbDevice::TransmissionTypes transmissionTypes = 0746 deviceConfig->device->getTransmissionTypes(); 0747 0748 DvbConfig dvbCConfig; 0749 QList<DvbConfig> dvbSConfigs; 0750 DvbConfig dvbTConfig; 0751 DvbConfig atscConfig; 0752 DvbConfig isdbTConfig; 0753 0754 foreach (const DvbConfig &config, deviceConfig->configs) { 0755 switch (config->getTransmissionType()) { 0756 case DvbConfigBase::DvbC: 0757 dvbCConfig = config; 0758 break; 0759 case DvbConfigBase::DvbS: 0760 dvbSConfigs.append(config); 0761 break; 0762 case DvbConfigBase::DvbT: 0763 dvbTConfig = config; 0764 break; 0765 case DvbConfigBase::Atsc: 0766 atscConfig = config; 0767 break; 0768 case DvbConfigBase::IsdbT: 0769 isdbTConfig = config; 0770 break; 0771 } 0772 } 0773 0774 if ((transmissionTypes & DvbDevice::DvbC) != 0) { 0775 addHSeparator(i18n("DVB-C")); 0776 0777 if (dvbCConfig.constData() == NULL) { 0778 DvbConfigBase *config = new DvbConfigBase(DvbConfigBase::DvbC); 0779 config->timeout = 1500; 0780 dvbCConfig = DvbConfig(config); 0781 } 0782 0783 new DvbConfigObject(this, boxLayout, manager, dvbCConfig.data(), false); 0784 configs.append(dvbCConfig); 0785 } 0786 0787 if ((transmissionTypes & (DvbDevice::DvbS | DvbDevice::DvbS2)) != 0) { 0788 bool dvbS2 = ((transmissionTypes & DvbDevice::DvbS2) != 0); 0789 0790 if (dvbS2) { 0791 addHSeparator(i18n("DVB-S2")); 0792 } else { 0793 addHSeparator(i18n("DVB-S")); 0794 } 0795 0796 dvbSObject = new DvbSConfigObject(this, boxLayout, manager, dvbSConfigs, deviceConfig->device, dvbS2); 0797 } 0798 0799 if ((transmissionTypes & DvbDevice::DvbT) != 0) { 0800 bool dvbT2 = ((transmissionTypes & DvbDevice::DvbT2) != 0); 0801 0802 if (dvbT2) { 0803 addHSeparator(i18n("DVB-T2")); 0804 } else { 0805 addHSeparator(i18n("DVB-T")); 0806 } 0807 0808 if (dvbTConfig.constData() == NULL) { 0809 DvbConfigBase *config = new DvbConfigBase(DvbConfigBase::DvbT); 0810 config->timeout = 1500; 0811 dvbTConfig = DvbConfig(config); 0812 } 0813 0814 new DvbConfigObject(this, boxLayout, manager, dvbTConfig.data(), dvbT2); 0815 configs.append(dvbTConfig); 0816 } 0817 0818 if ((transmissionTypes & DvbDevice::Atsc) != 0) { 0819 addHSeparator(i18n("ATSC")); 0820 0821 if (atscConfig.constData() == NULL) { 0822 DvbConfigBase *config = new DvbConfigBase(DvbConfigBase::Atsc); 0823 config->timeout = 1500; 0824 atscConfig = DvbConfig(config); 0825 } 0826 0827 new DvbConfigObject(this, boxLayout, manager, atscConfig.data(), false); 0828 configs.append(atscConfig); 0829 } 0830 0831 if ((transmissionTypes & DvbDevice::IsdbT) != 0) { 0832 addHSeparator(i18n("ISDB-T")); 0833 0834 if (isdbTConfig.constData() == NULL) { 0835 DvbConfigBase *config = new DvbConfigBase(DvbConfigBase::IsdbT); 0836 config->timeout = 1500; 0837 isdbTConfig = DvbConfig(config); 0838 } 0839 0840 new DvbConfigObject(this, boxLayout, manager, isdbTConfig.data(), false); 0841 configs.append(isdbTConfig); 0842 } 0843 0844 boxLayout->addStretch(); 0845 } 0846 0847 DvbConfigPage::~DvbConfigPage() 0848 { 0849 } 0850 0851 void DvbConfigPage::setMoveLeftEnabled(bool enabled) 0852 { 0853 moveLeftButton->setEnabled(enabled); 0854 } 0855 0856 void DvbConfigPage::setMoveRightEnabled(bool enabled) 0857 { 0858 moveRightButton->setEnabled(enabled); 0859 } 0860 0861 const DvbDeviceConfig *DvbConfigPage::getDeviceConfig() const 0862 { 0863 return deviceConfig; 0864 } 0865 0866 QList<DvbConfig> DvbConfigPage::getConfigs() 0867 { 0868 if (dvbSObject != NULL) { 0869 dvbSObject->appendConfigs(configs); 0870 } 0871 0872 for (int i = 0; i < configs.count(); ++i) { 0873 const DvbConfig &config = configs.at(i); 0874 0875 if (config->name.isEmpty() || config->scanSource.isEmpty()) { 0876 configs.removeAt(i); 0877 --i; 0878 } 0879 } 0880 0881 return configs; 0882 } 0883 0884 void DvbConfigPage::moveLeft() 0885 { 0886 emit moveLeft(this); 0887 } 0888 0889 void DvbConfigPage::moveRight() 0890 { 0891 emit moveRight(this); 0892 } 0893 0894 void DvbConfigPage::removeConfig() 0895 { 0896 emit remove(this); 0897 } 0898 0899 void DvbConfigPage::addHSeparator(const QString &title) 0900 { 0901 QFrame *frame = new QFrame(this); 0902 frame->setFrameShape(QFrame::HLine); 0903 boxLayout->addWidget(frame); 0904 boxLayout->addWidget(new QLabel(title, this)); 0905 } 0906 0907 DvbConfigObject::DvbConfigObject(QWidget *parent, QBoxLayout *layout, DvbManager *manager, 0908 DvbConfigBase *config_, bool isGen2_) : QObject(parent), config(config_) 0909 { 0910 QStringList sources; 0911 int sourceIndex = -1; 0912 0913 isGen2 = isGen2_; 0914 0915 switch (config->getTransmissionType()) { 0916 case DvbConfigBase::DvbC: 0917 defaultName = i18n("Cable"); 0918 sources = manager->getScanSources(DvbManager::DvbC); 0919 sourceIndex = sources.indexOf(config->scanSource); 0920 break; 0921 case DvbConfigBase::DvbS: 0922 // handled separately 0923 break; 0924 case DvbConfigBase::DvbT: 0925 if (isGen2) { 0926 defaultName = i18n("Terrestrial (T2)"); 0927 sources.append(QLatin1String("AUTO-T2-Normal")); 0928 sources.append(QLatin1String("AUTO-T2-Offsets")); 0929 sources.append(QLatin1String("AUTO-T2-Australia")); 0930 sources.append(QLatin1String("AUTO-T2-Italy")); 0931 sources.append(QLatin1String("AUTO-T2-Taiwan")); 0932 sources += manager->getScanSources(DvbManager::DvbT2); 0933 } else { 0934 defaultName = i18n("Terrestrial"); 0935 sources.append(QLatin1String("AUTO-T-Normal")); 0936 sources.append(QLatin1String("AUTO-T-Offsets")); 0937 sources.append(QLatin1String("AUTO-T-Australia")); 0938 sources.append(QLatin1String("AUTO-T-Italy")); 0939 sources.append(QLatin1String("AUTO-T-Taiwan")); 0940 sources += manager->getScanSources(DvbManager::DvbT); 0941 } 0942 sourceIndex = sources.indexOf(config->scanSource); 0943 sources.replace(0, i18n("Autoscan")); 0944 sources.replace(1, i18n("Autoscan with 167 kHz Offsets")); 0945 sources.replace(2, i18n("Autoscan Australia")); 0946 sources.replace(3, i18n("Autoscan Italy")); 0947 sources.replace(4, i18n("Autoscan Taiwan")); 0948 break; 0949 case DvbConfigBase::Atsc: 0950 defaultName = i18n("Atsc"); 0951 sources = manager->getScanSources(DvbManager::Atsc); 0952 sourceIndex = sources.indexOf(config->scanSource); 0953 break; 0954 case DvbConfigBase::IsdbT: 0955 defaultName = i18n("ISDB-T"); 0956 sources.append(QLatin1String("AUTO-UHF-6MHz")); 0957 sources.replace(0, i18n("Autoscan")); 0958 sources += manager->getScanSources(DvbManager::IsdbT); 0959 sourceIndex = sources.indexOf(config->scanSource); 0960 break; 0961 } 0962 0963 QGridLayout *gridLayout = new QGridLayout(); 0964 layout->addLayout(gridLayout); 0965 0966 gridLayout->addWidget(new QLabel(i18n("Tuner timeout (ms):")), 0, 0); 0967 0968 timeoutBox = new QSpinBox(parent); 0969 timeoutBox->setRange(100, 5000); 0970 timeoutBox->setSingleStep(100); 0971 timeoutBox->setValue(config->timeout); 0972 connect(timeoutBox, SIGNAL(valueChanged(int)), this, SLOT(timeoutChanged(int))); 0973 gridLayout->addWidget(timeoutBox, 0, 1); 0974 0975 gridLayout->addWidget(new QLabel(i18n("Source:")), 1, 0); 0976 0977 sourceBox = new QComboBox(parent); 0978 sourceBox->addItem(i18n("No Source")); 0979 sourceBox->addItems(sources); 0980 sourceBox->setCurrentIndex(sourceIndex + 1); 0981 connect(sourceBox, SIGNAL(currentIndexChanged(int)), this, SLOT(sourceChanged(int))); 0982 gridLayout->addWidget(sourceBox, 1, 1); 0983 0984 gridLayout->addWidget(new QLabel(i18n("Name:")), 2, 0); 0985 0986 nameEdit = new QLineEdit(parent); 0987 nameEdit->setText(config->name); 0988 connect(nameEdit, SIGNAL(editingFinished()), this, SLOT(nameChanged())); 0989 gridLayout->addWidget(nameEdit, 2, 1); 0990 0991 timeoutChanged(timeoutBox->value()); 0992 sourceChanged(sourceBox->currentIndex()); 0993 nameChanged(); 0994 connect(parent, SIGNAL(resetConfig()), this, SLOT(resetConfig())); 0995 } 0996 0997 DvbConfigObject::~DvbConfigObject() 0998 { 0999 } 1000 1001 void DvbConfigObject::timeoutChanged(int timeout) 1002 { 1003 config->timeout = timeout; 1004 } 1005 1006 void DvbConfigObject::sourceChanged(int index) 1007 { 1008 if (index <= 0) { 1009 // no source selected 1010 nameEdit->setEnabled(false); 1011 config->scanSource.clear(); 1012 } else if ((index <= 5) && (config->getTransmissionType() == DvbConfigBase::DvbT)) { 1013 nameEdit->setEnabled(true); 1014 1015 if (isGen2) { 1016 switch (index - 1) { 1017 case 0: 1018 config->scanSource = QLatin1String("AUTO-T2-Normal"); 1019 break; 1020 case 1: 1021 config->scanSource = QLatin1String("AUTO-T2-Offsets"); 1022 break; 1023 case 2: 1024 config->scanSource = QLatin1String("AUTO-T2-Australia"); 1025 break; 1026 case 3: 1027 config->scanSource = QLatin1String("AUTO-T2-Italy"); 1028 break; 1029 case 4: 1030 config->scanSource = QLatin1String("AUTO-T2-Taiwan"); 1031 break; 1032 } 1033 } else { 1034 switch (index - 1) { 1035 case 0: 1036 config->scanSource = QLatin1String("AUTO-T-Normal"); 1037 break; 1038 case 1: 1039 config->scanSource = QLatin1String("AUTO-T-Offsets"); 1040 break; 1041 case 2: 1042 config->scanSource = QLatin1String("AUTO-T-Australia"); 1043 break; 1044 case 3: 1045 config->scanSource = QLatin1String("AUTO-T-Italy"); 1046 break; 1047 case 4: 1048 config->scanSource = QLatin1String("AUTO-T-Taiwan"); 1049 break; 1050 } 1051 } 1052 } else { 1053 nameEdit->setEnabled(true); 1054 config->scanSource = sourceBox->currentText(); 1055 } 1056 } 1057 1058 void DvbConfigObject::nameChanged() 1059 { 1060 QString name = nameEdit->text(); 1061 1062 if (name.isEmpty()) { 1063 nameEdit->setText(defaultName); 1064 config->name = defaultName; 1065 } else { 1066 config->name = name; 1067 } 1068 } 1069 1070 void DvbConfigObject::resetConfig() 1071 { 1072 timeoutBox->setValue(1500); // FIXME hardcoded 1073 sourceBox->setCurrentIndex(0); 1074 nameEdit->setText(defaultName); 1075 } 1076 1077 DvbSConfigObject::DvbSConfigObject(QWidget *parent_, QBoxLayout *boxLayout, DvbManager *manager, 1078 const QList<DvbConfig> &configs, DvbDevice *device_, bool dvbS2) : QObject(parent_), parent(parent_), device(device_) 1079 { 1080 if (!configs.isEmpty()) { 1081 lnbConfig = new DvbConfigBase(*configs.at(0)); 1082 } else { 1083 lnbConfig = createConfig(0); 1084 } 1085 1086 if (dvbS2) { 1087 sources = manager->getScanSources(DvbManager::DvbS2); 1088 } else { 1089 sources = manager->getScanSources(DvbManager::DvbS); 1090 } 1091 1092 layout = new QGridLayout(); 1093 boxLayout->addLayout(layout); 1094 1095 layout->addWidget(new QLabel(i18n("Tuner timeout (ms):")), 0, 0); 1096 1097 timeoutBox = new QSpinBox(parent); 1098 timeoutBox->setRange(100, 5000); 1099 timeoutBox->setSingleStep(100); 1100 timeoutBox->setValue(lnbConfig->timeout); 1101 layout->addWidget(timeoutBox, 0, 1); 1102 1103 layout->addWidget(new QLabel(i18n("Use Higher LNBf voltage:")), 1104 1, 0); 1105 1106 higherVoltageBox = new QCheckBox(parent); 1107 higherVoltageBox->setTristate(true); 1108 higherVoltageBox->setCheckState((Qt::CheckState)lnbConfig->higherVoltage); 1109 higherVoltageBox->setToolTip(i18n("On some DVB devices, there's an extra control that allows to increase the \n" 1110 "voltage sent to LNBf, in order to compensate for cabling loss. This tri-state\n" 1111 "button defaults to not use it. It may be set to:\n" 1112 "- normal mode (unchecked);\n" 1113 "- higher voltage mode (checked);\n" 1114 "- tristate (don't send the control).")); 1115 layout->addWidget(higherVoltageBox, 1, 1); 1116 1117 layout->addWidget(new QLabel(i18n("Configuration:")), 2, 0); 1118 1119 configBox = new QComboBox(parent); 1120 configBox->addItem(i18n("DiSEqC Switch")); 1121 configBox->addItem(i18n("USALS Rotor")); 1122 configBox->addItem(i18n("Positions Rotor")); 1123 configBox->addItem(i18n("Disable DiSEqC")); 1124 configBox->setCurrentIndex(lnbConfig->configuration); 1125 connect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(configChanged(int))); 1126 layout->addWidget(configBox, 2, 1); 1127 1128 // Diseqc switch 1129 1130 for (int lnbNumber = 0; lnbNumber < 4; ++lnbNumber) { 1131 DvbConfigBase *config; 1132 1133 if (((lnbConfig->configuration == DvbConfigBase::DiseqcSwitch) || 1134 (lnbConfig->configuration == DvbConfigBase::NoDiseqc)) && 1135 (lnbNumber < configs.size())) { 1136 config = new DvbConfigBase(*configs.at(lnbNumber)); 1137 } else { 1138 config = createConfig(lnbNumber); 1139 } 1140 1141 QPushButton *pushButton = new QPushButton(i18n("LNB %1 Settings", lnbNumber + 1), 1142 parent); 1143 if (lnbNumber > 0) 1144 connect(this, &DvbSConfigObject::setDiseqcVisible, 1145 pushButton, &QPushButton::setVisible); 1146 else 1147 connect(this, &DvbSConfigObject::setFirstLnbVisible, 1148 pushButton, &QPushButton::setVisible); 1149 layout->addWidget(pushButton, lnbNumber + 3, 0); 1150 1151 QComboBox *comboBox = new QComboBox(parent); 1152 comboBox->addItem(i18n("No Source")); 1153 comboBox->addItems(sources); 1154 comboBox->setCurrentIndex(sources.indexOf(config->scanSource) + 1); 1155 if (lnbNumber > 0) 1156 connect(this, &DvbSConfigObject::setDiseqcVisible, 1157 comboBox, &QComboBox::setVisible); 1158 else 1159 connect(this, &DvbSConfigObject::setFirstLnbVisible, 1160 comboBox, &QComboBox::setVisible); 1161 layout->addWidget(comboBox, lnbNumber + 3, 1); 1162 1163 diseqcConfigs.append(DvbConfig(config)); 1164 lnbConfigs.append(new DvbSLnbConfigObject(timeoutBox, higherVoltageBox, comboBox, pushButton, 1165 config, device)); 1166 } 1167 1168 // USALS rotor / Positions rotor 1169 1170 QPushButton *pushButton = new QPushButton(i18n("LNB Settings"), parent); 1171 1172 connect(this, &DvbSConfigObject::setRotorVisible, pushButton, 1173 &QPushButton::setVisible); 1174 layout->addWidget(pushButton, 7, 0); 1175 1176 lnbConfigs.append(new DvbSLnbConfigObject(timeoutBox, higherVoltageBox, NULL, pushButton, lnbConfig, device)); 1177 1178 sourceBox = new QComboBox(parent); 1179 sourceBox->addItems(sources); 1180 connect(this, &DvbSConfigObject::setRotorVisible, sourceBox, 1181 &QComboBox::setVisible); 1182 layout->addWidget(sourceBox, 7, 1); 1183 1184 satelliteView = new QTreeWidget(parent); 1185 1186 // Usals rotor 1187 1188 pushButton = new QPushButton(i18n("Add Satellite"), parent); 1189 connect(this, &DvbSConfigObject::setUsalsVisible, pushButton, 1190 &QPushButton::setVisible); 1191 connect(pushButton, SIGNAL(clicked()), this, SLOT(addSatellite())); 1192 layout->addWidget(pushButton, 8, 0, 1, 2); 1193 1194 // Positions rotor 1195 1196 rotorSpinBox = new QSpinBox(parent); 1197 rotorSpinBox->setRange(0, 255); 1198 connect(this, &DvbSConfigObject::setPositionsVisible, rotorSpinBox, 1199 &QSpinBox::setVisible); 1200 layout->addWidget(rotorSpinBox, 9, 0); 1201 1202 pushButton = new QPushButton(i18n("Add Satellite"), parent); 1203 connect(this, &DvbSConfigObject::setPositionsVisible, pushButton, 1204 &QPushButton::setVisible); 1205 connect(pushButton, SIGNAL(clicked()), this, SLOT(addSatellite())); 1206 layout->addWidget(pushButton, 9, 1); 1207 1208 // USALS rotor / Positions rotor 1209 1210 satelliteView->setColumnCount(2); 1211 satelliteView->setHeaderLabels(QStringList() << i18n("Satellite") << i18n("Position")); 1212 satelliteView->setMinimumHeight(100); 1213 satelliteView->setRootIsDecorated(false); 1214 satelliteView->sortByColumn(0, Qt::AscendingOrder); 1215 satelliteView->setSortingEnabled(true); 1216 connect(this, SIGNAL(setRotorVisible(bool)), satelliteView, SLOT(setVisible(bool))); 1217 layout->addWidget(satelliteView, 10, 0, 1, 2); 1218 1219 if ((lnbConfig->configuration == DvbConfigBase::UsalsRotor) || 1220 (lnbConfig->configuration == DvbConfigBase::PositionsRotor)) { 1221 foreach (const DvbConfig &config, configs) { 1222 QStringList stringList; 1223 stringList << config->scanSource << QString::number(config->lnbNumber); 1224 satelliteView->addTopLevelItem(new QTreeWidgetItem(stringList)); 1225 } 1226 } 1227 1228 pushButton = new QPushButton(i18n("Remove Satellite"), parent); 1229 connect(this, &DvbSConfigObject::setRotorVisible, pushButton, 1230 &QPushButton::setVisible); 1231 connect(pushButton, SIGNAL(clicked()), this, SLOT(removeSatellite())); 1232 layout->addWidget(pushButton, 11, 0, 1, 2); 1233 1234 // Latitude/Longitude for USALS rotor 1235 1236 layout = new QGridLayout(); 1237 1238 validPixmap = QIcon::fromTheme(QLatin1String("dialog-ok-apply")).pixmap(22); 1239 invalidPixmap = QIcon::fromTheme(QLatin1String("dialog-cancel")).pixmap(22); 1240 1241 QLabel *label = new QLabel(i18n("Your position:")); 1242 layout->addWidget(label); 1243 connect(this, &DvbSConfigObject::setUsalsVisible, label, 1244 &QLabel::setVisible); 1245 1246 label = new QLabel(i18n("Latitude:")); 1247 layout->addWidget(label, 1, 0); 1248 connect(this, &DvbSConfigObject::setUsalsVisible, label, 1249 &QLabel::setVisible); 1250 1251 label = new QLabel(i18n("[S -90 ... 90 N]")); 1252 layout->addWidget(label, 1, 1); 1253 connect(this, &DvbSConfigObject::setUsalsVisible, label, 1254 &QLabel::setVisible); 1255 1256 latitudeEdit = new QLineEdit(parent); 1257 latitudeEdit->setText(QString::number(lnbConfig->latitude, 'g', 10)); 1258 connect(latitudeEdit, SIGNAL(textChanged(QString)), this, SLOT(latitudeChanged(QString))); 1259 layout->addWidget(latitudeEdit, 1, 2); 1260 connect(this, &DvbSConfigObject::setUsalsVisible, latitudeEdit, 1261 &QLineEdit::setVisible); 1262 1263 latitudeValidLabel = new QLabel(parent); 1264 latitudeValidLabel->setPixmap(validPixmap); 1265 layout->addWidget(latitudeValidLabel, 1, 3); 1266 connect(this, &DvbSConfigObject::setUsalsVisible, latitudeValidLabel, 1267 &QLineEdit::setVisible); 1268 1269 label = new QLabel(i18n("Longitude:")); 1270 layout->addWidget(label, 2, 0); 1271 connect(this, &DvbSConfigObject::setUsalsVisible, label, 1272 &QLabel::setVisible); 1273 1274 label = new QLabel(i18n("[W -180 ... 180 E]")); 1275 layout->addWidget(label, 2, 1); 1276 connect(this, &DvbSConfigObject::setUsalsVisible, label, 1277 &QLabel::setVisible); 1278 1279 longitudeEdit = new QLineEdit(parent); 1280 longitudeEdit->setText(QString::number(lnbConfig->longitude, 'g', 10)); 1281 connect(this, SIGNAL(setUsalsVisible(bool)), longitudeEdit, SLOT(setVisible(bool))); 1282 connect(this, &DvbSConfigObject::setUsalsVisible, longitudeEdit, 1283 &QLineEdit::setVisible); 1284 layout->addWidget(longitudeEdit, 2, 2); 1285 1286 longitudeValidLabel = new QLabel(parent); 1287 longitudeValidLabel->setPixmap(validPixmap); 1288 layout->addWidget(longitudeValidLabel, 2, 3); 1289 boxLayout->addLayout(layout); 1290 connect(this, &DvbSConfigObject::setUsalsVisible, longitudeValidLabel, 1291 &QLineEdit::setVisible); 1292 1293 configChanged(configBox->currentIndex()); 1294 connect(parent, SIGNAL(resetConfig()), this, SLOT(resetConfig())); 1295 } 1296 1297 DvbSConfigObject::~DvbSConfigObject() 1298 { 1299 delete lnbConfig; 1300 } 1301 1302 1303 void DvbSConfigObject::latitudeChanged(const QString &text) 1304 { 1305 bool ok; 1306 toLatitude(text, &ok); 1307 1308 if (ok) { 1309 latitudeValidLabel->setPixmap(validPixmap); 1310 } else { 1311 latitudeValidLabel->setPixmap(invalidPixmap); 1312 } 1313 } 1314 1315 void DvbSConfigObject::longitudeChanged(const QString &text) 1316 { 1317 bool ok; 1318 toLongitude(text, &ok); 1319 1320 if (ok) { 1321 longitudeValidLabel->setPixmap(validPixmap); 1322 } else { 1323 longitudeValidLabel->setPixmap(invalidPixmap); 1324 } 1325 } 1326 1327 1328 double DvbSConfigObject::toLatitude(const QString &text, bool *ok) 1329 { 1330 if (text.isEmpty()) { 1331 *ok = true; 1332 return 0; 1333 } 1334 1335 double value = text.toDouble(ok); 1336 1337 if (qAbs(value) > 90) { 1338 *ok = false; 1339 } 1340 1341 return value; 1342 } 1343 1344 double DvbSConfigObject::toLongitude(const QString &text, bool *ok) 1345 { 1346 if (text.isEmpty()) { 1347 *ok = true; 1348 return 0; 1349 } 1350 1351 double value = text.toDouble(ok); 1352 1353 if (qAbs(value) > 180) { 1354 *ok = false; 1355 } 1356 1357 return value; 1358 } 1359 1360 void DvbSConfigObject::appendConfigs(QList<DvbConfig> &list) 1361 { 1362 int index = configBox->currentIndex(); 1363 1364 if (index == 0 || index == 3) { 1365 // Diseqc switch or No Diseqc 1366 1367 if (index == 3) 1368 diseqcConfigs[0]->configuration = DvbConfigBase::NoDiseqc; 1369 else 1370 diseqcConfigs[0]->configuration = DvbConfigBase::DiseqcSwitch; 1371 1372 list += diseqcConfigs; 1373 } else if ((index == 1) || (index == 2)) { 1374 // Usals rotor / Positions rotor 1375 1376 for (int i = 0;; ++i) { 1377 QTreeWidgetItem *item = satelliteView->topLevelItem(i); 1378 1379 if (item == NULL) { 1380 break; 1381 } 1382 1383 QString satellite = item->text(0); 1384 1385 DvbConfigBase *config = new DvbConfigBase(*lnbConfig); 1386 config->name = satellite; 1387 config->scanSource = satellite; 1388 1389 if (index == 1) { 1390 // USALS rotor 1391 config->configuration = DvbConfigBase::UsalsRotor; 1392 1393 bool latitudeOk; 1394 bool longitudeOk; 1395 1396 double latitude = toLatitude(latitudeEdit->text(), &latitudeOk); 1397 double longitude = toLongitude(longitudeEdit->text(), &longitudeOk); 1398 1399 if (latitudeOk && longitudeOk) { 1400 config->latitude = latitude; 1401 config->longitude = longitude; 1402 } 1403 } else { 1404 // Positions rotor 1405 config->configuration = DvbConfigBase::PositionsRotor; 1406 config->lnbNumber = item->text(1).toInt(); 1407 } 1408 1409 list.append(DvbConfig(config)); 1410 } 1411 } 1412 } 1413 1414 void DvbSConfigObject::configChanged(int index) 1415 { 1416 if (index == 0) { 1417 // Diseqc switch 1418 1419 emit setDiseqcVisible(true); 1420 emit setFirstLnbVisible(true); 1421 emit setRotorVisible(false); 1422 emit setUsalsVisible(false); 1423 emit setPositionsVisible(false); 1424 } else if (index == 1) { 1425 // Usals rotor 1426 1427 satelliteView->hideColumn(1); 1428 1429 emit setDiseqcVisible(false); 1430 emit setFirstLnbVisible(false); 1431 emit setRotorVisible(true); 1432 emit setUsalsVisible(true); 1433 emit setPositionsVisible(false); 1434 } else if (index == 2) { 1435 // Positions rotor 1436 1437 if (satelliteView->isColumnHidden(1)) { 1438 int width = satelliteView->columnWidth(0); 1439 satelliteView->showColumn(1); 1440 satelliteView->setColumnWidth(0, width / 2); 1441 } 1442 1443 emit setDiseqcVisible(false); 1444 emit setFirstLnbVisible(false); 1445 emit setRotorVisible(true); 1446 emit setUsalsVisible(false); 1447 emit setPositionsVisible(true); 1448 } else if (index == 3) { 1449 // No Diseqc switch 1450 1451 emit setDiseqcVisible(false); 1452 emit setFirstLnbVisible(true); 1453 emit setRotorVisible(false); 1454 emit setUsalsVisible(false); 1455 emit setPositionsVisible(false); 1456 } 1457 } 1458 1459 void DvbSConfigObject::addSatellite() 1460 { 1461 QString satellite = sourceBox->currentText(); 1462 QString index = rotorSpinBox->text(); 1463 QStringList stringList = QStringList() << satellite << index; 1464 1465 if (configBox->currentIndex() == 1) { 1466 // USALS rotor 1467 1468 if (satelliteView->findItems(satellite, Qt::MatchExactly).isEmpty()) { 1469 satelliteView->addTopLevelItem(new QTreeWidgetItem(stringList)); 1470 } 1471 } else { 1472 // Positions rotor 1473 1474 QList<QTreeWidgetItem *> items = 1475 satelliteView->findItems(index, Qt::MatchExactly, 1); 1476 1477 if (!items.isEmpty()) { 1478 items.at(0)->setText(0, sourceBox->currentText()); 1479 } else { 1480 satelliteView->addTopLevelItem(new QTreeWidgetItem(stringList)); 1481 } 1482 } 1483 } 1484 1485 void DvbSConfigObject::removeSatellite() 1486 { 1487 qDeleteAll(satelliteView->selectedItems()); 1488 } 1489 1490 void DvbSConfigObject::resetConfig() 1491 { 1492 timeoutBox->setValue(1500); 1493 higherVoltageBox->setChecked(Qt::PartiallyChecked); 1494 configBox->setCurrentIndex(0); 1495 1496 for (int i = 0; i < lnbConfigs.size(); ++i) { 1497 lnbConfigs[i]->resetConfig(); 1498 } 1499 1500 satelliteView->clear(); 1501 } 1502 1503 DvbConfigBase *DvbSConfigObject::createConfig(int lnbNumber) 1504 { 1505 DvbConfigBase *config = new DvbConfigBase(DvbConfigBase::DvbS); 1506 config->timeout = 1500; 1507 config->higherVoltage = Qt::PartiallyChecked; 1508 config->configuration = DvbConfigBase::DiseqcSwitch; 1509 config->lnbNumber = lnbNumber; 1510 config->currentLnb = device->getLnbSatModels().at(0); 1511 config->bpf = 0; 1512 return config; 1513 } 1514 1515 DvbSLnbConfigObject::DvbSLnbConfigObject(QSpinBox *timeoutSpinBox, 1516 QCheckBox *higherVoltageBox, 1517 QComboBox *sourceBox_, 1518 QPushButton *configureButton_, DvbConfigBase *config_, DvbDevice *device_) : QObject(timeoutSpinBox), 1519 sourceBox(sourceBox_), configureButton(configureButton_), config(config_), device(device_) 1520 { 1521 connect(timeoutSpinBox, SIGNAL(valueChanged(int)), this, SLOT(timeoutChanged(int))); 1522 connect(higherVoltageBox, SIGNAL(stateChanged(int)), this, SLOT(higherVoltageChanged(int))); 1523 connect(configureButton, SIGNAL(clicked()), this, SLOT(configure())); 1524 1525 if (sourceBox != NULL) { 1526 connect(sourceBox, SIGNAL(currentIndexChanged(int)), 1527 this, SLOT(sourceChanged(int))); 1528 sourceChanged(sourceBox->currentIndex()); 1529 } 1530 1531 timeoutChanged(timeoutSpinBox->value()); 1532 } 1533 1534 DvbSLnbConfigObject::~DvbSLnbConfigObject() 1535 { 1536 } 1537 1538 void DvbSLnbConfigObject::resetConfig() 1539 { 1540 config->currentLnb = device->getLnbSatModels().at(0); 1541 config->bpf = 0; 1542 1543 if (sourceBox != NULL) { 1544 sourceBox->setCurrentIndex(0); 1545 } 1546 } 1547 1548 void DvbSLnbConfigObject::timeoutChanged(int value) 1549 { 1550 config->timeout = value; 1551 } 1552 1553 void DvbSLnbConfigObject::higherVoltageChanged(int value) 1554 { 1555 config->higherVoltage = value; 1556 } 1557 1558 void DvbSLnbConfigObject::sourceChanged(int index) 1559 { 1560 if (index <= 0) { 1561 // no source selected 1562 configureButton->setEnabled(false); 1563 config->name.clear(); 1564 config->scanSource.clear(); 1565 } else { 1566 configureButton->setEnabled(true); 1567 config->name = sourceBox->currentText(); 1568 config->scanSource = config->name; 1569 } 1570 } 1571 1572 void DvbSLnbConfigObject::configure() 1573 { 1574 QVBoxLayout *mainLayout = new QVBoxLayout(); 1575 1576 dialog = new QDialog(configureButton); 1577 dialog->setAttribute(Qt::WA_DeleteOnClose); 1578 dialog->setWindowTitle(i18n("LNB Settings")); 1579 dialog->setLayout(mainLayout); 1580 1581 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 1582 connect(buttonBox, &QDialogButtonBox::accepted, this, &DvbSLnbConfigObject::dialogAccepted); 1583 connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); 1584 1585 QWidget *mainWidget = new QWidget(dialog); 1586 QGridLayout *gridLayout = new QGridLayout(mainWidget); 1587 mainLayout->addWidget(mainWidget); 1588 1589 lnbSelectionGroup = new QButtonGroup(mainWidget); 1590 lnbSelectionGroup->setExclusive(true); 1591 connect(lnbSelectionGroup, SIGNAL(buttonClicked(int)), this, SLOT(selectType(int))); 1592 1593 int i, size = device->getLnbSatModels().size(); 1594 1595 currentType = -1; 1596 1597 for (i = 0; i < size; i++) { 1598 struct lnbSat lnb = device->getLnbSatModels().at(i); 1599 QRadioButton *radioButton = new QRadioButton(i18nd("libdvbv5", lnb.name.toLocal8Bit().constData()), mainWidget); 1600 mainLayout->addWidget(radioButton); 1601 lnbSelectionGroup->addButton(radioButton, i + 1); 1602 gridLayout->addWidget(radioButton, i % ((size + 1) / 2), i / ((size + 1) / 2)); 1603 1604 if (config->currentLnb.alias.isEmpty() || config->currentLnb.alias == lnb.alias) { 1605 radioButton->setChecked(true); 1606 config->currentLnb = lnb; 1607 currentType = i + 1; 1608 } 1609 } 1610 1611 // shouldn't happen, except if the config file has an invalid LNBf 1612 if (currentType < 0) { 1613 config->currentLnb = device->getLnbSatModels().at(0); 1614 currentType = 1; 1615 } 1616 1617 QFrame *frame = new QFrame(mainWidget); 1618 frame->setFrameShape(QFrame::VLine); 1619 gridLayout->addWidget(frame, 0, 3, 6, 1); 1620 1621 // FIXME: Those are actually the IF frequencies 1622 1623 lowBandLabel = new QLabel(i18n("Low frequency (KHz)"), mainWidget); 1624 gridLayout->addWidget(lowBandLabel, 0, 4); 1625 lowBandSpinBox = new QSpinBox(mainWidget); 1626 gridLayout->addWidget(lowBandSpinBox, 0, 5); 1627 lowBandSpinBox->setRange(0, 15000); 1628 lowBandSpinBox->setValue(config->currentLnb.lowFreq); 1629 lowBandSpinBox->setEnabled(false); 1630 1631 highBandLabel = new QLabel(i18n("High frequency (MHz)"), mainWidget); 1632 gridLayout->addWidget(highBandLabel, 1, 4); 1633 highBandSpinBox = new QSpinBox(mainWidget); 1634 gridLayout->addWidget(highBandSpinBox, 1, 5); 1635 highBandSpinBox->setRange(0, 15000); 1636 highBandSpinBox->setValue(config->currentLnb.highFreq); 1637 highBandSpinBox->setEnabled(false); 1638 1639 switchLabel = new QLabel(i18n("Switch frequency (MHz)"), mainWidget); 1640 gridLayout->addWidget(switchLabel, 2, 4); 1641 switchSpinBox = new QSpinBox(mainWidget); 1642 gridLayout->addWidget(switchSpinBox, 2, 5); 1643 switchSpinBox->setRange(0, 15000); 1644 switchSpinBox->setValue(config->currentLnb.rangeSwitch); 1645 switchSpinBox->setEnabled(false); 1646 1647 lowRangeLabel = new QLabel(i18n("Low range: %1 MHz to %2 MHz", config->currentLnb.freqRange[0].low, config->currentLnb.freqRange[0].high), mainWidget); 1648 gridLayout->addWidget(lowRangeLabel, 3, 4, 1, 2); 1649 1650 highRangeLabel = new QLabel(mainWidget); 1651 gridLayout->addWidget(highRangeLabel, 4, 4, 1, 2); 1652 1653 selectType(currentType); 1654 1655 mainLayout->addWidget(buttonBox); 1656 1657 dialog->setModal(true); 1658 dialog->show(); 1659 1660 } 1661 1662 void DvbSLnbConfigObject::selectType(int type) 1663 { 1664 struct lnbSat lnb = device->getLnbSatModels().at(type - 1); 1665 1666 1667 lowBandSpinBox->setValue(lnb.lowFreq); 1668 if (!lnb.lowFreq) { 1669 lowBandLabel->hide(); 1670 lowBandSpinBox->hide(); 1671 } else { 1672 lowBandLabel->show(); 1673 lowBandSpinBox->show(); 1674 } 1675 1676 highBandSpinBox->setValue(lnb.highFreq); 1677 if (!lnb.highFreq) { 1678 highBandLabel->hide(); 1679 highBandSpinBox->hide(); 1680 } else { 1681 highBandLabel->show(); 1682 highBandSpinBox->show(); 1683 } 1684 1685 switchSpinBox->setValue(lnb.rangeSwitch); 1686 if (!lnb.rangeSwitch) { 1687 switchLabel->hide(); 1688 switchSpinBox->hide(); 1689 } else { 1690 switchLabel->show(); 1691 switchSpinBox->show(); 1692 } 1693 1694 lowRangeLabel->setText(i18n("Low range: %1 MHz to %2 MHz", lnb.freqRange[0].low, lnb.freqRange[0].high)); 1695 1696 if (!lnb.freqRange[1].high) { 1697 if (!lnb.highFreq) { 1698 highRangeLabel->hide(); 1699 } else { 1700 highRangeLabel->setText(i18n("Bandstacked")); 1701 highRangeLabel->show(); 1702 } 1703 } else { 1704 highRangeLabel->setText(i18n("High range: %1 MHz to %2 MHz", lnb.freqRange[1].low, lnb.freqRange[1].high)); 1705 highRangeLabel->show(); 1706 } 1707 1708 currentType = type; 1709 } 1710 1711 void DvbSLnbConfigObject::dialogAccepted() 1712 { 1713 config->currentLnb = device->getLnbSatModels().at(currentType - 1); 1714 qCDebug(logDvb) << "Selected LNBf:" << config->currentLnb.alias; 1715 1716 dialog->accept(); 1717 } 1718 1719 #include "moc_dvbconfigdialog.cpp"