blob: 4a9e1e6529bf156c25ce68a49a38d56fdfb1283d [file] [log] [blame]
/***************************************************************************
* Copyright (C) 2015-2017 by Savoir-faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* Author: Anthony LĂ©onard <anthony.leonard@savoirfairelinux.com> *
* Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> *
* *
* 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 3 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, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "configurationwidget.h"
#include "ui_configurationwidget.h"
#include <QMessageBox>
#include <QDir>
#include <QStandardPaths>
#include <QFileDialog>
#include <QPropertyAnimation>
#include <QtConcurrent/QtConcurrent>
#include "video/devicemodel.h"
#include "video/channel.h"
#include "video/resolution.h"
#include "video/rate.h"
#include "video/previewmanager.h"
#include "audio/settings.h"
#include "audio/outputdevicemodel.h"
#include "audio/inputdevicemodel.h"
#include "media/recordingmodel.h"
#include "accountserializationadapter.h"
#include "accountstatedelegate.h"
#include "settingskey.h"
#include "utils.h"
#include "pathpassworddialog.h"
#include "photoboothdialog.h"
#include "wizarddialog.h"
#include "accountmodel.h"
#include "protocolmodel.h"
#include "accountdetails.h"
#include "callmodel.h"
#include "ringtonemodel.h"
#include "categorizedhistorymodel.h"
#include "profilemodel.h"
#include "profile.h"
#include "person.h"
#include "winsparkle.h"
#include "deleteaccountdialog.h"
ConfigurationWidget::ConfigurationWidget(QWidget *parent) :
NavWidget(parent),
ui(new Ui::ConfigurationWidget),
accountModel_(&AccountModel::instance()),
deviceModel_(&Video::DeviceModel::instance()),
accountDetails_(new AccountDetails())
{
ui->setupUi(this);
connect(ui->exitSettingsButton, &QPushButton::clicked, this, [=]() {
if (CallModel::instance().getActiveCalls().size() == 0
&& Video::PreviewManager::instance().isPreviewing()) {
Video::PreviewManager::instance().stopPreview();
}
accountModel_->save();
accountDetails_->save();
});
connect(ui->exitSettingsButton, &QPushButton::clicked, this, [=]() {
emit NavigationRequested(ScreenEnum::CallScreen);
});
ui->accountView->setModel(accountModel_);
accountStateDelegate_ = new AccountStateDelegate();
ui->accountView->setItemDelegate(accountStateDelegate_);
// connect delete button to popup trigger
connect(ui->deleteAccountBtn, &QPushButton::clicked, [=](){
auto idx = ui->accountView->currentIndex();
DeleteAccountDialog dialog(idx);
dialog.exec();
});
isLoading_ = true;
ui->deviceBox->setModel(deviceModel_);
connect(deviceModel_, SIGNAL(currentIndexChanged(int)),
this, SLOT(deviceIndexChanged(int)));
AccountModel::instance().selectionModel()->clear();
ui->accountView->setSelectionModel(AccountModel::instance().selectionModel());
connect(ui->accountView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(accountSelected(QItemSelection)));
ui->accountView->setCurrentIndex(accountModel_->index(0));
ui->accountDetailLayout->addWidget(accountDetails_);
ui->accountTypeBox->setModel(accountModel_->protocolModel());
ui->accountTypeBox->setCurrentIndex(ui->accountTypeBox->findText("RING"));
ui->startupBox->setChecked(Utils::CheckStartupLink());
ui->historyDaySettingsSpinBox->setValue(
CategorizedHistoryModel::instance().historyLimit());
ui->closeOrMinCheckBox->setChecked(settings_.value(
SettingsKey::closeOrMinimized).toBool());
ui->notificationCheckBox->setChecked(settings_.value(
SettingsKey::enableNotifications).toBool());
connect(ui->stackedWidget, &QStackedWidget::currentChanged, [](int index) {
if (index == 1
&& CallModel::instance().getActiveCalls().size() == 0) {
Video::PreviewManager::instance().startPreview();
} else {
if (CallModel::instance().getActiveCalls().size() == 0
&& Video::PreviewManager::instance().isPreviewing()) {
Video::PreviewManager::instance().stopPreview();
}
}
});
ui->videoView->setIsFullPreview(true);
auto recordPath = Media::RecordingModel::instance().recordPath();
if (recordPath.isEmpty()) {
recordPath = QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
Media::RecordingModel::instance().setRecordPath(recordPath);
}
ui->recordPath->setText(Media::RecordingModel::instance().recordPath());
ui->alwaysRecordCheckBox->setChecked(Media::RecordingModel::instance().isAlwaysRecording());
connect(ui->alwaysRecordCheckBox, &QCheckBox::clicked, [](bool checked){
Media::RecordingModel::instance().setAlwaysRecording(checked);
});
connect(ui->generalTabButton, &QPushButton::toggled, [=] (bool toggled) {
if (toggled) {
ui->stackedWidget->setCurrentWidget(ui->generalPage);
ui->videoTabButton->setChecked(false);
ui->accountTabButton->setChecked(false);
}
});
connect(ui->videoTabButton, &QPushButton::toggled, [=] (bool toggled) {
if (toggled) {
ui->stackedWidget->setCurrentWidget(ui->videoPage);
ui->accountTabButton->setChecked(false);
ui->generalTabButton->setChecked(false);
}
});
connect(ui->accountTabButton, &QPushButton::toggled, [=] (bool toggled) {
if (toggled) {
ui->stackedWidget->setCurrentWidget(ui->accountPage);
ui->videoTabButton->setChecked(false);
ui->generalTabButton->setChecked(false);
}
});
ui->generalTabButton->setChecked(true);
auto inputModel = Audio::Settings::instance().inputDeviceModel();
auto outputModel = Audio::Settings::instance().outputDeviceModel();
ui->outputComboBox->setModel(outputModel);
ui->inputComboBox->setModel(inputModel);
ui->outputComboBox->setCurrentIndex(outputModel->selectionModel()->currentIndex().row());
ui->inputComboBox->setCurrentIndex(inputModel->selectionModel()->currentIndex().row());
connect(ui->outputComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(outputIndexChanged(int)));
connect(ui->inputComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(inputIndexChanged(int)));
auto profile = ProfileModel::instance().selectedProfile();
ui->avatarButton->setIcon(QPixmap::fromImage(Utils::getCirclePhoto(profile->person()->photo().value<QImage>(), ui->avatarButton->width())));
ui->profileNameEdit->setText(profile->person()->formattedName());
//temporary fix hiding imports buttons
ui->exportButton->hide();
ui->importButton->hide();
ui->intervalUpdateCheckSpinBox->setEnabled(true);
}
void ConfigurationWidget::showPreview()
{
if (ui->stackedWidget->currentIndex() == 1
&& CallModel::instance().getActiveCalls().size() == 0) {
ui->previewUnavailable->hide();
ui->videoView->show();
Video::PreviewManager::instance().startPreview();
} else {
ui->previewUnavailable->show();
ui->videoView->hide();
}
}
void
ConfigurationWidget::showEvent(QShowEvent *event)
{
if (win_sparkle_get_automatic_check_for_updates()) {
ui->autoUpdateCheckBox->setChecked(true);
}
ui->intervalUpdateCheckSpinBox->setValue(win_sparkle_get_update_check_interval() / 86400);
QWidget::showEvent(event);
showPreview();
}
ConfigurationWidget::~ConfigurationWidget()
{
delete ui;
delete accountStateDelegate_;
}
void
ConfigurationWidget::deviceIndexChanged(int index)
{
ui->deviceBox->setCurrentIndex(index);
}
void
ConfigurationWidget::on_deviceBox_currentIndexChanged(int index)
{
if (index < 0)
return;
if (!isLoading_)
deviceModel_->setActive(index);
auto device = deviceModel_->activeDevice();
ui->sizeBox->clear();
isLoading_ = true;
if (device->channelList().size() > 0) {
for (auto resolution : device->channelList()[0]->validResolutions()) {
ui->sizeBox->addItem(resolution->name());
}
}
ui->sizeBox->setCurrentIndex(
device->channelList()[0]->activeResolution()->relativeIndex());
isLoading_ = false;
}
void
ConfigurationWidget::on_sizeBox_currentIndexChanged(int index)
{
auto device = deviceModel_->activeDevice();
if (index < 0)
return;
if (!isLoading_)
device->channelList()[0]->setActiveResolution(
device->channelList()[0]->validResolutions()[index]);
}
void
ConfigurationWidget::accountSelected(QItemSelection itemSel)
{
if (itemSel.size())
accountDetails_->show();
else
accountDetails_->hide();
if (accountConnection_)
disconnect(accountConnection_);
auto account = accountModel_->getAccountByModelIndex(
ui->accountView->currentIndex());
accountDetails_->setAccount(account);
if (account) {
AccountSerializationAdapter adapter(account, accountDetails_);
accountConnection_= connect(account,
SIGNAL(propertyChanged(Account*,QString,QString,QString)),
this,
SLOT(accountPropertyChanged(Account*,QString,QString,QString)));
}
}
void
ConfigurationWidget::accountPropertyChanged(Account* a,
const QString& name,
const QString& newVal,
const QString& oldVal)
{
Q_UNUSED(name)
Q_UNUSED(newVal)
Q_UNUSED(oldVal)
accountDetails_->setAccount(a);
AccountSerializationAdapter adapter(a, accountDetails_);
}
void
ConfigurationWidget::on_addAccountButton_clicked()
{
auto type = ui->accountTypeBox->model()->index(ui->accountTypeBox->currentIndex(), 0);
if (type.data() == "RING") {
WizardDialog dlg(WizardDialog::NEW_ACCOUNT);
dlg.exec();
} else {
auto account = accountModel_->add(tr("New Account"), type);
account->setRingtonePath(Utils::GetRingtonePath());
accountModel_->save();
}
}
void
ConfigurationWidget::on_startupBox_toggled(bool checked)
{
if (checked)
Utils::CreateStartupLink();
else
Utils::DeleteStartupLink();
}
void
ConfigurationWidget::on_clearHistoryButton_clicked()
{
QMessageBox confirmationDialog;
confirmationDialog.setText(tr("Are you sure you want to clear all your history?"));
confirmationDialog.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
auto ret = confirmationDialog.exec();
if (ret == QMessageBox::Ok)
CategorizedHistoryModel::instance().clearAllCollections();
}
void
ConfigurationWidget::on_historyDaySettingsSpinBox_valueChanged(int limit)
{
if (CategorizedHistoryModel::instance().historyLimit() != limit)
CategorizedHistoryModel::instance().setHistoryLimit(limit);
}
void
ConfigurationWidget::on_closeOrMinCheckBox_toggled(bool checked)
{
settings_.setValue(SettingsKey::closeOrMinimized, checked);
}
void
ConfigurationWidget::on_checkUpdateButton_clicked()
{
win_sparkle_check_update_with_ui();
}
void
ConfigurationWidget::on_autoUpdateCheckBox_toggled(bool checked)
{
win_sparkle_set_automatic_check_for_updates(checked);
}
void
ConfigurationWidget::on_intervalUpdateCheckSpinBox_valueChanged(int arg1)
{
win_sparkle_set_update_check_interval(arg1 * 86400);
}
void
ConfigurationWidget::on_stackedWidget_currentChanged(int index)
{
Q_UNUSED(index)
showPreview();
}
void
ConfigurationWidget::on_recordPath_clicked()
{
QString dir = QFileDialog::getExistingDirectory(this, tr("Choose Directory"),
Media::RecordingModel::instance().recordPath(),
QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks);
if (not dir.isEmpty()) {
Media::RecordingModel::instance().setRecordPath(dir);
ui->recordPath->setText(dir);
}
}
void
ConfigurationWidget::outputIndexChanged(int index)
{
auto outputModel = Audio::Settings::instance().outputDeviceModel();
outputModel->selectionModel()->setCurrentIndex(outputModel->index(index), QItemSelectionModel::ClearAndSelect);
}
void
ConfigurationWidget::inputIndexChanged(int index)
{
auto inputModel = Audio::Settings::instance().inputDeviceModel();
inputModel->selectionModel()->setCurrentIndex(inputModel->index(index), QItemSelectionModel::ClearAndSelect);
}
void
ConfigurationWidget::on_importButton_clicked()
{
PathPasswordDialog dlg;
if (dlg.exec() == QDialog::Accepted)
if (AccountModel::instance().importAccounts(dlg.path_, dlg.password_) > 0)
errorDlg_.showMessage(tr("An error occured while importing account."));
}
void
ConfigurationWidget::on_exportButton_clicked()
{
PathPasswordDialog dlg;
dlg.exportMode = true;
if (dlg.exec() == QDialog::Accepted) {
auto func = [](QString path, QString password)
{
AccountModel::instance().exportAccounts(
{AccountModel::instance().selectedAccount()->id()},
path,
password);
};
QtConcurrent::run(func, dlg.path_, dlg.password_);
}
}
void
ConfigurationWidget::on_avatarButton_clicked()
{
PhotoBoothDialog dlg;
dlg.exec();
if (dlg.result() == QDialog::Accepted) {
auto image = QImage(dlg.getOutputFileName());
auto avatar = image.scaled(100, 100, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
ProfileModel::instance().selectedProfile()->person()->setPhoto(avatar);
ProfileModel::instance().selectedProfile()->save();
ui->avatarButton->setIcon(QPixmap::fromImage(Utils::getCirclePhoto(avatar, ui->avatarButton->width())));
}
}
void
ConfigurationWidget::on_profileNameEdit_textEdited(const QString& name)
{
ProfileModel::instance().selectedProfile()->person()->setFormattedName(name);
ProfileModel::instance().selectedProfile()->save();
}
void
ConfigurationWidget::on_notificationCheckBox_toggled(bool checked)
{
settings_.setValue(SettingsKey::enableNotifications, checked);
}