Download

Just asking for a little advice please

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