Example #1
0
bool
GuiAppInstance::findAndTryLoadUntitledAutoSave()
{
    if ( !appPTR->getCurrentSettings()->isAutoSaveEnabledForUnsavedProjects() ) {
        return false;
    }

    QDir savesDir( Project::autoSavesDir() );
    QStringList entries = savesDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
    QStringList foundAutosaves;
    for (int i = 0; i < entries.size(); ++i) {
        const QString & entry = entries.at(i);
        QString searchStr( QLatin1Char('.') );
        searchStr.append( QString::fromUtf8(NATRON_PROJECT_FILE_EXT) );
        searchStr.append( QString::fromUtf8(".autosave") );
        int suffixPos = entry.indexOf(searchStr);
        if ( (suffixPos == -1) || entry.contains( QString::fromUtf8("RENDER_SAVE") ) ) {
            continue;
        }

        foundAutosaves << entry;
    }
    if ( foundAutosaves.empty() ) {
        return false;
    }

    QString text = tr("An auto-saved project was found with no associated project file.\n"
                      "Would you like to restore it? Clicking No will remove this auto-save.");


    appPTR->hideSplashScreen();

    StandardButtonEnum ret = Dialogs::questionDialog(tr("Auto-save").toStdString(),
                                                     text.toStdString(), false, StandardButtons(eStandardButtonYes | eStandardButtonNo),
                                                     eStandardButtonYes);
    if ( (ret == eStandardButtonNo) || (ret == eStandardButtonEscape) ) {
        Project::clearAutoSavesDir();

        return false;
    }

    for (int i = 0; i < foundAutosaves.size(); ++i) {
        const QString& autoSaveFileName = foundAutosaves[i];
        if (i == 0) {
            //Load the first one into the current instance of Natron, then open-up new instances
            if ( !getProject()->loadProject(savesDir.path() + QLatin1Char('/'), autoSaveFileName, true) ) {
                return false;
            }
        } else {
            CLArgs cl;
            AppInstance* newApp = appPTR->newAppInstance(cl, false);
            if ( !newApp->getProject()->loadProject(savesDir.path() + QLatin1Char('/'), autoSaveFileName, true) ) {
                return false;
            }
        }
    }

    return true;
} // findAndTryLoadAutoSave
Example #2
0
int
Gui::saveWarning()
{
    if ( !getApp()->getProject()->isSaveUpToDate() ) {
        StandardButtonEnum ret =  Dialogs::questionDialog(NATRON_APPLICATION_NAME, tr("Save changes to %1?").arg( getApp()->getProject()->getProjectFilename() ).toStdString(),
                                                          false,
                                                          StandardButtons(eStandardButtonSave | eStandardButtonDiscard | eStandardButtonCancel), eStandardButtonSave);
        if ( (ret == eStandardButtonEscape) || (ret == eStandardButtonCancel) ) {
            return 2;
        } else if (ret == eStandardButtonDiscard) {
            return 1;
        } else {
            return 0;
        }
    }

    return -1;
}
Example #3
0
void
GuiAppInstance::load(const CLArgs& cl,
                     bool makeEmptyInstance)
{
    if (getAppID() == 0) {
        appPTR->setLoadingStatus( QObject::tr("Creating user interface...") );
    }

    try {
        declareCurrentAppVariable_Python();
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }

    _imp->_gui = new Gui(this);
    _imp->_gui->createGui();

    printAutoDeclaredVariable(_imp->declareAppAndParamsString);

    ///if the app is interactive, build the plugins toolbuttons from the groups we extracted off the plugins.
    const std::list<boost::shared_ptr<PluginGroupNode> > & _toolButtons = appPTR->getTopLevelPluginsToolButtons();
    for (std::list<boost::shared_ptr<PluginGroupNode>  >::const_iterator it = _toolButtons.begin(); it != _toolButtons.end(); ++it) {
        _imp->findOrCreateToolButtonRecursive(*it);
    }
    _imp->_gui->sortAllPluginsToolButtons();

    Q_EMIT pluginsPopulated();

    ///show the gui
    _imp->_gui->show();


    boost::shared_ptr<Settings> nSettings = appPTR->getCurrentSettings();
    QObject::connect( getProject().get(), SIGNAL(formatChanged(Format)), this, SLOT(projectFormatChanged(Format)) );

    {
        QSettings settings( QString::fromUtf8(NATRON_ORGANIZATION_NAME), QString::fromUtf8(NATRON_APPLICATION_NAME) );
        if ( !settings.contains( QString::fromUtf8("checkForUpdates") ) ) {
            StandardButtonEnum reply = Dialogs::questionDialog(tr("Updates").toStdString(),
                                                               tr("Do you want " NATRON_APPLICATION_NAME " to check for updates "
                                                                  "on launch of the application ?").toStdString(), false);
            bool checkForUpdates = reply == eStandardButtonYes;
            nSettings->setCheckUpdatesEnabled(checkForUpdates);
        }

        if ( nSettings->isCheckForUpdatesEnabled() ) {
            appPTR->setLoadingStatus( tr("Checking if updates are available...") );
            checkForNewVersion();
        }
    }

    if ( nSettings->isDefaultAppearanceOutdated() ) {
        StandardButtonEnum reply = Dialogs::questionDialog(tr("Appearance").toStdString(),
                                                           tr(NATRON_APPLICATION_NAME " default appearance changed since last version.\n"
                                                              "Would you like to set the new default appearance?").toStdString(), false);
        if (reply == eStandardButtonYes) {
            nSettings->restoreDefaultAppearance();
        }
    }

    /// Create auto-save dir if it does not exists
    QDir dir = Project::autoSavesDir();
    dir.mkpath( QString::fromUtf8(".") );


    if (getAppID() == 0) {
        appPTR->getCurrentSettings()->doOCIOStartupCheckIfNeeded();

        if ( !appPTR->isShorcutVersionUpToDate() ) {
            StandardButtonEnum reply = questionDialog(tr("Shortcuts").toStdString(),
                                                      tr("Default shortcuts for " NATRON_APPLICATION_NAME " have changed, "
                                                         "would you like to set them to their defaults ? "
                                                         "Clicking no will keep the old shortcuts hence if a new shortcut has been "
                                                         "set to something else than an empty shortcut you won't benefit of it.").toStdString(),
                                                      false,
                                                      StandardButtons(eStandardButtonYes | eStandardButtonNo),
                                                      eStandardButtonNo);
            if (reply == eStandardButtonYes) {
                appPTR->restoreDefaultShortcuts();
            }
        }
    }

    if (makeEmptyInstance) {
        return;
    }

    /// If this is the first instance of the software, try to load an autosave
    if ( (getAppID() == 0) && cl.getScriptFilename().isEmpty() ) {
        if ( findAndTryLoadUntitledAutoSave() ) {
            ///if we successfully loaded an autosave ignore the specified project in the launch args.
            return;
        }
    }


    QFileInfo info( cl.getScriptFilename() );

    if ( cl.getScriptFilename().isEmpty() || !info.exists() ) {
        getProject()->createViewer();
        execOnProjectCreatedCallback();

        const QString& imageFile = cl.getImageFilename();
        if ( !imageFile.isEmpty() ) {
            handleFileOpenEvent( imageFile.toStdString() );
        }
    } else {
        if ( info.suffix() == QString::fromUtf8("py") ) {
            appPTR->setLoadingStatus( tr("Loading script: ") + cl.getScriptFilename() );

            ///If this is a Python script, execute it
            loadPythonScript(info);
            execOnProjectCreatedCallback();
        } else if ( info.suffix() == QString::fromUtf8(NATRON_PROJECT_FILE_EXT) ) {
            ///Otherwise just load the project specified.
            QString name = info.fileName();
            QString path = info.path();
            Global::ensureLastPathSeparator(path);
            appPTR->setLoadingStatus(tr("Loading project: ") + path + name);
            getProject()->loadProject(path, name);
            ///remove any file open event that might have occured
            appPTR->setFileToOpen( QString() );
        } else {
            Dialogs::errorDialog( tr("Invalid file").toStdString(),
                                  tr(NATRON_APPLICATION_NAME " only accepts python scripts or .ntp project files").toStdString() );
            execOnProjectCreatedCallback();
        }
    }

    const QString& extraOnProjectCreatedScript = cl.getDefaultOnProjectLoadedScript();
    if ( !extraOnProjectCreatedScript.isEmpty() ) {
        QFileInfo cbInfo(extraOnProjectCreatedScript);
        if ( cbInfo.exists() ) {
            loadPythonScript(cbInfo);
        }
    }
} // load
Example #4
0
void
OutputEffectInstance::renderFullSequence(bool isBlocking,
                                         bool enableRenderStats,
                                         BlockingBackgroundRender* renderController,
                                         int first,
                                         int last,
                                         int frameStep)
{
    int viewsCount = getApp()->getProject()->getProjectViewsCount();
    const ViewIdx mainView(0);
    std::vector<ViewIdx> viewsToRender(viewsCount);

    for (int i = 0; i < viewsCount; ++i) {
        viewsToRender[i] = ViewIdx(i);
    }

    ///The effect is sequential (e.g: WriteFFMPEG), and thus cannot render multiple views, we have to choose one
    ///We pick the user defined main view in the project settings
    SequentialPreferenceEnum sequentiallity = getSequentialPreference();
    bool canOnlyHandleOneView = sequentiallity == eSequentialPreferenceOnlySequential || sequentiallity == eSequentialPreferencePreferSequential;

    if (canOnlyHandleOneView) {
        viewsToRender.clear();
        viewsToRender.push_back(mainView);
    }

    if ( isViewAware() ) {
        //If the Writer is view aware, check if it wants to render all views at once or not
        KnobPtr outputFileNameKnob = getKnobByName(kOfxImageEffectFileParamName);
        if (outputFileNameKnob) {
            KnobOutputFile* outputFileName = dynamic_cast<KnobOutputFile*>( outputFileNameKnob.get() );
            assert(outputFileName);
            if (outputFileName) {
                std::string pattern = outputFileName->getValue();
                std::size_t foundViewPattern = pattern.find_first_of("%v");
                if (foundViewPattern == std::string::npos) {
                    foundViewPattern = pattern.find_first_of("%V");
                }
                if (foundViewPattern == std::string::npos) {
                    ///No view pattern
                    ///all views will be overwritten to the same file
                    ///If this is WriteOIIO, check the parameter "viewsSelector" to determine if the user wants to encode all
                    ///views to a single file or not
                    KnobPtr viewsKnob = getKnobByName(kWriteOIIOParamViewsSelector);
                    bool hasViewChoice = false;
                    if ( viewsKnob && !viewsKnob->getIsSecret() ) {
                        KnobChoice* viewsChoice = dynamic_cast<KnobChoice*>( viewsKnob.get() );
                        if (viewsChoice) {
                            hasViewChoice = true;
                            int viewChoice_i = viewsChoice->getValue();
                            if (viewChoice_i == 0) { // the "All" choice
                                viewsToRender.clear();
                                // note: if the plugin renders all views to a single file, then rendering view 0 will do the job.
                                viewsToRender.push_back( ViewIdx(0) );
                            } else {
                                //The user has specified a view
                                viewsToRender.clear();
                                assert(viewChoice_i >= 1);
                                viewsToRender.push_back( ViewIdx(viewChoice_i - 1) );
                            }
                        }
                    }
                    if (!hasViewChoice) {
                        if (viewsToRender.size() > 1) {
                            std::string mainViewName;
                            const std::vector<std::string>& viewNames = getApp()->getProject()->getProjectViewNames();
                            if ( mainView < (int)viewNames.size() ) {
                                mainViewName = viewNames[mainView];
                            }
                            QString message = tr("%1 does not support multi-view, only the view %2 will be rendered.")
                                              .arg( QString::fromUtf8( getNode()->getLabel_mt_safe().c_str() ) )
                                              .arg( QString::fromUtf8( mainViewName.c_str() ) );
                            if (!renderController) {
                                message.append( QChar::fromLatin1('\n') );
                                message.append( QString::fromUtf8("You can use the %v or %V indicator in the filename to render to separate files.\n"
                                                                  "Would you like to continue?") );
                                StandardButtonEnum rep = Dialogs::questionDialog(tr("Multi-view support").toStdString(), message.toStdString(), false, StandardButtons(eStandardButtonOk | eStandardButtonCancel), eStandardButtonOk);
                                if (rep != eStandardButtonOk) {
                                    return;
                                }
                            } else {
                                Dialogs::warningDialog( tr("Multi-view support").toStdString(), message.toStdString() );
                            }
                        }
                        //Render the main-view only...
                        viewsToRender.clear();
                        viewsToRender.push_back(mainView);
                    }
                } else {
                    ///The user wants to write each view into a separate file
                    ///This will disregard the content of kWriteOIIOParamViewsSelector and the Writer
                    ///should write one view per-file.
                }
            }
        }
    } else { // !isViewAware
        if (viewsToRender.size() > 1) {
            std::string mainViewName;
            const std::vector<std::string>& viewNames = getApp()->getProject()->getProjectViewNames();
            if ( mainView < (int)viewNames.size() ) {
                mainViewName = viewNames[mainView];
            }
            QString message = tr("%1 does not support multi-view, only the view %2 will be rendered.")
                              .arg( QString::fromUtf8( getNode()->getLabel_mt_safe().c_str() ) )
                              .arg( QString::fromUtf8( mainViewName.c_str() ) );
            if (!renderController) {
                message.append( QChar::fromLatin1('\n') );
                message.append( QString::fromUtf8("You can use the %v or %V indicator in the filename to render to separate files.\n"
                                                  "Would you like to continue?") );
                StandardButtonEnum rep = Dialogs::questionDialog(tr("Multi-view support").toStdString(), message.toStdString(), false, StandardButtons(eStandardButtonOk | eStandardButtonCancel), eStandardButtonOk);
                if (rep != eStandardButtonOk) {
                    return;
                }
            } else {
                Dialogs::warningDialog( tr("Multi-view support").toStdString(), message.toStdString() );
            }
        }
    }


    RenderSequenceArgs args;
    {
        QMutexLocker k(&_outputEffectDataLock);
        args.firstFrame = first;
        args.lastFrame = last;
        args.frameStep = frameStep;
        args.renderController = renderController;
        args.useStats = enableRenderStats;
        args.blocking = isBlocking;
        args.viewsToRender = viewsToRender;
        _renderSequenceRequests.push_back(args);
        if (_renderSequenceRequests.size() > 1) {
            //The node is already rendering a sequence, queue it and dequeue it in notifyRenderFinished()
            return;
        }
    }
    launchRenderSequence(args);
} // OutputEffectInstance::renderFullSequence