]> git.sesse.net Git - kdenlive/blob - src/mainwindow.cpp
hide progress bar when not in use
[kdenlive] / src / mainwindow.cpp
1 /***************************************************************************
2  *   Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20
21
22 #include <QTextStream>
23 #include <QTimer>
24 #include <QAction>
25 #include <QtTest>
26 #include <QtCore>
27
28 #include <KApplication>
29 #include <KAction>
30 #include <KLocale>
31 #include <KActionCollection>
32 #include <KStandardAction>
33 #include <KFileDialog>
34 #include <KMessageBox>
35 #include <KDebug>
36 #include <KIO/NetAccess>
37 #include <KSaveFile>
38 #include <KRuler>
39 #include <KConfigDialog>
40 #include <KXMLGUIFactory>
41 #include <KStatusBar>
42 #include <kstandarddirs.h>
43 #include <KUrlRequesterDialog>
44
45 #include <mlt++/Mlt.h>
46
47 #include "mainwindow.h"
48 #include "kdenlivesettings.h"
49 #include "kdenlivesettingsdialog.h"
50 #include "initeffects.h"
51 #include "profilesdialog.h"
52 #include "projectsettings.h"
53 #include "events.h"
54
55 #define ID_STATUS_MSG 1
56 #define ID_EDITMODE_MSG 2
57 #define ID_TIMELINE_MSG 3
58 #define ID_TIMELINE_POS 4
59 #define ID_TIMELINE_FORMAT 5
60  
61 MainWindow::MainWindow(QWidget *parent)
62     : KXmlGuiWindow(parent),
63       fileName(QString()), m_activeDocument(NULL), m_commandStack(NULL)
64 {
65   parseProfiles();
66   m_timelineArea = new KTabWidget(this);
67   m_timelineArea->setHoverCloseButton(true);
68   m_timelineArea->setTabReorderingEnabled(true);
69   connect(m_timelineArea, SIGNAL(currentChanged (int)), this, SLOT(activateDocument()));
70
71   initEffects::parseEffectFiles( &m_audioEffects, &m_videoEffects );
72   m_monitorManager = new MonitorManager();
73
74   projectListDock = new QDockWidget(i18n("Project Tree"), this);
75   projectListDock->setObjectName("project_tree");
76   m_projectList = new ProjectList(this);
77   projectListDock->setWidget(m_projectList);
78   addDockWidget(Qt::TopDockWidgetArea, projectListDock);
79
80   effectListDock = new QDockWidget(i18n("Effect List"), this);
81   effectListDock->setObjectName("effect_list");
82   m_effectList = new EffectsListView(&m_audioEffects, &m_videoEffects, &m_customEffects);
83
84   //m_effectList = new KListWidget(this);
85   effectListDock->setWidget(m_effectList);
86   addDockWidget(Qt::TopDockWidgetArea, effectListDock);
87   
88   effectStackDock = new QDockWidget(i18n("Effect Stack"), this);
89   effectStackDock->setObjectName("effect_stack");
90   effectStack = new EffectStackView(&m_audioEffects, &m_videoEffects, &m_customEffects,this);
91   effectStackDock->setWidget(effectStack);
92   addDockWidget(Qt::TopDockWidgetArea, effectStackDock);
93   
94   transitionConfigDock = new QDockWidget(i18n("Transition"), this);
95   transitionConfigDock->setObjectName("transition");
96   transitionConfig = new KListWidget(this);
97   transitionConfigDock->setWidget(transitionConfig);
98   addDockWidget(Qt::TopDockWidgetArea, transitionConfigDock);
99
100
101   clipMonitorDock = new QDockWidget(i18n("Clip Monitor"), this);
102   clipMonitorDock->setObjectName("clip_monitor");
103   m_clipMonitor = new Monitor("clip", m_monitorManager, this);
104   clipMonitorDock->setWidget(m_clipMonitor);
105   addDockWidget(Qt::TopDockWidgetArea, clipMonitorDock);
106   //m_clipMonitor->stop();
107
108   projectMonitorDock = new QDockWidget(i18n("Project Monitor"), this);
109   projectMonitorDock->setObjectName("project_monitor");
110   m_projectMonitor = new Monitor("project", m_monitorManager, this);
111   projectMonitorDock->setWidget(m_projectMonitor);
112   addDockWidget(Qt::TopDockWidgetArea, projectMonitorDock);
113
114   undoViewDock = new QDockWidget(i18n("Undo History"), this);
115   undoViewDock->setObjectName("undo_history");
116   m_undoView = new QUndoView(this);
117   undoViewDock->setWidget(m_undoView);
118   m_undoView->setStack(m_commandStack);
119   addDockWidget(Qt::TopDockWidgetArea, undoViewDock);
120
121   overviewDock = new QDockWidget(i18n("Project Overview"), this);
122   overviewDock->setObjectName("project_overview");
123   m_overView = new CustomTrackView(NULL, NULL, this);
124   overviewDock->setWidget(m_overView);
125   addDockWidget(Qt::TopDockWidgetArea, overviewDock);
126
127   setupActions();
128   tabifyDockWidget (projectListDock, effectListDock);
129   tabifyDockWidget (projectListDock, effectStackDock);
130   tabifyDockWidget (projectListDock, transitionConfigDock);
131   tabifyDockWidget (projectListDock, undoViewDock);
132   projectListDock->raise();
133
134   tabifyDockWidget (clipMonitorDock, projectMonitorDock);
135   setCentralWidget(m_timelineArea);
136
137   m_timecodeFormat = new KComboBox(this);
138   m_timecodeFormat->addItem(i18n("hh:mm:ss::ff"));
139   m_timecodeFormat->addItem(i18n("Frames"));
140
141   statusProgressBar=new QProgressBar(this);
142   statusProgressBar->setMinimum(0);
143   statusProgressBar->setMaximum(100);
144   statusProgressBar->setMaximumWidth(150);
145   statusProgressBar->setVisible(false);
146   statusLabel=new QLabel(this); 
147
148   statusBar()->insertPermanentWidget(0,statusProgressBar,1);
149   statusBar()->insertPermanentWidget(1,statusLabel,1);
150   statusBar()->insertPermanentFixedItem("00:00:00:00", ID_TIMELINE_POS);
151   statusBar()->insertPermanentWidget(ID_TIMELINE_FORMAT, m_timecodeFormat); 
152
153   setupGUI(Default, "kdenliveui.rc");
154
155   connect(projectMonitorDock, SIGNAL(visibilityChanged (bool)), m_projectMonitor, SLOT(refreshMonitor(bool)));
156   connect(clipMonitorDock, SIGNAL(visibilityChanged (bool)), m_clipMonitor, SLOT(refreshMonitor(bool)));
157   connect(m_monitorManager, SIGNAL(connectMonitors ()), this, SLOT(slotConnectMonitors()));
158   connect(m_monitorManager, SIGNAL(raiseClipMonitor (bool)), this, SLOT(slotRaiseMonitor(bool)));
159   connect(m_effectList, SIGNAL(addEffect(QDomElement)), this, SLOT(slotAddEffect(QDomElement)));
160   m_monitorManager->initMonitors(m_clipMonitor, m_projectMonitor);
161         
162   setAutoSaveSettings();
163   newFile();
164 }
165
166 //virtual
167 bool MainWindow::queryClose() 
168 {
169   saveOptions();
170   switch ( KMessageBox::warningYesNoCancel( this, i18n("Save changes to document ?")) ) {
171        case KMessageBox::Yes :
172          // save document here. If saving fails, return false;
173          return true;
174        case KMessageBox::No :
175          return true;
176        default: // cancel
177          return false;
178   }
179 }
180
181 void MainWindow::slotAddEffect(QDomElement effect)
182 {
183   if (!m_activeDocument) return;
184   /*QMap <QString, QString> filter;
185   if (effectType == 0)
186     filter = m_videoEffects.effect(effectName);
187   else if (effectType == 1)
188     filter = m_audioEffects.effect(effectName);
189   else 
190     filter = m_customEffects.effect(effectName);*/
191   TrackView *currentTimeLine = (TrackView *) m_timelineArea->currentWidget();
192   currentTimeLine->projectView()->slotAddEffect(effect);
193 }
194
195 void MainWindow::slotRaiseMonitor(bool clipMonitor)
196 {
197   if (clipMonitor) clipMonitorDock->raise();
198   else projectMonitorDock->raise();
199 }
200
201 void MainWindow::slotSetClipDuration(int id, int duration)
202 {
203   if (!m_activeDocument) return;
204   m_activeDocument->setProducerDuration(id, duration);
205 }
206
207 void MainWindow::slotConnectMonitors()
208 {
209
210   m_projectList->setRenderer(m_clipMonitor->render);
211
212   connect(m_projectList, SIGNAL(clipSelected(const QDomElement &)), m_clipMonitor, SLOT(slotSetXml(const QDomElement &)));
213
214   connect(m_projectList, SIGNAL(receivedClipDuration(int, int)), this, SLOT(slotSetClipDuration(int, int)));
215
216   connect(m_projectList, SIGNAL(getFileProperties(const QDomElement &, int)), m_clipMonitor->render, SLOT(getFileProperties(const QDomElement &, int)));
217
218   connect(m_clipMonitor->render, SIGNAL(replyGetImage(int, int, const QPixmap &, int, int)), m_projectList, SLOT(slotReplyGetImage(int, int, const QPixmap &, int, int)));
219
220   connect(m_clipMonitor->render, SIGNAL(replyGetFileProperties(int, const QMap < QString, QString > &, const QMap < QString, QString > &)), m_projectList, SLOT(slotReplyGetFileProperties(int, const QMap < QString, QString > &, const QMap < QString, QString > &)));
221
222 }
223
224 void MainWindow::setupActions()
225 {
226   KAction* clearAction = new KAction(this);
227   clearAction->setText(i18n("Clear"));
228   clearAction->setIcon(KIcon("document-new"));
229   clearAction->setShortcut(Qt::CTRL + Qt::Key_W);
230   actionCollection()->addAction("clear", clearAction);
231   /*connect(clearAction, SIGNAL(triggered(bool)),
232           textArea, SLOT(clear()));*/
233
234   KAction* profilesAction = new KAction(this);
235   profilesAction->setText(i18n("Manage Profiles"));
236   profilesAction->setIcon(KIcon("document-new"));
237   actionCollection()->addAction("manage_profiles", profilesAction);
238   connect(profilesAction, SIGNAL(triggered(bool)), this, SLOT(slotEditProfiles()));
239
240   KAction* projectAction = new KAction(this);
241   projectAction->setText(i18n("Project Settings"));
242   projectAction->setIcon(KIcon("document-new"));
243   actionCollection()->addAction("project_settings", projectAction);
244   connect(projectAction, SIGNAL(triggered(bool)), this, SLOT(slotEditProjectSettings()));
245
246
247  
248   KStandardAction::quit(kapp, SLOT(quit()),
249                         actionCollection());
250  
251   KStandardAction::open(this, SLOT(openFile()),
252                         actionCollection());
253
254   m_fileOpenRecent = KStandardAction::openRecent(this, SLOT(openFile(const KUrl &)),
255                         actionCollection());
256
257   KStandardAction::save(this, SLOT(saveFile()),
258                         actionCollection());
259  
260   KStandardAction::saveAs(this, SLOT(saveFileAs()),
261                         actionCollection());
262  
263   KStandardAction::openNew(this, SLOT(newFile()),
264                         actionCollection());
265
266   KStandardAction::preferences(this, SLOT(slotPreferences()),
267                         actionCollection());
268
269   /*KStandardAction::undo(this, SLOT(undo()),
270                         actionCollection());
271
272   KStandardAction::redo(this, SLOT(redo()),
273                         actionCollection());*/
274
275   connect(actionCollection(), SIGNAL( actionHighlighted( QAction* ) ), 
276     this, SLOT( slotDisplayActionMessage( QAction* ) ) );
277   //connect(actionCollection(), SIGNAL( clearStatusText() ),
278     //statusBar(), SLOT( clear() ) );
279
280   readOptions();  
281
282   /*m_redo = m_commandStack->createRedoAction(actionCollection());
283   m_undo = m_commandStack->createUndoAction(actionCollection());*/
284 }
285
286 void MainWindow::slotDisplayActionMessage( QAction *a)
287 {
288   statusBar()->showMessage(a->data().toString(), 3000);
289 }
290
291 void MainWindow::saveOptions()
292 {
293   KSharedConfigPtr config = KGlobal::config ();
294   m_fileOpenRecent->saveEntries(KConfigGroup (config, "Recent Files"));
295   config->sync(); 
296 }
297
298 void MainWindow::readOptions()
299 {
300   KSharedConfigPtr config = KGlobal::config ();
301   m_fileOpenRecent->loadEntries(KConfigGroup (config, "Recent Files"));
302 }
303  
304 void MainWindow::newFile()
305 {
306   KdenliveDoc *doc = new KdenliveDoc(KUrl(), 25, 720, 576);
307   TrackView *trackView = new TrackView(doc);
308   m_timelineArea->addTab(trackView, "New Project");
309   if (m_timelineArea->count() == 1)
310     connectDocument(trackView, doc);
311 }
312
313 void MainWindow::activateDocument()
314 {
315   TrackView *currentTab = (TrackView *) m_timelineArea->currentWidget();
316   KdenliveDoc *currentDoc = currentTab->document();
317   connectDocument(currentTab, currentDoc);
318 }
319  
320 void MainWindow::saveFileAs(const QString &outputFileName)
321 {
322   KSaveFile file(outputFileName);
323   file.open();
324   
325   QByteArray outputByteArray;
326   //outputByteArray.append(textArea->toPlainText());
327   file.write(outputByteArray);
328   file.finalize();
329   file.close();
330   
331   fileName = outputFileName;
332 }
333
334 void MainWindow::saveFileAs()
335 {
336   saveFileAs(KFileDialog::getSaveFileName());
337 }
338  
339 void MainWindow::saveFile()
340 {
341   if(!fileName.isEmpty())
342   {
343     saveFileAs(fileName);
344   }
345   else
346   {
347     saveFileAs();
348   }
349 }
350  
351 void MainWindow::openFile() //changed
352 {
353     KUrl url = KFileDialog::getOpenUrl(KUrl(), "application/vnd.kde.kdenlive;*.kdenlive");
354     if (url.isEmpty()) return;
355     m_fileOpenRecent->addUrl (url);
356     openFile(url);
357 }
358  
359 void MainWindow::openFile(const KUrl &url) //new
360 {
361   KdenliveDoc *doc = new KdenliveDoc(url, 25, 720, 576);
362   TrackView *trackView = new TrackView(doc);
363   m_timelineArea->setCurrentIndex(m_timelineArea->addTab(trackView, QIcon(), doc->documentName()));
364   m_timelineArea->setTabToolTip(m_timelineArea->currentIndex(), doc->url().path());
365   //connectDocument(trackView, doc);
366 }
367
368
369 void MainWindow::parseProfiles()
370 {
371         //kdDebug()<<" + + YOUR MLT INSTALL WAS FOUND IN: "<< MLT_PREFIX <<endl;
372         if (KdenliveSettings::mltpath().isEmpty()) {
373             KdenliveSettings::setMltpath(QString(MLT_PREFIX) + QString("/share/mlt/profiles/"));
374         }
375         if (KdenliveSettings::rendererpath().isEmpty())
376         {
377             KdenliveSettings::setRendererpath(KStandardDirs::findExe("inigo"));
378         }
379         QStringList profilesFilter;
380         profilesFilter<<"*";
381         QStringList profilesList = QDir(KdenliveSettings::mltpath()).entryList(profilesFilter, QDir::Files);
382
383         if (profilesList.isEmpty()) {
384             // Cannot find MLT path, try finding inigo
385             QString profilePath = KdenliveSettings::rendererpath();
386             if (!profilePath.isEmpty()) {
387                 profilePath = profilePath.section('/', 0, -3);
388                 KdenliveSettings::setMltpath(profilePath + "/share/mlt/profiles/");
389                 QStringList profilesList = QDir(KdenliveSettings::mltpath()).entryList(profilesFilter, QDir::Files);
390             }
391
392             if (profilesList.isEmpty()) {
393                 // Cannot find the MLT profiles, ask for location
394                 KUrlRequesterDialog *getUrl = new KUrlRequesterDialog(KdenliveSettings::mltpath(), i18n("Cannot find your Mlt profiles, please give the path"), this);
395                 getUrl->fileDialog()->setMode(KFile::Directory);
396                 getUrl->exec();
397                 KUrl mltPath = getUrl->selectedUrl ();
398                 delete getUrl;
399                 if (mltPath.isEmpty()) exit(1);
400                 KdenliveSettings::setMltpath(mltPath.path());
401                 QStringList profilesList = QDir(KdenliveSettings::mltpath()).entryList(profilesFilter, QDir::Files);
402             }
403         }
404
405         if (KdenliveSettings::rendererpath().isEmpty()) {
406                 // Cannot find the MLT inigo renderer, ask for location
407                 KUrlRequesterDialog *getUrl = new KUrlRequesterDialog(KdenliveSettings::mltpath(), i18n("Cannot find the inigo program required for rendering (part of Mlt)"), this);
408                 getUrl->exec();
409                 KUrl rendererPath = getUrl->selectedUrl();
410                 delete getUrl;
411                 if (rendererPath.isEmpty()) exit(1);
412                 KdenliveSettings::setRendererpath(rendererPath.path());
413         }
414
415         kDebug()<<"RESULTING MLT PATH: "<<KdenliveSettings::mltpath();
416
417         // Parse MLT profiles to build a list of available video formats
418         if (profilesList.isEmpty()) parseProfiles();
419     }
420
421
422 void MainWindow::slotEditProfiles()
423 {
424   ProfilesDialog *w = new ProfilesDialog;
425   w->exec();
426   delete w;
427 }
428
429 void MainWindow::slotEditProjectSettings()
430 {
431   ProjectSettings *w = new ProjectSettings;
432   w->exec();
433   delete w;
434 }
435
436
437 void MainWindow::slotUpdateMousePosition(int pos)
438 {
439   if (m_activeDocument)
440     switch(m_timecodeFormat->currentIndex()) {
441       case 0:
442         statusBar()->changeItem(m_activeDocument->timecode().getTimecodeFromFrames(pos), ID_TIMELINE_POS);
443         break;
444     default:
445       statusBar()->changeItem(QString::number(pos), ID_TIMELINE_POS);
446     }
447 }
448
449 void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //changed
450 {
451   //m_projectMonitor->stop();
452   kDebug()<<"///////////////////   CONNECTING DOC TO PROJECT VIEW ////////////////";
453   if (m_activeDocument) {
454     if (m_activeDocument == doc) return;
455     m_activeDocument->setProducers(m_projectList->producersList());
456     m_activeDocument->setRenderer(NULL);
457   }
458   connect(trackView, SIGNAL(cursorMoved()), m_projectMonitor, SLOT(activateMonitor()));
459   connect(trackView, SIGNAL(mousePosition(int)), this, SLOT(slotUpdateMousePosition(int)));
460   connect(m_projectMonitor, SIGNAL(renderPosition(int)), trackView, SLOT(moveCursorPos(int)));
461   connect(m_projectMonitor, SIGNAL(durationChanged(int)), trackView->projectView(), SLOT(setDuration(int)));
462   connect(doc, SIGNAL(addProjectClip(DocClipBase *)), m_projectList, SLOT(slotAddClip(DocClipBase *)));
463   connect(doc, SIGNAL(signalDeleteProjectClip(int)), m_projectList, SLOT(slotDeleteClip(int)));
464   connect(doc, SIGNAL(updateClipDisplay(int)), m_projectList, SLOT(slotUpdateClip(int)));
465   connect(doc, SIGNAL(deletTimelineClip(int)), trackView, SLOT(slotDeleteClip(int)));
466   connect(trackView, SIGNAL(clipItemSelected(ClipItem*)), effectStack, SLOT(slotClipItemSelected(ClipItem*)));
467   connect(effectStack, SIGNAL(updateClipEffect(ClipItem*, QDomElement)), trackView->projectView(), SLOT(slotUpdateClipEffect(ClipItem*, QDomElement)));
468   connect(effectStack, SIGNAL(removeEffect(ClipItem*, QDomElement)), trackView->projectView(), SLOT(slotDeleteEffect(ClipItem*, QDomElement)));
469   connect(effectStack, SIGNAL(refreshEffectStack(ClipItem*)), trackView->projectView(), SLOT(slotRefreshEffects(ClipItem*)));
470
471   m_projectList->setDocument(doc);
472   m_monitorManager->setTimecode(doc->timecode());
473   doc->setRenderer(m_projectMonitor->render);
474   //m_undoView->setStack(0);
475   m_commandStack = doc->commandStack();
476
477   m_overView->setScene(trackView->projectScene());
478   m_overView->scale(m_overView->width() / trackView->duration(), m_overView->height() / (50 * trackView->tracksNumber()));
479   //m_overView->fitInView(m_overView->itemAt(0, 50), Qt::KeepAspectRatio);
480   QAction *redo = m_commandStack->createRedoAction(actionCollection());
481   QAction *undo = m_commandStack->createUndoAction(actionCollection());
482
483   QWidget* w = factory()->container("mainToolBar", this);
484   if(w) {
485     if (actionCollection()->action("undo"))
486       delete actionCollection()->action("undo");
487     if(actionCollection()->action("redo"))
488       delete actionCollection()->action("redo");
489
490     actionCollection()->addAction("undo", undo);
491     actionCollection()->addAction("redo", redo);
492     w->addAction(undo);
493     w->addAction(redo);
494   }
495   m_undoView->setStack(doc->commandStack());
496   m_activeDocument = doc;
497 }
498
499 void MainWindow::slotPreferences()
500 {
501   //An instance of your dialog could be already created and could be
502   // cached, in which case you want to display the cached dialog
503   // instead of creating another one
504   if ( KConfigDialog::showDialog( "settings" ) )
505     return;
506
507   // KConfigDialog didn't find an instance of this dialog, so lets
508   // create it :
509   KdenliveSettingsDialog* dialog = new KdenliveSettingsDialog(this);
510   //connect( dialog, SIGNAL(settingsChanged()), this, SLOT(updateConfiguration()) );
511   dialog->show();
512 }
513 void MainWindow::customEvent ( QEvent * event ){
514         if (event->type()==10005){
515                 ProgressEvent* p=(ProgressEvent*) event;
516                 statusProgressBar->setValue(p->value());
517                 if (p->value()>0) {
518                         statusLabel->setText(tr("Creating Audio Thumbs"));
519                         statusProgressBar->setVisible(true);
520                 }
521                 else {
522                         statusLabel->setText("");
523                         statusProgressBar->setVisible(false);
524                 }
525         }
526 }
527 #include "mainwindow.moc"