-- Path of Building
--
-- Module: Build List
-- Displays the list of builds.
--
local pairs = pairs
local ipairs = ipairs
local t_insert = table.insert
local buildSortDropList = {
{ label = "Sort by Name", sortMode = "NAME" },
{ label = "Sort by Class", sortMode = "CLASS" },
{ label = "Sort by Last Edited", sortMode = "EDITED"},
{ label = "Sort by Level", sortMode = "LEVEL"},
}
local listMode = new("ControlHost")
function listMode:Init(selBuildName, subPath)
if self.initialised then
self.subPath = subPath or self.subPath
self.controls.buildList.controls.path:SetSubPath(self.subPath)
self.controls.buildList:SelByFileName(selBuildName and selBuildName..".xml")
--if main.showPublicBuilds then
if false then
self.controls.ExtBuildList = self:getPublicBuilds()
else
self.controls.ExtBuildList = nil
end
self:BuildList()
self:SelectControl(self.controls.buildList)
return
end
self.anchor = new("Control", nil, {0, 4, 0, 0})
self.anchor.x = function()
return main.screenW / 2
end
self.subPath = subPath or ""
self.list = { }
self.controls.new = new("ButtonControl", {"TOP",self.anchor,"TOP"}, {-259, 0, 60, 20}, "New", function()
main:SetMode("BUILD", false, "Unnamed build")
end)
self.controls.newFolder = new("ButtonControl", {"LEFT",self.controls.new,"RIGHT"}, {8, 0, 90, 20}, "New Folder", function()
self.controls.buildList:NewFolder()
end)
self.controls.open = new("ButtonControl", {"LEFT",self.controls.newFolder,"RIGHT"}, {8, 0, 60, 20}, "Open", function()
self.controls.buildList:LoadBuild(self.controls.buildList.selValue)
end)
self.controls.open.enabled = function() return self.controls.buildList.selValue ~= nil end
self.controls.copy = new("ButtonControl", {"LEFT",self.controls.open,"RIGHT"}, {8, 0, 60, 20}, "Copy", function()
self.controls.buildList:RenameBuild(self.controls.buildList.selValue, true)
end)
self.controls.copy.enabled = function() return self.controls.buildList.selValue ~= nil end
self.controls.rename = new("ButtonControl", {"LEFT",self.controls.copy,"RIGHT"}, {8, 0, 60, 20}, "Rename", function()
self.controls.buildList:RenameBuild(self.controls.buildList.selValue)
end)
self.controls.rename.enabled = function() return self.controls.buildList.selValue ~= nil end
self.controls.delete = new("ButtonControl", {"LEFT",self.controls.rename,"RIGHT"}, {8, 0, 60, 20}, "Delete", function()
self.controls.buildList:DeleteBuild(self.controls.buildList.selValue)
end)
self.controls.delete.enabled = function() return self.controls.buildList.selValue ~= nil end
self.controls.sort = new("DropDownControl", {"LEFT",self.controls.delete,"RIGHT"}, {8, 0, 140, 20}, buildSortDropList, function(index, value)
main.buildSortMode = value.sortMode
self:SortList()
end)
self.controls.sort:SelByValue(main.buildSortMode, "sortMode")
self.controls.buildList = new("BuildListControl", {"TOP",self.anchor,"TOP"}, {0, 75, 900, 0}, self)
self.controls.buildList.height = function()
return main.screenH - 80
end
local buildListWidth = function ()
--if main.showPublicBuilds then
if false then
return math.min((main.screenW / 2), 900)
else
return 900
end
end
local buildListOffset = function ()
--if main.showPublicBuilds then
if false then
local offset = math.min(450, main.screenW / 4)
return offset - 450
else
return 0
end
end
self.controls.buildList.width = buildListWidth
self.controls.buildList.x = buildListOffset
--if main.showPublicBuilds then
if false then
self.controls.ExtBuildList = self:getPublicBuilds()
end
self.controls.searchText = new("EditControl", {"TOP",self.anchor,"TOP"}, {0, 25, 640, 20}, self.filterBuildList, "Search", "%c%(%)", 100, function(buf)
main.filterBuildList = buf
self:BuildList()
end, nil, nil, true)
self.controls.searchText.width = buildListWidth
self.controls.searchText.x = buildListOffset
self:BuildList()
self.controls.buildList:SelByFileName(selBuildName and selBuildName..".xml")
self:SelectControl(self.controls.buildList)
self.initialised = true
end
function listMode:getPublicBuilds()
local buildProviders = {
{
name = "PoB Archives",
impl = new("PoBArchivesProvider", "builds")
}
}
local extBuildList = new("ExtBuildListControl", {"LEFT",self.controls.buildList,"RIGHT"}, {25, 0, main.screenW * 1 / 4 - 50, 0}, buildProviders)
extBuildList:Init("PoB Archives")
extBuildList.height = function()
return main.screenH - 80
end
extBuildList.width = function ()
return math.max((main.screenW / 4 - 50), 400)
end
return extBuildList
end
function listMode:Shutdown()
end
function listMode:GetArgs()
return self.controls.buildList.selValue and self.controls.buildList.selValue.buildName or false, self.subPath
end
function listMode:OnFrame(inputEvents)
for id, event in ipairs(inputEvents) do
if event.type == "KeyDown" then
if event.key == "v" and IsKeyDown("CTRL") then
if self.controls.buildList.copyBuild then
local build = self.controls.buildList.copyBuild
if build.subPath ~= self.subPath then
if build.folderName then
main:CopyFolder(build.folderName, main.buildPath..build.subPath, main.buildPath..self.subPath)
else
copyFile(build.fullFileName, self:GetDestName(self.subPath, build.fileName))
end
self:BuildList()
else
self.controls.buildList:RenameBuild(build, true)
end
self.controls.buildList.copyBuild = nil
elseif self.controls.buildList.cutBuild then
local build = self.controls.buildList.cutBuild
if build.subPath ~= self.subPath then
if build.folderName then
main:MoveFolder(build.folderName, main.buildPath..build.subPath, main.buildPath..self.subPath)
else
os.rename(build.fullFileName, self:GetDestName(self.subPath, build.fileName))
end
self:BuildList()
end
self.controls.buildList.cutBuild = nil
end
elseif event.key == "n" and IsKeyDown("CTRL") then
main:SetMode("BUILD", false, "Unnamed build")
elseif event.key == "MOUSE4" then
self.controls.buildList.controls.path:Undo()
elseif event.key == "MOUSE5" then
self.controls.buildList.controls.path:Redo()
end
end
end
self:ProcessControlsInput(inputEvents, main.viewPort)
main:DrawBackground(main.viewPort)
self:DrawControls(main.viewPort)
end
function listMode:GetDestName(subPath, fileName)
local i = 2
local destName = fileName
while true do
local test = io.open(destName, "r")
if test then
destName = fileName .. "[" .. i .. "]"
i = i + 1
else
break
end
end
return main.buildPath..subPath..destName
end
function listMode:BuildList()
wipeTable(self.list)
local filterList = main.filterBuildList or ""
local handle = nil
if filterList ~= "" then
handle = NewFileSearch(main.buildPath..self.subPath.."*"..filterList.."*.xml")
else
handle = NewFileSearch(main.buildPath..self.subPath.."*.xml")
end
while handle do
local fileName = handle:GetFileName()
local build = { }
build.fileName = fileName
build.subPath = self.subPath
build.fullFileName = main.buildPath..self.subPath..fileName
build.modified = handle:GetFileModifiedTime()
build.buildName = fileName:gsub("%.xml$","")
local fileHnd = io.open(build.fullFileName, "r")
if fileHnd then
local fileText = fileHnd:read("*a")
fileHnd:close()
if not fileText then
main:OpenCloudErrorPopup(build.fullFileName)
return
end
fileText = fileText:match("(<Build.->)")
if fileText then
local xml = common.xml.ParseXML(fileText.."</Build>")
if xml and xml[1] then
build.level = tonumber(xml[1].attrib.level)
build.className = xml[1].attrib.className
build.ascendClassName = xml[1].attrib.ascendClassName
end
end
end
t_insert(self.list, build)
if not handle:NextFile() then
break
end
end
handle = NewFileSearch(main.buildPath..self.subPath.."*", true)
while handle do
local folderName = handle:GetFileName()
t_insert(self.list, {
folderName = folderName,
subPath = self.subPath,
fullFileName = main.buildPath..self.subPath..folderName,
modified = handle:GetFileModifiedTime()
})
if not handle:NextFile() then
break
end
end
self:SortList()
end
function listMode:SortList()
local oldSelFileName = self.controls.buildList.selValue and self.controls.buildList.selValue.fileName
table.sort(self.list, function(a, b)
local a_is_folder = a.folderName ~= nil
local b_is_folder = b.folderName ~= nil
if a_is_folder and not b_is_folder then return true end
if not a_is_folder and b_is_folder then return false end
if main.buildSortMode == "EDITED" then
local modA = a.modified or 0 -- Use 0 as fallback if modified time is nil
local modB = b.modified or 0
if modA ~= modB then
return modA > modB -- Newest first maybe allow for inverting of order?
end
-- If modified times are the same or both 0 fall back to name sort
if a_is_folder then
return naturalSortCompare(a.folderName, b.folderName)
else
return naturalSortCompare(a.fileName, b.fileName)
end
end
if a_is_folder then
return naturalSortCompare(a.folderName, b.folderName)
else
if main.buildSortMode == "CLASS" then
local a_has_class = a.className ~= nil
local b_has_class = b.className ~= nil
if not a_has_class and b_has_class then return true
elseif a_has_class and not b_has_class then return false
elseif a_has_class and b_has_class and a.className ~= b.className then
return a.className < b.className
end
local a_has_asc = a.ascendClassName ~= nil
local b_has_asc = b.ascendClassName ~= nil
if not a_has_asc and b_has_asc then return true
elseif a_has_asc and not b_has_asc then return false
elseif a_has_asc and b_has_asc and a.ascendClassName ~= b.ascendClassName then
return a.ascendClassName < b.ascendClassName
end
return naturalSortCompare(a.fileName, b.fileName)
elseif main.buildSortMode == "LEVEL" then
if a.level and not b.level then return false
elseif not a.level and b.level then return true
elseif a.level and b.level then
if a.level ~= b.level then return a.level < b.level end
end
return naturalSortCompare(a.fileName, b.fileName)
else
return naturalSortCompare(a.fileName, b.fileName)
end
end
end)
if oldSelFileName then
self.controls.buildList:SelByFileName(oldSelFileName)
end
end
return listMode