mainwindow.cpp 183 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          *
 ***************************************************************************/

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

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

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

#include <QAction>
Laurent Montel's avatar
Laurent Montel committed
97
#include "kdenlive_debug.h"
98 99 100
#include <QStatusBar>
#include <QTemporaryFile>
#include <QMenu>
101
#include <QUndoGroup>
102
#include <QFileDialog>
103
#include <QStyleFactory>
104
#include <QMenuBar>
105 106

#include <stdlib.h>
107
#include <QStandardPaths>
Vincent Pinon's avatar
Vincent Pinon committed
108 109 110 111
#include <KConfigGroup>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
112
#include <QScreen>
113

114
static const char version[] = KDENLIVE_VERSION;
115 116
namespace Mlt
{
117
class Producer;
Laurent Montel's avatar
Laurent Montel committed
118
}
119

Marco Gittler's avatar
Marco Gittler committed
120 121 122 123 124
EffectsList MainWindow::videoEffects;
EffectsList MainWindow::audioEffects;
EffectsList MainWindow::customEffects;
EffectsList MainWindow::transitions;

Laurent Montel's avatar
Laurent Montel committed
125 126
QMap<QString, QImage> MainWindow::m_lumacache;
QMap<QString, QStringList> MainWindow::m_lumaFiles;
127

128
/*static bool sortByNames(const QPair<QString, QAction *> &a, const QPair<QString, QAction*> &b)
129 130
{
    return a.first < b.first;
131
}*/
132

Yuri Chornoivan's avatar
Yuri Chornoivan committed
133
// determine the default KDE style as defined BY THE USER
134
// (as opposed to whatever style KDE considers default)
Laurent Montel's avatar
Laurent Montel committed
135
static QString defaultStyle(const char *fallback = nullptr)
136 137 138 139 140 141
{
    KSharedConfigPtr kdeGlobals = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::NoGlobals);
    KConfigGroup cg(kdeGlobals, "KDE");
    return cg.readEntry("widgetStyle", fallback);
}

142
MainWindow::MainWindow(QWidget *parent) :
143
    KXmlGuiWindow(parent),
Laurent Montel's avatar
Laurent Montel committed
144 145 146
    m_timelineArea(nullptr),
    m_stopmotion(nullptr),
    m_effectStack(nullptr),
Vincent Pinon's avatar
Vincent Pinon committed
147
    m_exitCode(EXIT_SUCCESS),
Laurent Montel's avatar
Laurent Montel committed
148 149 150 151 152 153 154
    m_effectList(nullptr),
    m_transitionList(nullptr),
    m_clipMonitor(nullptr),
    m_projectMonitor(nullptr),
    m_recMonitor(nullptr),
    m_renderWidget(nullptr),
    m_messageLabel(nullptr),
155 156
    m_themeInitialized(false),
    m_isDarkTheme(false)
157
{
158 159 160 161
}

void MainWindow::init(const QString &MltPath, const QUrl &Url, const QString &clipsToLoad)
{
162 163

    // Widget themes for non KDE users
Laurent Montel's avatar
Laurent Montel committed
164
    KActionMenu *stylesAction = new KActionMenu(i18n("Style"), this);
165 166
    QActionGroup *stylesGroup = new QActionGroup(stylesAction);

167 168 169
    // 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();
170 171 172 173 174
    if (KdenliveSettings::widgetstyle().isEmpty()) {
        // First run
        QStringList incompatibleStyles;
        incompatibleStyles << QStringLiteral("GTK+") << QStringLiteral("windowsvista") << QStringLiteral("windowsxp");
        if (incompatibleStyles.contains(desktopStyle, Qt::CaseInsensitive)) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
175
            if (availableStyles.contains(QStringLiteral("breeze"), Qt::CaseInsensitive)) {
176 177
                // Auto switch to Breeze theme
                KdenliveSettings::setWidgetstyle(QStringLiteral("Breeze"));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
178
            } else if (availableStyles.contains(QStringLiteral("fusion"), Qt::CaseInsensitive)) {
179 180
                KdenliveSettings::setWidgetstyle(QStringLiteral("Fusion"));
            }
181 182 183
        }
    }

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
184 185 186 187 188 189 190 191
    // Add default style action
    QAction *defaultStyle = new QAction(i18n("Default"), stylesGroup);
    defaultStyle->setCheckable(true);
    stylesAction->addAction(defaultStyle);
    if (KdenliveSettings::widgetstyle().isEmpty()) {
        defaultStyle->setChecked(true);
    }

Laurent Montel's avatar
Laurent Montel committed
192
    foreach (const QString &style, availableStyles) {
193 194 195
        QAction *a = new QAction(style, stylesGroup);
        a->setCheckable(true);
        a->setData(style);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
196 197 198
        if (KdenliveSettings::widgetstyle() == style) {
            a->setChecked(true);
        }
199 200 201 202 203
        stylesAction->addAction(a);
    }
    connect(stylesGroup, &QActionGroup::triggered, this, &MainWindow::slotChangeStyle);

    // Color schemes
Laurent Montel's avatar
Laurent Montel committed
204
    KActionMenu *themeAction = new KActionMenu(i18n("Theme"), this);
205 206
    ThemeManager::instance()->setThemeMenuAction(themeAction);
    ThemeManager::instance()->setCurrentTheme(KdenliveSettings::colortheme());
Laurent Montel's avatar
Laurent Montel committed
207
    connect(ThemeManager::instance(), &ThemeManager::signalThemeChanged, this, &MainWindow::slotThemeChanged, Qt::DirectConnection);
208

209
    if (!KdenliveSettings::widgetstyle().isEmpty() && QString::compare(desktopStyle, KdenliveSettings::widgetstyle(), Qt::CaseInsensitive) != 0) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
210 211
        // User wants a custom widget style, init
        doChangeStyle();
Laurent Montel's avatar
Laurent Montel committed
212 213
    } else {
        ThemeManager::instance()->slotChangePalette();
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
214
    }
215
    //QIcon::setThemeSearchPaths(QStringList() <<QStringLiteral(":/icons/"));
216 217

    new RenderingAdaptor(this);
218 219
    QString defaultProfile = KdenliveSettings::default_profile();
    KdenliveSettings::setCurrent_profile(defaultProfile.isEmpty() ? ProjectManager::getDefaultProjectFormat() : defaultProfile);
220 221

    // If using a custom profile, make sure the file exists or fallback to default
Laurent Montel's avatar
Laurent Montel committed
222
    if (KdenliveSettings::current_profile().startsWith(QLatin1Char('/')) && !QFile::exists(KdenliveSettings::current_profile())) {
223
        KMessageBox::sorry(this, i18n("Cannot find your default profile, switching to ATSC 1080p 25"));
Laurent Montel's avatar
Laurent Montel committed
224 225
        KdenliveSettings::setCurrent_profile(QStringLiteral("atsc_1080p_25"));
        KdenliveSettings::setDefault_profile(QStringLiteral("atsc_1080p_25"));
226
    }
227
    m_commandStack = new QUndoGroup(this);
228 229
    m_timelineArea = new QTabWidget(this);
    //m_timelineArea->setTabReorderingEnabled(true);
230
    m_timelineArea->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
231
    m_timelineArea->setMinimumHeight(100);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
232 233 234
    // Hide tabbar
    QTabBar *bar = m_timelineArea->findChild<QTabBar *>();
    bar->setHidden(true);
235

236
    m_gpuAllowed = initEffects::parseEffectFiles(pCore->getMltRepository());
237
    //initEffects::parseCustomEffectsFile();
238

239
    m_shortcutRemoveFocus = new QShortcut(QKeySequence(QStringLiteral("Esc")), this);
Laurent Montel's avatar
Laurent Montel committed
240
    connect(m_shortcutRemoveFocus, &QShortcut::activated, this, &MainWindow::slotRemoveFocus);
Simon Eugster's avatar
Simon Eugster committed
241

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

Laurent Montel's avatar
Laurent Montel committed
268
    QDockWidget *libraryDock = addDock(i18n("Library"), QStringLiteral("library"), pCore->library());
Simon Eugster's avatar
Simon Eugster committed
269

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
270
    m_clipMonitor = new Monitor(Kdenlive::ClipMonitor, pCore->monitorManager(), this);
271
    pCore->bin()->setMonitor(m_clipMonitor);
272
    connect(m_clipMonitor, &Monitor::showConfigDialog, this, &MainWindow::slotPreferences);
273 274
    connect(m_clipMonitor, &Monitor::addMarker, this, &MainWindow::slotAddMarkerGuideQuickly);
    connect(m_clipMonitor, &Monitor::deleteMarker, this, &MainWindow::slotDeleteClipMarker);
275 276
    connect(m_clipMonitor, &Monitor::seekToPreviousSnap, this, &MainWindow::slotSnapRewind);
    connect(m_clipMonitor, &Monitor::seekToNextSnap, this, &MainWindow::slotSnapForward);
277

Laurent Montel's avatar
Laurent Montel committed
278
    connect(pCore->bin(), &Bin::clipNeedsReload, this, &MainWindow::slotUpdateClip);
Laurent Montel's avatar
Laurent Montel committed
279
    connect(pCore->bin(), &Bin::findInTimeline, this, &MainWindow::slotClipInTimeline);
280

281 282
    //TODO deprecated, replace with Bin methods if necessary
    /*connect(m_projectList, SIGNAL(loadingIsOver()), this, SLOT(slotElapsedTime()));
283
    connect(m_projectList, SIGNAL(updateRenderStatus()), this, SLOT(slotCheckRenderStatus()));
Laurent Montel's avatar
Laurent Montel committed
284
    connect(m_projectList, SIGNAL(updateProfile(QString)), this, SLOT(slotUpdateProjectProfile(QString)));
285
    connect(m_projectList, SIGNAL(refreshClip(QString,bool)), pCore->monitorManager(), SLOT(slotRefreshCurrentMonitor(QString)));
286
    connect(m_clipMonitor, SIGNAL(zoneUpdated(QPoint)), m_projectList, SLOT(slotUpdateClipCut(QPoint)));*/
Laurent Montel's avatar
Laurent Montel committed
287 288
    connect(m_clipMonitor, &Monitor::extractZone, pCore->bin(), &Bin::slotStartCutJob);
    connect(m_clipMonitor, &Monitor::passKeyPress, this, &MainWindow::triggerKey);
289

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
290
    m_projectMonitor = new Monitor(Kdenlive::ProjectMonitor, pCore->monitorManager(), this);
Laurent Montel's avatar
Laurent Montel committed
291
    connect(m_projectMonitor, &Monitor::passKeyPress, this, &MainWindow::triggerKey);
292 293 294 295
    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);
296
    connect(m_loopClip, &QAction::triggered, m_projectMonitor, &Monitor::slotLoopClip);
Laurent Montel's avatar
Laurent Montel committed
297
    connect(m_projectMonitor, SIGNAL(updateGuide(int, QString)), this, SLOT(slotEditGuide(int, QString)));
298

Laurent Montel's avatar
Laurent Montel committed
299 300 301 302 303
    /*
        //TODO disabled until ported to qml
        m_recMonitor = new RecMonitor(Kdenlive::RecordMonitor, pCore->monitorManager(), this);
        connect(m_recMonitor, SIGNAL(addProjectClip(QUrl)), this, SLOT(slotAddProjectClip(QUrl)));
        connect(m_recMonitor, SIGNAL(addProjectClipList(QList<QUrl>)), this, SLOT(slotAddProjectClipList(QList<QUrl>)));
304

Laurent Montel's avatar
Laurent Montel committed
305
    */
306
    pCore->monitorManager()->initMonitors(m_clipMonitor, m_projectMonitor, m_recMonitor);
Laurent Montel's avatar
Laurent Montel committed
307
    connect(m_clipMonitor, SIGNAL(addMasterEffect(QString, QDomElement)), pCore->bin(), SLOT(slotEffectDropped(QString, QDomElement)));
308

309 310
    // Audio spectrum scope
    m_audioSpectrum = new AudioGraphSpectrum(pCore->monitorManager());
Laurent Montel's avatar
Laurent Montel committed
311
    QDockWidget *spectrumDock = addDock(i18n("Audio Spectrum"), QStringLiteral("audiospectrum"), m_audioSpectrum);
312 313 314 315 316
    connect(this, &MainWindow::reloadTheme, m_audioSpectrum, &AudioGraphSpectrum::refreshPixmap);
    // Close library and audiospectrum on first run
    libraryDock->close();
    spectrumDock->close();

317
    m_projectBinDock = addDock(i18n("Project Bin"), QStringLiteral("project_bin"), pCore->bin());
318
    m_effectStack = new EffectStackView2(m_projectMonitor, this);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
319

Laurent Montel's avatar
Laurent Montel committed
320 321 322
    connect(m_effectStack, &EffectStackView2::startFilterJob, pCore->bin(), &Bin::slotStartFilterJob);
    connect(pCore->bin(), &Bin::masterClipSelected, m_effectStack, &EffectStackView2::slotMasterClipItemSelected);
    connect(pCore->bin(), &Bin::masterClipUpdated, m_effectStack, &EffectStackView2::slotRefreshMasterClipEffects);
Laurent Montel's avatar
Laurent Montel committed
323
    connect(m_effectStack, SIGNAL(addMasterEffect(QString, QDomElement)), pCore->bin(), SLOT(slotEffectDropped(QString, QDomElement)));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
324
    connect(m_effectStack, SIGNAL(updateMasterEffect(QString,QDomElement,QDomElement,int,bool)), pCore->bin(), SLOT(slotUpdateEffect(QString,QDomElement,QDomElement,int,bool)));
Laurent Montel's avatar
Laurent Montel committed
325
    connect(m_effectStack, SIGNAL(changeMasterEffectState(QString, QList<int>, bool)), pCore->bin(), SLOT(slotChangeEffectState(QString, QList<int>, bool)));
Laurent Montel's avatar
Laurent Montel committed
326
    connect(m_effectStack, &EffectStackView2::removeMasterEffect, pCore->bin(), &Bin::slotDeleteEffect);
Laurent Montel's avatar
Laurent Montel committed
327
    connect(m_effectStack, SIGNAL(changeEffectPosition(QString, QList<int>, int)), pCore->bin(), SLOT(slotMoveEffect(QString, QList<int>, int)));
Laurent Montel's avatar
Laurent Montel committed
328
    connect(m_effectStack, &EffectStackView2::reloadEffects, this, &MainWindow::slotReloadEffects);
Laurent Montel's avatar
Laurent Montel committed
329
    connect(m_effectStack, SIGNAL(displayMessage(QString, int)), m_messageLabel, SLOT(setProgressMessage(QString, int)));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
330

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
331
    m_effectStackDock = addDock(i18n("Properties"), QStringLiteral("effect_stack"), m_effectStack);
332

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

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

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

346
    m_undoView = new QUndoView();
347
    m_undoView->setCleanIcon(KoIconUtils::themedIcon(QStringLiteral("edit-clear")));
348 349
    m_undoView->setEmptyLabel(i18n("Clean"));
    m_undoView->setGroup(m_commandStack);
350
    m_undoViewDock = addDock(i18n("Undo History"), QStringLiteral("undo_history"), m_undoView);
351

352
    // Color and icon theme stuff
353
    addAction(QStringLiteral("themes_menu"), themeAction);
Laurent Montel's avatar
Laurent Montel committed
354
    connect(m_commandStack, &QUndoGroup::cleanChanged, m_saveAction, &QAction::setDisabled);
355
    addAction(QStringLiteral("styles_menu"), stylesAction);
Simon Eugster's avatar
Simon Eugster committed
356

357 358 359 360 361 362
    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
363 364 365 366
    // Close non-general docks for the initial layout
    // only show important ones
    m_undoViewDock->close();

367
    /// Tabify Widgets
368
    tabifyDockWidget(m_transitionListDock, m_effectListDock);
369
    tabifyDockWidget(m_effectStackDock, pCore->bin()->clipPropertiesDock());
370
    //tabifyDockWidget(m_effectListDock, m_effectStackDock);
371

372
    tabifyDockWidget(m_clipMonitorDock, m_projectMonitorDock);
373 374 375
    if (m_recMonitor) {
        tabifyDockWidget(m_clipMonitorDock, m_recMonitorDock);
    }
376
    bool firstRun = readOptions();
Simon Eugster's avatar
Simon Eugster committed
377

378
    QAction *action;
379 380
    // 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());
381
    action = new QAction(KoIconUtils::themedIcon(QStringLiteral("media-record")), i18n("Capture frame"), this);
382
    //action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
383
    m_stopmotion_actions->addAction(QStringLiteral("stopmotion_capture"), action);
384
    action = new QAction(i18n("Switch live / captured frame"), this);
385
    //action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
386 387
    m_stopmotion_actions->addAction(QStringLiteral("stopmotion_switch"), action);
    action = new QAction(KoIconUtils::themedIcon(QStringLiteral("edit-paste")), i18n("Show last frame over video"), this);
388 389
    action->setCheckable(true);
    action->setChecked(false);
390
    m_stopmotion_actions->addAction(QStringLiteral("stopmotion_overlay"), action);
391

392
    // Monitor Record action
393
    addAction(QStringLiteral("switch_monitor_rec"), m_clipMonitor->recAction());
394

395
    // Build effects menu
396
    m_effectsMenu = new QMenu(i18n("Add Effect"), this);
397 398
    m_effectActions = new KActionCategory(i18n("Effects"), actionCollection());
    m_effectList->reloadEffectList(m_effectsMenu, m_effectActions);
399

400 401 402 403
    m_transitionsMenu = new QMenu(i18n("Add Transition"), this);
    m_transitionActions = new KActionCategory(i18n("Transitions"), actionCollection());
    m_transitionList->reloadEffectList(m_transitionsMenu, m_transitionActions);

404
    ScopeManager *scmanager = new ScopeManager(this);
405

Till Theato's avatar
Till Theato committed
406
    new LayoutManagement(this);
407
    new HideTitleBars(this);
408
    new TimelineSearch(this);
409 410
    m_extraFactory = new KXMLGUIClient(this);
    buildDynamicActions();
411

412 413 414 415
    // Add shortcut to action tooltips
    QList< KActionCollection * > collections = KActionCollection::allCollections();
    for (int i = 0; i < collections.count(); ++i) {
        KActionCollection *coll = collections.at(i);
Laurent Montel's avatar
Laurent Montel committed
416
        foreach (QAction *tempAction, coll->actions()) {
417
            // find the shortcut pattern and delete (note the preceding space in the RegEx)
Laurent Montel's avatar
Laurent Montel committed
418
            QString strippedTooltip = tempAction->toolTip().remove(QRegExp(QStringLiteral("\\s\\(.*\\)")));
419
            // append shortcut if it exists for action
Laurent Montel's avatar
Laurent Montel committed
420 421 422
            if (tempAction->shortcut() == QKeySequence(0)) {
                tempAction->setToolTip(strippedTooltip);
            } else {
423
                tempAction->setToolTip(strippedTooltip + QStringLiteral(" (") + tempAction->shortcut().toString() + QLatin1Char(')'));
Laurent Montel's avatar
Laurent Montel committed
424
            }
425 426
        }
    }
427

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

    QToolButton *basketButton = new QToolButton(this);
    basketButton->setMenu(menu);
441
    basketButton->setToolButtonStyle(toolBar()->toolButtonStyle());
442 443
    basketButton->setDefaultAction(widgetlist);
    basketButton->setPopupMode(QToolButton::InstantPopup);
444
    //basketButton->setText(i18n("Favorite Effects"));
445
    basketButton->setToolTip(i18n("Favorite Effects"));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
446
    basketButton->setIcon(KoIconUtils::themedIcon(QStringLiteral("favorite")));
447

Laurent Montel's avatar
Laurent Montel committed
448
    QWidgetAction *toolButtonAction = new QWidgetAction(this);
449
    toolButtonAction->setText(i18n("Favorite Effects"));
Laurent Montel's avatar
Laurent Montel committed
450
    toolButtonAction->setIcon(KoIconUtils::themedIcon(QStringLiteral("favorite")));
451
    toolButtonAction->setDefaultWidget(basketButton);
452
    addAction(QStringLiteral("favorite_effects"), toolButtonAction);
Laurent Montel's avatar
Laurent Montel committed
453
    connect(toolButtonAction, &QAction::triggered, basketButton, &QToolButton::showMenu);
454

455 456 457 458 459
    // 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);
Laurent Montel's avatar
Laurent Montel committed
460
    QWidgetAction *renderButtonAction = new QWidgetAction(this);
461 462 463 464 465
    renderButtonAction->setText(i18n("Render Button"));
    renderButtonAction->setIcon(KoIconUtils::themedIcon(QStringLiteral("media-record")));
    renderButtonAction->setDefaultWidget(timelineRender);
    addAction(QStringLiteral("project_render_button"), renderButtonAction);

466
    // Timeline preview button
467
    ProgressButton *timelinePreview = new ProgressButton(i18n("Rendering preview"), 1000, this);
468 469
    QMenu *tlMenu = new QMenu(this);
    timelinePreview->setMenu(tlMenu);
470
    connect(this, &MainWindow::setPreviewProgress, timelinePreview, &ProgressButton::setProgress);
Laurent Montel's avatar
Laurent Montel committed
471
    QWidgetAction *previewButtonAction = new QWidgetAction(this);
472
    previewButtonAction->setText(i18n("Timeline Preview"));
473
    previewButtonAction->setIcon(KoIconUtils::themedIcon(QStringLiteral("preview-render-on")));
474
    previewButtonAction->setDefaultWidget(timelinePreview);
475
    addAction(QStringLiteral("timeline_preview_button"), previewButtonAction);
476

477
    setupGUI();
478 479 480 481 482 483 484 485 486 487
    if (firstRun) {
        QScreen *current = QApplication::primaryScreen();
        if (current) {
            if (current->availableSize().height() < 1000) {
                resize(current->availableSize());
            } else {
                resize(current->availableSize() / 1.5);
            }
        }
    }
488 489
    timelinePreview->setToolButtonStyle(m_timelineToolBar->toolButtonStyle());
    connect(m_timelineToolBar, &QToolBar::toolButtonStyleChanged, timelinePreview, &ProgressButton::setToolButtonStyle);
490

491 492 493
    timelineRender->setToolButtonStyle(toolBar()->toolButtonStyle());
    /*connect(m_timelineToolBar, &QToolBar::toolButtonStyleChanged, timelinePreview, &ProgressButton::setToolButtonStyle);*/

494 495
    /*ScriptingPart* sp = new ScriptingPart(this, QStringList());
    guiFactory()->addClient(sp);*/
496

497
    loadGenerators();
498
    loadDockActions();
499
    loadClipActions();
500 501

    // Connect monitor overlay info menu.
Laurent Montel's avatar
Laurent Montel committed
502
    QMenu *monitorOverlay = static_cast<QMenu *>(factory()->container(QStringLiteral("monitor_config_overlay"), this));
Laurent Montel's avatar
Laurent Montel committed
503
    connect(monitorOverlay, &QMenu::triggered, this, &MainWindow::slotSwitchMonitorOverlay);
504

Laurent Montel's avatar
Laurent Montel committed
505
    m_projectMonitor->setupMenu(static_cast<QMenu *>(factory()->container(QStringLiteral("monitor_go"), this)), monitorOverlay, m_playZone, m_loopZone, nullptr, m_loopClip);
Laurent Montel's avatar
Laurent Montel committed
506
    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)));
507

Laurent Montel's avatar
Laurent Montel committed
508
    QMenu *clipInTimeline = static_cast<QMenu *>(factory()->container(QStringLiteral("clip_in_timeline"), this));
509
    clipInTimeline->setIcon(KoIconUtils::themedIcon(QStringLiteral("go-jump")));
510
    pCore->bin()->setupGeneratorMenu();
Marco Gittler's avatar
Marco Gittler committed
511

Laurent Montel's avatar
Laurent Montel committed
512
    connect(pCore->monitorManager(), &MonitorManager::updateOverlayInfos, this, &MainWindow::slotUpdateMonitorOverlays);
513

514
    // Setup and fill effects and transitions menus.
Laurent Montel's avatar
Laurent Montel committed
515
    QMenu *m = static_cast<QMenu *>(factory()->container(QStringLiteral("video_effects_menu"), this));
Laurent Montel's avatar
Laurent Montel committed
516 517 518
    connect(m, &QMenu::triggered, this, &MainWindow::slotAddVideoEffect);
    connect(m_effectsMenu, &QMenu::triggered, this, &MainWindow::slotAddVideoEffect);
    connect(m_transitionsMenu, &QMenu::triggered, this, &MainWindow::slotAddTransition);
519

520 521 522 523
    m_timelineContextMenu = new QMenu(this);
    m_timelineContextClipMenu = new QMenu(this);
    m_timelineContextTransitionMenu = new QMenu(this);

524 525
    m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("insert_space")));
    m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("delete_space")));
526
    m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("delete_space_all_tracks")));
527 528
    m_timelineContextMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Paste)));

529
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("clip_in_project_tree")));
530
    //m_timelineContextClipMenu->addAction(actionCollection()->action("clip_to_project_tree"));
531
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("delete_timeline_clip")));
532
    m_timelineContextClipMenu->addSeparator();
533 534 535 536 537
    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")));
538
    m_timelineContextClipMenu->addSeparator();
539
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("cut_timeline_clip")));
540
    m_timelineContextClipMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Copy)));
541
    m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("paste_effects")));
542
    m_timelineContextClipMenu->addSeparator();
543

Laurent Montel's avatar
Laurent Montel committed
544
    QMenu *markersMenu = static_cast<QMenu *>(factory()->container(QStringLiteral("marker_menu"), this));
545
    m_timelineContextClipMenu->addMenu(markersMenu);
546
    m_timelineContextClipMenu->addSeparator();
547
    m_timelineContextClipMenu->addMenu(m_transitionsMenu);
548
    m_timelineContextClipMenu->addMenu(m_effectsMenu);
Marco Gittler's avatar
Marco Gittler committed
549

550
    m_timelineContextTransitionMenu->addAction(actionCollection()->action(QStringLiteral("delete_timeline_clip")));
551
    m_timelineContextTransitionMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Copy)));
552

553
    m_timelineContextTransitionMenu->addAction(actionCollection()->action(QStringLiteral("auto_transition")));
554

Laurent Montel's avatar
Laurent Montel committed
555 556
    connect(m_effectList, &EffectsListView::addEffect, this, &MainWindow::slotAddEffect);
    connect(m_effectList, &EffectsListView::reloadEffects, this, &MainWindow::slotReloadEffects);
557

558
    slotConnectMonitors();
559

560
    m_timelineToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
561
    // TODO: let user select timeline toolbar toolbutton style
562
    //connect(toolBar(), &QToolBar::iconSizeChanged, m_timelineToolBar, &QToolBar::setToolButtonStyle);
563 564
    m_timelineToolBar->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(m_timelineToolBar, &QWidget::customContextMenuRequested, this, &MainWindow::showTimelineToolbarMenu);
565 566

    QAction *prevRender = actionCollection()->action(QStringLiteral("prerender_timeline_zone"));
567 568
    QAction *stopPrevRender = actionCollection()->action(QStringLiteral("stop_prerender_timeline"));
    tlMenu->addAction(stopPrevRender);
569 570
    tlMenu->addAction(actionCollection()->action(QStringLiteral("set_render_timeline_zone")));
    tlMenu->addAction(actionCollection()->action(QStringLiteral("unset_render_timeline_zone")));
571
    tlMenu->addAction(actionCollection()->action(QStringLiteral("clear_render_timeline_zone")));
572 573 574 575 576 577 578

    // 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);
579
    tlMenu->addSeparator();
580
    tlMenu->addAction(actionCollection()->action(QStringLiteral("disable_preview")));
581
    tlMenu->addAction(actionCollection()->action(QStringLiteral("manage_cache")));
582
    timelinePreview->defineDefaultAction(prevRender, stopPrevRender);
583
    timelinePreview->setAutoRaise(true);
584

585 586
    QAction *showRender = actionCollection()->action(QStringLiteral("project_render"));
    tlrMenu->addAction(showRender);
587
    tlrMenu->addAction(actionCollection()->action(QStringLiteral("stop_project_render")));
588
    timelineRender->defineDefaultAction(showRender, showRender);
589 590
    timelineRender->setAutoRaise(true);

591
    //m_timelineToolBar->addAction(toolButtonAction);
592

593
    /*QWidget *sep = new QWidget(this);
594
    sep->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
595 596 597 598 599 600 601 602 603 604 605
    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);*/
606

607
    // Populate encoding profiles
608
    KConfig conf(QStringLiteral("encodingprofiles.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation);
609
    if (KdenliveSettings::proxyparams().isEmpty() || KdenliveSettings::proxyextension().isEmpty()) {
610 611 612 613 614 615
        KConfigGroup group(&conf, "proxy");
        QMap< QString, QString > values = group.entryMap();
        QMapIterator<QString, QString> i(values);
        if (i.hasNext()) {
            i.next();
            QString data = i.value();
616 617
            KdenliveSettings::setProxyparams(data.section(QLatin1Char(';'), 0, 0));
            KdenliveSettings::setProxyextension(data.section(QLatin1Char(';'), 1, 1));
618 619
        }
    }
620
    if (KdenliveSettings::v4l_parameters().isEmpty() || KdenliveSettings::v4l_extension().isEmpty()) {
621 622 623 624 625 626
        KConfigGroup group(&conf, "video4linux");
        QMap< QString, QString > values = group.entryMap();
        QMapIterator<QString, QString> i(values);
        if (i.hasNext()) {
            i.next();
            QString data = i.value();
627 628
            KdenliveSettings::setV4l_parameters(data.section(QLatin1Char(';'), 0, 0));
            KdenliveSettings::setV4l_extension(data.section(QLatin1Char(';'), 1, 1));
629 630
        }
    }
631 632 633 634 635 636 637
    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();
638 639
            KdenliveSettings::setGrab_parameters(data.section(QLatin1Char(';'), 0, 0));
            KdenliveSettings::setGrab_extension(data.section(QLatin1Char(';'), 1, 1));
640 641
        }
    }
642
    if (KdenliveSettings::decklink_parameters().isEmpty() || KdenliveSettings::decklink_extension().isEmpty()) {
643 644 645 646 647 648
        KConfigGroup group(&conf, "decklink");
        QMap< QString, QString > values = group.entryMap();
        QMapIterator<QString, QString> i(values);
        if (i.hasNext()) {
            i.next();
            QString data = i.value();
649 650
            KdenliveSettings::setDecklink_parameters(data.section(QLatin1Char(';'), 0, 0));
            KdenliveSettings::setDecklink_extension(data.section(QLatin1Char(';'), 1, 1));
651 652
        }
    }
Vincent Pinon's avatar
Vincent Pinon committed
653 654 655 656

    if (!QDir(KdenliveSettings::currenttmpfolder()).isReadable())
        KdenliveSettings::setCurrenttmpfolder(QStandardPaths::writableLocation(QStandardPaths::TempLocation));

Till Theato's avatar
Till Theato committed
657
    pCore->projectManager()->init(Url, clipsToLoad);
Laurent Montel's avatar
Laurent Montel committed
658 659 660
    QTimer::singleShot(0, pCore->projectManager(), &ProjectManager::slotLoadOnOpen);
    QTimer::singleShot(0, this, &MainWindow::GUISetupDone);
    connect(this, &MainWindow::reloadTheme, this, &MainWindow::slotReloadTheme, Qt::UniqueConnection);
661

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

669 670
void MainWindow::slotThemeChanged(const QString &theme)
{
Laurent Montel's avatar
Laurent Montel committed
671
    disconnect(this, &MainWindow::reloadTheme, this, &MainWindow::slotReloadTheme);
672 673 674 675
    KSharedConfigPtr config = KSharedConfig::openConfig(theme);
    setPalette(KColorScheme::createApplicationPalette(config));
    qApp->setPalette(palette());
    QPalette plt = palette();
676 677

    KdenliveSettings::setColortheme(theme);
678 679 680 681
    if (m_effectStack) {
        m_effectStack->updatePalette();
        m_effectStack->transitionConfig()->updatePalette();
    }
Laurent Montel's avatar
Laurent Montel committed
682 683 684 685 686 687 688 689 690 691 692 693 694
    if (m_effectList) {
        m_effectList->updatePalette();
    }
    if (m_transitionList) {
        m_transitionList->updatePalette();
    }
    if (m_clipMonitor) {
        m_clipMonitor->setPalette(plt);
    }
    if (m_projectMonitor) {
        m_projectMonitor->setPalette(plt);
    }
    if (m_messageLabel) {
695
        m_messageLabel->updatePalette();
Laurent Montel's avatar
Laurent Montel committed
696
    }
697
    if (pCore->projectManager() && pCore->projectManager()->currentTimeline()) {
698
        pCore->projectManager()->currentTimeline()->updatePalette();
699
    }
700 701 702
    if (m_timelineArea) {
        m_timelineArea->setPalette(plt);
    }
703

704 705
#if KXMLGUI_VERSION_MINOR < 23 && KXMLGUI_VERSION_MAJOR == 5
    // Not required anymore with auto colored icons since KF5 5.23
706 707 708 709 710 711
    QColor background = plt.window().color();
    bool useDarkIcons = background.value() < 100;
    if (m_themeInitialized && useDarkIcons != m_isDarkTheme) {
        if (pCore->bin()) {
            pCore->bin()->refreshIcons();
        }
Laurent Montel's avatar
Laurent Montel committed
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
        if (m_clipMonitor) {
            m_clipMonitor->refreshIcons();
        }
        if (m_projectMonitor) {
            m_projectMonitor->refreshIcons();
        }
        if (pCore->monitorManager()) {
            pCore->monitorManager()->refreshIcons();
        }
        if (m_effectStack && m_effectStack->transitionConfig()) {
            m_effectStack->transitionConfig()->refreshIcons();
        }
        if (m_effectList) {
            m_effectList->refreshIcons();
        }
        if (m_effectStack) {
            m_effectStack->refreshIcons();
        }
730 731 732 733
        if (pCore->projectManager() && pCore->projectManager()->currentTimeline()) {
            pCore->projectManager()->currentTimeline()->refreshIcons();
        }

Laurent Montel's avatar
Laurent Montel committed
734
        foreach (QAction *action, actionCollection()->actions()) {
735
            QIcon icon = action->icon();
Laurent Montel's avatar
Laurent Montel committed
736 737 738
            if (icon.isNull()) {
                continue;
            }
739 740
            QString iconName = icon.name();
            QIcon newIcon = KoIconUtils::themedIcon(iconName);
Laurent Montel's avatar
Laurent Montel committed
741 742 743
            if (newIcon.isNull()) {
                continue;
            }
744 745 746 747 748
            action->setIcon(newIcon);
        }
    }
    m_themeInitialized = true;
    m_isDarkTheme = useDarkIcons;
749
#endif
Laurent Montel's avatar
Laurent Montel committed
750
    connect(this, &MainWindow::reloadTheme, this, &MainWindow::slotReloadTheme, Qt::UniqueConnection);
751 752
}

Laurent Montel's avatar
Laurent Montel committed
753 754
bool MainWindow::event(QEvent *e)
{
755
    switch (e->type()) {
Laurent Montel's avatar
Laurent Montel committed
756 757 758 759 760 761
    case QEvent::ApplicationPaletteChange:
        emit reloadTheme();
        e->accept();
        break;
    default:
        break;
762 763 764 765
    }
    return KXmlGuiWindow::event(e);
}

766 767 768 769 770
void MainWindow::slotReloadTheme()
{
    ThemeManager::instance()->slotSettingsChanged();
}

771
MainWindow::~MainWindow()
772
{
Laurent Montel's avatar
Laurent Montel committed
773
    delete m_stopmotion;
774
    delete m_audioSpectrum;
Laurent Montel's avatar
Laurent Montel committed
775 776
    m_effectStack->slotClipItemSelected(nullptr, m_projectMonitor);
    m_effectStack->slotTransitionItemSelected(nullptr, 0, QPoint(), false);
Laurent Montel's avatar
Laurent Montel committed
777 778 779 780 781 782
    if (m_projectMonitor) {
        m_projectMonitor->stop();
    }
    if (m_clipMonitor) {
        m_clipMonitor->stop();
    }
783
    delete pCore;
784 785 786 787
    delete m_effectStack;
    delete m_projectMonitor;
    delete m_clipMonitor;
    delete m_shortcutRemoveFocus;
788
    qDeleteAll(m_transitions);
789 790 791
    Mlt::Factory::close();
}

792 793 794 795 796 797 798 799 800
//virtual
bool MainWindow::queryClose()
{
    if (m_renderWidget) {
        int waitingJobs = m_renderWidget->waitingJobsCount();
        if (waitingJobs > 0) {
            switch (KMessageBox::warningYesNoCancel(this, i18np("You have 1 rendering job waiting in the queue.\nWhat do you want to do with this job?", "You have %1 rendering jobs waiting in the queue.\nWhat do you want to do with these jobs?", waitingJobs), QString(), KGuiItem(i18n("Start them now")), KGuiItem(i18n("Delete them")))) {
            case KMessageBox::Yes :
                // create script with waiting jobs and start it
Laurent Montel's avatar
Laurent Montel committed
801 802 803
                if (m_renderWidget->startWaitingRenderJobs() == false) {
                    return false;
                }
804 805 806 807
                break;
            case KMessageBox::No :
                // Don't do anything, jobs will be deleted
                break;
Laurent Montel's avatar
Laurent Montel committed
808
            default:
809 810 811 812 813 814 815 816
                return false;
            }
        }
    }
    saveOptions();

    // WARNING: According to KMainWindow::queryClose documentation we are not supposed to close the document here?
    return pCore->projectManager()->closeCurrentDocument(true, true);
817 818
}

819 820
void MainWindow::loadGenerators()
{
Laurent Montel's avatar
Laurent Montel committed
821
    QMenu *addMenu = static_cast<QMenu *>(factory()->container(QStringLiteral("generators"), this));
822
    Generators::getGenerators(KdenliveSettings::producerslist(), addMenu);
Laurent Montel's avatar
Laurent Montel committed
823
    connect(addMenu, &QMenu::triggered, this, &MainWindow::buildGenerator);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
824 825
}

826
void MainWindow::buildGenerator(QAction *action)
827
{
828 829 830 831
    Generators gen(m_clipMonitor, action->data().toString(), this);
    if (gen.exec() == QDialog::Accepted) {
        pCore->bin()->slotAddClipToProject(gen.getSavedClip());
    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
832 833
}

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
834
void MainWindow::saveProperties(KConfigGroup &config)