kdenlivesettingsdialog.cpp 66.7 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
#include "renderer.h"
31

32

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

Nicolas Carion's avatar
Nicolas Carion committed
37
#include "kdenlive_debug.h"
38
#include "klocalizedstring.h"
39
#include <KLineEdit>
Nicolas Carion's avatar
Nicolas Carion committed
40
#include <KMessageBox>
41
#include <KOpenWithDialog>
Nicolas Carion's avatar
Nicolas Carion committed
42 43
#include <KRun>
#include <KService>
44
#include <QDir>
45
#include <QThread>
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
46
#include <QAction>
Nicolas Carion's avatar
Nicolas Carion committed
47
#include <QTimer>
48

Nicolas Carion's avatar
Nicolas Carion committed
49
#include <fcntl.h>
50
#include <stdio.h>
Nicolas Carion's avatar
Nicolas Carion committed
51
#include <stdlib.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(const QMap<QString, QString> &mappable_actions, bool gpuAllowed, QWidget *parent)
62 63 64 65
    : KConfigDialog(parent, QStringLiteral("settings"), KdenliveSettings::self())
    , m_modified(false)
    , m_shuttleModified(false)
    , m_mappable_actions(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 75
    // Hide avformat-novalidate trick, causes crash (bug #2205 and #2206)
    m_configMisc.kcfg_projectloading_avformatnovalidate->setVisible(false);
76

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

79 80
    QWidget *p8 = new QWidget;
    m_configProject.setupUi(p8);
81
    m_page8 = addPage(p8, i18n("Project Defaults"));
Nicolas Carion's avatar
Nicolas Carion committed
82
    auto *vbox = new QVBoxLayout;
83 84 85
    m_pw = new ProfileWidget(this);
    vbox->addWidget(m_pw);
    m_configProject.profile_box->setLayout(vbox);
86
    m_configProject.profile_box->setTitle(i18n("Select the default profile (preset)"));
87
    // Select profile
88
    m_pw->loadProfile(KdenliveSettings::default_profile().isEmpty() ? pCore->getCurrentProfile()->path() : KdenliveSettings::default_profile());
89
    connect(m_pw, &ProfileWidget::profileChanged, this, &KdenliveSettingsDialog::slotDialogModified);
90
    m_page8->setIcon(QIcon::fromTheme(QStringLiteral("project-defaults")));
Laurent Montel's avatar
Laurent Montel committed
91
    connect(m_configProject.kcfg_generateproxy, &QAbstractButton::toggled, m_configProject.kcfg_proxyminsize, &QWidget::setEnabled);
92
    m_configProject.kcfg_proxyminsize->setEnabled(KdenliveSettings::generateproxy());
93 94
    m_configProject.projecturl->setMode(KFile::Directory);
    m_configProject.projecturl->setUrl(QUrl::fromLocalFile(KdenliveSettings::defaultprojectfolder()));
Laurent Montel's avatar
Laurent Montel committed
95
    connect(m_configProject.kcfg_generateimageproxy, &QAbstractButton::toggled, m_configProject.kcfg_proxyimageminsize, &QWidget::setEnabled);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
96
    m_configProject.kcfg_proxyimageminsize->setEnabled(KdenliveSettings::generateimageproxy());
97

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

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

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

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

    QWidget *p4 = new QWidget;
    m_configCapture.setupUi(p4);
137 138
    m_configCapture.tabWidget->removeTab(0);
    m_configCapture.tabWidget->removeTab(2);
139
#ifdef USE_V4L
140

141
    // Video 4 Linux device detection
Laurent Montel's avatar
Laurent Montel committed
142
    for (int i = 0; i < 10; ++i) {
Laurent Montel's avatar
Laurent Montel committed
143
        QString path = QStringLiteral("/dev/video") + QString::number(i);
144
        if (QFile::exists(path)) {
145
            QStringList deviceInfo = V4lCaptureHandler::getDeviceName(path);
146 147 148 149
            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);
            }
150 151
        }
    }
Nicolas Carion's avatar
Nicolas Carion committed
152 153 154 155
    connect(m_configCapture.kcfg_detectedv4ldevices, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotUpdatev4lDevice);
    connect(m_configCapture.kcfg_v4l_format, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotUpdatev4lCaptureProfile);
Laurent Montel's avatar
Laurent Montel committed
156
    connect(m_configCapture.config_v4l, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotEditVideo4LinuxProfile);
157 158

    slotUpdatev4lDevice();
159
#endif
160

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

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

Nicolas Carion's avatar
Nicolas Carion committed
178
    slotCheckShuttle(static_cast<int>(KdenliveSettings::enableshuttle()));
179
    m_configShuttle.shuttledisabled->hide();
180 181

    // Store the button pointers into an array for easier handling them in the other functions.
182
    // TODO: impl enumerator or live with cut and paste :-)))
183 184
    setupJogshuttleBtns(KdenliveSettings::shuttledevice());
#if 0
185 186 187 188 189
    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);
190 191 192 193 194
    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);
195 196 197 198 199
    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);
200
#endif
201

Nicolas Carion's avatar
Nicolas Carion committed
202
#else  /* ! USE_JOGSHUTTLE */
203 204 205
    m_configShuttle.kcfg_enableshuttle->hide();
    m_configShuttle.kcfg_enableshuttle->setDisabled(true);
#endif /* USE_JOGSHUTTLE */
206
    m_page5 = addPage(p5, i18n("JogShuttle"));
207
    m_page5->setIcon(QIcon::fromTheme(QStringLiteral("jog-dial")));
208

209 210
    QWidget *p6 = new QWidget;
    m_configSdl.setupUi(p6);
211
    m_configSdl.reload_blackmagic->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
Laurent Montel's avatar
Laurent Montel committed
212
    connect(m_configSdl.reload_blackmagic, &QAbstractButton::clicked, this, &KdenliveSettingsDialog::slotReloadBlackMagic);
213

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

216
    m_page6 = addPage(p6, i18n("Playback"));
217
    m_page6->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
218

219 220
    QWidget *p7 = new QWidget;
    m_configTranscode.setupUi(p7);
221
    m_page7 = addPage(p7, i18n("Transcode"));
222
    m_page7->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
223

Laurent Montel's avatar
Laurent Montel committed
224 225 226 227
    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);
228

Laurent Montel's avatar
Laurent Montel committed
229 230 231 232 233
    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);
234

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

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

Laurent Montel's avatar
Laurent Montel committed
239 240
    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
241

242
    loadEncodingProfiles();
243

Nicolas Carion's avatar
Nicolas Carion committed
244 245 246 247
    connect(m_configSdl.kcfg_audio_driver, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotCheckAlsaDriver);
    connect(m_configSdl.kcfg_audio_backend, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotCheckAudioBackend);
248
    initDevices();
Nicolas Carion's avatar
Nicolas Carion committed
249 250
    connect(m_configCapture.kcfg_grab_capture_type, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotUpdateGrabRegionStatus);
251

252
    slotUpdateGrabRegionStatus();
253
    loadTranscodeProfiles();
254

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

268
    // ffmpeg profile
269
    m_configCapture.v4l_showprofileinfo->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
270 271 272
    m_configCapture.v4l_parameters->setVisible(false);
    m_configCapture.v4l_parameters->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 4);
    m_configCapture.v4l_parameters->setPlainText(KdenliveSettings::v4l_parameters());
273

274
    act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure profiles"), this);
275
    act->setData(2);
Laurent Montel's avatar
Laurent Montel committed
276
    connect(act, &QAction::triggered, this, &KdenliveSettingsDialog::slotManageEncodingProfile);
277
    m_configCapture.v4l_manageprofile->setDefaultAction(act);
Nicolas Carion's avatar
Nicolas Carion committed
278 279
    connect(m_configCapture.kcfg_v4l_profile, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotUpdateV4lProfile);
Laurent Montel's avatar
Laurent Montel committed
280
    connect(m_configCapture.v4l_showprofileinfo, &QAbstractButton::clicked, m_configCapture.v4l_parameters, &QWidget::setVisible);
281

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

295
    // Timeline preview
296
    act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure profiles"), this);
297
    act->setData(1);
Laurent Montel's avatar
Laurent Montel committed
298
    connect(act, &QAction::triggered, this, &KdenliveSettingsDialog::slotManageEncodingProfile);
299
    m_configProject.preview_manageprofile->setDefaultAction(act);
Nicolas Carion's avatar
Nicolas Carion committed
300 301
    connect(m_configProject.kcfg_preview_profile, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotUpdatePreviewProfile);
Laurent Montel's avatar
Laurent Montel committed
302
    connect(m_configProject.preview_showprofileinfo, &QAbstractButton::clicked, m_configProject.previewparams, &QWidget::setVisible);
303 304 305
    m_configProject.previewparams->setVisible(false);
    m_configProject.previewparams->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 3);
    m_configProject.previewparams->setPlainText(KdenliveSettings::previewparams());
306
    m_configProject.preview_showprofileinfo->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
307
    m_configProject.preview_showprofileinfo->setToolTip(i18n("Show default timeline preview parameters"));
308
    m_configProject.preview_manageprofile->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
309 310
    m_configProject.preview_manageprofile->setToolTip(i18n("Manage timeline preview profiles"));
    m_configProject.kcfg_preview_profile->setToolTip(i18n("Select default timeline preview profile"));
311

312
    // proxy profile stuff
313
    m_configProject.proxy_showprofileinfo->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
314
    m_configProject.proxy_showprofileinfo->setToolTip(i18n("Show default profile parameters"));
315
    m_configProject.proxy_manageprofile->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
316 317
    m_configProject.proxy_manageprofile->setToolTip(i18n("Manage proxy profiles"));
    m_configProject.kcfg_proxy_profile->setToolTip(i18n("Select default proxy profile"));
318
    m_configProject.proxyparams->setVisible(false);
319
    m_configProject.proxyparams->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 3);
320
    m_configProject.proxyparams->setPlainText(KdenliveSettings::proxyparams());
321

322
    act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure profiles"), this);
323
    act->setData(0);
Laurent Montel's avatar
Laurent Montel committed
324
    connect(act, &QAction::triggered, this, &KdenliveSettingsDialog::slotManageEncodingProfile);
325 326
    m_configProject.proxy_manageprofile->setDefaultAction(act);

Laurent Montel's avatar
Laurent Montel committed
327
    connect(m_configProject.proxy_showprofileinfo, &QAbstractButton::clicked, m_configProject.proxyparams, &QWidget::setVisible);
Nicolas Carion's avatar
Nicolas Carion committed
328 329
    connect(m_configProject.kcfg_proxy_profile, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this,
            &KdenliveSettingsDialog::slotUpdateProxyProfile);
330 331 332

    slotUpdateProxyProfile(-1);
    slotUpdateV4lProfile(-1);
333
    slotUpdateGrabProfile(-1);
334
    slotUpdateDecklinkProfile(-1);
335

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

340 341
    getBlackMagicDeviceList(m_configCapture.kcfg_decklink_capturedevice);
    if (!getBlackMagicOutputDeviceList(m_configSdl.kcfg_blackmagic_output_device)) {
342
        // No blackmagic card found
343
        m_configSdl.kcfg_external_display->setEnabled(false);
344
    }
345 346
}

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
//static
bool KdenliveSettingsDialog::getBlackMagicDeviceList(KComboBox *devicelist, bool force)
{
    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;
}

bool KdenliveSettingsDialog::getBlackMagicOutputDeviceList(KComboBox *devicelist, bool force)
{
    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
403
void KdenliveSettingsDialog::setupJogshuttleBtns(const QString &device)
404
{
405 406
    QList<KComboBox *> list;
    QList<QLabel *> list1;
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423

    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
424 425 426 427 428 429 430 431
    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
432 433 434 435 436 437 438 439
    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

440
    for (int i = 0; i < list.count(); ++i) {
441 442 443
        list[i]->hide();
        list1[i]->hide();
    }
444
#ifdef USE_JOGSHUTTLE
445 446 447
    if (!m_configShuttle.kcfg_enableshuttle->isChecked()) {
        return;
    }
448 449
    int keysCount = JogShuttle::keysCount(device);

450
    for (int i = 0; i < keysCount; ++i) {
451 452 453 454 455 456 457 458 459
        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();
460
    QList<QString>::Iterator iter = action_names.begin();
Nicolas Carion's avatar
Nicolas Carion committed
461
    // qCDebug(KDENLIVE_LOG) << "::::::::::::::::";
462
    while (iter != action_names.end()) {
Nicolas Carion's avatar
Nicolas Carion committed
463
        // qCDebug(KDENLIVE_LOG) << *iter;
464 465 466
        ++iter;
    }

Nicolas Carion's avatar
Nicolas Carion committed
467
    // qCDebug(KDENLIVE_LOG) << "::::::::::::::::";
468

469
    qSort(action_names);
470 471
    iter = action_names.begin();
    while (iter != action_names.end()) {
Nicolas Carion's avatar
Nicolas Carion committed
472
        // qCDebug(KDENLIVE_LOG) << *iter;
473 474
        ++iter;
    }
Nicolas Carion's avatar
Nicolas Carion committed
475
    // qCDebug(KDENLIVE_LOG) << "::::::::::::::::";
476 477 478 479 480

    // 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
481
    for (const QString &action_id : actions_map) {
482 483 484 485 486 487 488 489 490 491
        // 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;
Nicolas Carion's avatar
Nicolas Carion committed
492
    for (KComboBox *button : m_shuttle_buttons) {
493 494 495
        button->addItems(action_names);
        connect(button, SIGNAL(activated(int)), this, SLOT(slotShuttleModified()));
        ++i;
496
        if (i < actions_map.size()) {
497
            button->setCurrentIndex(action_pos[actions_map[i]]);
498
        }
499
    }
500
#endif
501 502
}

Nicolas Carion's avatar
Nicolas Carion committed
503
KdenliveSettingsDialog::~KdenliveSettingsDialog() {}
504

505
void KdenliveSettingsDialog::slotUpdateGrabRegionStatus()
506
{
507
    m_configCapture.region_group->setHidden(m_configCapture.kcfg_grab_capture_type->currentIndex() != 1);
508
}
509

510 511 512 513 514
void KdenliveSettingsDialog::slotEnableCaptureFolder()
{
    m_configEnv.capturefolderurl->setEnabled(!m_configEnv.kcfg_capturetoprojectfolder->isChecked());
}

515 516 517 518 519
void KdenliveSettingsDialog::slotEnableLibraryFolder()
{
    m_configEnv.libraryfolderurl->setEnabled(!m_configEnv.kcfg_librarytodefaultfolder->isChecked());
}

520 521
void KdenliveSettingsDialog::initDevices()
{
522 523
    // Fill audio drivers
    m_configSdl.kcfg_audio_driver->addItem(i18n("Automatic"), QString());
524
#ifndef Q_WS_MAC
525 526
    m_configSdl.kcfg_audio_driver->addItem(i18n("OSS"), "dsp");
    m_configSdl.kcfg_audio_driver->addItem(i18n("ALSA"), "alsa");
527
    m_configSdl.kcfg_audio_driver->addItem(i18n("PulseAudio"), "pulse");
528 529 530
    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");
531
#endif
532

533
    if (!KdenliveSettings::audiodrivername().isEmpty())
534
        for (int i = 1; i < m_configSdl.kcfg_audio_driver->count(); ++i) {
535 536
            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
537
                KdenliveSettings::setAudio_driver((uint)i);
538 539
            }
        }
540

541
    // Fill the list of audio playback / recording devices
542
    m_configSdl.kcfg_audio_device->addItem(i18n("Default"), QString());
543
    m_configCapture.kcfg_v4l_alsadevice->addItem(i18n("Default"), "default");
544
    if (!QStandardPaths::findExecutable(QStringLiteral("aplay")).isEmpty()) {
545
        m_readProcess.setOutputChannelMode(KProcess::OnlyStdoutChannel);
546
        m_readProcess.setProgram(QStringLiteral("aplay"), QStringList() << QStringLiteral("-l"));
Laurent Montel's avatar
Laurent Montel committed
547
        connect(&m_readProcess, &KProcess::readyReadStandardOutput, this, &KdenliveSettingsDialog::slotReadAudioDevices);
548 549 550
        m_readProcess.execute(5000);
    } else {
        // If aplay is not installed on the system, parse the /proc/asound/pcm file
551
        QFile file(QStringLiteral("/proc/asound/pcm"));
552
        if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
553
            QTextStream stream(&file);
554
            QString line = stream.readLine();
555
            QString deviceId;
556
            while (!line.isNull()) {
557
                if (line.contains(QStringLiteral("playback"))) {
Laurent Montel's avatar
Laurent Montel committed
558
                    deviceId = line.section(QLatin1Char(':'), 0, 0);
Nicolas Carion's avatar
Nicolas Carion committed
559 560 561
                    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()));
562
                }
563
                if (line.contains(QStringLiteral("capture"))) {
Laurent Montel's avatar
Laurent Montel committed
564
                    deviceId = line.section(QLatin1Char(':'), 0, 0);
Nicolas Carion's avatar
Nicolas Carion committed
565 566 567
                    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()));
568
                }
569
                line = stream.readLine();
570
            }
571
            file.close();
572 573 574
        } else {
            qCDebug(KDENLIVE_LOG) << " / / / /CANNOT READ PCM";
        }
575
    }
576

577 578
    // Add pulseaudio capture option
    m_configCapture.kcfg_v4l_alsadevice->addItem(i18n("PulseAudio"), "pulse");
579

580 581
    if (!KdenliveSettings::audiodevicename().isEmpty()) {
        // Select correct alsa device
582 583 584
        int ix = m_configSdl.kcfg_audio_device->findData(KdenliveSettings::audiodevicename());
        m_configSdl.kcfg_audio_device->setCurrentIndex(ix);
        KdenliveSettings::setAudio_device(ix);
585
    }
Alberto Villa's avatar
Alberto Villa committed
586

587 588 589 590 591 592 593
    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);
    }

594
    m_configSdl.kcfg_audio_backend->addItem(i18n("SDL"), KdenliveSettings::sdlAudioBackend());
595 596 597 598 599 600 601
    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);
    }
602
    m_configSdl.group_sdl->setEnabled(KdenliveSettings::audiobackend().startsWith(QLatin1String("sdl_audio")));
603

604
    loadCurrentV4lProfileInfo();
605 606
}

607 608
void KdenliveSettingsDialog::slotReadAudioDevices()
{
609
    QString result = QString(m_readProcess.readAllStandardOutput());
Nicolas Carion's avatar
Nicolas Carion committed
610 611
    // qCDebug(KDENLIVE_LOG) << "// / / / / / READING APLAY: ";
    // qCDebug(KDENLIVE_LOG) << result;
Laurent Montel's avatar
Laurent Montel committed
612
    const QStringList lines = result.split(QLatin1Char('\n'));
613
    for (const QString &devicestr : lines) {
Laurent Montel's avatar
Laurent Montel committed
614
        ////qCDebug(KDENLIVE_LOG) << "// READING LINE: " << data;
615 616 617
        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);
618
            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
619 620
            m_configCapture.kcfg_v4l_alsadevice->addItem(devicestr.section(QLatin1Char(':'), -1).simplified(),
                                                         QStringLiteral("hw:%1,%2").arg(card).arg(device));
621
        }
622 623 624
    }
}

625 626
void KdenliveSettingsDialog::showPage(int page, int option)
{
627 628
    switch (page) {
    case 1:
629
        setCurrentPage(m_page1);
630 631
        break;
    case 2:
632
        setCurrentPage(m_page2);
633 634
        break;
    case 3:
635
        setCurrentPage(m_page3);
636 637
        break;
    case 4:
638
        setCurrentPage(m_page4);
639 640 641
        m_configCapture.tabWidget->setCurrentIndex(option);
        break;
    case 5:
642
        setCurrentPage(m_page5);
643
        break;
644 645 646 647 648 649 650 651
    case 6:
        setCurrentPage(m_page6);
        break;
    case 7:
        setCurrentPage(m_page7);
        break;
    default:
        setCurrentPage(m_page1);
652 653
    }
}
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
654

655 656
void KdenliveSettingsDialog::slotEditAudioApplication()
{
657
    KService::Ptr service;
658
    QPointer<KOpenWithDialog> dlg = new KOpenWithDialog(QList<QUrl>(), i18n("Select default audio editor"), m_configEnv.kcfg_defaultaudioapp->text(), this);
659 660
    if (dlg->exec() == QDialog::Accepted) {
        service = dlg->service();
661
        m_configEnv.kcfg_defaultaudioapp->setText(KRun::binaryName(service->exec(), false));
662
    }
663

664
    delete dlg;
665 666
}

667 668
void KdenliveSettingsDialog::slotEditImageApplication()
{
669
    QPointer<KOpenWithDialog> dlg = new KOpenWithDialog(QList<QUrl>(), i18n("Select default image editor"), m_configEnv.kcfg_defaultimageapp->text(), this);
670
    if (dlg->exec() == QDialog::Accepted) {
Laurent Montel's avatar
Laurent Montel committed
671
        KService::Ptr service = dlg->service();
672
        m_configEnv.kcfg_defaultimageapp->setText(KRun::binaryName(service->exec(), false));
673
    }
674
    delete dlg;
675 676
}

677 678
void KdenliveSettingsDialog::slotCheckShuttle(int state)
{
679
#ifdef USE_JOGSHUTTLE
Nicolas Carion's avatar
Nicolas Carion committed
680
    m_configShuttle.config_group->setEnabled(state != 0);
681
    m_configShuttle.shuttledevicelist->clear();
682

683 684
    QStringList devNames = KdenliveSettings::shuttledevicenames();
    QStringList devPaths = KdenliveSettings::shuttledevicepaths();
685

686 687 688
    if (devNames.count() != devPaths.count()) {
        return;
    }
689
    for (int i = 0; i < devNames.count(); ++i) {
Nicolas Carion's avatar
Nicolas Carion committed
690
        m_configShuttle.shuttledevicelist->addItem(devNames.at(i), devPaths.at(i));
691
    }
Nicolas Carion's avatar
Nicolas Carion committed
692
    if (state != 0) {