diff --git a/toonz/sources/common/tcontenthistory.cpp b/toonz/sources/common/tcontenthistory.cpp index ded790d..b3ad752 100644 --- a/toonz/sources/common/tcontenthistory.cpp +++ b/toonz/sources/common/tcontenthistory.cpp @@ -73,7 +73,7 @@ inline QString blanks(const QString &str, int count = 15) { //-------------------------------------------------------------------- inline QString getStr(const TFrameId &id) { - if (id.getLetter() != 0) + if (!id.getLetter().isEmpty()) return QString::number(id.getNumber()) + id.getLetter(); else return QString::number(id.getNumber()); @@ -159,7 +159,7 @@ const QString TContentHistory::currentToString() const { dateSorted.insert(pair(it->second, it->first)); std::multimap::const_iterator it1 = dateSorted.begin(); - QDateTime currDate = it1->first; + QDateTime currDate = it1->first; while (it1 != dateSorted.end()) { set frames; diff --git a/toonz/sources/common/timage_io/tlevel_io.cpp b/toonz/sources/common/timage_io/tlevel_io.cpp index 0a62826..7877d33 100644 --- a/toonz/sources/common/timage_io/tlevel_io.cpp +++ b/toonz/sources/common/timage_io/tlevel_io.cpp @@ -132,6 +132,9 @@ TLevelP TLevelReader::loadInfo() { if (!data.empty()) { std::vector::iterator it = std::min_element(data.begin(), data.end(), myLess); + + m_frameFormat = (*it).getFrame().getCurrentFormat(); + /* TFilePath fr = (*it).withoutParentDir().withName("").withType(""); wstring ws = fr.getWideString(); if (ws.length() == 5) { @@ -150,7 +153,7 @@ TLevelP TLevelReader::loadInfo() { else m_frameFormat = TFrameId::UNDERSCORE_NO_PAD; } - + */ } else m_frameFormat = TFrameId::FOUR_ZEROS; diff --git a/toonz/sources/common/tsystem/tfilepath.cpp b/toonz/sources/common/tsystem/tfilepath.cpp index a892a8a..33e2338 100644 --- a/toonz/sources/common/tsystem/tfilepath.cpp +++ b/toonz/sources/common/tsystem/tfilepath.cpp @@ -27,9 +27,16 @@ const char wauxslash = '\\'; // QT #include +#include bool TFilePath::m_underscoreFormatAllowed = true; +// specifies file path condition for sequential image for each project. +// See filepathproperties.h +bool TFilePath::m_useStandard = true; +bool TFilePath::m_acceptNonAlphabetSuffix = false; +int TFilePath::m_letterCountForSuffix = 1; + namespace { /*-- fromSeg位置 と @@ -102,23 +109,27 @@ std::string TFrameId::expand(FrameFormat format) const { } else { o_buff << m_frame; } - if (m_letter != '\0') o_buff << m_letter; - return o_buff.str(); + if (m_letter.isEmpty()) + return o_buff.str(); + else + return o_buff.str() + m_letter.toStdString(); } //------------------------------------------------------------------- const TFrameId &TFrameId::operator++() { ++m_frame; - m_letter = 0; + m_letter = ""; + // m_letter = 0; return *this; } //------------------------------------------------------------------- const TFrameId &TFrameId::operator--() { - if (m_letter > 0) - m_letter = 0; + if (!m_letter.isEmpty()) m_letter = ""; + // if (m_letter > 0) + // m_letter = 0; else --m_frame; return *this; @@ -245,9 +256,9 @@ void TFilePath::setPath(std::wstring path) { } // se si tratta di un path in formato UNC e' del tipo "\\\\MachineName" else if ((path.length() >= 3 && path[0] == L'\\' && path[1] == L'\\' && - iswalnum(path[2])) || + iswalnum(path[2])) || (path.length() >= 3 && path[0] == L'/' && path[1] == L'/' && - iswalnum(path[2]))) { + iswalnum(path[2]))) { isUncName = true; m_path.append(2, L'\\'); m_path.append(1, path[2]); @@ -283,14 +294,13 @@ void TFilePath::setPath(std::wstring path) { // oppure sia UNC (Windows only) ) if (!((m_path.length() == 1 && m_path[0] == wslash) || (m_path.length() == 3 && iswalpha(m_path[0]) && m_path[1] == L':' && - m_path[2] == wslash)) && + m_path[2] == wslash)) && (m_path.length() > 1 && m_path[m_path.length() - 1] == wslash)) m_path.erase(m_path.length() - 1, 1); - if (isUncName && - !(m_path.find_last_of(L'\\') > 1 || - m_path.find_last_of(L'/') > - 1)) // e' indicato solo il nome della macchina... + if (isUncName && !(m_path.find_last_of(L'\\') > 1 || + m_path.find_last_of(L'/') > + 1)) // e' indicato solo il nome della macchina... m_path.append(1, wslash); } @@ -516,10 +526,10 @@ bool TFilePath::isAbsolute() const { bool TFilePath::isRoot() const { return ((m_path.length() == 1 && m_path[0] == slash) || (m_path.length() == 3 && iswalpha(m_path[0]) && m_path[1] == ':' && - m_path[2] == slash) || + m_path[2] == slash) || ((m_path.length() > 2 && m_path[0] == slash && m_path[1] == slash) && - (std::string::npos == m_path.find(slash, 2) || - m_path.find(slash, 2) == (m_path.size() - 1)))); + (std::string::npos == m_path.find(slash, 2) || + m_path.find(slash, 2) == (m_path.size() - 1)))); } //----------------------------------------------------------------------------- @@ -527,6 +537,15 @@ bool TFilePath::isRoot() const { // ritorna ""(niente tipo, niente punto), "." (file con tipo) o ".." (file con // tipo e frame) std::string TFilePath::getDots() const { + if (!TFilePath::m_useStandard) { + TFilePathInfo info = analyzePath(); + if (info.extension.isEmpty()) return ""; + if (info.sepChar.isNull()) return "."; + // return ".." regardless of sepChar type (either "_" or ".") + return ".."; + } + //----- + QString type = QString::fromStdString(getType()).toLower(); if (isFfmpegType()) return "."; int i = getLastSlash(m_path); @@ -551,6 +570,12 @@ std::string TFilePath::getDots() const { std::string TFilePath::getDottedType() const // ritorna l'estensione con PUNTO (se c'e') { + if (!TFilePath::m_useStandard) { + QString ext = analyzePath().extension; + if (ext.isEmpty()) return ""; + return "." + ext.toLower().toStdString(); + } + int i = getLastSlash(m_path); std::wstring str = m_path.substr(i + 1); i = str.rfind(L"."); @@ -564,6 +589,15 @@ std::string TFilePath::getDottedType() std::string TFilePath::getUndottedType() const // ritorna l'estensione senza PUNTO { + if (!TFilePath::m_useStandard) { + QString ext = analyzePath().extension; + if (ext.isEmpty()) + return ""; + else + return ext.toLower().toStdString(); + } + + //----- size_t i = getLastSlash(m_path); std::wstring str = m_path.substr(i + 1); i = str.rfind(L"."); @@ -575,6 +609,11 @@ std::string TFilePath::getUndottedType() std::wstring TFilePath::getWideName() const // noDot! noSlash! { + if (!TFilePath::m_useStandard) { + return analyzePath().levelName.toStdWString(); + } + //----- + QString type = QString::fromStdString(getType()).toLower(); int i = getLastSlash(m_path); // cerco l'ultimo slash std::wstring str = m_path.substr(i + 1); @@ -609,6 +648,16 @@ std::string TFilePath::getLevelName() const { // es. TFilePath("/pippo/pluto.0001.gif").getLevelName() == "pluto..gif" std::wstring TFilePath::getLevelNameW() const { + if (!TFilePath::m_useStandard) { + TFilePathInfo info = analyzePath(); + if (info.extension.isEmpty()) return info.levelName.toStdWString(); + QString name = info.levelName; + if (!info.sepChar.isNull()) name += info.sepChar; + name += "." + info.extension; + return name.toStdWString(); + } + //----- + int i = getLastSlash(m_path); // cerco l'ultimo slash std::wstring str = m_path.substr(i + 1); // str e' m_path senza directory QString type = QString::fromStdString(getType()).toLower(); @@ -623,7 +672,8 @@ std::wstring TFilePath::getLevelNameW() const { return str; if (!checkForSeqNum(type) || !isNumbers(str, i, j) || - i == (int)std::wstring::npos) return str; + i == (int)std::wstring::npos) + return str; // prova.0001.tif return str.erase(i + 1, j - i - 1); } @@ -634,8 +684,9 @@ TFilePath TFilePath::getParentDir() const // noSlash! { int i = getLastSlash(m_path); // cerco l'ultimo slash if (i < 0) { - if (m_path.length() >= 2 && (('a' <= m_path[0] && m_path[0] <= 'z') || - ('A' <= m_path[0] && m_path[0] <= 'Z')) && + if (m_path.length() >= 2 && + (('a' <= m_path[0] && m_path[0] <= 'z') || + ('A' <= m_path[0] && m_path[0] <= 'Z')) && m_path[1] == ':') return TFilePath(m_path.substr(0, 2)); else @@ -647,8 +698,13 @@ TFilePath TFilePath::getParentDir() const // noSlash! } //----------------------------------------------------------------------------- - +// return true if the fID is EMPTY_FRAME bool TFilePath::isLevelName() const { + if (!TFilePath::m_useStandard) { + return analyzePath().fId.getNumber() == TFrameId::EMPTY_FRAME; + } + //----- + QString type = QString::fromStdString(getType()).toLower(); if (isFfmpegType() || !checkForSeqNum(type)) return false; try { @@ -661,6 +717,11 @@ bool TFilePath::isLevelName() const { } TFrameId TFilePath::getFrame() const { + if (!TFilePath::m_useStandard) { + return analyzePath().fId; + } + + //----- int i = getLastSlash(m_path); // cerco l'ultimo slash std::wstring str = m_path.substr(i + 1); // str e' il path senza parentdir QString type = QString::fromStdString(getType()).toLower(); @@ -676,8 +737,7 @@ TFrameId TFilePath::getFrame() const { if (j == (int)std::wstring::npos) return TFrameId(TFrameId::NO_FRAME); if (i == j + 1) return TFrameId(TFrameId::EMPTY_FRAME); - /*-- 間が数字でない場合(ファイル名にまぎれた"_" や "."がある場合)を除外する - * --*/ + // 間が数字でない場合(ファイル名にまぎれた"_" や "."がある場合)を除外する if (!checkForSeqNum(type) || !isNumbers(str, j, i)) return TFrameId(TFrameId::NO_FRAME); @@ -686,14 +746,13 @@ TFrameId TFilePath::getFrame() const { digits++; number = number * 10 + str[k] - L'0'; } - char letter = '\0'; + char letter = '\0'; if (iswalpha(str[k])) letter = str[k++] + ('a' - L'a'); - /* - if (number == 0 || k < i) // || letter!='\0') - throw TMalformedFrameException( - *this, - str + L": " + QObject::tr("Malformed frame name").toStdWString()); - */ + + // if (number == 0 || k < i) // || letter!='\0') + // throw TMalformedFrameException( + // *this, + // str + L": " + QObject::tr("Malformed frame name").toStdWString()); int padding = 0; if (str[j + 1] == '0') padding = digits; @@ -747,6 +806,20 @@ TFilePath TFilePath::withName(const std::string &name) const { //----------------------------------------------------------------------------- TFilePath TFilePath::withName(const std::wstring &name) const { + if (!TFilePath::m_useStandard) { + TFilePathInfo info = analyzePath(); + + QString ret = info.parentDir + QString::fromStdWString(name); + if (info.fId.getNumber() != TFrameId::NO_FRAME) { + QString sepChar = (info.sepChar.isNull()) ? "." : QString(info.sepChar); + ret += sepChar + QString::fromStdString( + info.fId.expand(info.fId.getCurrentFormat())); + } + if (!info.extension.isEmpty()) ret += "." + info.extension; + + return TFilePath(ret); + } + int i = getLastSlash(m_path); // cerco l'ultimo slash std::wstring str = m_path.substr(i + 1); // str e' il path senza parentdir QString type = QString::fromStdString(getType()).toLower(); @@ -786,6 +859,31 @@ TFilePath TFilePath::withParentDir(const TFilePath &dir) const { TFilePath TFilePath::withFrame(const TFrameId &frame, TFrameId::FrameFormat format) const { + if (!TFilePath::m_useStandard) { + TFilePathInfo info = analyzePath(); + // Override format input because it may be wrong. + if (checkForSeqNum(info.extension)) format = frame.getCurrentFormat(); + // override format if the original fid is available + else if (info.fId.getNumber() != TFrameId::NO_FRAME) + format = info.fId.getCurrentFormat(); + + if (info.extension.isEmpty()) { + if (frame.isEmptyFrame() || frame.isNoFrame()) return *this; + + return TFilePath(m_path + L"." + ::to_wstring(frame.expand(format))); + } + if (frame.isNoFrame()) { + return TFilePath(info.parentDir + info.levelName + "." + info.extension); + } + QString sepChar = (info.sepChar.isNull()) ? "." : QString(info.sepChar); + + return TFilePath(info.parentDir + info.levelName + sepChar + + QString::fromStdString(frame.expand(format)) + "." + + info.extension); + } + + //----------------- + const std::wstring dot = L".", dotDot = L".."; int i = getLastSlash(m_path); // cerco l'ultimo slash std::wstring str = m_path.substr(i + 1); // str e' il path senza parentdir @@ -800,6 +898,8 @@ TFilePath TFilePath::withFrame(const TFrameId &frame, format == TFrameId::UNDERSCORE_NO_PAD || format == TFrameId::UNDERSCORE_CUSTOM_PAD)) ch = "_"; + + // no extension case if (j == (int)std::wstring::npos) { if (frame.isEmptyFrame() || frame.isNoFrame()) return *this; @@ -834,7 +934,7 @@ TFilePath TFilePath::withFrame(const TFrameId &frame, (k == j - 1 || (checkForSeqNum(type) && isNumbers(str, k, - j)))) /*-- "_." の並びか、"_[数字]."の並びのとき --*/ + j)))) //-- "_." の並びか、"_[数字]."の並びのとき -- return TFilePath(m_path.substr(0, k + i + 1) + ((frame.isNoFrame()) ? L"" @@ -885,6 +985,16 @@ TFilePath TFilePath::operator-(const TFilePath &fp) const { //----------------------------------------------------------------------------- bool TFilePath::match(const TFilePath &fp) const { + if (!TFilePath::m_useStandard) { + if (getParentDir() != fp.getParentDir()) return false; + + TFilePathInfo info = analyzePath(); + TFilePathInfo info_ext = fp.analyzePath(); + + return (info.levelName == info_ext.levelName && info.fId == info_ext.fId && + info.extension == info_ext.extension); + } + return getParentDir() == fp.getParentDir() && getName() == fp.getName() && getFrame() == fp.getFrame() && getType() == fp.getType(); } @@ -907,3 +1017,118 @@ void TFilePath::split(std::wstring &head, TFilePath &tail) const { head = ancestor.getWideString(); tail = *this - ancestor; } + +//----------------------------------------------------------------------------- + +QString TFilePath::fidRegExpStr() { + if (m_useStandard) return QString("(\\d+)([a-zA-Z]?)"); + QString suffixLetter = (m_acceptNonAlphabetSuffix) + ? "[^\\._ \\\\/:,;*?\"<>|0123456789]" + : "[a-zA-Z]"; + QString countLetter = (m_letterCountForSuffix == 0) + ? "{0,}" + : (QString("{0,%1}").arg(m_letterCountForSuffix)); + return QString("(\\d+)(%1%2)").arg(suffixLetter).arg(countLetter); + // const QString fIdRegExp("(\\d+)([a-zA-Z]?)"); +} + +//----------------------------------------------------------------------------- + +TFilePath::TFilePathInfo TFilePath::analyzePath() const { + assert(!TFilePath::m_useStandard); + + TFilePath::TFilePathInfo info; + + int i = getLastSlash(m_path); + std::wstring str = m_path.substr(i + 1); + + if (i >= 0) info.parentDir = QString::fromStdWString(m_path.substr(0, i + 1)); + + QString fileName = QString::fromStdWString(str); + + // Level Name : letters other than \/:,;*?"<>| + const QString levelNameRegExp("([^\\\\/:,;*?\"<>|]+)"); + // Sep Char : period or underscore + const QString sepCharRegExp("([\\._])"); + // Frame Number and Suffix + QString fIdRegExp = TFilePath::fidRegExpStr(); + + // Extension:letters other than "._" or \/:,;*?"<>| or " "(space) + const QString extensionRegExp("([^\\._ \\\\/:,;*?\"<>|]+)"); + + // ignore frame numbers on non-sequential (i.e. movie) extension case : + // hoge_0001.mp4 + // QRegExp rx_mf("^" + levelNameRegExp + "\\." + extensionRegExp + "$"); + // if (rx_mf.indexIn(levelName) != -1) { + // QString ext = rx_mf.cap(2); + // if (!checkForSeqNum(ext)) { + // info.levelName = rx_mf.cap(1); + // info.sepChar = QChar(); + // info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); //NO_PADで初期化する + // info.extension = ext; + // return info; + // } + //} + + // hogehoge.0001a.jpg + // empty frame case : hogehoge..jpg + QRegExp rx("^" + levelNameRegExp + sepCharRegExp + "(?:" + fIdRegExp + ")?" + + "\\." + extensionRegExp + "$"); + if (rx.indexIn(fileName) != -1) { + assert(rx.captureCount() == 5); + info.levelName = rx.cap(1); + info.sepChar = rx.cap(2)[0]; + info.extension = rx.cap(5); + // ignore frame numbers on non-sequential (i.e. movie) extension case : + // hoge_0001.mp4 + if (!checkForSeqNum(info.extension)) { + info.levelName = rx.cap(1) + rx.cap(2); + if (!rx.cap(3).isEmpty()) info.levelName += rx.cap(3); + if (!rx.cap(4).isEmpty()) info.levelName += rx.cap(4); + info.sepChar = QChar(); + info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); // initialize with NO_PAD + } else { + QString numberStr = rx.cap(3); + if (numberStr.isEmpty()) // empty frame case : hogehoge..jpg + info.fId = + TFrameId(TFrameId::EMPTY_FRAME, 0, 4, info.sepChar.toLatin1()); + else { + int number = numberStr.toInt(); + int padding = 0; + if (numberStr[0] == "0") // with padding + padding = numberStr.count(); + QString suffix; + if (!rx.cap(4).isEmpty()) suffix = rx.cap(4); + info.fId = TFrameId(number, suffix, padding, info.sepChar.toLatin1()); + } + } + return info; + } + + // QRegExp rx_ef("^" + levelNameRegExp + sepCharRegExp + "\\." + + // extensionRegExp + "$"); if (rx_ef.indexIn(levelName) != -1) { + // info.levelName = rx_ef.cap(1); + // info.sepChar = rx_ef.cap(2)[0]; + // info.fId = TFrameId(TFrameId::EMPTY_FRAME, 0, 4, info.sepChar.toLatin1()); + // info.extension = rx_ef.cap(3); + // return info; + //} + + // no frame case : hogehoge.jpg + // no level name case : .jpg + QRegExp rx_nf("^(?:" + levelNameRegExp + ")?\\." + extensionRegExp + "$"); + if (rx_nf.indexIn(fileName) != -1) { + if (!rx_nf.cap(1).isEmpty()) info.levelName = rx_nf.cap(1); + info.sepChar = QChar(); + info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); // initialize with NO_PAD + info.extension = rx_nf.cap(2); + return info; + } + + // no periods + info.levelName = fileName; + info.sepChar = QChar(); + info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); // initialize with NO_PAD + info.extension = QString(); + return info; +} \ No newline at end of file diff --git a/toonz/sources/image/3gp/tiio_3gpW.cpp b/toonz/sources/image/3gp/tiio_3gpW.cpp index 669bdec..0d4d0d8 100644 --- a/toonz/sources/image/3gp/tiio_3gpW.cpp +++ b/toonz/sources/image/3gp/tiio_3gpW.cpp @@ -109,7 +109,9 @@ string buildQTErrorString(int ec) { case QTUnableToSetMovieBox: return "unable to set movie box"; - default: { return "unknown error ('" + std::to_string(ec) + "')"; } + default: { + return "unknown error ('" + std::to_string(ec) + "')"; + } } } @@ -276,7 +278,7 @@ void copy(TRasterP rin, PixelXRGB *bufout, int lx, int ly) { } rin->unlock(); } -}; +}; // namespace //----------------------------------------------------------- void TImageWriter3gp::save(const TImageP &img) { @@ -507,7 +509,9 @@ TLevelWriter3gp::TLevelWriter3gp(const TFilePath &path, TPropertyGroup *winfo) #else #define FailWithAction(cond, action, handler) \ if (cond) { \ - { action; } \ + { \ + action; \ + } \ goto handler; \ } else \ 0 @@ -564,7 +568,7 @@ void TLevelWriter3gp::saveSoundTrack(TSoundTrack *st) { myMedia = NewTrackMedia(theTrack, SoundMediaType, st->getSampleRate(), m_soundDataRef, HandleDataHandlerSubType); // track->rate >> 16 - myErr = GetMoviesError(); + myErr = GetMoviesError(); FailIf(myErr != noErr, Exit); // start a media editing session @@ -741,7 +745,7 @@ TImageWriterP TLevelWriter3gp::getFrameWriter(TFrameId fid) { if (m_cancelled) return 0; if (m_IOError) throw TImageException(m_path, buildQTErrorString(m_IOError)); - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber() - 1; TImageWriter3gp *iwm = new TImageWriter3gp(m_path, index, this); @@ -1010,7 +1014,7 @@ TImageReaderP TLevelReader3gp::getFrameReader(TFrameId fid) { if (m_IOError != QTNoError) throw TImageException(m_path, buildQTErrorString(m_IOError)); - if (fid.getLetter() != 0) return TImageReaderP(0); + if (!fid.getLetter().isEmpty()) return TImageReaderP(0); int index = fid.getNumber() - 1; TImageReader3gp *irm = new TImageReader3gp(m_path, index, this); diff --git a/toonz/sources/image/3gp/tiio_3gp_proxy.cpp b/toonz/sources/image/3gp/tiio_3gp_proxy.cpp index e9dcc57..37ede93 100644 --- a/toonz/sources/image/3gp/tiio_3gp_proxy.cpp +++ b/toonz/sources/image/3gp/tiio_3gp_proxy.cpp @@ -1,6 +1,7 @@ -#if defined(x64) || defined(__LP64__) || defined(LINUX) || defined(FREEBSD) || (defined(_WIN32) && defined(__GNUC__)) +#if defined(x64) || defined(__LP64__) || defined(LINUX) || defined(FREEBSD) || \ + (defined(_WIN32) && defined(__GNUC__)) // Toonz includes #include "tfilepath.h" @@ -164,7 +165,7 @@ void TLevelWriter3gp::setFrameRate(double fps) { //------------------------------------------------------------------ TImageWriterP TLevelWriter3gp::getFrameWriter(TFrameId fid) { - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber() - 1; return new TImageWriter3gpProxy(m_path, index, this); @@ -340,7 +341,7 @@ TLevelReader3gp::~TLevelReader3gp() { //------------------------------------------------------------------ TImageReaderP TLevelReader3gp::getFrameReader(TFrameId fid) { - if (fid.getLetter() != 0) return TImageReaderP(0); + if (!fid.getLetter().isEmpty()) return TImageReaderP(0); int index = fid.getNumber() - 1; return new TImageReader3gpProxy(m_path, index, this, m_info); diff --git a/toonz/sources/image/avi/tiio_avi.cpp b/toonz/sources/image/avi/tiio_avi.cpp index c5b3140..6e40cff 100644 --- a/toonz/sources/image/avi/tiio_avi.cpp +++ b/toonz/sources/image/avi/tiio_avi.cpp @@ -332,7 +332,7 @@ void TLevelWriterAvi::createBitmap(int lx, int ly) { TImageWriterP TLevelWriterAvi::getFrameWriter(TFrameId fid) { if (IOError != 0) throw TImageException(m_path, buildAVIExceptionString(IOError)); - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber() - 1; TImageWriterAvi *iwa = new TImageWriterAvi(m_path, index, this); return TImageWriterP(iwa); @@ -879,7 +879,7 @@ TLevelP TLevelReaderAvi::loadInfo() { TImageReaderP TLevelReaderAvi::getFrameReader(TFrameId fid) { if (IOError != 0) throw TImageException(m_path, buildAVIExceptionString(IOError)); - if (fid.getLetter() != 0) return TImageReaderP(0); + if (!fid.getLetter().isEmpty()) return TImageReaderP(0); int index = fid.getNumber() - 1; TImageReaderAvi *ira = new TImageReaderAvi(m_path, index, this); diff --git a/toonz/sources/image/ffmpeg/tiio_gif.cpp b/toonz/sources/image/ffmpeg/tiio_gif.cpp index 7a6f02f..d2d5a25 100644 --- a/toonz/sources/image/ffmpeg/tiio_gif.cpp +++ b/toonz/sources/image/ffmpeg/tiio_gif.cpp @@ -119,7 +119,7 @@ TLevelWriterGif::~TLevelWriterGif() { TImageWriterP TLevelWriterGif::getFrameWriter(TFrameId fid) { // if (IOError != 0) // throw TImageException(m_path, buildGifExceptionString(IOError)); - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber(); TImageWriterGif *iwg = new TImageWriterGif(m_path, index, this); return TImageWriterP(iwg); @@ -224,7 +224,7 @@ TLevelP TLevelReaderGif::loadInfo() { TImageReaderP TLevelReaderGif::getFrameReader(TFrameId fid) { // if (IOError != 0) // throw TImageException(m_path, buildAVIExceptionString(IOError)); - if (fid.getLetter() != 0) return TImageReaderP(0); + if (!fid.getLetter().isEmpty()) return TImageReaderP(0); int index = fid.getNumber(); TImageReaderGif *irm = new TImageReaderGif(m_path, index, this, m_info); return TImageReaderP(irm); diff --git a/toonz/sources/image/ffmpeg/tiio_mp4.cpp b/toonz/sources/image/ffmpeg/tiio_mp4.cpp index 4c1b176..5598224 100644 --- a/toonz/sources/image/ffmpeg/tiio_mp4.cpp +++ b/toonz/sources/image/ffmpeg/tiio_mp4.cpp @@ -100,7 +100,7 @@ TLevelWriterMp4::~TLevelWriterMp4() { TImageWriterP TLevelWriterMp4::getFrameWriter(TFrameId fid) { // if (IOError != 0) // throw TImageException(m_path, buildMp4ExceptionString(IOError)); - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber(); TImageWriterMp4 *iwg = new TImageWriterMp4(m_path, index, this); return TImageWriterP(iwg); @@ -203,7 +203,7 @@ TLevelP TLevelReaderMp4::loadInfo() { TImageReaderP TLevelReaderMp4::getFrameReader(TFrameId fid) { // if (IOError != 0) // throw TImageException(m_path, buildAVIExceptionString(IOError)); - if (fid.getLetter() != 0) return TImageReaderP(0); + if (!fid.getLetter().isEmpty()) return TImageReaderP(0); int index = fid.getNumber(); TImageReaderMp4 *irm = new TImageReaderMp4(m_path, index, this, m_info); diff --git a/toonz/sources/image/ffmpeg/tiio_webm.cpp b/toonz/sources/image/ffmpeg/tiio_webm.cpp index e54c7ad..0616045 100644 --- a/toonz/sources/image/ffmpeg/tiio_webm.cpp +++ b/toonz/sources/image/ffmpeg/tiio_webm.cpp @@ -101,7 +101,7 @@ TLevelWriterWebm::~TLevelWriterWebm() { TImageWriterP TLevelWriterWebm::getFrameWriter(TFrameId fid) { // if (IOError != 0) // throw TImageException(m_path, buildGifExceptionString(IOError)); - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber(); TImageWriterWebm *iwg = new TImageWriterWebm(m_path, index, this); return TImageWriterP(iwg); @@ -204,7 +204,7 @@ TLevelP TLevelReaderWebm::loadInfo() { TImageReaderP TLevelReaderWebm::getFrameReader(TFrameId fid) { // if (IOError != 0) // throw TImageException(m_path, buildAVIExceptionString(IOError)); - if (fid.getLetter() != 0) return TImageReaderP(0); + if (!fid.getLetter().isEmpty()) return TImageReaderP(0); int index = fid.getNumber(); TImageReaderWebm *irm = new TImageReaderWebm(m_path, index, this, m_info); diff --git a/toonz/sources/image/mov/tiio_movW.cpp b/toonz/sources/image/mov/tiio_movW.cpp index f415e00..a01a765 100644 --- a/toonz/sources/image/mov/tiio_movW.cpp +++ b/toonz/sources/image/mov/tiio_movW.cpp @@ -114,7 +114,9 @@ string buildQTErrorString(int ec) { case QTUnableToSetMovieBox: return "unable to set movie box"; - default: { return "unknown error ('" + std::to_string(ec) + "')"; } + default: { + return "unknown error ('" + std::to_string(ec) + "')"; + } } } @@ -267,7 +269,7 @@ void copy(TRasterP rin, PixelXRGB *bufout, int lx, int ly) { } rin32->unlock(); } -}; +}; // namespace //----------------------------------------------------------- /* @@ -538,8 +540,7 @@ throw TImageException(getFilePath(), "can't compress image"); 100, // 100 matches the length of 1 frame (SampleDescriptionHandle) img_descr, // in the movie/media's timeScale - 1, - 0, &sampleTime)) != noErr) + 1, 0, &sampleTime)) != noErr) throw TImageException(getFilePath(), "can't add image to movie media"); if ((err = EndMediaEdits(m_videoMedia)) != noErr) @@ -618,7 +619,9 @@ TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TPropertyGroup *winfo) #else #define FailWithAction(cond, action, handler) \ if (cond) { \ - { action; } \ + { \ + action; \ + } \ goto handler; \ } else \ 0 @@ -748,7 +751,7 @@ void TLevelWriterMov::saveSoundTrack(TSoundTrack *st) { myErr = EndMediaEdits(m_soundMedia); FailIf(myErr != noErr, MediaErr); -// NOTE: Sound media is inserted into the movie track only at destruction + // NOTE: Sound media is inserted into the movie track only at destruction ConverterErr: // Multiple bailout labels just to NoDest: // separate debugging strings, it seems. @@ -821,16 +824,14 @@ TLevelWriterMov::~TLevelWriterMov() { QTMetaDataRef metaDataRef; if ((mderr = QTCopyMovieMetaData(m_movie, &metaDataRef)) != noErr) - throw TImageException(getFilePath(), - "can't access metadata information"); + throw TImageException(getFilePath(), "can't access metadata information"); if ((mderr = QTMetaDataAddItem( metaDataRef, kQTMetaDataStorageFormatUserData, kQTMetaDataKeyFormatUserData, (const UInt8 *)firstFrameKey.c_str(), firstFrameKeySize, (const UInt8 *)(&m_firstFrame), sizeof(int), kQTMetaDataTypeUnsignedIntegerBE, 0)) != noErr) - throw TImageException(getFilePath(), - "can't insert metadata information"); + throw TImageException(getFilePath(), "can't insert metadata information"); QTMetaDataRelease(metaDataRef); } @@ -864,7 +865,7 @@ TLevelWriterMov::~TLevelWriterMov() { TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid) { if (m_IOError) throw TImageException(m_path, buildQTErrorString(m_IOError)); - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber() - 1; TImageWriterMov *iwm = new TImageWriterMov(m_path, index, this); @@ -940,7 +941,7 @@ TLevelReaderMov::TLevelReaderMov(const TFilePath &path) // Retrieve the timecode media handler { - Track tcTrack = GetMovieIndTrackType(m_movie, 1, TimeCodeMediaType, + Track tcTrack = GetMovieIndTrackType(m_movie, 1, TimeCodeMediaType, movieTrackMediaType); Media tcMedia = GetTrackMedia(tcTrack); m_timecodeHandler = GetMediaHandler(tcMedia); @@ -1354,7 +1355,7 @@ TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid) { if (m_IOError != QTNoError) throw TImageException(m_path, buildQTErrorString(m_IOError)); - if (fid.getLetter() != 0) return TImageReaderP(0); + if (!fid.getLetter().isEmpty()) return TImageReaderP(0); int index = fid.getNumber() - 1; TImageReaderMov *irm = new TImageReaderMov(m_path, index, this, m_info); diff --git a/toonz/sources/image/mov/tiio_mov_proxy.cpp b/toonz/sources/image/mov/tiio_mov_proxy.cpp index b274311..359e7cb 100644 --- a/toonz/sources/image/mov/tiio_mov_proxy.cpp +++ b/toonz/sources/image/mov/tiio_mov_proxy.cpp @@ -1,6 +1,7 @@ -#if defined(x64) || defined(__LP64__) || defined(LINUX) || defined(FREEBSD) || (defined(_WIN32) && defined(__GNUC__)) +#if defined(x64) || defined(__LP64__) || defined(LINUX) || defined(FREEBSD) || \ + (defined(_WIN32) && defined(__GNUC__)) // Toonz includes #include "tfilepath.h" @@ -232,7 +233,7 @@ void TLevelWriterMov::setFrameRate(double fps) { //------------------------------------------------------------------ TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid) { - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber() - 1; return new TImageWriterMovProxy(m_path, index, this); @@ -408,7 +409,7 @@ TLevelReaderMov::~TLevelReaderMov() { //------------------------------------------------------------------ TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid) { - if (fid.getLetter() != 0) return TImageReaderP(0); + if (!fid.getLetter().isEmpty()) return TImageReaderP(0); int index = fid.getNumber() - 1; return new TImageReaderMovProxy(m_path, index, this, m_info); diff --git a/toonz/sources/image/pli/pli_io.cpp b/toonz/sources/image/pli/pli_io.cpp index 155738d..df4d586 100644 --- a/toonz/sources/image/pli/pli_io.cpp +++ b/toonz/sources/image/pli/pli_io.cpp @@ -29,7 +29,7 @@ typedef TVectorImage::IntersectionBranch IntersectionBranch; TNZ_LITTLE_ENDIAN undefined !! #endif - static const int c_majorVersionNumber = 120; + static const int c_majorVersionNumber = 150; static const int c_minorVersionNumber = 0; /*=====================================================================*/ @@ -58,8 +58,8 @@ inline double doubleFromUlong1(TUINT32 hi, TUINT32 lo) { l[1] = hi; l[0] = lo; #else - l[0] = hi; - l[1] = lo; + l[0] = hi; + l[1] = lo; #endif return *(double *)l; // - 1; @@ -84,8 +84,8 @@ public: #if TNZ_LITTLE_ENDIAN app = n; #else - UCHAR *uc = (UCHAR *)&n; - app = *(uc) | (*(uc + 1)) << 8 | (*(uc + 2)) << 16 | (*(uc + 3)) << 24; + UCHAR *uc = (UCHAR *)&n; + app = *(uc) | (*(uc + 1)) << 8 | (*(uc + 2)) << 16 | (*(uc + 3)) << 24; #endif write((char *)&app, sizeof(TUINT32)); return *this; @@ -669,15 +669,27 @@ void ParsedPliImp::loadInfo(bool readPlt, TPalette *&palette, USHORT frame; m_iChan >> frame; - char letter = 0; - if (m_majorVersionNumber > 6 || - (m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) - m_iChan >> letter; + QByteArray suffix; + if (m_majorVersionNumber >= 150) { + TUINT32 suffixLength; + m_iChan >> suffixLength; + if ((int)suffixLength > 0) { + suffix.resize(suffixLength); + m_iChan.read(suffix.data(), suffixLength); + } + } else { + char letter = 0; + if (m_majorVersionNumber > 6 || + (m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) + m_iChan >> letter; + if (letter > 0) suffix = QByteArray(&letter, 1); + } - m_frameOffsInFile[TFrameId(frame, letter)] = m_iChan.tellg(); + m_frameOffsInFile[TFrameId(frame, QString::fromUtf8(suffix))] = + m_iChan.tellg(); // m_iChan.seekg(m_tagLength, ios::cur); - m_iChan.seekg(m_tagLength - 2, ios::cur); + if (m_majorVersionNumber < 150) m_iChan.seekg(m_tagLength - 2, ios::cur); } else if (type == PliTag::STYLE_NGOBJ) { m_iChan.seekg(pos, ios::beg); TagElem *tagElem = readTag(); @@ -798,7 +810,7 @@ ImageTag *ParsedPliImp::loadFrame(const TFrameId &frameNumber) { // PliTag *tag; USHORT type = PliTag::IMAGE_BEGIN_GOBJ; USHORT frame; - char letter; + QByteArray suffix; TFrameId frameId; // cerco il frame @@ -813,13 +825,22 @@ ImageTag *ParsedPliImp::loadFrame(const TFrameId &frameNumber) { while ((type = readTagHeader()) != PliTag::END_CNTRL) { if (type == PliTag::IMAGE_BEGIN_GOBJ) { m_iChan >> frame; - if (m_majorVersionNumber > 6 || - (m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) - m_iChan >> letter; - else - letter = 0; - frameId = TFrameId(frame, letter); + if (m_majorVersionNumber >= 150) { + TUINT32 suffixLength; + m_iChan >> suffixLength; + suffix.resize(suffixLength); + m_iChan.read(suffix.data(), suffixLength); + } else { + char letter = 0; + if (m_majorVersionNumber > 6 || + (m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) { + m_iChan >> letter; + if (letter > 0) suffix = QByteArray(&letter, 1); + } + } + + frameId = TFrameId(frame, QString::fromUtf8(suffix)); m_frameOffsInFile[frameId] = m_iChan.tellg(); if (frameId == frameNumber) break; } else @@ -1056,15 +1077,16 @@ inline bool ParsedPliImp::readDynamicData(TINT32 &val, TUINT32 &bufOffs) { case 4: if (m_isIrixEndian) { val = (m_buf[bufOffs + 3] | (m_buf[bufOffs + 2] << 8) | - (m_buf[bufOffs + 1] << 16) | (m_buf[bufOffs] << 24)) & 0x7fffffff; + (m_buf[bufOffs + 1] << 16) | (m_buf[bufOffs] << 24)) & + 0x7fffffff; if (m_buf[bufOffs] & 0x80) { val = -val; isNegative = true; } } else { val = (m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8) | - (m_buf[bufOffs + 2] << 16) | - (m_buf[bufOffs + 3] << 24)) & 0x7fffffff; + (m_buf[bufOffs + 2] << 16) | (m_buf[bufOffs + 3] << 24)) & + 0x7fffffff; if (m_buf[bufOffs + 3] & 0x80) { val = -val; isNegative = true; @@ -1466,7 +1488,7 @@ UINT ParsedPliImp::readRasterData(TRaster32P &r, TUINT32 &bufOffs) { /*=====================================================================*/ inline void getLongValFromFloat(double val, TINT32 &intVal, TUINT32 &decVal) { - intVal = (TINT32)val; + intVal = (TINT32)val; if (val < 0) decVal = (TUINT32)((double)((-val) - (-intVal)) * 65536.0); /*if (intVal<(0x1<<7)) intVal|=(0x1<<7); @@ -1614,11 +1636,25 @@ PliTag *ParsedPliImp::readImageTag() { bufOffs += 2; int headerLength = 2; - char letter = 0; - if (m_majorVersionNumber > 6 || - (m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) { - letter = (char)m_buf[bufOffs++]; - ++headerLength; + + QByteArray suffix; + if (m_majorVersionNumber >= 150) { + TUINT32 suffixLength; + readTUINT32Data(suffixLength, bufOffs); + headerLength += 4; + if (suffixLength > 0) { + suffix = QByteArray((char *)m_buf.get() + bufOffs, suffixLength); + bufOffs += suffixLength; + headerLength += suffixLength; + } + } else { + char letter = 0; + if (m_majorVersionNumber > 6 || + (m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) { + letter = (char)m_buf[bufOffs++]; + ++headerLength; + if (letter > 0) suffix = QByteArray(&letter, 1); + } } TUINT32 numObjects = (m_tagLength - headerLength) / m_currDynamicTypeBytesNum; @@ -1638,7 +1674,8 @@ PliTag *ParsedPliImp::readImageTag() { assert(false); std::unique_ptr tag( - new ImageTag(TFrameId(frame, letter), numObjects, std::move(object))); + new ImageTag(TFrameId(frame, QString::fromUtf8(suffix)), numObjects, + std::move(object))); return tag.release(); } @@ -1655,8 +1692,8 @@ inline double doubleFromUlong(TUINT32 q) { l[1] = 0x3FF00000 | (q >> 12); l[0] = (q & 0xFFE) << 20; #else - l[0] = 0x3FF00000 | (q >> 12); - l[1] = (q & 0xFFE) << 20; + l[0] = 0x3FF00000 | (q >> 12); + l[1] = (q & 0xFFE) << 20; #endif return *(double *)l - 1; @@ -1700,7 +1737,7 @@ PliTag *ParsedPliImp::readIntersectionDataTag() { readUShortData(style, bufOffs); branchArray[i].m_style = style; /* -*/ + */ if (m_buf[bufOffs] & 0x80) // in un numero double tra 0 e 1, il bit piu' // significativo e' sempre 0 // sfrutto questo bit; se e' 1, vuol dire che il valore e' 0.0 o 1.0 in un @@ -1981,7 +2018,7 @@ TUINT32 ParsedPliImp::writePaletteWithAlphaTag(PaletteWithAlphaTag *tag) { inline void ParsedPliImp::WRITE_UCHAR_FROM_DOUBLE(double dval) { assert(m_oChan); - int ival = tround(dval); + int ival = tround(dval); if (ival > 255) ival = 255; assert(ival >= 0); *m_oChan << (UCHAR)ival; @@ -2128,10 +2165,24 @@ TUINT32 ParsedPliImp::writeImageTag(ImageTag *tag) { TUINT32 *objectOffset, offset, tagLength; int maxval = 0, minval = 100000; - writeTagHeader((UCHAR)PliTag::IMAGE_BEGIN_GOBJ, 3); - *m_oChan << (USHORT)tag->m_numFrame.getNumber(); - *m_oChan << tag->m_numFrame.getLetter(); - + QByteArray suffix = tag->m_numFrame.getLetter().toUtf8(); + TUINT32 suffixLength = suffix.size(); + UINT fIdTagLength; + if (m_majorVersionNumber >= 150) { // write the suffix length before data + fIdTagLength = 2 + 4 + suffixLength; + writeTagHeader((UCHAR)PliTag::IMAGE_BEGIN_GOBJ, fIdTagLength); + *m_oChan << (USHORT)tag->m_numFrame.getNumber(); + *m_oChan << suffixLength; + if (suffixLength > 0) m_oChan->writeBuf(suffix.data(), suffixLength); + } else { // write only the first byte + fIdTagLength = 3; + writeTagHeader((UCHAR)PliTag::IMAGE_BEGIN_GOBJ, fIdTagLength); + *m_oChan << (USHORT)tag->m_numFrame.getNumber(); + if (suffixLength > 0) + m_oChan->writeBuf(suffix.data(), 1); + else + *m_oChan << (UCHAR)0; + } m_currDynamicTypeBytesNum = 3; objectOffset = new TUINT32[tag->m_numObjects]; @@ -2155,12 +2206,23 @@ TUINT32 ParsedPliImp::writeImageTag(ImageTag *tag) { setDynamicTypeBytesNum(minval, maxval); - tagLength = tag->m_numObjects * m_currDynamicTypeBytesNum + 3; + tagLength = tag->m_numObjects * m_currDynamicTypeBytesNum + fIdTagLength; + // tagLength = tag->m_numObjects * m_currDynamicTypeBytesNum + 3; offset = writeTagHeader((UCHAR)PliTag::IMAGE_GOBJ, tagLength); + suffix = tag->m_numFrame.getLetter().toUtf8(); *m_oChan << (USHORT)tag->m_numFrame.getNumber(); - *m_oChan << tag->m_numFrame.getLetter(); + + if (m_majorVersionNumber >= 150) { // write the suffix length before data + *m_oChan << suffixLength; + if (suffixLength > 0) m_oChan->writeBuf(suffix.data(), suffixLength); + } else { // write only the first byte + if (suffixLength > 0) + m_oChan->writeBuf(suffix.data(), 1); + else + *m_oChan << (UCHAR)0; + } for (i = 0; i < tag->m_numObjects; i++) writeDynamicData(objectOffset[i]); @@ -2420,29 +2482,29 @@ TUINT32 ParsedPliImp::writeGeometricTransformationTag( if (objectOffset > (unsigned int)maxval) maxval = (int)objectOffset; getLongValFromFloat(tag->m_affine.a11, intVal[0], decVal[0]); - if (intVal[0] < minval) minval = (int)intVal[0]; - if (intVal[0] > maxval) maxval = (int)intVal[0]; + if (intVal[0] < minval) minval = (int)intVal[0]; + if (intVal[0] > maxval) maxval = (int)intVal[0]; if (decVal[0] > (unsigned int)maxval) maxval = (int)decVal[0]; getLongValFromFloat(tag->m_affine.a12, intVal[1], decVal[1]); if (decVal[1] > (unsigned int)maxval) maxval = (int)decVal[1]; - if (intVal[1] < minval) minval = (int)intVal[1]; - if (intVal[1] > maxval) maxval = (int)intVal[1]; + if (intVal[1] < minval) minval = (int)intVal[1]; + if (intVal[1] > maxval) maxval = (int)intVal[1]; getLongValFromFloat(tag->m_affine.a13, intVal[2], decVal[2]); if (decVal[2] > (unsigned int)maxval) maxval = (int)decVal[2]; - if (intVal[2] < minval) minval = (int)intVal[2]; - if (intVal[2] > maxval) maxval = (int)intVal[2]; + if (intVal[2] < minval) minval = (int)intVal[2]; + if (intVal[2] > maxval) maxval = (int)intVal[2]; getLongValFromFloat(tag->m_affine.a21, intVal[3], decVal[3]); if (decVal[3] > (unsigned int)maxval) maxval = (int)decVal[3]; - if (intVal[3] < minval) minval = (int)intVal[3]; - if (intVal[3] > maxval) maxval = (int)intVal[3]; + if (intVal[3] < minval) minval = (int)intVal[3]; + if (intVal[3] > maxval) maxval = (int)intVal[3]; getLongValFromFloat(tag->m_affine.a22, intVal[4], decVal[4]); if (decVal[4] > (unsigned int)maxval) maxval = (int)decVal[4]; - if (intVal[4] < minval) minval = (int)intVal[4]; - if (intVal[4] > maxval) maxval = (int)intVal[4]; + if (intVal[4] < minval) minval = (int)intVal[4]; + if (intVal[4] > maxval) maxval = (int)intVal[4]; getLongValFromFloat(tag->m_affine.a23, intVal[5], decVal[5]); if (decVal[5] > (unsigned int)maxval) maxval = (int)decVal[5]; - if (intVal[5] < minval) minval = (int)intVal[5]; - if (intVal[5] > maxval) maxval = (int)intVal[5]; + if (intVal[5] < minval) minval = (int)intVal[5]; + if (intVal[5] > maxval) maxval = (int)intVal[5]; setDynamicTypeBytesNum(minval, maxval); @@ -2479,11 +2541,11 @@ TUINT32 ParsedPliImp::writeDoublePairTag(DoublePairTag *tag) { getLongValFromFloat(tag->m_first, xIntVal, xDecVal); getLongValFromFloat(tag->m_second, yIntVal, yDecVal); - if (xIntVal < minval) minval = (int)xIntVal; - if (xIntVal > maxval) maxval = (int)xIntVal; + if (xIntVal < minval) minval = (int)xIntVal; + if (xIntVal > maxval) maxval = (int)xIntVal; if ((int)xDecVal > maxval) maxval = (int)xDecVal; - if (yIntVal < minval) minval = (int)yIntVal; - if (yIntVal > maxval) maxval = (int)yIntVal; + if (yIntVal < minval) minval = (int)yIntVal; + if (yIntVal > maxval) maxval = (int)yIntVal; if ((int)yDecVal > maxval) maxval = (int)yDecVal; setDynamicTypeBytesNum(minval, maxval); @@ -2635,10 +2697,16 @@ void ParsedPli::getVersion(UINT &majorVersionNumber, /*=====================================================================*/ void ParsedPli::setVersion(UINT majorVersionNumber, UINT minorVersionNumber) { - if (imp->m_versionLocked) return; + if (imp->m_versionLocked) { + // accept only when settings higher versions + if ((imp->m_majorVersionNumber > majorVersionNumber) || + (imp->m_majorVersionNumber == majorVersionNumber && + imp->m_minorVersionNumber >= minorVersionNumber)) + return; + } if (majorVersionNumber >= 120) imp->m_versionLocked = true; - imp->m_majorVersionNumber = majorVersionNumber; - imp->m_minorVersionNumber = minorVersionNumber; + imp->m_majorVersionNumber = majorVersionNumber; + imp->m_minorVersionNumber = minorVersionNumber; } /*=====================================================================*/ diff --git a/toonz/sources/image/pli/tiio_pli.cpp b/toonz/sources/image/pli/tiio_pli.cpp index 311e982..4a44841 100644 --- a/toonz/sources/image/pli/tiio_pli.cpp +++ b/toonz/sources/image/pli/tiio_pli.cpp @@ -160,7 +160,7 @@ void buildPalette(ParsedPli *pli, const TImageP img) { assert(vPalette->getPageCount()); std::vector pageNames(vPalette->getPageCount()); - for (i = 0; i < pageNames.size(); i++) + for (i = 0; i < pageNames.size(); i++) pageNames[i] = TStyleParam(::to_string(vPalette->getPage(i)->getName())); StyleTag *pageNamesTag = new StyleTag(0, 0, pageNames.size(), pageNames.data()); @@ -414,18 +414,18 @@ TImageP TImageReaderPli::doLoad() { } // switch(groupTag->m_object[j]->m_type) } // for (i=0; im_numObjects; i++) -//} // try + //} // try -// catch(...) // cosi' e' inutile o raccolgo qualcosa prima di rilanciare o lo -// elimino -//{ -// throw; -// } + // catch(...) // cosi' e' inutile o raccolgo qualcosa prima di rilanciare o lo + // elimino + //{ + // throw; + // } -// if (regionsComputed) //WARNING !!! la seedFill mette il flag a ValidRegion a -// TRUE -// outVectImage->seedFill(); //le vecchie immagini hanno il seed -// (version<3.1) + // if (regionsComputed) //WARNING !!! la seedFill mette il flag a ValidRegion + // a TRUE + // outVectImage->seedFill(); //le vecchie immagini hanno il seed + // (version<3.1) #ifdef _DEBUG outVectImage->checkIntersections(); @@ -564,6 +564,9 @@ solo nel costruttore) PliTag *tag = new PrecisionScaleTag(precisionScale); tags.push_back((PliObjectTag *)tag); } + + // update the format version if multiple suffixes is supported0 + if (!TFilePath::useStandard()) pli->setVersion(150, 0); // Store the auto close tolerance double pliTolerance = m_lwp->m_pli->getAutocloseTolerance(); // write the tag if the frame's tolerance has been changed or @@ -744,7 +747,7 @@ TPalette *readPalette(GroupTag *paletteTag, int majorVersion, // caricarli! std::vector params(styleTag->m_numParams); - for (int j = 0; j < styleTag->m_numParams; j++) + for (int j = 0; j < styleTag->m_numParams; j++) params[j] = styleTag->m_param[j]; PliInputStream chan(¶ms, majorVersion, minorVersion); diff --git a/toonz/sources/image/sprite/tiio_sprite.cpp b/toonz/sources/image/sprite/tiio_sprite.cpp index 1300bdf..353fc9c 100644 --- a/toonz/sources/image/sprite/tiio_sprite.cpp +++ b/toonz/sources/image/sprite/tiio_sprite.cpp @@ -190,7 +190,7 @@ TLevelWriterSprite::~TLevelWriterSprite() { //----------------------------------------------------------- TImageWriterP TLevelWriterSprite::getFrameWriter(TFrameId fid) { - if (fid.getLetter() != 0) return TImageWriterP(0); + if (!fid.getLetter().isEmpty()) return TImageWriterP(0); int index = fid.getNumber(); TImageWriterSprite *iwg = new TImageWriterSprite(m_path, index, this); return TImageWriterP(iwg); @@ -265,9 +265,9 @@ void TLevelWriterSprite::save(const TImageP &img, int frameIndex) { m_top = t; m_bottom = b; } else { - if (l < m_left) m_left = l; - if (r > m_right) m_right = r; - if (t < m_top) m_top = t; + if (l < m_left) m_left = l; + if (r > m_right) m_right = r; + if (t < m_top) m_top = t; if (b > m_bottom) m_bottom = b; } QImage *newQi = new QImage(m_lx, m_ly, QImage::Format_ARGB32_Premultiplied); diff --git a/toonz/sources/image/tzl/tiio_tzl.cpp b/toonz/sources/image/tzl/tiio_tzl.cpp index 34c0134..b944dc7 100644 --- a/toonz/sources/image/tzl/tiio_tzl.cpp +++ b/toonz/sources/image/tzl/tiio_tzl.cpp @@ -25,8 +25,7 @@ TNZ_LITTLE_ENDIAN undefined !! #endif - const int CURRENT_VERSION = 14; -const int CREATOR_LENGTH = 40; + const int CREATOR_LENGTH = 40; namespace { @@ -40,6 +39,13 @@ char *reverse(char *buffer, int size) { } return buffer; } + +// switch the saving version according to the file path property +int currentVersion() { + if (TFilePath::useStandard()) return 14; + return 15; +} + } // namespace static int tfwrite(const char *data, const unsigned int count, FILE *f) { @@ -138,6 +144,8 @@ bool readVersion(FILE *chan, int &version) { version = 13; } else if (memcmp(magic, "TLV14", 5) == 0) { version = 14; + } else if (memcmp(magic, "TLV15", 5) == 0) { + version = 15; } else { return false; } @@ -162,7 +170,7 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable, if (!readVersion(chan, version)) return false; // read creator - if (version == 14) { + if (version >= 14) { char buffer[CREATOR_LENGTH + 1]; memset(buffer, 0, sizeof buffer); fread(&buffer, sizeof(char), CREATOR_LENGTH, chan); @@ -201,9 +209,18 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable, TFrameId oldFid(TFrameId::EMPTY_FRAME); for (int i = 0; i < (int)frameCount; i++) { TINT32 number, offs, length; - char letter; + QByteArray suffix; fread(&number, sizeof(TINT32), 1, chan); - fread(&letter, sizeof(char), 1, chan); + if (version >= 15) { + TINT32 suffixLength; + fread(&suffixLength, sizeof(TINT32), 1, chan); + suffix.resize(suffixLength); + fread(suffix.data(), sizeof(char), suffixLength, chan); + } else { + char letter; + fread(&letter, sizeof(char), 1, chan); + suffix = QByteArray(&letter, 1); + } fread(&offs, sizeof(TINT32), 1, chan); if (version >= 12) fread(&length, sizeof(TINT32), 1, chan); @@ -215,7 +232,7 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable, // std::cout << "#" << i << std::hex << " n 0x" << number //<< " l 0x" << letter << " o 0x" << offs << std::dec << std::endl; - TFrameId fid(number, letter); + TFrameId fid(number, QString::fromUtf8(suffix)); // assert(i==0 || oldFid= 12) { @@ -241,9 +258,18 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable, for (int i = 0; i < (int)frameCount; i++) { TINT32 number, thumbnailOffs, thumbnailLength; - char letter; + QByteArray suffix; fread(&number, sizeof(TINT32), 1, chan); - fread(&letter, sizeof(char), 1, chan); + if (version >= 15) { + TINT32 suffixLength; + fread(&suffixLength, sizeof(TINT32), 1, chan); + suffix.resize(suffixLength); + fread(suffix.data(), sizeof(char), suffixLength, chan); + } else { + char letter; + fread(&letter, sizeof(char), 1, chan); + suffix = QByteArray(&letter, 1); + } fread(&thumbnailOffs, sizeof(TINT32), 1, chan); fread(&thumbnailLength, sizeof(TINT32), 1, chan); @@ -252,7 +278,7 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable, thumbnailOffs = swapTINT32(thumbnailOffs); thumbnailLength = swapTINT32(thumbnailLength); #endif - TFrameId fid(number, letter); + TFrameId fid(number, QString::fromUtf8(suffix)); iconOffsTable[fid] = TzlChunk(thumbnailOffs, thumbnailLength); } } @@ -460,7 +486,7 @@ void TLevelWriterTzl::buildFreeChunksTable() { // dati relativi alle immagini if (m_version == 13) curPos = 6 * sizeof(TINT32) + 4 * sizeof(char) + 8 * sizeof(char); - else if (m_version == 14) + else if (m_version >= 14) curPos = 6 * sizeof(TINT32) + 4 * sizeof(char) + 8 * sizeof(char) + CREATOR_LENGTH * sizeof(char); else @@ -495,7 +521,7 @@ TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info) , m_palette(0) , m_res(0, 0) , m_exists(false) - , m_version(CURRENT_VERSION) + , m_version(currentVersion()) , m_updatedIconsSize(false) , m_currentIconSize(0, 0) , m_iconSize(TDimension(80, 60)) @@ -506,13 +532,14 @@ TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info) m_path = path; m_palettePath = path.withNoFrame().withType("tpl"); TFileStatus fs(path); - m_magic = "TLV14B1a"; // actual version + m_magic = (m_version == 14) ? "TLV14B1a" : "TLV15B1a"; // actual version erasedFrame = false; // version TLV10B1a: first version // version TLV11B1a: added frameIds // version TLV12B1a: incremental writings // version TLV13B1a: added thumbnails - // version TLV15B1a: add creator string (fixed size = CREATOR_LENGTH char) + // version TLV14B1a: add creator string (fixed size = CREATOR_LENGTH char) + // version TLV15B1a: support multiple suffixes if (fs.doesExist()) { // if (!fs.isWritable()) @@ -530,7 +557,7 @@ TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info) if (m_version >= 12) buildFreeChunksTable(); m_headerWritten = true; m_exists = true; - if (m_version == 14) + if (m_version >= 14) m_frameCountPos = 8 + CREATOR_LENGTH + 3 * sizeof(TINT32); else m_frameCountPos = 8 + 3 * sizeof(TINT32); @@ -555,9 +582,9 @@ TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info) //------------------------------------------------------------------- TLevelWriterTzl::~TLevelWriterTzl() { - if (m_version < CURRENT_VERSION) { + if (m_version < currentVersion()) { if (!convertToLatestVersion()) return; - assert(m_version == CURRENT_VERSION); + assert(m_version == currentVersion()); } delete m_codec; @@ -573,13 +600,18 @@ TLevelWriterTzl::~TLevelWriterTzl() { TzlOffsetMap::iterator it = m_frameOffsTable.begin(); for (; it != m_frameOffsTable.end(); ++it) { - TFrameId fid = it->first; - TINT32 num = fid.getNumber(); - char letter = fid.getLetter(); - TINT32 offs = it->second.m_offs; - TINT32 length = it->second.m_length; + TFrameId fid = it->first; + TINT32 num = fid.getNumber(); + QByteArray suffix = fid.getLetter().toUtf8(); + TINT32 offs = it->second.m_offs; + TINT32 length = it->second.m_length; tfwrite(&num, 1, m_chan); - tfwrite(&letter, 1, m_chan); + if (m_version >= 15) { // write the suffix length before data + TINT32 suffixLength = suffix.size(); + tfwrite(&suffixLength, 1, m_chan); + tfwrite(suffix.constData(), suffixLength, m_chan); + } else // write only the first byte + tfwrite(suffix.constData(), 1, m_chan); tfwrite(&offs, 1, m_chan); tfwrite(&length, 1, m_chan); } @@ -593,11 +625,16 @@ TLevelWriterTzl::~TLevelWriterTzl() { for (; iconIt != m_iconOffsTable.end(); ++iconIt) { TFrameId fid = iconIt->first; TINT32 num = fid.getNumber(); - char letter = fid.getLetter(); + QByteArray suffix = fid.getLetter().toUtf8(); TINT32 thumbnailOffs = iconIt->second.m_offs; TINT32 thumbnailLength = iconIt->second.m_length; tfwrite(&num, 1, m_chan); - tfwrite(&letter, 1, m_chan); + if (m_version >= 15) { // write the suffix length before data + TINT32 suffixLength = suffix.size(); + tfwrite(&suffixLength, 1, m_chan); + tfwrite(suffix.constData(), suffixLength, m_chan); + } else // write only the first byte + tfwrite(suffix.constData(), 1, m_chan); tfwrite(&thumbnailOffs, 1, m_chan); tfwrite(&thumbnailLength, 1, m_chan); } @@ -774,7 +811,7 @@ bool TLevelWriterTzl::convertToLatestVersion() { if (!m_chan) return false; if (!writeVersionAndCreator(m_chan, m_magic, m_creator)) return false; m_creatorWritten = true; - m_version = CURRENT_VERSION; + m_version = currentVersion(); TLevelReaderP lr(tempPath); if (!lr) return false; TLevelP level = lr->loadInfo(); @@ -798,13 +835,18 @@ bool TLevelWriterTzl::convertToLatestVersion() { TzlOffsetMap::iterator it2 = m_frameOffsTable.begin(); for (; it2 != m_frameOffsTable.end(); ++it2) { - TFrameId fid = it2->first; - TINT32 num = fid.getNumber(); - char letter = fid.getLetter(); - TINT32 offs = it2->second.m_offs; - TINT32 length = it2->second.m_length; + TFrameId fid = it2->first; + TINT32 num = fid.getNumber(); + QByteArray suffix = fid.getLetter().toUtf8(); + TINT32 offs = it2->second.m_offs; + TINT32 length = it2->second.m_length; tfwrite(&num, 1, m_chan); - tfwrite(&letter, 1, m_chan); + if (m_version >= 15) { // write the suffix length before data + TINT32 suffixLength = suffix.size(); + tfwrite(&suffixLength, 1, m_chan); + tfwrite(suffix.constData(), suffixLength, m_chan); + } else // write only the first byte + tfwrite(suffix.constData(), 1, m_chan); tfwrite(&offs, 1, m_chan); tfwrite(&length, 1, m_chan); } @@ -816,11 +858,16 @@ bool TLevelWriterTzl::convertToLatestVersion() { for (; iconIt != m_iconOffsTable.end(); ++iconIt) { TFrameId fid = iconIt->first; TINT32 num = fid.getNumber(); - char letter = fid.getLetter(); + QByteArray suffix = fid.getLetter().toUtf8(); TINT32 thumbnailOffs = iconIt->second.m_offs; TINT32 thumbnailLength = iconIt->second.m_length; tfwrite(&num, 1, m_chan); - tfwrite(&letter, 1, m_chan); + if (m_version >= 15) { // write the suffix length before data + TINT32 suffixLength = suffix.size(); + tfwrite(&suffixLength, 1, m_chan); + tfwrite(suffix.constData(), suffixLength, m_chan); + } else // write only the first byte + tfwrite(suffix.constData(), 1, m_chan); tfwrite(&thumbnailOffs, 1, m_chan); tfwrite(&thumbnailLength, 1, m_chan); } @@ -856,7 +903,7 @@ bool TLevelWriterTzl::convertToLatestVersion() { m_headerWritten = true; m_exists = true; m_frameCountPos = 8 + CREATOR_LENGTH + 3 * sizeof(TINT32); - assert(m_version == CURRENT_VERSION); + assert(m_version == currentVersion()); if (!m_renumberTable.empty()) renumberFids(m_renumberTable); return true; } @@ -867,9 +914,9 @@ void TLevelWriterTzl::saveImage(const TImageP &img, const TFrameId &_fid, if (!m_chan) return; // se il file è di una versione precedente allora lo converto prima - if (m_version < CURRENT_VERSION) { + if (m_version < currentVersion()) { if (!convertToLatestVersion()) return; - assert(m_version == CURRENT_VERSION); + assert(m_version == currentVersion()); } if (!m_updatedIconsSize && m_exists) @@ -1348,7 +1395,7 @@ float TLevelWriterTzl::getFreeSpace() { if (m_version == 13) totalSpace = m_offsetTablePos - 6 * sizeof(TINT32) - 4 * sizeof(char) - 8 * sizeof(char); - else if (m_version == 14) + else if (m_version >= 14) totalSpace = m_offsetTablePos - 6 * sizeof(TINT32) - 4 * sizeof(char) - 8 * sizeof(char) - CREATOR_LENGTH * sizeof(char); assert(totalSpace > 0); @@ -2285,6 +2332,10 @@ TImageP TImageReaderTzl::load() { if (!m_lrp->m_frameOffsTable.empty() && !m_lrp->m_iconOffsTable.empty()) image = load14(); break; + case 15: // same as v14 + if (!m_lrp->m_frameOffsTable.empty() && !m_lrp->m_iconOffsTable.empty()) + image = load14(); + break; default: image = load10(); } diff --git a/toonz/sources/include/tfilepath.h b/toonz/sources/include/tfilepath.h index 3004db6..72700ae 100644 --- a/toonz/sources/include/tfilepath.h +++ b/toonz/sources/include/tfilepath.h @@ -16,7 +16,7 @@ #define DVVAR DV_IMPORT_VAR #endif -class QString; +#include //----------------------------------------------------------------------------- /* @@ -28,8 +28,8 @@ class QString; //! figures and, in case, by a character (necessary for added frames) class DVAPI TFrameId { int m_frame; - char m_letter; // serve per i frame "aggiunti" del tipo pippo.0001a.tzp => - // f=1 c='a' + QString m_letter; // serve per i frame "aggiunti" del tipo pippo.0001a.tzp => + // f=1 c='a' int m_zeroPadding; char m_startSeqInd; @@ -50,13 +50,13 @@ public: }; // pippo_1.tif TFrameId(int f = EMPTY_FRAME) - : m_frame(f), m_letter(0), m_zeroPadding(4), m_startSeqInd('.') {} - TFrameId(int f, char c) - : m_frame(f), m_letter(c), m_zeroPadding(4), m_startSeqInd('.') {} - TFrameId(int f, char c, int p) - : m_frame(f), m_letter(c), m_zeroPadding(p), m_startSeqInd('.') {} - TFrameId(int f, char c, int p, char s) - : m_frame(f), m_letter(c), m_zeroPadding(p), m_startSeqInd(s) {} + : m_frame(f), m_letter(""), m_zeroPadding(4), m_startSeqInd('.') {} + TFrameId(int f, char c, int p = 4, char s = '.') + : m_frame(f), m_zeroPadding(p), m_startSeqInd(s) { + m_letter = (c == '\0') ? "" : QString(c); + } + TFrameId(int f, QString str, int p = 4, char s = '.') + : m_frame(f), m_letter(str), m_zeroPadding(p), m_startSeqInd(s) {} inline bool operator==(const TFrameId &f) const { return f.m_frame == m_frame && f.m_letter == m_letter; @@ -66,7 +66,8 @@ public: } inline bool operator<(const TFrameId &f) const { return (m_frame < f.m_frame || - (m_frame == f.m_frame && m_letter < f.m_letter)); + (m_frame == f.m_frame && + QString::localeAwareCompare(m_letter, f.m_letter) < 0)); } inline bool operator>(const TFrameId &f) const { return f < *this; } inline bool operator>=(const TFrameId &f) const { return !operator<(f); } @@ -89,7 +90,7 @@ public: // operator string() const; std::string expand(FrameFormat format = FOUR_ZEROS) const; int getNumber() const { return m_frame; } - char getLetter() const { return m_letter; } + QString getLetter() const { return m_letter; } void setZeroPadding(int p) { m_zeroPadding = p; } int getZeroPadding() const { return m_zeroPadding; } @@ -132,7 +133,23 @@ inline std::ostream &operator<<(std::ostream &out, const TFrameId &f) { constructor.*/ class DVAPI TFilePath { static bool m_underscoreFormatAllowed; + + // specifies file path condition for sequential image for each project. + // See filepathproperties.h + static bool m_useStandard; + static bool m_acceptNonAlphabetSuffix; + static int m_letterCountForSuffix; + std::wstring m_path; + + struct TFilePathInfo { + QString parentDir; // with slash + QString levelName; + QChar sepChar; // either "." or "_" + TFrameId fId; + QString extension; + }; + void setPath(std::wstring path); public: @@ -142,6 +159,23 @@ public: m_underscoreFormatAllowed = state; } + // called from TProjectManager::getCurrentProject() and + // ProjectPopup::updateProjectFromFields + // returns true if something changed + static bool setFilePathProperties(bool useStandard, bool acceptNonAlphaSuffix, + int letterCountForSuffix) { + if (m_useStandard == useStandard && + m_acceptNonAlphabetSuffix == acceptNonAlphaSuffix && + m_letterCountForSuffix == letterCountForSuffix) + return false; + m_useStandard = useStandard; + m_acceptNonAlphabetSuffix = acceptNonAlphaSuffix; + m_letterCountForSuffix = letterCountForSuffix; + return true; + } + static bool useStandard() { return m_useStandard; } + static QString fidRegExpStr(); + /*!This constructor creates a string removing redundances ('//', './',etc.) and final slashes, correcting (redressing) the "twisted" slashes. @@ -191,6 +225,7 @@ If the path is ":" a slash will be added*/ std::string getType() const { return getUndottedType(); } // ritorna l'estensione SENZA PUNTO + /*!Returns the base filename (no extension, no dots, no slash)*/ std::string getName() const; // noDot! noSlash! std::wstring getWideName() const; // noDot! noSlash! @@ -274,6 +309,8 @@ type is a string that indicate the filename extension(ex:. bmp or .bmp)*/ // '/a/b/c.txt' => head='a' tail='b/c.txt' void split(std::wstring &head, TFilePath &tail) const; + + TFilePathInfo analyzePath() const; }; //----------------------------------------------------------------------------- diff --git a/toonz/sources/include/toonz/filepathproperties.h b/toonz/sources/include/toonz/filepathproperties.h new file mode 100644 index 0000000..4c61ac9 --- /dev/null +++ b/toonz/sources/include/toonz/filepathproperties.h @@ -0,0 +1,49 @@ +#pragma once + +#ifndef FILEPATHPROPERTIES_H +#define FILEPATHPROPERTIES_H + +#include "tcommon.h" + +#undef DVAPI +#undef DVVAR +#ifdef TOONZLIB_EXPORTS +#define DVAPI DV_EXPORT_API +#define DVVAR DV_EXPORT_VAR +#else +#define DVAPI DV_IMPORT_API +#define DVVAR DV_IMPORT_VAR +#endif +//============================================================================= +// forward declarations +class TIStream; +class TOStream; + +//============================================================================= +// FilePathProperties +// This class defines file path condition for sequential image level + +class DVAPI FilePathProperties { + bool m_useStandard; + bool m_acceptNonAlphabetSuffix; + int m_letterCountForSuffix; + +public: + FilePathProperties(); + + bool useStandard() { return m_useStandard; } + void setUseStandard(bool on) { m_useStandard = on; } + + bool acceptNonAlphabetSuffix() { return m_acceptNonAlphabetSuffix; } + void setAcceptNonAlphabetSuffix(bool on) { m_acceptNonAlphabetSuffix = on; } + + int letterCountForSuffix() { return m_letterCountForSuffix; } + void setLetterCountForSuffix(int val) { m_letterCountForSuffix = val; } + + void saveData(TOStream& os) const; + void loadData(TIStream& is); + + bool isDefault(); +}; + +#endif \ No newline at end of file diff --git a/toonz/sources/include/toonz/tproject.h b/toonz/sources/include/toonz/tproject.h index d8ec955..7683018 100644 --- a/toonz/sources/include/toonz/tproject.h +++ b/toonz/sources/include/toonz/tproject.h @@ -9,6 +9,7 @@ class ToonzScene; class TSceneProperties; +class FilePathProperties; #undef DVAPI #undef DVVAR @@ -27,6 +28,8 @@ class DVAPI TProject final : public TSmartObject { std::map m_useScenePathFlags; TSceneProperties *m_sprop; + FilePathProperties *m_fpProp; + public: // default folders names static const std::string Inputs; @@ -68,6 +71,8 @@ public: void setSceneProperties(const TSceneProperties &sprop); const TSceneProperties &getSceneProperties() const { return *m_sprop; } + FilePathProperties *getFilePathProperties() const { return m_fpProp; } + //????????????????????????????????????????????? void setUseScenePath(std::string folderName, bool on); //????????????????????????????????????????????? diff --git a/toonz/sources/include/toonz/txsheet.h b/toonz/sources/include/toonz/txsheet.h index 5989d8a..23abc7b 100644 --- a/toonz/sources/include/toonz/txsheet.h +++ b/toonz/sources/include/toonz/txsheet.h @@ -438,8 +438,9 @@ frame duplication. // cutomized exposseLevel used from LoadLevel command int exposeLevel(int row, int col, TXshLevel *xl, std::vector &fIds_, - int xFrom = -1, int xTo = -1, int step = -1, int inc = -1, - int frameCount = -1, bool doesFileActuallyExist = true); + TFrameId xFrom = TFrameId(), TFrameId xTo = TFrameId(), + int step = -1, int inc = -1, int frameCount = -1, + bool doesFileActuallyExist = true); /*! Exposes level \b \e xl \b \e fids in xsheet starting from cell identified * by \b \e row and \b \e col. diff --git a/toonz/sources/tnztools/tool.cpp b/toonz/sources/tnztools/tool.cpp index 503035e..1468a64 100644 --- a/toonz/sources/tnztools/tool.cpp +++ b/toonz/sources/tnztools/tool.cpp @@ -102,8 +102,8 @@ TFrameId getNewFrameId(TXshSimpleLevel *sl, int row) { TFrameId fid(row + 1); if (sl->isFid(fid)) { fid = TFrameId(fid.getNumber(), 'a'); - while (fid.getLetter() < 'z' && sl->isFid(fid)) - fid = TFrameId(fid.getNumber(), fid.getLetter() + 1); + while (fid.getLetter().toUtf8().at(0) < 'z' && sl->isFid(fid)) + fid = TFrameId(fid.getNumber(), fid.getLetter().toUtf8().at(0) + 1); } return fid; } @@ -123,9 +123,15 @@ TFrameId getDesiredFId(TXshCellColumn *column, int r0, TXshSimpleLevel *sl, if (neighborFId.isEmptyFrame()) neighborFId = tmpFId; if (maxFId < tmpFId) maxFId = tmpFId; } - if (maxFId.getLetter() && maxFId.getLetter() < 'z' && maxFId == neighborFId) - return TFrameId(maxFId.getNumber(), maxFId.getLetter() + 1); - else + + QByteArray suffix = maxFId.getLetter().toUtf8(); + // increment letter + if (suffix.size() == 1 && + ((suffix.at(0) >= 'A' && suffix.at(0) < 'Z') || + (suffix.at(0) >= 'a' && suffix.at(0) < 'z')) && + maxFId == neighborFId) { + return TFrameId(maxFId.getNumber(), suffix.at(0) + 1); + } else return TFrameId(maxFId.getNumber() + 1); } diff --git a/toonz/sources/tnztools/toolutils.cpp b/toonz/sources/tnztools/toolutils.cpp index db4032f..6038269 100644 --- a/toonz/sources/tnztools/toolutils.cpp +++ b/toonz/sources/tnztools/toolutils.cpp @@ -1819,6 +1819,15 @@ bool ToolUtils::doUpdateXSheet(TXshSimpleLevel *sl, bool ToolUtils::renumberForInsertFId(TXshSimpleLevel *sl, const TFrameId &fid, const TFrameId &maxFid, TXsheet *xsh) { + auto getNextLetter = [](const QString &letter) { + if (letter.isEmpty()) return QString('a'); + if (letter == 'z' || letter == 'Z') return QString(); + QByteArray byteArray = letter.toUtf8(); + // return incrementing the last letter + byteArray.data()[byteArray.size() - 1]++; + return QString::fromUtf8(byteArray); + }; + std::vector fids; std::vector oldFrames; sl->getFids(oldFrames); @@ -1832,10 +1841,10 @@ bool ToolUtils::renumberForInsertFId(TXshSimpleLevel *sl, const TFrameId &fid, for (auto itr = fidsSet.upper_bound(maxFid); itr != fidsSet.end(); ++itr) { if (*itr > tmpFid) break; fIdsToBeShifted.push_back(*itr); - if (fid.getLetter()) { - if ((*itr).getLetter() < 'z') - tmpFid = TFrameId((*itr).getNumber(), - ((*itr).getLetter()) ? (*itr).getLetter() + 1 : 'a'); + if (!fid.getLetter().isEmpty()) { + QString nextLetter = getNextLetter((*itr).getLetter()); + if (!nextLetter.isEmpty()) + tmpFid = TFrameId((*itr).getNumber(), nextLetter); else tmpFid = TFrameId((*itr).getNumber() + 1); } else @@ -1846,11 +1855,10 @@ bool ToolUtils::renumberForInsertFId(TXshSimpleLevel *sl, const TFrameId &fid, for (TFrameId &tmpFid : fids) { if (fIdsToBeShifted.contains(tmpFid)) { - if (fid.getLetter()) { - if (tmpFid.getLetter() < 'z') - tmpFid = - TFrameId(tmpFid.getNumber(), - (tmpFid.getLetter()) ? tmpFid.getLetter() + 1 : 'a'); + if (!fid.getLetter().isEmpty()) { + QString nextLetter = getNextLetter(tmpFid.getLetter()); + if (!nextLetter.isEmpty()) + tmpFid = TFrameId(tmpFid.getNumber(), nextLetter); else tmpFid = TFrameId(tmpFid.getNumber() + 1); } else diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index bd8f000..c55ba8b 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -2725,6 +2725,13 @@ static void dRenumberCells(int col, int r0, int r1) { levelsTable[sl].push_back(std::make_pair(oldFid, newFid)); } } + auto getNextLetter = [](const QString &letter) { + if (letter.isEmpty()) return QString('a'); + QByteArray byteArray = letter.toUtf8(); + // return incrementing the last letter + byteArray.data()[byteArray.size() - 1]++; + return QString::fromUtf8(byteArray); + }; // Ensure renumber consistency in case some destination fid would overwrite // some unrenumbered fid in the level @@ -2734,8 +2741,7 @@ static void dRenumberCells(int col, int r0, int r1) { if (cellsMap.find(it->second) == cellsMap.end() && it->first.getSimpleLevel()->isFid(it->second.getFrameId())) { TFrameId &fid = it->second.m_frameId; - fid = TFrameId(fid.getNumber(), - fid.getLetter() ? fid.getLetter() + 1 : 'a', + fid = TFrameId(fid.getNumber(), getNextLetter(fid.getLetter()), fid.getZeroPadding(), fid.getStartSeqInd()); } } @@ -2923,8 +2929,8 @@ static void createNewDrawing(TXsheet *xsh, int row, int col, TFrameId fid(row + 1); if (sl->isFid(fid)) { fid = TFrameId(fid.getNumber(), 'a'); - while (fid.getLetter() < 'z' && sl->isFid(fid)) - fid = TFrameId(fid.getNumber(), fid.getLetter() + 1); + while (fid.getLetter().toUtf8().at(0) < 'z' && sl->isFid(fid)) + fid = TFrameId(fid.getNumber(), fid.getLetter().toUtf8().at(0) + 1); } // add the new frame sl->setFrame(fid, sl->createEmptyFrame()); diff --git a/toonz/sources/toonz/exportxsheetpdf.cpp b/toonz/sources/toonz/exportxsheetpdf.cpp index 7290b6b..4c8f55d 100644 --- a/toonz/sources/toonz/exportxsheetpdf.cpp +++ b/toonz/sources/toonz/exportxsheetpdf.cpp @@ -874,7 +874,8 @@ void XSheetPDFTemplate::drawCellNumber(QPainter& painter, QRect rect, str = getFrameNumberWithLetters(cell.m_frameId.getNumber()); } else { str = QString::number(cell.m_frameId.getNumber()); - if (cell.m_frameId.getLetter() != '\0') str += cell.m_frameId.getLetter(); + if (!cell.m_frameId.getLetter().isEmpty()) + str += cell.m_frameId.getLetter(); } painter.drawText(rect, Qt::AlignCenter, str); } diff --git a/toonz/sources/toonz/filebrowserpopup.cpp b/toonz/sources/toonz/filebrowserpopup.cpp index d474ab1..f276322 100644 --- a/toonz/sources/toonz/filebrowserpopup.cpp +++ b/toonz/sources/toonz/filebrowserpopup.cpp @@ -15,6 +15,11 @@ #include "convertpopup.h" #include "matchline.h" #include "colormodelbehaviorpopup.h" +#if defined(x64) +#include "penciltestpopup.h" // FrameNumberLineEdit +#else +#include "penciltestpopup_qt.h" +#endif // TnzQt includes #include "toonzqt/gutil.h" @@ -683,8 +688,8 @@ LoadLevelPopup::LoadLevelPopup() QPushButton *showSubsequenceButton = createShowButton(this); QLabel *subsequenceLabel = new QLabel(tr("Load Subsequence Level"), this); m_subsequenceFrame = new QFrame(this); - m_fromFrame = new DVGui::IntLineEdit(this, 1, 1); - m_toFrame = new DVGui::IntLineEdit(this, 1, 1); + m_fromFrame = new FrameNumberLineEdit(this, TFrameId(1)); + m_toFrame = new FrameNumberLineEdit(this, TFrameId(1)); //----Arrangement in Xsheet m_arrLvlPropWidget = new QWidget(this); @@ -692,8 +697,8 @@ LoadLevelPopup::LoadLevelPopup() QLabel *arrangementLabel = new QLabel(tr("Level Settings & Arrangement in Xsheet"), this); m_arrangementFrame = new QFrame(this); - m_xFrom = new DVGui::IntLineEdit(this, 1, 1); - m_xTo = new DVGui::IntLineEdit(this, 1, 1); + m_xFrom = new FrameNumberLineEdit(this, TFrameId(1)); + m_xTo = new FrameNumberLineEdit(this, TFrameId(1)); m_stepCombo = new QComboBox(this); m_incCombo = new QComboBox(this); m_posFrom = new DVGui::IntLineEdit(this, 1, 1); @@ -944,12 +949,12 @@ void LoadLevelPopup::onNameSetEditted() { } else { m_notExistLabel->show(); - m_fromFrame->setText("1"); - m_toFrame->setText("1"); + m_fromFrame->setValue(TFrameId(1)); + m_toFrame->setValue(TFrameId(1)); m_subsequenceFrame->setEnabled(true); - m_xFrom->setText("1"); - m_xTo->setText("1"); + m_xFrom->setValue(TFrameId(1)); + m_xTo->setValue(TFrameId(1)); m_levelName->setText(QString::fromStdString(path.getName())); @@ -974,26 +979,39 @@ void LoadLevelPopup::updatePosTo() { return; } - int xFrom = m_xFrom->text().toInt(); - int xTo = m_xTo->text().toInt(); + TFrameId xFrom = m_xFrom->getValue(); + TFrameId xTo = m_xTo->getValue(); int frameLength; bool isScene = (QString::fromStdString(fp.getType()) == "tnz"); + if (isScene) { // scene does not consider frame suffixes + xFrom = TFrameId(xFrom.getNumber()); + xTo = TFrameId(xTo.getNumber()); + } + + auto frameLengthBetweenFIds = [&]() { + if (xFrom > xTo) return 0; + int ret = xTo.getNumber() - xFrom.getNumber() + 1; + if (!xTo.getLetter().isEmpty()) ret++; + return ret; + }; + //--- if loading the "missing" level if (m_notExistLabel->isVisible()) { int inc = m_incCombo->currentIndex(); if (inc == 0) // Inc = Auto { - frameLength = (xTo - xFrom + 1) * ((m_stepCombo->currentIndex() == 0) - ? 1 - : m_stepCombo->currentIndex()); + frameLength = + frameLengthBetweenFIds() * ((m_stepCombo->currentIndex() == 0) + ? 1 + : m_stepCombo->currentIndex()); } else // Inc =! Auto { int loopAmount; - loopAmount = tceil((double)(xTo - xFrom + 1) / (double)inc); + loopAmount = tceil((double)(frameLengthBetweenFIds()) / (double)inc); frameLength = loopAmount * ((m_stepCombo->currentIndex() == 0) ? inc : m_stepCombo->currentIndex()); @@ -1004,7 +1022,7 @@ void LoadLevelPopup::updatePosTo() { else if (m_incCombo->currentIndex() == 0) // Inc = Auto { if (isScene) { - frameLength = xTo - xFrom + 1; + frameLength = frameLengthBetweenFIds(); } else { std::vector fIds = getCurrentFIds(); //--- If loading the level with sequential files, reuse the list of @@ -1012,32 +1030,23 @@ void LoadLevelPopup::updatePosTo() { if (fIds.size() != 0) { if (m_stepCombo->currentIndex() == 0) // Step = Auto { + frameLength = 0; std::vector::iterator it; - int firstFrame = 0; - int lastFrame = 0; for (it = fIds.begin(); it != fIds.end(); it++) { - if (xFrom <= it->getNumber()) { - firstFrame = it->getNumber(); + if (xFrom <= *it && *it <= xTo) + frameLength++; + else if (xTo < *it) break; - } - } - for (it = fIds.begin(); it != fIds.end(); it++) { - if (it->getNumber() <= xTo) { - lastFrame = it->getNumber(); - } } - frameLength = lastFrame - firstFrame + 1; } else // Step != Auto { std::vector::iterator it; int loopAmount = 0; for (it = fIds.begin(); it != fIds.end(); it++) { - if (xFrom <= it->getNumber() && it->getNumber() <= xTo) - loopAmount++; + if (xFrom <= *it && *it <= xTo) loopAmount++; } frameLength = loopAmount * m_stepCombo->currentIndex(); } - } // loading another type of level such as tlv else { @@ -1050,29 +1059,20 @@ void LoadLevelPopup::updatePosTo() { if (m_stepCombo->currentIndex() == 0) // Step = Auto { + frameLength = 0; TLevel::Iterator it; - int firstFrame = 0; - int lastFrame = 0; for (it = level->begin(); it != level->end(); it++) { - if (xFrom <= it->first.getNumber()) { - firstFrame = it->first.getNumber(); + if (xFrom <= it->first && it->first <= xTo) + frameLength++; + else if (xTo < it->first) break; - } - } - for (it = level->begin(); it != level->end(); it++) { - if (it->first.getNumber() <= xTo) { - lastFrame = it->first.getNumber(); - } } - frameLength = lastFrame - firstFrame + 1; } else // Step != Auto { TLevel::Iterator it; int loopAmount = 0; for (it = level->begin(); it != level->end(); it++) { - if (xFrom <= it->first.getNumber() && - it->first.getNumber() <= xTo) - loopAmount++; + if (xFrom <= it->first && it->first <= xTo) loopAmount++; } frameLength = loopAmount * m_stepCombo->currentIndex(); } @@ -1086,7 +1086,7 @@ void LoadLevelPopup::updatePosTo() { else { int inc = m_incCombo->currentIndex(); int loopAmount; - loopAmount = tceil((double)(xTo - xFrom + 1) / (double)inc); + loopAmount = tceil((double)(frameLengthBetweenFIds()) / (double)inc); frameLength = loopAmount * ((m_stepCombo->currentIndex() == 0) ? inc : m_stepCombo->currentIndex()); @@ -1099,8 +1099,8 @@ void LoadLevelPopup::updatePosTo() { /*! if the from / to values in the subsequent box, update m_xFrom and m_xTo */ void LoadLevelPopup::onSubsequentFrameChanged() { - m_xFrom->setText(m_fromFrame->text()); - m_xTo->setText(m_toFrame->text()); + m_xFrom->setValue(m_fromFrame->getValue()); + m_xTo->setValue(m_toFrame->getValue()); updatePosTo(); } @@ -1168,9 +1168,9 @@ bool LoadLevelPopup::execute() { //---- SubSequent load // if loading the "missing" level if (m_notExistLabel->isVisible()) { - int firstFrameNumber = m_fromFrame->text().toInt(); - int lastFrameNumber = m_toFrame->text().toInt(); - setLoadingLevelRange(firstFrameNumber, lastFrameNumber); + TFrameId firstLoadingFId = m_fromFrame->getValue(); + TFrameId lastLoadingFId = m_toFrame->getValue(); + setLoadingLevelRange(firstLoadingFId, lastLoadingFId); } else if (m_subsequenceFrame->isEnabled() && m_subsequenceFrame->isVisible()) { std::vector fIds = getCurrentFIds(); @@ -1196,11 +1196,10 @@ bool LoadLevelPopup::execute() { return false; } } - int firstFrameNumber = m_fromFrame->text().toInt(); - int lastFrameNumber = m_toFrame->text().toInt(); - if (firstFrame.getNumber() != firstFrameNumber || - lastFrame.getNumber() != lastFrameNumber) - setLoadingLevelRange(firstFrameNumber, lastFrameNumber); + TFrameId firstLoadingFId = m_fromFrame->getValue(); + TFrameId lastLoadingFId = m_toFrame->getValue(); + if (firstFrame != firstLoadingFId || lastFrame != lastLoadingFId) + setLoadingLevelRange(firstLoadingFId, lastLoadingFId); } IoCmd::LoadResourceArguments args(fp); @@ -1213,20 +1212,27 @@ bool LoadLevelPopup::execute() { args.frameIdsSet.push_back(*getCurrentFIdsSet().begin()); else if (m_notExistLabel->isVisible()) { - int firstFrameNumber = m_fromFrame->text().toInt(); - int lastFrameNumber = m_toFrame->text().toInt(); + TFrameId firstLoadingFId = m_fromFrame->getValue(); + TFrameId lastLoadingFId = m_toFrame->getValue(); // putting the Fids in order to avoid LoadInfo later std::vector tmp_fids; - for (int i = firstFrameNumber; i <= lastFrameNumber; i++) { + int i = firstLoadingFId.getNumber(); + if (!firstLoadingFId.getLetter().isEmpty()) { + tmp_fids.push_back(firstLoadingFId); + i++; + } + for (; i <= lastLoadingFId.getNumber(); i++) { tmp_fids.push_back(TFrameId(i)); } + if (!lastLoadingFId.getLetter().isEmpty()) + tmp_fids.push_back(lastLoadingFId); args.frameIdsSet.push_back(tmp_fids); } - int xFrom = m_xFrom->text().toInt(); - if (xFrom) args.xFrom = xFrom; - int xTo = m_xTo->text().toInt(); - if (xTo) args.xTo = xTo; + TFrameId xFrom = m_xFrom->getValue(); + if (!xFrom.isEmptyFrame()) args.xFrom = xFrom; + TFrameId xTo = m_xTo->getValue(); + if (!xTo.isEmptyFrame()) args.xTo = xTo; args.levelName = m_levelName->text().toStdWString(); args.step = m_stepCombo->currentIndex(); @@ -1348,9 +1354,8 @@ void LoadLevelPopup::updateBottomGUI() { disableAll(); return; } else if (ext == "tpl") { - QString str; - m_fromFrame->setText(str.number(1)); - m_toFrame->setText(str.number(1)); + m_fromFrame->setText("1"); + m_toFrame->setText("1"); m_subsequenceFrame->setEnabled(false); m_xFrom->setText("1"); @@ -1396,13 +1401,12 @@ void LoadLevelPopup::updateBottomGUI() { return; } } - - m_fromFrame->setText(QString().number(firstFrame.getNumber())); - m_toFrame->setText(QString().number(lastFrame.getNumber())); + m_fromFrame->setValue(firstFrame); + m_toFrame->setValue(lastFrame); m_subsequenceFrame->setEnabled(true); - m_xFrom->setText(m_fromFrame->text()); - m_xTo->setText(m_toFrame->text()); + m_xFrom->setValue(firstFrame); + m_xTo->setValue(lastFrame); // if some option in the preferences is selected, load the level with // removing diff --git a/toonz/sources/toonz/filebrowserpopup.h b/toonz/sources/toonz/filebrowserpopup.h index 0d39271..a4e0f1a 100644 --- a/toonz/sources/toonz/filebrowserpopup.h +++ b/toonz/sources/toonz/filebrowserpopup.h @@ -32,6 +32,7 @@ class QPushButton; class QComboBox; class QGroupBox; class QCheckBox; +class FrameNumberLineEdit; namespace DVGui { class ColorField; @@ -266,11 +267,11 @@ class LoadLevelPopup final : public FileBrowserPopup { Q_OBJECT QFrame *m_subsequenceFrame; - DVGui::IntLineEdit *m_fromFrame, *m_toFrame; + FrameNumberLineEdit *m_fromFrame, *m_toFrame; QWidget *m_arrLvlPropWidget; QFrame *m_arrangementFrame; - DVGui::IntLineEdit *m_xFrom, *m_xTo; + FrameNumberLineEdit *m_xFrom, *m_xTo; QComboBox *m_stepCombo, *m_incCombo; DVGui::IntLineEdit *m_posFrom, *m_posTo; diff --git a/toonz/sources/toonz/filmstrip.cpp b/toonz/sources/toonz/filmstrip.cpp index fd6d3df..b39ef39 100644 --- a/toonz/sources/toonz/filmstrip.cpp +++ b/toonz/sources/toonz/filmstrip.cpp @@ -708,9 +708,9 @@ void FilmstripFrames::paintEvent(QPaintEvent *evt) { } // for sequential frame else { - char letter = fid.getLetter(); - text = QString::number(fid.getNumber()).rightJustified(4, '0') + - (letter != '\0' ? QString(letter) : ""); + QString letter = fid.getLetter(); + text = QString::number(fid.getNumber()).rightJustified(4, '0') + + (!letter.isEmpty() ? letter : ""); } p.drawText(tmp_frameRect.adjusted(0, 0, -3, 2), text, QTextOption(Qt::AlignRight | Qt::AlignBottom)); diff --git a/toonz/sources/toonz/filmstripcommand.cpp b/toonz/sources/toonz/filmstripcommand.cpp index ee607c4..04dbd78 100644 --- a/toonz/sources/toonz/filmstripcommand.cpp +++ b/toonz/sources/toonz/filmstripcommand.cpp @@ -1343,6 +1343,17 @@ public: int getHistoryType() override { return HistoryType::FilmStrip; } }; +QString getNextLetter(const QString &letter) { + // 空なら a を返す + if (letter.isEmpty()) return QString('a'); + // 1文字かつ z または Z ならEmptyを返す + if (letter == 'z' || letter == 'Z') return QString(); + QByteArray byteArray = letter.toUtf8(); + // それ以外の場合、最後の文字をとにかく1進めて返す + byteArray.data()[byteArray.size() - 1]++; + return QString::fromUtf8(byteArray); +}; + } // namespace //============================================================================= @@ -1386,10 +1397,10 @@ void FilmstripCmd::renumber( // make sure that srcFid has not been used. add a letter if this is needed if (tmp.count(tarFid) > 0) { do { - char letter = tarFid.getLetter(); - tarFid = TFrameId(tarFid.getNumber(), letter == 0 ? 'a' : letter + 1); - } while (tarFid.getLetter() <= 'z' && tmp.count(tarFid) > 0); - if (tarFid.getLetter() > 'z') { + tarFid = + TFrameId(tarFid.getNumber(), getNextLetter(tarFid.getLetter())); + } while (!tarFid.getLetter().isEmpty() && tmp.count(tarFid) > 0); + if (tarFid.getLetter().isEmpty()) { // todo: error message return; } @@ -2566,13 +2577,9 @@ void FilmstripCmd::renumberDrawing(TXshSimpleLevel *sl, const TFrameId &oldFid, if (it == fids.end()) return; TFrameId newFid = desiredNewFid; while (std::find(fids.begin(), fids.end(), newFid) != fids.end()) { - char letter = newFid.getLetter(); - if (letter == 'z') return; - if (letter == 0) - letter = 'a'; - else - letter++; - newFid = TFrameId(newFid.getNumber(), letter); + QString nextLetter = getNextLetter(newFid.getLetter()); + if (nextLetter.isEmpty()) return; + newFid = TFrameId(newFid.getNumber(), nextLetter); } *it = newFid; if (Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled()) { diff --git a/toonz/sources/toonz/iocommand.cpp b/toonz/sources/toonz/iocommand.cpp index b3d5c82..36ba01b 100644 --- a/toonz/sources/toonz/iocommand.cpp +++ b/toonz/sources/toonz/iocommand.cpp @@ -890,9 +890,9 @@ TXshLevel *loadLevel(ToonzScene *scene, const IoCmd::LoadResourceArguments::ResourceData &rd, const TFilePath &castFolder, int row0, int &col0, int row1, int &col1, bool expose, std::vector &fIds, - int xFrom = -1, int xTo = -1, std::wstring levelName = L"", - int step = -1, int inc = -1, int frameCount = -1, - bool doesFileActuallyExist = true) { + TFrameId xFrom = TFrameId(), TFrameId xTo = TFrameId(), + std::wstring levelName = L"", int step = -1, int inc = -1, + int frameCount = -1, bool doesFileActuallyExist = true) { TFilePath actualPath = scene->decodeFilePath(rd.m_path); LoadLevelUndo *undo = 0; @@ -1021,12 +1021,15 @@ TXshLevel *loadLevel(ToonzScene *scene, // loadResource(scene, path, castFolder, row, col, expose) //--------------------------------------------------------------------------- -TXshLevel *loadResource( - ToonzScene *scene, const IoCmd::LoadResourceArguments::ResourceData &rd, - const TFilePath &castFolder, int row0, int &col0, int row1, int &col1, - bool expose, std::vector fIds = std::vector(), - int xFrom = -1, int xTo = -1, std::wstring levelName = L"", int step = -1, - int inc = -1, int frameCount = -1, bool doesFileActuallyExist = true) { +TXshLevel *loadResource(ToonzScene *scene, + const IoCmd::LoadResourceArguments::ResourceData &rd, + const TFilePath &castFolder, int row0, int &col0, + int row1, int &col1, bool expose, + std::vector fIds = std::vector(), + TFrameId xFrom = TFrameId(), TFrameId xTo = TFrameId(), + std::wstring levelName = L"", int step = -1, + int inc = -1, int frameCount = -1, + bool doesFileActuallyExist = true) { IoCmd::LoadResourceArguments::ResourceData actualRd(rd); actualRd.m_path = scene->decodeFilePath(rd.m_path); diff --git a/toonz/sources/toonz/iocommand.h b/toonz/sources/toonz/iocommand.h index b72a854..19af69c 100644 --- a/toonz/sources/toonz/iocommand.h +++ b/toonz/sources/toonz/iocommand.h @@ -127,7 +127,7 @@ public: std::vector loadedLevels; //!< [\p Out] Levels loaded by //! resource loading procedures. - int xFrom, xTo; + TFrameId xFrom, xTo; std::wstring levelName; int step, inc, frameCount; bool doesFileActuallyExist; diff --git a/toonz/sources/toonz/penciltestpopup.cpp b/toonz/sources/toonz/penciltestpopup.cpp index 6a30de6..4266468 100644 --- a/toonz/sources/toonz/penciltestpopup.cpp +++ b/toonz/sources/toonz/penciltestpopup.cpp @@ -347,26 +347,25 @@ QString fidsToString(const std::vector& fids, } else { bool beginBlock = true; for (int f = 0; f < fids.size() - 1; f++) { - int num = fids[f].getNumber(); - char letter = fids[f].getLetter(); - int next_num = fids[f + 1].getNumber(); - char next_letter = fids[f + 1].getLetter(); + int num = fids[f].getNumber(); + QString letter = fids[f].getLetter(); + int next_num = fids[f + 1].getNumber(); + QString next_letter = fids[f + 1].getLetter(); - if (num + 1 == next_num && letter == '\0' && next_letter == '\0') { + if (num + 1 == next_num && letter.isEmpty() && next_letter.isEmpty()) { if (beginBlock) { retStr += QString::number(num) + " - "; beginBlock = false; } } else { retStr += QString::number(num); - if (letter != '\0') retStr += QString(letter); + if (!letter.isEmpty()) retStr += letter; retStr += ", "; beginBlock = true; } } retStr += QString::number(fids.back().getNumber()); - if (fids.back().getLetter() != '\0') - retStr += QString(fids.back().getLetter()); + if (!fids.back().getLetter().isEmpty()) retStr += fids.back().getLetter(); } return retStr; } @@ -690,10 +689,12 @@ FrameNumberLineEdit::FrameNumberLineEdit(QWidget* parent, TFrameId fId, bool acceptLetter) : LineEdit(parent) { setFixedWidth(60); - if (acceptLetter) - m_regexpValidator = - new QRegExpValidator(QRegExp("^\\d{1,4}[A-Za-z]?$"), this); - else + if (acceptLetter) { + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + m_regexpValidator = new QRegExpValidator(QRegExp(regExpStr), this); + TProjectManager* pm = TProjectManager::instance(); + pm->addListener(this); + } else m_regexpValidator = new QRegExpValidator(QRegExp("^\\d{1,4}$"), this); m_regexpValidator_alt = @@ -718,7 +719,7 @@ void FrameNumberLineEdit::updateValidator() { void FrameNumberLineEdit::setValue(TFrameId fId) { QString str; if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) { - if (fId.getLetter() != '\0') { + if (!fId.getLetter().isEmpty()) { // need some warning? } str = convertToFrameWithLetter(fId.getNumber(), 3); @@ -744,18 +745,31 @@ TFrameId FrameNumberLineEdit::getValue() { } return TFrameId(f); } else { - QRegExp rx("^(\\d{1,4})([A-Za-z]?)$"); + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + QRegExp rx(regExpStr); int pos = rx.indexIn(text()); if (pos < 0) return TFrameId(); if (rx.cap(2).isEmpty()) return TFrameId(rx.cap(1).toInt()); else - return TFrameId(rx.cap(1).toInt(), rx.cap(2).at(0).toLatin1()); + return TFrameId(rx.cap(1).toInt(), rx.cap(2)); } } //----------------------------------------------------------------------------- +void FrameNumberLineEdit::onProjectSwitched() { + QRegExpValidator* oldValidator = m_regexpValidator; + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + m_regexpValidator = new QRegExpValidator(QRegExp(regExpStr), this); + updateValidator(); + if (oldValidator) delete oldValidator; +} + +void FrameNumberLineEdit::onProjectChanged() { onProjectSwitched(); } + +//----------------------------------------------------------------------------- + void FrameNumberLineEdit::focusInEvent(QFocusEvent* e) { m_textOnFocusIn = text(); } @@ -2126,12 +2140,15 @@ void PencilTestPopup::onFrameCaptured(cv::Mat& image) { } else { TFrameId fId = m_frameNumberEdit->getValue(); - if (fId.getLetter() == '\0' || fId.getLetter() == 'Z' || - fId.getLetter() == 'z') // next number + if (fId.getLetter().isEmpty() || fId.getLetter() == "Z" || + fId.getLetter() == "z") // next number m_frameNumberEdit->setValue(TFrameId(fId.getNumber() + 1)); else { // next alphabet - char letter = fId.getLetter() + 1; - m_frameNumberEdit->setValue(TFrameId(fId.getNumber(), letter)); + QByteArray byteArray = fId.getLetter().toUtf8(); + // return incrementing the last letter + byteArray.data()[byteArray.size() - 1]++; + m_frameNumberEdit->setValue( + TFrameId(fId.getNumber(), QString::fromUtf8(byteArray))); } } diff --git a/toonz/sources/toonz/penciltestpopup.h b/toonz/sources/toonz/penciltestpopup.h index 94a33fa..b6569fe 100644 --- a/toonz/sources/toonz/penciltestpopup.h +++ b/toonz/sources/toonz/penciltestpopup.h @@ -8,6 +8,7 @@ #include "toonz/namebuilder.h" #include "opencv2/opencv.hpp" #include "tfilepath.h" +#include "toonz/tproject.h" #include #include @@ -118,7 +119,8 @@ signals: // "Show ABC Appendix to the Frame Number in Xsheet Cell" is active. //----------------------------------------------------------------------------- -class FrameNumberLineEdit : public DVGui::LineEdit { +class FrameNumberLineEdit : public DVGui::LineEdit, + public TProjectManager::Listener { Q_OBJECT /* having two validators and switch them according to the preferences*/ QRegExpValidator *m_regexpValidator, *m_regexpValidator_alt; @@ -136,6 +138,10 @@ public: /*! Return an integer with text field value. */ TFrameId getValue(); + // TProjectManager::Listener + void onProjectSwitched() override; + void onProjectChanged() override; + protected: /*! If focus is lost and current text value is out of range emit signal \b editingFinished.*/ diff --git a/toonz/sources/toonz/penciltestpopup_qt.cpp b/toonz/sources/toonz/penciltestpopup_qt.cpp index aef2a90..a0333c3 100644 --- a/toonz/sources/toonz/penciltestpopup_qt.cpp +++ b/toonz/sources/toonz/penciltestpopup_qt.cpp @@ -887,10 +887,12 @@ FrameNumberLineEdit::FrameNumberLineEdit(QWidget* parent, TFrameId fId, bool acceptLetter) : LineEdit(parent) { setFixedWidth(60); - if (acceptLetter) - m_regexpValidator = - new QRegExpValidator(QRegExp("^\\d{1,4}[A-Za-z]?$"), this); - else + if (acceptLetter) { + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + m_regexpValidator = new QRegExpValidator(QRegExp(regExpStr), this); + TProjectManager* pm = TProjectManager::instance(); + pm->addListener(this); + } else m_regexpValidator = new QRegExpValidator(QRegExp("^\\d{1,4}$"), this); m_regexpValidator_alt = @@ -915,7 +917,7 @@ void FrameNumberLineEdit::updateValidator() { void FrameNumberLineEdit::setValue(TFrameId fId) { QString str; if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) { - if (fId.getLetter() != '\0') { + if (!fId.getLetter().isEmpty()) { // need some warning? } str = convertToFrameWithLetter(fId.getNumber(), 3); @@ -941,18 +943,31 @@ TFrameId FrameNumberLineEdit::getValue() { } return TFrameId(f); } else { - QRegExp rx("^(\\d{1,4})([A-Za-z]?)$"); + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + QRegExp rx(regExpStr); int pos = rx.indexIn(text()); if (pos < 0) return TFrameId(); if (rx.cap(2).isEmpty()) return TFrameId(rx.cap(1).toInt()); else - return TFrameId(rx.cap(1).toInt(), rx.cap(2).at(0).toLatin1()); + return TFrameId(rx.cap(1).toInt(), rx.cap(2)); } } //----------------------------------------------------------------------------- +void FrameNumberLineEdit::onProjectSwitched() { + QRegExpValidator* oldValidator = m_regexpValidator; + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + m_regexpValidator = new QRegExpValidator(QRegExp(regExpStr), this); + updateValidator(); + if (oldValidator) delete oldValidator; +} + +void FrameNumberLineEdit::onProjectChanged() { onProjectSwitched(); } + +//----------------------------------------------------------------------------- + void FrameNumberLineEdit::focusInEvent(QFocusEvent* e) { m_textOnFocusIn = text(); } @@ -2180,8 +2195,11 @@ void PencilTestPopup::onFrameCaptured(QImage& image) { fId.getLetter() == 'z') // next number m_frameNumberEdit->setValue(TFrameId(fId.getNumber() + 1)); else { // next alphabet - char letter = fId.getLetter() + 1; - m_frameNumberEdit->setValue(TFrameId(fId.getNumber(), letter)); + QByteArray byteArray = fId.getLetter().toUtf8(); + // return incrementing the last letter + byteArray.data()[byteArray.size() - 1]++; + m_frameNumberEdit->setValue( + TFrameId(fId.getNumber(), QString::fromUtf8(byteArray))); } } diff --git a/toonz/sources/toonz/penciltestpopup_qt.h b/toonz/sources/toonz/penciltestpopup_qt.h index ee320ae..a0a4bdd 100644 --- a/toonz/sources/toonz/penciltestpopup_qt.h +++ b/toonz/sources/toonz/penciltestpopup_qt.h @@ -7,6 +7,7 @@ #include "toonzqt/lineedit.h" #include "toonz/namebuilder.h" #include "tfilepath.h" +#include "toonz/tproject.h" #include #include @@ -184,7 +185,8 @@ signals: // "Show ABC Appendix to the Frame Number in Xsheet Cell" is active. //----------------------------------------------------------------------------- -class FrameNumberLineEdit : public DVGui::LineEdit { +class FrameNumberLineEdit : public DVGui::LineEdit, + public TProjectManager::Listener { Q_OBJECT /* having two validators and switch them according to the preferences*/ QRegExpValidator *m_regexpValidator, *m_regexpValidator_alt; @@ -198,10 +200,14 @@ public: ~FrameNumberLineEdit() {} /*! Set text in field to \b value. */ - void setValue(TFrameId value); + void setValue(TFrameId fId); /*! Return an integer with text field value. */ TFrameId getValue(); + // TProjectManager::Listener + void onProjectSwitched() override; + void onProjectChanged() override; + protected: /*! If focus is lost and current text value is out of range emit signal \b editingFinished.*/ diff --git a/toonz/sources/toonz/projectpopup.cpp b/toonz/sources/toonz/projectpopup.cpp index 828cccc..b278148 100644 --- a/toonz/sources/toonz/projectpopup.cpp +++ b/toonz/sources/toonz/projectpopup.cpp @@ -17,9 +17,13 @@ #include "toonzqt/checkbox.h" #include "toonzqt/gutil.h" +// TnzLib +#include "toonz/filepathproperties.h" + // TnzCore includes #include "tsystem.h" #include "tenv.h" +#include "tfilepath.h" // Qt includes #include @@ -28,9 +32,19 @@ #include #include #include +#include +#include +#include +#include using namespace DVGui; +namespace { + +enum { Rule_Standard = 0, Rule_Custom }; + +} + //============================================================================= // ProjectDvDirModelProjectNode //----------------------------------------------------------------------------- @@ -141,7 +155,7 @@ DvDirModelNode *ProjectDirModel::getNode(const QModelIndex &index) const { QModelIndex ProjectDirModel::index(int row, int column, const QModelIndex &parent) const { if (column != 0) return QModelIndex(); - DvDirModelNode *parentNode = m_root; + DvDirModelNode *parentNode = m_root; if (parent.isValid()) parentNode = getNode(parent); if (row < 0 || row >= parentNode->getChildCount()) return QModelIndex(); DvDirModelNode *node = parentNode->getChild(row); @@ -279,62 +293,136 @@ ProjectPopup::ProjectPopup(bool isModal) m_model = new ProjectDirModel; m_treeView = new DvDirTreeView(this); + m_rulePreferenceBG = new QButtonGroup(this); + QRadioButton *standardRB = new QRadioButton(tr("Standard"), this); + QRadioButton *customRB = + new QRadioButton(QString("[Experimental] ") + tr("Custom"), this); + m_acceptNonAlphabetSuffixCB = + new CheckBox(tr("Accept Non-alphabet Suffix"), this); + m_letterCountCombo = new QComboBox(this); + + QTabWidget *tabWidget = new QTabWidget(this); + + //----- + m_nameFld->setMaximumHeight(WidgetHeight); m_treeView->setModel(m_model); + m_rulePreferenceBG->addButton(standardRB, Rule_Standard); + m_rulePreferenceBG->addButton(customRB, Rule_Custom); + m_rulePreferenceBG->setExclusive(true); + standardRB->setToolTip(tr( + "In the standard mode files with the following file name are handled as sequencial images:\n\ +[LEVEL_NAME][\".\"or\"_\"][FRAME_NUMBER][SUFFIX].[EXTENSION]\n\ +For [SUFFIX] zero or one occurrences of alphabet (a-z, A-Z) can be used in the standard mode.")); + customRB->setToolTip( + tr("In the custom mode you can customize the file path rules.\n\ +Note that this mode uses regular expression for file name validation and may slow the operation.")); + + m_letterCountCombo->addItem(tr("1"), 1); + m_letterCountCombo->addItem(tr("2"), 2); + m_letterCountCombo->addItem(tr("3"), 3); + m_letterCountCombo->addItem(tr("5"), 5); + m_letterCountCombo->addItem(tr("Unlimited"), 0); + //----layout m_topLayout->setMargin(5); m_topLayout->setSpacing(10); { - m_topLayout->addWidget(m_treeView, 0); + m_topLayout->addWidget(tabWidget, 1); - QGridLayout *upperLayout = new QGridLayout(); - upperLayout->setMargin(5); - upperLayout->setHorizontalSpacing(5); - upperLayout->setVerticalSpacing(10); - { - upperLayout->addWidget(m_choosePrjLabel, 0, 0, - Qt::AlignRight | Qt::AlignVCenter); - upperLayout->addWidget(m_chooseProjectCombo, 0, 1); + // project folder settings - upperLayout->addWidget(m_prjNameLabel, 1, 0, - Qt::AlignRight | Qt::AlignVCenter); - upperLayout->addWidget(m_nameFld, 1, 1); + QWidget *projectFolderPanel = new QWidget(this); + QVBoxLayout *pfLayout = new QVBoxLayout(); + pfLayout->setMargin(5); + pfLayout->setSpacing(10); + { + pfLayout->addWidget(m_treeView, 0); + + QGridLayout *upperLayout = new QGridLayout(); + upperLayout->setMargin(5); + upperLayout->setHorizontalSpacing(5); + upperLayout->setVerticalSpacing(10); + { + upperLayout->addWidget(m_choosePrjLabel, 0, 0, + Qt::AlignRight | Qt::AlignVCenter); + upperLayout->addWidget(m_chooseProjectCombo, 0, 1); + + upperLayout->addWidget(m_prjNameLabel, 1, 0, + Qt::AlignRight | Qt::AlignVCenter); + upperLayout->addWidget(m_nameFld, 1, 1); + } + upperLayout->setColumnStretch(0, 0); + upperLayout->setColumnStretch(1, 1); + + std::vector folderNames; + pm->getFolderNames(folderNames); + int i; + for (i = 0; i < (int)folderNames.size(); i++) { + std::string name = folderNames[i]; + QString qName = QString::fromStdString(name); + FileField *ff = new FileField(0, qName); + m_folderFlds.append(qMakePair(name, ff)); + upperLayout->addWidget(new QLabel("+" + qName, this), i + 2, 0, + Qt::AlignRight | Qt::AlignVCenter); + upperLayout->addWidget(ff, i + 2, 1); + } + std::vector> cbs = { + std::make_tuple(tr("Append $scenepath to +drawings"), + TProject::Drawings), + std::make_tuple(tr("Append $scenepath to +inputs"), TProject::Inputs), + std::make_tuple(tr("Append $scenepath to +extras"), + TProject::Extras)}; + int currentRow = upperLayout->rowCount(); + + for (int i = 0; i < cbs.size(); ++i) { + auto const &name = std::get<0>(cbs[i]); + auto const &folderName = std::get<1>(cbs[i]); + CheckBox *cb = new CheckBox(name); + cb->setMaximumHeight(WidgetHeight); + upperLayout->addWidget(cb, currentRow + i, 1); + m_useScenePathCbs.append(qMakePair(folderName, cb)); + } + pfLayout->addLayout(upperLayout); } - upperLayout->setColumnStretch(0, 0); - upperLayout->setColumnStretch(1, 1); + projectFolderPanel->setLayout(pfLayout); + tabWidget->addTab(projectFolderPanel, tr("Project Folder")); + + // file path settings + QWidget *filePathPanel = new QWidget(this); + QVBoxLayout *fpLayout = new QVBoxLayout(); + fpLayout->setMargin(5); + fpLayout->setSpacing(10); + { + fpLayout->addWidget(standardRB, 0); + fpLayout->addWidget(customRB, 0); + + // add some indent + QGridLayout *customLay = new QGridLayout(); + customLay->setMargin(10); + customLay->setHorizontalSpacing(10); + customLay->setVerticalSpacing(10); + { + customLay->addWidget(m_acceptNonAlphabetSuffixCB, 0, 0, 1, 2); + customLay->addWidget( + new QLabel(tr("Maximum Letter Count For Suffix"), this), 1, 0); + customLay->addWidget(m_letterCountCombo, 1, 1); + } + customLay->setColumnStretch(2, 1); + fpLayout->addLayout(customLay, 0); - std::vector folderNames; - pm->getFolderNames(folderNames); - int i; - for (i = 0; i < (int)folderNames.size(); i++) { - std::string name = folderNames[i]; - QString qName = QString::fromStdString(name); - FileField *ff = new FileField(0, qName); - m_folderFlds.append(qMakePair(name, ff)); - upperLayout->addWidget(new QLabel("+" + qName, this), i + 2, 0, - Qt::AlignRight | Qt::AlignVCenter); - upperLayout->addWidget(ff, i + 2, 1); - } - std::vector> cbs = { - std::make_tuple(tr("Append $scenepath to +drawings"), - TProject::Drawings), - std::make_tuple(tr("Append $scenepath to +inputs"), TProject::Inputs), - std::make_tuple(tr("Append $scenepath to +extras"), TProject::Extras)}; - int currentRow = upperLayout->rowCount(); - - for (int i = 0; i < cbs.size(); ++i) { - auto const &name = std::get<0>(cbs[i]); - auto const &folderName = std::get<1>(cbs[i]); - CheckBox *cb = new CheckBox(name); - cb->setMaximumHeight(WidgetHeight); - upperLayout->addWidget(cb, currentRow + i, 1); - m_useScenePathCbs.append(qMakePair(folderName, cb)); + fpLayout->addStretch(1); } - m_topLayout->addLayout(upperLayout); + filePathPanel->setLayout(fpLayout); + tabWidget->addTab(filePathPanel, tr("File Path Rules")); } pm->addListener(this); + + //--------- + connect(m_rulePreferenceBG, SIGNAL(idToggled(int, bool)), this, + SLOT(onRulePreferenceToggled(int, bool))); } //----------------------------------------------------------------------------- @@ -401,6 +489,17 @@ void ProjectPopup::updateFieldsFromProject(TProject *project) { cb->setCheckState(cbState); cb->blockSignals(signalesAlreadyBlocked); } + + // file path + FilePathProperties *fpProp = project->getFilePathProperties(); + bool useStandard = fpProp->useStandard(); + bool acceptNonAlphabet = fpProp->acceptNonAlphabetSuffix(); + int letterCount = fpProp->letterCountForSuffix(); + m_rulePreferenceBG->button((useStandard) ? Rule_Standard : Rule_Custom) + ->setChecked(true); + m_acceptNonAlphabetSuffixCB->setChecked(acceptNonAlphabet); + m_letterCountCombo->setCurrentIndex( + m_letterCountCombo->findData(letterCount)); } //----------------------------------------------------------------------------- @@ -418,6 +517,20 @@ void ProjectPopup::updateProjectFromFields(TProject *project) { bool useScenePath = cbState == Qt::Checked; project->setUseScenePath(folderName, cbState); } + + // file path + FilePathProperties *fpProp = project->getFilePathProperties(); + bool useStandard = m_rulePreferenceBG->checkedId() == Rule_Standard; + bool acceptNonAlphabet = m_acceptNonAlphabetSuffixCB->isChecked(); + int letterCount = m_letterCountCombo->currentData().toInt(); + fpProp->setUseStandard(useStandard); + fpProp->setAcceptNonAlphabetSuffix(acceptNonAlphabet); + fpProp->setLetterCountForSuffix(letterCount); + + if (TFilePath::setFilePathProperties(useStandard, acceptNonAlphabet, + letterCount)) + DvDirModel::instance()->refreshFolderChild(QModelIndex()); // refresh all + TProjectManager::instance()->notifyProjectChanged(); } @@ -440,6 +553,13 @@ void ProjectPopup::showEvent(QShowEvent *) { updateChooseProjectCombo(); } +//----------------------------------------------------------------------------- + +void ProjectPopup::onRulePreferenceToggled(int id, bool on) { + m_acceptNonAlphabetSuffixCB->setEnabled((id == Rule_Custom) == on); + m_letterCountCombo->setEnabled((id == Rule_Custom) == on); +} + //============================================================================= /*! \class ProjectSettingsPopup \brief The ProjectSettingsPopup class provides a dialog to @@ -461,16 +581,23 @@ ProjectSettingsPopup::ProjectSettingsPopup() : ProjectPopup(false) { int i; for (i = 0; i < m_folderFlds.size(); i++) { FileField *ff = m_folderFlds[i].second; - connect(ff, SIGNAL(pathChanged()), this, SLOT(onFolderChanged())); + connect(ff, SIGNAL(pathChanged()), this, SLOT(onSomethingChanged())); } for (i = 0; i < m_useScenePathCbs.size(); i++) { CheckBox *cb = m_useScenePathCbs[i].second; - connect(cb, SIGNAL(stateChanged(int)), this, - SLOT(onUseSceneChekboxChanged(int))); + connect(cb, SIGNAL(stateChanged(int)), this, SLOT(onSomethingChanged())); } connect(m_chooseProjectCombo, SIGNAL(activated(int)), this, SLOT(onChooseProjectChanged(int))); + + // file path settings + connect(m_rulePreferenceBG, SIGNAL(idClicked(int)), this, + SLOT(onSomethingChanged())); + connect(m_acceptNonAlphabetSuffixCB, SIGNAL(clicked(bool)), this, + SLOT(onSomethingChanged())); + connect(m_letterCountCombo, SIGNAL(activated(int)), this, + SLOT(onSomethingChanged())); } //----------------------------------------------------------------------------- @@ -497,21 +624,7 @@ void ProjectSettingsPopup::onChooseProjectChanged(int index) { //----------------------------------------------------------------------------- -void ProjectSettingsPopup::onFolderChanged() { - TProjectP project = TProjectManager::instance()->getCurrentProject(); - updateProjectFromFields(project.getPointer()); - try { - project->save(); - } catch (TSystemException se) { - DVGui::warning(QString::fromStdWString(se.getMessage())); - return; - } - DvDirModel::instance()->refreshFolder(project->getProjectFolder()); -} - -//----------------------------------------------------------------------------- - -void ProjectSettingsPopup::onUseSceneChekboxChanged(int) { +void ProjectSettingsPopup::onSomethingChanged() { TProjectP project = TProjectManager::instance()->getCurrentProject(); updateProjectFromFields(project.getPointer()); try { @@ -651,6 +764,11 @@ void ProjectCreatePopup::showEvent(QShowEvent *) { index = m_model->index(0, 0, QModelIndex()); selection->select(index, QItemSelectionModel::Select); m_treeView->setSelectionModel(selection); + + // default file path settings + m_rulePreferenceBG->button(Rule_Standard)->setChecked(true); + m_acceptNonAlphabetSuffixCB->setChecked(false); + m_letterCountCombo->setCurrentIndex(m_letterCountCombo->findData(1)); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/projectpopup.h b/toonz/sources/toonz/projectpopup.h index 782d176..f13e415 100644 --- a/toonz/sources/toonz/projectpopup.h +++ b/toonz/sources/toonz/projectpopup.h @@ -13,10 +13,11 @@ namespace DVGui { class FileField; class LineEdit; class CheckBox; -} +} // namespace DVGui class DvDirTreeView; class QComboBox; +class QButtonGroup; //============================================================================= // ProjectDvDirModelRootNode @@ -118,6 +119,11 @@ protected: QComboBox *m_chooseProjectCombo; QList m_projectPaths; + // file path settings + QButtonGroup *m_rulePreferenceBG; + DVGui::CheckBox *m_acceptNonAlphabetSuffixCB; + QComboBox *m_letterCountCombo; + public: ProjectPopup(bool isModal); // da TProjectManager::Listener @@ -132,6 +138,8 @@ public: protected: void showEvent(QShowEvent *) override; +protected slots: + void onRulePreferenceToggled(int, bool); }; //============================================================================= @@ -145,8 +153,7 @@ public: ProjectSettingsPopup(); public slots: - void onFolderChanged(); - void onUseSceneChekboxChanged(int); + void onSomethingChanged(); void onChooseProjectChanged(int); }; diff --git a/toonz/sources/toonz/tvpjson_io.cpp b/toonz/sources/toonz/tvpjson_io.cpp index 4aaa470..0c6de3a 100644 --- a/toonz/sources/toonz/tvpjson_io.cpp +++ b/toonz/sources/toonz/tvpjson_io.cpp @@ -250,12 +250,13 @@ void TvpJsonLayer::build(int index, ToonzScene* scene, TXshCellColumn* column) { if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) instance_name = getFrameNumberWithLetters(fid.getNumber()); else { - std::string frameNumber(""); + QString frameNumber(""); // set number - if (fid.getNumber() >= 0) frameNumber = std::to_string(fid.getNumber()); + if (fid.getNumber() >= 0) + frameNumber = QString::number(fid.getNumber()); // add letter - if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter()); - instance_name = QString::fromStdString(frameNumber); + if (!fid.getLetter().isEmpty()) frameNumber += fid.getLetter(); + instance_name = frameNumber; } fid.setZeroPadding(frameFormats[cell.m_level.getPointer()].first); diff --git a/toonz/sources/toonz/xdtsio.cpp b/toonz/sources/toonz/xdtsio.cpp index a3dbecf..023acfe 100644 --- a/toonz/sources/toonz/xdtsio.cpp +++ b/toonz/sources/toonz/xdtsio.cpp @@ -60,21 +60,24 @@ void XdtsHeader::write(QJsonObject &json) const { //----------------------------------------------------------------------------- TFrameId XdtsFrameDataItem::str2Fid(const QString &str) const { + if (str.isEmpty()) return TFrameId::EMPTY_FRAME; bool ok; int frame = str.toInt(&ok); if (ok) return TFrameId(frame); - // separate the last word as suffix - frame = str.left(str.size() - 1).toInt(&ok); - if (!ok) return TFrameId(-1); // EMPTY - if (!str[str.size() - 1].isLetter()) return TFrameId(-1); // EMPTY - char c = str[str.size() - 1].toLatin1(); - return TFrameId(frame, c); + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + QRegExp rx(regExpStr); + int pos = rx.indexIn(str); + if (pos < 0) return TFrameId(); + if (rx.cap(2).isEmpty()) + return TFrameId(rx.cap(1).toInt()); + else + return TFrameId(rx.cap(1).toInt(), rx.cap(2)); } QString XdtsFrameDataItem::fid2Str(const TFrameId &fid) const { - if (fid.getLetter() == 0) return QString::number(fid.getNumber()); - return QString::number(fid.getNumber()) + QString(fid.getLetter()); + if (fid.getLetter().isEmpty()) return QString::number(fid.getNumber()); + return QString::number(fid.getNumber()) + fid.getLetter(); } void XdtsFrameDataItem::read(const QJsonObject &json) { diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp index 3a786b1..bdc33cf 100644 --- a/toonz/sources/toonz/xshcellviewer.cpp +++ b/toonz/sources/toonz/xshcellviewer.cpp @@ -297,7 +297,8 @@ void parse(const QString &text, std::wstring &levelName, TFrameId &fid) { QRegExp spaces("\\t|\\s"); QRegExp numbers("\\d+"); QRegExp characters("[^\\d+]"); - QRegExp fidWithSuffix("([0-9]+)([a-z]?)"); + QRegExp fidWithSuffix(TFilePath::fidRegExpStr()); + // QRegExp fidWithSuffix("([0-9]+)([a-z]?)"); QString str = text; // remove final spaces @@ -316,9 +317,8 @@ void parse(const QString &text, std::wstring &levelName, TFrameId &fid) { fid = TFrameId(str.toInt()); } else if (fidWithSuffix.exactMatch(str)) { levelName = L""; - fid = TFrameId( - fidWithSuffix.cap(1).toInt(), - fidWithSuffix.cap(2) == "" ? 0 : fidWithSuffix.cap(2).toLatin1()[0]); + fid = TFrameId(fidWithSuffix.cap(1).toInt(), fidWithSuffix.cap(2)); + // fidWithSuffix.cap(2) == "" ? 0 : fidWithSuffix.cap(2).toLatin1()[0]); } else if (str.contains(characters)) { levelName = text.toStdWString(); fid = TFrameId::NO_FRAME; @@ -332,9 +332,8 @@ void parse(const QString &text, std::wstring &levelName, TFrameId &fid) { } else if (fidWithSuffix.exactMatch(lastString)) { QString firstString = str.left(lastSpaceIndex); levelName = firstString.toStdWString(); - fid = TFrameId( - fidWithSuffix.cap(1).toInt(), - fidWithSuffix.cap(2) == "" ? 0 : fidWithSuffix.cap(2).toLatin1()[0]); + fid = TFrameId(fidWithSuffix.cap(1).toInt(), fidWithSuffix.cap(2)); + // fidWithSuffix.cap(2) == "" ? 0 : fidWithSuffix.cap(2).toLatin1()[0]); } else if (lastString.contains(characters)) { levelName = text.toStdWString(); fid = TFrameId::NO_FRAME; @@ -626,9 +625,9 @@ void RenameCellField::showInRowCol(int row, int col, bool multiColumnSelected) { : QString::fromStdWString(levelName) + QString(" ") + m_viewer->getFrameNumberWithLetters(fid.getNumber())); else { - std::string frameNumber(""); - if (fid.getNumber() > 0) frameNumber = std::to_string(fid.getNumber()); - if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter()); + QString frameNumber(""); + if (fid.getNumber() > 0) frameNumber = QString::number(fid.getNumber()); + if (!fid.getLetter().isEmpty()) frameNumber += fid.getLetter(); // get text from sound text level if (cell.m_level->getType() == TXshLevelType::SND_TXT_XSHLEVEL) { @@ -641,12 +640,12 @@ void RenameCellField::showInRowCol(int row, int col, bool multiColumnSelected) { } // other level types else { - setText((frameNumber.empty()) + setText((frameNumber.isEmpty()) ? QString::fromStdWString(levelName) : (multiColumnSelected) - ? QString::fromStdString(frameNumber) + ? frameNumber : QString::fromStdWString(levelName) + QString(" ") + - QString::fromStdString(frameNumber)); + frameNumber); } } selectAll(); @@ -734,8 +733,8 @@ void RenameCellField::renameSoundTextColumn(TXshSoundTextColumn *sndTextCol, //----------------------------------------------------------------------------- void RenameCellField::renameCell() { - QString s = text(); - std::wstring newName = s.toStdWString(); + QString newName = text(); + // std::wstring newName = s.toStdWString(); setText(""); @@ -749,16 +748,16 @@ void RenameCellField::renameCell() { xsheet->getColumn(m_col)->getSoundTextColumn()) { TXshSoundTextColumn *sndTextCol = xsheet->getColumn(m_col)->getSoundTextColumn(); - renameSoundTextColumn(sndTextCol, s); + renameSoundTextColumn(sndTextCol, newName); return; } // convert the last one digit of the frame number to alphabet // Ex. 12 -> 1B 21 -> 2A 30 -> 3 if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) - parse_with_letter(QString::fromStdWString(newName), levelName, fid); + parse_with_letter(newName, levelName, fid); else { - parse(QString::fromStdWString(newName), levelName, fid); + parse(newName, levelName, fid); } bool animationSheetEnabled = Preferences::instance()->isAnimationSheetEnabled(); @@ -1928,12 +1927,12 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference, if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) fnum = m_viewer->getFrameNumberWithLetters(fid.getNumber()); else { - std::string frameNumber(""); + QString frameNumber(""); // set number - if (fid.getNumber() >= 0) frameNumber = std::to_string(fid.getNumber()); + if (fid.getNumber() >= 0) frameNumber = QString::number(fid.getNumber()); // add letter - if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter()); - fnum = QString::fromStdString(frameNumber); + if (!fid.getLetter().isEmpty()) frameNumber += fid.getLetter(); + fnum = frameNumber; } int alignFlag = @@ -2268,9 +2267,9 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col, TFrameId fid = cell.m_frameId; std::wstring levelName = cell.m_level->getName(); - std::string frameNumber(""); - if (fid.getNumber() > 0) frameNumber = std::to_string(fid.getNumber()); - if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter()); + // QString frameNumber(""); + // if (fid.getNumber() > 0) frameNumber = QString::number(fid.getNumber()); + // if (fid.getLetter() != 0) frameNumber += fid.getLetter(); QRect nameRect = o->rect(PredefinedRect::CELL_NAME).translated(QPoint(x, y)); @@ -2312,13 +2311,12 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col, numberStr = m_viewer->getFrameNumberWithLetters(fid.getNumber()); p.drawText(nameRect, Qt::AlignRight | Qt::AlignBottom, numberStr); } else { - std::string frameNumber(""); + QString frameNumber(""); // set number - if (fid.getNumber() > 0) frameNumber = std::to_string(fid.getNumber()); + if (fid.getNumber() > 0) frameNumber = QString::number(fid.getNumber()); // add letter - if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter()); - numberStr = QString::fromStdString(frameNumber); - p.drawText(nameRect, Qt::AlignRight | Qt::AlignBottom, numberStr); + if (!fid.getLetter().isEmpty()) frameNumber += fid.getLetter(); + p.drawText(nameRect, Qt::AlignRight | Qt::AlignBottom, frameNumber); } } @@ -2979,14 +2977,13 @@ void CellArea::mouseMoveEvent(QMouseEvent *event) { : QString::fromStdWString(levelName) + QString(" ") + m_viewer->getFrameNumberWithLetters(fid.getNumber()); } else { - std::string frameNumber(""); - if (fid.getNumber() >= 0) frameNumber = std::to_string(fid.getNumber()); - if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter()); + QString frameNumber(""); + if (fid.getNumber() >= 0) frameNumber = QString::number(fid.getNumber()); + if (!fid.getLetter().isEmpty()) frameNumber += fid.getLetter(); m_tooltip = - QString((frameNumber.empty()) - ? QString::fromStdWString(levelName) - : QString::fromStdWString(levelName) + QString(" ") + - QString::fromStdString(frameNumber)); + QString((frameNumber.isEmpty()) ? QString::fromStdWString(levelName) + : QString::fromStdWString(levelName) + + QString(" ") + frameNumber); } } else if (isSoundColumn && o->rect(PredefinedRect::PREVIEW_TRACK) .adjusted(0, 0, -frameAdj.x(), -frameAdj.y()) diff --git a/toonz/sources/toonz/xsheetdragtool.cpp b/toonz/sources/toonz/xsheetdragtool.cpp index 68edf66..3de2307 100644 --- a/toonz/sources/toonz/xsheetdragtool.cpp +++ b/toonz/sources/toonz/xsheetdragtool.cpp @@ -551,7 +551,7 @@ public: int i; for (i = 1; i < count; i++) if (m_sourceCells[i].m_level != cell.m_level || - m_sourceCells[i].m_frameId.getLetter() != 0) + !m_sourceCells[i].m_frameId.getLetter().isEmpty()) return; // check if all the selected cells have the same frame number diff --git a/toonz/sources/toonzlib/CMakeLists.txt b/toonz/sources/toonzlib/CMakeLists.txt index 70b8871..692f8d0 100644 --- a/toonz/sources/toonzlib/CMakeLists.txt +++ b/toonz/sources/toonzlib/CMakeLists.txt @@ -162,6 +162,7 @@ set(HEADERS ../include/toonz/preferencesitemids.h ../include/toonz/txsheetcolumnchange.h ../include/toonz/expressionreferencemonitor.h + ../include/toonz/filepathproperties.h ) set(SOURCES @@ -320,6 +321,7 @@ set(SOURCES txshmeshcolumn.cpp textureutils.cpp boardsettings.cpp + filepathproperties.cpp ) if(BUILD_TARGET_WIN) diff --git a/toonz/sources/toonzlib/filepathproperties.cpp b/toonz/sources/toonzlib/filepathproperties.cpp new file mode 100644 index 0000000..3b79a1a --- /dev/null +++ b/toonz/sources/toonzlib/filepathproperties.cpp @@ -0,0 +1,38 @@ +#include "toonz/filepathproperties.h" + +// TnzCore includes +#include "tstream.h" + +FilePathProperties::FilePathProperties() + : m_useStandard(true) + , m_acceptNonAlphabetSuffix(false) + , m_letterCountForSuffix(1) {} + +bool FilePathProperties::isDefault() { + return (m_useStandard == true && m_acceptNonAlphabetSuffix == false && + m_letterCountForSuffix == 1); +} + +void FilePathProperties::saveData(TOStream& os) const { + os.child("useStandard") << ((m_useStandard) ? 1 : 0); + os.child("acceptNonAlphabetSuffix") << ((m_acceptNonAlphabetSuffix) ? 1 : 0); + os.child("letterCountForSuffix") << m_letterCountForSuffix; +} + +// make sure to let TFilePath to know the new properties! +void FilePathProperties::loadData(TIStream& is) { + int val; + std::string tagName; + while (is.matchTag(tagName)) { + if (tagName == "useStandard") { + is >> val; + m_useStandard = (val == 1); + } else if (tagName == "acceptNonAlphabetSuffix") { + is >> val; + m_acceptNonAlphabetSuffix = (val == 1); + } else if (tagName == "letterCountForSuffix") { + is >> m_letterCountForSuffix; + } + is.closeChild(); + } +} \ No newline at end of file diff --git a/toonz/sources/toonzlib/scriptbinding_scene.cpp b/toonz/sources/toonzlib/scriptbinding_scene.cpp index 1f18b26..9b1312a 100644 --- a/toonz/sources/toonzlib/scriptbinding_scene.cpp +++ b/toonz/sources/toonzlib/scriptbinding_scene.cpp @@ -206,10 +206,10 @@ QScriptValue Scene::getCell(int row, int col) { if (sl) { QScriptValue level = create(engine(), new Level(sl)); QScriptValue fid; - if (cell.m_frameId.getLetter() == 0) + if (cell.m_frameId.getLetter().isEmpty()) fid = cell.m_frameId.getNumber(); else - fid = QString::fromStdString(cell.m_frameId.expand()); + fid = QString::fromStdString(cell.m_frameId.expand()); QScriptValue result = engine()->newObject(); result.setProperty("level", level); result.setProperty("fid", fid); diff --git a/toonz/sources/toonzlib/tproject.cpp b/toonz/sources/toonzlib/tproject.cpp index 4daa45d..9c27655 100644 --- a/toonz/sources/toonzlib/tproject.cpp +++ b/toonz/sources/toonzlib/tproject.cpp @@ -9,6 +9,7 @@ #include "toonz/observer.h" #include "toonz/toonzfolders.h" #include "toonz/cleanupparameters.h" +#include "toonz/filepathproperties.h" // TnzBase includes #include "tenv.h" @@ -16,6 +17,7 @@ // TnzCore includes #include "tsystem.h" #include "tstream.h" +#include "tfilepath.h" #include "tfilepath_io.h" #include "tconvert.h" @@ -285,11 +287,18 @@ void hideOlderProjectFiles(const TFilePath &folderPath) { \see TProjectManager and TOStream. */ -TProject::TProject() : m_name(), m_path(), m_sprop(new TSceneProperties()) {} +TProject::TProject() + : m_name() + , m_path() + , m_sprop(new TSceneProperties()) + , m_fpProp(new FilePathProperties()) {} //------------------------------------------------------------------- -TProject::~TProject() { delete m_sprop; } +TProject::~TProject() { + delete m_sprop; + delete m_fpProp; +} //------------------------------------------------------------------- /*! Associates the \b name to the specified \b path. @@ -569,6 +578,13 @@ bool TProject::save(const TFilePath &projectPath) { os.openChild("sceneProperties"); getSceneProperties().saveData(os); os.closeChild(); + + if (!getFilePathProperties()->isDefault()) { + os.openChild("filePathProperties"); + getFilePathProperties()->saveData(os); + os.closeChild(); + } + os.closeChild(); // crea (se necessario) le directory relative ai vari folder @@ -674,6 +690,9 @@ void TProject::load(const TFilePath &projectPath) { } setSceneProperties(sprop); is.matchEndTag(); + } else if (tagName == "filePathProperties") { + m_fpProp->loadData(is); + is.matchEndTag(); } } } @@ -977,6 +996,12 @@ TProjectP TProjectManager::getCurrentProject() { assert(TProject::isAProjectPath(fp)); currentProject = new TProject(); currentProject->load(fp); + + // update TFilePath condition on loading the current project + FilePathProperties *fpProp = currentProject->getFilePathProperties(); + TFilePath::setFilePathProperties(fpProp->useStandard(), + fpProp->acceptNonAlphabetSuffix(), + fpProp->letterCountForSuffix()); } return currentProject; } diff --git a/toonz/sources/toonzlib/txsheet.cpp b/toonz/sources/toonzlib/txsheet.cpp index 8d4d5e3..02b41de 100644 --- a/toonz/sources/toonzlib/txsheet.cpp +++ b/toonz/sources/toonzlib/txsheet.cpp @@ -1059,8 +1059,8 @@ int TXsheet::exposeLevel(int row, int col, TXshLevel *xl, bool overwrite) { //----------------------------------------------------------------------------- // customized version for load level popup int TXsheet::exposeLevel(int row, int col, TXshLevel *xl, - std::vector &fIds_, int xFrom, int xTo, - int step, int inc, int frameCount, + std::vector &fIds_, TFrameId xFrom, + TFrameId xTo, int step, int inc, int frameCount, bool doesFileActuallyExist) { if (!xl) return 0; std::vector fids; @@ -1102,22 +1102,19 @@ int TXsheet::exposeLevel(int row, int col, TXshLevel *xl, { std::vector::iterator it; it = fids.begin(); - while (it->getNumber() < xFrom) it++; + while (*it < xFrom) it++; if (step == 0) // Step = Auto { std::vector::iterator next_it; next_it = it; next_it++; - - int startFrame = it->getNumber(); - - for (int f = startFrame; f < startFrame + frameCount; f++) { - if (next_it != fids.end() && f >= next_it->getNumber()) { + for (int f = 0; f < frameCount; f++) { + setCell(row++, col, TXshCell(xl, *it)); + if (next_it != fids.end()) { it++; next_it++; } - setCell(row++, col, TXshCell(xl, *it)); } } @@ -1141,7 +1138,7 @@ int TXsheet::exposeLevel(int row, int col, TXshLevel *xl, loopCount = frameCount / step; for (int loop = 0; loop < loopCount; loop++) { - TFrameId id(xFrom + loop * inc, fids.begin()->getLetter()); + TFrameId id(xFrom.getNumber() + loop * inc, xFrom.getLetter()); for (int s = 0; s < step; s++) { setCell(row++, col, TXshCell(xl, id)); } diff --git a/toonz/sources/toonzlib/txshlevelcolumn.cpp b/toonz/sources/toonzlib/txshlevelcolumn.cpp index 1bc1aae..affee58 100644 --- a/toonz/sources/toonzlib/txshlevelcolumn.cpp +++ b/toonz/sources/toonzlib/txshlevelcolumn.cpp @@ -17,24 +17,17 @@ TFrameId qstringToFrameId(QString str) { return TFrameId::EMPTY_FRAME; else if (str == "-" || str == "-2") return TFrameId::NO_FRAME; - TFrameId fid; - int s = 0; - QString number; - char letter(0); - for (s = 0; s < str.size(); s++) { - QChar c = str.at(s); - if (c.isNumber()) number.append(c); -#if QT_VERSION >= 0x050500 - else - letter = c.toLatin1(); -#else - else - letter = c.toAscii(); -#endif - } - return TFrameId(number.toInt(), letter); -} + + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + QRegExp rx(regExpStr); + int pos = rx.indexIn(str); + if (pos < 0) return TFrameId(); + if (rx.cap(2).isEmpty()) + return TFrameId(rx.cap(1).toInt()); + else + return TFrameId(rx.cap(1).toInt(), rx.cap(2)); } +} // namespace //----------------------------------------------------------------------------- @@ -123,13 +116,13 @@ void TXshLevelColumn::loadData(TIStream &is) { while (is.openChild(tagName)) { if (tagName == "cell") { TPersist *p = 0; - QString str; + std::string str; int row = 1, rowCount = 1, increment = 0; TFilePath path; is >> row >> rowCount >> p >> str >> increment; - TFrameId fid = qstringToFrameId(str); - assert((fid.getLetter() == 0 && rowCount >= 0) || - (fid.getLetter() != 0 && rowCount == 1)); + TFrameId fid = qstringToFrameId(QString::fromStdString(str)); + assert((fid.getLetter().isEmpty() && rowCount >= 0) || + (!fid.getLetter().isEmpty() && rowCount == 1)); TXshLevel *xshLevel = dynamic_cast(p); if (xshLevel) { int fidNumber = fid.getNumber(); @@ -182,11 +175,11 @@ void TXshLevelColumn::saveData(TOStream &os) { int n = 1, inc = 0, dr = fid.getNumber(); // If fid has not letter save more than one cell and its incrementation; // otherwise save one cell. - if (r < r1 && fid.getLetter() == 0) { + if (r < r1 && fid.getLetter().isEmpty()) { TXshCell cell2 = getCell(r + 1); TFrameId fid2 = cell2.m_frameId; if (cell2.m_level.getPointer() == cell.m_level.getPointer() && - fid2.getLetter() == 0) { + fid2.getLetter().isEmpty()) { inc = cell2.m_frameId.getNumber() - dr; n++; for (;;) { @@ -194,7 +187,7 @@ void TXshLevelColumn::saveData(TOStream &os) { cell2 = getCell(r + n); TFrameId fid2 = cell2.m_frameId; if (cell2.m_level.getPointer() != cell.m_level.getPointer() || - fid2.getLetter() != 0) + !fid2.getLetter().isEmpty()) break; if (fid2.getNumber() != dr + n * inc) break; n++; diff --git a/toonz/sources/toonzlib/txshmeshcolumn.cpp b/toonz/sources/toonzlib/txshmeshcolumn.cpp index 3af1bdc..76302db 100644 --- a/toonz/sources/toonzlib/txshmeshcolumn.cpp +++ b/toonz/sources/toonzlib/txshmeshcolumn.cpp @@ -24,28 +24,16 @@ TFrameId qstringToFrameId(QString str) { else if (str == "-" || str == "-2") return TFrameId::NO_FRAME; - TFrameId fid; - - QString number; - char letter(0); - - int s, strSize = str.size(); - for (s = 0; s < strSize; ++s) { - QChar c = str.at(s); - - if (c.isNumber()) - number.append(c); - else -#if QT_VERSION >= 0x050500 - letter = c.toLatin1(); -#else - letter = c.toAscii(); -#endif - } - - return TFrameId(number.toInt(), letter); -} + QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr()); + QRegExp rx(regExpStr); + int pos = rx.indexIn(str); + if (pos < 0) return TFrameId(); + if (rx.cap(2).isEmpty()) + return TFrameId(rx.cap(1).toInt()); + else + return TFrameId(rx.cap(1).toInt(), rx.cap(2)); } +} // namespace //******************************************************************************* // TXshMeshColumn implementation @@ -94,12 +82,12 @@ void TXshMeshColumn::saveData(TOStream &os) { // If fid has no letter save more than one cell and its increment - // otherwise save just one cell - if (r < r1 && fid.getLetter() == 0) { + if (r < r1 && fid.getLetter().isEmpty()) { TXshCell cell2 = getCell(r + 1); TFrameId fid2 = cell2.m_frameId; if (cell2.m_level.getPointer() == cell.m_level.getPointer() && - fid2.getLetter() == 0) { + fid2.getLetter().isEmpty()) { inc = cell2.m_frameId.getNumber() - dr; for (++n;; ++n) { if (r + n > r1) break; @@ -108,7 +96,7 @@ void TXshMeshColumn::saveData(TOStream &os) { TFrameId fid2 = cell2.m_frameId; if (cell2.m_level.getPointer() != cell.m_level.getPointer() || - fid2.getLetter() != 0) + !fid2.getLetter().isEmpty()) break; if (fid2.getNumber() != dr + n * inc) break; @@ -150,16 +138,16 @@ void TXshMeshColumn::loadData(TIStream &is) { while (is.openChild(tagName)) { if (tagName == "cell") { TPersist *p = 0; - QString str; + std::string str; int row = 1, rowCount = 1, increment = 0; TFilePath path; is >> row >> rowCount >> p >> str >> increment; - TFrameId fid = qstringToFrameId(str); - assert((fid.getLetter() == 0 && rowCount >= 0) || - (fid.getLetter() != 0 && rowCount == 1)); + TFrameId fid = qstringToFrameId(QString::fromStdString(str)); + assert((fid.getLetter().isEmpty() && rowCount >= 0) || + (!fid.getLetter().isEmpty() && rowCount == 1)); TXshLevel *xshLevel = dynamic_cast(p); if (xshLevel) { diff --git a/toonz/sources/toonzlib/txshsimplelevel.cpp b/toonz/sources/toonzlib/txshsimplelevel.cpp index a7a31c7..380fc5b 100644 --- a/toonz/sources/toonzlib/txshsimplelevel.cpp +++ b/toonz/sources/toonzlib/txshsimplelevel.cpp @@ -484,7 +484,8 @@ int TXshSimpleLevel::guessStep() const { TFrameId firstFid = *ft++, secondFid = *ft++; - if (firstFid.getLetter() != 0 || secondFid.getLetter() != 0) return 1; + if (!firstFid.getLetter().isEmpty() || !secondFid.getLetter().isEmpty()) + return 1; int step = secondFid.getNumber() - firstFid.getNumber(); if (step == 1) return 1; @@ -493,7 +494,7 @@ int TXshSimpleLevel::guessStep() const { // (cerco di limitare il numero di volte in cui devo controllare tutta la // lista) TFrameId lastFid = *m_frames.rbegin(); - if (lastFid.getLetter() != 0) return 1; + if (!lastFid.getLetter().isEmpty()) return 1; if (lastFid.getNumber() != firstFid.getNumber() + step * (frameCount - 1)) return 1; @@ -501,7 +502,7 @@ int TXshSimpleLevel::guessStep() const { for (int i = 2; ft != m_frames.end(); ++ft, ++i) { const TFrameId &fid = *ft; - if (fid.getLetter() != 0) return 1; + if (!fid.getLetter().isEmpty()) return 1; if (fid.getNumber() != firstFid.getNumber() + step * i) return 1; }