mainwindow.cpp 181 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/***************************************************************************
 *   Copyright (C) 2007 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

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
21
#include "mainwindow.h"
22
#include "mainwindowadaptor.h"
23
#include "core.h"
24
#include "bin/projectclip.h"
25
#include "bin/generators/generators.h"
26
#include "library/librarywidget.h"
27
#include "monitor/scopes/audiographspectrum.h"
28
#include "mltcontroller/clipcontroller.h"
29
#include "kdenlivesettings.h"
Vincent Pinon's avatar
Vincent Pinon committed
30
#include "dialogs/kdenlivesettingsdialog.h"
31
#include "dialogs/clipcreationdialog.h"
Vincent Pinon's avatar
Vincent Pinon committed
32
#include "effectslist/initeffects.h"
Vincent Pinon's avatar
Vincent Pinon committed
33
#include "project/dialogs/projectsettings.h"
Vincent Pinon's avatar
Vincent Pinon committed
34
#include "project/clipmanager.h"
Till Theato's avatar
Till Theato committed
35 36 37
#include "monitor/monitor.h"
#include "monitor/recmonitor.h"
#include "monitor/monitormanager.h"
38
#include "doc/kdenlivedoc.h"
Vincent Pinon's avatar
Vincent Pinon committed
39
#include "timeline/timeline.h"
Ed Rogalsky's avatar
Ed Rogalsky committed
40
#include "timeline/track.h"
41
#include "timeline/customtrackview.h"
Vincent Pinon's avatar
Vincent Pinon committed
42
#include "effectslist/effectslistview.h"
43
#include "effectslist/effectbasket.h"
44
#include "effectstack/effectstackview2.h"
45
#include "project/transitionsettings.h"
46
#include "mltcontroller/bincontroller.h"
47
#include "mltcontroller/producerqueue.h"
Vincent Pinon's avatar
Vincent Pinon committed
48
#include "dialogs/renderwidget.h"
49
#include "renderer.h"
Vincent Pinon's avatar
Vincent Pinon committed
50
#include "dialogs/wizard.h"
51
#include "project/projectcommands.h"
Vincent Pinon's avatar
Vincent Pinon committed
52
#include "titler/titlewidget.h"
Vincent Pinon's avatar
Vincent Pinon committed
53
#include "timeline/markerdialog.h"
54
#include "timeline/clipitem.h"
Vincent Pinon's avatar
Vincent Pinon committed
55
#include "project/cliptranscode.h"
56
#include "scopes/scopemanager.h"
Vincent Pinon's avatar
Vincent Pinon committed
57
#include "project/dialogs/archivewidget.h"
58
#include "utils/resourcewidget.h"
59
#include "layoutmanagement.h"
60
#include "hidetitlebars.h"
61
#include "mltconnection.h"
Till Theato's avatar
Till Theato committed
62
#include "project/projectmanager.h"
63
#include "timeline/timelinesearch.h"
64
#include <config-kdenlive.h>
65
#include "utils/thememanager.h"
66
#include "utils/progressbutton.h"
67 68
#include "effectslist/effectslistwidget.h"

69
#include "utils/KoIconUtils.h"
70
#include "project/dialogs/temporarydata.h"
71 72 73
#ifdef USE_JOGSHUTTLE
#include "jogshuttle/jogmanager.h"
#endif
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
74

75
#include <KActionCollection>
76
#include <KActionCategory>
77
#include <KActionMenu>
78
#include <KStandardAction>
79
#include <KShortcutsDialog>
80 81 82
#include <KMessageBox>
#include <KConfigDialog>
#include <KXMLGUIFactory>
83
#include <KIconTheme>
84
#include <KColorSchemeManager>
85
#include <KRecentDirs>
86 87 88
#include <KUrlRequesterDialog>
#include <ktogglefullscreenaction.h>
#include <KNotifyConfigWidget>
89 90
#include <kns3/downloaddialog.h>
#include <kns3/knewstuffaction.h>
91
#include <KToolBar>
92
#include <KColorScheme>
93
#include <KEditToolBar>
94
#include <KDualAction>
95
#include <klocalizedstring.h>
96 97

#include <QAction>
98 99 100 101
#include <QDebug>
#include <QStatusBar>
#include <QTemporaryFile>
#include <QMenu>
102
#include <QDesktopWidget>
103
#include <QBitmap>
104
#include <QUndoGroup>
105
#include <QFileDialog>
106
#include <QStyleFactory>
107
#include <QMenuBar>
108 109

#include <stdlib.h>
110
#include <QStandardPaths>
Vincent Pinon's avatar
Vincent Pinon committed
111 112 113 114
#include <KConfigGroup>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
115
#include <QtGlobal>
116
#include <QScreen>
117

118
static const char version[] = KDENLIVE_VERSION;
119 120
namespace Mlt
{
121 122 123
class Producer;
};

Marco Gittler's avatar
Marco Gittler committed
124 125 126 127 128
EffectsList MainWindow::videoEffects;
EffectsList MainWindow::audioEffects;
EffectsList MainWindow::customEffects;
EffectsList MainWindow::transitions;

129
QMap <QString,QImage> MainWindow::m_lumacache;
130
QMap <QString,QStringList> MainWindow::m_lumaFiles;
131

132
/*static bool sortByNames(const QPair<QString, QAction *> &a, const QPair<QString, QAction*> &b)
133 134
{
    return a.first < b.first;
135
}*/
136

137 138 139 140 141 142 143 144 145
// determine the the default KDE style as defined BY THE USER
// (as opposed to whatever style KDE considers default)
static QString defaultStyle(const char *fallback=Q_NULLPTR)
{
    KSharedConfigPtr kdeGlobals = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::NoGlobals);
    KConfigGroup cg(kdeGlobals, "KDE");
    return cg.readEntry("widgetStyle", fallback);
}

146
MainWindow::MainWindow(const QString &MltPath, const QUrl &Url, const QString & clipsToLoad, QWidget *parent) :
147
    KXmlGuiWindow(parent),
148 149 150
    m_timelineArea(Q_NULLPTR),
    m_stopmotion(Q_NULLPTR),
    m_effectStack(Q_NULLPTR),
Vincent Pinon's avatar
Vincent Pinon committed
151
    m_exitCode(EXIT_SUCCESS),
152 153 154 155 156 157 158
    m_effectList(Q_NULLPTR),
    m_transitionList(Q_NULLPTR),
    m_clipMonitor(Q_NULLPTR),
    m_projectMonitor(Q_NULLPTR),
    m_recMonitor(Q_NULLPTR),
    m_renderWidget(Q_NULLPTR),
    m_messageLabel(Q_NULLPTR),
159 160
    m_themeInitialized(false),
    m_isDarkTheme(false)
161
{
Vincent Pinon's avatar
Vincent Pinon committed
162
    qRegisterMetaType<audioShortVector> ("audioShortVector");
163
    qRegisterMetaType< QVector<double> > ("QVector<double>");
Vincent Pinon's avatar
Vincent Pinon committed
164
    qRegisterMetaType<MessageType> ("MessageType");
165
    qRegisterMetaType<stringMap> ("stringMap");
166
    qRegisterMetaType<audioByteArray> ("audioByteArray");
167
    qRegisterMetaType< QVector <int> > ();
168
    qRegisterMetaType<QDomElement> ("QDomElement");
169
    qRegisterMetaType<requestClipInfo> ("requestClipInfo");
170
    qRegisterMetaType<MltVideoProfile> ("MltVideoProfile");
171
    Core::build(this);
172 173 174 175 176

    // Widget themes for non KDE users
    KActionMenu *stylesAction= new KActionMenu(i18n("Style"), this);
    QActionGroup *stylesGroup = new QActionGroup(stylesAction);

177 178 179 180 181

    // GTK theme does not work well with Kdenlive, and does not support color theming, so avoid it
    QStringList availableStyles = QStyleFactory::keys();
    QString desktopStyle = QApplication::style()->objectName();
    if (QString::compare(desktopStyle, QLatin1String("GTK+"), Qt::CaseInsensitive) == 0 && KdenliveSettings::widgetstyle().isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
182
        if (availableStyles.contains(QStringLiteral("breeze"), Qt::CaseInsensitive)) {
183 184
            // Auto switch to Breeze theme
            KdenliveSettings::setWidgetstyle(QStringLiteral("Breeze"));
Laurent Montel's avatar
Laurent Montel committed
185
        } else if (availableStyles.contains(QStringLiteral("fusion"), Qt::CaseInsensitive)) {
186 187 188 189
            KdenliveSettings::setWidgetstyle(QStringLiteral("Fusion"));
        }
    }

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
190 191 192 193 194 195 196 197
    // Add default style action
    QAction *defaultStyle = new QAction(i18n("Default"), stylesGroup);
    defaultStyle->setCheckable(true);
    stylesAction->addAction(defaultStyle);
    if (KdenliveSettings::widgetstyle().isEmpty()) {
        defaultStyle->setChecked(true);
    }

198 199 200 201
    foreach(const QString &style, availableStyles) {
        QAction *a = new QAction(style, stylesGroup);
        a->setCheckable(true);
        a->setData(style);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
202 203 204
        if (KdenliveSettings::widgetstyle() == style) {
            a->setChecked(true);
        }
205 206 207 208 209
        stylesAction->addAction(a);
    }
    connect(stylesGroup, &QActionGroup::triggered, this, &MainWindow::slotChangeStyle);

    // Color schemes
210 211 212
    KActionMenu *themeAction= new KActionMenu(i18n("Theme"), this);
    ThemeManager::instance()->setThemeMenuAction(themeAction);
    ThemeManager::instance()->setCurrentTheme(KdenliveSettings::colortheme());
213
    connect(ThemeManager::instance(), SIGNAL(signalThemeChanged(const QString &)), this, SLOT(slotThemeChanged(const QString &)), Qt::DirectConnection);
214

215
    if (!KdenliveSettings::widgetstyle().isEmpty() && QString::compare(desktopStyle, KdenliveSettings::widgetstyle(), Qt::CaseInsensitive) != 0) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
216 217 218 219
        // User wants a custom widget style, init
        doChangeStyle();
    }
    else ThemeManager::instance()->slotChangePalette();
220
    //QIcon::setThemeSearchPaths(QStringList() <<QStringLiteral(":/icons/"));
221 222 223 224

    new RenderingAdaptor(this);
    pCore->initialize();
    MltConnection::locateMeltAndProfilesPath(MltPath);
225 226
    QString defaultProfile = KdenliveSettings::default_profile();
    KdenliveSettings::setCurrent_profile(defaultProfile.isEmpty() ? ProjectManager::getDefaultProjectFormat() : defaultProfile);
227 228 229 230

    // If using a custom profile, make sure the file exists or fallback to default
    if (KdenliveSettings::current_profile().startsWith(QStringLiteral("/")) && !QFile::exists(KdenliveSettings::current_profile())) {
        KMessageBox::sorry(this, i18n("Cannot find your default profile, switching to ATSC 1080p 25"));
Laurent Montel's avatar
Laurent Montel committed
231 232
        KdenliveSettings::setCurrent_profile(QStringLiteral("atsc_1080p_25"));
        KdenliveSettings::setDefault_profile(QStringLiteral("atsc_1080p_25"));
233
    }
234
    m_commandStack = new QUndoGroup(this);
235 236
    m_timelineArea = new QTabWidget(this);
    //m_timelineArea->setTabReorderingEnabled(true);
237
    m_timelineArea->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
Simon Eugster's avatar
Simon Eugster committed
238
    m_timelineArea->setMinimumHeight(200);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
239 240 241
    // Hide tabbar
    QTabBar *bar = m_timelineArea->findChild<QTabBar *>();
    bar->setHidden(true);
242

243
    m_gpuAllowed = initEffects::parseEffectFiles(pCore->binController()->mltRepository());
244
    //initEffects::parseCustomEffectsFile();
245

246
    m_shortcutRemoveFocus = new QShortcut(QKeySequence(QStringLiteral("Esc")), this);
Simon Eugster's avatar
Simon Eugster committed
247 248
    connect(m_shortcutRemoveFocus, SIGNAL(activated()), this, SLOT(slotRemoveFocus()));

249
    /// Add Widgets
250
    setDockOptions(dockOptions() | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
251
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
252 253
    setDockOptions(dockOptions() | QMainWindow::GroupedDragging);
#endif
254
    setTabPosition(Qt::AllDockWidgetAreas, (QTabWidget::TabPosition) KdenliveSettings::tabposition());
255
    m_timelineToolBar = toolBar(QStringLiteral("timelineToolBar"));
256
    m_timelineToolBarContainer = new QWidget(this);
257
    QVBoxLayout *ctnLay = new QVBoxLayout;
258 259
    ctnLay->setSpacing(0);
    ctnLay->setContentsMargins(0, 0, 0, 0);
260 261
    m_timelineToolBarContainer->setLayout(ctnLay);
    ctnLay->addWidget(m_timelineToolBar);
262 263 264 265
    KSharedConfigPtr config = KSharedConfig::openConfig();
    KConfigGroup mainConfig(config, QStringLiteral("MainWindow"));
    KConfigGroup tbGroup(&mainConfig, QStringLiteral("Toolbar timelineToolBar"));
    m_timelineToolBar->applySettings(tbGroup);
266 267 268 269 270
    QFrame *fr = new QFrame(this);
    fr->setFrameShape(QFrame::HLine);
    fr->setMaximumHeight(1);
    fr->setLineWidth(1);
    ctnLay->addWidget(fr);
271
    ctnLay->addWidget(m_timelineArea);
272
    setCentralWidget(m_timelineToolBarContainer);
273
    setupActions();
274

275
    QDockWidget * libraryDock = addDock(i18n("Library"), QStringLiteral("library"), pCore->library());
Simon Eugster's avatar
Simon Eugster committed
276

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
277
    m_clipMonitor = new Monitor(Kdenlive::ClipMonitor, pCore->monitorManager(), this);
278
    pCore->bin()->setMonitor(m_clipMonitor);
279
    connect(m_clipMonitor, &Monitor::showConfigDialog, this, &MainWindow::slotPreferences);
280 281
    connect(m_clipMonitor, &Monitor::addMarker, this, &MainWindow::slotAddMarkerGuideQuickly);
    connect(m_clipMonitor, &Monitor::deleteMarker, this, &MainWindow::slotDeleteClipMarker);
282 283
    connect(m_clipMonitor, &Monitor::seekToPreviousSnap, this, &MainWindow::slotSnapRewind);
    connect(m_clipMonitor, &Monitor::seekToNextSnap, this, &MainWindow::slotSnapForward);
284

285
    connect(pCore->bin(), SIGNAL(clipNeedsReload(QString,bool)),this, SLOT(slotUpdateClip(QString,bool)));
286
    connect(pCore->bin(), SIGNAL(findInTimeline(QString)), this, SLOT(slotClipInTimeline(QString)));
287

288 289
    //TODO deprecated, replace with Bin methods if necessary
    /*connect(m_projectList, SIGNAL(loadingIsOver()), this, SLOT(slotElapsedTime()));
290
    connect(m_projectList, SIGNAL(updateRenderStatus()), this, SLOT(slotCheckRenderStatus()));
Laurent Montel's avatar
Laurent Montel committed
291
    connect(m_projectList, SIGNAL(updateProfile(QString)), this, SLOT(slotUpdateProjectProfile(QString)));
292
    connect(m_projectList, SIGNAL(refreshClip(QString,bool)), pCore->monitorManager(), SLOT(slotRefreshCurrentMonitor(QString)));
293
    connect(m_clipMonitor, SIGNAL(zoneUpdated(QPoint)), m_projectList, SLOT(slotUpdateClipCut(QPoint)));*/
294
    connect(m_clipMonitor, SIGNAL(extractZone(QString)), pCore->bin(), SLOT(slotStartCutJob(QString)));
295
    connect(m_clipMonitor, SIGNAL(passKeyPress(QKeyEvent*)), this, SLOT(triggerKey(QKeyEvent*)));
296

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
297
    m_projectMonitor = new Monitor(Kdenlive::ProjectMonitor, pCore->monitorManager(), this);
298
    connect(m_projectMonitor, SIGNAL(passKeyPress(QKeyEvent*)), this, SLOT(triggerKey(QKeyEvent*)));
299 300 301 302
    connect(m_projectMonitor, &Monitor::addMarker, this, &MainWindow::slotAddMarkerGuideQuickly);
    connect(m_projectMonitor, &Monitor::deleteMarker, this, &MainWindow::slotDeleteClipMarker);
    connect(m_projectMonitor, &Monitor::seekToPreviousSnap, this, &MainWindow::slotSnapRewind);
    connect(m_projectMonitor, &Monitor::seekToNextSnap, this, &MainWindow::slotSnapForward);
303
    connect(m_loopClip, &QAction::triggered, m_projectMonitor, &Monitor::slotLoopClip);
304
    connect(m_projectMonitor, SIGNAL(updateGuide(int, QString)), this, SLOT(slotEditGuide(int, QString)));
305

306 307
/*
    //TODO disabled until ported to qml
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
308
    m_recMonitor = new RecMonitor(Kdenlive::RecordMonitor, pCore->monitorManager(), this);
309 310
    connect(m_recMonitor, SIGNAL(addProjectClip(QUrl)), this, SLOT(slotAddProjectClip(QUrl)));
    connect(m_recMonitor, SIGNAL(addProjectClipList(QList<QUrl>)), this, SLOT(slotAddProjectClipList(QList<QUrl>)));
311

312
*/
313
    pCore->monitorManager()->initMonitors(m_clipMonitor, m_projectMonitor, m_recMonitor);
314
    connect(m_clipMonitor, SIGNAL(addMasterEffect(QString,QDomElement)), pCore->bin(), SLOT(slotEffectDropped(QString,QDomElement)));
315

316 317 318 319 320 321 322 323
    // Audio spectrum scope
    m_audioSpectrum = new AudioGraphSpectrum(pCore->monitorManager());
    QDockWidget * spectrumDock = addDock(i18n("Audio Spectrum"), QStringLiteral("audiospectrum"), m_audioSpectrum);
    connect(this, &MainWindow::reloadTheme, m_audioSpectrum, &AudioGraphSpectrum::refreshPixmap);
    // Close library and audiospectrum on first run
    libraryDock->close();
    spectrumDock->close();

324
    m_projectBinDock = addDock(i18n("Project Bin"), QStringLiteral("project_bin"), pCore->bin());
325
    m_effectStack = new EffectStackView2(m_projectMonitor, this);
326
    connect(m_effectStack, SIGNAL(startFilterJob(const ItemInfo&,const QString&,QMap<QString,QString>&,QMap<QString,QString>&,QMap<QString,QString>&)), pCore->bin(), SLOT(slotStartFilterJob(const ItemInfo &,const QString&,QMap<QString,QString>&,QMap<QString,QString>&,QMap<QString,QString>&)));
327
    connect(pCore->bin(), SIGNAL(masterClipSelected(ClipController *, Monitor *)), m_effectStack, SLOT(slotMasterClipItemSelected(ClipController *, Monitor *)));
328
    connect(pCore->bin(), SIGNAL(masterClipUpdated(ClipController *, Monitor *)), m_effectStack, SLOT(slotRefreshMasterClipEffects(ClipController *, Monitor *)));
329
    connect(m_effectStack, SIGNAL(addMasterEffect(QString,QDomElement)), pCore->bin(), SLOT(slotEffectDropped(QString,QDomElement)));
330 331
    connect(m_effectStack, SIGNAL(updateMasterEffect(QString,QDomElement,QDomElement,int)), pCore->bin(), SLOT(slotUpdateEffect(QString,QDomElement,QDomElement,int)));
    connect(m_effectStack, SIGNAL(changeMasterEffectState(QString,QList<int>,bool)), pCore->bin(), SLOT(slotChangeEffectState(QString,QList<int>,bool)));
332
    connect(m_effectStack, SIGNAL(removeMasterEffect(QString,QDomElement)), pCore->bin(), SLOT(slotDeleteEffect(QString,QDomElement)));
333
    connect(m_effectStack, SIGNAL(changeEffectPosition(QString,const QList <int>,int)), pCore->bin(), SLOT(slotMoveEffect(QString,const QList <int>,int)));
334
    connect(m_effectStack, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects()));
335
    connect(m_effectStack, SIGNAL(displayMessage(QString,int)), m_messageLabel, SLOT(setProgressMessage(QString,int)));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
336
    m_effectStackDock = addDock(i18n("Properties"), QStringLiteral("effect_stack"), m_effectStack);
337

Simon Eugster's avatar
Simon Eugster committed
338
    m_effectList = new EffectsListView();
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
339
    m_effectListDock = addDock(i18n("Effects"), QStringLiteral("effect_list"), m_effectList);
Simon Eugster's avatar
Simon Eugster committed
340

341
    m_transitionList = new EffectsListView(EffectsListView::TransitionMode);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
342
    m_transitionListDock = addDock(i18n("Transitions"), QStringLiteral("transition_list"), m_transitionList);
343

Simon Eugster's avatar
Simon Eugster committed
344
    // Add monitors here to keep them at the right of the window
345 346
    m_clipMonitorDock = addDock(i18n("Clip Monitor"), QStringLiteral("clip_monitor"), m_clipMonitor);
    m_projectMonitorDock = addDock(i18n("Project Monitor"), QStringLiteral("project_monitor"), m_projectMonitor);
347
    if (m_recMonitor) {
348
        m_recMonitorDock = addDock(i18n("Record Monitor"), QStringLiteral("record_monitor"), m_recMonitor);
349
    }
Simon Eugster's avatar
Simon Eugster committed
350

351
    m_undoView = new QUndoView();
352
    m_undoView->setCleanIcon(KoIconUtils::themedIcon(QStringLiteral("edit-clear")));
353 354
    m_undoView->setEmptyLabel(i18n("Clean"));
    m_undoView->setGroup(m_commandStack);
355
    m_undoViewDock = addDock(i18n("Undo History"), QStringLiteral("undo_history"), m_undoView);
356

357
    // Color and icon theme stuff
358
    addAction(QStringLiteral("themes_menu"), themeAction);
359
    connect(m_commandStack, SIGNAL(cleanChanged(bool)), m_saveAction, SLOT(setDisabled(bool)));
360
    addAction(QStringLiteral("styles_menu"), stylesAction);
Simon Eugster's avatar
Simon Eugster committed
361

362 363 364 365 366 367
    QAction *iconAction = new QAction(i18n("Force Breeze Icon Theme"), this);
    iconAction->setCheckable(true);
    iconAction->setChecked(KdenliveSettings::force_breeze());
    addAction(QStringLiteral("force_icon_theme"), iconAction);
    connect(iconAction, &QAction::triggered, this, &MainWindow::forceIconSet);

Simon Eugster's avatar
Simon Eugster committed
368 369 370 371 372 373
    // Close non-general docks for the initial layout
    // only show important ones
    m_undoViewDock->close();



374
    /// Tabify Widgets
375
    tabifyDockWidget(m_transitionListDock, m_effectListDock);
376
    tabifyDockWidget(m_effectStackDock, pCore->bin()->clipPropertiesDock());
377
    //tabifyDockWidget(m_effectListDock, m_effectStackDock);
378

379
    tabifyDockWidget(m_clipMonitorDock, m_projectMonitorDock);
380 381 382
    if (m_recMonitor) {
        tabifyDockWidget(m_clipMonitorDock, m_recMonitorDock);
    }
383
    bool firstRun = readOptions();
Simon Eugster's avatar
Simon Eugster committed
384

385
    QAction *action;
386 387
    // Stop motion actions. Beware of the order, we MUST use the same order in stopmotion/stopmotion.cpp
    m_stopmotion_actions = new KActionCategory(i18n("Stop Motion"), actionCollection());
388
    action = new QAction(KoIconUtils::themedIcon(QStringLiteral("media-record")), i18n("Capture frame"), this);
389
    //action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
390
    m_stopmotion_actions->addAction(QStringLiteral("stopmotion_capture"), action);
391
    action = new QAction(i18n("Switch live / captured frame"), this);
392
    //action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
393 394
    m_stopmotion_actions->addAction(QStringLiteral("stopmotion_switch"), action);
    action = new QAction(KoIconUtils::themedIcon(QStringLiteral("edit-paste")), i18n("Show last frame over video"), this);
395 396
    action->setCheckable(true);
    action->setChecked(false);
397
    m_stopmotion_actions->addAction(QStringLiteral("stopmotion_overlay"), action);
398

399
    // Monitor Record action
400
    addAction(QStringLiteral("switch_monitor_rec"), m_clipMonitor->recAction());
401

402
    // Build effects menu
403
    m_effectsMenu = new QMenu(i18n("Add Effect"), this);
404 405
    m_effectActions = new KActionCategory(i18n("Effects"), actionCollection());
    m_effectList->reloadEffectList(m_effectsMenu, m_effectActions);
406

407 408 409 410
    m_transitionsMenu = new QMenu(i18n("Add Transition"), this);
    m_transitionActions = new KActionCategory(i18n("Transitions"), actionCollection());
    m_transitionList->reloadEffectList(m_transitionsMenu, m_transitionActions);

411
    ScopeManager *scmanager = new ScopeManager(this);
412

Till Theato's avatar
Till Theato committed
413
    new LayoutManagement(this);
414
    new HideTitleBars(this);
415
    new TimelineSearch(this);
416 417
    m_extraFactory = new KXMLGUIClient(this);
    buildDynamicActions();
418

419 420 421 422 423 424 425 426 427 428 429 430 431 432
    // Add shortcut to action tooltips
    QList< KActionCollection * > collections = KActionCollection::allCollections();
    for (int i = 0; i < collections.count(); ++i) {
        KActionCollection *coll = collections.at(i);
        foreach( QAction* tempAction, coll->actions()) {
            // find the shortcut pattern and delete (note the preceding space in the RegEx)
            QString strippedTooltip = tempAction->toolTip().remove(QRegExp("\\s\\(.*\\)"));
            // append shortcut if it exists for action
            if (tempAction->shortcut() == QKeySequence(0))
                tempAction->setToolTip( strippedTooltip);
            else
                tempAction->setToolTip( strippedTooltip + " (" + tempAction->shortcut().toString() + ")");
        }
    }
433

434 435
    // Create Effect Basket (dropdown list of favorites)
    m_effectBasket = new EffectBasket(m_effectList);
436
    connect(m_effectBasket, SIGNAL(addEffect(QDomElement)), this, SLOT(slotAddEffect(QDomElement)));
437 438
    QWidgetAction *widgetlist = new QWidgetAction(this);
    widgetlist->setDefaultWidget(m_effectBasket);
439
    //widgetlist->setText(i18n("Favorite Effects"));
440
    widgetlist->setToolTip(i18n("Favorite Effects"));
Laurent Montel's avatar
Laurent Montel committed
441
    widgetlist->setIcon(KoIconUtils::themedIcon(QStringLiteral("favorite")));
442 443 444 445 446
    QMenu *menu = new QMenu(this);
    menu->addAction(widgetlist);

    QToolButton *basketButton = new QToolButton(this);
    basketButton->setMenu(menu);
447
    basketButton->setToolButtonStyle(toolBar()->toolButtonStyle());
448 449
    basketButton->setDefaultAction(widgetlist);
    basketButton->setPopupMode(QToolButton::InstantPopup);
450
    //basketButton->setText(i18n("Favorite Effects"));
451
    basketButton->setToolTip(i18n("Favorite Effects"));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
452
    basketButton->setIcon(KoIconUtils::themedIcon(QStringLiteral("favorite")));
453

454
    QWidgetAction* toolButtonAction = new QWidgetAction(this);
455
    toolButtonAction->setText(i18n("Favorite Effects"));
Laurent Montel's avatar
Laurent Montel committed
456
    toolButtonAction->setIcon(KoIconUtils::themedIcon(QStringLiteral("favorite")));
457
    toolButtonAction->setDefaultWidget(basketButton);
458
    addAction(QStringLiteral("favorite_effects"), toolButtonAction);
459
    connect(toolButtonAction, SIGNAL(triggered(bool)), basketButton, SLOT(showMenu()));
460

461 462 463 464 465 466 467 468 469 470 471
    // Render button
    ProgressButton *timelineRender = new ProgressButton(i18n("Render"), 100, this);
    QMenu *tlrMenu = new QMenu(this);
    timelineRender->setMenu(tlrMenu);
    connect(this, &MainWindow::setRenderProgress, timelineRender, &ProgressButton::setProgress);
    QWidgetAction* renderButtonAction = new QWidgetAction(this);
    renderButtonAction->setText(i18n("Render Button"));
    renderButtonAction->setIcon(KoIconUtils::themedIcon(QStringLiteral("media-record")));
    renderButtonAction->setDefaultWidget(timelineRender);
    addAction(QStringLiteral("project_render_button"), renderButtonAction);

472
    // Timeline preview button
473
    ProgressButton *timelinePreview = new ProgressButton(i18n("Rendering preview"), 1000, this);
474 475
    QMenu *tlMenu = new QMenu(this);
    timelinePreview->setMenu(tlMenu);
476
    connect(this, &MainWindow::setPreviewProgress, timelinePreview, &ProgressButton::setProgress);
477 478
    QWidgetAction* previewButtonAction = new QWidgetAction(this);
    previewButtonAction->setText(i18n("Timeline Preview"));
479
    previewButtonAction->setIcon(KoIconUtils::themedIcon(QStringLiteral("preview-render-on")));
480
    previewButtonAction->setDefaultWidget(timelinePreview);
481
    addAction(QStringLiteral("timeline_preview_button"), previewButtonAction);
482

483
    setupGUI();
484 485 486 487 488 489 490 491 492 493
    if (firstRun) {
        QScreen *current = QApplication::primaryScreen();
        if (current) {
            if (current->availableSize().height() < 1000) {
                resize(current->availableSize());
            } else {
                resize(current->availableSize() / 1.5);
            }
        }
    }
494 495
    timelinePreview->setToolButtonStyle(m_timelineToolBar->toolButtonStyle());
    connect(m_timelineToolBar, &QToolBar::toolButtonStyleChanged, timelinePreview, &ProgressButton::setToolButtonStyle);
496

497 498 499
    timelineRender->setToolButtonStyle(toolBar()->toolButtonStyle());
    /*connect(m_timelineToolBar, &QToolBar::toolButtonStyleChanged, timelinePreview, &ProgressButton::setToolButtonStyle);*/

500 501
    /*ScriptingPart* sp = new ScriptingPart(this, QStringList());
    guiFactory()->addClient(sp);*/
502

503
    loadGenerators();
504
    loadDockActions();
505
    loadClipActions();
506 507

    // Connect monitor overlay info menu.
508 509
    QMenu *monitorOverlay = static_cast<QMenu*>(factory()->container(QStringLiteral("monitor_config_overlay"), this));
    connect(monitorOverlay, SIGNAL(triggered(QAction*)), this, SLOT(slotSwitchMonitorOverlay(QAction*)));
510

511
    m_projectMonitor->setupMenu(static_cast<QMenu*>(factory()->container(QStringLiteral("monitor_go"), this)), monitorOverlay, m_playZone, m_loopZone, Q_NULLPTR, m_loopClip);
512
    m_clipMonitor->setupMenu(static_cast<QMenu*>(factory()->container(QStringLiteral("monitor_go"), this)), monitorOverlay, m_playZone, m_loopZone, static_cast<QMenu*>(factory()->container(QStringLiteral("marker_menu"), this)));
513

514 515
    QMenu *clipInTimeline = static_cast<QMenu*>(factory()->container(QStringLiteral("clip_in_timeline"), this));
    clipInTimeline->setIcon(KoIconUtils::themedIcon(QStringLiteral("go-jump")));
516
    pCore->bin()->setupGeneratorMenu();
Marco Gittler's avatar
Marco Gittler committed
517

518 519
    connect(pCore->monitorManager(), SIGNAL(updateOverlayInfos(int,int)), this, SLOT(slotUpdateMonitorOverlays(int,int)));

520
    // Setup and fill effects and transitions menus.
521
    QMenu *m = static_cast<QMenu*>(factory()->container(QStringLiteral("video_effects_menu"), this));
Laurent Montel's avatar
Laurent Montel committed
522 523
    connect(m, SIGNAL(triggered(QAction*)), this, SLOT(slotAddVideoEffect(QAction*)));
    connect(m_effectsMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotAddVideoEffect(QAction*)));
524
    connect(m_transitionsMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotAddTransition(QAction*)));
525

526 527 528 529
    m_timelineContextMenu = new QMenu(this);
    m_timelineContextClipMenu = new QMenu(this);
    m_timelineContextTransitionMenu = new QMenu(this);

530 531
    m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("insert_space")));
    m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("delete_space")));
532
    m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("delete_space_all_tracks")));
533 534
    m_timelineContextMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Paste)));

535
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("clip_in_project_tree")));
536
    //m_timelineContextClipMenu->addAction(actionCollection()->action("clip_to_project_tree"));
537
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("delete_timeline_clip")));
538
    m_timelineContextClipMenu->addSeparator();
539 540 541 542 543
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("group_clip")));
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("ungroup_clip")));
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("split_audio")));
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("set_audio_align_ref")));
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("align_audio")));
544
    m_timelineContextClipMenu->addSeparator();
545
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("cut_timeline_clip")));
546
    m_timelineContextClipMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Copy)));
547
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("paste_effects")));
548
    m_timelineContextClipMenu->addSeparator();
549

550
    QMenu *markersMenu = static_cast<QMenu*>(factory()->container(QStringLiteral("marker_menu"), this));
551
    m_timelineContextClipMenu->addMenu(markersMenu);
552
    m_timelineContextClipMenu->addSeparator();
553
    m_timelineContextClipMenu->addMenu(m_transitionsMenu);
554
    m_timelineContextClipMenu->addMenu(m_effectsMenu);
Marco Gittler's avatar
Marco Gittler committed
555

556
    m_timelineContextTransitionMenu->addAction(actionCollection()->action(QStringLiteral("delete_timeline_clip")));
557
    m_timelineContextTransitionMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Copy)));
558

559
    m_timelineContextTransitionMenu->addAction(actionCollection()->action(QStringLiteral("auto_transition")));
560

Laurent Montel's avatar
Laurent Montel committed
561
    connect(m_effectList, SIGNAL(addEffect(QDomElement)), this, SLOT(slotAddEffect(QDomElement)));
562 563
    connect(m_effectList, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects()));

564
    slotConnectMonitors();
565

566
    m_timelineToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
567
    // TODO: let user select timeline toolbar toolbutton style
568
    //connect(toolBar(), &QToolBar::iconSizeChanged, m_timelineToolBar, &QToolBar::setToolButtonStyle);
569 570
    m_timelineToolBar->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(m_timelineToolBar, &QWidget::customContextMenuRequested, this, &MainWindow::showTimelineToolbarMenu);
571 572

    QAction *prevRender = actionCollection()->action(QStringLiteral("prerender_timeline_zone"));
573 574
    QAction *stopPrevRender = actionCollection()->action(QStringLiteral("stop_prerender_timeline"));
    tlMenu->addAction(stopPrevRender);
575 576
    tlMenu->addAction(actionCollection()->action(QStringLiteral("set_render_timeline_zone")));
    tlMenu->addAction(actionCollection()->action(QStringLiteral("unset_render_timeline_zone")));
577
    tlMenu->addAction(actionCollection()->action(QStringLiteral("clear_render_timeline_zone")));
578 579 580 581 582 583 584

    // Automatic timeline preview action
    QAction *autoRender = new QAction(KoIconUtils::themedIcon(QStringLiteral("view-refresh")), i18n("Automatic Preview"), this);
    autoRender->setCheckable(true);
    autoRender->setChecked(KdenliveSettings::autopreview());
    connect(autoRender, &QAction::triggered, this, &MainWindow::slotToggleAutoPreview);
    tlMenu->addAction(autoRender);
585
    tlMenu->addSeparator();
586
    tlMenu->addAction(actionCollection()->action(QStringLiteral("disable_preview")));
587
    tlMenu->addAction(actionCollection()->action(QStringLiteral("manage_cache")));
588
    timelinePreview->defineDefaultAction(prevRender, stopPrevRender);
589
    timelinePreview->setAutoRaise(true);
590

591 592
    QAction *showRender = actionCollection()->action(QStringLiteral("project_render"));
    tlrMenu->addAction(showRender);
593
    tlrMenu->addAction(actionCollection()->action(QStringLiteral("stop_project_render")));
594
    timelineRender->defineDefaultAction(showRender, showRender);
595 596
    timelineRender->setAutoRaise(true);

597

598
    //m_timelineToolBar->addAction(toolButtonAction);
599

600
    /*QWidget *sep = new QWidget(this);
601
    sep->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
602 603 604 605 606 607 608 609 610 611 612
    m_timelineToolBar->addWidget(sep);
    m_timelineToolBar->addAction(m_buttonAutomaticSplitAudio);
    m_timelineToolBar->addAction(m_buttonVideoThumbs);
    m_timelineToolBar->addAction(m_buttonAudioThumbs);
    m_timelineToolBar->addAction(m_buttonShowMarkers);
    m_timelineToolBar->addAction(m_buttonSnap);
    m_timelineToolBar->addSeparator();
    m_timelineToolBar->addAction(m_buttonFitZoom);
    m_timelineToolBar->addAction(m_zoomOut);
    m_timelineToolBar->addWidget(m_zoomSlider);
    m_timelineToolBar->addAction(m_zoomIn);*/
613

614
    // Populate encoding profiles
615
    KConfig conf(QStringLiteral("encodingprofiles.rc"), KConfig::CascadeConfig, QStandardPaths::DataLocation);
616
    if (KdenliveSettings::proxyparams().isEmpty() || KdenliveSettings::proxyextension().isEmpty()) {
617 618 619 620 621 622 623 624 625 626
        KConfigGroup group(&conf, "proxy");
        QMap< QString, QString > values = group.entryMap();
        QMapIterator<QString, QString> i(values);
        if (i.hasNext()) {
            i.next();
            QString data = i.value();
            KdenliveSettings::setProxyparams(data.section(';', 0, 0));
            KdenliveSettings::setProxyextension(data.section(';', 1, 1));
        }
    }
627
    if (KdenliveSettings::v4l_parameters().isEmpty() || KdenliveSettings::v4l_extension().isEmpty()) {
628 629 630 631 632 633 634 635 636 637
        KConfigGroup group(&conf, "video4linux");
        QMap< QString, QString > values = group.entryMap();
        QMapIterator<QString, QString> i(values);
        if (i.hasNext()) {
            i.next();
            QString data = i.value();
            KdenliveSettings::setV4l_parameters(data.section(';', 0, 0));
            KdenliveSettings::setV4l_extension(data.section(';', 1, 1));
        }
    }
638 639 640 641 642 643 644 645 646 647 648
    if (KdenliveSettings::grab_parameters().isEmpty() || KdenliveSettings::grab_extension().isEmpty()) {
        KConfigGroup group(&conf, "screengrab");
        QMap< QString, QString > values = group.entryMap();
        QMapIterator<QString, QString> i(values);
        if (i.hasNext()) {
            i.next();
            QString data = i.value();
            KdenliveSettings::setGrab_parameters(data.section(';', 0, 0));
            KdenliveSettings::setGrab_extension(data.section(';', 1, 1));
        }
    }
649
    if (KdenliveSettings::decklink_parameters().isEmpty() || KdenliveSettings::decklink_extension().isEmpty()) {
650 651 652 653 654 655 656 657 658 659
        KConfigGroup group(&conf, "decklink");
        QMap< QString, QString > values = group.entryMap();
        QMapIterator<QString, QString> i(values);
        if (i.hasNext()) {
            i.next();
            QString data = i.value();
            KdenliveSettings::setDecklink_parameters(data.section(';', 0, 0));
            KdenliveSettings::setDecklink_extension(data.section(';', 1, 1));
        }
    }
Till Theato's avatar
Till Theato committed
660
    pCore->projectManager()->init(Url, clipsToLoad);
661
    QTimer::singleShot(0, pCore->projectManager(), SLOT(slotLoadOnOpen()));
662
    QTimer::singleShot(0, this, SIGNAL(GUISetupDone()));
663
    connect(this, SIGNAL(reloadTheme()), this, SLOT(slotReloadTheme()), Qt::UniqueConnection);
664

665 666 667
#ifdef USE_JOGSHUTTLE
    new JogManager(this);
#endif
668
    scmanager->slotCheckActiveScopes();
Laurent Montel's avatar
Laurent Montel committed
669
    m_messageLabel->setMessage(QStringLiteral("This is a beta version. Always backup your data"), MltError);
670
}
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
671

672 673
void MainWindow::slotThemeChanged(const QString &theme)
{
674
    disconnect(this, SIGNAL(reloadTheme()), this, SLOT(slotReloadTheme()));
675 676 677 678
    KSharedConfigPtr config = KSharedConfig::openConfig(theme);
    setPalette(KColorScheme::createApplicationPalette(config));
    qApp->setPalette(palette());
    QPalette plt = palette();
679 680

    KdenliveSettings::setColortheme(theme);
681 682 683 684
    if (m_effectStack) {
        m_effectStack->updatePalette();
        m_effectStack->transitionConfig()->updatePalette();
    }
685
    if (m_effectList) m_effectList->updatePalette();
686
    if (m_transitionList) m_transitionList->updatePalette();
687 688
    if (m_clipMonitor) m_clipMonitor->setPalette(plt);
    if (m_projectMonitor) m_projectMonitor->setPalette(plt);
689 690
    if (m_messageLabel)
        m_messageLabel->updatePalette();
691
    if (pCore->projectManager() && pCore->projectManager()->currentTimeline()) {
692
        pCore->projectManager()->currentTimeline()->updatePalette();
693
    }
694 695 696
    if (m_timelineArea) {
        m_timelineArea->setPalette(plt);
    }
697

698 699
#if KXMLGUI_VERSION_MINOR < 23 && KXMLGUI_VERSION_MAJOR == 5
    // Not required anymore with auto colored icons since KF5 5.23
700 701 702 703 704 705 706 707 708
    QColor background = plt.window().color();
    bool useDarkIcons = background.value() < 100;
    if (m_themeInitialized && useDarkIcons != m_isDarkTheme) {
        if (pCore->bin()) {
            pCore->bin()->refreshIcons();
        }
        if (m_clipMonitor) m_clipMonitor->refreshIcons();
        if (m_projectMonitor) m_projectMonitor->refreshIcons();
        if (pCore->monitorManager()) pCore->monitorManager()->refreshIcons();
Vincent Pinon's avatar
Vincent Pinon committed
709
        if (m_effectStack && m_effectStack->transitionConfig()) m_effectStack->transitionConfig()->refreshIcons();
Jean-Baptiste Mardelle's avatar