kdenlivesettingsdialog.cpp 71.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/***************************************************************************
 *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
 *                                                                         *
 *   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          *
 ***************************************************************************/

20
#include "kdenlivesettingsdialog.h"
Nicolas Carion's avatar
Nicolas Carion committed
21
#include "clipcreationdialog.h"
Nicolas Carion's avatar
linting  
Nicolas Carion committed
22
#include "core.h"
23
#include "dialogs/profilesdialog.h"
Nicolas Carion's avatar
Nicolas Carion committed
24
#include "encodingprofilesdialog.h"
25
#include "kdenlivesettings.h"
Nicolas Carion's avatar
linting  
Nicolas Carion committed
26
#include "profiles/profilemodel.hpp"
27
#include "profiles/profilerepository.hpp"
Nicolas Carion's avatar
Nicolas Carion committed
28 29
#include "profilesdialog.h"
#include "project/dialogs/profilewidget.h"
30

Vincent Pinon's avatar
Vincent Pinon committed
31 32 33
#ifdef USE_V4L
#include "capture/v4lcapture.h"
#endif
34

Nicolas Carion's avatar
Nicolas Carion committed
35
#include "kdenlive_debug.h"
36
#include "klocalizedstring.h"
37
#include <KLineEdit>
Nicolas Carion's avatar
Nicolas Carion committed
38
#include <KMessageBox>
39
#include <KOpenWithDialog>
Nicolas Carion's avatar
Nicolas Carion committed
40 41
#include <KRun>
#include <KService>
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
42
#include <QAction>
43
#include <QDir>
Akhil K Gangadharan's avatar
Akhil K Gangadharan committed
44 45
#include <QGuiApplication>
#include <QScreen>
46 47 48
#include <QSize>
#include <QThread>
#include <QTimer>
Nicolas Carion's avatar
Nicolas Carion committed
49 50
#include <cstdio>
#include <cstdlib>
Nicolas Carion's avatar
Nicolas Carion committed
51
#include <fcntl.h>
52
#include <unistd.h>
53

54
#ifdef USE_JOGSHUTTLE
55 56
#include "jogshuttle/jogaction.h"
#include "jogshuttle/jogshuttleconfig.h"
57
#include <QStandardPaths>
Nicolas Carion's avatar
Nicolas Carion committed
58
#include <linux/input.h>
59
#endif
60

Nicolas Carion's avatar
Nicolas Carion committed
61
KdenliveSettingsDialog::KdenliveSettingsDialog(QMap<QString, QString> mappable_actions, bool gpuAllowed, QWidget *parent)
62 63 64
    : KConfigDialog(parent, QStringLiteral("settings"), KdenliveSettings::self())
    , m_modified(false)
    , m_shuttleModified(false)
Nicolas Carion's avatar
Nicolas Carion committed
65
    , m_mappable_actions(std::move(mappable_actions))
66
{
67
    KdenliveSettings::setV4l_format(0);
68
    QWidget *p1 = new QWidget;
69
    QFontInfo ftInfo(font());
70
    m_configMisc.setupUi(p1);
71
    m_page1 = addPage(p1, i18n("Misc"));
72
    m_page1->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
73

74
    m_configMisc.kcfg_use_exiftool->setEnabled(!QStandardPaths::findExecutable(QStringLiteral("exiftool")).isEmpty());
75

76 77
    QWidget *p8 = new QWidget;
    m_configProject.setupUi(p8);
78
    m_page8 = addPage(p8, i18n("Project Defaults"));
Nicolas Carion's avatar
Nicolas Carion committed
79
    auto *vbox = new QVBoxLayout;
80 81 82
    m_pw = new ProfileWidget(this);
    vbox->addWidget(m_pw);
    m_configProject.profile_box->setLayout(vbox);
83
    m_configProject.profile_box->setTitle(i18n("Select the default profile (preset)"));
84
    // Select profile
85
    m_pw->loadProfile(KdenliveSettings::default_profile().isEmpty() ? pCore->getCurrentProfile()->path() : KdenliveSettings::default_profile());
86
    connect(m_pw, &ProfileWidget::profileChanged, this, &KdenliveSettingsDialog::slotDialogModified);
87
    m_page8->setIcon(QIcon::fromTheme(QStringLiteral("project-defaults")));
88 89
    m_configProject.projecturl->setMode(KFile::Directory);
    m_configProject.projecturl->setUrl(QUrl::fromLocalFile(KdenliveSettings::defaultprojectfolder()));
90 91 92

    QWidget *p9 = new QWidget;
    m_configProxy.setupUi(p9);
93
    KPageWidgetItem *page9 = addPage(p9, i18n("Proxy Clips"));
94 95 96 97 98 99
    page9->setIcon(QIcon::fromTheme(QStringLiteral("zoom-out")));
    connect(m_configProxy.kcfg_generateproxy, &QAbstractButton::toggled, m_configProxy.kcfg_proxyminsize, &QWidget::setEnabled);
    m_configProxy.kcfg_proxyminsize->setEnabled(KdenliveSettings::generateproxy());
    connect(m_configProxy.kcfg_generateimageproxy, &QAbstractButton::toggled, m_configProxy.kcfg_proxyimageminsize, &QWidget::setEnabled);
    m_configProxy.kcfg_proxyimageminsize->setEnabled(KdenliveSettings::generateimageproxy());
    loadExternalProxyProfiles();
100

101
    QWidget *p3 = new QWidget;
102
    m_configTimeline.setupUi(p3);
103
    m_page3 = addPage(p3, i18n("Timeline"));
104
    m_page3->setIcon(QIcon::fromTheme(QStringLiteral("video-display")));
105
    m_configTimeline.kcfg_trackheight->setMinimum(ftInfo.pixelSize() * 1.5);
106 107 108 109

    QWidget *p2 = new QWidget;
    m_configEnv.setupUi(p2);
    m_configEnv.mltpathurl->setMode(KFile::Directory);
110 111 112 113 114
    m_configEnv.mltpathurl->lineEdit()->setObjectName(QStringLiteral("kcfg_mltpath"));
    m_configEnv.rendererpathurl->lineEdit()->setObjectName(QStringLiteral("kcfg_rendererpath"));
    m_configEnv.ffmpegurl->lineEdit()->setObjectName(QStringLiteral("kcfg_ffmpegpath"));
    m_configEnv.ffplayurl->lineEdit()->setObjectName(QStringLiteral("kcfg_ffplaypath"));
    m_configEnv.ffprobeurl->lineEdit()->setObjectName(QStringLiteral("kcfg_ffprobepath"));
115 116
    int maxThreads = QThread::idealThreadCount();
    m_configEnv.kcfg_mltthreads->setMaximum(maxThreads > 2 ? maxThreads : 8);
117
    m_configEnv.tmppathurl->setMode(KFile::Directory);
118
    m_configEnv.tmppathurl->lineEdit()->setObjectName(QStringLiteral("kcfg_currenttmpfolder"));
119
    m_configEnv.capturefolderurl->setMode(KFile::Directory);
120
    m_configEnv.capturefolderurl->lineEdit()->setObjectName(QStringLiteral("kcfg_capturefolder"));
121
    m_configEnv.capturefolderurl->setEnabled(!KdenliveSettings::capturetoprojectfolder());
Laurent Montel's avatar
Laurent Montel committed
122
    connect(m_configEnv.kcfg_capturetoprojectfolder, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotEnableCaptureFolder);
123 124 125 126
    // Library folder
    m_configEnv.libraryfolderurl->setMode(KFile::Directory);
    m_configEnv.libraryfolderurl->lineEdit()->setObjectName(QStringLiteral("kcfg_libraryfolder"));
    m_configEnv.libraryfolderurl->setEnabled(!KdenliveSettings::librarytodefaultfolder());
127
    m_configEnv.kcfg_librarytodefaultfolder->setToolTip(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/library"));
Laurent Montel's avatar
Laurent Montel committed
128
    connect(m_configEnv.kcfg_librarytodefaultfolder, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotEnableLibraryFolder);
129

130 131 132
    // Mime types
    QStringList mimes = ClipCreationDialog::getExtensions();
    qSort(mimes);
Laurent Montel's avatar
Laurent Montel committed
133
    m_configEnv.supportedmimes->setPlainText(mimes.join(QLatin1Char(' ')));
134

135
    m_page2 = addPage(p2, i18n("Environment"));
136
    m_page2->setIcon(QIcon::fromTheme(QStringLiteral("application-x-executable-script")));
137 138 139

    QWidget *p4 = new QWidget;
    m_configCapture.setupUi(p4);
140
    // Remove ffmpeg tab, unused
141
    m_configCapture.tabWidget->removeTab(0);
142 143 144
    m_configCapture.label->setVisible(false);
    m_configCapture.kcfg_defaultcapture->setVisible(false);
    //m_configCapture.tabWidget->removeTab(2);
145
#ifdef USE_V4L
146

147
    // Video 4 Linux device detection
Laurent Montel's avatar
Laurent Montel committed
148
    for (int i = 0; i < 10; ++i) {
Laurent Montel's avatar
Laurent Montel committed
149
        QString path = QStringLiteral("/dev/video") + QString::number(i);
150
        if (QFile::exists(path)) {
151
            QStringList deviceInfo = V4lCaptureHandler::getDeviceName(path);
152 153 154 155
            if (!deviceInfo.isEmpty()) {
                m_configCapture.kcfg_detectedv4ldevices->addItem(deviceInfo.at(0), path);
                m_configCapture.kcfg_detectedv4ldevices->setItemData(m_configCapture.kcfg_detectedv4ldevices->count() - 1, deviceInfo.at(1), Qt::UserRole + 1);
            }
156 157
        }
    }
158
    connect(m_configCapture.kcfg_detectedv4ldevices, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
159
            &KdenliveSettingsDialog::slotUpdatev4lDevice);
160
    connect(m_configCapture.kcfg_v4l_format, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
161
            &KdenliveSettingsDialog::slotUpdatev4lCaptureProfile);
Laurent Montel's avatar
Laurent Montel committed
162
    connect(m_configCapture.config_v4l, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotEditVideo4LinuxProfile);
163 164

    slotUpdatev4lDevice();
165
#endif
166

167
    m_page4 = addPage(p4, i18n("Capture"));
168
    m_page4->setIcon(QIcon::fromTheme(QStringLiteral("media-record")));
169
    m_configCapture.tabWidget->setCurrentIndex(KdenliveSettings::defaultcapture());
Alberto Villa's avatar
Alberto Villa committed
170
#ifdef Q_WS_MAC
171 172
    m_configCapture.tabWidget->setEnabled(false);
    m_configCapture.kcfg_defaultcapture->setEnabled(false);
Alberto Villa's avatar
Alberto Villa committed
173
    m_configCapture.label->setText(i18n("Capture is not yet available on Mac OS X."));
174
#endif
175

176 177
    QWidget *p5 = new QWidget;
    m_configShuttle.setupUi(p5);
178
#ifdef USE_JOGSHUTTLE
179
    m_configShuttle.toolBtnReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
Laurent Montel's avatar
Laurent Montel committed
180
    connect(m_configShuttle.kcfg_enableshuttle, &QCheckBox::stateChanged, this, &KdenliveSettingsDialog::slotCheckShuttle);
181
    connect(m_configShuttle.shuttledevicelist, SIGNAL(activated(int)), this, SLOT(slotUpdateShuttleDevice(int)));
Laurent Montel's avatar
Laurent Montel committed
182
    connect(m_configShuttle.toolBtnReload, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotReloadShuttleDevices);
183

Nicolas Carion's avatar
Nicolas Carion committed
184
    slotCheckShuttle(static_cast<int>(KdenliveSettings::enableshuttle()));
185
    m_configShuttle.shuttledisabled->hide();
186 187

    // Store the button pointers into an array for easier handling them in the other functions.
188
    // TODO: impl enumerator or live with cut and paste :-)))
189 190
    setupJogshuttleBtns(KdenliveSettings::shuttledevice());
#if 0
191 192 193 194 195
    m_shuttle_buttons.push_back(m_configShuttle.shuttle1);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle2);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle3);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle4);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle5);
196 197 198 199 200
    m_shuttle_buttons.push_back(m_configShuttle.shuttle6);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle7);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle8);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle9);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle10);
201 202 203 204 205
    m_shuttle_buttons.push_back(m_configShuttle.shuttle11);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle12);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle13);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle14);
    m_shuttle_buttons.push_back(m_configShuttle.shuttle15);
206
#endif
207

Nicolas Carion's avatar
Nicolas Carion committed
208
#else  /* ! USE_JOGSHUTTLE */
209 210 211
    m_configShuttle.kcfg_enableshuttle->hide();
    m_configShuttle.kcfg_enableshuttle->setDisabled(true);
#endif /* USE_JOGSHUTTLE */
212
    m_page5 = addPage(p5, i18n("JogShuttle"));
213
    m_page5->setIcon(QIcon::fromTheme(QStringLiteral("jog-dial")));
214

215 216
    QWidget *p6 = new QWidget;
    m_configSdl.setupUi(p6);
217
    m_configSdl.reload_blackmagic->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
Laurent Montel's avatar
Laurent Montel committed
218
    connect(m_configSdl.reload_blackmagic, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotReloadBlackMagic);
219

Nicolas Carion's avatar
Nicolas Carion committed
220
    // m_configSdl.kcfg_openglmonitors->setHidden(true);
221

222
    m_page6 = addPage(p6, i18n("Playback"));
223
    m_page6->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
224

225 226
    QWidget *p7 = new QWidget;
    m_configTranscode.setupUi(p7);
227
    m_page7 = addPage(p7, i18n("Transcode"));
228
    m_page7->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
229

Laurent Montel's avatar
Laurent Montel committed
230 231 232 233
    connect(m_configTranscode.button_add, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotAddTranscode);
    connect(m_configTranscode.button_delete, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotDeleteTranscode);
    connect(m_configTranscode.profiles_list, &QListWidget::itemChanged, this, &KdenliveSettingsDialog::slotDialogModified);
    connect(m_configTranscode.profiles_list, &QListWidget::currentRowChanged, this, &KdenliveSettingsDialog::slotSetTranscodeProfile);
234

Laurent Montel's avatar
Laurent Montel committed
235 236 237 238 239
    connect(m_configTranscode.profile_name, &QLineEdit::textChanged, this, &KdenliveSettingsDialog::slotEnableTranscodeUpdate);
    connect(m_configTranscode.profile_description, &QLineEdit::textChanged, this, &KdenliveSettingsDialog::slotEnableTranscodeUpdate);
    connect(m_configTranscode.profile_extension, &QLineEdit::textChanged, this, &KdenliveSettingsDialog::slotEnableTranscodeUpdate);
    connect(m_configTranscode.profile_parameters, &QPlainTextEdit::textChanged, this, &KdenliveSettingsDialog::slotEnableTranscodeUpdate);
    connect(m_configTranscode.profile_audioonly, &QCheckBox::stateChanged, this, &KdenliveSettingsDialog::slotEnableTranscodeUpdate);
240

Laurent Montel's avatar
Laurent Montel committed
241
    connect(m_configTranscode.button_update, &QAbstractButton::pressed, this, &KdenliveSettingsDialog::slotUpdateTranscodingProfile);
242

243
    m_configTranscode.profile_parameters->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
Alberto Villa's avatar
Alberto Villa committed
244

Laurent Montel's avatar
Laurent Montel committed
245 246
    connect(m_configEnv.kp_image, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotEditImageApplication);
    connect(m_configEnv.kp_audio, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotEditAudioApplication);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
247

248
    loadEncodingProfiles();
249

250
    connect(m_configSdl.kcfg_audio_driver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
251
            &KdenliveSettingsDialog::slotCheckAlsaDriver);
252
    connect(m_configSdl.kcfg_audio_backend, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
253
            &KdenliveSettingsDialog::slotCheckAudioBackend);
254
    initDevices();
255
    connect(m_configCapture.kcfg_grab_capture_type, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
256
            &KdenliveSettingsDialog::slotUpdateGrabRegionStatus);
257

258
    slotUpdateGrabRegionStatus();
259
    loadTranscodeProfiles();
260

261
    // decklink profile
262
    QAction *act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure profiles"), this);
263
    act->setData(4);
Laurent Montel's avatar
Laurent Montel committed
264
    connect(act, &QAction::triggered, this, &KdenliveSettingsDialog::slotManageEncodingProfile);
265
    m_configCapture.decklink_manageprofile->setDefaultAction(act);
266
    m_configCapture.decklink_showprofileinfo->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
267 268 269
    m_configCapture.decklink_parameters->setVisible(false);
    m_configCapture.decklink_parameters->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 4);
    m_configCapture.decklink_parameters->setPlainText(KdenliveSettings::decklink_parameters());
270
    connect(m_configCapture.kcfg_decklink_profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
271
            &KdenliveSettingsDialog::slotUpdateDecklinkProfile);
Laurent Montel's avatar
Laurent Montel committed
272
    connect(m_configCapture.decklink_showprofileinfo, &QAbstractButton::clicked, m_configCapture.decklink_parameters, &QWidget::setVisible);
273

274
    // ffmpeg profile
275
    m_configCapture.v4l_showprofileinfo->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
276 277 278
    m_configCapture.v4l_parameters->setVisible(false);
    m_configCapture.v4l_parameters->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 4);
    m_configCapture.v4l_parameters->setPlainText(KdenliveSettings::v4l_parameters());
279

280
    act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure profiles"), this);
281
    act->setData(2);
Laurent Montel's avatar
Laurent Montel committed
282
    connect(act, &QAction::triggered, this, &KdenliveSettingsDialog::slotManageEncodingProfile);
283
    m_configCapture.v4l_manageprofile->setDefaultAction(act);
284
    connect(m_configCapture.kcfg_v4l_profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
285
            &KdenliveSettingsDialog::slotUpdateV4lProfile);
Laurent Montel's avatar
Laurent Montel committed
286
    connect(m_configCapture.v4l_showprofileinfo, &QAbstractButton::clicked, m_configCapture.v4l_parameters, &QWidget::setVisible);
287

288
    // screen grab profile
289
    m_configCapture.grab_showprofileinfo->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
290 291 292
    m_configCapture.grab_parameters->setVisible(false);
    m_configCapture.grab_parameters->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 4);
    m_configCapture.grab_parameters->setPlainText(KdenliveSettings::grab_parameters());
293
    act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure profiles"), this);
294
    act->setData(3);
Laurent Montel's avatar
Laurent Montel committed
295
    connect(act, &QAction::triggered, this, &KdenliveSettingsDialog::slotManageEncodingProfile);
296
    m_configCapture.grab_manageprofile->setDefaultAction(act);
297
    connect(m_configCapture.kcfg_grab_profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
298
            &KdenliveSettingsDialog::slotUpdateGrabProfile);
Laurent Montel's avatar
Laurent Montel committed
299
    connect(m_configCapture.grab_showprofileinfo, &QAbstractButton::clicked, m_configCapture.grab_parameters, &QWidget::setVisible);
Alberto Villa's avatar
Alberto Villa committed
300

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
    // audio capture channels
    m_configCapture.audiocapturechannels->clear();
    m_configCapture.audiocapturechannels->addItem(i18n("Mono (1 channel)"), 1);
    m_configCapture.audiocapturechannels->addItem(i18n("Stereo (2 channels)"), 2);

    int channelsIndex = m_configCapture.audiocapturechannels->findData(KdenliveSettings::audiocapturechannels());
    m_configCapture.audiocapturechannels->setCurrentIndex(qMax(channelsIndex, 0));
    connect(m_configCapture.audiocapturechannels, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotUpdateAudioCaptureChannels);

    // audio capture sample rate
    m_configCapture.audiocapturesamplerate->clear();
    m_configCapture.audiocapturesamplerate->addItem(i18n("44100 Hz"), 44100);
    m_configCapture.audiocapturesamplerate->addItem(i18n("48000 Hz"), 48000);

    int sampleRateIndex = m_configCapture.audiocapturesamplerate->findData(KdenliveSettings::audiocapturesamplerate());
    m_configCapture.audiocapturesamplerate->setCurrentIndex(qMax(sampleRateIndex, 0));
    connect(m_configCapture.audiocapturesamplerate, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotUpdateAudioCaptureSampleRate);

    m_configCapture.labelNoAudioDevices->setVisible(false);

323
    // Timeline preview
324
    act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure profiles"), this);
325
    act->setData(1);
Laurent Montel's avatar
Laurent Montel committed
326
    connect(act, &QAction::triggered, this, &KdenliveSettingsDialog::slotManageEncodingProfile);
327
    m_configProject.preview_manageprofile->setDefaultAction(act);
328
    connect(m_configProject.kcfg_preview_profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
329
            &KdenliveSettingsDialog::slotUpdatePreviewProfile);
Laurent Montel's avatar
Laurent Montel committed
330
    connect(m_configProject.preview_showprofileinfo, &QAbstractButton::clicked, m_configProject.previewparams, &QWidget::setVisible);
331 332 333
    m_configProject.previewparams->setVisible(false);
    m_configProject.previewparams->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 3);
    m_configProject.previewparams->setPlainText(KdenliveSettings::previewparams());
334
    m_configProject.preview_showprofileinfo->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
335
    m_configProject.preview_showprofileinfo->setToolTip(i18n("Show default timeline preview parameters"));
336
    m_configProject.preview_manageprofile->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
337 338
    m_configProject.preview_manageprofile->setToolTip(i18n("Manage timeline preview profiles"));
    m_configProject.kcfg_preview_profile->setToolTip(i18n("Select default timeline preview profile"));
339

340
    // proxy profile stuff
341 342 343 344 345 346 347 348
    m_configProxy.proxy_showprofileinfo->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
    m_configProxy.proxy_showprofileinfo->setToolTip(i18n("Show default profile parameters"));
    m_configProxy.proxy_manageprofile->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
    m_configProxy.proxy_manageprofile->setToolTip(i18n("Manage proxy profiles"));
    m_configProxy.kcfg_proxy_profile->setToolTip(i18n("Select default proxy profile"));
    m_configProxy.proxyparams->setVisible(false);
    m_configProxy.proxyparams->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 3);
    m_configProxy.proxyparams->setPlainText(KdenliveSettings::proxyparams());
349

350
    act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure profiles"), this);
351
    act->setData(0);
Laurent Montel's avatar
Laurent Montel committed
352
    connect(act, &QAction::triggered, this, &KdenliveSettingsDialog::slotManageEncodingProfile);
353
    m_configProxy.proxy_manageprofile->setDefaultAction(act);
354

355
    connect(m_configProxy.proxy_showprofileinfo, &QAbstractButton::clicked, m_configProxy.proxyparams, &QWidget::setVisible);
356
    connect(m_configProxy.kcfg_proxy_profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
Nicolas Carion's avatar
Nicolas Carion committed
357
            &KdenliveSettingsDialog::slotUpdateProxyProfile);
358 359 360

    slotUpdateProxyProfile(-1);
    slotUpdateV4lProfile(-1);
361
    slotUpdateGrabProfile(-1);
362
    slotUpdateDecklinkProfile(-1);
363

364 365
    // enable GPU accel only if Movit is found
    m_configSdl.kcfg_gpu_accel->setEnabled(gpuAllowed);
366
    m_configSdl.kcfg_gpu_accel->setToolTip(i18n("GPU processing needs MLT compiled with Movit and Rtaudio modules"));
Alberto Villa's avatar
Alberto Villa committed
367

368 369
    getBlackMagicDeviceList(m_configCapture.kcfg_decklink_capturedevice);
    if (!getBlackMagicOutputDeviceList(m_configSdl.kcfg_blackmagic_output_device)) {
370
        // No blackmagic card found
371
        m_configSdl.kcfg_external_display->setEnabled(false);
372
    }
373 374
    
    initAudioRecDevice();
Akhil K Gangadharan's avatar
Akhil K Gangadharan committed
375

376
    // Config dialog size
Akhil K Gangadharan's avatar
Akhil K Gangadharan committed
377 378 379 380
    KSharedConfigPtr config = KSharedConfig::openConfig();
    KConfigGroup settingsGroup(config, "settings");
    QSize optimalSize;

381 382
    if (!settingsGroup.exists() || !settingsGroup.hasKey("dialogSize")) {
        const QSize screenSize = (QGuiApplication::primaryScreen()->availableSize() * 0.9);
Akhil K Gangadharan's avatar
Akhil K Gangadharan committed
383 384
        const QSize targetSize = QSize(1024, 700);
        optimalSize = targetSize.boundedTo(screenSize);
385 386
    } else {
        optimalSize = settingsGroup.readEntry("dialogSize", QVariant(size())).toSize();
Akhil K Gangadharan's avatar
Akhil K Gangadharan committed
387 388
    }
    resize(optimalSize);
389 390
}

391
// static
392
bool KdenliveSettingsDialog::getBlackMagicDeviceList(QComboBox *devicelist, bool force)
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
{
    if (!force && !KdenliveSettings::decklink_device_found()) {
        return false;
    }
    Mlt::Profile profile;
    Mlt::Producer bm(profile, "decklink");
    int found_devices = 0;
    if (bm.is_valid()) {
        bm.set("list_devices", 1);
        found_devices = bm.get_int("devices");
    } else {
        KdenliveSettings::setDecklink_device_found(false);
    }
    if (found_devices <= 0) {
        devicelist->setEnabled(false);
        return false;
    }
    KdenliveSettings::setDecklink_device_found(true);
    for (int i = 0; i < found_devices; ++i) {
        char *tmp = qstrdup(QStringLiteral("device.%1").arg(i).toUtf8().constData());
        devicelist->addItem(bm.get(tmp));
        delete[] tmp;
    }
    return true;
}

419 420 421 422
// static
bool KdenliveSettingsDialog::initAudioRecDevice()
{
    QStringList audioDevices = pCore->getAudioCaptureDevices();
423 424 425 426

    //show a hint to the user to know what to check for in case the device list are empty (common issue)
    m_configCapture.labelNoAudioDevices->setVisible(audioDevices.empty());

427 428 429 430 431 432 433 434 435 436 437 438 439 440
    m_configCapture.kcfg_defaultaudiocapture->addItems(audioDevices);
    connect(m_configCapture.kcfg_defaultaudiocapture, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [&]() {
        QString currentDevice = m_configCapture.kcfg_defaultaudiocapture->currentText();
        KdenliveSettings::setDefaultaudiocapture(currentDevice);
    });
    QString selectedDevice = KdenliveSettings::defaultaudiocapture();
    int selectedIndex = m_configCapture.kcfg_defaultaudiocapture->findText(selectedDevice);
    if (!selectedDevice.isEmpty() && selectedIndex > -1) {
        m_configCapture.kcfg_defaultaudiocapture->setCurrentIndex(selectedIndex);
    }
    return true;
}

bool KdenliveSettingsDialog::getBlackMagicOutputDeviceList(QComboBox *devicelist, bool force)
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
{
    if (!force && !KdenliveSettings::decklink_device_found()) {
        return false;
    }
    Mlt::Profile profile;
    Mlt::Consumer bm(profile, "decklink");
    int found_devices = 0;
    if (bm.is_valid()) {
        bm.set("list_devices", 1);
        found_devices = bm.get_int("devices");
    } else {
        KdenliveSettings::setDecklink_device_found(false);
    }
    if (found_devices <= 0) {
        devicelist->setEnabled(false);
        return false;
    }
    KdenliveSettings::setDecklink_device_found(true);
    for (int i = 0; i < found_devices; ++i) {
        char *tmp = qstrdup(QStringLiteral("device.%1").arg(i).toUtf8().constData());
        devicelist->addItem(bm.get(tmp));
        delete[] tmp;
    }
    devicelist->addItem(QStringLiteral("test"));
    return true;
}

Laurent Montel's avatar
Laurent Montel committed
468
void KdenliveSettingsDialog::setupJogshuttleBtns(const QString &device)
469
{
470
    QList<QComboBox *> list;
471
    QList<QLabel *> list1;
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488

    list << m_configShuttle.shuttle1;
    list << m_configShuttle.shuttle2;
    list << m_configShuttle.shuttle3;
    list << m_configShuttle.shuttle4;
    list << m_configShuttle.shuttle5;
    list << m_configShuttle.shuttle6;
    list << m_configShuttle.shuttle7;
    list << m_configShuttle.shuttle8;
    list << m_configShuttle.shuttle9;
    list << m_configShuttle.shuttle10;
    list << m_configShuttle.shuttle11;
    list << m_configShuttle.shuttle12;
    list << m_configShuttle.shuttle13;
    list << m_configShuttle.shuttle14;
    list << m_configShuttle.shuttle15;

Nicolas Carion's avatar
Nicolas Carion committed
489 490 491 492 493 494 495 496
    list1 << m_configShuttle.label_2;  // #1
    list1 << m_configShuttle.label_4;  // #2
    list1 << m_configShuttle.label_3;  // #3
    list1 << m_configShuttle.label_7;  // #4
    list1 << m_configShuttle.label_5;  // #5
    list1 << m_configShuttle.label_6;  // #6
    list1 << m_configShuttle.label_8;  // #7
    list1 << m_configShuttle.label_9;  // #8
497 498 499 500 501 502 503 504
    list1 << m_configShuttle.label_10; // #9
    list1 << m_configShuttle.label_11; // #10
    list1 << m_configShuttle.label_12; // #11
    list1 << m_configShuttle.label_13; // #12
    list1 << m_configShuttle.label_14; // #13
    list1 << m_configShuttle.label_15; // #14
    list1 << m_configShuttle.label_16; // #15

505
    for (int i = 0; i < list.count(); ++i) {
506 507 508
        list[i]->hide();
        list1[i]->hide();
    }
509
#ifdef USE_JOGSHUTTLE
510 511 512
    if (!m_configShuttle.kcfg_enableshuttle->isChecked()) {
        return;
    }
513 514
    int keysCount = JogShuttle::keysCount(device);

515
    for (int i = 0; i < keysCount; ++i) {
516 517 518 519 520 521 522 523 524
        m_shuttle_buttons.push_back(list[i]);
        list[i]->show();
        list1[i]->show();
    }

    // populate the buttons with the current configuration. The items are sorted
    // according to the user-selected language, so they do not appear in random order.
    QMap<QString, QString> mappable_actions(m_mappable_actions);
    QList<QString> action_names = mappable_actions.keys();
525
    QList<QString>::Iterator iter = action_names.begin();
Nicolas Carion's avatar
Nicolas Carion committed
526
    // qCDebug(KDENLIVE_LOG) << "::::::::::::::::";
527
    while (iter != action_names.end()) {
Nicolas Carion's avatar
Nicolas Carion committed
528
        // qCDebug(KDENLIVE_LOG) << *iter;
529 530 531
        ++iter;
    }

Nicolas Carion's avatar
Nicolas Carion committed
532
    // qCDebug(KDENLIVE_LOG) << "::::::::::::::::";
533

534
    qSort(action_names);
535 536
    iter = action_names.begin();
    while (iter != action_names.end()) {
Nicolas Carion's avatar
Nicolas Carion committed
537
        // qCDebug(KDENLIVE_LOG) << *iter;
538 539
        ++iter;
    }
Nicolas Carion's avatar
Nicolas Carion committed
540
    // qCDebug(KDENLIVE_LOG) << "::::::::::::::::";
541 542 543 544 545

    // Here we need to compute the action_id -> index-in-action_names. We iterate over the
    // action_names, as the sorting may depend on the user-language.
    QStringList actions_map = JogShuttleConfig::actionMap(KdenliveSettings::shuttlebuttons());
    QMap<QString, int> action_pos;
Nicolas Carion's avatar
Nicolas Carion committed
546
    for (const QString &action_id : actions_map) {
547 548 549 550 551 552 553 554 555 556
        // This loop find out at what index is the string that would map to the action_id.
        for (int i = 0; i < action_names.size(); ++i) {
            if (mappable_actions[action_names.at(i)] == action_id) {
                action_pos[action_id] = i;
                break;
            }
        }
    }

    int i = 0;
557
    for (QComboBox *button : m_shuttle_buttons) {
558 559 560
        button->addItems(action_names);
        connect(button, SIGNAL(activated(int)), this, SLOT(slotShuttleModified()));
        ++i;
561
        if (i < actions_map.size()) {
562
            button->setCurrentIndex(action_pos[actions_map[i]]);
563
        }
564
    }
565
#endif
566 567
}

Nicolas Carion's avatar
Nicolas Carion committed
568
KdenliveSettingsDialog::~KdenliveSettingsDialog() = default;
569

570
void KdenliveSettingsDialog::slotUpdateGrabRegionStatus()
571
{
572
    m_configCapture.region_group->setHidden(m_configCapture.kcfg_grab_capture_type->currentIndex() != 1);
573
}
574

575 576 577 578 579
void KdenliveSettingsDialog::slotEnableCaptureFolder()
{
    m_configEnv.capturefolderurl->setEnabled(!m_configEnv.kcfg_capturetoprojectfolder->isChecked());
}

580 581 582 583 584
void KdenliveSettingsDialog::slotEnableLibraryFolder()
{
    m_configEnv.libraryfolderurl->setEnabled(!m_configEnv.kcfg_librarytodefaultfolder->isChecked());
}

585 586
void KdenliveSettingsDialog::initDevices()
{
587 588
    // Fill audio drivers
    m_configSdl.kcfg_audio_driver->addItem(i18n("Automatic"), QString());
589
#ifndef Q_WS_MAC
590 591
    m_configSdl.kcfg_audio_driver->addItem(i18n("OSS"), "dsp");
    m_configSdl.kcfg_audio_driver->addItem(i18n("ALSA"), "alsa");
592
    m_configSdl.kcfg_audio_driver->addItem(i18n("PulseAudio"), "pulse");
593 594 595
    m_configSdl.kcfg_audio_driver->addItem(i18n("OSS with DMA access"), "dma");
    m_configSdl.kcfg_audio_driver->addItem(i18n("Esound daemon"), "esd");
    m_configSdl.kcfg_audio_driver->addItem(i18n("ARTS daemon"), "artsc");
596
#endif
597

598
    if (!KdenliveSettings::audiodrivername().isEmpty())
599
        for (int i = 1; i < m_configSdl.kcfg_audio_driver->count(); ++i) {
600 601
            if (m_configSdl.kcfg_audio_driver->itemData(i).toString() == KdenliveSettings::audiodrivername()) {
                m_configSdl.kcfg_audio_driver->setCurrentIndex(i);
Nicolas Carion's avatar
Nicolas Carion committed
602
                KdenliveSettings::setAudio_driver((uint)i);
603 604
            }
        }
605

606
    // Fill the list of audio playback / recording devices
607
    m_configSdl.kcfg_audio_device->addItem(i18n("Default"), QString());
608
    m_configCapture.kcfg_v4l_alsadevice->addItem(i18n("Default"), "default");
609
    if (!QStandardPaths::findExecutable(QStringLiteral("aplay")).isEmpty()) {
610
        m_readProcess.setOutputChannelMode(KProcess::OnlyStdoutChannel);
611
        m_readProcess.setProgram(QStringLiteral("aplay"), QStringList() << QStringLiteral("-l"));
Laurent Montel's avatar
Laurent Montel committed
612
        connect(&m_readProcess, &KProcess::readyReadStandardOutput, this, &KdenliveSettingsDialog::slotReadAudioDevices);
613 614 615
        m_readProcess.execute(5000);
    } else {
        // If aplay is not installed on the system, parse the /proc/asound/pcm file
616
        QFile file(QStringLiteral("/proc/asound/pcm"));
617
        if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
618
            QTextStream stream(&file);
619
            QString line = stream.readLine();
620
            QString deviceId;
621
            while (!line.isNull()) {
622
                if (line.contains(QStringLiteral("playback"))) {
Laurent Montel's avatar
Laurent Montel committed
623
                    deviceId = line.section(QLatin1Char(':'), 0, 0);
Nicolas Carion's avatar
Nicolas Carion committed
624 625 626
                    m_configSdl.kcfg_audio_device->addItem(line.section(QLatin1Char(':'), 1, 1), QStringLiteral("plughw:%1,%2")
                                                                                                     .arg(deviceId.section(QLatin1Char('-'), 0, 0).toInt())
                                                                                                     .arg(deviceId.section(QLatin1Char('-'), 1, 1).toInt()));
627
                }
628
                if (line.contains(QStringLiteral("capture"))) {
Laurent Montel's avatar
Laurent Montel committed
629
                    deviceId = line.section(QLatin1Char(':'), 0, 0);
Nicolas Carion's avatar
Nicolas Carion committed
630 631 632
                    m_configCapture.kcfg_v4l_alsadevice->addItem(
                        line.section(QLatin1Char(':'), 1, 1).simplified(),
                        QStringLiteral("hw:%1,%2").arg(deviceId.section(QLatin1Char('-'), 0, 0).toInt()).arg(deviceId.section(QLatin1Char('-'), 1, 1).toInt()));
633
                }
634
                line = stream.readLine();
635
            }
636
            file.close();
637 638 639
        } else {
            qCDebug(KDENLIVE_LOG) << " / / / /CANNOT READ PCM";
        }
640
    }
641

642 643
    // Add pulseaudio capture option
    m_configCapture.kcfg_v4l_alsadevice->addItem(i18n("PulseAudio"), "pulse");
644

645 646
    if (!KdenliveSettings::audiodevicename().isEmpty()) {
        // Select correct alsa device
647 648 649
        int ix = m_configSdl.kcfg_audio_device->findData(KdenliveSettings::audiodevicename());
        m_configSdl.kcfg_audio_device->setCurrentIndex(ix);
        KdenliveSettings::setAudio_device(ix);
650
    }
Alberto Villa's avatar
Alberto Villa committed
651

652 653 654 655 656 657 658
    if (!KdenliveSettings::v4l_alsadevicename().isEmpty()) {
        // Select correct alsa device
        int ix = m_configCapture.kcfg_v4l_alsadevice->findData(KdenliveSettings::v4l_alsadevicename());
        m_configCapture.kcfg_v4l_alsadevice->setCurrentIndex(ix);
        KdenliveSettings::setV4l_alsadevice(ix);
    }

659
    m_configSdl.kcfg_audio_backend->addItem(i18n("SDL"), KdenliveSettings::sdlAudioBackend());
660 661 662 663 664 665 666
    m_configSdl.kcfg_audio_backend->addItem(i18n("RtAudio"), "rtaudio");

    if (!KdenliveSettings::audiobackend().isEmpty()) {
        int ix = m_configSdl.kcfg_audio_backend->findData(KdenliveSettings::audiobackend());
        m_configSdl.kcfg_audio_backend->setCurrentIndex(ix);
        KdenliveSettings::setAudio_backend(ix);
    }
667
    m_configSdl.group_sdl->setEnabled(KdenliveSettings::audiobackend().startsWith(QLatin1String("sdl_audio")));
668

669
    loadCurrentV4lProfileInfo();
670 671
}

672 673
void KdenliveSettingsDialog::slotReadAudioDevices()
{
674
    QString result = QString(m_readProcess.readAllStandardOutput());
Nicolas Carion's avatar
Nicolas Carion committed
675 676
    // qCDebug(KDENLIVE_LOG) << "// / / / / / READING APLAY: ";
    // qCDebug(KDENLIVE_LOG) << result;
Laurent Montel's avatar
Laurent Montel committed
677
    const QStringList lines = result.split(QLatin1Char('\n'));
678
    for (const QString &devicestr : lines) {
Laurent Montel's avatar
Laurent Montel committed
679
        ////qCDebug(KDENLIVE_LOG) << "// READING LINE: " << data;
680 681 682
        if (!devicestr.startsWith(QLatin1Char(' ')) && devicestr.count(QLatin1Char(':')) > 1) {
            QString card = devicestr.section(QLatin1Char(':'), 0, 0).section(QLatin1Char(' '), -1);
            QString device = devicestr.section(QLatin1Char(':'), 1, 1).section(QLatin1Char(' '), -1);
683
            m_configSdl.kcfg_audio_device->addItem(devicestr.section(QLatin1Char(':'), -1).simplified(), QStringLiteral("plughw:%1,%2").arg(card).arg(device));
Nicolas Carion's avatar
Nicolas Carion committed
684 685
            m_configCapture.kcfg_v4l_alsadevice->addItem(devicestr.section(QLatin1Char(':'), -1).simplified(),
                                                         QStringLiteral("hw:%1,%2").arg(card).arg(device));
686
        }
687 688 689
    }
}

690 691
void KdenliveSettingsDialog::showPage(int page, int option)
{
692 693
    switch (page) {
    case 1:
694
        setCurrentPage(m_page1);
695 696
        break;
    case 2:
697
        setCurrentPage(m_page2);
698 699
        break;
    case 3:
700
        setCurrentPage(m_page3);
701 702
        break;
    case 4:
703
        setCurrentPage(m_page4);
704 705 706
        m_configCapture.tabWidget->setCurrentIndex(option);
        break;
    case 5:
707
        setCurrentPage(m_page5);
708
        break;
709 710 711 712 713 714 715 716
    case 6:
        setCurrentPage(m_page6);
        break;
    case 7:
        setCurrentPage(m_page7);
        break;
    default:
        setCurrentPage(m_page1);
717 718
    }
}
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
719