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