Hi,
i just want to ask for a little advice.
For my UI Blueprinti need a “SelectDirectory” Dialog but so far i didn’t found a way to browse thru directories in Blueprint, so i wrote a little c++ class to do just that.
The thing is i never realy done anything in c++, i began coding in perl so the syntax is somewhat familiar but in the last years if i had to code something
i used PureBasic (nice little language) and the nearest you go OOP there is over interfaces.
So to get to the point, this is practically my first c++ class and i want to ask if some one would look over it and point out what i did wrong or if it is ok how it is.
Thanks in advance and sorry for my bad english.
DirectoryWatch.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "DirectoryWatch.generated.h"
struct FDirectoryWatch_DirectoryEntry
{
FString EntryName;
FString Path;
FDateTime EntryDateTime;
};
struct FDirectoryWatch_Directory
{
int32 CurrentEntry;
TArray<FDirectoryWatch_DirectoryEntry> DList;
};
/**
*
*/
UCLASS(Blueprintable)
class UDirectoryWatch : public UObject
{
GENERATED_UCLASS_BODY()
~UDirectoryWatch();
public:
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Checks if the Filename has only valid characters"))
virtual void CheckFilename(FString Filename, bool &IsValid);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the size of the specified file or -1 if 'file not found' or -2 'file is a directory'"))
virtual void FileSize(FString Filename, int32 &FileSize);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the dates of the file"))
virtual void GetFileDate(FString Filename, FDateTime& Accessed, FDateTime& Created, FDateTime& Modified, bool &FileExists);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the current directory for the program."))
virtual void GetCurrentDirectory(FString &CurrentDirectory);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Returns the current directory for the program."))
virtual void SetCurrentDirectory(FString Directory, FString &CurrentDirectory);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Gets the path part of a full path"))
virtual void GetPathPart(FString Path, FString &PathPart);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Return the home directory of the user"))
virtual void GetHomeDirectory(FString &HomeDirectory);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Retrieves the file extension part of a full path"))
virtual void GetExtensionPart(FString Path, FString &Extension);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Checks if the path read only"))
virtual void GetReadWriteStatus(FString Path, bool &IsReadOnly);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Gets the file part of a full path"))
virtual void GetFilePart(FString Path, bool WithExtension, FString &FilePart);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Gets the full path to the temporary directory"))
virtual void GetTemporaryDirectory( FString &TemporaryDirectory);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Examine the given directory"))
virtual void ExamineDirectory(int32 &DirectoryID, FString DirectoryPath = "");
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the name off the current entry in the directory list."))
virtual void DirectoryEntryName(int32 DirectoryID, FString &DirectoryName);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the Path off the current entry in the directory list."))
virtual void DirectoryEntryPath(int32 DirectoryID, FString &PathName);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "This function must be called after an ExamineDirectory()! It will get the next directory entry."))
virtual void NextDirectoryEntry(int32 DirectoryID, bool & IsLastEntry);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Resets the NextDirectoryEntry back to 0."))
virtual void ResetDirectoryList(int32 DirectoryID);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the dates off the current entry in the directory list."))
virtual void DirectoryEntryDate(int32 DirectoryID, FDateTime& Accessed, FDateTime& Created, FDateTime& Modified);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the size of the current entry."))
virtual void DirectoryEntrySize(int32 DirectoryID, int32 &FileSize);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the type of the current entry."))
virtual void DirectoryEntryType(int32 DirectoryID, bool &IsFile, bool &IsDirectory, bool &IsExistent);
UFUNCTION(BlueprintPure, Category = "DirectoryWatch", meta = (ToolTip = "Returns the how many entrys are in the given list."))
virtual void DirectoryEntryCount(int32 DirectoryID, int32 &EntryCount);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "This frees the resources associated the given DirectoryID."))
virtual void FinishDirectory(int32 DirectoryID);
/*
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Set the modification time of a file."))
virtual FString SetFileDate(FString File, FDateTime DateTime);
*/
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Copy an entire directory to a new location."))
virtual void CopyDirectory(FString SourceDirectory, FString DestinationDirectory, bool Force, bool & Successful);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Delete an entire directory to a new location."))
virtual void DeleteDirectory(FString DirectoryPath, bool & Successful);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Create a directory"))
virtual void CreateDirectory(FString DirectoryPath, bool & Successful);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Copy a file to a new location"))
virtual void CopyFile(FString SourceFile, FString DestinationDirectory, bool Replace, bool Force, int32 & Successful);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Delete a file"))
virtual void DeleteFile(FString SourceFile, bool Force, bool & Successful);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "Rename or move a file a file"))
virtual void RenameOrMoveFile(FString SourceFile, FString NewName, bool & Successful);
UFUNCTION(BlueprintCallable, Category = "DirectoryWatch", meta = (ToolTip = "This function frees all the resources in the list"))
virtual void FinishAllDirectory();
private:
// File interface
IPlatformFile * FileInterface;
// Path helpers for retrieving game dir, engine dir, etc.
FPaths PathHelpers;
IFileManager * FileManager;
// All files accesses are relative to this directory, when no absolute path is specified.
FString CurrentPathVar;
private:
// make a absolut path out off a relative one
FString isRelative_UpdatePath(FString Path);
// Clear the path off all the "\"
FString CleanPath(FString Path);
// Map of all the examined directoriess
TMap<int32, FDirectoryWatch_Directory> CurrentDirectoryList;
};
// Overwrite the visit function and fill the directory array
class FDirectoryWatchVisitor : public IPlatformFile::FDirectoryVisitor
{
public:
/** Relative paths to local files and their timestamps. */
TArray<FDirectoryWatch_DirectoryEntry> Directories;
TArray<FDirectoryWatch_DirectoryEntry> Files;
FDirectoryWatchVisitor(IPlatformFile& InFileInterface) : FileInterface(InFileInterface) {}
virtual bool Visit(const TCHAR* Filename, bool bIsDirectory)
{
FString RelativeFilename = Filename;
FPaths::MakeStandardFilename(RelativeFilename);
this->TMPEntry.EntryName = RelativeFilename;
this->TMPEntry.Path = Filename;
this->TMPEntry.EntryDateTime = FileInterface.GetTimeStamp(Filename);
if (bIsDirectory)
{
this->Directories.Add(TMPEntry);
}
else
{
this->Files.Add(TMPEntry);
}
return true;
}
private:
IPlatformFile& FileInterface;
FDirectoryWatch_DirectoryEntry TMPEntry;
};
DirectoryWatch.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "DirectoryWatch.h"
UDirectoryWatch::UDirectoryWatch(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
this->FileInterface = &FPlatformFileManager::Get().GetPlatformFile();
this->FileManager = &IFileManager::Get();
this->PathHelpers = FPaths();
this->CurrentPathVar = this->PathHelpers.GameDir();
}
UDirectoryWatch::~UDirectoryWatch()
{
this->FinishAllDirectory();
}
FString UDirectoryWatch::isRelative_UpdatePath(FString Path)
{
if (this->PathHelpers.IsRelative(Path))
{
FString OutPath = this->CurrentPathVar + Path;
return OutPath;
}
return Path;
}
FString UDirectoryWatch::CleanPath(FString Path)
{
return Path.Replace(TEXT("\\"), TEXT("/"));
}
// Checks if the Filename has only valid characters
void UDirectoryWatch::CheckFilename(FString Filename, bool &IsValid)
{
Filename = this->isRelative_UpdatePath(CleanPath(Filename));
IsValid = this->PathHelpers.ValidatePath(Filename);
return;
}
// Returns the size of the specified file or -1 if "file not found" or -2 "file is a directory"
void UDirectoryWatch::FileSize(FString Filename, int32 &FileSize)
{
Filename = CleanPath(Filename);
if (this->FileInterface->DirectoryExists(*Filename))
{
FileSize = -2;
return;
}
FileSize = this->FileInterface->FileSize(*Filename);
return;
}
//Returns the current directory for the program (default is GameDir())
void UDirectoryWatch::GetCurrentDirectory(FString &CurrentDirectory)
{
if (this->CurrentPathVar == "")
{
CurrentDirectory = this->PathHelpers.GameDir();
return;
}
CurrentDirectory = "";
return;
}
//Gets the path part of a full path
void UDirectoryWatch::GetExtensionPart(FString Path, FString &Extension)
{
Extension = this->PathHelpers.GetExtension(CleanPath(Path), false);
return;
}
//Gets the path part of a full path
void UDirectoryWatch::GetReadWriteStatus(FString Path, bool &IsReadOnly)
{
Path = this->isRelative_UpdatePath(CleanPath(Path));
IsReadOnly = this->FileInterface->IsReadOnly(*Path);
return;
}
// Returns the dates of the file
void UDirectoryWatch::GetFileDate(FString Filename, FDateTime& Accessed, FDateTime& Created, FDateTime& Modified, bool &FileExists)
{
Filename = this->isRelative_UpdatePath(CleanPath(Filename));
if ((this->FileInterface->FileExists(*Filename)) || (this->FileInterface->DirectoryExists(*Filename)))
{
Accessed = this->FileInterface->GetAccessTimeStamp(*Filename);
Modified = this->FileInterface->GetTimeStamp(*Filename);
int64 FileAgeSeconds = this->FileManager->GetFileAgeSeconds(*Filename);
int64 Today = FDateTime::Now().ToUnixTimestamp();
int64 FileAge = Today - FileAgeSeconds;
Created = FDateTime::FromUnixTimestamp(FileAge);
FileExists = true;
return;
}
FileExists = false;
return;
}
//Gets the path part of a full path
void UDirectoryWatch::GetPathPart(FString Path, FString &CurrentDirectory)
{
Path = this->isRelative_UpdatePath(CleanPath(Path));
CurrentDirectory = this->PathHelpers.GetPath(*Path);
return;
}
void UDirectoryWatch::GetHomeDirectory(FString &HomeDirectory)
{
HomeDirectory = FPlatformProcess::UserDir();
return;
}
//Gets the file part of a full path
void UDirectoryWatch::GetFilePart(FString FilePath, bool WithExtension, FString &FilePart)
{
FilePath = this->isRelative_UpdatePath(CleanPath(FilePath));
if (this->FileInterface->FileExists(*FilePath))
{
if (WithExtension)
{
FilePart = this->PathHelpers.GetCleanFilename(*FilePath);
return;
}
FilePart = this->PathHelpers.GetBaseFilename(*FilePath);
return;
}
else
{
FilePart = "";
}
return;
}
// Gets the full path to the temporary directory
void UDirectoryWatch::GetTemporaryDirectory(FString &TemporaryDirectory)
{
TemporaryDirectory = CleanPath(FPlatformProcess::UserTempDir());
return;
}
//Returns the current directory for the program
void UDirectoryWatch::SetCurrentDirectory(FString Directory, FString &CurrentDirectory)
{
Directory = this->isRelative_UpdatePath(CleanPath(Directory));
if (this->FileInterface->DirectoryExists(*Directory))
{
this->CurrentPathVar = Directory;
if (this->CurrentPathVar.Right(1) != "/") this->CurrentPathVar += "/";
CurrentDirectory = this->CurrentPathVar;
return;
}
CurrentDirectory = "";
return;
}
//Examine the given directory
void UDirectoryWatch::ExamineDirectory(int32 &DirectoryID, FString DirectoryPath)
{
DirectoryPath = this->isRelative_UpdatePath(CleanPath(DirectoryPath));
FString CurrentDirectory;
SetCurrentDirectory(DirectoryPath, CurrentDirectory);
if (CurrentDirectory == "") return;
DirectoryID = FCrc::StrCrc32(*DirectoryPath);
if (this->CurrentDirectoryList.Find(DirectoryID))
{
this->CurrentDirectoryList.Remove(DirectoryID);
}
this->CurrentDirectoryList.Add(DirectoryID);
FDirectoryWatchVisitor Visitor(*this->FileInterface);
Visitor.Visit(*DirectoryPath, true);
this->FileInterface->IterateDirectory(*DirectoryPath, Visitor);
this->CurrentDirectoryList[DirectoryID].DList = Visitor.Directories;
this->CurrentDirectoryList[DirectoryID].DList.Append(Visitor.Files);
Visitor.Directories.Empty();
Visitor.Files.Empty();
return;
}
// Get the next entry. Must be called after an ExamineDirectory()
void UDirectoryWatch::NextDirectoryEntry(int32 DirectoryID, bool & IsLastEntry)
{
IsLastEntry = false;
int32 CurrentEntry = this->CurrentDirectoryList[DirectoryID].CurrentEntry;
int32 NextEntry = this->CurrentDirectoryList[DirectoryID].CurrentEntry + 1;
if (NextEntry >= this->CurrentDirectoryList[DirectoryID].DList.Num())
{
IsLastEntry = true;
return;
}
else
{
this->CurrentDirectoryList[DirectoryID].CurrentEntry++;
}
return;
}
// Resets the NextDirectoryEntry back to 0
void UDirectoryWatch::ResetDirectoryList(int32 DirectoryID)
{
this->CurrentDirectoryList[DirectoryID].CurrentEntry = 0;
return;
}
// Returns the name off the current entry in the directory list
void UDirectoryWatch::DirectoryEntryName(int32 DirectoryID, FString &DirectoryName)
{
int32 CurrentEntry = this->CurrentDirectoryList[DirectoryID].CurrentEntry;
DirectoryName = this->PathHelpers.GetCleanFilename(*this->CurrentDirectoryList[DirectoryID].DList[CurrentEntry].EntryName);
return;
}
// Returns the Path off the current entry in the directory list
void UDirectoryWatch::DirectoryEntryPath(int32 DirectoryID, FString &PathName)
{
PathName = this->CurrentDirectoryList[DirectoryID].DList[this->CurrentDirectoryList[DirectoryID].CurrentEntry].Path;
return;
}
// Returns the dates off the current entry in the directory list
void UDirectoryWatch::DirectoryEntryDate(int32 DirectoryID, FDateTime& Accessed, FDateTime& Created, FDateTime& Modified)
{
FString CurrentFile = this->CurrentDirectoryList[DirectoryID].DList[this->CurrentDirectoryList[DirectoryID].CurrentEntry].Path;
bool Exists;
this->GetFileDate(CurrentFile, Accessed, Created, Modified, Exists);
return;
}
// Returns the size of the current entry
void UDirectoryWatch::DirectoryEntrySize(int32 DirectoryID, int32 &FileSize)
{
FString CurrentFile = this->CurrentDirectoryList[DirectoryID].DList[this->CurrentDirectoryList[DirectoryID].CurrentEntry].Path;
this->FileSize(CurrentFile, (int32&)FileSize);
return;
}
// Returns the type of the current entry
void UDirectoryWatch::DirectoryEntryType(int32 DirectoryID, bool &IsFile, bool &IsDirectory, bool &IsExistent)
{
IsFile = false;
IsDirectory = false;
IsExistent = true;
FString CurrentFile = this->CurrentDirectoryList[DirectoryID].DList[this->CurrentDirectoryList[DirectoryID].CurrentEntry].Path;
int32 FileSize;
this->FileSize(CurrentFile, (int32&) FileSize);
if (FileSize >= 0) IsFile = true;
if (FileSize == -1) IsExistent = false;
if (FileSize == -2) IsDirectory = true;
return;
}
// Returns the how many entrys are in the given list
void UDirectoryWatch::DirectoryEntryCount(int32 DirectoryID, int32 &EntryCount)
{
EntryCount = this->CurrentDirectoryList[DirectoryID].DList.Num() - 1;
return;
}
// This function frees the resources associated the given DirectoryID.
void UDirectoryWatch::FinishDirectory(int32 DirectoryID)
{
this->CurrentDirectoryList[DirectoryID].DList.Empty();
this->CurrentDirectoryList.Remove(DirectoryID);
return;
}
// This function frees all the resources in the list
void UDirectoryWatch::FinishAllDirectory()
{
for (auto ListIT = CurrentDirectoryList.CreateIterator(); ListIT; ++ListIT)
{
this->CurrentDirectoryList[ListIT.Key()].DList.Empty();
}
this->CurrentDirectoryList.Empty();
return;
}
// Set the modification time of a file
/*
FString UDirectoryWatch::SetFileDate(FString File, FDateTime DateTime)
{
File = this->isRelative_UpdatePath(CleanPath(File));
int32 FileSize;
this->FileSize(File, FileSize);
if (FileSize == -1) return "-1";
this->FileInterface->SetTimeStamp(*File, DateTime);
return File;
}
*/
// Copy an entire directory to a new location.
void UDirectoryWatch::CopyDirectory(FString SourceDirectory, FString DestinationDirectory, bool Force, bool & Successful)
{
SourceDirectory = this->isRelative_UpdatePath(CleanPath(SourceDirectory));
DestinationDirectory = this->isRelative_UpdatePath(CleanPath(DestinationDirectory));
if (!this->FileInterface->DirectoryExists(*SourceDirectory)) return;
if (!this->FileInterface->DirectoryExists(*DestinationDirectory)) return;
if (DestinationDirectory.Contains(SourceDirectory)) return;
Successful = this->FileInterface->CopyDirectoryTree(*DestinationDirectory, *SourceDirectory, Force);
return;
}
// Delete an entire directory to a new location.
void UDirectoryWatch::DeleteDirectory(FString DirectoryPath, bool & Successful)
{
DirectoryPath = this->isRelative_UpdatePath(CleanPath(DirectoryPath));
if (!this->FileInterface->DirectoryExists(*DirectoryPath)) return;
Successful = this->FileManager->DeleteDirectory(*DirectoryPath, true, true);
return;
}
// Create a new Directory
void UDirectoryWatch::CreateDirectory(FString DirectoryPath, bool & Successful)
{
DirectoryPath = this->isRelative_UpdatePath(CleanPath(DirectoryPath));
Successful = this->FileInterface->CreateDirectory(*DirectoryPath);
return;
}
// Copy a file to a new location.
void UDirectoryWatch::CopyFile(FString SourceFile, FString DestinationDirectory, bool Replace, bool Force, int32 & Successful)
{
SourceFile = this->isRelative_UpdatePath(CleanPath(SourceFile));
DestinationDirectory = this->isRelative_UpdatePath(CleanPath(DestinationDirectory));
if (!this->FileInterface->FileExists(*SourceFile)) return;
Successful = this->FileManager->Copy(*DestinationDirectory, *SourceFile, Replace, Force, true, nullptr);
return;
}
// Delete a file
void UDirectoryWatch::DeleteFile(FString SourceFile, bool Force, bool & Successful)
{
SourceFile = this->isRelative_UpdatePath(CleanPath(SourceFile));
if (!this->FileInterface->FileExists(*SourceFile)) return;
Successful = this->FileManager->Delete(*SourceFile, false, Force, false);
return;
}
// Rename or move a file a file
void UDirectoryWatch::RenameOrMoveFile(FString SourceFile, FString NewName, bool & Successful)
{
SourceFile = this->isRelative_UpdatePath(CleanPath(SourceFile));
if (!this->FileInterface->FileExists(*SourceFile)) return;
Successful = this->FileInterface->MoveFile(*NewName, *SourceFile);
return;
}
Here an image of the test in Blueprint