]> git.sesse.net Git - kdenlive/blobdiff - src/mainwindow.cpp
Limit the use of qApp->processEvents that might cause concurrency issues: http:/...
[kdenlive] / src / mainwindow.cpp
index 355ebca77a84cc97eb1d1e6f5179cd69f0ca20d4..95b00560e59af1460bff02229bc44c301b66b738 100644 (file)
@@ -142,6 +142,11 @@ EffectsList MainWindow::transitions;
 
 QMap <QString,QImage> MainWindow::m_lumacache;
 
+static bool sortByNames(const QPair<QString, KAction*> &a, const QPair<QString, KAction*> &b)
+{
+    return a.first < b.first;
+}
+
 MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & clipsToLoad, QWidget *parent) :
     KXmlGuiWindow(parent),
     m_activeDocument(NULL),
@@ -467,12 +472,12 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
 
     QMenu *clipInTimeline = static_cast<QMenu*>(factory()->container("clip_in_timeline", this));
     clipInTimeline->setIcon(KIcon("go-jump"));
-       QHash<QString,QMenu*> menus;
-       menus.insert("addMenu",static_cast<QMenu*>(factory()->container("generators", this)));
-        menus.insert("extractAudioMenu",static_cast<QMenu*>(factory()->container("extract_audio", this)));
-       menus.insert("transcodeMenu",static_cast<QMenu*>(factory()->container("transcoders", this)));
-       menus.insert("clipActionsMenu",static_cast<QMenu*>(factory()->container("clip_actions", this)));
-       menus.insert("inTimelineMenu",clipInTimeline);
+    QHash<QString,QMenu*> menus;
+    menus.insert("addMenu",static_cast<QMenu*>(factory()->container("generators", this)));
+    menus.insert("extractAudioMenu",static_cast<QMenu*>(factory()->container("extract_audio", this)));
+    menus.insert("transcodeMenu",static_cast<QMenu*>(factory()->container("transcoders", this)));
+    menus.insert("clipActionsMenu",static_cast<QMenu*>(factory()->container("clip_actions", this)));
+    menus.insert("inTimelineMenu",clipInTimeline);
     m_projectList->setupGeneratorMenu(menus);
 
     // build themes menus
@@ -574,29 +579,6 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
 
     slotConnectMonitors();
 
-    // Open or create a file.  Command line argument passed in Url has
-    // precedence, then "openlastproject", then just a plain empty file.
-    // If opening Url fails, openlastproject will _not_ be used.
-    if (!Url.isEmpty()) {
-        // delay loading so that the window shows up
-        m_startUrl = Url;
-        QTimer::singleShot(500, this, SLOT(openFile()));
-    } else if (KdenliveSettings::openlastproject()) {
-        QTimer::singleShot(500, this, SLOT(openLastFile()));
-    } else { //if (m_timelineArea->count() == 0) {
-        newFile(false);
-    }
-
-    if (!clipsToLoad.isEmpty() && m_activeDocument) {
-        QStringList list = clipsToLoad.split(',');
-        QList <QUrl> urls;
-        foreach(const QString &path, list) {
-            kDebug() << QDir::current().absoluteFilePath(path);
-            urls << QUrl::fromLocalFile(QDir::current().absoluteFilePath(path));
-        }
-        m_projectList->slotAddClip(urls);
-    }
-
 #ifdef USE_JOGSHUTTLE
     activateShuttleDevice();
 #endif
@@ -605,33 +587,41 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     actionCollection()->addAssociatedWidget(m_clipMonitor->container());
     actionCollection()->addAssociatedWidget(m_projectMonitor->container());
 
-    QMap <QString, KAction *> viewActions;
+    QList<QPair<QString, KAction *> > viewActions;
+    QPair <QString, KAction *> pair;
     KAction *showTimeline = new KAction(i18n("Timeline"), this);
     showTimeline->setCheckable(true);
     showTimeline->setChecked(true);
     connect(showTimeline, SIGNAL(triggered(bool)), this, SLOT(slotShowTimeline(bool)));
-    viewActions.insert(showTimeline->text(), showTimeline);
+    
+    KMenu *viewMenu = static_cast<KMenu*>(factory()->container("dockwindows", this));
+    pair.first = showTimeline->text();
+    pair.second = showTimeline;
+    viewActions.append(pair);
     
     QList <QDockWidget *> docks = findChildren<QDockWidget *>();
     for (int i = 0; i < docks.count(); i++) {
         QDockWidget* dock = docks.at(i);
+       QAction * a = dock->toggleViewAction();
+       if (!a) continue;
        KAction* dockInformations = new KAction(this);
-       dockInformations->setText(dock->windowTitle());
+       dockInformations->setText(a->text());
        dockInformations->setCheckable(true);
        dockInformations->setChecked(!dock->isHidden());
-       connect(dockInformations,SIGNAL(toggled(bool)), dock, SLOT(setVisible(bool)));
-       viewActions.insert(dockInformations->text(), dockInformations);
-    }
-
-
-    KMenu *viewMenu = static_cast<KMenu*>(factory()->container("dockwindows", this));
-    //const QList<QAction *> viewActions = createPopupMenu()->actions();
-    QMap<QString, KAction *>::const_iterator i = viewActions.constBegin();
-    while (i != viewActions.constEnd()) {
-       viewMenu->addAction(guiActions->addAction(i.key(), i.value()));
-       ++i;
+       // HACK: since QActions cannot be used in KActionCategory to allow shortcut, we create a duplicate KAction of the dock QAction and link them
+       connect(a,SIGNAL(toggled(bool)), dockInformations, SLOT(setChecked(bool)));
+       connect(dockInformations,SIGNAL(triggered(bool)), a, SLOT(trigger()));
+       pair.first = dockInformations->text();
+       pair.second = dockInformations;
+       viewActions.append(pair);
     }
     
+    // Sort dock view action by name
+    qSort(viewActions.begin(), viewActions.end(), sortByNames);
+    // Populate view menu
+    for (int i = 0; i < viewActions.count(); i++)
+       viewMenu->addAction(guiActions->addAction(viewActions.at(i).first, viewActions.at(i).second));
+    
     // Populate encoding profiles
     KConfig conf("encodingprofiles.rc", KConfig::FullConfig, "appdata");
     if (KdenliveSettings::proxyparams().isEmpty() || KdenliveSettings::proxyextension().isEmpty()) {
@@ -669,6 +659,30 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     }
     
     connect (KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotChangePalette()));
+
+    // Open or create a file.  Command line argument passed in Url has
+    // precedence, then "openlastproject", then just a plain empty file.
+    // If opening Url fails, openlastproject will _not_ be used.
+    if (!Url.isEmpty()) {
+        // delay loading so that the window shows up
+        m_startUrl = Url;
+        QTimer::singleShot(500, this, SLOT(openFile()));
+    } else if (KdenliveSettings::openlastproject()) {
+        QTimer::singleShot(500, this, SLOT(openLastFile()));
+    } else { //if (m_timelineArea->count() == 0) {
+        newFile(false);
+    }
+
+    if (!clipsToLoad.isEmpty() && m_activeDocument) {
+        QStringList list = clipsToLoad.split(',');
+        QList <QUrl> urls;
+        foreach(const QString &path, list) {
+            kDebug() << QDir::current().absoluteFilePath(path);
+            urls << QUrl::fromLocalFile(QDir::current().absoluteFilePath(path));
+        }
+        m_projectList->slotAddClip(urls);
+    }
+    
 }
 
 MainWindow::~MainWindow()
@@ -676,6 +690,12 @@ MainWindow::~MainWindow()
     if (m_stopmotion) {
         delete m_stopmotion;
     }
+
+#ifdef USE_JOGSHUTTLE
+    if (m_jogProcess)
+       delete m_jogProcess;
+#endif
+
     m_effectStack->slotClipItemSelected(NULL);
     m_transitionConfig->slotTransitionItemSelected(NULL, 0, QPoint(), false);
 
@@ -919,7 +939,6 @@ void MainWindow::slotConnectMonitors()
     connect(m_projectMonitor->render, SIGNAL(replyGetImage(const QString &, const QString &, int, int)), m_projectList, SLOT(slotReplyGetImage(const QString &, const QString &, int, int)));
     connect(m_projectMonitor->render, SIGNAL(replyGetImage(const QString &, const QImage &)), m_projectList, SLOT(slotReplyGetImage(const QString &, const QImage &)));
 
-    kDebug()<<"  - - - - - -\n CONNECTED REPLY";
     connect(m_projectMonitor->render, SIGNAL(replyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool)), m_projectList, SLOT(slotReplyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool)));
 
     connect(m_projectMonitor->render, SIGNAL(removeInvalidClip(const QString &, bool)), m_projectList, SLOT(slotRemoveInvalidClip(const QString &, bool)));
@@ -1248,14 +1267,12 @@ void MainWindow::setupActions()
     connect(projectAdjust, SIGNAL(triggered(bool)), m_projectList, SLOT(adjustProjectProfileToItem()));
 
     KAction* monitorPlay = new KAction(KIcon("media-playback-start"), i18n("Play"), this);
-    KShortcut playShortcut;
-    playShortcut.setPrimary(Qt::Key_Space);
-    playShortcut.setAlternate(Qt::Key_K);
-    monitorPlay->setShortcut(playShortcut);
+    monitorPlay->setShortcut(Qt::Key_Space);
     collection.addAction("monitor_play", monitorPlay);
     connect(monitorPlay, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotPlay()));
 
     KAction* monitorPause = new KAction(KIcon("media-playback-stop"), i18n("Pause"), this);
+    monitorPause->setShortcut(Qt::Key_K);
     collection.addAction("monitor_pause", monitorPause);
     connect(monitorPause, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotPause()));
 
@@ -1510,14 +1527,20 @@ void MainWindow::setupActions()
 
     KAction* splitAudio = new KAction(KIcon("document-new"), i18n("Split Audio"), this);
     collection.addAction("split_audio", splitAudio);
+    // "A+V" as data means this action should only be available for clips with audio AND video
+    splitAudio->setData("A+V");
     connect(splitAudio, SIGNAL(triggered(bool)), this, SLOT(slotSplitAudio()));
 
     KAction* setAudioAlignReference = new KAction(i18n("Set Audio Reference"), this);
     collection.addAction("set_audio_align_ref", setAudioAlignReference);
+    // "A" as data means this action should only be available for clips with audio
+    setAudioAlignReference->setData("A");
     connect(setAudioAlignReference, SIGNAL(triggered()), this, SLOT(slotSetAudioAlignReference()));
 
     KAction* alignAudio = new KAction(i18n("Align Audio to Reference"), this);
     collection.addAction("align_audio", alignAudio);
+    // "A" as data means this action should only be available for clips with audio
+    alignAudio->setData("A");
     connect(alignAudio, SIGNAL(triggered()), this, SLOT(slotAlignAudio()));
 
     KAction* audioOnly = new KAction(KIcon("document-new"), i18n("Audio Only"), this);
@@ -2145,7 +2168,6 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale)
     progressDialog.progressBar()->setMaximum(4);
     progressDialog.show();
     progressDialog.progressBar()->setValue(0);
-    qApp->processEvents();
 
     bool openBackup;
     KdenliveDoc *doc = new KdenliveDoc(stale ? KUrl(stale->fileName()) : url, KdenliveSettings::defaultprojectfolder(), m_commandStack, KdenliveSettings::default_profile(), QMap <QString, QString> (), QMap <QString, QString> (), QPoint(KdenliveSettings::videotracks(), KdenliveSettings::audiotracks()), m_projectMonitor->render, m_notesWidget, &openBackup, this, &progressDialog);
@@ -2153,7 +2175,7 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale)
     progressDialog.progressBar()->setValue(1);
     progressDialog.progressBar()->setMaximum(4);
     progressDialog.setLabelText(i18n("Loading project"));
-    qApp->processEvents();
+    progressDialog.repaint();
 
     if (stale == NULL) {
         QByteArray hash = QCryptographicHash::hash(url.encodedPath(), QCryptographicHash::Md5).toHex();
@@ -2168,13 +2190,13 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale)
     connectDocumentInfo(doc);
 
     progressDialog.progressBar()->setValue(2);
-    qApp->processEvents();
+    progressDialog.repaint();
 
     bool ok;
     TrackView *trackView = new TrackView(doc, m_tracksActionCollection->actions(), &ok, this);
     connectDocument(trackView, doc);
     progressDialog.progressBar()->setValue(3);
-    qApp->processEvents();
+    progressDialog.repaint();
 
     m_timelineArea->setCurrentIndex(m_timelineArea->addTab(trackView, KIcon("kdenlive"), doc->description()));
     if (!ok) {
@@ -3297,12 +3319,12 @@ void MainWindow::slotShowClipProperties(DocClipBase *clip)
         if (dia_ui->exec() == QDialog::Accepted) {
             QMap <QString, QString> newprops;
             newprops.insert("xmldata", dia_ui->xml().toString());
-            if (dia_ui->outPoint() != clip->duration().frames(m_activeDocument->fps())) {
+            if (dia_ui->duration() != clip->duration().frames(m_activeDocument->fps())) {
                 // duration changed, we need to update duration
-                newprops.insert("out", QString::number(dia_ui->outPoint()));
+                newprops.insert("out", QString::number(dia_ui->duration() - 1));
                 int currentLength = QString(clip->producerProperty("length")).toInt();
-                if (currentLength <= dia_ui->outPoint())
-                        newprops.insert("length", QString::number(dia_ui->outPoint() + 1));
+                if (currentLength <= dia_ui->duration())
+                        newprops.insert("length", QString::number(dia_ui->duration()));
                 else newprops.insert("length", clip->producerProperty("length"));
             }
             if (!path.isEmpty()) {