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