1 /*
2 SPDX-FileCopyrightText: 2014 Till Theato <root@ttill.de>
3 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
4 */
5 
6 #include "core.h"
7 #include "bin/bin.h"
8 #include "bin/projectitemmodel.h"
9 #include "capture/mediacapture.h"
10 #include "doc/docundostack.hpp"
11 #include "doc/kdenlivedoc.h"
12 #include "kdenlive_debug.h"
13 #include "kdenlivesettings.h"
14 #include "library/librarywidget.h"
15 #include "audiomixer/mixermanager.hpp"
16 #include "mainwindow.h"
17 #include "mltconnection.h"
18 #include "mltcontroller/clipcontroller.h"
19 #include "monitor/monitormanager.h"
20 #include "profiles/profilemodel.hpp"
21 #include "profiles/profilerepository.hpp"
22 #include "project/projectmanager.h"
23 #include "timeline2/model/timelineitemmodel.hpp"
24 #include "timeline2/view/timelinecontroller.h"
25 #include "timeline2/view/timelinewidget.h"
26 #include "dialogs/subtitleedit.h"
27 #include "dialogs/textbasededit.h"
28 #include "dialogs/proxytest.h"
29 #include "dialogs/timeremap.h"
30 #include <mlt++/MltRepository.h>
31 
32 #include <KMessageBox>
33 #include <QCoreApplication>
34 #include <QInputDialog>
35 #include <QDir>
36 #include <QQuickStyle>
37 #include <locale>
38 #ifdef Q_OS_MAC
39 #include <xlocale.h>
40 #endif
41 
42 std::unique_ptr<Core> Core::m_self;
Core()43 Core::Core()
44     : audioThumbCache(QStringLiteral("audioCache"), 2000000)
45     , taskManager(this)
46     , m_thumbProfile(nullptr)
47     , m_capture(new MediaCapture(this))
48 {
49 }
50 
prepareShutdown()51 void Core::prepareShutdown()
52 {
53     m_guiConstructed = false;
54     //m_mainWindow->getCurrentTimeline()->controller()->prepareClose();
55     projectItemModel()->blockSignals(true);
56     QThreadPool::globalInstance()->clear();
57 }
58 
~Core()59 Core::~Core()
60 {
61     if (m_monitorManager) {
62         delete m_monitorManager;
63     }
64     if (m_projectManager) {
65         delete m_projectManager;
66     }
67     ClipController::mediaUnavailable.reset();
68 }
69 
build(bool testMode)70 bool Core::build(bool testMode)
71 {
72     if (m_self) {
73         return true;
74     }
75     m_self.reset(new Core());
76     m_self->initLocale();
77 
78     qRegisterMetaType<audioShortVector>("audioShortVector");
79     qRegisterMetaType<QVector<double>>("QVector<double>");
80     qRegisterMetaType<QList<QAction*>>("QList<QAction*>");
81     qRegisterMetaType<MessageType>("MessageType");
82     qRegisterMetaType<stringMap>("stringMap");
83     qRegisterMetaType<audioByteArray>("audioByteArray");
84     qRegisterMetaType<QList<ItemInfo>>("QList<ItemInfo>");
85     qRegisterMetaType<std::shared_ptr<Mlt::Producer>>("std::shared_ptr<Mlt::Producer>");
86     qRegisterMetaType<QVector<int>>();
87     qRegisterMetaType<QDomElement>("QDomElement");
88     qRegisterMetaType<requestClipInfo>("requestClipInfo");
89     qRegisterMetaType<QVector<QPair<QString, QVariant>>>("paramVector");
90     qRegisterMetaType<ProfileParam*>("ProfileParam*");
91 
92     if (!testMode) {
93         // Check if we had a crash
94         QFile lockFile(QDir::temp().absoluteFilePath(QStringLiteral("kdenlivelock")));
95         if (lockFile.exists()) {
96             // a previous instance crashed, propose to delete config files
97             if (KMessageBox::questionYesNo(QApplication::activeWindow(), i18n("Kdenlive crashed on last startup.\nDo you want to reset the configuration files ?")) ==  KMessageBox::Yes)
98             {
99                 // Release startup crash lock file
100                 QFile lockFile(QDir::temp().absoluteFilePath(QStringLiteral("kdenlivelock")));
101                 lockFile.remove();
102                 return false;
103             }
104         } else {
105             // Create lock file
106             lockFile.open(QFile::WriteOnly);
107             lockFile.write(QByteArray());
108             lockFile.close();
109         }
110     }
111 
112     m_self->m_projectItemModel = ProjectItemModel::construct();
113     return true;
114 }
115 
initGUI(bool isAppImage,const QString & MltPath,const QUrl & Url,const QString & clipsToLoad)116 void Core::initGUI(bool isAppImage, const QString &MltPath, const QUrl &Url, const QString &clipsToLoad)
117 {
118     m_profile = KdenliveSettings::default_profile();
119     m_currentProfile = m_profile;
120     m_mainWindow = new MainWindow();
121     m_guiConstructed = true;
122     QStringList styles = QQuickStyle::availableStyles();
123     if (styles.contains(QLatin1String("org.kde.desktop"))) {
124         QQuickStyle::setStyle("org.kde.desktop");
125     } else if (styles.contains(QLatin1String("Fusion"))) {
126         QQuickStyle::setStyle("Fusion");
127     }
128 
129     connect(this, &Core::showConfigDialog, m_mainWindow, &MainWindow::slotPreferences);
130 
131     m_projectManager = new ProjectManager(this);
132     Bin *bin = new Bin(m_projectItemModel, m_mainWindow);
133     m_mainWindow->addBin(bin);
134 
135     connect(bin, &Bin::requestShowClipProperties, bin, &Bin::showClipProperties);
136     connect(m_projectItemModel.get(), &ProjectItemModel::refreshPanel, m_mainWindow->activeBin(), &Bin::refreshPanel);
137     connect(m_projectItemModel.get(), &ProjectItemModel::refreshClip, m_mainWindow->activeBin(), &Bin::refreshClip);
138     connect(m_projectItemModel.get(), static_cast<void (ProjectItemModel::*)(const QStringList &, const QModelIndex &)>(&ProjectItemModel::itemDropped), m_mainWindow->activeBin(),
139             static_cast<void (Bin::*)(const QStringList &, const QModelIndex &)>(&Bin::slotItemDropped));
140     connect(m_projectItemModel.get(), static_cast<void (ProjectItemModel::*)(const QList<QUrl> &, const QModelIndex &)>(&ProjectItemModel::itemDropped), m_mainWindow->activeBin(),
141             static_cast<const QString (Bin::*)(const QList<QUrl> &, const QModelIndex &)>(&Bin::slotItemDropped));
142     connect(m_projectItemModel.get(), &ProjectItemModel::effectDropped, m_mainWindow->activeBin(), &Bin::slotEffectDropped);
143     connect(m_projectItemModel.get(), &ProjectItemModel::addTag, m_mainWindow->activeBin(), &Bin::slotTagDropped);
144     connect(m_projectItemModel.get(), &QAbstractItemModel::dataChanged, m_mainWindow->activeBin(), &Bin::slotItemEdited);
145 
146     m_library = new LibraryWidget(m_projectManager, m_mainWindow);
147     m_subtitleWidget = new SubtitleEdit(m_mainWindow);
148     m_mixerWidget = new MixerManager(m_mainWindow);
149     m_textEditWidget = new TextBasedEdit(m_mainWindow);
150     m_timeRemapWidget = new TimeRemap(m_mainWindow);
151     connect(m_library, SIGNAL(addProjectClips(QList<QUrl>)), m_mainWindow->getBin(), SLOT(droppedUrls(QList<QUrl>)));
152     connect(this, &Core::updateLibraryPath, m_library, &LibraryWidget::slotUpdateLibraryPath);
153     connect(m_capture.get(), &MediaCapture::recordStateChanged, m_mixerWidget, &MixerManager::recordStateChanged);
154     connect(m_mixerWidget, &MixerManager::updateRecVolume, m_capture.get(), &MediaCapture::setAudioVolume);
155     m_monitorManager = new MonitorManager(this);
156     connect(m_monitorManager, &MonitorManager::cleanMixer, m_mixerWidget, &MixerManager::clearMixers);
157     connect(m_subtitleWidget, &SubtitleEdit::addSubtitle, m_mainWindow, &MainWindow::slotAddSubtitle);
158     connect(m_subtitleWidget, &SubtitleEdit::cutSubtitle, this, [this](int id, int cursorPos) {
159         if (m_guiConstructed && m_mainWindow->getCurrentTimeline()->controller()) {
160             m_mainWindow->getCurrentTimeline()->controller()->cutSubtitle(id, cursorPos);
161         }
162     });
163 
164 
165     // The MLT Factory will be initiated there, all MLT classes will be usable only after this
166     if (isAppImage) {
167         QString appPath = qApp->applicationDirPath();
168         KdenliveSettings::setFfmpegpath(QDir::cleanPath(appPath + QStringLiteral("/ffmpeg")));
169         KdenliveSettings::setFfplaypath(QDir::cleanPath(appPath + QStringLiteral("/ffplay")));
170         KdenliveSettings::setFfprobepath(QDir::cleanPath(appPath + QStringLiteral("/ffprobe")));
171         KdenliveSettings::setRendererpath(QDir::cleanPath(appPath + QStringLiteral("/melt")));
172         m_mainWindow->init(QDir::cleanPath(appPath + QStringLiteral("/../share/mlt/profiles")));
173     } else {
174         // Open connection with Mlt
175         m_mainWindow->init(MltPath);
176     }
177     m_projectItemModel->buildPlaylist();
178     // load the profiles from disk
179     ProfileRepository::get()->refresh();
180     // load default profile
181     m_profile = KdenliveSettings::default_profile();
182     // load default profile and ask user to select one if not found.
183     if (m_profile.isEmpty()) {
184         m_profile = ProjectManager::getDefaultProjectFormat();
185         KdenliveSettings::setDefault_profile(m_profile);
186     }
187     profileChanged();
188 
189     if (!ProfileRepository::get()->profileExists(m_profile)) {
190         KMessageBox::sorry(m_mainWindow, i18n("The default profile of Kdenlive is not set or invalid, press OK to set it to a correct value."));
191 
192         // TODO this simple widget should be improved and probably use profileWidget
193         // we get the list of profiles
194         QVector<QPair<QString, QString>> all_profiles = ProfileRepository::get()->getAllProfiles();
195         QStringList all_descriptions;
196         for (const auto &profile : qAsConst(all_profiles)) {
197             all_descriptions << profile.first;
198         }
199 
200         // ask the user
201         bool ok;
202         QString item = QInputDialog::getItem(m_mainWindow, i18n("Select Default Profile"), i18n("Profile:"), all_descriptions, 0, false, &ok);
203         if (ok) {
204             ok = false;
205             for (const auto &profile : qAsConst(all_profiles)) {
206                 if (profile.first == item) {
207                     m_profile = profile.second;
208                     ok = true;
209                 }
210             }
211         }
212         if (!ok) {
213             KMessageBox::error(
214                 m_mainWindow,
215                 i18n("The given profile is invalid. We default to the profile \"dv_pal\", but you can change this from Kdenlive's settings panel"));
216             m_profile = QStringLiteral("dv_pal");
217         }
218         KdenliveSettings::setDefault_profile(m_profile);
219         profileChanged();
220     }
221         // Init producer shown for unavailable media
222     // TODO make it a more proper image, it currently causes a crash on exit
223     ClipController::mediaUnavailable = std::make_shared<Mlt::Producer>(ProfileRepository::get()->getProfile(m_self->m_profile)->profile(), "color:blue");
224     ClipController::mediaUnavailable->set("length", 99999999);
225 
226     if (!Url.isEmpty()) {
227         emit loadingMessageUpdated(i18n("Loading project..."));
228     }
229     projectManager()->init(Url, clipsToLoad);
230     if (qApp->isSessionRestored()) {
231         // NOTE: we are restoring only one window, because Kdenlive only uses one MainWindow
232         m_mainWindow->restore(1, false);
233     }
234     QMetaObject::invokeMethod(pCore->projectManager(), "slotLoadOnOpen", Qt::QueuedConnection);
235     m_mainWindow->show();
236     bin->slotUpdatePalette();
237     emit m_mainWindow->GUISetupDone();
238 }
239 
buildLumaThumbs(const QStringList & values)240 void Core::buildLumaThumbs(const QStringList &values)
241 {
242     for (auto &entry : values) {
243         if (MainWindow::m_lumacache.contains(entry)) {
244             continue;
245         }
246         QImage pix(entry);
247         if (!pix.isNull()) {
248             MainWindow::m_lumacache.insert(entry, pix.scaled(50, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation));
249         }
250     }
251 }
252 
nameForLumaFile(const QString filename)253 const QString Core::nameForLumaFile(const QString filename) {
254     static QMap<QString, QString> names;
255     names.insert("square2-bars.pgm", i18nc("Luma transition name", "Square 2 Bars"));
256     names.insert("checkerboard_small.pgm", i18nc("Luma transition name", "Checkerboard Small"));
257     names.insert("horizontal_blinds.pgm", i18nc("Luma transition name", "Horizontal Blinds"));
258     names.insert("radial.pgm", i18nc("Luma transition name", "Radial"));
259     names.insert("linear_x.pgm", i18nc("Luma transition name", "Linear X"));
260     names.insert("bi-linear_x.pgm", i18nc("Luma transition name", "Bi-Linear X"));
261     names.insert("linear_y.pgm", i18nc("Luma transition name", "Linear Y"));
262     names.insert("bi-linear_y.pgm", i18nc("Luma transition name", "Bi-Linear Y"));
263     names.insert("square.pgm", i18nc("Luma transition name", "Square"));
264     names.insert("square2.pgm", i18nc("Luma transition name", "Square 2"));
265     names.insert("cloud.pgm", i18nc("Luma transition name", "Cloud"));
266     names.insert("symmetric_clock.pgm", i18nc("Luma transition name", "Symmetric Clock"));
267     names.insert("radial-bars.pgm", i18nc("Luma transition name", "Radial Bars"));
268     names.insert("spiral.pgm", i18nc("Luma transition name", "Spiral"));
269     names.insert("spiral2.pgm", i18nc("Luma transition name", "Spiral 2"));
270     names.insert("curtain.pgm", i18nc("Luma transition name", "Curtain"));
271     names.insert("burst.pgm", i18nc("Luma transition name", "Burst"));
272     names.insert("clock.pgm", i18nc("Luma transition name", "Clock"));
273 
274     names.insert("luma01.pgm", i18nc("Luma transition name", "Bar Horizontal"));
275     names.insert("luma02.pgm", i18nc("Luma transition name", "Bar Vertical"));
276     names.insert("luma03.pgm", i18nc("Luma transition name", "Barn Door Horizontal"));
277     names.insert("luma04.pgm", i18nc("Luma transition name", "Barn Door Vertical"));
278     names.insert("luma05.pgm", i18nc("Luma transition name", "Barn Door Diagonal SW-NE"));
279     names.insert("luma06.pgm", i18nc("Luma transition name", "Barn Door Diagonal NW-SE"));
280     names.insert("luma07.pgm", i18nc("Luma transition name", "Diagonal Top Left"));
281     names.insert("luma08.pgm", i18nc("Luma transition name", "Diagonal Top Right"));
282     names.insert("luma09.pgm", i18nc("Luma transition name", "Matrix Waterfall Horizontal"));
283     names.insert("luma10.pgm", i18nc("Luma transition name", "Matrix Waterfall Vertical"));
284     names.insert("luma11.pgm", i18nc("Luma transition name", "Matrix Snake Horizontal"));
285     names.insert("luma12.pgm", i18nc("Luma transition name", "Matrix Snake Parallel Horizontal"));
286     names.insert("luma13.pgm", i18nc("Luma transition name", "Matrix Snake Vertical"));
287     names.insert("luma14.pgm", i18nc("Luma transition name", "Matrix Snake Parallel Vertical"));
288     names.insert("luma15.pgm", i18nc("Luma transition name", "Barn V Up"));
289     names.insert("luma16.pgm", i18nc("Luma transition name", "Iris Circle"));
290     names.insert("luma17.pgm", i18nc("Luma transition name", "Double Iris"));
291     names.insert("luma18.pgm", i18nc("Luma transition name", "Iris Box"));
292     names.insert("luma19.pgm", i18nc("Luma transition name", "Box Bottom Right"));
293     names.insert("luma20.pgm", i18nc("Luma transition name", "Box Bottom Left"));
294     names.insert("luma21.pgm", i18nc("Luma transition name", "Box Right Center"));
295     names.insert("luma22.pgm", i18nc("Luma transition name", "Clock Top"));
296 
297     return names.contains(filename) ? names.constFind(filename).value() : filename;
298 }
299 
self()300 std::unique_ptr<Core> &Core::self()
301 {
302     if (!m_self) {
303         qWarning() << "Core has not been created";
304     }
305     return m_self;
306 }
307 
window()308 MainWindow *Core::window()
309 {
310     return m_mainWindow;
311 }
312 
projectManager()313 ProjectManager *Core::projectManager()
314 {
315     return m_projectManager;
316 }
317 
monitorManager()318 MonitorManager *Core::monitorManager()
319 {
320     return m_monitorManager;
321 }
322 
getMonitor(int id)323 Monitor *Core::getMonitor(int id)
324 {
325     if (id == Kdenlive::ClipMonitor) {
326         return m_monitorManager->clipMonitor();
327     }
328     return m_monitorManager->projectMonitor();
329 }
330 
bin()331 Bin *Core::bin()
332 {
333     return m_mainWindow->getBin();
334 }
335 
activeBin()336 Bin *Core::activeBin()
337 {
338     return m_mainWindow->activeBin();
339 }
340 
selectBinClip(const QString & clipId,bool activateMonitor,int frame,const QPoint & zone)341 void Core::selectBinClip(const QString &clipId, bool activateMonitor, int frame, const QPoint &zone)
342 {
343     m_mainWindow->activeBin()->selectClipById(clipId, frame, zone, activateMonitor);
344 }
345 
selectTimelineItem(int id)346 void Core::selectTimelineItem(int id)
347 {
348     if (m_guiConstructed && m_mainWindow->getCurrentTimeline()->controller()->getModel()) {
349         m_mainWindow->getCurrentTimeline()->controller()->getModel()->requestAddToSelection(id, true);
350     }
351 }
352 
getSubtitleModel(bool enforce)353 std::shared_ptr<SubtitleModel> Core::getSubtitleModel(bool enforce)
354 {
355     if (m_guiConstructed && m_mainWindow->getCurrentTimeline()->controller()->getModel()) {
356         auto subModel = m_mainWindow->getCurrentTimeline()->controller()->getModel()->getSubtitleModel();
357         if (enforce && subModel == nullptr) {
358             m_mainWindow->slotEditSubtitle();
359             subModel = m_mainWindow->getCurrentTimeline()->controller()->getModel()->getSubtitleModel();
360         }
361         return subModel;
362     }
363     return nullptr;
364 }
365 
library()366 LibraryWidget *Core::library()
367 {
368     return m_library;
369 }
370 
textEditWidget()371 TextBasedEdit *Core::textEditWidget()
372 {
373     return m_textEditWidget;
374 }
375 
timeRemapWidget()376 TimeRemap *Core::timeRemapWidget()
377 {
378     return m_timeRemapWidget;
379 }
380 
currentRemap(const QString & clipId)381 bool Core::currentRemap(const QString &clipId)
382 {
383     return m_timeRemapWidget == nullptr ? false : m_timeRemapWidget->currentClip() == clipId;
384 }
385 
subtitleWidget()386 SubtitleEdit *Core::subtitleWidget()
387 {
388     return m_subtitleWidget;
389 }
390 
mixer()391 MixerManager *Core::mixer()
392 {
393     return m_mixerWidget;
394 }
395 
initLocale()396 void Core::initLocale()
397 {
398     QLocale systemLocale = QLocale(); // For disabling group separator by default
399     systemLocale.setNumberOptions(QLocale::OmitGroupSeparator);
400     QLocale::setDefault(systemLocale);
401 }
402 
activeTool()403 ToolType::ProjectTool Core::activeTool() {
404     return m_mainWindow->getCurrentTimeline()->activeTool();
405 }
406 
getMltRepository()407 std::unique_ptr<Mlt::Repository> &Core::getMltRepository()
408 {
409     return MltConnection::self()->getMltRepository();
410 }
411 
getCurrentProfile() const412 std::unique_ptr<ProfileModel> &Core::getCurrentProfile() const
413 {
414     return ProfileRepository::get()->getProfile(m_currentProfile);
415 }
416 
getMonitorProfile()417 Mlt::Profile &Core::getMonitorProfile()
418 {
419     return m_monitorProfile;
420 }
421 
getProjectProfile()422 Mlt::Profile *Core::getProjectProfile()
423 {
424     if (!m_projectProfile) {
425         m_projectProfile = std::make_unique<Mlt::Profile>(m_currentProfile.toStdString().c_str());
426         m_projectProfile->set_explicit(true);
427         updateMonitorProfile();
428     }
429     return m_projectProfile.get();
430 }
431 
432 
updateMonitorProfile()433 void Core::updateMonitorProfile()
434 {
435     m_monitorProfile.set_colorspace(m_projectProfile->colorspace());
436     m_monitorProfile.set_frame_rate(m_projectProfile->frame_rate_num(), m_projectProfile->frame_rate_den());
437     m_monitorProfile.set_width(m_projectProfile->width());
438     m_monitorProfile.set_height(m_projectProfile->height());
439     m_monitorProfile.set_progressive(m_projectProfile->progressive());
440     m_monitorProfile.set_sample_aspect(m_projectProfile->sample_aspect_num(), m_projectProfile->sample_aspect_den());
441     m_monitorProfile.set_display_aspect(m_projectProfile->display_aspect_num(), m_projectProfile->display_aspect_den());
442     m_monitorProfile.set_explicit(true);
443     emit monitorProfileUpdated();
444 }
445 
getCurrentProfilePath() const446 const QString &Core::getCurrentProfilePath() const
447 {
448     return m_currentProfile;
449 }
450 
setCurrentProfile(const QString & profilePath)451 bool Core::setCurrentProfile(const QString &profilePath)
452 {
453     if (m_currentProfile == profilePath) {
454         // no change required, ensure timecode has correct fps
455         m_timecode.setFormat(getCurrentProfile()->fps());
456         return true;
457     }
458     if (ProfileRepository::get()->profileExists(profilePath)) {
459         m_currentProfile = profilePath;
460         m_thumbProfile.reset();
461         if (m_projectProfile) {
462             m_projectProfile->set_colorspace(getCurrentProfile()->colorspace());
463             m_projectProfile->set_frame_rate(getCurrentProfile()->frame_rate_num(), getCurrentProfile()->frame_rate_den());
464             m_projectProfile->set_height(getCurrentProfile()->height());
465             m_projectProfile->set_progressive(getCurrentProfile()->progressive());
466             m_projectProfile->set_sample_aspect(getCurrentProfile()->sample_aspect_num(), getCurrentProfile()->sample_aspect_den());
467             m_projectProfile->set_display_aspect(getCurrentProfile()->display_aspect_num(), getCurrentProfile()->display_aspect_den());
468             m_projectProfile->set_width(getCurrentProfile()->width());
469             m_projectProfile->set_explicit(true);
470             updateMonitorProfile();
471         }
472         // inform render widget
473         m_timecode.setFormat(getCurrentProfile()->fps());
474         profileChanged();
475         emit m_mainWindow->updateRenderWidgetProfile();
476         m_monitorManager->resetProfiles();
477         emit m_monitorManager->updatePreviewScaling();
478         if (m_guiConstructed && m_mainWindow->hasTimeline() && m_mainWindow->getCurrentTimeline()->controller()->getModel()) {
479             m_mainWindow->getCurrentTimeline()->controller()->getModel()->updateProfile(getProjectProfile());
480             checkProfileValidity();
481             emit m_mainWindow->getCurrentTimeline()->controller()->frameFormatChanged();
482         }
483         return true;
484     }
485     return false;
486 }
487 
checkProfileValidity()488 void Core::checkProfileValidity()
489 {
490     int offset = (getCurrentProfile()->profile().width() % 2) + (getCurrentProfile()->profile().height() % 2);
491     if (offset > 0) {
492         // Profile is broken, warn user
493         if (m_mainWindow->getBin()) {
494             emit m_mainWindow->getBin()->displayBinMessage(i18n("Your project profile is invalid, rendering might fail."), KMessageWidget::Warning);
495         }
496     }
497 }
498 
getCurrentSar() const499 double Core::getCurrentSar() const
500 {
501     return getCurrentProfile()->sar();
502 }
503 
getCurrentDar() const504 double Core::getCurrentDar() const
505 {
506     return getCurrentProfile()->dar();
507 }
508 
getCurrentFps() const509 double Core::getCurrentFps() const
510 {
511     return getCurrentProfile()->fps();
512 }
513 
514 
getCurrentFrameDisplaySize() const515 QSize Core::getCurrentFrameDisplaySize() const
516 {
517     return {int(getCurrentProfile()->height() * getCurrentDar() + 0.5), getCurrentProfile()->height()};
518 }
519 
getCurrentFrameSize() const520 QSize Core::getCurrentFrameSize() const
521 {
522     return {getCurrentProfile()->width(), getCurrentProfile()->height()};
523 }
524 
requestMonitorRefresh()525 void Core::requestMonitorRefresh()
526 {
527     if (!m_guiConstructed) return;
528     m_monitorManager->refreshProjectMonitor();
529 }
530 
refreshProjectRange(QPair<int,int> range)531 void Core::refreshProjectRange(QPair<int, int> range)
532 {
533     if (!m_guiConstructed) return;
534     m_monitorManager->refreshProjectRange(range);
535 }
536 
getCompositionSizeOnTrack(const ObjectId & id)537 const QSize Core::getCompositionSizeOnTrack(const ObjectId &id)
538 {
539     return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getCompositionSizeOnTrack(id);
540 }
541 
currentTrackInfo() const542 QPair <int,QString> Core::currentTrackInfo() const
543 {
544     if (m_mainWindow->getCurrentTimeline()->controller()) {
545         int tid = m_mainWindow->getCurrentTimeline()->controller()->activeTrack();
546         if (tid >= 0) {
547             return {m_mainWindow->getCurrentTimeline()->controller()->getModel()->getTrackMltIndex(tid), m_mainWindow->getCurrentTimeline()->controller()->getModel()->getTrackTagById(tid)};
548         }
549         if (tid == -2) {
550             return {-2, i18n("Subtitles")};
551         }
552     }
553     return {-1,QString()};
554 }
555 
getItemPosition(const ObjectId & id)556 int Core::getItemPosition(const ObjectId &id)
557 {
558     if (!m_guiConstructed) return 0;
559     switch (id.first) {
560     case ObjectType::TimelineClip:
561         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
562             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipPosition(id.second);
563         }
564         break;
565     case ObjectType::TimelineComposition:
566         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) {
567             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getCompositionPosition(id.second);
568         }
569         break;
570     case ObjectType::TimelineMix:
571         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
572             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getMixInOut(id.second).first;
573         } else {
574             qWarning() << "querying non clip properties";
575         }
576         break;
577     case ObjectType::BinClip:
578     case ObjectType::TimelineTrack:
579     case ObjectType::Master:
580         return 0;
581     default:
582         qWarning() << "unhandled object type";
583     }
584     return 0;
585 }
586 
getItemIn(const ObjectId & id)587 int Core::getItemIn(const ObjectId &id)
588 {
589     if (!m_guiConstructed || !m_mainWindow->getCurrentTimeline() || !m_mainWindow->getCurrentTimeline()->controller()->getModel()) {
590         qWarning() << "GUI not build";
591         return 0;
592     }
593     switch (id.first) {
594     case ObjectType::TimelineClip:
595         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
596             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipIn(id.second);
597         } else {
598             qWarning() << "querying non clip properties";
599         }
600         break;
601     case ObjectType::TimelineMix:
602     case ObjectType::TimelineComposition:
603     case ObjectType::BinClip:
604     case ObjectType::TimelineTrack:
605     case ObjectType::Master:
606         return 0;
607     default:
608         qWarning() << "unhandled object type";
609     }
610     return 0;
611 }
612 
getItemState(const ObjectId & id)613 PlaylistState::ClipState Core::getItemState(const ObjectId &id)
614 {
615     if (!m_guiConstructed) return PlaylistState::Disabled;
616     switch (id.first) {
617     case ObjectType::TimelineClip:
618         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
619             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipState(id.second);
620         }
621         break;
622     case ObjectType::TimelineComposition:
623         return PlaylistState::VideoOnly;
624     case ObjectType::BinClip:
625         return m_mainWindow->getBin()->getClipState(id.second);
626     case ObjectType::TimelineTrack:
627         return m_mainWindow->getCurrentTimeline()->controller()->getModel()->isAudioTrack(id.second) ? PlaylistState::AudioOnly : PlaylistState::VideoOnly;
628     case ObjectType::Master:
629         return PlaylistState::Disabled;
630     default:
631         qWarning() << "unhandled object type";
632         break;
633     }
634     return PlaylistState::Disabled;
635 }
636 
getItemDuration(const ObjectId & id)637 int Core::getItemDuration(const ObjectId &id)
638 {
639     if (!m_guiConstructed) return 0;
640     switch (id.first) {
641     case ObjectType::TimelineClip:
642         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
643             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipPlaytime(id.second);
644         }
645         break;
646     case ObjectType::TimelineComposition:
647         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) {
648             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getCompositionPlaytime(id.second);
649         }
650         break;
651     case ObjectType::BinClip:
652         return int(m_mainWindow->getBin()->getClipDuration(id.second));
653     case ObjectType::TimelineTrack:
654     case ObjectType::Master:
655         return m_mainWindow->getCurrentTimeline()->controller()->duration() - 1;
656     case ObjectType::TimelineMix:
657         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
658             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getMixDuration(id.second);
659         } else {
660             qWarning() << "querying non clip properties";
661         }
662         break;
663     default:
664         qWarning() << "unhandled object type: "<<(int)id.first;
665     }
666     return 0;
667 }
668 
getItemFrameSize(const ObjectId & id)669 QSize Core::getItemFrameSize(const ObjectId &id)
670 {
671     if (!m_guiConstructed) return QSize();
672     switch (id.first) {
673     case ObjectType::TimelineClip:
674         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
675             return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipFrameSize(id.second);
676         }
677         break;
678     case ObjectType::BinClip:
679         return m_mainWindow->getBin()->getFrameSize(id.second);
680     case ObjectType::TimelineTrack:
681     case ObjectType::Master:
682     case ObjectType::TimelineComposition:
683     case ObjectType::TimelineMix:
684         return pCore->getCurrentFrameSize();
685     default:
686         qWarning() << "unhandled object type frame size";
687     }
688     return pCore->getCurrentFrameSize();
689 }
690 
getItemTrack(const ObjectId & id)691 int Core::getItemTrack(const ObjectId &id)
692 {
693     if (!m_guiConstructed) return 0;
694     switch (id.first) {
695     case ObjectType::TimelineClip:
696     case ObjectType::TimelineComposition:
697     case ObjectType::TimelineMix:
698         return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getItemTrackId(id.second);
699     default:
700         qWarning() << "unhandled object type";
701     }
702     return 0;
703 }
704 
refreshProjectItem(const ObjectId & id)705 void Core::refreshProjectItem(const ObjectId &id)
706 {
707     if (!m_guiConstructed || m_mainWindow->getCurrentTimeline()->loading) return;
708     switch (id.first) {
709     case ObjectType::TimelineClip:
710     case ObjectType::TimelineMix:
711         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
712             m_mainWindow->getCurrentTimeline()->controller()->refreshItem(id.second);
713         }
714         break;
715     case ObjectType::TimelineComposition:
716         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) {
717             m_mainWindow->getCurrentTimeline()->controller()->refreshItem(id.second);
718         }
719         break;
720     case ObjectType::TimelineTrack:
721         if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isTrack(id.second)) {
722             requestMonitorRefresh();
723         }
724         break;
725     case ObjectType::BinClip:
726         if (m_monitorManager->clipMonitorVisible()) {
727             m_monitorManager->activateMonitor(Kdenlive::ClipMonitor);
728             m_monitorManager->refreshClipMonitor(true);
729         }
730         if (m_monitorManager->projectMonitorVisible() && m_mainWindow->getCurrentTimeline()->controller()->refreshIfVisible(id.second)) {
731             m_monitorManager->refreshTimer.start();
732         }
733         break;
734     case ObjectType::Master:
735         requestMonitorRefresh();
736         break;
737     default:
738         qWarning() << "unhandled object type";
739     }
740 }
741 
hasTimelinePreview() const742 bool Core::hasTimelinePreview() const
743 {
744     if (!m_guiConstructed) {
745         return false;
746     }
747     return m_mainWindow->getCurrentTimeline()->controller()->renderedChunks().size() > 0;
748 }
749 
currentDoc()750 KdenliveDoc *Core::currentDoc()
751 {
752     return m_projectManager->current();
753 }
754 
timecode() const755 Timecode Core::timecode() const
756 {
757     return m_timecode;
758 }
759 
setDocumentModified()760 void Core::setDocumentModified()
761 {
762     m_projectManager->current()->setModified();;
763 }
764 
projectDuration() const765 int Core::projectDuration() const
766 {
767     if (!m_guiConstructed) {
768         return 0;
769     }
770     return m_mainWindow->getCurrentTimeline()->controller()->duration();
771 }
772 
profileChanged()773 void Core::profileChanged()
774 {
775     GenTime::setFps(getCurrentFps());
776 }
777 
pushUndo(const Fun & undo,const Fun & redo,const QString & text)778 void Core::pushUndo(const Fun &undo, const Fun &redo, const QString &text)
779 {
780     undoStack()->push(new FunctionalUndoCommand(undo, redo, text));
781 }
782 
pushUndo(QUndoCommand * command)783 void Core::pushUndo(QUndoCommand *command)
784 {
785     undoStack()->push(command);
786 }
787 
undoIndex() const788 int Core::undoIndex() const
789 {
790     return m_projectManager->undoStack()->index();
791 }
792 
displayMessage(const QString & message,MessageType type,int timeout)793 void Core::displayMessage(const QString &message, MessageType type, int timeout)
794 {
795     if (m_mainWindow) {
796         if (type == ProcessingJobMessage || type == OperationCompletedMessage) {
797             emit m_mainWindow->displayProgressMessage(message, type, timeout);
798         } else {
799             emit m_mainWindow->displayMessage(message, type, timeout);
800         }
801     } else {
802         qDebug() << message;
803     }
804 }
805 
loadingClips(int count)806 void Core::loadingClips(int count)
807 {
808     emit m_mainWindow->displayProgressMessage(i18n("Loading clips"), MessageType::ProcessingJobMessage, count);
809 }
810 
displayBinMessage(const QString & text,int type,const QList<QAction * > & actions,bool showClose,BinMessage::BinCategory messageCategory)811 void Core::displayBinMessage(const QString &text, int type, const QList<QAction *> &actions, bool showClose, BinMessage::BinCategory messageCategory)
812 {
813     m_mainWindow->getBin()->doDisplayMessage(text, KMessageWidget::MessageType(type), actions, showClose, messageCategory);
814 }
815 
displayBinLogMessage(const QString & text,int type,const QString & logInfo)816 void Core::displayBinLogMessage(const QString &text, int type, const QString &logInfo)
817 {
818     m_mainWindow->getBin()->doDisplayMessage(text, KMessageWidget::MessageType(type), logInfo);
819 }
820 
clearAssetPanel(int itemId)821 void Core::clearAssetPanel(int itemId)
822 {
823     if (m_guiConstructed) emit m_mainWindow->clearAssetPanel(itemId);
824 }
825 
getItemEffectStack(int itemType,int itemId)826 std::shared_ptr<EffectStackModel> Core::getItemEffectStack(int itemType, int itemId)
827 {
828     if (!m_guiConstructed) return nullptr;
829     switch (itemType) {
830     case int(ObjectType::TimelineClip):
831         return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipEffectStack(itemId);
832     case int(ObjectType::TimelineTrack):
833         return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getTrackEffectStackModel(itemId);
834     case int(ObjectType::BinClip):
835         return m_mainWindow->getBin()->getClipEffectStack(itemId);
836     case int(ObjectType::Master):
837         return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getMasterEffectStackModel();
838     default:
839         return nullptr;
840     }
841 }
842 
undoStack()843 std::shared_ptr<DocUndoStack> Core::undoStack()
844 {
845     return projectManager()->undoStack();
846 }
847 
getTrackNames(bool videoOnly)848 QMap<int, QString> Core::getTrackNames(bool videoOnly)
849 {
850     if (!m_guiConstructed) return QMap<int, QString>();
851     return m_mainWindow->getCurrentTimeline()->controller()->getTrackNames(videoOnly);
852 }
853 
getCompositionATrack(int cid) const854 QPair<int, int> Core::getCompositionATrack(int cid) const
855 {
856     if (!m_guiConstructed) return {};
857     return m_mainWindow->getCurrentTimeline()->controller()->getCompositionATrack(cid);
858 }
859 
compositionAutoTrack(int cid) const860 bool Core::compositionAutoTrack(int cid) const
861 {
862     return m_mainWindow->getCurrentTimeline()->controller()->compositionAutoTrack(cid);
863 }
864 
setCompositionATrack(int cid,int aTrack)865 void Core::setCompositionATrack(int cid, int aTrack)
866 {
867     if (!m_guiConstructed) return;
868     m_mainWindow->getCurrentTimeline()->controller()->setCompositionATrack(cid, aTrack);
869 }
870 
projectItemModel()871 std::shared_ptr<ProjectItemModel> Core::projectItemModel()
872 {
873     return m_projectItemModel;
874 }
875 
invalidateRange(QPair<int,int> range)876 void Core::invalidateRange(QPair<int, int> range)
877 {
878     if (!m_guiConstructed || m_mainWindow->getCurrentTimeline()->loading) return;
879     m_mainWindow->getCurrentTimeline()->controller()->invalidateZone(range.first, range.second);
880 }
881 
invalidateItem(ObjectId itemId)882 void Core::invalidateItem(ObjectId itemId)
883 {
884     if (!m_guiConstructed || !m_mainWindow->getCurrentTimeline() || m_mainWindow->getCurrentTimeline()->loading) return;
885     switch (itemId.first) {
886     case ObjectType::TimelineClip:
887     case ObjectType::TimelineComposition:
888         m_mainWindow->getCurrentTimeline()->controller()->invalidateItem(itemId.second);
889         break;
890     case ObjectType::TimelineTrack:
891         m_mainWindow->getCurrentTimeline()->controller()->invalidateTrack(itemId.second);
892         break;
893     case ObjectType::BinClip:
894         m_mainWindow->getBin()->invalidateClip(QString::number(itemId.second));
895         break;
896     case ObjectType::Master:
897         m_mainWindow->getCurrentTimeline()->controller()->invalidateZone(0, -1);
898         break;
899     default:
900         // compositions should not have effects
901         break;
902     }
903 }
904 
getClipSpeed(int id) const905 double Core::getClipSpeed(int id) const
906 {
907     return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipSpeed(id);
908 }
909 
updateItemKeyframes(ObjectId id)910 void Core::updateItemKeyframes(ObjectId id)
911 {
912     if (id.first == ObjectType::TimelineClip && m_guiConstructed) {
913         m_mainWindow->getCurrentTimeline()->controller()->updateClip(id.second, {TimelineModel::KeyframesRole});
914     }
915 }
916 
updateItemModel(ObjectId id,const QString & service)917 void Core::updateItemModel(ObjectId id, const QString &service)
918 {
919     if (m_guiConstructed && id.first == ObjectType::TimelineClip && !m_mainWindow->getCurrentTimeline()->loading && service.startsWith(QLatin1String("fade"))) {
920         bool startFade = service.startsWith(QLatin1String("fadein")) || service.startsWith(QLatin1String("fade_from_"));
921         m_mainWindow->getCurrentTimeline()->controller()->updateClip(id.second, {startFade ? TimelineModel::FadeInRole : TimelineModel::FadeOutRole});
922     }
923 }
924 
showClipKeyframes(ObjectId id,bool enable)925 void Core::showClipKeyframes(ObjectId id, bool enable)
926 {
927     if (id.first == ObjectType::TimelineClip) {
928         m_mainWindow->getCurrentTimeline()->controller()->showClipKeyframes(id.second, enable);
929     } else if (id.first == ObjectType::TimelineComposition) {
930         m_mainWindow->getCurrentTimeline()->controller()->showCompositionKeyframes(id.second, enable);
931     }
932 }
933 
thumbProfile()934 Mlt::Profile *Core::thumbProfile()
935 {
936     QMutexLocker lck(&m_thumbProfileMutex);
937     if (!m_thumbProfile) {
938         m_thumbProfile = std::make_unique<Mlt::Profile>(m_currentProfile.toStdString().c_str());
939         double factor = 144. / m_thumbProfile->height();
940         m_thumbProfile->set_height(144);
941         int width = int(m_thumbProfile->width() * factor + 0.5);
942         if (width % 2 > 0) {
943             width ++;
944         }
945         m_thumbProfile->set_width(width);
946         m_thumbProfile->set_explicit(true);
947     }
948     return m_thumbProfile.get();
949 }
950 
getTimelinePosition() const951 int Core::getTimelinePosition() const
952 {
953     if (m_guiConstructed) {
954         return m_monitorManager->projectMonitor()->position();
955     }
956     return 0;
957 }
958 
triggerAction(const QString & name)959 void Core::triggerAction(const QString &name)
960 {
961     QAction *action = m_mainWindow->actionCollection()->action(name);
962     if (action) {
963         action->trigger();
964     }
965 }
966 
actionText(const QString & name)967 const QString Core::actionText(const QString &name)
968 {
969     QAction *action = m_mainWindow->actionCollection()->action(name);
970     if (action) {
971         return action->toolTip();
972     }
973     return QString();
974 }
975 
clean()976 void Core::clean()
977 {
978     m_self.reset();
979 }
980 
startMediaCapture(int tid,bool checkAudio,bool checkVideo)981 void Core::startMediaCapture(int tid, bool checkAudio, bool checkVideo)
982 {
983     if (checkAudio && checkVideo) {
984         m_capture->recordVideo(tid, true);
985     } else if (checkAudio) {
986         m_capture->recordAudio(tid, true);
987     }
988     m_mediaCaptureFile = m_capture->getCaptureOutputLocation();
989 }
990 
stopMediaCapture(int tid,bool checkAudio,bool checkVideo)991 void Core::stopMediaCapture(int tid, bool checkAudio, bool checkVideo)
992 {
993     if (checkAudio && checkVideo) {
994         m_capture->recordVideo(tid, false);
995     } else if (checkAudio) {
996         m_capture->recordAudio(tid, false);
997     }
998 }
999 
getAudioCaptureDevices()1000 QStringList Core::getAudioCaptureDevices()
1001 {
1002     return m_capture->getAudioCaptureDevices();
1003 }
1004 
getMediaCaptureState()1005 int Core::getMediaCaptureState()
1006 {
1007     return m_capture->getState();
1008 }
1009 
isMediaCapturing()1010 bool Core::isMediaCapturing()
1011 {
1012     return m_capture->isRecording();
1013 }
1014 
getAudioDevice()1015 MediaCapture *Core::getAudioDevice()
1016 {
1017     return m_capture.get();
1018 }
1019 
getProjectFolderName()1020 QString Core::getProjectFolderName()
1021 {
1022     if (currentDoc()) {
1023         return currentDoc()->projectDataFolder() + QDir::separator();
1024     }
1025     return QString();
1026 }
1027 
getTimelineClipBinId(int cid)1028 QString Core::getTimelineClipBinId(int cid)
1029 {
1030     if (!m_guiConstructed) {
1031         return QString();
1032     }
1033     if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(cid)) {
1034         return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipBinId(cid);
1035     }
1036     return QString();
1037 }
getAllTimelineTracksId()1038 std::unordered_set<QString> Core::getAllTimelineTracksId()
1039 {
1040     std::unordered_set<int> timelineClipIds = m_mainWindow->getCurrentTimeline()->controller()->getModel()->getItemsInRange(-1,0);
1041     std::unordered_set<QString> tClipBinIds;
1042     for(int id : timelineClipIds) {
1043         auto idString = m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipBinId(id);
1044         tClipBinIds.insert(idString);
1045     }
1046     return tClipBinIds;
1047 }
1048 
getDurationFromString(const QString & time)1049 int Core::getDurationFromString(const QString &time)
1050 {
1051     return m_timecode.getFrameCount(time);
1052 }
1053 
processInvalidFilter(const QString service,const QString id,const QString message)1054 void Core::processInvalidFilter(const QString service, const QString id, const QString message)
1055 {
1056     if (m_guiConstructed) emit m_mainWindow->assetPanelWarning(service, id, message);
1057 }
1058 
updateProjectTags(QMap<QString,QString> tags)1059 void Core::updateProjectTags(QMap <QString, QString> tags)
1060 {
1061     // Clear previous tags
1062     for (int i = 1 ; i< 20; i++) {
1063         QString current = currentDoc()->getDocumentProperty(QString("tag%1").arg(i));
1064         if (current.isEmpty()) {
1065             break;
1066         } else {
1067             currentDoc()->setDocumentProperty(QString("tag%1").arg(i), QString());
1068         }
1069     }
1070     QMapIterator<QString, QString> j(tags);
1071     int i = 1;
1072     while (j.hasNext()) {
1073         j.next();
1074         currentDoc()->setDocumentProperty(QString("tag%1").arg(i), QString("%1:%2").arg(j.key(), j.value()));
1075         i++;
1076     }
1077 }
1078 
getMasterProducerInstance()1079 std::unique_ptr<Mlt::Producer> Core::getMasterProducerInstance()
1080 {
1081     if (m_guiConstructed && m_mainWindow->getCurrentTimeline()) {
1082         std::unique_ptr<Mlt::Producer> producer(m_mainWindow->getCurrentTimeline()->controller()->tractor()->cut(0, m_mainWindow->getCurrentTimeline()->controller()->duration() - 1));
1083         return producer;
1084     }
1085     return nullptr;
1086 }
1087 
getTrackProducerInstance(int tid)1088 std::unique_ptr<Mlt::Producer> Core::getTrackProducerInstance(int tid)
1089 {
1090     if (m_guiConstructed && m_mainWindow->getCurrentTimeline()) {
1091         std::unique_ptr<Mlt::Producer> producer(new Mlt::Producer(m_mainWindow->getCurrentTimeline()->controller()->trackProducer(tid)));
1092         return producer;
1093     }
1094     return nullptr;
1095 }
1096 
enableMultiTrack(bool enable)1097 bool Core::enableMultiTrack(bool enable)
1098 {
1099     if (!m_guiConstructed || !m_mainWindow->getCurrentTimeline()) {
1100         return false;
1101     }
1102     bool isMultiTrack = pCore->monitorManager()->isMultiTrack();
1103     if (isMultiTrack || enable) {
1104         pCore->window()->getMainTimeline()->controller()->slotMultitrackView(enable, true);
1105         return true;
1106     }
1107     return false;
1108 }
1109 
audioChannels()1110 int Core::audioChannels()
1111 {
1112     if (m_projectManager && m_projectManager->current()) {
1113         return m_projectManager->current()->audioChannels();
1114     }
1115     return 2;
1116 }
1117 
addGuides(QList<int> guides)1118 void Core::addGuides(QList <int> guides)
1119 {
1120     QMap <GenTime, QString> markers;
1121     for (int pos : guides) {
1122         GenTime p(pos, pCore->getCurrentFps());
1123         markers.insert(p, pCore->currentDoc()->timecode().getDisplayTimecode(p, false));
1124     }
1125     currentDoc()->getGuideModel()->addMarkers(markers);
1126 }
1127 
temporaryUnplug(QList<int> clipIds,bool hide)1128 void Core::temporaryUnplug(QList<int> clipIds, bool hide)
1129 {
1130     window()->getMainTimeline()->controller()->temporaryUnplug(clipIds, hide);
1131 }
1132 
transcodeFile(const QString url)1133 void Core::transcodeFile(const QString url)
1134 {
1135     qDebug()<<"=== TRANSCODING: "<<url;
1136     window()->slotTranscode({url});
1137 }
1138 
setWidgetKeyBinding(const QString & mess)1139 void Core::setWidgetKeyBinding(const QString &mess)
1140 {
1141     window()->setWidgetKeyBinding(mess);
1142 }
1143 
showEffectZone(ObjectId id,QPair<int,int> inOut,bool checked)1144 void Core::showEffectZone(ObjectId id, QPair <int, int>inOut, bool checked)
1145 {
1146     if (m_guiConstructed && m_mainWindow->getCurrentTimeline()->controller() && id.first != ObjectType::BinClip) {
1147         m_mainWindow->getCurrentTimeline()->controller()->showRulerEffectZone(inOut, checked);
1148     }
1149 }
1150 
updateMasterZones()1151 void Core::updateMasterZones()
1152 {
1153     if (m_guiConstructed && m_mainWindow->getCurrentTimeline()->controller()) {
1154         m_mainWindow->getCurrentTimeline()->controller()->updateMasterZones(m_mainWindow->getCurrentTimeline()->controller()->getModel()->getMasterEffectZones());
1155     }
1156 }
1157 
testProxies()1158 void Core::testProxies()
1159 {
1160     QScopedPointer<ProxyTest> dialog(new ProxyTest(QApplication::activeWindow()));
1161     dialog->exec();
1162 }
1163 
resizeMix(int cid,int duration,MixAlignment align,int rightFrames)1164 void Core::resizeMix(int cid, int duration, MixAlignment align, int rightFrames)
1165 {
1166     m_mainWindow->getCurrentTimeline()->controller()->resizeMix(cid, duration, align, rightFrames);
1167 }
1168 
getMixAlign(int cid) const1169 MixAlignment Core::getMixAlign(int cid) const
1170 {
1171     return m_mainWindow->getCurrentTimeline()->controller()->getMixAlign(cid);
1172 }
1173 
getMixCutPos(int cid) const1174 int Core::getMixCutPos(int cid) const
1175 {
1176     return m_mainWindow->getCurrentTimeline()->controller()->getMixCutPos(cid);
1177 }
1178 
cleanup()1179 void Core::cleanup()
1180 {
1181     audioThumbCache.clear();
1182     taskManager.slotCancelJobs();
1183     timeRemapWidget()->selectedClip(-1);
1184     disconnect(m_mainWindow->getMainTimeline()->controller(), &TimelineController::durationChanged, m_projectManager, &ProjectManager::adjustProjectDuration);
1185     m_mainWindow->getMainTimeline()->controller()->clipActions.clear();
1186 }
1187 
getNewStuff(const QString & config)1188 int Core::getNewStuff(const QString &config)
1189 {
1190     return m_mainWindow->getNewStuff(config);
1191 }
1192 
addBin(const QString & id)1193 void Core::addBin(const QString &id)
1194 {
1195     Bin *bin = new Bin(m_projectItemModel, m_mainWindow, false);
1196     bin->setupMenu();
1197     bin->setMonitor(m_monitorManager->clipMonitor());
1198     const QString folderName = bin->setDocument(pCore->currentDoc(), id);
1199     m_mainWindow->addBin(bin, folderName);
1200 }
1201 
loadTimelinePreview(const QString & chunks,const QString & dirty,const QDateTime & documentDate,int enablePreview,Mlt::Playlist & playlist)1202 void Core::loadTimelinePreview(const QString &chunks, const QString &dirty, const QDateTime &documentDate, int enablePreview, Mlt::Playlist &playlist)
1203 {
1204     pCore->window()->getMainTimeline()->controller()->loadPreview(chunks, dirty, documentDate, enablePreview, playlist);
1205 }
1206