MainWindow.cpp 35.5 KB
Newer Older
Ludovic Fauvet's avatar
Ludovic Fauvet committed
1
/*****************************************************************************
2
 * MainWindow.cpp: VLMC MainWindow
Ludovic Fauvet's avatar
Ludovic Fauvet committed
3
 *****************************************************************************
4
 * Copyright (C) 2008-2016 VideoLAN
Ludovic Fauvet's avatar
Ludovic Fauvet committed
5
6
 *
 * Authors: Ludovic Fauvet <etix@l0cal.com>
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
7
 *          Hugo Beauzée-Luyssen <hugo@beauzee.fr>
Ludovic Fauvet's avatar
Ludovic Fauvet committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

24
25
26
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
27

28
#include <QSizePolicy>
Christophe Courtaut's avatar
Christophe Courtaut committed
29
#include <QDockWidget>
30
#include <QFileDialog>
31
#include <QSlider>
32
#include <QMessageBox>
33
#include <QDesktopServices>
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
34
#include <QUndoView>
35
#include <QUrl>
36
#include <QNetworkProxy>
37
#include <QSysInfo>
luyikei's avatar
luyikei committed
38
#include <QScrollArea>
39
#include <QProgressBar>
40
#include "Main/Core.h"
41
#include "Project/Project.h"
42
43
44
#include "Library/Library.h"
#include "Tools/VlmcDebug.h"
#include "Tools/VlmcLogger.h"
luyikei's avatar
luyikei committed
45
#include "Backend/IBackend.h"
46
47
#include "Workflow/MainWorkflow.h"
#include "Renderer/ClipRenderer.h"
48
#include "Commands/AbstractUndoStack.h"
49
50
51
52
53
54

/* Gui */
#include "MainWindow.h"
#include "About.h"
#include "export/RendererSettings.h"
#include "export/ShareOnInternet.h"
55
#include "settings/SettingsDialog.h"
56
57

/* Widgets */
58
#include "effectsengine/EffectsListView.h"
luyikei's avatar
luyikei committed
59
#include "transition/TransitionsListView.h"
60
#include "library/MediaLibraryView.h"
luyikei's avatar
luyikei committed
61
#include "library/ClipLibraryView.h"
62
#include "preview/PreviewWidget.h"
63
64
65
#include "timeline/Timeline.h"

/* Settings / Preferences */
66
#include "Project/RecentProjects.h"
67
#include "wizard/ProjectWizard.h"
68
#include "Settings/Settings.h"
69
#include "LanguageHelper.h"
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
70
#include "Commands/KeyboardShortcutHelper.h"
Ludovic Fauvet's avatar
Ludovic Fauvet committed
71

luyikei's avatar
luyikei committed
72
MainWindow::MainWindow( Backend::IBackend* backend, QWidget *parent )
73
74
    : QMainWindow( parent )
    , m_backend( backend )
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
75
76
    , m_projectPreferences( nullptr )
    , m_wizard( nullptr )
Ludovic Fauvet's avatar
Ludovic Fauvet committed
77
78
{
    m_ui.setupUi( this );
79

luyikei's avatar
luyikei committed
80
    Core::instance()->logger()->setup();
81
82
83
    //Preferences
    initVlmcPreferences();

84
    // GUI
85
    createGlobalPreferences();
86
    initToolbar();
87
    createStatusBar();
88
    initializeDockWidgets();
89
90
    checkFolders();
    loadGlobalProxySettings();
91
    createProjectPreferences();
92
    updateRecentProjects();
93

Ludovic Fauvet's avatar
Ludovic Fauvet committed
94
#ifdef WITH_CRASHBUTTON
95
96
    setupCrashTester();
#endif
97

98
99
100
101
102
103
104
105
    connect( Core::instance()->project(), &Project::projectNameChanged,
             this, &MainWindow::projectNameChanged );
    connect( Core::instance()->project(), &Project::outdatedBackupFileFound,
             this, &MainWindow::onOudatedBackupFile );
    connect( Core::instance()->project(), &Project::backupProjectLoaded,
             this, &MainWindow::onBackupFileLoaded );
    connect( Core::instance()->project(), &Project::projectSaved,
             this, &MainWindow::onProjectSaved );
106
107
    connect( Core::instance()->project(), &Project::cleanStateChanged,
             this, &MainWindow::cleanStateChanged );
108
109
    connect( Core::instance()->recentProjects(), &RecentProjects::updated,
             this, &MainWindow::updateRecentProjects );
110
111

    // Connect the medialibrary before it starts discovering/reloading
112
    connect( Core::instance()->library(), &Library::progressUpdated, this,
113
114
             [this]( int percent ) {
        if ( percent < 100 )
115
        {
116
            m_progressBar->setValue( percent );
117
118
119
120
            m_ui.statusbar->show();
            m_ui.actionStatusbar->setEnabled( false );
            m_ui.actionStatusbar->setChecked( true );
        }
121
122
123
124
        else
        {
            m_progressBar->hide();
            m_ui.statusbar->clearMessage();
125
126
127
128
129
130
            m_ui.actionStatusbar->setEnabled( true );
            if ( VLMC_GET_BOOL( "private/ShowStatusbar" ) == false )
            {
                m_ui.actionStatusbar->setChecked( false );
                m_ui.statusbar->hide();
            }
131
        }
132
    });
133

134
    connect( Core::instance()->library(), &Library::discoveryProgress, this,
135
136
137
        [this](const QString& folder) {
            m_ui.statusbar->showMessage( "Discovering " + folder + "...", 2500 );
    }, Qt::QueuedConnection );
138
    connect( Core::instance()->library(), &Library::discoveryCompleted, this,
139
140
141
142
        [this]( const QString& ) {
            m_ui.statusbar->showMessage( "Analyzing media" );
    }, Qt::QueuedConnection );

143
#ifdef WITH_CRASHHANDLER
144
    if ( restoreSession() == true )
145
146
        return ;
#endif
147
148
149
150

    //All preferences have been created: restore them:
    Core::instance()->settings()->load();

151
    // Restore the geometry
152
    restoreGeometry( VLMC_GET_BYTEARRAY( "private/MainWindowGeometry" ) );
153
    // Restore the layout
154
    restoreState( VLMC_GET_BYTEARRAY( "private/MainWindowState" ) );
155
    retranslateUi();
156
    projectNameChanged( Project::unNamedProject );
Ludovic Fauvet's avatar
Ludovic Fauvet committed
157
158
}

159
160
MainWindow::~MainWindow()
{
161
162
    m_projectPreview->stop();
    m_clipPreview->stop();
luyikei's avatar
luyikei committed
163
    delete m_timeline;
164
165
}

166
167
168
void
MainWindow::showWizard()
{
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
169
    if ( m_wizard == nullptr )
170
    {
171
        m_wizard = new ProjectWizard( this );
172
173
174
        m_wizard->setModal( true );
    }
    m_wizard->show();
175
176
}

177
178
179
180
181
void
MainWindow::retranslateUi()
{
    m_dockedUndoView->setWindowTitle( tr( "History" ) );
    m_dockedEffectsList->setWindowTitle( tr( "Effects List" ) );
luyikei's avatar
luyikei committed
182
    m_dockedTransitionsList->setWindowTitle( tr( "Transitions List" ) );
luyikei's avatar
luyikei committed
183
184
    m_dockedMediaLibrary->setWindowTitle( tr( "Media Library" ) );
    m_dockedClipLibrary->setWindowTitle( tr( "Clip Library" ) );
185
186
    m_dockedClipPreview->setWindowTitle( tr( "Clip Preview" ) );
    m_dockedProjectPreview->setWindowTitle( tr( "Project Preview" ) );
187
188
}

189
void
190
MainWindow::changeEvent( QEvent *e )
Ludovic Fauvet's avatar
Ludovic Fauvet committed
191
192
193
194
{
    switch ( e->type() )
    {
    case QEvent::LanguageChange:
195
196
197
        // Translate m_ui as a separate step to avoid calling it twice upon first
        // creation. We call retranslateUi() from MainWindow's constructor, but we also initialize
        // m_ui, which calls m_ui.retranslateUi()
Ludovic Fauvet's avatar
Ludovic Fauvet committed
198
        m_ui.retranslateUi( this );
199
        retranslateUi();
Ludovic Fauvet's avatar
Ludovic Fauvet committed
200
        break;
201
202
203
204
205
206
    case QEvent::WindowStateChange:
        if ( isFullScreen() )
            m_ui.actionFullscreen->setChecked( true );
        else
            m_ui.actionFullscreen->setChecked( false );
        break;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
207
208
209
210
211
    default:
        break;
    }
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
212
//use this helper when the shortcut is binded to a menu action
213
214
215
#define CREATE_MENU_SHORTCUT( key, defaultValue, name, desc, actionInstance  )      \
        VLMC_CREATE_PREFERENCE_KEYBOARD( key, defaultValue, name, desc );           \
        new KeyboardShortcutHelper( key, m_ui.actionInstance, this );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
216

217
218
219
void
MainWindow::initVlmcPreferences()
{
220
    //Setup VLMC Keyboard Preference...
221
222
223
    VLMC_CREATE_PREFERENCE_KEYBOARD( "keyboard/mediapreview", "Ctrl+Return",
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Media preview" ),
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Preview the selected media, or pause the current preview" ) );
224

225
226
227
    VLMC_CREATE_PREFERENCE_KEYBOARD( "keyboard/renderpreview", "Space",
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Render preview" ),
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Preview the project, or pause the current preview" ) );
228

229
    //A bit nasty, but we better use what Qt's providing as default shortcut
230
231
232
233
    CREATE_MENU_SHORTCUT( "keyboard/undo",
                          QKeySequence( QKeySequence::Undo ).toString().toLocal8Bit(),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Undo" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Undo the last action" ), actionUndo );
234

235
236
237
238
    CREATE_MENU_SHORTCUT( "keyboard/redo",
                          QKeySequence( QKeySequence::Redo ).toString().toLocal8Bit(),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Redo" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Redo the last action" ), actionRedo );
239

240
241
242
243
    CREATE_MENU_SHORTCUT( "keyboard/help",
                          QKeySequence( QKeySequence::HelpContents ).toString().toLocal8Bit(),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Help" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Toggle the help page" ), actionHelp );
244

245
246
247
    CREATE_MENU_SHORTCUT( "keyboard/quit", "Ctrl+Q",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Quit" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Quit VLMC" ), actionQuit );
248

249
250
251
    CREATE_MENU_SHORTCUT( "keyboard/preferences", "Alt+P",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Preferences" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Open VLMC preferences" ), actionPreferences );
252

253
254
255
256
    CREATE_MENU_SHORTCUT( "keyboard/projectpreferences", "Ctrl+P",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Project preferences" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Open the project preferences"), actionProject_Preferences );

257
258
259
    CREATE_MENU_SHORTCUT( "keyboard/fullscreen", "F",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Fullscreen" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Switch to fullscreen mode" ), actionFullscreen );
260

261
262
263
    CREATE_MENU_SHORTCUT( "keyboard/newproject",
                          QKeySequence( QKeySequence::New ).toString().toLocal8Bit(),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "New project" ),
264
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Open the new project wizard" ), actionNew_Project );
265

266
267
268
269
    CREATE_MENU_SHORTCUT( "keyboard/openproject",
                          QKeySequence( QKeySequence::Open ).toString().toLocal8Bit(),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Open a project" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Open an existing project" ), actionLoad_Project );
270

271
272
273
274
    CREATE_MENU_SHORTCUT( "keyboard/save",
                          QKeySequence( QKeySequence::Save ).toString().toLocal8Bit(),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Save" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Save the current project" ), actionSave );
275

276
277
278
    CREATE_MENU_SHORTCUT( "keyboard/saveas", "Ctrl+Shift+S",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Save as" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Save the current project to a new file" ), actionSave_As );
279

280
281
282
283
    CREATE_MENU_SHORTCUT( "keyboard/closeproject",
                          QKeySequence( QKeySequence::Close ).toString().toLocal8Bit(),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Close the project" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Close the current project" ), actionClose_Project );
284

285
286
287
    CREATE_MENU_SHORTCUT( "keyboard/importmedia", "Ctrl+I",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Import media" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Open the import window" ), actionImport );
288

289
290
291
292
    CREATE_MENU_SHORTCUT( "keyboard/renderproject", "Ctrl+R",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Render the project" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Render the project to a file" ), actionRender );

293
294
295
296
297
298
299
300
    CREATE_MENU_SHORTCUT( "keyboard/defaultmode", "n",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Selection mode" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Select the selection tool in the timeline" ), actionSelection_mode );

    CREATE_MENU_SHORTCUT( "keyboard/cutmode", "x",
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Cut mode" ),
                          QT_TRANSLATE_NOOP( "PreferenceWidget", "Select the cut/razor tool in the timeline" ), actionCut_mode );

301
    //Setup VLMC Lang. Preferences...
302
    SettingValue* lang = VLMC_CREATE_PREFERENCE_LANGUAGE( "vlmc/VLMCLang", "default",
303
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Language" ),
304
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "The VLMC's UI language" ) );
305

306
    connect( lang, SIGNAL( changed( QVariant ) ),
luyikei's avatar
luyikei committed
307
             LanguageHelper::instance(), SLOT( languageChanged( const QVariant& ) ) );
308

309
    //Setup VLMC General Preferences...
310
    VLMC_CREATE_PREFERENCE_BOOL( "vlmc/ConfirmDeletion", true,
311
                                 QT_TRANSLATE_NOOP( "PreferenceWidget", "Confirm clip deletion"),
312
                                 QT_TRANSLATE_NOOP( "PreferenceWidget", "Ask for confirmation before deleting a clip from the timeline" ) );
313

314
    VLMC_CREATE_PREFERENCE_PATH( "vlmc/TempFolderLocation", QDir::tempPath() + "/VLMC/",
Rohit Yadav's avatar
Rohit Yadav committed
315
                                    QT_TRANSLATE_NOOP( "PreferenceWidget", "Temporary folder" ),
316
317
                                    QT_TRANSLATE_NOOP( "PreferenceWidget", "The temporary folder used by VLMC to process videos." ) );

318
    //Setup VLMC Youtube Preference...
319
    VLMC_CREATE_PREFERENCE_STRING( "youtube/DeveloperKey", "",
320
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Youtube Developer Key" ),
321
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "VLMC's Youtube Developer Key" ) );
322
323
324

    VLMC_CREATE_PREFERENCE_STRING( "youtube/Username", "username",
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Youtube Username" ),
325
326
327
328
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Valid YouTube username" ) );

    VLMC_CREATE_PREFERENCE_PASSWORD( "youtube/Password", "",
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Youtube Password" ),
329
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Leave this field empty, password will be stored in unencrypted form." ) );
330
331

    //Setup VLMC Proxy Settings
332
333
334
335
336
337
338
    VLMC_CREATE_PREFERENCE_BOOL( "network/UseProxy", false,
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Enable Proxy for VLMC"),
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Enables Global Network Proxy for VLMC." ) );

    VLMC_CREATE_PREFERENCE_STRING( "network/ProxyHost", "",
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Proxy Hostname" ),
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Set Proxy Hostname." ) );
339
340
341

    VLMC_CREATE_PREFERENCE_STRING( "network/ProxyPort", "",
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Proxy Port" ),
342
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Set Proxy Port." ) );
343
344
345

    VLMC_CREATE_PREFERENCE_STRING( "network/ProxyUsername", "",
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Proxy Username" ),
346
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Set Proxy Username, if any." ) );
347

348
    VLMC_CREATE_PREFERENCE_PASSWORD( "network/ProxyPassword", "",
349
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Proxy Password" ),
350
                                     QT_TRANSLATE_NOOP( "PreferenceWidget", "Set Proxy Password, if any." ) );
351

352
353
354
355
356
357
    // Setup private variables
    VLMC_CREATE_PRIVATE_PREFERENCE_BOOL( "private/CleanQuit", true );
    VLMC_CREATE_PRIVATE_PREFERENCE_STRING( "private/EmergencyBackup", "" );
    VLMC_CREATE_PRIVATE_PREFERENCE_STRING( "private/ImportPreviouslySelectPath", QDir::homePath() );
    VLMC_CREATE_PRIVATE_PREFERENCE_BYTEARRAY( "private/MainWindowGeometry", "" );
    VLMC_CREATE_PRIVATE_PREFERENCE_BYTEARRAY( "private/MainWindowState", "" );
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376

    // Toolbar
    auto toolbarSetting = VLMC_CREATE_PRIVATE_PREFERENCE_BOOL( "private/ShowToolbar", false );
    connect( toolbarSetting, &SettingValue::changed, this, [this]( const QVariant& var )
    {
        bool v = var.toBool();
        m_ui.toolBar->setVisible( v );
        m_ui.actionToolbar->setChecked( v );
    } );
    connect( m_ui.actionToolbar, &QAction::toggled, toolbarSetting, &SettingValue::set );

    // Statusbar
    auto statusbarSetting = VLMC_CREATE_PRIVATE_PREFERENCE_BOOL( "private/ShowStatusbar", false );
    connect( statusbarSetting, &SettingValue::changed, this, [this]( const QVariant& var )
    {
        bool v = var.toBool();
        m_ui.statusbar->setVisible( v );
        m_ui.actionStatusbar->setChecked( v );
    } );
377
    connect( m_ui.actionStatusbar, &QAction::triggered, statusbarSetting, &SettingValue::set );
luyikei's avatar
luyikei committed
378
379
380
381
382
383
384
385
386
387
388
389
390
391

    // Layout Lock
    auto lockSetting = VLMC_CREATE_PRIVATE_PREFERENCE_BOOL( "private/LayoutLock", true );
    connect( lockSetting, &SettingValue::changed, this, [this]( const QVariant& var )
    {
        bool v = var.toBool();
        for ( auto w : findChildren<QDockWidget *>() )
            if ( v == true )
                w->setTitleBarWidget( new QWidget );
            else
                w->setTitleBarWidget( 0 );
         m_ui.actionLock->setChecked( v );
    } );
    connect( m_ui.actionLock, &QAction::toggled, lockSetting, &SettingValue::set );
392
393
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
394
395
#undef CREATE_MENU_SHORTCUT

396
397
void
MainWindow::on_actionSave_triggered()
398
{
luyikei's avatar
luyikei committed
399
    if ( Core::instance()->project()->hasProjectFile() == false )
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
400
        on_actionSave_As_triggered();
barun511's avatar
barun511 committed
401
    else
luyikei's avatar
luyikei committed
402
        Core::instance()->project()->save();
403
404
}

405
void
406
MainWindow::on_actionSave_As_triggered()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
407
{
408
409
410
411
412
    auto path = Core::instance()->recentProjects()->mostRecentProjectFile();

    if ( path.isEmpty() == true )
        path = VLMC_GET_STRING( "vlmc/WorkspaceLocation" );

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
413
    QString dest = QFileDialog::getSaveFileName( nullptr, QObject::tr( "Enter the output file name" ),
414
                                  path, QObject::tr( "VLMC project file(*.vlmc)" ) );
415
416
    if ( dest.isEmpty() == true )
        return;
417
    if ( !dest.endsWith( ".vlmc" ) )
418
        dest += ".vlmc";
luyikei's avatar
luyikei committed
419
    Core::instance()->project()->saveAs( dest );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
420
421
}

422
void
423
MainWindow::on_actionLoad_Project_triggered()
424
{
425
    QString folder = VLMC_GET_STRING( "vlmc/WorkspaceLocation" );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
426
    QString fileName = QFileDialog::getOpenFileName( nullptr, tr( "Please choose a project file" ),
427
                                    folder, tr( "VLMC project file(*.vlmc)" ) );
428
429
    if ( fileName.isEmpty() == true )
        return ;
430
    Core::instance()->project()->load( fileName );
431
432
}

433
void
434
MainWindow::createStatusBar()
435
{
436
437
438
    m_progressBar = new QProgressBar( this );
    m_ui.statusbar->addPermanentWidget( m_progressBar );
    m_progressBar->show();
439

440
441
442
443
444
    // Spacer
    QWidget* spacer = new QWidget( this );
    spacer->setFixedWidth( 20 );
    m_ui.statusbar->addPermanentWidget( spacer );

Ludovic Fauvet's avatar
Ludovic Fauvet committed
445
446
447
    // Zoom Out
    QToolButton* zoomOutButton = new QToolButton( this );
    zoomOutButton->setIcon( QIcon( ":/images/zoomout" ) );
Ludovic Fauvet's avatar
Ludovic Fauvet committed
448
    zoomOutButton->setStatusTip( tr( "Zoom out" ) );
Ludovic Fauvet's avatar
Ludovic Fauvet committed
449
450
451
    m_ui.statusbar->addPermanentWidget( zoomOutButton );
    connect( zoomOutButton, SIGNAL( clicked() ),
             this, SLOT( zoomOut() ) );
452
453

    // Zoom slider
454
455
456
457
458
459
    m_zoomSlider = new QSlider( this );
    m_zoomSlider->setOrientation( Qt::Horizontal );
    m_zoomSlider->setTickInterval( 1 );
    m_zoomSlider->setSingleStep( 1 );
    m_zoomSlider->setPageStep( 1 );
    m_zoomSlider->setMinimum( 0 );
460
    m_zoomSlider->setMaximum( 9 );
461
    m_zoomSlider->setValue( 4 );
462
    m_zoomSlider->setFixedWidth( 80 );
Rohit Yadav's avatar
Rohit Yadav committed
463
    m_zoomSlider->setInvertedAppearance( true );
464
    m_ui.statusbar->addPermanentWidget( m_zoomSlider );
465

Ludovic Fauvet's avatar
Ludovic Fauvet committed
466
467
468
    // Zoom IN
    QToolButton* zoomInButton = new QToolButton( this );
    zoomInButton->setIcon( QIcon( ":/images/zoomin" ) );
Ludovic Fauvet's avatar
Ludovic Fauvet committed
469
    zoomInButton->setStatusTip( tr( "Zoom in" ) );
Ludovic Fauvet's avatar
Ludovic Fauvet committed
470
471
472
    m_ui.statusbar->addPermanentWidget( zoomInButton );
    connect( zoomInButton, SIGNAL( clicked() ),
             this, SLOT( zoomIn() ) );
473
474
    connect( m_zoomSlider, &QSlider::valueChanged, this, [this]( int val )
    {
475
        emit scaleChanged( val );
476
    } );
477
478
}

479
void
480
MainWindow::initializeDockWidgets()
481
{
482
    m_timeline = new Timeline( Core::instance()->project()->settings(), this );
luyikei's avatar
luyikei committed
483
    setCentralWidget( m_timeline->container() );
484

485
    setupLibrary();
486
    setupEffectsList();
luyikei's avatar
luyikei committed
487
    setupTransitionsList();
488
489
    setupClipPreview();
    setupProjectPreview();
490
491
    setupUndoRedoWidget();
}
492

493
494
495
void
MainWindow::setupUndoRedoWidget()
{
496
    m_undoView = new QUndoView;
luyikei's avatar
luyikei committed
497
    m_undoView->setObjectName( QStringLiteral( "History" ) );
498
    m_dockedUndoView = dockWidget( m_undoView, Qt::TopDockWidgetArea );
499
    auto stack = Core::instance()->workflow()->undoStack();
500
501
502
503
504
    connect( stack, SIGNAL( canUndoChanged( bool ) ), this, SLOT( canUndoChanged( bool ) ) );
    connect( stack, SIGNAL( canRedoChanged( bool ) ), this, SLOT( canRedoChanged( bool ) ) );
    canUndoChanged( stack->canUndo() );
    canRedoChanged( stack->canRedo() );
    m_undoView->setStack( stack );
505
}
506

507
508
509
void
MainWindow::setupEffectsList()
{
510
    m_effectsList = new EffectsListView( this );
luyikei's avatar
luyikei committed
511
    m_dockedEffectsList = dockWidget( m_effectsList->container(), Qt::TopDockWidgetArea );
512
513
}

luyikei's avatar
luyikei committed
514
515
516
517
518
519
520
void
MainWindow::setupTransitionsList()
{
    m_transitionsList = new TransitionsListView( this );
    m_dockedTransitionsList = dockWidget( m_transitionsList->container(), Qt::TopDockWidgetArea );
}

521
522
523
void
MainWindow::setupLibrary()
{
524
    m_mediaLibrary = new MediaLibraryView( this );
luyikei's avatar
luyikei committed
525
526
527
    m_clipLibrary = new ClipLibraryView( this );
    m_dockedMediaLibrary = dockWidget( m_mediaLibrary->container(), Qt::TopDockWidgetArea );
    m_dockedClipLibrary = dockWidget( m_clipLibrary->container(), Qt::TopDockWidgetArea );
528
529
}

530
531
532
533
534
535
536
void
MainWindow::setupClipPreview()
{
    m_clipPreview = new PreviewWidget;
    auto renderer = new ClipRenderer;
    renderer->setParent( m_clipPreview );
    m_clipPreview->setRenderer( renderer );
luyikei's avatar
luyikei committed
537
538
    connect( Core::instance()->library(), &Library::clipRemoved,
             renderer, &ClipRenderer::clipUnloaded );
luyikei's avatar
luyikei committed
539
540
    connect( m_clipLibrary, &ClipLibraryView::clipSelected, renderer, [renderer]( const QString& uuid )
    {
luyikei's avatar
luyikei committed
541
        renderer->setClip( Core::instance()->library()->clip( uuid ) );
luyikei's avatar
luyikei committed
542
    } );
543
544
    connect( m_mediaLibrary, &MediaLibraryView::baseClipSelected, renderer, [renderer]( const QString& uuid )
    {
luyikei's avatar
luyikei committed
545
        renderer->setClip( Core::instance()->library()->clip( uuid ) );
546
547
    } );

548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564

    KeyboardShortcutHelper* clipShortcut = new KeyboardShortcutHelper( "keyboard/mediapreview", this );
    connect( clipShortcut, SIGNAL( activated() ), m_clipPreview, SLOT( on_pushButtonPlay_clicked() ) );
    m_dockedClipPreview = dockWidget( m_clipPreview, Qt::TopDockWidgetArea );
}

void
MainWindow::setupProjectPreview()
{
    m_projectPreview = new PreviewWidget;
    m_projectPreview->setClipEdition( false );
    m_projectPreview->setRenderer( Core::instance()->workflow()->renderer() );
    KeyboardShortcutHelper* renderShortcut = new KeyboardShortcutHelper( "keyboard/renderpreview", this );
    connect( renderShortcut, SIGNAL( activated() ), m_projectPreview, SLOT( on_pushButtonPlay_clicked() ) );
    m_dockedProjectPreview = dockWidget( m_projectPreview, Qt::TopDockWidgetArea );
}

565
566
567
568
569
570
571
572
void
MainWindow::initToolbar()
{
    QActionGroup    *mouseActions = new QActionGroup( m_ui.toolBar );
    mouseActions->addAction( m_ui.actionSelection_mode );
    mouseActions->addAction( m_ui.actionCut_mode );
    m_ui.actionSelection_mode->setChecked( true );
    m_ui.toolBar->addActions( mouseActions->actions() );
573
    connect( mouseActions, SIGNAL( triggered( QAction* ) ),
574
575
             this, SLOT( toolButtonClicked( QAction* ) ) );
    m_ui.menuTools->addActions( mouseActions->actions() );
576
577
578
579
580
581
582
#if defined ( Q_OS_MAC )
    // Use native fullscreen on OS X >= LION
    if ( QSysInfo::macVersion() >= QSysInfo::MV_LION ) {
        m_ui.actionFullscreen->setEnabled( false );
        m_ui.actionFullscreen->setVisible( false );
    }
#endif
583
584
}

585
586
void
MainWindow::createGlobalPreferences()
587
{
luyikei's avatar
luyikei committed
588
    m_globalPreferences = new SettingsDialog( Core::instance()->settings(), tr( "VLMC Preferences" ), this );
589
590
591
592
    m_globalPreferences->addCategory( "vlmc", QT_TRANSLATE_NOOP( "Settings", "General" ), QIcon( ":/images/vlmc" ) );
    m_globalPreferences->addCategory( "keyboard", QT_TRANSLATE_NOOP( "Settings", "Keyboard" ), QIcon( ":/images/keyboard" ) );
    m_globalPreferences->addCategory( "youtube", QT_TRANSLATE_NOOP( "Settings", "YouTube" ), QIcon( ":/images/youtube" ) );
    m_globalPreferences->addCategory( "network", QT_TRANSLATE_NOOP( "Settings", "Network" ), QIcon( ":/images/network" ) );
593
594
}

595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
void
MainWindow::loadGlobalProxySettings()
{
    if( VLMC_GET_BOOL( "network/UseProxy" ) )
    {
        /* Updates Global Proxy for VLMC */
        QNetworkProxy proxy;
        proxy.setType( QNetworkProxy::HttpProxy );
        proxy.setHostName( VLMC_GET_STRING( "network/ProxyHost" ) );
        proxy.setPort( VLMC_GET_STRING( "network/ProxyPort" ).toInt() );
        proxy.setUser( VLMC_GET_STRING( "network/ProxyUsername" ) );
        proxy.setPassword( VLMC_GET_STRING( "network/ProxyPassword" ) );
        QNetworkProxy::setApplicationProxy( proxy );
        return;
    }

    QNetworkProxy::setApplicationProxy( QNetworkProxy::NoProxy );
}

614
615
void
MainWindow::createProjectPreferences()
616
{
luyikei's avatar
luyikei committed
617
    m_projectPreferences = new SettingsDialog( Core::instance()->project()->settings(), tr( "Project preferences" ), this );
618
619
620
    m_projectPreferences->addCategory( "general", QT_TRANSLATE_NOOP( "Settings", "General" ), QIcon( ":/images/vlmc" ) );
    m_projectPreferences->addCategory( "video", QT_TRANSLATE_NOOP( "Settings", "Video" ), QIcon( ":/images/video" ) );
    m_projectPreferences->addCategory( "audio", QT_TRANSLATE_NOOP( "Settings", "Audio" ), QIcon( ":/images/audio" ) );
621
622
}

623
624
625
626
void
MainWindow::checkFolders()
{
    QDir dirUtil;
627
628
    if ( !dirUtil.exists( VLMC_GET_STRING( "vlmc/TempFolderLocation" ) ) )
        dirUtil.mkdir( VLMC_GET_STRING( "vlmc/TempFolderLocation" ) );
629
630
}

631
632
633
634
void
MainWindow::clearTemporaryFiles()
{
    QDir dirUtil;
635
    if( dirUtil.cd( VLMC_GET_STRING( "vlmc/TempFolderLocation" ) ) )
luyikei's avatar
luyikei committed
636
        for ( const QString& file: dirUtil.entryList( QDir::Files ) )
637
638
            dirUtil.remove( file );
}
639

640
641
//Private slots definition

642
void
643
MainWindow::on_actionQuit_triggered()
Ludovic Fauvet's avatar
Ludovic Fauvet committed
644
{
645
    saveSettings();
646
    close();
Ludovic Fauvet's avatar
Ludovic Fauvet committed
647
}
648

649
void
650
MainWindow::on_actionPreferences_triggered()
651
{
652
   m_globalPreferences->show();
653
}
Ludovic Fauvet's avatar
Ludovic Fauvet committed
654

655
void
656
MainWindow::on_actionAbout_triggered()
Ludovic Fauvet's avatar
Ludovic Fauvet committed
657
{
658
659
    About about( this );
    about.exec();
Ludovic Fauvet's avatar
Ludovic Fauvet committed
660
}
661

662
663
bool
MainWindow::checkVideoLength()
664
{
luyikei's avatar
luyikei committed
665
    if ( Core::instance()->workflow()->canRender() == false )
666
    {
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
667
        QMessageBox::warning( nullptr, tr ( "VLMC Renderer" ), tr( "There is nothing to render." ) );
668
        return false;
luyikei's avatar
luyikei committed
669
    }
670
671
672
673
    return true;
}

bool
674
MainWindow::renderVideoSettings( bool shareOnInternet )
675
{
676
    RendererSettings settings( shareOnInternet );
677

678
    if ( settings.exec() == QDialog::Rejected )
679
680
        return false;

681
682
683
684
685
686
687
    QString     outputFileName = settings.outputFileName();
    quint32     width          = settings.width();
    quint32     height         = settings.height();
    double      fps            = settings.fps();
    quint32     vbitrate       = settings.videoBitrate();
    quint32     abitrate       = settings.audioBitrate();
    auto        ar             = settings.aspectRatio();
688
689
    auto        nbChannels     = settings.nbChannels();
    auto        sampleRate     = settings.sampleRate();
690

luyikei's avatar
luyikei committed
691
692
693
694

    return  Core::instance()->workflow()->startRenderToFile( outputFileName, width, height,
                                                             fps, ar, vbitrate, abitrate,
                                                             nbChannels, sampleRate );
695
696
}

697
698
699
700
701
702
703
704
QDockWidget*
MainWindow::dockWidget( QWidget* widget, Qt::DockWidgetArea startArea )
{
    QDockWidget*    dock = new QDockWidget( this );

    dock->setAllowedAreas( Qt::AllDockWidgetAreas );
    widget->setParent( dock );
    dock->setWidget( widget );
705
    dock->setObjectName( widget->objectName() );
luyikei's avatar
luyikei committed
706
707
708
709
    if ( VLMC_GET_BOOL( "private/LayoutLock" ) == true )
        dock->setTitleBarWidget( new QWidget );
    else
        dock->setTitleBarWidget( 0 );
710
711
712
713
714
    addDockWidget( startArea, dock );
    registerWidgetInWindowMenu( dock );
    return dock;
}

715
void
716
717
718
MainWindow::on_actionRender_triggered()
{
    if ( checkVideoLength() )
719
    {
720
        //Setup dialog box for querying render parameters.
721
        renderVideoSettings( false );
722
    }
723
724
}

725
void
726
MainWindow::on_actionShare_On_Internet_triggered()
727
728
729
{
    if ( checkVideoLength() )
    {
730
731
        if( !renderVideoSettings( true ) )
            return;
732

733
        checkFolders();
734
        QString fileName = VLMC_GET_STRING( "vlmc/TempFolderLocation" ) + "/" +
luyikei's avatar
luyikei committed
735
                           Core::instance()->project()->name() +
736
                           "-vlmc.mp4";
737

738
        loadGlobalProxySettings();
739

740
741
        ShareOnInternet *shareVideo = new ShareOnInternet();
        shareVideo->setVideoFile( fileName );
742

743
744
745
746
747
        if ( shareVideo->exec() == QDialog::Rejected )
        {
            delete shareVideo;
            return;
        }
748

749
        delete shareVideo;
750
751
752
    }
}

753
void
754
MainWindow::on_actionNew_Project_triggered()
755
{
756
757
    m_wizard->restart();
    m_wizard->show();
758
759
}

760
void
761
MainWindow::on_actionHelp_triggered()
762
{
763
    QDesktopServices::openUrl( QUrl( "http://videolan.org/vlmc" ) );
764
765
}

766
void
767
MainWindow::zoomIn()
Ludovic Fauvet's avatar
Ludovic Fauvet committed
768
769
770
771
{
    m_zoomSlider->setValue( m_zoomSlider->value() - 1 );
}

772
void
773
MainWindow::zoomOut()
Ludovic Fauvet's avatar
Ludovic Fauvet committed
774
775
776
{
    m_zoomSlider->setValue( m_zoomSlider->value() + 1 );
}
Ludovic Fauvet's avatar
Ludovic Fauvet committed
777

luyikei's avatar
luyikei committed
778
779
780
781
782
783
void
MainWindow::setScale( quint32 scale )
{
    m_zoomSlider->setValue( scale );
}

784
void
785
MainWindow::on_actionFullscreen_triggered( bool checked )
Ludovic Fauvet's avatar
Ludovic Fauvet committed
786
{
787
788
789
    if ( checked && !isFullScreen() )
    {
        setUnifiedTitleAndToolBarOnMac( false );
Ludovic Fauvet's avatar
Ludovic Fauvet committed
790
        showFullScreen();
791
    }
Ludovic Fauvet's avatar
Ludovic Fauvet committed
792
    else
793
794
    {
        setUnifiedTitleAndToolBarOnMac( true );
Ludovic Fauvet's avatar
Ludovic Fauvet committed
795
        showNormal();
796
    }
Ludovic Fauvet's avatar
Ludovic Fauvet committed
797
}
798

799
void
800
MainWindow::registerWidgetInWindowMenu( QDockWidget* widget )
801
{
luyikei's avatar
luyikei committed
802
    m_ui.menuView->insertAction( m_ui.widgetsSeparator, widget->toggleViewAction() );
803
}
804

805
void
806
MainWindow::toolButtonClicked( QAction *action )
807
{
808
    if ( action == m_ui.actionSelection_mode )
809
        emit selectionToolSelected();
810
    else if ( action == m_ui.actionCut_mode )
811
        emit cutToolSelected();
812
    else
813
        vlmcCritical() << "Unknown tool. This should not happen !";
814
}
815

816
void
817
MainWindow::on_actionProject_Preferences_triggered()
818
{
819
  m_projectPreferences->show();
820
}
821

822
823
bool
MainWindow::saveSettings()
824
{
825
    // ??????
826
    clearTemporaryFiles();
luyikei's avatar
luyikei committed
827
    Settings* settings = Core::instance()->settings();
828
829
830
831
832
833
    // Save the current geometry
    settings->setValue( "private/MainWindowGeometry", saveGeometry() );
    // Save the current layout
    settings->setValue( "private/MainWindowState", saveState() );
    settings->setValue( "private/CleanQuit", true );
    return true;
834
835
836
837
838
}

void
MainWindow::closeEvent( QCloseEvent* e )
{
luyikei's avatar
luyikei committed
839
    if ( Core::instance()->project()->isClean() == false )
840
841
842
843
844
845
846
847
848
849
    {
        QMessageBox msgBox;
        msgBox.setText( QObject::tr( "The project has been modified." ) );
        msgBox.setInformativeText( QObject::tr( "Do you want to save it?" ) );
        msgBox.setStandardButtons( QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel );
        msgBox.setDefaultButton( QMessageBox::Save );
        int     ret = msgBox.exec();
        switch ( ret )
        {
        case QMessageBox::Save:
850
            on_actionSave_triggered();
851
852
853
854
855
856
857
858
859
860
            break;
        case QMessageBox::Discard:
            break;
        case QMessageBox::Cancel:
            e->ignore();
            return;
        }
    }
    saveSettings();
    e->accept();
861
}
862

863
864
865
866
867
868
869
void
MainWindow::updateRecentProjects()
{
    auto menu = new QMenu;
    for ( const auto& var : Core::instance()->recentProjects()->toVariant().toList() )
    {
        const auto& m = var.toMap();
870
871
        const auto& name = m["name"].toString();
        const auto& file = m["file"].toString();
872
873
874
875
876
877
        auto action = menu->addAction( QString( "%1 - %2" )
                                       .arg( name )
                                       .arg( file )
                                       );
        connect( action, &QAction::triggered, this, [this, file]()
        {
878
879
880
881
882
883
884
885
886
887
888
            if ( QFile::exists( file ) == false )
            {
                    QMessageBox::warning( this, tr( "Project file missing" ),
                                          QStringLiteral( "%1\n%2" )
                                          .arg( tr( "Sorry, we couldn't find your file. Was it moved, renamed, or deleted?" ) )
                                          .arg( file ) );
            }
            else
            {
                    Core::instance()->project()->load( file );
            }
889
890
891
892
893
        } );
    }
    m_ui.actionRecent_Projects->setMenu( menu );
}

894
void
895
MainWindow::projectNameChanged( const QString& projectName )
896
{