File indexing completed on 2024-05-05 04:54:13
0001 /* 0002 SPDX-FileCopyrightText: 2017 Jean-Baptiste Mardelle 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #include <KLocalizedContext> 0007 0008 #include "../model/builders/meltBuilder.hpp" 0009 #include "assets/keyframes/model/keyframemodel.hpp" 0010 #include "assets/model/assetparametermodel.hpp" 0011 #include "bin/model/markerlistmodel.hpp" 0012 #include "bin/model/markersortmodel.h" 0013 #include "capture/mediacapture.h" 0014 #include "core.h" 0015 #include "doc/docundostack.hpp" 0016 #include "doc/kdenlivedoc.h" 0017 #include "effects/effectsrepository.hpp" 0018 #include "kdenlivesettings.h" 0019 #include "mainwindow.h" 0020 #include "monitor/monitorproxy.h" 0021 #include "profiles/profilemodel.hpp" 0022 #include "qml/timelineitems.h" 0023 #include "qmltypes/thumbnailprovider.h" 0024 #include "timelinecontroller.h" 0025 #include "timelinewidget.h" 0026 #include "utils/clipboardproxy.hpp" 0027 0028 #include <QAction> 0029 #include <QActionGroup> 0030 #include <QFontDatabase> 0031 #include <QMenu> 0032 #include <QQmlContext> 0033 #include <QQmlEngine> 0034 #include <QQuickItem> 0035 #include <QSortFilterProxyModel> 0036 #include <QUuid> 0037 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0038 #include "kdeclarative_version.h" 0039 #endif 0040 #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) || KDECLARATIVE_VERSION > QT_VERSION_CHECK(5, 98, 0) 0041 #include <KQuickIconProvider> 0042 #else 0043 #include <KDeclarative/KDeclarative> 0044 #endif 0045 0046 const int TimelineWidget::comboScale[] = {1, 2, 4, 8, 15, 30, 50, 75, 100, 150, 200, 300, 500, 800, 1000, 1500, 2000, 3000, 6000, 15000, 30000}; 0047 0048 TimelineWidget::TimelineWidget(const QUuid uuid, QWidget *parent) 0049 : QQuickWidget(parent) 0050 , m_uuid(uuid) 0051 { 0052 #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) || KDECLARATIVE_VERSION > QT_VERSION_CHECK(5, 98, 0) 0053 engine()->addImageProvider(QStringLiteral("icon"), new KQuickIconProvider); 0054 #else 0055 KDeclarative::KDeclarative kdeclarative; 0056 kdeclarative.setDeclarativeEngine(engine()); 0057 kdeclarative.setupEngine(engine()); 0058 #endif 0059 engine()->rootContext()->setContextObject(new KLocalizedContext(this)); 0060 setClearColor(palette().window().color()); 0061 setMouseTracking(true); 0062 registerTimelineItems(); 0063 m_sortModel = std::make_unique<QSortFilterProxyModel>(this); 0064 m_proxy = new TimelineController(this); 0065 connect(m_proxy, &TimelineController::zoneMoved, this, &TimelineWidget::zoneMoved); 0066 connect(m_proxy, &TimelineController::ungrabHack, this, &TimelineWidget::slotUngrabHack); 0067 connect(m_proxy, &TimelineController::regainFocus, this, &TimelineWidget::regainFocus, Qt::DirectConnection); 0068 connect(m_proxy, &TimelineController::stopAudioRecord, this, &TimelineWidget::stopAudioRecord, Qt::DirectConnection); 0069 setResizeMode(QQuickWidget::SizeRootObjectToView); 0070 setVisible(false); 0071 setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); 0072 setFocusPolicy(Qt::StrongFocus); 0073 m_favEffects = new QMenu(i18n("Insert an effect..."), this); 0074 m_favCompositions = new QMenu(i18n("Insert a composition..."), this); 0075 installEventFilter(this); 0076 m_targetsMenu = new QMenu(this); 0077 } 0078 0079 TimelineWidget::~TimelineWidget() 0080 { 0081 delete m_proxy; 0082 } 0083 0084 void TimelineWidget::updateEffectFavorites() 0085 { 0086 const QMap<QString, QString> effects = sortedItems(KdenliveSettings::favorite_effects(), false); 0087 QMapIterator<QString, QString> i(effects); 0088 m_favEffects->clear(); 0089 while (i.hasNext()) { 0090 i.next(); 0091 QAction *ac = m_favEffects->addAction(i.key()); 0092 ac->setData(i.value()); 0093 } 0094 } 0095 0096 void TimelineWidget::updateTransitionFavorites() 0097 { 0098 const QMap<QString, QString> effects = sortedItems(KdenliveSettings::favorite_transitions(), true); 0099 QMapIterator<QString, QString> i(effects); 0100 m_favCompositions->clear(); 0101 while (i.hasNext()) { 0102 i.next(); 0103 QAction *ac = m_favCompositions->addAction(i.key()); 0104 ac->setData(i.value()); 0105 } 0106 } 0107 0108 const QMap<QString, QString> TimelineWidget::sortedItems(const QStringList &items, bool isTransition) 0109 { 0110 QMap<QString, QString> sortedItems; 0111 for (const QString &effect : items) { 0112 sortedItems.insert(m_proxy->getAssetName(effect, isTransition), effect); 0113 } 0114 return sortedItems; 0115 } 0116 0117 void TimelineWidget::setTimelineMenu(QMenu *clipMenu, QMenu *compositionMenu, QMenu *timelineMenu, QMenu *guideMenu, QMenu *timelineRulerMenu, 0118 QAction *editGuideAction, QMenu *headerMenu, QMenu *thumbsMenu, QMenu *subtitleClipMenu) 0119 { 0120 m_timelineClipMenu = new QMenu(this); 0121 QList<QAction *> cActions = clipMenu->actions(); 0122 for (auto &a : cActions) { 0123 m_timelineClipMenu->addAction(a); 0124 } 0125 m_timelineCompositionMenu = new QMenu(this); 0126 cActions = compositionMenu->actions(); 0127 for (auto &a : cActions) { 0128 m_timelineCompositionMenu->addAction(a); 0129 } 0130 m_timelineMixMenu = new QMenu(this); 0131 QAction *deleteAction = pCore->window()->actionCollection()->action(QLatin1String("delete_timeline_clip")); 0132 m_timelineMixMenu->addAction(deleteAction); 0133 0134 m_timelineMenu = new QMenu(this); 0135 cActions = timelineMenu->actions(); 0136 for (auto &a : cActions) { 0137 m_timelineMenu->addAction(a); 0138 } 0139 m_timelineRulerMenu = new QMenu(this); 0140 cActions = timelineRulerMenu->actions(); 0141 for (auto &a : cActions) { 0142 m_timelineRulerMenu->addAction(a); 0143 } 0144 m_guideMenu = guideMenu; 0145 m_headerMenu = headerMenu; 0146 m_thumbsMenu = thumbsMenu; 0147 m_headerMenu->addMenu(m_thumbsMenu); 0148 m_timelineSubtitleClipMenu = subtitleClipMenu; 0149 m_editGuideAcion = editGuideAction; 0150 updateEffectFavorites(); 0151 updateTransitionFavorites(); 0152 connect(m_favEffects, &QMenu::triggered, this, [&](QAction *ac) { m_proxy->addEffectToClip(ac->data().toString()); }); 0153 connect(m_favCompositions, &QMenu::triggered, this, [&](QAction *ac) { m_proxy->addCompositionToClip(ac->data().toString()); }); 0154 connect(m_guideMenu, &QMenu::triggered, this, [&](QAction *ac) { m_proxy->setPosition(ac->data().toInt()); }); 0155 connect(m_thumbsMenu, &QMenu::triggered, this, 0156 [&](QAction *ac) { m_proxy->setActiveTrackProperty(QStringLiteral("kdenlive:thumbs_format"), ac->data().toString()); }); 0157 // Fix qml focus issue 0158 connect(m_headerMenu, &QMenu::aboutToHide, this, &TimelineWidget::slotUngrabHack, Qt::DirectConnection); 0159 connect(m_timelineClipMenu, &QMenu::aboutToHide, this, &TimelineWidget::slotUngrabHack, Qt::DirectConnection); 0160 connect(m_timelineClipMenu, &QMenu::triggered, this, &TimelineWidget::slotResetContextPos); 0161 connect(m_timelineCompositionMenu, &QMenu::aboutToHide, this, &TimelineWidget::slotUngrabHack, Qt::DirectConnection); 0162 connect(m_timelineRulerMenu, &QMenu::aboutToHide, this, &TimelineWidget::slotUngrabHack, Qt::DirectConnection); 0163 connect(m_timelineMenu, &QMenu::aboutToHide, this, &TimelineWidget::slotUngrabHack, Qt::DirectConnection); 0164 connect(m_timelineMenu, &QMenu::triggered, this, &TimelineWidget::slotResetContextPos); 0165 connect(m_timelineSubtitleClipMenu, &QMenu::aboutToHide, this, &TimelineWidget::slotUngrabHack, Qt::DirectConnection); 0166 0167 m_timelineClipMenu->addMenu(m_favEffects); 0168 m_timelineClipMenu->addMenu(m_favCompositions); 0169 m_timelineMenu->addMenu(m_favCompositions); 0170 } 0171 0172 void TimelineWidget::unsetModel() 0173 { 0174 rootContext()->setContextProperty("controller", nullptr); 0175 rootContext()->setContextProperty("multitrack", nullptr); 0176 rootContext()->setContextProperty("timeline", nullptr); 0177 rootContext()->setContextProperty("guidesModel", nullptr); 0178 rootContext()->setContextProperty("subtitleModel", nullptr); 0179 m_sortModel.reset(new QSortFilterProxyModel(this)); 0180 m_proxy->prepareClose(); 0181 } 0182 0183 const QUuid &TimelineWidget::getUuid() const 0184 { 0185 return m_uuid; 0186 } 0187 0188 void TimelineWidget::setModel(const std::shared_ptr<TimelineItemModel> &model, MonitorProxy *proxy) 0189 { 0190 loading = true; 0191 m_sortModel->setSourceModel(model.get()); 0192 m_sortModel->setSortRole(TimelineItemModel::SortRole); 0193 m_sortModel->sort(0, Qt::DescendingOrder); 0194 m_proxy->setModel(model); 0195 rootContext()->setContextProperty("multitrack", m_sortModel.get()); 0196 rootContext()->setContextProperty("controller", model.get()); 0197 rootContext()->setContextProperty("timeline", m_proxy); 0198 rootContext()->setContextProperty("guidesModel", model->getFilteredGuideModel().get()); 0199 // Create a unique id for this timeline to prevent thumbnails 0200 // leaking from one project to another because of qml's image caching 0201 rootContext()->setContextProperty("documentId", model->uuid()); 0202 rootContext()->setContextProperty("audiorec", pCore->getAudioDevice()); 0203 rootContext()->setContextProperty("clipboard", new ClipboardProxy(this)); 0204 rootContext()->setContextProperty("miniFont", QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); 0205 rootContext()->setContextProperty("subtitleModel", model->getSubtitleModel().get()); 0206 const QStringList effs = sortedItems(KdenliveSettings::favorite_effects(), false).values(); 0207 const QStringList trans = sortedItems(KdenliveSettings::favorite_transitions(), true).values(); 0208 0209 setSource(QUrl(QStringLiteral("qrc:/qml/timeline.qml"))); 0210 engine()->addImageProvider(QStringLiteral("thumbnail"), new ThumbnailProvider); 0211 connect(rootObject(), SIGNAL(mousePosChanged(int)), pCore->window(), SLOT(slotUpdateMousePosition(int))); 0212 connect(rootObject(), SIGNAL(zoomIn(bool)), pCore->window(), SLOT(slotZoomIn(bool))); 0213 connect(rootObject(), SIGNAL(zoomOut(bool)), pCore->window(), SLOT(slotZoomOut(bool))); 0214 connect(rootObject(), SIGNAL(processingDrag(bool)), pCore->window(), SIGNAL(enableUndo(bool))); 0215 connect(m_proxy, &TimelineController::seeked, proxy, &MonitorProxy::setPosition); 0216 rootObject()->setProperty("dar", pCore->getCurrentDar()); 0217 connect(rootObject(), SIGNAL(showClipMenu(int)), this, SLOT(showClipMenu(int))); 0218 connect(rootObject(), SIGNAL(showMixMenu(int)), this, SLOT(showMixMenu(int))); 0219 connect(rootObject(), SIGNAL(showCompositionMenu()), this, SLOT(showCompositionMenu())); 0220 connect(rootObject(), SIGNAL(showTimelineMenu()), this, SLOT(showTimelineMenu())); 0221 connect(rootObject(), SIGNAL(showRulerMenu()), this, SLOT(showRulerMenu())); 0222 connect(rootObject(), SIGNAL(showHeaderMenu()), this, SLOT(showHeaderMenu())); 0223 connect(rootObject(), SIGNAL(showTargetMenu(int)), this, SLOT(showTargetMenu(int))); 0224 connect(rootObject(), SIGNAL(showSubtitleClipMenu()), this, SLOT(showSubtitleClipMenu())); 0225 m_proxy->setRoot(rootObject()); 0226 setVisible(true); 0227 loading = false; 0228 m_proxy->checkDuration(); 0229 } 0230 0231 void TimelineWidget::loadMarkerModel() 0232 { 0233 if (m_proxy) { 0234 rootContext()->setContextProperty("guidesModel", m_proxy->getModel()->getFilteredGuideModel().get()); 0235 } 0236 } 0237 0238 void TimelineWidget::mousePressEvent(QMouseEvent *event) 0239 { 0240 Q_EMIT focusProjectMonitor(); 0241 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0242 m_clickPos = event->globalPos(); 0243 #else 0244 m_clickPos = event->globalPosition().toPoint(); 0245 #endif 0246 QQuickWidget::mousePressEvent(event); 0247 } 0248 0249 void TimelineWidget::showClipMenu(int cid) 0250 { 0251 // Hide not applicable effects 0252 QList<QAction *> effects = m_favEffects->actions(); 0253 int tid = model()->getClipTrackId(cid); 0254 bool isAudioTrack = false; 0255 if (tid > -1) { 0256 isAudioTrack = model()->isAudioTrack(tid); 0257 } 0258 m_favCompositions->setEnabled(!isAudioTrack); 0259 for (auto ac : qAsConst(effects)) { 0260 const QString &id = ac->data().toString(); 0261 if (EffectsRepository::get()->isAudioEffect(id) != isAudioTrack) { 0262 ac->setVisible(false); 0263 } else { 0264 ac->setVisible(true); 0265 } 0266 } 0267 m_timelineClipMenu->popup(m_clickPos); 0268 } 0269 0270 void TimelineWidget::showMixMenu(int /*cid*/) 0271 { 0272 // Show mix menu 0273 m_timelineMixMenu->popup(m_clickPos); 0274 } 0275 0276 void TimelineWidget::showCompositionMenu() 0277 { 0278 m_timelineCompositionMenu->popup(m_clickPos); 0279 } 0280 0281 void TimelineWidget::showHeaderMenu() 0282 { 0283 bool isAudio = m_proxy->isActiveTrackAudio(); 0284 QList<QAction *> menuActions = m_headerMenu->actions(); 0285 QList<QAction *> audioActions; 0286 QStringList allowedActions = {QLatin1String("show_track_record"), QLatin1String("separate_channels"), QLatin1String("normalize_channels")}; 0287 for (QAction *ac : qAsConst(menuActions)) { 0288 if (allowedActions.contains(ac->data().toString())) { 0289 audioActions << ac; 0290 } 0291 } 0292 if (!isAudio) { 0293 // Video track 0294 int currentThumbs = m_proxy->getActiveTrackProperty(QStringLiteral("kdenlive:thumbs_format")).toInt(); 0295 QList<QAction *> actions = m_thumbsMenu->actions(); 0296 for (QAction *ac : qAsConst(actions)) { 0297 if (ac->data().toInt() == currentThumbs) { 0298 ac->setChecked(true); 0299 break; 0300 } 0301 } 0302 m_thumbsMenu->menuAction()->setVisible(true); 0303 for (auto ac : qAsConst(audioActions)) { 0304 ac->setVisible(false); 0305 } 0306 } else { 0307 // Audio track 0308 m_thumbsMenu->menuAction()->setVisible(false); 0309 for (auto ac : qAsConst(audioActions)) { 0310 ac->setVisible(true); 0311 if (ac->data().toString() == QLatin1String("show_track_record")) { 0312 ac->setChecked(m_proxy->getActiveTrackProperty(QStringLiteral("kdenlive:audio_rec")).toInt() == 1); 0313 } 0314 } 0315 } 0316 m_headerMenu->popup(m_clickPos); 0317 } 0318 0319 void TimelineWidget::showTargetMenu(int tid) 0320 { 0321 int currentTargetStream; 0322 if (tid == -1) { 0323 // Called through shortcut 0324 tid = m_proxy->activeTrack(); 0325 if (tid == -1) { 0326 return; 0327 } 0328 if (m_proxy->clipTargets() < 2 || !model()->isAudioTrack(tid)) { 0329 pCore->displayMessage(i18n("No available stream"), MessageType::ErrorMessage); 0330 return; 0331 } 0332 QVariant returnedValue; 0333 QMetaObject::invokeMethod(rootObject(), "getActiveTrackStreamPos", Qt::DirectConnection, Q_RETURN_ARG(QVariant, returnedValue)); 0334 m_clickPos = mapToGlobal(QPoint(5, y())) + QPoint(0, returnedValue.toInt()); 0335 } 0336 QMap<int, QString> possibleTargets = m_proxy->getCurrentTargets(tid, currentTargetStream); 0337 m_targetsMenu->clear(); 0338 if (m_targetsGroup) { 0339 delete m_targetsGroup; 0340 } 0341 m_targetsGroup = new QActionGroup(this); 0342 QMapIterator<int, QString> i(possibleTargets); 0343 while (i.hasNext()) { 0344 i.next(); 0345 QAction *ac = m_targetsMenu->addAction(i.value()); 0346 ac->setData(i.key()); 0347 m_targetsGroup->addAction(ac); 0348 ac->setCheckable(true); 0349 if (i.key() == currentTargetStream) { 0350 ac->setChecked(true); 0351 } 0352 } 0353 connect(m_targetsGroup, &QActionGroup::triggered, this, [this, tid](QAction *action) { 0354 int targetStream = action->data().toInt(); 0355 m_proxy->assignAudioTarget(tid, targetStream); 0356 }); 0357 if (m_targetsMenu->isEmpty() || possibleTargets.isEmpty()) { 0358 m_headerMenu->popup(m_clickPos); 0359 } else { 0360 m_targetsMenu->popup(m_clickPos); 0361 } 0362 } 0363 0364 void TimelineWidget::showRulerMenu() 0365 { 0366 m_guideMenu->clear(); 0367 const QList<CommentedTime> guides = pCore->currentDoc()->getGuideModel(m_uuid)->getAllMarkers(); 0368 m_editGuideAcion->setEnabled(false); 0369 double fps = pCore->getCurrentFps(); 0370 int currentPos = rootObject()->property("consumerPosition").toInt(); 0371 for (const auto &guide : guides) { 0372 auto *ac = new QAction(guide.comment(), this); 0373 int frame = guide.time().frames(fps); 0374 ac->setData(frame); 0375 if (frame == currentPos) { 0376 m_editGuideAcion->setEnabled(true); 0377 } 0378 m_guideMenu->addAction(ac); 0379 } 0380 m_timelineRulerMenu->popup(m_clickPos); 0381 } 0382 0383 void TimelineWidget::showTimelineMenu() 0384 { 0385 m_guideMenu->clear(); 0386 const QList<CommentedTime> guides = pCore->currentDoc()->getGuideModel(m_uuid)->getAllMarkers(); 0387 m_editGuideAcion->setEnabled(false); 0388 double fps = pCore->getCurrentFps(); 0389 int currentPos = rootObject()->property("consumerPosition").toInt(); 0390 for (const auto &guide : guides) { 0391 auto ac = new QAction(guide.comment(), this); 0392 int frame = guide.time().frames(fps); 0393 ac->setData(frame); 0394 if (frame == currentPos) { 0395 m_editGuideAcion->setEnabled(true); 0396 } 0397 m_guideMenu->addAction(ac); 0398 } 0399 m_timelineMenu->popup(m_clickPos); 0400 } 0401 0402 void TimelineWidget::showSubtitleClipMenu() 0403 { 0404 m_timelineSubtitleClipMenu->popup(m_clickPos); 0405 } 0406 0407 void TimelineWidget::slotChangeZoom(int value, bool zoomOnMouse) 0408 { 0409 double pixelScale = QFontMetrics(font()).maxWidth() * 2; 0410 m_proxy->setScaleFactorOnMouse(pixelScale / comboScale[value], zoomOnMouse); 0411 } 0412 0413 void TimelineWidget::slotCenterView() 0414 { 0415 QMetaObject::invokeMethod(rootObject(), "centerViewOnCursor"); 0416 } 0417 0418 void TimelineWidget::slotFitZoom() 0419 { 0420 QVariant returnedValue; 0421 double prevScale = m_proxy->scaleFactor(); 0422 QMetaObject::invokeMethod(rootObject(), "fitZoom", Qt::DirectConnection, Q_RETURN_ARG(QVariant, returnedValue)); 0423 double scale = returnedValue.toDouble(); 0424 QMetaObject::invokeMethod(rootObject(), "scrollPos", Qt::DirectConnection, Q_RETURN_ARG(QVariant, returnedValue)); 0425 int scrollPos = returnedValue.toInt(); 0426 if (qFuzzyCompare(prevScale, scale) && scrollPos == 0) { 0427 scale = m_prevScale; 0428 scrollPos = m_scrollPos; 0429 } else { 0430 m_prevScale = prevScale; 0431 m_scrollPos = scrollPos; 0432 scrollPos = 0; 0433 } 0434 m_proxy->setScaleFactorOnMouse(scale, false); 0435 // Update zoom slider 0436 Q_EMIT m_proxy->updateZoom(scale); 0437 QMetaObject::invokeMethod(rootObject(), "goToStart", Q_ARG(QVariant, scrollPos)); 0438 } 0439 0440 Mlt::Tractor *TimelineWidget::tractor() 0441 { 0442 return m_proxy->tractor(); 0443 } 0444 0445 TimelineController *TimelineWidget::controller() 0446 { 0447 return m_proxy; 0448 } 0449 0450 std::shared_ptr<TimelineItemModel> TimelineWidget::model() 0451 { 0452 return m_proxy->getModel(); 0453 } 0454 0455 void TimelineWidget::zoneUpdated(const QPoint &zone) 0456 { 0457 m_proxy->setZone(zone, false); 0458 } 0459 0460 void TimelineWidget::zoneUpdatedWithUndo(const QPoint &oldZone, const QPoint &newZone) 0461 { 0462 m_proxy->updateZone(oldZone, newZone); 0463 } 0464 0465 void TimelineWidget::setTool(ToolType::ProjectTool tool) 0466 { 0467 rootObject()->setProperty("activeTool", int(tool)); 0468 } 0469 0470 ToolType::ProjectTool TimelineWidget::activeTool() 0471 { 0472 return ToolType::ProjectTool(rootObject()->property("activeTool").toInt()); 0473 } 0474 0475 QPair<int, int> TimelineWidget::getAvTracksCount() const 0476 { 0477 return m_proxy->getAvTracksCount(); 0478 } 0479 0480 void TimelineWidget::slotUngrabHack() 0481 { 0482 // Workaround bug: https://bugreports.qt.io/browse/QTBUG-59044 0483 // https://phabricator.kde.org/D5515 0484 QTimer::singleShot(250, this, [this]() { 0485 // Reset menu position, necessary if user closes the menu without selecting any action 0486 rootObject()->setProperty("clickFrame", -1); 0487 }); 0488 if (quickWindow()) { 0489 if (quickWindow()->mouseGrabberItem()) { 0490 quickWindow()->mouseGrabberItem()->ungrabMouse(); 0491 QPoint mousePos = mapFromGlobal(QCursor::pos()); 0492 QMetaObject::invokeMethod(rootObject(), "regainFocus", Qt::DirectConnection, Q_ARG(QVariant, mousePos)); 0493 } else { 0494 QMetaObject::invokeMethod(rootObject(), "endDrag", Qt::DirectConnection); 0495 } 0496 } 0497 } 0498 0499 void TimelineWidget::slotResetContextPos(QAction *) 0500 { 0501 rootObject()->setProperty("clickFrame", -1); 0502 m_clickPos = QPoint(); 0503 } 0504 0505 int TimelineWidget::zoomForScale(double value) const 0506 { 0507 int scale = int(100 / value); 0508 int ix = 13; 0509 while (comboScale[ix] > scale && ix > 0) { 0510 ix--; 0511 } 0512 return ix; 0513 } 0514 0515 void TimelineWidget::focusTimeline() 0516 { 0517 setFocus(); 0518 if (rootObject()) { 0519 rootObject()->setFocus(true); 0520 } 0521 } 0522 0523 void TimelineWidget::endDrag() 0524 { 0525 if (rootObject()) { 0526 QMetaObject::invokeMethod(rootObject(), "endBinDrag"); 0527 } 0528 } 0529 0530 void TimelineWidget::startAudioRecord(int tid) 0531 { 0532 if (rootObject()) { 0533 QMetaObject::invokeMethod(rootObject(), "startAudioRecord", Qt::DirectConnection, Q_ARG(QVariant, tid)); 0534 } 0535 } 0536 0537 void TimelineWidget::stopAudioRecord() 0538 { 0539 if (rootObject()) { 0540 QMetaObject::invokeMethod(rootObject(), "stopAudioRecord", Qt::DirectConnection); 0541 } 0542 } 0543 0544 void TimelineWidget::focusInEvent(QFocusEvent *event) 0545 { 0546 QQuickWidget::focusInEvent(event); 0547 QTimer::singleShot(250, rootObject(), SLOT(forceActiveFocus())); 0548 } 0549 0550 bool TimelineWidget::eventFilter(QObject *object, QEvent *event) 0551 { 0552 switch (event->type()) { 0553 case QEvent::Enter: 0554 if (!hasFocus()) { 0555 Q_EMIT pCore->window()->showTimelineFocus(true, true); 0556 } 0557 break; 0558 case QEvent::Leave: 0559 if (!hasFocus()) { 0560 Q_EMIT pCore->window()->showTimelineFocus(false, true); 0561 } 0562 break; 0563 case QEvent::FocusOut: 0564 Q_EMIT pCore->window()->showTimelineFocus(false, false); 0565 break; 0566 case QEvent::FocusIn: 0567 Q_EMIT pCore->window()->showTimelineFocus(true, false); 0568 break; 0569 default: 0570 break; 0571 } 0572 return QQuickWidget::eventFilter(object, event); 0573 } 0574 0575 void TimelineWidget::regainFocus() 0576 { 0577 if (underMouse() && rootObject()) { 0578 QPoint mousePos = mapFromGlobal(QCursor::pos()); 0579 QMetaObject::invokeMethod(rootObject(), "regainFocus", Qt::DirectConnection, Q_ARG(QVariant, mousePos)); 0580 } 0581 } 0582 0583 bool TimelineWidget::hasSubtitles() const 0584 { 0585 return m_proxy->getModel()->hasSubtitleModel(); 0586 } 0587 0588 void TimelineWidget::connectSubtitleModel(bool firstConnect) 0589 { 0590 qDebug() << "root context get sub model new function"; 0591 if (!model()->hasSubtitleModel()) { 0592 // qDebug()<<"null ptr here at root context"; 0593 return; 0594 } else { 0595 // qDebug()<<"null ptr NOT here at root context"; 0596 rootObject()->setProperty("showSubtitles", KdenliveSettings::showSubtitles()); 0597 if (firstConnect) { 0598 rootContext()->setContextProperty("subtitleModel", model()->getSubtitleModel().get()); 0599 } 0600 } 0601 }