Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "iocommand.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Tnz6 includes
Toshihiro Shimizu 890ddd
#include "tapp.h"
Toshihiro Shimizu 890ddd
#include "menubarcommandids.h"
Toshihiro Shimizu 890ddd
#include "loadfolderpopup.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/dvdialog.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/gutil.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/validatedchoicedialog.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/menubarcommand.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tscenehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tfiletype.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qcoreapplication></qcoreapplication>
Toshihiro Shimizu 890ddd
#include <qdir></qdir>
Toshihiro Shimizu 890ddd
#include <qfileinfo></qfileinfo>
Toshihiro Shimizu 890ddd
#include <qregexp></qregexp>
Toshihiro Shimizu 890ddd
#include <qbuttongroup></qbuttongroup>
Toshihiro Shimizu 890ddd
#include <qradiobutton></qradiobutton>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// boost includes
Toshihiro Shimizu 890ddd
#include <boost optional.hpp=""></boost>
Toshihiro Shimizu 890ddd
#include <boost operators.hpp=""></boost>
Toshihiro Shimizu 890ddd
#include <boost range.hpp=""></boost>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <boost iterator="" transform_iterator.hpp=""></boost>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <boost algorithm="" for_each.hpp="" range=""></boost>
Toshihiro Shimizu 890ddd
#include <boost algorithm="" copy.hpp="" range=""></boost>
Toshihiro Shimizu 890ddd
#include <boost adaptor="" filtered.hpp="" range=""></boost>
Toshihiro Shimizu 890ddd
#include <boost adaptor="" adjacent_filtered.hpp="" range=""></boost>
Toshihiro Shimizu 890ddd
#include <boost adaptor="" range="" transformed.hpp=""></boost>
Toshihiro Shimizu 890ddd
kusano 66e8e3
#include <boost in_place_factory.hpp="" utility=""></boost>
kusano 66e8e3
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <set></set>
Tact Yoshida da287b
#include <algorithm></algorithm>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace  structures
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef IoCmd::LoadResourceArguments LRArgs;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef TFilePath (*PathFunc)(const TFilePath &);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct FormatData {
Shinya Kitaoka 120a6e
  QRegExp m_regExp;
Shinya Kitaoka 120a6e
  PathFunc m_resourcePathFunc, m_componentPathFunc;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    ResourceData  definition
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
struct Resource  //!  A single resource to be loaded.
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
  struct Path : private boost::less_than_comparable<path>  //!  Path locating a</path>
Shinya Kitaoka 120a6e
                                                           //!  resource.
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TFilePath m_rootFp,  //!< Selected root folder hosting the resource.
Shinya Kitaoka 120a6e
        m_relFp;         //!< Path representing the resource, \a relative
Shinya Kitaoka 120a6e
                         //!  to \p m_rootFolder.
Shinya Kitaoka 120a6e
  public:
Shinya Kitaoka 120a6e
    Path(const TFilePath &rootPath, const TFilePath &relativeFilePath)
Shinya Kitaoka 120a6e
        : m_rootFp(rootPath), m_relFp(relativeFilePath) {
Shinya Kitaoka 120a6e
      assert(m_rootFp.isAbsolute());
Shinya Kitaoka 120a6e
      assert(!m_relFp.isAbsolute());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFilePath absoluteResourcePath() const { return m_rootFp + m_relFp; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool operator<(const Path &other) const {
Shinya Kitaoka 120a6e
      return (m_rootFp < other.m_rootFp ||
Shinya Kitaoka 120a6e
              (!(other.m_relFp < m_relFp) && m_relFp < other.m_relFp));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  struct Component {
Shinya Kitaoka 120a6e
    TFilePath m_srcFp;    //!< Source path, relative to parent folder.
Shinya Kitaoka 120a6e
    PathFunc m_pathFunc;  //!< Possible callback function transforming source
Shinya Kitaoka 120a6e
                          //!  paths into their imported counterparts.
Shinya Kitaoka 120a6e
  public:
Shinya Kitaoka 120a6e
    Component(const TFilePath &srcPath, PathFunc pathFunc)
Shinya Kitaoka 120a6e
        : m_srcFp(srcPath), m_pathFunc(pathFunc) {
Shinya Kitaoka 120a6e
      assert(m_srcFp.getParentDir() == TFilePath());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  typedef std::vector<component> CompSeq;</component>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  Path m_path;           //!< The level path.
Shinya Kitaoka 120a6e
  CompSeq m_components;  //!< File Paths for level components. The first path
Shinya Kitaoka 120a6e
                         //!  is intended as the resource's file representant.
Shinya Kitaoka 120a6e
  boost::optional<leveloptions></leveloptions>
Shinya Kitaoka 120a6e
      m_levelOptions;  //!< Level Options to be loaded for a level resource.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  Resource(const Path &path) : m_path(path) {}
Shinya Kitaoka 120a6e
  Resource(const TFilePath &rootPath, const TFilePath &relativeFilePath)
Shinya Kitaoka 120a6e
      : m_path(rootPath, relativeFilePath) {}
Shinya Kitaoka 120a6e
  Resource(const Path &path, const CompSeq &components)
Shinya Kitaoka 120a6e
      : m_path(path), m_components(components) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    OverwriteDialog  definition
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class OverwriteDialog final : public DVGui::ValidatedChoiceDialog {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  enum Resolution {
Shinya Kitaoka 120a6e
    NO_RESOLUTION,
Shinya Kitaoka 120a6e
    CANCEL,
Shinya Kitaoka 120a6e
    OVERWRITE,
Shinya Kitaoka 120a6e
    SKIP,
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  struct Obj {
Shinya Kitaoka 120a6e
    const TFilePath &m_dstDir;
Shinya Kitaoka 120a6e
    Resource &m_rsrc;
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  OverwriteDialog(QWidget *parent);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString acceptResolution(void *obj, int resolution, bool applyToAll) override;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace  functions
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath relativePath(const TFilePath &from, const TFilePath &to) {
Shinya Kitaoka 120a6e
  return TFilePath(QDir(from.getQString()).relativeFilePath(to.getQString()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isLoadable(const TFilePath &resourcePath) {
Shinya Kitaoka 120a6e
  TFileType::Type type = TFileType::getInfo(resourcePath);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return (type & TFileType::IMAGE || type & TFileType::LEVEL);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename regstruct=""></typename>
Shinya Kitaoka 120a6e
bool exactMatch(const RegStruct ®Struct, const TFilePath &fp) {
Shinya Kitaoka 120a6e
  return regStruct.m_regExp.exactMatch(fp.getQString());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath multiframeResourcePath(const TFilePath &fp) {
Shinya Kitaoka 120a6e
  return fp.withFrame(TFrameId::EMPTY_FRAME);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath retasComponentPath(const TFilePath &fp) {
Shinya Kitaoka 120a6e
  std::wstring name = fp.getWideName();
Toshihiro Shimizu 890ddd
manongjohn 663b2a
  // Assumes the name is Axxxx.tga and needs to be changed to A.xxxx.tga
manongjohn 663b2a
  if (name.size() > 4 && fp.getDots() != "..")
manongjohn 663b2a
    name.insert(name.size() - 4, 1, L'.');
manongjohn 663b2a
Shinya Kitaoka 120a6e
  return fp.withName(name);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath retasResourcePath(const TFilePath &fp) {
Shinya Kitaoka 120a6e
  return retasComponentPath(fp).withFrame(TFrameId::EMPTY_FRAME);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static const FormatData l_formatDatas[] = {
Shinya Kitaoka 120a6e
    {QRegExp(".+\\.[0-9]{4,4}.*\\..*"), &multiframeResourcePath, 0},
Shinya Kitaoka 120a6e
    {QRegExp(".+[0-9]{4,4}\\.tga", Qt::CaseInsensitive), &retasResourcePath,
Shinya Kitaoka 120a6e
     &retasComponentPath}};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef std::pair<resource::path, int=""> RsrcKey;</resource::path,>
Toshihiro Shimizu 890ddd
typedef std::map<rsrckey, resource::compseq=""> RsrcMap;</rsrckey,>
Toshihiro Shimizu 890ddd
otakuto 91a93e
auto const differentPath = [](const RsrcMap::value_type &a,
otakuto 91a93e
                              const RsrcMap::value_type &b) -> bool {
Shinya Kitaoka 120a6e
  return (a.first.first < b.first.first) || (b.first.first < a.first.first);
otakuto 91a93e
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct buildResources_locals {
Shinya Kitaoka 120a6e
  static bool isValid(const RsrcMap::value_type &rsrcVal) {
Shinya Kitaoka 120a6e
    return (isLoadable(rsrcVal.first.first.m_relFp) && !rsrcVal.second.empty());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static Resource toResource(const RsrcMap::value_type &rsrcVal) {
Shinya Kitaoka 120a6e
    return Resource(rsrcVal.first.first, rsrcVal.second);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  struct MergeData {
Shinya Kitaoka 120a6e
    QRegExp m_regExp;    //!< Path regexp for file pattern recognition.
Shinya Kitaoka 120a6e
    int m_componentIdx;  //!< Starting index for components merging.
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static void mergeInto(RsrcMap::iterator &rt, RsrcMap &rsrcMap) {
Shinya Kitaoka 120a6e
    // NOTE: This algorithm works for 1-level-deep inclusions. I guess this is
Shinya Kitaoka 120a6e
    // sufficient,
Shinya Kitaoka 120a6e
    //       for now.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static const std::string componentsTable[] = {"cln", "tpl", "hst"};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static const MergeData mergeTable[] = {
Shinya Kitaoka 120a6e
        {QRegExp(".*\\.\\..*"), 0}, {QRegExp(".*\\.tlv"), 1}, {QRegExp(), 3}};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Lookup rd's path in the mergeTable
Shinya Kitaoka 120a6e
    const MergeData *mdt,
Shinya Kitaoka 120a6e
        *mdEnd = mergeTable + boost::size(mergeTable) - 1;  // Last item is fake
Shinya Kitaoka 120a6e
otakuto 3bf772
    mdt = std::find_if(mergeTable, mdEnd, [&rt](const MergeData& mergeData){ return exactMatch(mergeData, rt->first.first.m_relFp); });
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (mdt != mdEnd) {
Shinya Kitaoka 120a6e
      // Lookup every possible resource component to merge
Shinya Kitaoka 120a6e
      const std::string *cBegin = componentsTable + mdt->m_componentIdx,
Shinya Kitaoka 120a6e
                        *cEnd   = componentsTable + (mdt + 1)->m_componentIdx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (const std::string *ct = cBegin; ct != cEnd; ++ct) {
Shinya Kitaoka 120a6e
        RsrcKey childKey(
Shinya Kitaoka 120a6e
            Resource::Path(rt->first.first.m_rootFp,
Shinya Kitaoka 120a6e
                           rt->first.first.m_relFp.withNoFrame().withType(*ct)),
Shinya Kitaoka 120a6e
            rt->first.second);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        RsrcMap::iterator chrt = rsrcMap.find(childKey);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (chrt != rsrcMap.end()) {
Shinya Kitaoka 120a6e
          // Move every component into rsrc
Shinya Kitaoka 120a6e
          rt->second.insert(rt->second.end(), chrt->second.begin(),
Shinya Kitaoka 120a6e
                            chrt->second.end());
Shinya Kitaoka 120a6e
          chrt->second.clear();
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static void assignLevelOptions(Resource &rsrc) {
Shinya Kitaoka 120a6e
    assert(!rsrc.m_components.empty());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const Preferences &prefs = *Preferences::instance();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Match level format against the level's *file representant*
Shinya Kitaoka 120a6e
    int formatIdx = prefs.matchLevelFormat(rsrc.m_components.front().m_srcFp);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (formatIdx >= 0)
Shinya Kitaoka 120a6e
      rsrc.m_levelOptions = prefs.levelFormat(formatIdx).m_options;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
};  // buildResources_locals
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void buildResources(std::vector<resource> &resources, const TFilePath &rootPath,</resource>
Shinya Kitaoka 120a6e
                    const TFilePath &subPath = TFilePath()) {
Shinya Kitaoka 120a6e
  typedef buildResources_locals locals;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TFilePath &folderPath = rootPath + subPath;
Shinya Kitaoka 120a6e
  assert(QFileInfo(folderPath.getQString()).isDir());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Extract loadable levels in the folder
Shinya Kitaoka 120a6e
  QDir folderDir(folderPath.getQString());
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    const QStringList &files =
Shinya Kitaoka 120a6e
        folderDir.entryList(QDir::Files);  // Files only first
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Store every possible resource path
Shinya Kitaoka 120a6e
    RsrcMap rsrcMap;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QStringList::const_iterator ft, fEnd = files.end();
Shinya Kitaoka 120a6e
    for (ft = files.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
      const TFilePath &compPath = TFilePath(*ft);  // Relative to folderPath
Shinya Kitaoka 120a6e
      PathFunc componentFunc    = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TFilePath relPath = relativePath(rootPath, folderPath + compPath);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      const FormatData *fdt,
Shinya Kitaoka 120a6e
          *fdEnd = l_formatDatas + boost::size(l_formatDatas);
Shinya Kitaoka 120a6e
      fdt        = std::find_if(
otakuto 3bf772
          l_formatDatas, fdEnd, [&relPath](const FormatData &formatData){ return exactMatch(formatData, relPath); });
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (fdt != fdEnd) {
Shinya Kitaoka 120a6e
        relPath       = fdt->m_resourcePathFunc(relPath);
Shinya Kitaoka 120a6e
        componentFunc = fdt->m_componentPathFunc;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      assert(!relPath.isEmpty());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      RsrcKey rsrcKey(Resource::Path(rootPath, relPath),
Shinya Kitaoka 120a6e
                      int(fdt - l_formatDatas));
Shinya Kitaoka 120a6e
      rsrcMap[rsrcKey].push_back(Resource::Component(compPath, componentFunc));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Further let found resources merge with others they recognize as
Shinya Kitaoka 120a6e
    // 'children'
Shinya Kitaoka 120a6e
    RsrcMap::iterator rt, rEnd = rsrcMap.end();
Shinya Kitaoka 120a6e
    for (rt = rsrcMap.begin(); rt != rEnd; ++rt) locals::mergeInto(rt, rsrcMap);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Export valid data into the output resources collection
otakuto 91a93e
    boost::copy(rsrcMap | boost::adaptors::filtered(locals::isValid) |
otakuto 91a93e
                    boost::adaptors::adjacent_filtered(
otakuto 91a93e
                        differentPath)  // E.g. A.xxxx.tga and Axxxx.tga
otakuto 91a93e
                    | boost::adaptors::transformed(locals::toResource),
otakuto 91a93e
                std::back_inserter(resources));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Look for level options associated to each level
Shinya Kitaoka 120a6e
  std::for_each(resources.begin(), resources.end(), locals::assignLevelOptions);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Recursive on sub-folders
Shinya Kitaoka 120a6e
  const QStringList &dirs =
Shinya Kitaoka 120a6e
      folderDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QStringList::const_iterator dt, dEnd = dirs.end();
Shinya Kitaoka 120a6e
  for (dt = dirs.begin(); dt != dEnd; ++dt)
Shinya Kitaoka 120a6e
    buildResources(resources, rootPath, subPath + TFilePath(*dt));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath dstPath(const TFilePath &dstDir, const Resource::Component &comp) {
Shinya Kitaoka 120a6e
  return dstDir +
Shinya Kitaoka 120a6e
         (comp.m_pathFunc ? comp.m_pathFunc(comp.m_srcFp) : comp.m_srcFp);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct import_Locals {
Shinya Kitaoka 120a6e
  const ToonzScene &m_scene;
Shinya Kitaoka 2a7129
  std::unique_ptr<overwritedialog> m_overwriteDialog;</overwritedialog>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void switchToDst(Resource::Path &path) {
Shinya Kitaoka 120a6e
    path.m_rootFp = m_scene.decodeFilePath(
Shinya Kitaoka 120a6e
        m_scene.getImportedLevelPath(path.absoluteResourcePath())
Shinya Kitaoka 120a6e
            .getParentDir()            // E.g. +drawings/
Shinya Kitaoka 120a6e
        + path.m_rootFp.getWideName()  // Root dir name
manongjohn 663b2a
        );
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static void copy(const TFilePath &srcDir, const TFilePath &dstDir,
Shinya Kitaoka 120a6e
                   const Resource::Component &comp, bool overwrite) {
Shinya Kitaoka 120a6e
    TSystem::copyFile(dstPath(dstDir, comp), srcDir + comp.m_srcFp, overwrite);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void import(Resource &rsrc) {
Shinya Kitaoka 120a6e
    if (!m_scene.isExternPath(rsrc.m_path.m_rootFp)) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      // Build parent folder paths
Shinya Kitaoka 120a6e
      const TFilePath &srcDir =
Shinya Kitaoka 120a6e
          rsrc.m_path.absoluteResourcePath().getParentDir();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      switchToDst(rsrc.m_path);
Shinya Kitaoka 120a6e
      const TFilePath &dstDir =
Shinya Kitaoka 120a6e
          rsrc.m_path.absoluteResourcePath().getParentDir();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Make sure destination folder exists
Shinya Kitaoka 120a6e
      TSystem::mkDir(dstDir);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Find out whether a destination component file
Shinya Kitaoka 120a6e
      // already exists
Shinya Kitaoka 120a6e
      bool overwrite = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      OverwriteDialog::Obj obj = {dstDir, rsrc};
Shinya Kitaoka 120a6e
      switch (m_overwriteDialog->execute(&obj)) {
Shinya Kitaoka 120a6e
      case OverwriteDialog::OVERWRITE:
Shinya Kitaoka 120a6e
        overwrite = true;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case OverwriteDialog::SKIP:
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Perform resource copy
Shinya Kitaoka 120a6e
      std::for_each(rsrc.m_components.begin(), rsrc.m_components.end(),
otakuto 3bf772
                    [&srcDir, &dstDir, &overwrite](const Resource::Component &comp){ copy(srcDir, dstDir, comp, overwrite); });
Shinya Kitaoka 120a6e
    } catch (const TException &e) {
Shinya Kitaoka 120a6e
      DVGui::error(QString::fromStdWString(e.getMessage()));
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
};  // import_Locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void import(const ToonzScene &scene, std::vector<resource> &resources,</resource>
Shinya Kitaoka 120a6e
            IoCmd::LoadResourceArguments::ScopedBlock &sb) {
Shinya Kitaoka 2a7129
  import_Locals locals = {scene, std::unique_ptr<overwritedialog>()};</overwritedialog>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Setup import GUI
Shinya Kitaoka 120a6e
  int r, rCount = resources.size();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  DVGui::ProgressDialog *progressDialog = 0;
Shinya Kitaoka 120a6e
  if (rCount > 1) {
Shinya Kitaoka 120a6e
    progressDialog = &sb.progressDialog();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    progressDialog->setModal(true);
Shinya Kitaoka 120a6e
    progressDialog->setMinimum(0);
Shinya Kitaoka 120a6e
    progressDialog->setMaximum(rCount);
Shinya Kitaoka 120a6e
    progressDialog->show();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Perform import
Shinya Kitaoka 120a6e
  locals.m_overwriteDialog.reset(new OverwriteDialog(
Shinya Kitaoka 120a6e
      progressDialog ? (QWidget *)progressDialog
Shinya Kitaoka 120a6e
                     : (QWidget *)TApp::instance()->getMainWindow()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (r = 0; r != rCount; ++r) {
Shinya Kitaoka 120a6e
    Resource &rsrc = resources[r];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (progressDialog) {
Shinya Kitaoka 120a6e
      progressDialog->setLabelText(
Shinya Kitaoka 120a6e
          DVGui::ProgressDialog::tr("Importing \"%1\"...")
Shinya Kitaoka 120a6e
              .arg(rsrc.m_path.m_relFp.getQString()));
Shinya Kitaoka 120a6e
      progressDialog->setValue(r);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      QCoreApplication::processEvents();
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    locals.import(rsrc);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    OverwriteDialog  implementation
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
OverwriteDialog::OverwriteDialog(QWidget *parent)
Shinya Kitaoka 120a6e
    : ValidatedChoiceDialog(parent, ValidatedChoiceDialog::APPLY_TO_ALL) {
shun-iwasawa 199e29
  setWindowTitle(QObject::tr("Warning!", "OverwriteDialog"));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Option 1: OVERWRITE
Shinya Kitaoka 120a6e
  QRadioButton *radioButton = new QRadioButton;
shun-iwasawa 199e29
  radioButton->setText(QObject::tr("Overwrite", "OverwriteDialog"));
Shinya Kitaoka 120a6e
  radioButton->setFixedHeight(20);
Shinya Kitaoka 120a6e
  radioButton->setChecked(true);  // initial option: OVERWRITE
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_buttonGroup->addButton(radioButton, OVERWRITE);
Shinya Kitaoka 120a6e
  addWidget(radioButton);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Option 2: SKIP
Shinya Kitaoka 120a6e
  radioButton = new QRadioButton;
shun-iwasawa 199e29
  radioButton->setText(QObject::tr("Skip", "OverwriteDialog"));
Shinya Kitaoka 120a6e
  radioButton->setFixedHeight(20);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_buttonGroup->addButton(radioButton, SKIP);
Shinya Kitaoka 120a6e
  addWidget(radioButton);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  endVLayout();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  layout()->setSizeConstraint(QLayout::SetFixedSize);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString OverwriteDialog::acceptResolution(void *obj_, int resolution,
Shinya Kitaoka 120a6e
                                          bool applyToAll) {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static bool existsComponent(const TFilePath &dstDir,
Shinya Kitaoka 120a6e
                                const Resource::Component &comp) {
Shinya Kitaoka 120a6e
      return QFile::exists(dstPath(dstDir, comp).getQString());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static bool existsResource(const TFilePath &dstDir, const Resource &rsrc) {
Tact Yoshida da287b
      return std::any_of(rsrc.m_components.begin(), rsrc.m_components.end(),
otakuto 3bf772
                         [&dstDir](const Resource::Component &comp){ return existsComponent(dstDir, comp); });
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };  // locals
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const Obj &obj = *static_cast<obj *="">(obj_);</obj>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QString error;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (resolution == NO_RESOLUTION) {
Shinya Kitaoka 120a6e
    // Test existence of any resource components
Shinya Kitaoka 120a6e
    if (locals::existsResource(obj.m_dstDir, obj.m_rsrc))
shun-iwasawa 199e29
      error = QObject::tr(
shun-iwasawa 199e29
                  "File \"%1\" already exists.\nDo you want to overwrite it?",
shun-iwasawa 199e29
                  "OverwriteDialog")
Shinya Kitaoka 120a6e
                  .arg(obj.m_rsrc.m_path.m_relFp.getQString());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return error;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    API functions
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int IoCmd::loadResourceFolders(LoadResourceArguments &args,
Shinya Kitaoka 120a6e
                               LoadResourceArguments::ScopedBlock *sb) {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static LRArgs::ResourceData toResourceData(const Resource &rsrc) {
Shinya Kitaoka 120a6e
      LRArgs::ResourceData rd(rsrc.m_path.absoluteResourcePath());
Shinya Kitaoka 120a6e
      rd.m_options = rsrc.m_levelOptions;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      return rd;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static bool isExternPath(const ToonzScene &scene,
Shinya Kitaoka 120a6e
                             const LRArgs::ResourceData &rd) {
Shinya Kitaoka 120a6e
      return scene.isExternPath(rd.m_path);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };  // locals
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  boost::optional<lrargs::scopedblock> sb_;</lrargs::scopedblock>
Shinya Kitaoka 120a6e
  if (!sb) sb = (sb_ = boost::in_place()).get_ptr();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
Shinya Kitaoka 120a6e
  assert(scene);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Loading options popup
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Deal with import decision
Shinya Kitaoka 120a6e
  bool import = false;
Shinya Kitaoka 120a6e
  {
Tact Yoshida da287b
    if (std::any_of(
Shinya Kitaoka 120a6e
            args.resourceDatas.begin(), args.resourceDatas.end(),
otakuto 3bf772
            [scene](const LRArgs::ResourceData &rd){ return locals::isExternPath(*scene, rd); })) {
Shinya Kitaoka 120a6e
      // Ask for data import in this case
Shinya Kitaoka 120a6e
      int resolutionButton = DVGui::MsgBox(
Shinya Kitaoka 120a6e
          QObject::tr("Selected folders don't belong to the current project.\n"
Shinya Kitaoka 120a6e
                      "Do you want to import them or load from their original "
Shinya Kitaoka 120a6e
                      "location?"),
Shinya Kitaoka 120a6e
          QObject::tr("Load"), QObject::tr("Import"), QObject::tr("Cancel"));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      enum { CLOSED, LOAD, IMPORT, CANCELED };
Shinya Kitaoka 120a6e
      switch (resolutionButton) {
Shinya Kitaoka 120a6e
      case CLOSED:
Shinya Kitaoka 120a6e
      case CANCELED:
Shinya Kitaoka 120a6e
        return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      case IMPORT:
Shinya Kitaoka 120a6e
        import = true;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Select resources to be loaded
Shinya Kitaoka 120a6e
  std::vector<resource> resources;</resource>
Shinya Kitaoka 120a6e
otakuto 3bf772
  boost::for_each(args.resourceDatas,
otakuto 3bf772
    [&resources](const LRArgs::ResourceData &resourceData){ buildResources(resources, resourceData.m_path, TFilePath()); });
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Import them if required
Shinya Kitaoka 120a6e
  if (import) ::import(*scene, resources, *sb);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Temporarily substitute args' import policy
Shinya Kitaoka 120a6e
  struct SubstImportPolicy {
Shinya Kitaoka 120a6e
    LRArgs &m_args;
Shinya Kitaoka 120a6e
    LRArgs::ImportPolicy m_policy;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    SubstImportPolicy(LRArgs &args, LRArgs::ImportPolicy policy)
Shinya Kitaoka 120a6e
        : m_args(args), m_policy(args.importPolicy) {
Shinya Kitaoka 120a6e
      args.importPolicy = policy;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ~SubstImportPolicy() { m_args.importPolicy = m_policy; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  } substImportPolicy(args, import ? LRArgs::IMPORT : LRArgs::LOAD);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Perform loading via loadResources()
Shinya Kitaoka 120a6e
  args.resourceDatas.assign(
Shinya Kitaoka 120a6e
      boost::make_transform_iterator(resources.begin(), locals::toResourceData),
Shinya Kitaoka 120a6e
      boost::make_transform_iterator(resources.end(), locals::toResourceData));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return IoCmd::loadResources(args, false, sb);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Command instantiation
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
OpenPopupCommandHandler<loadfolderpopup> loadFolderCommand(MI_LoadFolder);</loadfolderpopup>