Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tproject.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/sceneproperties.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheet.h"
Toshihiro Shimizu 890ddd
#include "toonz/observer.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzfolders.h"
Toshihiro Shimizu 890ddd
#include "toonz/cleanupparameters.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tenv.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tstream.h"
Toshihiro Shimizu 890ddd
#include "tfilepath_io.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qfileinfo></qfileinfo>
Toshihiro Shimizu 890ddd
#include <qdir></qdir>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <fstream></fstream>
Toshihiro Shimizu 890ddd
#include <stdlib.h></stdlib.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace std;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
/* Version-related strings added to project files, in reversed chronological
Shinya Kitaoka 120a6e
 * order */
Toshihiro Shimizu 890ddd
const std::wstring prjSuffix[4] = {L"_otprj", L"_prj63ml", L"_prj6", L"_prj"};
Shinya Kitaoka 120a6e
const std::wstring xmlExt       = L".xml";
Shinya Kitaoka 120a6e
const int prjSuffixCount        = 4;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
/*! Default inputs folder: is used to save all scanned immage.*/
Shinya Kitaoka 3bfa54
const std::string
Shinya Kitaoka 120a6e
    TProject::Inputs = "inputs",
Shinya Kitaoka 120a6e
    /*! Default drawings folder: is used to save all tlv and pli levels.*/
Shinya Kitaoka 120a6e
    TProject::Drawings = "drawings",
Shinya Kitaoka 120a6e
    /*! Default scenes folder: is used to save all scenes.*/
Shinya Kitaoka 120a6e
    TProject::Scenes = "scenes",
Shinya Kitaoka 120a6e
    /*! Default scripts folder: is used to save all the script.*/
Shinya Kitaoka 120a6e
    TProject::Scripts = "scripts",
Shinya Kitaoka 120a6e
    /*! Default extras folder: is used to save all imported images and levels
Shinya Kitaoka 120a6e
       not pli or tlv.*/
Shinya Kitaoka 120a6e
    TProject::Extras = "extras",
Shinya Kitaoka 120a6e
    /*! Default outputs folder: is used to save all rendered scenes.*/
Shinya Kitaoka 120a6e
    TProject::Outputs = "outputs",
Shinya Kitaoka 120a6e
    /*! Default palettes folder: is used for color design (色指定)*/
Shinya Kitaoka 120a6e
    TProject::Palettes = "palettes";
Toshihiro Shimizu 890ddd
//! Default project name
Shinya Kitaoka 120a6e
const TFilePath TProject::SandboxProjectName("sandbox");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TProjectP currentProject;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// helper functions
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath makeRelative(TFilePath ref, TFilePath fp) {
Shinya Kitaoka 120a6e
  if (!fp.isAbsolute()) return fp;
Shinya Kitaoka 120a6e
  TFilePath dots;
Shinya Kitaoka 120a6e
  for (;;) {
Shinya Kitaoka 120a6e
    if (ref.isAncestorOf(fp)) {
Shinya Kitaoka 120a6e
      TFilePath relativePath = dots + (fp - ref);
Shinya Kitaoka 120a6e
      return relativePath;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (ref.isRoot()) return fp;
Shinya Kitaoka 120a6e
    ref  = ref.getParentDir();
Shinya Kitaoka 120a6e
    dots = dots + "..";
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath makeAbsolute(TFilePath ref, TFilePath fp) {
Shinya Kitaoka 120a6e
  if (fp.isAbsolute()) return fp;
Shinya Kitaoka 120a6e
  const TFilePath twoDots("..");
Shinya Kitaoka 120a6e
  while (twoDots.isAncestorOf(fp)) {
Shinya Kitaoka 120a6e
    TFilePath refParent = ref.getParentDir();
Shinya Kitaoka 120a6e
    if (refParent == TFilePath()) break;  // non dovrebbe succedere
Shinya Kitaoka 120a6e
    ref = refParent;
Shinya Kitaoka 120a6e
    fp  = fp - twoDots;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  fp = ref + fp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return fp;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TEnv::StringVar currentProjectPath("CurrentProject", "");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Returns the project suffix (ie anything beyond the last '_' included)
Toshihiro Shimizu 890ddd
//! of the passed file path.
Shinya Kitaoka 120a6e
std::wstring getProjectSuffix(const TFilePath &path) {
Shinya Kitaoka 120a6e
  const std::wstring &name = path.getWideName();
Shinya Kitaoka 120a6e
  int idx                  = name.find_last_of(L'_');
Shinya Kitaoka 120a6e
  if (idx == string::npos) return L"";
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return name.substr(idx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! In case the supplied path has an old version suffix,
Toshihiro Shimizu 890ddd
//! this function updates it to the most recent; otherwise,
Toshihiro Shimizu 890ddd
//! it is left untouched.
Shinya Kitaoka 120a6e
TFilePath getLatestVersionProjectPath(const TFilePath &path) {
Shinya Kitaoka 120a6e
  const std::wstring &suffix = getProjectSuffix(path);
Shinya Kitaoka 120a6e
  for (int i = 1; i < prjSuffixCount; ++i)
Shinya Kitaoka 120a6e
    if (suffix == prjSuffix[i]) {
Shinya Kitaoka 120a6e
      const std::wstring &name = path.getWideName();
Shinya Kitaoka 120a6e
      int pos                  = name.size() - suffix.size();
Shinya Kitaoka 120a6e
      return path.withName(path.getWideName().substr(0, pos) + prjSuffix[0]);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return path;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! Return project path with right suffix.
Shinya Kitaoka 120a6e
                VERSION 6.0: _prj6.xml;
Shinya Kitaoka 120a6e
                PRECEDENT VERSION: _prj.xml.
Shinya Kitaoka 120a6e
                If in \b folder exists ONLY old version project path return old
Shinya Kitaoka 120a6e
   version path;
Shinya Kitaoka 120a6e
                otherwise return 6.0 version project path.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TFilePath searchProjectPath(TFilePath folder) {
Shinya Kitaoka 120a6e
  assert(folder.isAbsolute());
Shinya Kitaoka 120a6e
  wstring projectName = folder.getWideName();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Search for the first available project file, starting from the most recent.
Shinya Kitaoka 120a6e
  TFilePath projectPath;
Shinya Kitaoka 120a6e
  for (int i = 0; i < prjSuffixCount; ++i) {
Shinya Kitaoka 120a6e
    projectPath = folder + TFilePath(projectName + prjSuffix[i] + xmlExt);
Shinya Kitaoka 120a6e
    if (TFileStatus(projectPath).doesExist()) return projectPath;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If none exist in the folder, build the name with the most recent suffix
Shinya Kitaoka 120a6e
  return folder + TFilePath(projectName + prjSuffix[0] + xmlExt);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isFolderUnderVersionControl(const TFilePath &folderPath) {
Shinya Kitaoka 120a6e
  QDir dir(QString::fromStdWString(folderPath.getWideString()));
John Dancel 1e3f0c
  if (dir.entryList(QDir::AllDirs | QDir::Hidden).contains(".svn")) return true;
John Dancel 1e3f0c
  // For SVN 1.7 and greater, check parent directories to see if it's under
John Dancel 1e3f0c
  // version control
John Dancel 1e3f0c
  while (dir.cdUp()) {
John Dancel 1e3f0c
    if (dir.entryList(QDir::AllDirs | QDir::Hidden).contains(".svn"))
John Dancel 1e3f0c
      return true;
John Dancel 1e3f0c
  }
John Dancel 1e3f0c
John Dancel 1e3f0c
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void hideOlderProjectFiles(const TFilePath &folderPath) {
Shinya Kitaoka 120a6e
  const std::wstring &name = folderPath.getWideName();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFilePath path;
Shinya Kitaoka 120a6e
  for (int i = 1; i < prjSuffixCount; ++i) {
Shinya Kitaoka 120a6e
    path = folderPath + (name + prjSuffix[i] + xmlExt);
Shinya Kitaoka 120a6e
    if (TFileStatus(path).doesExist())
Shinya Kitaoka 120a6e
      TSystem::renameFile(path.withType("xml_"), path);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// TProject
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \class TProject tproject.h
Shinya Kitaoka 120a6e
        \brief Define and handle a toonz project.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    A toonz project is identified by a project name that matches a folder with
Shinya Kitaoka 120a6e
   the same name in the project root.\n
Shinya Kitaoka 120a6e
        The project folder can contains saveral other folders.
Shinya Kitaoka 120a6e
        By default, five folders are created: Inputs, Drawings, Scenes, Extras
Shinya Kitaoka 120a6e
   and Outputs.
Shinya Kitaoka 120a6e
        Each of this folders can be renamed using the setFolder(string name,
Shinya Kitaoka 120a6e
   TFilePath path) method.
luzpaz 27707d
        Usually, the \b name parameter is chosen from inputs, drawings, scenes,
Shinya Kitaoka 120a6e
   extras and outputs;
Shinya Kitaoka 120a6e
        the \b path parameter contains the folder that can have a different name
Shinya Kitaoka 120a6e
   from them.
Shinya Kitaoka 120a6e
        All association between names and folder are kept in a mapping.\n
Shinya Kitaoka 120a6e
        A folder of a project can be constant or scene dependent. A constant
Shinya Kitaoka 120a6e
   folder is used by
Shinya Kitaoka 120a6e
        every scene created in the project to save or load data. A scene
Shinya Kitaoka 120a6e
   dependent folder is used only by the scene
luzpaz 27707d
        from which the folder depends. A scene dependent folder contains the
Shinya Kitaoka 120a6e
   string "$scene" in its path.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        \code
Shinya Kitaoka 120a6e
        e.g.
Shinya Kitaoka 120a6e
        Scene path: "...\\prodA\\episode1\\scenes\\sceneA.tzn"
Shinya Kitaoka 120a6e
        Drawings scene dependent folder:
Shinya Kitaoka 120a6e
   "...\\prodA\\episode1\\$scene\\drawings"
Shinya Kitaoka 120a6e
        Drawings folder path: "...\\prodA\\episode1\\SceneA\\drawings"
Shinya Kitaoka 120a6e
        \endcode
Shinya Kitaoka 120a6e
        \n\n
luzpaz 27707d
        By default, from the toonz installation, exist always a toonz project
Shinya Kitaoka 120a6e
   called "sandbox".
Shinya Kitaoka 120a6e
        \see TProjectManager, TSceneProperties.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \fn TFilePath TProject::getName() const
Shinya Kitaoka 120a6e
        Returns the name of the project.
Shinya Kitaoka 120a6e
        \code
Shinya Kitaoka 120a6e
        e.g. "prodA\\episode1"
Shinya Kitaoka 120a6e
        \endcode
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \fn TFilePath TProject::getProjectPath() const
Shinya Kitaoka 120a6e
        Returns the path of the project. It is an absolute path.
Shinya Kitaoka 120a6e
        \code
Shinya Kitaoka 120a6e
        e.g. "prodA\\episode1" -> "...\\prodA\\episode1\\episode1_prj.xml"
Shinya Kitaoka 120a6e
        \endcode
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \fn TFilePath TProject::getProjectFolder() const
Shinya Kitaoka 120a6e
        Returns the project folder path. It is an absolute path.
Shinya Kitaoka 120a6e
        \code
Shinya Kitaoka 120a6e
        e.g. "prodA\\episode1" -> "...\\prodA\\episode1\\"
Shinya Kitaoka 120a6e
        \endcode
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \fn const TSceneProperties &TProject::getSceneProperties() const
Toshihiro Shimizu 890ddd
    Returns the scene properties of the project.
Toshihiro Shimizu 890ddd
    \see TSceneProperties
Shinya Kitaoka 120a6e
        */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \fn void TProject::save()
Shinya Kitaoka 120a6e
        Saves the project.
luzpaz 27707d
        Is equivalent to save(getProjectPath()).
Shinya Kitaoka 120a6e
        The project is saved as a xml file.\n
Shinya Kitaoka 120a6e
        Uses TProjectManager and TOStream.
Shinya Kitaoka 120a6e
        \note Exceptions can be thrown.
Shinya Kitaoka 120a6e
        \see TProjectManager and TOStream.
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TProject::TProject() : m_name(), m_path(), m_sprop(new TSceneProperties()) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TProject::~TProject() { delete m_sprop; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Associates the \b name to the specified \b path.
Shinya Kitaoka 120a6e
        \code
Shinya Kitaoka 120a6e
        e.g. setFolder(TProject::Drawings, TFilePath("C:\\temp\\drawings"))
Shinya Kitaoka 120a6e
        \endcode
luzpaz 27707d
        Usually, the \b name parameter is chosen from inputs, drawings, scenes,
Shinya Kitaoka 120a6e
   extras and outputs;
Shinya Kitaoka 120a6e
        the \b path contains the folder that can have a different name from
Shinya Kitaoka 120a6e
   them.
Shinya Kitaoka 120a6e
        Every association between names and paths is contained in a mapping.
Shinya Kitaoka 120a6e
        \note Not absolute path are thought relative to the project folder.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void TProject::setFolder(string name, TFilePath path) {
Shinya Kitaoka 120a6e
  std::map<std::string, tfilepath="">::iterator it;</std::string,>
Shinya Kitaoka 120a6e
  it = m_folders.find(name);
Shinya Kitaoka 120a6e
  if (it == m_folders.end()) {
Shinya Kitaoka 120a6e
    m_folderNames.push_back(name);
Shinya Kitaoka 120a6e
    m_folders[name] = path;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    it->second = path;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Create a folder named with \b name.
Shinya Kitaoka 120a6e
        Call the setFolder(name,TFilePath(name)) method.\n
Shinya Kitaoka 120a6e
        e.g. setFolder(TProject::Drawings) is equivalent to
Shinya Kitaoka 120a6e
   setFolder(TProject::Drawings, TFilePath("drawings"))\n
Shinya Kitaoka 120a6e
        The resulting is "..\\projectFolder\\drawings"
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void TProject::setFolder(string name) { setFolder(name, TFilePath(name)); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the path of the folder named with \b name.\n
Shinya Kitaoka 120a6e
        Returns TFilePath() if there isn't a folder named with \b name.
shun_iwasawa 472b70
        \note The returned path could be a relative path if \b absolute is
shun_iwasawa 472b70
   false.
Toshihiro Shimizu 890ddd
*/
shun_iwasawa 472b70
TFilePath TProject::getFolder(string name, bool absolute) const {
Shinya Kitaoka 120a6e
  std::map<std::string, tfilepath="">::const_iterator it;</std::string,>
Shinya Kitaoka 120a6e
  it = m_folders.find(name);
Shinya Kitaoka 120a6e
  if (it != m_folders.end())
shun_iwasawa 472b70
    return (absolute) ? makeAbsolute(getProjectFolder(), it->second)
shun_iwasawa 472b70
                      : it->second;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return TFilePath();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the path of the Scene folder.\n
Shinya Kitaoka 120a6e
        The Scene folder contains all the saved scene. The returned path is an
Shinya Kitaoka 120a6e
   absolute path.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TFilePath TProject::getScenesPath() const {
Shinya Kitaoka 120a6e
  TFilePath scenes = getFolder(Scenes);
Shinya Kitaoka 120a6e
  return makeAbsolute(getProjectFolder(), scenes);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the path of the folder indexed with \b index.\n
Shinya Kitaoka 120a6e
        Returns TFilePath() if there isn't a folder indexed with \b index.
Shinya Kitaoka 120a6e
        \note The returned path could be a relative path.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TFilePath TProject::getFolder(int index) const {
Shinya Kitaoka 120a6e
  if (0 <= index && index < (int)m_folderNames.size())
Shinya Kitaoka 120a6e
    return getFolder(m_folderNames[index]);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return TFilePath();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns true if the folder indexed with \b index isn't scene dependent.\n
Shinya Kitaoka 120a6e
        A scene dependent folder is a folder containing "$scene" in its path.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
bool TProject::isConstantFolder(int index) const {
Shinya Kitaoka 120a6e
  TFilePath fp = getFolder(index);
Shinya Kitaoka 120a6e
  return fp.getWideString().find(L"$scene") == wstring::npos;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//! Returns the number of the folders contained in the project folder.
Shinya Kitaoka 120a6e
int TProject::getFolderCount() const { return m_folders.size(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//! Returns the name of the folder indexed with \b index.
Shinya Kitaoka 120a6e
string TProject::getFolderName(int index) const {
Shinya Kitaoka 120a6e
  if (0 <= index && index < (int)m_folderNames.size())
Shinya Kitaoka 120a6e
    return m_folderNames[index];
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return "";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! Returns the index of the folder named with \b folderName.\n
Shinya Kitaoka 120a6e
        If a folder named with \b folderName doesn't exist, return -1.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
int TProject::getFolderIndex(string name) const {
Shinya Kitaoka 120a6e
  std::vector<std::string>::const_iterator it;</std::string>
Shinya Kitaoka 120a6e
  it = std::find(m_folderNames.begin(), m_folderNames.end(), name);
Shinya Kitaoka 120a6e
  if (it == m_folderNames.end()) return -1;
Shinya Kitaoka 120a6e
  return std::distance(it, m_folderNames.begin());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns true if this project is the current project.
Shinya Kitaoka 120a6e
        Uses \b TProjectManager.
Shinya Kitaoka 120a6e
        \see TProjectManager
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
bool TProject::isCurrent() const {
Shinya Kitaoka 120a6e
  TFilePath currentProjectPath =
Shinya Kitaoka 120a6e
      TProjectManager::instance()->getCurrentProjectPath();
Shinya Kitaoka 120a6e
  if (getProjectPath() == currentProjectPath)
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return getLatestVersionProjectPath(currentProjectPath) ==
Shinya Kitaoka 120a6e
           getLatestVersionProjectPath(getProjectPath());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Set the scene properties \b sprop to the project.
Toshihiro Shimizu 890ddd
    \see TSceneProperties*/
Shinya Kitaoka 120a6e
void TProject::setSceneProperties(const TSceneProperties &sprop) {
Shinya Kitaoka 120a6e
  m_sprop->assign(&sprop);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the absolute path of \b fp.
Shinya Kitaoka 120a6e
        If \b fp contains "$project", replaces it with the name of the project.
Shinya Kitaoka 120a6e
        \note the returned path can contain "$scene"
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TFilePath TProject::decode(TFilePath fp) const {
Shinya Kitaoka 120a6e
  for (;;) {
Shinya Kitaoka 120a6e
    wstring fpstr = fp.getWideString();
Shinya Kitaoka 120a6e
    int j         = fpstr.find(L"$project");
Shinya Kitaoka 120a6e
    if (j == (int)wstring::npos) break;
Shinya Kitaoka 120a6e
    fpstr.replace(j, 8, getName().getWideString());
Shinya Kitaoka 120a6e
    fp = TFilePath(fpstr);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return makeAbsolute(getProjectFolder(), fp);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TProject::setUseScenePath(string folderName, bool on) {
Shinya Kitaoka 120a6e
  m_useScenePathFlags[folderName] = on;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TProject::getUseScenePath(string folderName) const {
Shinya Kitaoka 120a6e
  std::map<std::string, bool="">::const_iterator it;</std::string,>
Shinya Kitaoka 120a6e
  it = m_useScenePathFlags.find(folderName);
Shinya Kitaoka 120a6e
  return it != m_useScenePathFlags.end() ? it->second : false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the index of the folder specified in the path \b folderDir.
Shinya Kitaoka 120a6e
        Returns -1 if \b folderDir isn't a folder of the project.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
int TProject::getFolderIndexFromPath(const TFilePath &folderDir) {
Shinya Kitaoka 120a6e
  TFilePath scenePath          = decode(getFolder(Scenes));
Shinya Kitaoka 120a6e
  bool sceneDependentScenePath = false;
Shinya Kitaoka 120a6e
  if (scenePath.getName().find("$scene") != string::npos) {
Shinya Kitaoka 120a6e
    scenePath               = scenePath.getParentDir();
Shinya Kitaoka 120a6e
    sceneDependentScenePath = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int folderIndex;
Shinya Kitaoka 120a6e
  for (folderIndex = 0; folderIndex < getFolderCount(); folderIndex++)
Shinya Kitaoka 120a6e
    if (isConstantFolder(folderIndex)) {
Shinya Kitaoka 120a6e
      TFilePath fp = decode(getFolder(folderIndex));
Shinya Kitaoka 120a6e
      if (fp == folderDir) return folderIndex;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      TFilePath fp = decode(getFolder(folderIndex));
Shinya Kitaoka 120a6e
      wstring a    = fp.getWideString();
Shinya Kitaoka 120a6e
      wstring b    = folderDir.getWideString();
Shinya Kitaoka 120a6e
      int alen     = a.length();
Shinya Kitaoka 120a6e
      int blen     = b.length();
Shinya Kitaoka 120a6e
      int i        = a.find(L"$scene");
Shinya Kitaoka 120a6e
      assert(i != (int)wstring::npos);
Shinya Kitaoka 120a6e
      if (i == (int)wstring::npos) continue;
Shinya Kitaoka 120a6e
      int j = i + 1;
Shinya Kitaoka 120a6e
      while (j < alen && isalnum(a[j])) j++;
Shinya Kitaoka 120a6e
      // a.substr(i,j-i) == "$scenexxxx"
Shinya Kitaoka 120a6e
      int k = j + blen - alen;
Shinya Kitaoka 120a6e
      if (!(0 <= i && i < k && k <= blen)) continue;
Shinya Kitaoka 120a6e
      assert(i < blen);
Shinya Kitaoka 120a6e
      if (i > 0 && a.substr(0, i) != b.substr(0, i)) continue;
Shinya Kitaoka 120a6e
      if (k < blen && (j >= alen || a.substr(j) != b.substr(k))) continue;
Shinya Kitaoka 120a6e
      wstring v = b.substr(i, k - i);
Shinya Kitaoka 120a6e
      TFilePath scene(v + L".tnz");
Shinya Kitaoka 120a6e
      if (sceneDependentScenePath)
Shinya Kitaoka 120a6e
        scene = scenePath + scene.getWideName() + scene;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        scene = scenePath + scene;
Shinya Kitaoka 120a6e
      if (TFileStatus(scene).doesExist()) return folderIndex;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the folder's name of the specified TFilePath \b folderDir.\n
Shinya Kitaoka 120a6e
        Returns the empty string if \b folderDir isn't a folder of the
Shinya Kitaoka 120a6e
   project.*/
Shinya Kitaoka 120a6e
wstring TProject::getFolderNameFromPath(const TFilePath &folderDir) {
Shinya Kitaoka 120a6e
  int index = getFolderIndexFromPath(folderDir);
Shinya Kitaoka 120a6e
  if (index < 0) return L"";
Shinya Kitaoka 120a6e
  if (getFolder(index).isAbsolute())
Shinya Kitaoka 120a6e
    return ::to_wstring("+" + getFolderName(index));
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return folderDir.getWideName();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Saves the project in the specified path.
Shinya Kitaoka 120a6e
        The TfilePath fp must be an absolute path. The project is saved as a xml
Shinya Kitaoka 120a6e
   file.\n
Shinya Kitaoka 120a6e
        Uses TProjectManager and TOStream.
Shinya Kitaoka 120a6e
        \note Exceptions can be thrown.
Shinya Kitaoka 120a6e
        \see TProjectManager and TOStream.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
bool TProject::save(const TFilePath &projectPath) {
Shinya Kitaoka 120a6e
  assert(isAProjectPath(projectPath));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TProjectManager *pm     = TProjectManager::instance();
Shinya Kitaoka 120a6e
  m_name                  = pm->projectPathToProjectName(projectPath);
Shinya Kitaoka 120a6e
  m_path                  = getLatestVersionProjectPath(projectPath);
Shinya Kitaoka 120a6e
  TFilePath projectFolder = projectPath.getParentDir();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!TFileStatus(projectFolder).doesExist()) {
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      TSystem::mkDir(projectFolder);
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath sceneFolder    = decode(getFolder(TProject::Scenes));
Shinya Kitaoka 120a6e
  TFilePath scenesDescPath = sceneFolder + "scenes.xml";
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFileStatus fs(projectPath);
Shinya Kitaoka 120a6e
  if (fs.doesExist() && !fs.isWritable()) {
Shinya Kitaoka 120a6e
    throw TSystemException(
Shinya Kitaoka 120a6e
        projectPath,
Shinya Kitaoka 120a6e
        "Cannot save the project settings. The file is read-only.");
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TFileStatus fs2(scenesDescPath);
Shinya Kitaoka 120a6e
  if (fs2.doesExist() && !fs2.isWritable()) {
Shinya Kitaoka 120a6e
    throw TSystemException(
Shinya Kitaoka 120a6e
        projectPath,
Shinya Kitaoka 120a6e
        "Cannot save the project settings. The scenes file is read-only.");
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TOStream os(m_path);
Shinya Kitaoka 120a6e
  os.openChild("project");
Shinya Kitaoka 120a6e
  os.openChild("version");
Shinya Kitaoka 120a6e
  os << 70 << 1;    // Standard version signature:
Shinya Kitaoka 120a6e
  os.closeChild();  //   <major *="" 10="" number="" toonz="" version="">.</major>
Shinya Kitaoka 120a6e
                    //   advancement>
Shinya Kitaoka 120a6e
  os.openChild("folders");
Shinya Kitaoka 120a6e
  int i = 0;
Shinya Kitaoka 120a6e
  for (i = 0; i < getFolderCount(); i++) {
Shinya Kitaoka 120a6e
    TFilePath folderRelativePath = getFolder(i);
Shinya Kitaoka 120a6e
    if (folderRelativePath == TFilePath()) continue;
Shinya Kitaoka 120a6e
    std::map<std::string, string=""> attr;</std::string,>
Shinya Kitaoka 120a6e
    string folderName = getFolderName(i);
Shinya Kitaoka 120a6e
    attr["name"]      = folderName;
Shinya Kitaoka 120a6e
    attr["path"]      = ::to_string(folderRelativePath);  // escape()
Shinya Kitaoka 120a6e
    if (getUseScenePath(folderName)) attr["useScenePath"] = "yes";
Shinya Kitaoka 120a6e
    os.openCloseChild("folder", attr);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  os.closeChild();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  os.openChild("sceneProperties");
Shinya Kitaoka 120a6e
  getSceneProperties().saveData(os);
Shinya Kitaoka 120a6e
  os.closeChild();
Shinya Kitaoka 120a6e
  os.closeChild();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // crea (se necessario) le directory relative ai vari folder
Shinya Kitaoka 120a6e
  for (i = 0; i < getFolderCount(); i++)
Shinya Kitaoka 120a6e
    if (isConstantFolder(i)) {
Shinya Kitaoka 120a6e
      TFilePath fp = getFolder(i);
Shinya Kitaoka 120a6e
      if (fp == TFilePath()) continue;
Shinya Kitaoka 120a6e
      fp = decode(fp);
Shinya Kitaoka 120a6e
      // if(!fp.isAbsolute()) fp = projectFolder + fp;
Shinya Kitaoka 120a6e
      if (!TFileStatus(fp).doesExist()) {
Shinya Kitaoka 120a6e
        try {
Shinya Kitaoka 120a6e
          TSystem::mkDir(fp);
Shinya Kitaoka 120a6e
        } catch (...) {
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*-- +scenes だけでなく、全てのProject Folderにscenes.xmlを生成する --*/
Shinya Kitaoka 120a6e
  std::vector<std::string> foldernames;</std::string>
Shinya Kitaoka 120a6e
  pm->getFolderNames(foldernames);
Shinya Kitaoka 120a6e
  for (int f = 0; f < foldernames.size(); f++) {
Shinya Kitaoka 120a6e
    TFilePath folderpath = decode(getFolder(foldernames.at(f)));
Shinya Kitaoka 120a6e
    if (folderpath.isEmpty() || !isConstantFolder(f)) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFilePath xmlPath = folderpath + "scenes.xml";
Shinya Kitaoka 120a6e
    TFileStatus xmlfs(xmlPath);
Shinya Kitaoka 120a6e
    if (xmlfs.doesExist() && !xmlfs.isWritable()) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFilePath relativeProjectFolder =
Shinya Kitaoka 120a6e
        makeRelative(folderpath, m_path.getParentDir());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TOStream os2(xmlPath);
Shinya Kitaoka 120a6e
    std::map<std::string, string=""> attr;</std::string,>
Shinya Kitaoka 120a6e
    attr["type"] = "projectFolder";
Shinya Kitaoka 120a6e
    os2.openChild("parentProject", attr);
Shinya Kitaoka 120a6e
    os2 << relativeProjectFolder;
Shinya Kitaoka 120a6e
    os2.closeChild();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // The project has been successfully saved. In case there are other
Shinya Kitaoka 120a6e
  // project files from older Toonz project versions, those files are
Shinya Kitaoka 120a6e
  // renamed so that older Toonz versions can no longer 'see' it.
Shinya Kitaoka 120a6e
  if (!isFolderUnderVersionControl(projectFolder))
Shinya Kitaoka 120a6e
    hideOlderProjectFiles(projectFolder);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TProject::save() { return save(m_path); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Loads the project specified in \b projectPath.\n
Shinya Kitaoka 120a6e
        \b projectPath must be an absolute path.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void TProject::load(const TFilePath &projectPath) {
Shinya Kitaoka 120a6e
  assert(isAProjectPath(projectPath));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath latestProjectPath = getLatestVersionProjectPath(projectPath);
Shinya Kitaoka 120a6e
  TFilePath inputProjectPath  = searchProjectPath(projectPath.getParentDir());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TProjectManager *pm = TProjectManager::instance();
Shinya Kitaoka 120a6e
  m_name              = pm->projectPathToProjectName(latestProjectPath);
Shinya Kitaoka 120a6e
  m_path              = latestProjectPath;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_folderNames.clear();
Shinya Kitaoka 120a6e
  m_folders.clear();
Shinya Kitaoka 120a6e
  m_useScenePathFlags.clear();
Shinya Kitaoka 120a6e
  delete m_sprop;
Shinya Kitaoka 120a6e
  m_sprop = new TSceneProperties();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Read the project
Shinya Kitaoka 120a6e
  TIStream is(inputProjectPath);
Shinya Kitaoka 120a6e
  if (!is) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  string tagName;
Shinya Kitaoka 120a6e
  if (!is.matchTag(tagName) || tagName != "project") return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (is.matchTag(tagName)) {
Shinya Kitaoka 120a6e
    if (tagName == "folders") {
Shinya Kitaoka 120a6e
      while (is.matchTag(tagName)) {
Shinya Kitaoka 120a6e
        if (tagName == "folder") {
Shinya Kitaoka 120a6e
          string name = is.getTagAttribute("name");
Shinya Kitaoka 120a6e
          TFilePath path(is.getTagAttribute("path"));
Shinya Kitaoka 120a6e
          setFolder(name, path);
Shinya Kitaoka 120a6e
          string useScenePath = is.getTagAttribute("useScenePath");
Shinya Kitaoka 120a6e
          setUseScenePath(name, useScenePath == "yes");
Shinya Kitaoka 120a6e
        } else
Shinya Kitaoka 120a6e
          throw TException("expected <folder>");</folder>
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      is.matchEndTag();
Shinya Kitaoka 120a6e
    } else if (tagName == "version") {
Shinya Kitaoka 120a6e
      int major, minor;
Shinya Kitaoka 120a6e
      is >> major >> minor;
Shinya Kitaoka 120a6e
      is.setVersion(VersionNumber(major, minor));
Shinya Kitaoka 120a6e
      is.matchEndTag();
Shinya Kitaoka 120a6e
    } else if (tagName == "sceneProperties") {
Shinya Kitaoka 120a6e
      TSceneProperties sprop;
Shinya Kitaoka 120a6e
      try {
Shinya Kitaoka 120a6e
        sprop.loadData(is, true);
Shinya Kitaoka 120a6e
      } catch (...) {
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      setSceneProperties(sprop);
Shinya Kitaoka 120a6e
      is.matchEndTag();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns true if the specified path is a project path.\n
Shinya Kitaoka 120a6e
        A project path must be absolute, must be an xml file and must have the
Shinya Kitaoka 120a6e
   name of the
Shinya Kitaoka 120a6e
        parent root with either one of the version-dependent suffixes "_prj*".\n
Shinya Kitaoka 120a6e
        \code
Shinya Kitaoka 120a6e
        e.g. "C:\\Toonz 5.2 stuff\\projects\\prodA\\episode1\\episode1_prj.xml"
Shinya Kitaoka 120a6e
   is a project path.
Shinya Kitaoka 120a6e
        \endcode
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
bool TProject::isAProjectPath(const TFilePath &fp) {
Shinya Kitaoka 120a6e
  if (fp.isAbsolute() && fp.getType() == "xml") {
Shinya Kitaoka 120a6e
    const std::wstring &fpName     = fp.getWideName();
Shinya Kitaoka 120a6e
    const std::wstring &folderName = fp.getParentDir().getWideName();
Shinya Kitaoka 120a6e
    for (int i = 0; i < prjSuffixCount; ++i)
Shinya Kitaoka 120a6e
      if (fpName == (folderName + prjSuffix[i])) return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Shinya Kitaoka d1f6c4
class SimpleProject final : public TProject {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  SimpleProject() : TProject(TFilePath("___simpleProject")) {
Toshihiro Shimizu 890ddd
  }
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// TProjectManager
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \class TProjectManager tproject.h
Shinya Kitaoka 120a6e
        \brief Manages all toonz projects. The class provides all needed method
Shinya Kitaoka 120a6e
   to retrieve projects paths, names
Shinya Kitaoka 120a6e
        and folders.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        It is possible to handle more than one project root.
luzpaz 27707d
        The class maintains a container this purpose. All the projects roots must
luzpaz 27707d
   be set by hand in the windows
Shinya Kitaoka 120a6e
        registery. By default, only one project root is created when toonz is
Shinya Kitaoka 120a6e
   installed.\n
Shinya Kitaoka 120a6e
        The project root container can be updated using addProjectsRoot(const
Shinya Kitaoka 120a6e
   TFilePath &root), addDefaultProjectsRoot()
Shinya Kitaoka 120a6e
        methods.
Shinya Kitaoka 120a6e
luzpaz 27707d
        The class maintains also information about the current project. The class
Shinya Kitaoka 120a6e
   provides all needed method to retrieve
Shinya Kitaoka 120a6e
        the current project path, name and folder.
Shinya Kitaoka 120a6e
        \see TProject
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \fn bool TProjectManager::isTabModeEnabled() const
Shinya Kitaoka 120a6e
        Returns the tab mode.
Shinya Kitaoka 120a6e
        \note the tab mode is used for Tab Application
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \fn void TProjectManager::enableTabMode(bool tabMode)
Shinya Kitaoka 120a6e
        Set the tab mode to the passed \b tabMode.
Shinya Kitaoka 120a6e
        \note the tab mode is used for Tab Application
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TProjectManager::TProjectManager() : m_tabMode(false), m_tabKidsMode(false) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TProjectManager::~TProjectManager() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the instance to the TProjectManager.\n
Shinya Kitaoka 120a6e
        If an instance doesn't exist, creates one.*/
Shinya Kitaoka 120a6e
TProjectManager *TProjectManager::instance() {
Shinya Kitaoka 120a6e
  static TProjectManager _instance;
Shinya Kitaoka 120a6e
  return &_instance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Shinya Kitaoka 120a6e
/*! Adds the specified folder \b fp in the projecs roots container.\n
Shinya Kitaoka 120a6e
        If \b fp is already contained in the container, the method does nothing.
Shinya Kitaoka 120a6e
        \note \b fp must be a folder and not a file path.*/
Shinya Kitaoka 120a6e
void TProjectManager::addProjectsRoot(const TFilePath &root) {
Shinya Kitaoka 120a6e
  // assert(TFileStatus(root).isDirectory());
Shinya Kitaoka 120a6e
  if (std::find(m_projectsRoots.begin(), m_projectsRoots.end(), root) ==
Shinya Kitaoka 120a6e
      m_projectsRoots.end())
Shinya Kitaoka 120a6e
    m_projectsRoots.push_back(root);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
/*! Adds the specified folder \b fp in the version control projecs roots
Shinya Kitaoka 120a6e
   container.\n
Shinya Kitaoka 120a6e
        If \b fp is already contained in the container, the method does nothing.
Shinya Kitaoka 120a6e
        \note \b fp must be a folder and not a file path.*/
Shinya Kitaoka 120a6e
void TProjectManager::addSVNProjectsRoot(const TFilePath &root) {
Shinya Kitaoka 120a6e
  assert(TFileStatus(root).isDirectory());
Shinya Kitaoka 120a6e
  if (std::find(m_svnProjectsRoots.begin(), m_svnProjectsRoots.end(), root) ==
Shinya Kitaoka 120a6e
      m_svnProjectsRoots.end())
Shinya Kitaoka 120a6e
    m_svnProjectsRoots.push_back(root);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TProjectManager::addDefaultProjectsRoot() {
Shinya Kitaoka 120a6e
  addProjectsRoot(TEnv::getStuffDir() + "projects");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath TProjectManager::getCurrentProjectRoot() {
Shinya Kitaoka 120a6e
  TFilePath currentProjectPath = getCurrentProjectPath();
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_projectsRoots.size(); i++)
Shinya Kitaoka 120a6e
    if (m_projectsRoots[i].isAncestorOf(currentProjectPath))
Shinya Kitaoka 120a6e
      return m_projectsRoots[i];
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_svnProjectsRoots.size(); i++)
Shinya Kitaoka 120a6e
    if (m_svnProjectsRoots[i].isAncestorOf(currentProjectPath))
Shinya Kitaoka 120a6e
      return m_svnProjectsRoots[i];
Shinya Kitaoka 120a6e
  if (m_projectsRoots.empty())
Shinya Kitaoka 120a6e
    addDefaultProjectsRoot();  // shouldn't be necessary
Shinya Kitaoka 120a6e
  return m_projectsRoots[0];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the name of the specified \b projectPath.
Shinya Kitaoka 120a6e
        \note projectPath must be an absolute path.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TFilePath TProjectManager::projectPathToProjectName(
Shinya Kitaoka 120a6e
    const TFilePath &projectPath) {
Shinya Kitaoka 120a6e
  assert(projectPath.isAbsolute());
Shinya Kitaoka 120a6e
  TFilePath projectFolder = projectPath.getParentDir();
Shinya Kitaoka 120a6e
  if (m_projectsRoots.empty()) addDefaultProjectsRoot();
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_projectsRoots.size(); i++) {
Shinya Kitaoka 120a6e
    if (m_projectsRoots[i].isAncestorOf(projectFolder))
Shinya Kitaoka 120a6e
      return projectFolder - m_projectsRoots[i];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_svnProjectsRoots.size(); i++) {
Shinya Kitaoka 120a6e
    if (m_svnProjectsRoots[i].isAncestorOf(projectFolder))
Shinya Kitaoka 120a6e
      return projectFolder - m_svnProjectsRoots[i];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // non dovrei mai arrivare qui: il progetto non sta sotto un project root
Shinya Kitaoka 120a6e
  return projectFolder.withoutParentDir();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns an absolute path of the specified \b projectName.\n
luzpaz 27707d
        \note The returned project path is always computed used the first
Shinya Kitaoka 120a6e
   project root in the container.*/
Shinya Kitaoka 120a6e
TFilePath TProjectManager::projectNameToProjectPath(
Shinya Kitaoka 120a6e
    const TFilePath &projectName) {
Shinya Kitaoka 120a6e
  assert(!TProject::isAProjectPath(projectName));
Shinya Kitaoka 120a6e
  assert(!projectName.isAbsolute());
Shinya Kitaoka 120a6e
  if (m_projectsRoots.empty()) addDefaultProjectsRoot();
Shinya Kitaoka 120a6e
  if (projectName == TProject::SandboxProjectName)
Shinya Kitaoka 120a6e
    return searchProjectPath(TEnv::getStuffDir() + projectName);
Shinya Kitaoka 120a6e
  return searchProjectPath(m_projectsRoots[0] + projectName);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Shinya Kitaoka 120a6e
/*! Returns the absolute path of the project file respect to the specified \b
Shinya Kitaoka 120a6e
   projectFolder.\n
Shinya Kitaoka 120a6e
        \note \b projectName must be an absolute path.*/
Shinya Kitaoka 120a6e
TFilePath TProjectManager::projectFolderToProjectPath(
Shinya Kitaoka 120a6e
    const TFilePath &projectFolder) {
Shinya Kitaoka 120a6e
  assert(projectFolder.isAbsolute());
Shinya Kitaoka 120a6e
  return searchProjectPath(projectFolder);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Shinya Kitaoka 120a6e
/*! Returns the absolute path of the specified \b projectName only if the
Shinya Kitaoka 120a6e
   project already exist.\n
Shinya Kitaoka 120a6e
        Returns TFilePath() if a project with the specified \b projectName
luzpaz 27707d
   doesn't exist.\n
Shinya Kitaoka 120a6e
        \note \b projectName must be a relative path.*/
Shinya Kitaoka 120a6e
TFilePath TProjectManager::getProjectPathByName(const TFilePath &projectName) {
Shinya Kitaoka 120a6e
  assert(!TProject::isAProjectPath(projectName));
Shinya Kitaoka 120a6e
  assert(!projectName.isAbsolute());
Shinya Kitaoka 120a6e
  // TFilePath relativeProjectPath = projectName + (projectName.getName() +
Shinya Kitaoka 120a6e
  // projectPathSuffix);
Shinya Kitaoka 120a6e
  if (m_projectsRoots.empty()) addDefaultProjectsRoot();
Shinya Kitaoka 120a6e
  if (projectName == TProject::SandboxProjectName)
Shinya Kitaoka 120a6e
    return searchProjectPath(TEnv::getStuffDir() + projectName);
Shinya Kitaoka 120a6e
  int i, n = (int)m_projectsRoots.size();
Shinya Kitaoka 120a6e
  for (i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
    TFilePath projectPath = searchProjectPath(m_projectsRoots[i] + projectName);
Shinya Kitaoka 120a6e
    assert(TProject::isAProjectPath(projectPath));
Shinya Kitaoka 120a6e
    if (TFileStatus(projectPath).doesExist()) return projectPath;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_svnProjectsRoots.size(); i++) {
Shinya Kitaoka 120a6e
    TFilePath projectPath =
Shinya Kitaoka 120a6e
        searchProjectPath(m_svnProjectsRoots[i] + projectName);
Shinya Kitaoka 120a6e
    assert(TProject::isAProjectPath(projectPath));
Shinya Kitaoka 120a6e
    if (TFileStatus(projectPath).doesExist()) return projectPath;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return TFilePath();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Gets all project folder names and put them in the passed vector \b names.
Shinya Kitaoka 120a6e
        \note All previous data contained in \b names are lost.*/
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void TProjectManager::getFolderNames(std::vector<std::string> &names) {</std::string>
Shinya Kitaoka 120a6e
  names.clear();
Shinya Kitaoka 120a6e
  TFilePath fp = ToonzFolder::getProfileFolder() + "project_folders.txt";
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    Tifstream is(fp);
Shinya Kitaoka 120a6e
    if (is)
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        char buffer[1024];
Shinya Kitaoka 120a6e
        is.getline(buffer, sizeof(buffer));
Shinya Kitaoka 120a6e
        if (is.eof()) break;
Shinya Kitaoka 120a6e
        char *s = buffer;
Shinya Kitaoka 120a6e
        while (*s == ' ' || *s == '\t') s++;  // skips blanks
Shinya Kitaoka 120a6e
        char *t = s;
Shinya Kitaoka 120a6e
        while (*t && *t != '\r' && *t != '\n') t++;  // reads up to end of line
Shinya Kitaoka 120a6e
        while (t > s && (t[-1] == ' ' || t[-1] == '\t'))
Shinya Kitaoka 120a6e
          t--;  // remove trailing blanks
Shinya Kitaoka 120a6e
        t[0] = '\0';
Shinya Kitaoka 120a6e
        if (s[0]) names.push_back(string(s));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  const std::string stdNames[] = {TProject::Inputs,  TProject::Drawings,
Shinya Kitaoka 120a6e
                                  TProject::Scenes,  TProject::Extras,
Shinya Kitaoka 120a6e
                                  TProject::Outputs, TProject::Scripts};
Tact Yoshida 1d7cf9
  for (auto const &name : stdNames) {
Shinya Kitaoka 120a6e
    // se il nome non e' gia' stato inserito lo aggiungo
Shinya Kitaoka 120a6e
    if (std::find(names.begin(), names.end(), name) == names.end())
Shinya Kitaoka 120a6e
      names.push_back(name);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Set the the path \b fp as current project path.\n
Shinya Kitaoka 120a6e
        \b fp must be an absolute path.*/
Shinya Kitaoka 120a6e
void TProjectManager::setCurrentProjectPath(const TFilePath &fp) {
Shinya Kitaoka 120a6e
  assert(TProject::isAProjectPath(fp));
Shinya Kitaoka 120a6e
  currentProjectPath = ::to_string(fp.getWideString());
Shinya Kitaoka 120a6e
  currentProject     = TProjectP();
Shinya Kitaoka 120a6e
  notifyListeners();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the current project path.\n
luzpaz 27707d
        The project path, usually, is set in key registry. If a current
luzpaz 27707d
   project path isn't set,
luzpaz 27707d
        TProject::SandboxProjectName is set as current project.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TFilePath TProjectManager::getCurrentProjectPath() {
Shinya Kitaoka 120a6e
  TFilePath fp(currentProjectPath);
Shinya Kitaoka 120a6e
  if (fp == TFilePath())
Shinya Kitaoka 120a6e
    fp = projectNameToProjectPath(TProject::SandboxProjectName);
Shinya Kitaoka 120a6e
  if (!TProject::isAProjectPath(fp)) {
Shinya Kitaoka 120a6e
    // in Toonz 5.1 e precedenti era un project name
Shinya Kitaoka 120a6e
    if (!fp.isAbsolute()) fp = getProjectPathByName(fp);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  fp = searchProjectPath(fp.getParentDir());
Shinya Kitaoka 120a6e
  if (!TFileStatus(fp).doesExist())
shun-iwasawa fe2893
    fp = projectNameToProjectPath(TProject::SandboxProjectName);
Shinya Kitaoka 120a6e
  fp       = getLatestVersionProjectPath(fp);
Shinya Kitaoka 120a6e
  string s = ::to_string(fp);
Shinya Kitaoka 120a6e
  if (s != (string)currentProjectPath) currentProjectPath = s;
Shinya Kitaoka 120a6e
  return fp;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the current TProject.\n
Shinya Kitaoka 120a6e
        If a current TProject() doesn't exist, load the project in the the
Shinya Kitaoka 120a6e
   current project path.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TProjectP TProjectManager::getCurrentProject() {
Shinya Kitaoka 120a6e
  if (currentProject.getPointer() == 0) {
Shinya Kitaoka 120a6e
    TFilePath fp = getCurrentProjectPath();
Shinya Kitaoka 120a6e
    assert(TProject::isAProjectPath(fp));
Shinya Kitaoka 120a6e
    currentProject = new TProject();
Shinya Kitaoka 120a6e
    currentProject->load(fp);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return currentProject;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Returns the TProjectP in which the specified \b scenePath is saved.\n
Shinya Kitaoka 120a6e
        Returns 0 if \b scenePath isn't a valid scene, or isn't saved in a valid
Shinya Kitaoka 120a6e
   folder of a project root.
Shinya Kitaoka 120a6e
        \note \b scenePath must be an absolute path.\n
Shinya Kitaoka 120a6e
        Creates a new TProject. The caller gets ownership.*/
Shinya Kitaoka 120a6e
TProjectP TProjectManager::loadSceneProject(const TFilePath &scenePath) {
Shinya Kitaoka 120a6e
  // cerca il file scenes.xml nella stessa directory della scena
Shinya Kitaoka 120a6e
  // oppure in una
Shinya Kitaoka 120a6e
  // directory superiore
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath folder = scenePath.getParentDir();
Shinya Kitaoka 120a6e
  TFilePath sceneDesc;
Shinya Kitaoka 120a6e
  bool found = true;
Shinya Kitaoka 120a6e
  for (;;) {
Shinya Kitaoka 120a6e
    sceneDesc = folder + "scenes.xml";
Shinya Kitaoka 120a6e
    if (TFileStatus(sceneDesc).doesExist()) break;
Shinya Kitaoka 120a6e
    if (folder.isRoot()) {
Shinya Kitaoka 120a6e
      found = false;
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    folder = folder.getParentDir();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // legge il path (o il nome) del progetto
Shinya Kitaoka 120a6e
  TFilePath projectPath;
Shinya Kitaoka 120a6e
  if (found) {
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      TIStream is(sceneDesc);
Shinya Kitaoka 120a6e
      string tagName;
Shinya Kitaoka 120a6e
      is.matchTag(tagName);
Shinya Kitaoka 120a6e
      string type = is.getTagAttribute("type");
Shinya Kitaoka 120a6e
      TFilePath projectFolderPath;
Shinya Kitaoka 120a6e
      is >> projectFolderPath;
Shinya Kitaoka 120a6e
      if (type == "") {
Shinya Kitaoka 120a6e
        projectFolderPath = TFilePath("..");
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      is.matchEndTag();
Shinya Kitaoka 120a6e
      projectPath = makeAbsolute(folder, projectFolderPath);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TFilePath path;
Shinya Kitaoka 120a6e
      for (int i = 0; i < prjSuffixCount; ++i) {
Shinya Kitaoka 120a6e
        path =
Shinya Kitaoka 120a6e
            projectPath + (projectPath.getWideName() + prjSuffix[i] + xmlExt);
Shinya Kitaoka 120a6e
        if (TFileStatus(path).doesExist()) break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      projectPath = path;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (projectPath == TFilePath()) return 0;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    projectPath = getSandboxProjectPath();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!TProject::isAProjectPath(projectPath)) {
Shinya Kitaoka 120a6e
    // in Toonz 5.1 e precedenti era un project name
Shinya Kitaoka 120a6e
    if (!projectPath.isAbsolute())
Shinya Kitaoka 120a6e
      projectPath = getProjectPathByName(projectPath);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!TFileStatus(projectPath).doesExist()) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TProject *project = new TProject();
Shinya Kitaoka 120a6e
  project->load(projectPath);
Shinya Kitaoka 120a6e
  return project;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TProjectManager::notifyListeners() {
Shinya Kitaoka 120a6e
  for (std::set<listener *="">::iterator i = m_listeners.begin();</listener>
Shinya Kitaoka 120a6e
       i != m_listeners.end(); ++i)
Shinya Kitaoka 120a6e
    (*i)->onProjectSwitched();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TProjectManager::notifyProjectChanged() {
Shinya Kitaoka 120a6e
  for (std::set<listener *="">::iterator i = m_listeners.begin();</listener>
Shinya Kitaoka 120a6e
       i != m_listeners.end(); ++i)
Shinya Kitaoka 120a6e
    (*i)->onProjectChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
luzpaz 27707d
/*! Adds \b listener to the listeners container.*/
Shinya Kitaoka 120a6e
void TProjectManager::addListener(Listener *listener) {
Shinya Kitaoka 120a6e
  m_listeners.insert(listener);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
luzpaz 27707d
/*! Removes \b listener from the listeners container.*/
Shinya Kitaoka 120a6e
void TProjectManager::removeListener(Listener *listener) {
Shinya Kitaoka 120a6e
  m_listeners.erase(listener);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Shinya Kitaoka 120a6e
/*! Initializes the specified \b scene using the TSceneProperties of the current
Shinya Kitaoka 120a6e
   project.\n
Shinya Kitaoka 120a6e
        \see TSceneProperties
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void TProjectManager::initializeScene(ToonzScene *scene) {
Shinya Kitaoka 120a6e
  TProject *project       = scene->getProject();
Shinya Kitaoka 120a6e
  TSceneProperties *sprop = scene->getProperties();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath currentProjectPath = getCurrentProjectPath();
Shinya Kitaoka 120a6e
  project->load(currentProjectPath);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  sprop->assign(&project->getSceneProperties());
Shinya Kitaoka 120a6e
  CleanupParameters::GlobalParameters.assign(
Shinya Kitaoka 120a6e
      project->getSceneProperties().getCleanupParameters());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // scene->setProject(this);
Shinya Kitaoka 120a6e
  scene->setUntitled();
Shinya Kitaoka 120a6e
  sprop->cloneCamerasTo(scene->getTopXsheet()->getStageObjectTree());
Shinya Kitaoka 120a6e
  sprop->onInitialize();
Shinya Kitaoka 120a6e
  // scene->save(scene->getScenePath());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Saves the TSceneProperties of the specified scene in the current project.*/
Shinya Kitaoka 120a6e
void TProjectManager::saveTemplate(ToonzScene *scene) {
Shinya Kitaoka 120a6e
  TSceneProperties props;
Shinya Kitaoka 120a6e
  props.assign(scene->getProperties());
Shinya Kitaoka 120a6e
  props.cloneCamerasFrom(scene->getXsheet()->getStageObjectTree());
Shinya Kitaoka 120a6e
shun-iwasawa 3f818e
  // camera capture's "save in" path is saved in env, not in the project
shun-iwasawa 3f818e
  props.setCameraCaptureSaveInPath(TFilePath());
shun-iwasawa 3f818e
Shinya Kitaoka 120a6e
  TProjectP currentProject = getCurrentProject();
Shinya Kitaoka 120a6e
  currentProject->setSceneProperties(props);
Shinya Kitaoka 120a6e
  currentProject->save();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Creates the standard project folder "sandbox" if it doesn't exist.*/
Shinya Kitaoka 120a6e
void TProjectManager::createSandboxIfNeeded() {
Shinya Kitaoka 120a6e
  TFilePath path = getSandboxProjectPath();
Shinya Kitaoka 120a6e
  if (!TFileStatus(path).doesExist()) {
Shinya Kitaoka 120a6e
    TProjectP project = createStandardProject();
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      project->save(path);
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Create a standard project.\n
Shinya Kitaoka 120a6e
        A standard project is a project containing the standard named and
Shinya Kitaoka 120a6e
   constant folder.
Shinya Kitaoka 120a6e
        \see TProject. */
Shinya Kitaoka 120a6e
TProjectP TProjectManager::createStandardProject() {
Shinya Kitaoka 120a6e
  TProject *project = new TProject();
Shinya Kitaoka 120a6e
  // set default folders (+drawings, ecc.)
Shinya Kitaoka 120a6e
  std::vector<std::string> names;</std::string>
Shinya Kitaoka 120a6e
  getFolderNames(names);
Shinya Kitaoka 120a6e
  std::vector<std::string>::iterator it;</std::string>
Shinya Kitaoka 120a6e
  for (it = names.begin(); it != names.end(); ++it) project->setFolder(*it);
Shinya Kitaoka 120a6e
  return project;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Return the absolute path of the standard folder "sandbox".
Shinya Kitaoka 120a6e
TFilePath TProjectManager::getSandboxProjectFolder() {
Shinya Kitaoka 120a6e
  return getSandboxProjectPath().getParentDir();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//! Return the absolute path of the standard project "sandbox_prj6.xml" file.
Shinya Kitaoka 120a6e
TFilePath TProjectManager::getSandboxProjectPath() {
Shinya Kitaoka 120a6e
  return getProjectPathByName(TProject::SandboxProjectName);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TProjectManager::isProject(const TFilePath &projectFolder) {
Shinya Kitaoka 120a6e
  TFilePath projectPath = projectFolderToProjectPath(projectFolder);
Shinya Kitaoka 120a6e
  return TFileStatus(projectPath).doesExist();
Toshihiro Shimizu 890ddd
}