33 #include <QTemporaryFile>
44 FileName::FileName() {
49 FileName::FileName(
const char *file) {
51 m_d->setOriginal(file);
55 FileName::FileName(
const QString &file) {
57 m_d->setOriginal(file);
61 FileName::FileName(
const FileName &other) : m_d(other.m_d) {
70 QString FileName::originalPath()
const {
71 return QFileInfo(
m_d->original(
false)).
path();
89 return QFileInfo(expanded()).path();
93 QString FileName::attributes()
const {
95 QString fileNameWithAttribs = QFileInfo(
m_d->original(
true)).fileName();
97 int attribStartPos = fileNameWithAttribs.indexOf(
"+");
99 if (attribStartPos != -1)
100 result = fileNameWithAttribs.mid(attribStartPos + 1);
106 QString FileName::baseName()
const {
107 return QFileInfo(
m_d->original(
false)).completeBaseName();
111 QString FileName::name()
const {
112 return QFileInfo(
m_d->original(
false)).fileName();
116 QString FileName::extension()
const {
117 return QFileInfo(
m_d->original(
false)).suffix();
121 QString FileName::expanded()
const {
122 return m_d->expanded(
false);
126 QString FileName::original()
const {
127 return m_d->original(
true);
131 FileName FileName::addExtension(
const QString &newExtension)
const {
134 if (result.extension() != newExtension) {
135 QString attributesStr = result.attributes();
137 if (attributesStr ==
"")
138 result =
FileName(result.originalPath() +
"/" + result.name() +
"." + newExtension);
140 result =
FileName(result.originalPath() +
"/" + result.name() +
"." + newExtension
141 +
"+" + attributesStr);
148 FileName FileName::removeExtension()
const {
149 QString attributesStr = attributes();
152 if (attributesStr ==
"")
153 result =
FileName(originalPath() +
"/" + baseName());
155 result =
FileName(originalPath() +
"/" + baseName() +
"+" + attributesStr);
161 FileName FileName::setExtension(
const QString &newExtension)
const {
164 if (extension() != newExtension) {
165 result = result.removeExtension().addExtension(newExtension);
172 bool FileName::isVersioned()
const {
175 return isNumericallyVersioned() || isDateVersioned();
179 bool FileName::isNumericallyVersioned()
const {
180 return FileName(expanded()).name().contains(
"?");
184 bool FileName::isDateVersioned()
const {
185 return FileName(expanded()).name().contains(QRegExp(
"\\{.*\\}"));
189 FileName FileName::highestVersion()
const {
194 if (!isVersioned()) {
196 QObject::tr(
"Asked for highest version of file named [%1] in [%2] but there "
197 "are no version sequences in the name")
198 .arg(name()).arg(originalPath()),
203 if (isDateVersioned()) {
204 result = result.version(result.highestVersionDate());
208 if (isNumericallyVersioned()) {
209 result = result.version(result.highestVersionNum());
216 FileName FileName::newVersion()
const {
221 if (!isVersioned()) {
223 QObject::tr(
"Asked for new version of file named [%1] in [%2] but there "
224 "are no version sequences in the name")
225 .arg(name()).arg(originalPath()),
230 if (isDateVersioned()) {
231 result = result.version(QDate::currentDate());
235 if (isNumericallyVersioned()) {
237 result = result.version(result.highestVersionNum() + 1);
239 catch (IException &) {
240 result = result.version(1);
244 if (result.fileExists()) {
246 QObject::tr(
"Could not generate unique new version of file named [%1] in "
247 "[%2] because the file [%3] exists")
248 .arg(name()).arg(originalPath()).arg(result.name()),
257 FileName FileName::version(
long versionNumber)
const {
258 QString file =
FileName(expanded()).name();
260 int width = file.count(
"?");
262 if (versionNumber < 0) {
264 QObject::tr(
"FileName does not support negative version numbers in the file name, "
265 "tried to get version [%1] in file named [%2]")
266 .arg(versionNumber).arg(originalPath() +
"/" + file),
270 if (versionNumber >= pow(10.0, width)) {
272 QObject::tr(
"FileName does not support version numbers greater than what would fit in "
273 "the file name, tried to get version [%1] in file named [%2]")
274 .arg(versionNumber).arg(originalPath() +
"/" + file),
279 QString &before = splitName.first;
280 QString &after = splitName.second;
282 file = before + QString(
"%1").arg(QString::number(versionNumber), width,
'0') + after;
284 return FileName(originalPath() +
"/" + file);
288 FileName FileName::version(QDate versionDate)
const {
289 QString newName = versionDate.toString(fileNameQDatePattern());
291 return FileName(originalPath() +
"/" + newName);
295 bool FileName::fileExists()
const {
296 return QFileInfo(expanded()).exists();
300 QDir FileName::dir()
const {
301 return QFileInfo(expanded()).dir();
305 FileName FileName::createTempFile(FileName templateFileName) {
306 QString preppedFileName = QString(
"%1/%2XXXXXX.%3").arg(templateFileName.path())
307 .arg(templateFileName.baseName()).arg(templateFileName.extension());
308 QTemporaryFile tempFile(preppedFileName);
309 tempFile.setAutoRemove(
false);
311 if (!tempFile.open()) {
313 QObject::tr(
"Could not create a unique temporary file name based on [%1]")
314 .arg(templateFileName.original()),
321 QString newTempFileNameStr = templateFileName.originalPath() +
"/" +
322 QFileInfo(tempFile.fileName()).fileName();
323 result =
FileName(newTempFileNameStr);
329 QString FileName::toString()
const {
346 bool FileName::operator==(
const FileName &rhs) {
347 QString expandedOfThis = expanded();
348 QString canonicalOfThis = QFileInfo(expandedOfThis).canonicalFilePath();
350 QString expandedOfRhs = rhs.expanded();
351 QString canonicalOfRhs = QFileInfo(expandedOfRhs).canonicalFilePath();
356 bool equal = (!canonicalOfThis.isEmpty() && canonicalOfThis == canonicalOfRhs);
359 equal = (canonicalOfThis.isEmpty() && canonicalOfRhs.isEmpty() &&
360 expandedOfThis == expandedOfRhs);
368 bool FileName::operator!=(
const FileName &rhs) {
369 return !(*
this == rhs);
373 QDate FileName::highestVersionDate()
const {
374 QString fileQDatePattern = fileNameQDatePattern();
377 if (fileQDatePattern.contains(
"?")) {
378 QString trueLengthName = name().replace(QRegExp(
"[{}]"),
"");
379 truncateRange.first = trueLengthName.indexOf(
"?");
380 truncateRange.second = trueLengthName.lastIndexOf(
"?");
381 fileQDatePattern = fileQDatePattern.replace(
"?",
"");
384 QString file = name();
387 QDate sputnikLaunch(1957, 10, 4);
389 QString before = file.mid(0, file.indexOf(
"{"));
390 QString after = file.mid(file.lastIndexOf(
"}") + 1);
394 nameFilters.append(before +
"*" + after);
398 foreach (QString foundFile, files) {
400 if (truncateRange.first >= 0 && truncateRange.second > truncateRange.first) {
401 foundFile = foundFile.mid(0, truncateRange.first) +
402 foundFile.mid(truncateRange.second + 1);
406 QDate fileDate = QDate::fromString(foundFile, fileQDatePattern);
408 if (fileDate.isValid()) {
410 if (fileDate < sputnikLaunch)
411 fileDate = fileDate.addYears(100);
413 if (!result.isValid() || fileDate > result) {
419 if (!result.isValid()) {
421 QObject::tr(
"No existing files found with a date version matching [%1] in "
431 long FileName::highestVersionNum()
const {
432 QString file =
FileName(expanded()).name();
435 int width = file.count(
"?");
438 QString &before = splitName.first;
439 QString &after = splitName.second;
442 nameFilters.append(before + QString(
"%1").arg(
"", width,
'?') + after);
443 QStringList files = dir().entryList(nameFilters, QDir::NoFilter, QDir::Name);
445 long foundValue = -1;
446 bool success =
false;
448 for (
int i = files.count() - 1; !success && i >= 0; i--) {
449 foundValue = files[i].mid(before.count(), width).toLong(&success);
457 QObject::tr(
"No existing files found with a numerial version matching [%1] "
472 QString file = QFileInfo(expanded()).fileName();
474 if (file.contains(QRegExp(
"\\?\\?*[^?][^?]*\\?"))) {
476 QObject::tr(
"Only one numerical version sequence is allowed in a filename; "
477 "there are multiple in [%1]").arg(file),
481 if (isDateVersioned()) {
482 QString fileDatePattern =
FileName(expanded()).name();
488 fileDatePattern.replace(QRegExp(
"\\{\\}"),
"");
490 fileDatePattern =
"'" + fileDatePattern.replace(QRegExp(
"[{}]"),
"'") +
"'";
492 QString dated = QDate::currentDate().toString(fileDatePattern);
493 if (file.contains(
"'")) {
495 QObject::tr(
"Date version sequenced file names cannot have single quotes in them; "
496 "the file named [%1] is not usable").arg(file),
499 else if (dated ==
"") {
501 QObject::tr(
"The date version sequence is not usable in the file named [%1]").arg(file),
504 else if (dated == fileDatePattern.replace(QRegExp(
"'"),
"")) {
506 QObject::tr(
"The date version sequences are not recognized in the file named [%1]")
513 QString FileName::fileNameQDatePattern()
const {
515 QString file =
FileName(expanded()).name();
518 file = file.replace(QRegExp(
"[{}]"),
"'");
521 if (file.startsWith(
"'"))
527 if (file.endsWith(
"'"))
528 file = file.mid(0, file.length() - 1);
539 QString file =
FileName(expanded()).name();
543 if (!isNumericallyVersioned()) {
547 before = file.mid(0, file.indexOf(
"?"));
548 after = file.mid(file.lastIndexOf(
"?") + 1);
555 FileName::Data::Data() {
556 m_originalFileNameString = NULL;
557 m_expandedFileNameString = NULL;
559 m_originalFileNameString =
new QString;
560 m_expandedFileNameString =
new QString;
564 FileName::Data::Data(
const Data &other) :
QSharedData(other) {
565 m_originalFileNameString = NULL;
566 m_expandedFileNameString = NULL;
568 m_originalFileNameString =
new QString(*other.m_originalFileNameString);
569 m_expandedFileNameString =
new QString(*other.m_expandedFileNameString);
573 FileName::Data::~Data() {
574 delete m_originalFileNameString;
575 m_originalFileNameString = NULL;
577 delete m_expandedFileNameString;
578 m_expandedFileNameString = NULL;
582 QString FileName::Data::original(
bool includeAttributes)
const {
583 QString result = *m_originalFileNameString;
586 if (!includeAttributes) {
587 int attributesPos = result.indexOf(
"+");
589 if (attributesPos != -1)
590 result = result.left(attributesPos);
597 void FileName::Data::setOriginal(
const QString &originalStr) {
598 *m_originalFileNameString = originalStr;
601 QString expandedStr = original(
true);
603 int varSearchStartPos = 0;
604 int varStartPos = -1;
607 while((varStartPos = expandedStr.indexOf(
"$", varSearchStartPos)) != -1) {
608 int varEndPos = expandedStr.indexOf(QRegExp(
"[^a-zA-Z{}0-9]"), varStartPos + 1);
610 varEndPos = expandedStr.length();
612 bool variableValid =
false;
613 int varNameLength = varEndPos - varStartPos;
615 if (varNameLength > 0) {
616 QString varName = expandedStr.mid(varStartPos + 1, varEndPos - varStartPos - 1);
618 if (varName.length()) {
619 if (varName[0] ==
'{' && varName[varName.length() - 1] ==
'}')
620 varName = varName.mid(1, varName.length() - 2);
625 if(Preference::Preferences().hasGroup(
"DataDirectory")) {
626 PvlGroup &dataDir = Preference::Preferences().findGroup(
"DataDirectory");
627 if(dataDir.hasKeyword(varName)) {
628 varValue = ((QString)dataDir[varName.toStdString().c_str()][0]);
633 if (varValue.isEmpty()) {
635 val = getenv(varName.toStdString().c_str());
636 if(val != NULL) varValue = val;
642 if (!varValue.isEmpty()) {
643 expandedStr = expandedStr.replace(varStartPos, varNameLength, varValue);
644 variableValid =
true;
651 varSearchStartPos = varStartPos;
655 varSearchStartPos = varStartPos + 1;
659 *m_expandedFileNameString = expandedStr;
663 QString FileName::Data::expanded(
bool includeAttributes)
const {
664 QString result = *m_expandedFileNameString;
667 if (!includeAttributes) {
668 int attributesPos = result.indexOf(
"+");
670 if (attributesPos != -1)
671 result = result.left(attributesPos);
File name manipulation and expansion.
A type of error that occurred when performing an actual I/O operation.
void validateVersioningState() const
This verifies the class invariant when using versioning - that the FileName is in an acceptable state...
#define _FILEINFO_
Macro for the filename and line number.
A type of error that cannot be classified as any of the other error types.
This is the reference-counted data for FileName.
FileName & operator=(const FileName &rhs)
Clears the current contents of the FileName object and reinitializes it with the argument.
~FileName()
Destroys the FileName object.
FileName()
Constructs an empty FileName object.
QString path() const
Returns the path.
QSharedDataPointer< Data > m_d