Swift for Xojo Developers : Part 1 - FolderItem

Swift has a rather robust file handling ability. but for those of us familiar with Xojo, the Folderitem is the method we are most familar with.

Here is a Swift class (part of a larger File handling module).
The other classes will be posted in the days to come

/*
 +------------+----------------------------------------------------------------+
 |       Name | folderitem                                                     |
 +------------+----------------------------------------------------------------+
 |       Type | class                                                          |
 +------------+----------------------------------------------------------------+
 |  Properties| count                isReadable           parent               |
 |            | creationDate         isWriteable          path                 |
 |            | displayName          length               URL                  |
 |            | exists               modificationDate     URLpath              |
 |            | isFolder             name                                      |
 +------------+----------------------------------------------------------------+
 |     Methods| CopyTo               Delete                                    |
 |            | CreateAsFolder       MoveTo                                    |
 +------------+----------------------------------------------------------------+
 |   Functions| child                item                                      |
 +------------+----------------------------------------------------------------+
 */
private var zLastError     : Bool = false
private var zLastErrorCode : Int = 0
private var zLastErrorMsg  : String = "OK"
/**
 The FolderItem class objects represent files or folders
 - Author:
 R.David Sisemore
 - Version:
 0.1
 */
class folderitem {
    private var zPath         : URL
    private var zFiles        = [String]()
    private var zNeedsRefresh : Bool = true

    required init(path : URL) {
        zPath=path
        zNeedsRefresh=true
        ThrowErrorMessage( .OK )
    }
    /**
     The name of the *FolderItem*. Changing this name will change the name of the file or folder.
     ````
     aFolderItem.Name = newStringValue
     or
     StringValue = aFolderItem.Name
     ````
     */
    var name : String {
        get { return fileMANAGER.displayName(atPath: zPath.absoluteString) }
        set {
            ThrowErrorMessage( .OK )
            do {
                let newNAME = newValue
                let oldPath = zPath
                let newPath = child(newNAME).URL
                try fileMANAGER.moveItem(at: oldPath, to: newPath)
                zPath=newPath
                zNeedsRefresh=true
            } catch let error as NSError {
                ThrowError( .RENAME,error)
            }
        }
    }

    ///  Returns the FolderItem object for the parent of this item in the file hierarchy.
    var parent           : folderitem { get { return folderitem(path:zPath.deletingLastPathComponent()) } }

    /// The name of the FolderItem as it should be seen by the user. [readonly version of 'name']
    var displayName      : String     { get { return name } }

    /// Indicates whether or not the folder item points to a file or directory that exists.
    var exists           : Bool       { get { return fileMANAGER.fileExists(atPath: path) } }
    /// True if the FolderItem is a directory (a folder). [same as Xojo folderitem.Directory]
    var isFolder         : Bool       { get { return fileMANAGER.isDirectoryAtPath(zPath) } }
    /// True if you have permissions to write to the FolderItem.
    var isWriteable      : Bool       { get { return fileMANAGER.isWritableFile(atPath: path) } } //zPath.absoluteString) } }
    /// True if you have permissions to read from the FolderItem.
    var isReadable       : Bool       { get { return fileMANAGER.isReadableFile(atPath: path) } } //zPath.absoluteString) } }
    /// Contains the error code for the last supported operation on the FolderItem.
    var lastErrorCode    : Int        { get { return zLastErrorCode } }
    ///  Contains the error message for the last supported operation on the FolderItem.
    var lastErrorMessage : String     { get { return zLastErrorMsg } }
    /// The number of items in the FolderItem if it is a directory/folder.
    var count            : Int        { get { refresh();  return zFiles.count } }
    /// The size of the file in bytes. For directories, the size will be zero.
    var length : Int    {
        get {
            if let fileAttr = try? fileMANAGER.attributesOfItem(atPath: path),
                let fileSize=fileAttr[.size] as! Int?   {
                return fileSize
            }
            return 0
        }
    }
    /// The modification date of the FolderItem.
    var modificationDate : String { get { return fileDate(.modificationDate) } }
    /// The creation date of the FolderItem.
    var creationDate     : String { get { return fileDate(.creationDate) } }
    /// The full path to the FolderItem [Xojo folderitem.NativePath]
    var path             : String { get { return zPath.path } }
    var URLpath          : String { get { return zPath.absoluteString } }
    var URL              : URL    { get { return zPath} }
    /**
     Returns a FolderItem that represents a file or directory within this FolderItem with the name Name.
     ````
     newFolderItem = FolderItem.child(Name)
     ````
     */
    func child(_ name:String) -> folderitem {
        let tempPath : URL = zPath.appendingPathComponent(name) // Destination Path in /Documents
        return folderitem(path: tempPath)
    }
    /**
     If this FolderItem is a directory, Index is an element in a one-based array of FolderItems in this directory.
     ````
     newFolderItem = FolderItem.item(int)
     ````
     */
    func item(_ index:Int) -> folderitem? {
        refresh()
        ThrowErrorMessage( .OK )
        if index>=0 && index<zFiles.count {
            return self.child(zFiles[index])
        } else {
            ThrowError( .INDEX)
            return nil
        }
    }


    func CopyTo(name:String) {
        ThrowErrorMessage( .OK )
        do {
            let oldPath = zPath
            let newPath = parent.child(name).URL
            try fileMANAGER.copyItem(at: oldPath, to: newPath)
        } catch let error as NSError { ThrowError( .COPY,error) }
    }

    func MoveTo(destination:String) {
        ThrowErrorMessage( .OK )
        do {
            let oldPath = zPath
            let newPath = parent.child(destination).URL
            try fileMANAGER.moveItem(at: oldPath, to: newPath)
            zPath=newPath
            zNeedsRefresh=true
        } catch let error as NSError { ThrowError( .MOVE,error) }
    }
    ///        Creates a folder at the location specified by the FolderItem properties.

    func CreateAsFolder() {
        ThrowErrorMessage( .OK )
        if fileMANAGER.fileExists(atPath: path) {
            return
        } // already exists
        do {
            try fileMANAGER.createDirectory(atPath: path,withIntermediateDirectories: false, attributes: nil)
        } catch let error as NSError { ThrowError( .DIRECTORY,error) }
    }
    /// Deletes the file or directory specified by the FolderItem.
    func Delete() {
        ThrowErrorMessage( .OK )
        do {
            try fileMANAGER.removeItem(atPath: path)
            zNeedsRefresh=true
        } catch let error as NSError { ThrowError( .DELETE,error) }
    }
    //
    // ------ P R I V A T E   F U N C T I O N S ------
    //
    private func fileDate(_ dateID : FileAttributeKey) -> String {
        if let infoAttr = try? fileMANAGER.attributesOfItem(atPath: path),
            let infoDate = infoAttr[dateID] as! Date?
        {
            let dateFormatter = DateFormatter()
            dateFormatter.locale = Locale.current
            dateFormatter.dateFormat = "dd-MMM-yyyy HH:mm"
            return dateFormatter.string(from: infoDate)
        }
        return "<no date>"
    }

    private func refresh() {
        if zNeedsRefresh {
            do {
                zFiles = try fileMANAGER.contentsOfDirectory(atPath: path)
            } catch  {
                zFiles = []
            }
            if zFiles.count>0 {
                zFiles.sort()
                for i in(0...zFiles.count-1).reversed() {
                    if Left(zFiles[i],1)=="." { zFiles.remove(at: i) }
                }
            }
            zNeedsRefresh=false
        }
    }

    private func ThrowError(_ errCode : fileERRORS,_ error:NSError) {
        ThrowErrorMessage(errCode,"\(error.localizedDescription)")
    }

    private func ThrowError(_ errCode : fileERRORS,errorMsg:String="") {
        ThrowErrorMessage(errCode,errorMsg)
    }
}
2 Likes