ProjectManager.cpp 11.9 KB
Newer Older
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
1
2
3
/*****************************************************************************
 * ProjectManager.cpp: Manager the project loading and saving.
 *****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
4
 * Copyright (C) 2008-2010 VideoLAN
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * Authors: Hugo Beauzee-Luyssen <hugo@vlmc.org>
 *
 * 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.
 *****************************************************************************/

23
#include "config.h"
24

25
#ifdef WITH_CRASHHANDLER_GUI
26
    #include "CrashHandler.h"
27
#endif
28

29
30
31
32
33
#include "Library.h"
#include "MainWorkflow.h"
#include "ProjectManager.h"
#include "SettingsManager.h"

Ludovic Fauvet's avatar
Ludovic Fauvet committed
34
#include <QFileDialog>
35
#include <QMessageBox>
36
37
#include <QSettings>
#include <QtDebug>
Ludovic Fauvet's avatar
Ludovic Fauvet committed
38
#include <QTimer>
39

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
40
#include <errno.h>
41
#include <signal.h>
42

43
#ifdef WITH_CRASHHANDLER
44
45
46
47
48
49
void    ProjectManager::signalHandler( int sig )
{
    signal( sig, SIG_DFL );

    ProjectManager::getInstance()->emergencyBackup();

50
51
52
53
54
55
    #ifdef WITH_CRASHHANDLER_GUI
        CrashHandler* ch = new CrashHandler( sig );
        ::exit( ch->exec() );
    #else
        ::exit( 1 );
    #endif
56
}
57
#endif
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
58

59
const QString   ProjectManager::unNamedProject = tr( "<Unnamed project>" );
60
const QString   ProjectManager::unSavedProject = tr( "<Unsaved project>" );
61

62
ProjectManager::ProjectManager() : m_projectFile( NULL ), m_needSave( false )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
63
{
64
65
    QSettings s;
    m_recentsProjects = s.value( "RecentsProjects" ).toStringList();
66

67
#ifdef WITH_CRASHHANDLER
68
    signal( SIGSEGV, ProjectManager::signalHandler );
69
    signal( SIGFPE, ProjectManager::signalHandler );
70
71
    signal( SIGABRT, ProjectManager::signalHandler );
    signal( SIGILL, ProjectManager::signalHandler );
72
#endif
73
74
75
76

    connect( this, SIGNAL( projectClosed() ), Library::getInstance(), SLOT( clear() ) );
    connect( this, SIGNAL( projectClosed() ), MainWorkflow::getInstance(), SLOT( clear() ) );

77
    QVariant val =
78
            SettingsManager::getInstance()->value( "project/ProjectName", unNamedProject, SettingsManager::Project );
79
80
    SettingsManager::getInstance()->watchValue( "project/ProjectName", this,
                                                SLOT(projectNameChanged(QVariant) ),
81
                                                SettingsManager::Project );
82
83
84
85

    //Automatic save part :
    m_timer = new QTimer( this );
    connect( m_timer, SIGNAL( timeout() ), this, SLOT( autoSaveRequired() ) );
86
    QVariant autoSaveEnabled =
87
            SettingsManager::getInstance()->value( "global/AutomaticBackup", false, SettingsManager::Vlmc );
88
89
    SettingsManager::getInstance()->watchValue( "global/AutomaticBackup", this,
                                                SLOT( automaticSaveEnabledChanged(QVariant) ),
90
                                                SettingsManager::Vlmc,
91
                                                Qt::QueuedConnection );
92
    QVariant autoSaveInterval =
93
            SettingsManager::getInstance()->value( "global/AutomaticBackupInterval", 5, SettingsManager::Vlmc );
94
95
    SettingsManager::getInstance()->watchValue( "global/AutomaticBackupInterval", this,
                                                SLOT( automaticSaveIntervalChanged(QVariant) ),
96
                                                SettingsManager::Vlmc,
97
                                                Qt::QueuedConnection );
98
    automaticSaveEnabledChanged( autoSaveEnabled );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
99
100
101
102
}

ProjectManager::~ProjectManager()
{
103
104
105
106
    // Write uncommited change to the disk
    QSettings s;
    s.sync();

107
108
    if ( m_projectFile != NULL )
        delete m_projectFile;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
109
110
}

111
112
113
114
115
bool    ProjectManager::needSave() const
{
    return m_needSave;
}

116
117
118
119
120
QStringList ProjectManager::recentsProjects() const
{
    return m_recentsProjects;
}

121
122
123
void    ProjectManager::cleanChanged( bool val )
{
    m_needSave = !val;
124
    emit projectUpdated( projectName(), val );
125
126
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
127
128
129
void    ProjectManager::loadTimeline()
{
    QDomElement     root = m_domDocument->documentElement();
130

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
131
    MainWorkflow::getInstance()->loadProject( root.firstChildElement( "timeline" ) );
132
    emit projectUpdated( projectName(), true );
133
134
135
136
137
}

void    ProjectManager::parseProjectNode( const QDomElement &node )
{
    QDomElement     projectNameNode = node.firstChildElement( "ProjectName" );
138
    m_projectName = projectNameNode.attribute( "value", ProjectManager::unNamedProject );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
139
140
}

141
void    ProjectManager::loadProject( const QString& fileName )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
142
{
143
    if ( fileName.isEmpty() == true )
144
145
        return;

146
147
148
    if ( closeProject() == false )
        return ;

149
150
    m_projectFile = new QFile( fileName );

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
151
152
153
154
    m_domDocument = new QDomDocument;
    m_projectFile->open( QFile::ReadOnly );
    m_domDocument->setContent( m_projectFile );
    m_projectFile->close();
155
    m_needSave = false;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
156

157
    if ( ProjectManager::isBackupFile( fileName ) == false )
158
        appendToRecentProject( fileName );
159
160
161
162
163
164
165
166
    else
    {
        //Delete the project file representation, so the next time the user
        //saves its project, vlmc will ask him where to save it.
        delete m_projectFile;
        m_projectFile = NULL;
    }

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
167
168
    QDomElement     root = m_domDocument->documentElement();

169
    parseProjectNode( root.firstChildElement( "project" ) );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
170
171
    connect( Library::getInstance(), SIGNAL( projectLoaded() ), this, SLOT( loadTimeline() ) );
    Library::getInstance()->loadProject( root.firstChildElement( "medias" ) );
172
    SettingsManager::getInstance()->load( root.firstChildElement( "project" ) );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
173
174
}

175
QString  ProjectManager::acquireProjectFileName()
176
177
178
179
{
    QString fileName =
            QFileDialog::getOpenFileName( NULL, "Enter the output file name",
                                          QString(), "VLMC project file(*.vlmc)" );
180
    return fileName;
181
182
}

183
bool    ProjectManager::createNewProjectFile( bool saveAs )
184
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
185
    if ( m_projectFile == NULL || saveAs == true )
186
187
188
189
190
191
192
193
    {
        QString outputFileName =
            QFileDialog::getSaveFileName( NULL, "Enter the output file name",
                                          QString(), "VLMC project file(*.vlmc)" );
        if ( outputFileName.length() == 0 )
            return false;
        if ( m_projectFile != NULL )
            delete m_projectFile;
194
195
        if ( outputFileName.endsWith( ".vlmc" ) == false )
            outputFileName += ".vlmc";
196
        m_projectFile = new QFile( outputFileName );
197
        appendToRecentProject( outputFileName );
198
        emit projectUpdated( projectName(), true );
199
200
201
202
    }
    return true;
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
203
void    ProjectManager::saveProject( bool saveAs /*= true*/ )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
204
{
205
206
207
    //If the project is still unsaved, or if we want to
    //save the project with a new name
    if ( createNewProjectFile( saveAs ) == false )
208
        return ;
209
210
    __saveProject( m_projectFile->fileName() );
    emit projectSaved();
211
    emit projectUpdated( projectName(), true );
212
213
214
215
}

void    ProjectManager::__saveProject( const QString &fileName )
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
216
217
218
219
220
221
222
223
224
225
226
    QDomImplementation    implem = QDomDocument().implementation();
    //FIXME: Think about naming the project...
    QString name = "VLMCProject";
    QString publicId = "-//XADECK//DTD Stone 1.0 //EN";
    QString systemId = "http://www-imagis.imag.fr/DTD/stone1.dtd";
    QDomDocument doc(implem.createDocumentType( name, publicId, systemId ) );

    QDomElement rootNode = doc.createElement( "vlmc" );

    Library::getInstance()->saveProject( doc, rootNode );
    MainWorkflow::getInstance()->saveProject( doc, rootNode );
227
    SettingsManager::getInstance()->save( doc, rootNode );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
228
229
230

    doc.appendChild( rootNode );

231
232
233
234
    QFile   file( fileName );
    file.open( QFile::WriteOnly );
    file.write( doc.toString().toAscii() );
    file.close();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
235
}
236

237
238
239
240
241
void    ProjectManager::newProject( const QString &projectName )
{
    if ( closeProject() == false )
        return ;
    m_projectName = projectName;
242
    emit projectUpdated( this->projectName(), false );
243
}
244

245
bool    ProjectManager::closeProject()
246
{
247
    if ( askForSaveIfModified() == false )
248
        return false;
249
250
251
252
253
    if ( m_projectFile != NULL )
    {
        delete m_projectFile;
        m_projectFile = NULL;
    }
254
    m_projectName = QString();
255
    //This one is for the mainwindow, to update the title bar
256
    emit projectUpdated( projectName(), true );
257
    //This one is for every part that need to clean something when the project is closed.
258
    emit projectClosed();
259
    return true;
260
}
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

bool    ProjectManager::askForSaveIfModified()
{
    if ( m_needSave == true )
    {
        QMessageBox msgBox;
        msgBox.setText( tr( "The project has been modified." ) );
        msgBox.setInformativeText( 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:
                saveProject();
                break ;
            case QMessageBox::Discard:
                break ;
            case QMessageBox::Cancel:
            default:
                return false ;
        }
    }
    return true;
}
287

288
void    ProjectManager::projectNameChanged( const QVariant& name )
289
290
{
    m_projectName = name.toString();
291
    emit projectUpdated( m_projectName, !m_needSave );
292
}
293
294
295

void    ProjectManager::emergencyBackup()
{
296
297
    QString     name;

298
299
    if ( m_projectFile != NULL )
    {
300
        name = m_projectFile->fileName();
301
302
303
304
305
        name += "backup";
        __saveProject( name );
    }
    else
    {
306
       name = QDir::currentPath() + "/unsavedproject.vlmcbackup";
307
308
        __saveProject( name );
    }
309
310
311
    QSettings   s;
    s.setValue( "EmergencyBackup", name );
    s.sync();
312
}
313

314
bool    ProjectManager::loadEmergencyBackup()
315
{
316
317
    QSettings   s;
    QString lastProject = s.value( "EmergencyBackup" ).toString();
318
319
320
    if ( QFile::exists( lastProject ) == true )
    {
        loadProject(  lastProject );
321
        m_needSave = true;
322
323
324
325
326
327
328
329
330
        return true;
    }
    return false;
}

bool    ProjectManager::isBackupFile( const QString& projectFile )
{
    return projectFile.endsWith( "backup" );
}
331
332
333
334
335
336
337
338
339
340
341
342
343

void    ProjectManager::appendToRecentProject( const QString& projectFile )
{
        // Append the item to the recents list
        m_recentsProjects.removeAll( projectFile );
        m_recentsProjects.prepend( projectFile );
        while ( m_recentsProjects.count() > 15 )
            m_recentsProjects.removeLast();

        QSettings s;
        s.setValue( "RecentsProjects", m_recentsProjects );
        s.sync();
}
344
345
346
347
348
349
350

void    ProjectManager::automaticSaveEnabledChanged( const QVariant& val )
{
    bool    enabled = val.toBool();

    if ( enabled == true )
    {
351
        QVariant interval = SettingsManager::getInstance()->value( "global/AutomaticBackupInterval", 5, SettingsManager::Vlmc );
352
        m_timer->start( interval.toInt() * 1000 * 60 );
353
354
355
356
357
358
359
    }
    else
        m_timer->stop();
}

void    ProjectManager::automaticSaveIntervalChanged( const QVariant& val )
{
360
    QVariant enabled = SettingsManager::getInstance()->value( "global/AutomaticBackup", false, SettingsManager::Vlmc );
361

362
    if ( enabled.toBool() == false )
363
        return ;
364
    m_timer->start( val.toInt() * 1000 * 60 );
365
366
367
368
}

void    ProjectManager::autoSaveRequired()
{
369
370
371
    if ( m_projectFile == NULL )
        return ;
    saveProject( false );
372
}
373
374
375
376
377
378
379
380
381
382
383
384
385
386

QString ProjectManager::projectName() const
{
    if ( m_projectName.isEmpty() == true )
    {
        if ( m_projectFile != NULL )
        {
            QFileInfo       fInfo( *m_projectFile );
            return fInfo.baseName();
        }
        return ProjectManager::unSavedProject;
    }
    return m_projectName;
}