File indexing completed on 2024-05-12 16:23:31

0001 /***************************************************************************
0002  *   Copyright (C) 2005-2017 by Linuxstopmotion contributors;              *
0003  *   see the AUTHORS file for details.                                     *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 #include "devicetab.h"
0021 
0022 #include <algorithm>
0023 #include <memory>
0024 #include <string>
0025 
0026 #include "flexiblelineedit.h"
0027 #include "graphics/icons/close.xpm"
0028 #include "src/domain/domainfacade.h"
0029 #include "src/foundation/preferencestool.h"
0030 #include "src/foundation/logger.h"
0031 #include "src/technical/util.h"
0032 
0033 #include <QHeaderView>
0034 #include <QTableWidget>
0035 #include <QLineEdit>
0036 #include <QPushButton>
0037 #include <QLabel>
0038 #include <QGridLayout>
0039 #include <QGroupBox>
0040 #include <QTextEdit>
0041 
0042 
0043 DeviceTab::DeviceTab(QWidget *parent)
0044     : QWidget(parent)
0045 {
0046     deviceTable          = 0;
0047     addButton            = 0;
0048     removeButton         = 0;
0049     editButton           = 0;
0050     closeChangeBoxButton = 0;
0051     deviceEdit           = 0;
0052     devicePreferences    = 0;
0053     deviceLabel          = 0;
0054     checkTableItem       = 0;
0055     informationText      = 0;
0056 
0057     numAutoDetectedDevices = -1;
0058     makeGUI();
0059 }
0060 
0061 
0062 void DeviceTab::makeGUI()
0063 {
0064     this->setFocusPolicy(Qt::ClickFocus);
0065 
0066     informationText = new QTextEdit;
0067     informationText->setReadOnly(true);
0068     informationText->setHtml(
0069         "<p>" + tr("Below you can set which device Stopmotion should use for grabbing images "
0070         "and displaying video.") + "<br><br>" +
0071         tr("You can select from the auto-detected devices below or add devices yourself. "
0072         "It is not recommended to use devices which is not auto-detected, but feel free to do "
0073         "it if you are an advanced user.") + "<br><br>" +
0074         tr("The selected device is recognized as <b>$VIDEODEVICE</b> under Video Import.") +
0075         "</p>");
0076     informationText->setMinimumWidth(440);
0077     informationText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0078 
0079     QStringList lst;
0080     lst << tr("Name") << tr("Description");
0081 
0082     deviceTable = new QTableWidget;
0083     deviceTable->setColumnCount(2);
0084     deviceTable->setRowCount(0);
0085     deviceTable->setSelectionMode(QAbstractItemView::SingleSelection);
0086     deviceTable->setSelectionBehavior(QAbstractItemView::SelectRows);
0087     deviceTable->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
0088     deviceTable->setHorizontalHeaderLabels(lst);
0089     deviceTable->verticalHeader()->setVisible(false);
0090 
0091     connect(deviceTable, SIGNAL(cellClicked(int, int)), this, SLOT(activeCellChanged(int, int)));
0092     connect(deviceTable, SIGNAL(cellChanged(int, int)), this, SLOT(contentsChanged(int, int)));
0093 
0094     addButton = new QPushButton(tr("&Add"));
0095     addButton->setFocusPolicy( Qt::NoFocus );
0096     connect(addButton, SIGNAL(clicked()), this, SLOT(addDevice()));
0097 
0098     removeButton = new QPushButton(tr("&Remove"));
0099     connect( removeButton, SIGNAL(clicked()), this, SLOT(removeDevice()));
0100 
0101     editButton = new QPushButton(tr("&Edit"));
0102     QObject::connect( editButton, SIGNAL(clicked()), this, SLOT(editDevice()));
0103 
0104     devicePreferences = new QGroupBox;
0105     devicePreferences->setTitle(tr("Video device settings"));
0106     devicePreferences->hide();
0107 
0108     closeChangeBoxButton = new QPushButton;
0109     closeChangeBoxButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
0110     closeChangeBoxButton->setIcon(QPixmap(closeicon));
0111     closeChangeBoxButton->setFlat(true);
0112     connect(closeChangeBoxButton, SIGNAL(clicked()),this, SLOT(closeChangeBox()));
0113 
0114     deviceLabel = new QLabel( tr("Video Device ($VIDEODEVICE): ") );
0115     deviceEdit = new FlexibleLineEdit;
0116     connect(deviceEdit, SIGNAL(textChanged(const QString &)),
0117             this, SLOT(updateDeviceString(const QString &)));
0118 
0119     QVBoxLayout *mainLayout = new QVBoxLayout;
0120     mainLayout->addWidget(informationText);
0121     QVBoxLayout *buttonLayout = new QVBoxLayout;
0122     buttonLayout->setContentsMargins(0, 0, 0, 0);
0123     buttonLayout->setSpacing(2);
0124     buttonLayout->addStretch(1);
0125     buttonLayout->addWidget(addButton);
0126     buttonLayout->addWidget(removeButton);
0127     buttonLayout->addWidget(editButton);
0128     QHBoxLayout *deviceLayout = new QHBoxLayout;
0129     deviceLayout->addWidget(deviceTable);
0130     deviceLayout->addLayout(buttonLayout);
0131     mainLayout->addLayout(deviceLayout);
0132     mainLayout->addWidget(devicePreferences);
0133     setLayout(mainLayout);
0134 
0135     QVBoxLayout *devicePrefsLayout = new QVBoxLayout;
0136     QHBoxLayout *hbLayout = new QHBoxLayout;
0137     hbLayout->setContentsMargins(0, 0, 0, 0);
0138     hbLayout->setSpacing(0);
0139     hbLayout->addStretch(1);
0140     hbLayout->addWidget(closeChangeBoxButton);
0141     devicePrefsLayout->addLayout(hbLayout);
0142     devicePrefsLayout->addWidget(deviceLabel);
0143     devicePrefsLayout->addWidget(deviceEdit);
0144     devicePreferences->setLayout(devicePrefsLayout);
0145 }
0146 
0147 
0148 void DeviceTab::initialize() {
0149     Logger::get().logDebug("Initializing video device settings");
0150     PreferencesTool *pref = PreferencesTool::get();
0151 
0152     std::vector<GrabberDevice> devices = DomainFacade::getFacade()->getGrabberDevices();
0153     numAutoDetectedDevices = devices.size();
0154     deviceTable->setRowCount(numAutoDetectedDevices);
0155 
0156     // Auto-detected devices
0157     for (int i = 0; i < numAutoDetectedDevices; ++i) {
0158         QString name( devices[i].name.c_str() );
0159         QString device( devices[i].device.c_str() );
0160         QString desc(QString("*Autodetected* ") + devices[i].type.c_str() + "-" +
0161             tr("device") + " (" + device + ")");
0162 
0163         QTableWidgetItem *item = new QTableWidgetItem(name);
0164         item->setFlags( item->flags() & (~Qt::ItemIsEditable) );
0165         deviceTable->setItem(i, 0,  item);
0166 
0167         item = new QTableWidgetItem(desc);
0168         item->setFlags( item->flags() & (~Qt::ItemIsEditable) );
0169         deviceTable->setItem(i, 1, item);
0170 
0171         deviceNameStrings.push_back(name);
0172         deviceStrings.push_back(device);
0173         deviceDescriptionStrings.push_back(desc);
0174     }
0175 
0176     // Userdefined devices
0177     int active = pref->getPreference("activeVideoDevice", -1);
0178     int numDevices = pref->getPreference("numDevices", 0);
0179     int numUserDevices = 0;
0180     int newActive = -1;
0181     std::string oldDevice;
0182     std::string oldName;
0183     bool oldWasAutoDetected = false;
0184 
0185     for (int i = 0; i < numDevices; ++i) {
0186         Preference descP(QString("deviceDescription%1").arg(i).toUtf8().constData(),"");
0187         QString desc(descP.get());
0188         Preference nameP(QString("deviceName%1").arg(i).toUtf8().constData(),"");
0189         QString name(nameP.get());
0190         Preference deviceP(QString("device%1").arg(i).toUtf8().constData(),"");
0191         QString device(deviceP.get());
0192         if (active == i) {
0193             oldDevice = device.toStdString();
0194             oldName = name.toStdString();
0195         }
0196 
0197         if ( !desc.startsWith("*Autodetected*") ) {
0198             if (active == i)
0199                 newActive = numUserDevices + numAutoDetectedDevices;
0200             deviceTable->setRowCount( numUserDevices + numAutoDetectedDevices + 1 );
0201             deviceTable->setItem(numUserDevices + numAutoDetectedDevices,
0202                     0, new QTableWidgetItem(name));
0203             deviceTable->setItem(numUserDevices + numAutoDetectedDevices,
0204                     1, new QTableWidgetItem(desc));
0205             ++numUserDevices;
0206 
0207             deviceNameStrings.push_back(name);
0208             deviceStrings.push_back(device);
0209             deviceDescriptionStrings.push_back(desc);
0210         } else if (active == i) {
0211             oldWasAutoDetected = true;
0212         }
0213     }
0214 
0215     if (oldWasAutoDetected && 0 < numAutoDetectedDevices) {
0216         // try to find a reasonable match for the last chosen auto detected
0217         // device
0218         int bestScore = 0;
0219         newActive = numAutoDetectedDevices - 1;
0220         for (int i = 0; i != numAutoDetectedDevices; ++i) {
0221             int score = 0;
0222             if (oldName == devices[i].name)
0223                 score = 2;
0224             if (oldDevice == devices[i].device)
0225                 score += 1;
0226             if (bestScore < score) {
0227                 newActive = i;
0228             }
0229         }
0230     }
0231     if (0 <= newActive)
0232         deviceTable->setCurrentCell(newActive, 0);
0233 }
0234 
0235 
0236 void DeviceTab::apply() {
0237     PreferencesTool *prefs = PreferencesTool::get();
0238 
0239     // Remove old preferences
0240     int numDevices = prefs->getPreference("numDevices", -1);
0241     if (numDevices > 0) {
0242         for (int i = 0; i < numDevices; ++i) {
0243             prefs->removePreference(QString("deviceName%1").arg(i).toUtf8().constData());
0244             prefs->removePreference(QString("deviceDescription%1").arg(i).toUtf8().constData());
0245             prefs->removePreference(QString("device%1").arg(i).toUtf8().constData());
0246         }
0247     }
0248 
0249     // Set new preferences
0250     numDevices = deviceTable->rowCount();
0251     if (numDevices > 0) {
0252         prefs->setPreference("numDevices", numDevices);
0253         prefs->setPreference("activeVideoDevice", deviceTable->currentRow());
0254         for (int i = 0; i < numDevices; ++i) {
0255             prefs->setPreference(QString("deviceName%1").arg(i).toUtf8().constData(),
0256                     deviceTable->item(i, 0)->text().toUtf8().constData());
0257             prefs->setPreference(QString("deviceDescription%1").arg(i).toUtf8().constData(),
0258                     deviceTable->item(i, 1)->text().toUtf8().constData());
0259             prefs->setPreference(QString("device%1").arg(i).toUtf8().constData(),
0260                     deviceStrings[i].toUtf8().constData());
0261         }
0262     } else {
0263         prefs->setPreference("numDevices", -1);
0264         prefs->setPreference("activeVideoDevice", -1);
0265     }
0266 }
0267 
0268 
0269 void DeviceTab::resizeEvent(QResizeEvent *event)
0270 {
0271     contentsChanged(0, 0);
0272     QWidget::resizeEvent(event);
0273 }
0274 
0275 
0276 void DeviceTab::contentsChanged(int, int)
0277 {
0278     deviceTable->resizeColumnsToContents();
0279     int totalWidth = deviceTable->columnWidth(0) + deviceTable->columnWidth(1);
0280     int tableWidth = deviceTable->width() - 5;
0281     if ( totalWidth < tableWidth) {
0282         deviceTable->setColumnWidth( 1, tableWidth - deviceTable->columnWidth(0) );
0283     }
0284 }
0285 
0286 
0287 void DeviceTab::activeCellChanged(int, int)
0288 {
0289     if ( devicePreferences->isVisible() ) {
0290         editDevice();
0291     }
0292 }
0293 
0294 
0295 void DeviceTab::editDevice()
0296 {
0297     int selected = deviceTable->currentRow();
0298     if (selected >= 0) {
0299         deviceEdit->setText(deviceStrings[selected]);
0300         devicePreferences->show();
0301 
0302         // Disables editing of autodetected devices
0303         if (selected < numAutoDetectedDevices) {
0304             deviceEdit->setReadOnly(true);
0305         }
0306         else {
0307             deviceEdit->setReadOnly(false);
0308         }
0309     }
0310 }
0311 
0312 
0313 void DeviceTab::closeChangeBox()
0314 {
0315     devicePreferences->hide();
0316     this->resize(minimumSize());
0317 }
0318 
0319 
0320 void DeviceTab::updateDeviceString(const QString &txt)
0321 {
0322     deviceStrings[deviceTable->currentRow()] = txt;
0323 }
0324 
0325 
0326 void DeviceTab::addDevice()
0327 {
0328     int newRow = deviceTable->rowCount();
0329     deviceTable->setRowCount(newRow + 1);
0330     deviceTable->setItem( newRow, 0, new QTableWidgetItem(QString("")) );
0331     deviceTable->setItem( newRow, 1, new QTableWidgetItem(QString("")) );
0332     deviceTable->setCurrentCell(newRow, 0);
0333 
0334     deviceStrings.push_back("");
0335     deviceNameStrings.push_back("");
0336     deviceDescriptionStrings.push_back("");
0337 }
0338 
0339 
0340 void DeviceTab::removeDevice()
0341 {
0342     int selectedRow = deviceTable->currentRow();
0343     if (selectedRow >= 0 && selectedRow >= numAutoDetectedDevices) {
0344         deviceStrings.erase(deviceStrings.begin() + selectedRow);
0345         deviceNameStrings.erase(deviceNameStrings.begin() + selectedRow);
0346         deviceDescriptionStrings.erase(deviceDescriptionStrings.begin() + selectedRow);
0347         deviceTable->removeRow(selectedRow);
0348         contentsChanged(0, 0);
0349     }
0350 }
0351 
0352 
0353 void DeviceTab::retranslateStrings()
0354 {
0355     informationText->setHtml(
0356         "<p>" + tr("Below you can set which device Stopmotion should use for grabbing images "
0357         "and displaying video.") + "<br><br>" +
0358         tr("You can select from the auto-detected devices below or add devices yourself. "
0359         "It is not recommended to use devices which is not auto-detected, but feel free to do "
0360         "it if you are an advanced user.") + "<br><br>" +
0361         tr("The selected device is recognized as <b>$VIDEODEVICE</b> under Video Import.") +
0362         "</p>");
0363 
0364     QStringList lst;
0365     lst << tr("Name") << tr("Description");
0366     deviceTable->setHorizontalHeaderLabels(lst);
0367 
0368     addButton->setText( tr("&Add") );
0369     removeButton->setText( tr("&Remove") );
0370     editButton->setText( tr("&Edit") );
0371 
0372 
0373     devicePreferences->setTitle(tr("Video device settings"));
0374     deviceLabel->setText( tr("Video Device ($VIDEODEVICE): ") );
0375 }