You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1695 lines
56 KiB

-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- http://www.curse.com/addons/wow/tradeskill-master --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local TSM = select(2, ...)
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster") -- loads the localization table
local AceGUI = LibStub("AceGUI-3.0") -- load the AceGUI libraries
local lib = TSMAPI
TSM.GROUP_SEP = "`"
function TSMAPI:FormatGroupPath(path, useColor)
if not path then return end
if useColor then
return TSMAPI.Design:GetInlineColor("link")..gsub(path, TSM.GROUP_SEP, "->").."|r"
else
return gsub(path, TSM.GROUP_SEP, "->")
end
end
local GROUP_LEVEL_COLORS = {
"FCF141",
"BDAEC6",
"06A2CB",
"FFB85C",
"51B599",
}
function TSMAPI:ColorGroupName(groupName, level)
local color = GROUP_LEVEL_COLORS[(level-1) % #GROUP_LEVEL_COLORS + 1]
return "|cFF"..color..groupName.."|r"
end
function TSMAPI:JoinGroupPath(...)
return strjoin(TSM.GROUP_SEP, ...)
end
local private = {}
TSMAPI:RegisterForTracing(private, "TradeSkillMaster.Groups_private")
private.operationInfo = {}
function TSM:RegisterOperationInfo(module, info)
info = CopyTable(info)
info.module = module
tinsert(private.operationInfo, info)
end
-- Splits the given group path into the parent path and group name
-- Parent will be nil if there is no parent
local function SplitGroupPath(path)
local parts = {TSM.GROUP_SEP:split(path)}
local parent = table.concat(parts, TSM.GROUP_SEP, 1, #parts-1)
parent = parent ~= "" and parent or nil
local groupName = parts[#parts]
return parent, groupName
end
local function GetSubGroups(groupPath)
local subGroups = {}
local hasSubGroup
for group in pairs(TSM.db.profile.groups) do
local _, _, subGroupName = strfind(group, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP.."([^`]+)$")
if subGroupName then
subGroups[group] = subGroupName
hasSubGroup = true
end
end
if hasSubGroup then
return subGroups
end
end
-- Creates a new group with the specified path
local SetOperationOverride
local function CreateGroup(groupPath)
if TSM.db.profile.groups[groupPath] then return end
TSM.db.profile.groups[groupPath] = {}
for _, info in ipairs(private.operationInfo) do
TSM.db.profile.groups[groupPath][info.module] = TSM.db.profile.groups[groupPath][info.module] or {}
if SplitGroupPath(groupPath) then
for _, info in ipairs(private.operationInfo) do
SetOperationOverride(groupPath, info.module, nil)
end
end
end
end
-- Deletes a group with the specified path and everything (items/subGroups) below it
local function DeleteGroup(groupPath)
if not TSM.db.profile.groups[groupPath] then return end
-- delete this group and all subgroups
for path in pairs(TSM.db.profile.groups) do
if path == groupPath or strfind(path, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP) then
TSM.db.profile.groups[path] = nil
end
end
local parent = SplitGroupPath(groupPath)
if parent and TSM.db.profile.keepInParent then
-- move all items in this group its subgroups to the parent
local changes = {}
for itemString, path in pairs(TSM.db.profile.items) do
if path == groupPath or strfind(path, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP) then
changes[itemString] = parent
end
end
for itemString, newPath in pairs(changes) do
TSM.db.profile.items[itemString] = newPath
end
else
-- delete all items in this group or subgroup
for itemString, path in pairs(TSM.db.profile.items) do
if path == groupPath or strfind(path, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP) then
TSM.db.profile.items[itemString] = nil
end
end
end
end
-- Moves (renames) a group at the given path to the newPath
local function MoveGroup(groupPath, newPath)
if not TSM.db.profile.groups[groupPath] then return end
if TSM.db.profile.groups[newPath] then return end
-- change the path of all subgroups
local changes = {}
for path, groupData in pairs(TSM.db.profile.groups) do
if path == groupPath or strfind(path, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP) then
changes[path] = gsub(path, "^"..TSMAPI:StrEscape(groupPath), TSMAPI:StrEscape(newPath))
end
end
for oldPath, newPath in pairs(changes) do
TSM.db.profile.groups[newPath] = TSM.db.profile.groups[oldPath]
TSM.db.profile.groups[oldPath] = nil
end
-- change the path for all items in this group (and subgroups)
changes = {}
for itemString, path in pairs(TSM.db.profile.items) do
if path == groupPath or strfind(path, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP) then
changes[itemString] = gsub(path, "^"..TSMAPI:StrEscape(groupPath), newPath)
end
end
for itemString, newPath in pairs(changes) do
TSM.db.profile.items[itemString] = newPath
end
end
-- Adds an item to the group at the specified path.
local function AddItem(itemString, path)
if not (strfind(path, TSM.GROUP_SEP) or not TSM.db.profile.items[itemString]) then return end
if not TSM.db.profile.groups[path] then return end
TSM.db.profile.items[itemString] = path
end
-- Deletes an item from the group at the specified path.
local function DeleteItem(itemString)
if not TSM.db.profile.items[itemString] then return end
TSM.db.profile.items[itemString] = nil
end
-- Moves an item from an existing group to the group at the specified path.
local function MoveItem(itemString, path)
if not TSM.db.profile.items[itemString] then return end
if not TSM.db.profile.groups[path] then return end
TSM.db.profile.items[itemString] = path
end
local function SetOperationHelper(path, module, origPath)
if TSM.db.profile.groups[path][module] and TSM.db.profile.groups[path][module].override then return end
TSM.db.profile.groups[path][module] = CopyTable(TSM.db.profile.groups[origPath][module])
TSM.db.profile.groups[path][module].override = nil
local subGroups = GetSubGroups(path)
if subGroups then
for subGroupPath in pairs(subGroups) do
SetOperationHelper(subGroupPath, module, origPath)
end
end
end
local function SetOperation(path, module, operation, index)
if not TSM.db.profile.groups[path] then return end
if not TSM.db.profile.groups[path][module] then return end
TSM.db.profile.groups[path][module][index] = operation
local subGroups = GetSubGroups(path)
if subGroups then
for subGroupPath in pairs(subGroups) do
SetOperationHelper(subGroupPath, module, path)
end
end
end
local function AddOperation(path, module)
if not TSM.db.profile.groups[path] then return end
tinsert(TSM.db.profile.groups[path][module], "")
local subGroups = GetSubGroups(path)
if subGroups then
for subGroupPath in pairs(subGroups) do
SetOperationHelper(subGroupPath, module, path)
end
end
end
local function DeleteOperation(path, module, index)
if not TSM.db.profile.groups[path] then return end
local numOperations = #TSM.db.profile.groups[path][module]
for i=index+1, numOperations do
SetOperation(path, module, TSM.db.profile.groups[path][module][i], i-1)
end
SetOperation(path, module, nil, numOperations)
end
function SetOperationOverride(path, module, override)
if not TSM.db.profile.groups[path] then return end
-- clear all operations for this path/module
TSM.db.profile.groups[path][module] = {override=(override or nil)}
-- set this group's (and all applicable subgroups') operation to the parent's
local parentPath = SplitGroupPath(path)
if not parentPath then return end
TSM.db.profile.groups[parentPath][module] = TSM.db.profile.groups[parentPath][module] or {override=(override or nil)}
for index, operation in ipairs(TSM.db.profile.groups[parentPath][module]) do
SetOperation(path, module, operation, index)
end
end
function TSM:GetGroupItems(path)
local items = {}
for itemString, groupPath in pairs(TSM.db.profile.items) do
if groupPath == path then
items[itemString] = true
end
end
return items
end
function TSM:GetGroupPathList(module)
local list, disabled = {}, {}
for groupPath in pairs(TSM.db.profile.groups) do
if module then
local operations = TSM:GetGroupOperations(groupPath, module)
if not operations then
disabled[groupPath] = true
end
end
tinsert(list, groupPath)
end
for groupPath in pairs(TSM.db.profile.groups) do
if not disabled[groupPath] then
local pathParts = {TSM.GROUP_SEP:split(groupPath)}
for i=1, #pathParts-1 do
local path = table.concat(pathParts, TSM.GROUP_SEP, 1, i)
disabled[path] = nil
end
end
end
sort(list, function(a,b) return strlower(gsub(a, TSM.GROUP_SEP, "\001")) < strlower(gsub(b, TSM.GROUP_SEP, "\001")) end)
return list, disabled
end
function TSM:GetGroupOperations(path, module)
if not TSM.db.profile.groups[path] then return end
if module and TSM.db.profile.groups[path][module] then
local operations = CopyTable(TSM.db.profile.groups[path][module])
for i=#operations, 1, -1 do
if operations[i] == "" or TSM:IsOperationIgnored(module, operations[i]) then
tremove(operations, i)
end
end
if #operations > 0 then
return operations
end
end
end
-- Takes a list of itemString/groupPath k,v pairs and adds them to new groups.
function TSMAPI:CreatePresetGroups(itemList, moduleName, operationInfo)
for itemString, groupPath in pairs(itemList) do
if not TSM.db.profile.items[itemString] and not TSMAPI:IsSoulbound(itemString) then
local pathParts = {TSM.GROUP_SEP:split(groupPath)}
for i=1, #pathParts do
local path = table.concat(pathParts, TSM.GROUP_SEP, 1, i)
if not TSM.db.profile.groups[path] then
CreateGroup(path)
end
end
AddItem(itemString, groupPath)
if moduleName and operationInfo and operationInfo[groupPath] then
if strfind(groupPath, TSM.GROUP_SEP) then
SetOperationOverride(groupPath, moduleName, true)
end
SetOperation(groupPath, moduleName, operationInfo[groupPath], 1)
end
end
end
private:UpdateTree()
end
function TSMAPI:GetItemOperation(itemString, module)
local groupPath = TSM.db.profile.items[itemString]
if not groupPath then return end
local operations = TSM:GetGroupOperations(groupPath, module)
if not operations then return end
local result = CopyTable(operations)
result.override = nil
return result
end
function TSMAPI:GetGroupPath(itemString)
return TSM.db.profile.items[itemString]
end
-- gets all items which have an operation for the given module assigned to their groups
function TSMAPI:GetModuleItems(module)
if not module then return end
local result = {}
for itemString in pairs(TSM.db.profile.items) do
result[itemString] = TSMAPI:GetItemOperation(itemString, module)
end
return result
end
local function ShowExportFrame(text)
local f = AceGUI:Create("TSMWindow")
f:SetCallback("OnClose", function(self) AceGUI:Release(self) end)
f:SetTitle("TradeSkillMaster - "..L["Export Group Items"])
f:SetLayout("Fill")
f:SetHeight(300)
local eb = AceGUI:Create("TSMMultiLineEditBox")
eb:SetLabel(L["Group Item Data"])
eb:SetMaxLetters(0)
eb:SetText(text)
f:AddChild(eb)
f.frame:SetFrameStrata("FULLSCREEN_DIALOG")
f.frame:SetFrameLevel(100)
end
local function ModuleOptionsRefresh(TSMObj, ...)
TSMObj.Options:UpdateTree()
TSMObj.Options.treeGroup:SelectByPath(#TSMObj.Options.treeGroup.tree, ...)
if select('#', ...) > 0 then
TSMObj.Options.treeGroup.children[1]:SelectTab(#TSMObj.Options.treeGroup.children[1].tablist)
end
end
function TSMAPI:DrawOperationManagement(TSMObj, container, operationName)
local moduleName = gsub(TSMObj.name, "TSM_", "")
local operation = TSMObj.operations[operationName]
local playerList = {}
local realmKey = TSM.db.keys.realm
for playerName in pairs(TSM.db.realm.characters) do
playerList[playerName.." - "..realmKey] = playerName
end
local realmList = {}
for realm in pairs(TSM.db.sv.realm) do
realmList[realm] = realm
end
local groupList = {}
for path, modules in pairs(TSM.db.profile.groups) do
if modules[moduleName] then
for i=1, #modules[moduleName] do
if modules[moduleName][i] == operationName then
tinsert(groupList, path)
end
end
end
end
sort(groupList, function(a,b) return strlower(gsub(a, TSM.GROUP_SEP, "\001")) < strlower(gsub(b, TSM.GROUP_SEP, "\001")) end)
local groupWidgets = {
{
type = "Label",
relativeWidth = 1,
text = L["Below is a list of groups which this operation is currently applied to. Clicking on the 'Remove' button next to the group name will remove the operation from that group."],
},
{
type = "HeadingLine",
},
}
for _, groupPath in ipairs(groupList) do
tinsert(groupWidgets, {
type = "Button",
relativeWidth = 0.2,
text = L["Remove"],
callback = function()
for i=#TSM.db.profile.groups[groupPath][moduleName], 1, -1 do
if TSM.db.profile.groups[groupPath][moduleName][i] == operationName then
DeleteOperation(groupPath, moduleName, i)
end
end
TSM:CheckOperationRelationships(moduleName)
ModuleOptionsRefresh(TSMObj, operationName)
end,
tooltip = L["Click this button to completely remove this operation from the specified group."],
})
tinsert(groupWidgets, {
type = "Label",
relativeWidth = 0.05,
text = "",
})
tinsert(groupWidgets, {
type = "Label",
relativeWidth = 0.75,
text = TSMAPI:FormatGroupPath(groupPath, true),
})
end
local page = {
{
type = "ScrollFrame",
layout = "Flow",
children = {
{
type = "InlineGroup",
layout = "flow",
title = L["Operation Management"],
children = {
{
type = "Dropdown",
label = L["Ignore Operation on Faction-Realms:"],
list = realmList,
relativeWidth = 0.5,
settingInfo = {operation, "ignorerealm"},
multiselect = true,
tooltip = L["This operation will be ignored when you're on any character which is checked in this dropdown."],
},
{
type = "Dropdown",
label = L["Ignore Operation on Characters:"],
list = playerList,
relativeWidth = 0.5,
settingInfo = {operation, "ignorePlayer"},
multiselect = true,
tooltip = L["This operation will be ignored when you're on any character which is checked in this dropdown."],
},
{
type = "HeadingLine"
},
{
type = "EditBox",
label = L["Rename Operation"],
value = operationName,
relativeWidth = 0.5,
callback = function(self,_,name)
name = (name or ""):trim()
if name == "" then return end
if TSMObj.operations[name] then
self:SetText("")
return TSMObj:Printf(L["Error renaming operation. Operation with name '%s' already exists."], name)
end
TSMObj.operations[name] = TSMObj.operations[operationName]
TSMObj.operations[operationName] = nil
for _, groupPath in ipairs(groupList) do
for i=1, #TSM.db.profile.groups[groupPath][moduleName] do
if TSM.db.profile.groups[groupPath][moduleName][i] == operationName then
TSM.db.profile.groups[groupPath][moduleName][i] = name
end
end
end
TSM:CheckOperationRelationships(moduleName)
ModuleOptionsRefresh(TSMObj, name)
end,
tooltip = L["Give this operation a new name. A descriptive name will help you find this operation later."],
},
{
type = "EditBox",
label = L["Duplicate Operation"],
relativeWidth = 0.5,
callback = function(self,_,name)
name = (name or ""):trim()
if name == "" then return end
if TSMObj.operations[name] then
self:SetText("")
return TSMObj:Printf(L["Error duplicating operation. Operation with name '%s' already exists."], name)
end
TSMObj.operations[name] = CopyTable(TSMObj.operations[operationName])
TSM:CheckOperationRelationships(moduleName)
ModuleOptionsRefresh(TSMObj, name)
end,
tooltip = L["Type in the name of a new operation you wish to create with the same settings as this operation."],
},
{
type = "HeadingLine"
},
{
type = "GroupBox",
label = L["Apply Operation to Group"],
relativeWidth = .5,
callback = function(self, _, path)
TSM.db.profile.groups[path][moduleName] = TSM.db.profile.groups[path][moduleName] or {}
local operations = TSM.db.profile.groups[path][moduleName]
local num = #operations
if num == 0 then
SetOperationOverride(path, moduleName, true)
AddOperation(path, moduleName)
SetOperation(path, moduleName, operationName, 1)
TSM:Printf(L["Applied %s to %s."], TSMAPI.Design:GetInlineColor("link")..operationName.."|r", TSMAPI:FormatGroupPath(path, true))
elseif operations[num] == "" then
SetOperationOverride(path, moduleName, true)
SetOperation(path, moduleName, operationName, num)
TSM:Printf(L["Applied %s to %s."], TSMAPI.Design:GetInlineColor("link")..operationName.."|r", TSMAPI:FormatGroupPath(path, true))
else
local canAdd
for _, info in ipairs(private.operationInfo) do
if moduleName == info.module then
canAdd = num < info.maxOperations
break
end
end
if canAdd then
StaticPopupDialogs["TSM_APPLY_OPERATION_ADD"] = StaticPopupDialogs["TSM_APPLY_OPERATION_ADD"] or {
text = L["This group already has operations. Would you like to add another one or replace the last one?"],
button1 = ADD,
button2 = L["Replace"],
button3 = CANCEL,
timeout = 0,
OnAccept = function()
-- the "add" button
local path, moduleName, operationName, num = unpack(StaticPopupDialogs["TSM_APPLY_OPERATION_ADD"].tsmInfo)
SetOperationOverride(path, moduleName, true)
AddOperation(path, moduleName)
SetOperation(path, moduleName, operationName, num+1)
TSM:Printf(L["Applied %s to %s."], TSMAPI.Design:GetInlineColor("link")..operationName.."|r", TSMAPI:FormatGroupPath(path, true))
end,
OnCancel = function()
-- the "replace" button
local path, moduleName, operationName, num = unpack(StaticPopupDialogs["TSM_APPLY_OPERATION_ADD"].tsmInfo)
SetOperationOverride(path, moduleName, true)
SetOperation(path, moduleName, operationName, num)
TSM:Printf(L["Applied %s to %s."], TSMAPI.Design:GetInlineColor("link")..operationName.."|r", TSMAPI:FormatGroupPath(path, true))
end,
preferredIndex = 3,
}
StaticPopupDialogs["TSM_APPLY_OPERATION_ADD"].tsmInfo = {path, moduleName, operationName, num}
TSMAPI:ShowStaticPopupDialog("TSM_APPLY_OPERATION_ADD")
else
StaticPopupDialogs["TSM_APPLY_OPERATION"] = StaticPopupDialogs["TSM_APPLY_OPERATION"] or {
text = L["This group already has the max number of operation. Would you like to replace the last one?"],
button1 = L["Replace"],
button2 = CANCEL,
timeout = 0,
OnAccept = function()
-- the "replace" button
local path, moduleName, operationName, num = unpack(StaticPopupDialogs["TSM_APPLY_OPERATION"].tsmInfo)
SetOperation(path, moduleName, operationName, num)
TSM:Printf(L["Applied %s to %s."], TSMAPI.Design:GetInlineColor("link")..operationName.."|r", TSMAPI:FormatGroupPath(path, true))
end,
preferredIndex = 3,
}
StaticPopupDialogs["TSM_APPLY_OPERATION"].tsmInfo = {path, moduleName, operationName, num}
TSMAPI:ShowStaticPopupDialog("TSM_APPLY_OPERATION")
end
end
self:SetText()
ModuleOptionsRefresh(TSMObj, operationName)
end,
},
{
type = "Button",
text = L["Delete Operation"],
relativeWidth = 0.5,
callback = function()
TSMObj.operations[operationName] = nil
for _, groupPath in ipairs(groupList) do
for i=#TSM.db.profile.groups[groupPath][moduleName], 1, -1 do
if TSM.db.profile.groups[groupPath][moduleName][i] == operationName then
DeleteOperation(groupPath, moduleName, i)
end
end
end
TSM:CheckOperationRelationships(moduleName)
ModuleOptionsRefresh(TSMObj)
end,
},
{
type = "HeadingLine"
},
{
type = "EditBox",
label = L["Import Operation Settings"],
relativeWidth = 1,
callback = function(self, _, value)
value = value:trim()
if value == "" then return end
local valid, data = LibStub("AceSerializer-3.0"):Deserialize(value)
if not valid then
TSM:Print(L["Invalid import string."])
self:SetFocus()
return
elseif data.module ~= moduleName then
TSM:Print(L["Invalid import string."].." "..L["You appear to be attempting to import an operation from a different module."])
self:SetText("")
return
end
data.module = nil
data.ignorePlayer = {}
data.ignorerealm = {}
data.relationships = {}
TSMObj.operations[operationName] = data
self:SetText("")
TSM:Print(L["Successfully imported operation settings."])
ModuleOptionsRefresh(TSMObj, operationName)
end,
tooltip = L["Paste the exported operation settings into this box and hit enter or press the 'Okay' button. Imported settings will irreversibly replace existing settings for this operation."],
},
{
type = "Button",
text = L["Export Operation"],
relativeWidth = 1,
callback = function()
local data = CopyTable(operation)
data.module = moduleName
data.ignorePlayer = nil
data.ignorerealm = nil
data.relationships = nil
ShowExportFrame(LibStub("AceSerializer-3.0"):Serialize(data))
end,
},
},
},
{
type = "InlineGroup",
layout = "flow",
title = L["Groups"],
children = groupWidgets,
},
},
},
}
TSMAPI:BuildPage(container, page)
end
function TSMAPI:NewOperationCallback(moduleName, group, operationName)
if not group then return end
StaticPopupDialogs["TSM_NEW_OPERATION_ADD"] = StaticPopupDialogs["TSM_NEW_OPERATION_ADD"] or {
button1 = YES,
button2 = NO,
timeout = 0,
OnAccept = function()
-- the "add" button
local group, moduleName, operationName = unpack(StaticPopupDialogs["TSM_NEW_OPERATION_ADD"].tsmInfo)
SetOperation(group, moduleName, operationName, #TSM.db.profile.groups[group][moduleName])
TSM:Printf(L["Applied %s to %s."], TSMAPI.Design:GetInlineColor("link")..operationName.."|r", TSMAPI:FormatGroupPath(group, true))
end,
preferredIndex = 3,
}
StaticPopupDialogs["TSM_NEW_OPERATION_ADD"].text = format(L["Would you like to add this new operation to %s?"], TSMAPI:FormatGroupPath(group, true))
StaticPopupDialogs["TSM_NEW_OPERATION_ADD"].tsmInfo = {group, moduleName, operationName}
TSMAPI:ShowStaticPopupDialog("TSM_NEW_OPERATION_ADD")
end
function TSMAPI:UpdateOperation(moduleName, operationName)
if not TSM.operations[moduleName][operationName] then return end
for key in pairs(TSM.operations[moduleName][operationName].relationships) do
local operation = TSM.operations[moduleName][operationName]
while operation.relationships[key] do
local newOperation = TSM.operations[moduleName][operation.relationships[key]]
if not newOperation then break end
operation = newOperation
end
TSM.operations[moduleName][operationName][key] = operation[key]
end
end
local function IsCircularRelationship(moduleName, operation, key, visited)
visited = visited or {}
if visited[operation] then return true end
visited[operation] = true
if not operation.relationships[key] then return end
return IsCircularRelationship(moduleName, TSM.operations[moduleName][operation.relationships[key]], key, visited)
end
function TSMAPI:ShowOperationRelationshipTab(obj, container, operation, settingInfo)
local moduleName = gsub(obj.name, "TradeSkillMaster_", "")
moduleName = gsub(obj.name, "TSM_", "")
local operationList = {[""]=L["<No Relationship>"]}
local operationListOrder = {""}
local incomingRelationships = {}
for name, data in pairs(obj.operations) do
if data ~= operation then
operationList[name] = name
tinsert(operationListOrder, name)
end
for key, targetOperation in pairs(data.relationships) do
if obj.operations[targetOperation] == operation then
incomingRelationships[key] = name
end
end
end
sort(operationListOrder)
local target = ""
local children = {
{
type = "InlineGroup",
layout = "Flow",
children = {
{
type = "Label",
text = L["Here you can setup relationships between the settings of this operation and other operations for this module. For example, if you have a relationship set to OperationA for the stack size setting below, this operation's stack size setting will always be equal to OperationA's stack size setting."],
relativeWidth = 1,
},
{
type = "HeadingLine",
},
{
type = "Dropdown",
label = L["Target Operation"],
list = operationList,
order = operationListOrder,
relativeWidth = 0.5,
value = target,
callback = function(self, _, value)
target = value
end,
tooltip = L["Creating a relationship for this setting will cause the setting for this operation to be equal to the equivalent setting of another operation."],
},
{
type = "Button",
text = L["Set All Relationships to Target"],
relativeWidth = 0.49,
callback = function()
for _, inline in ipairs(settingInfo) do
for _, widget in ipairs(inline) do
local prev = operation.relationships[widget.key]
if target == "" then
operation.relationships[widget.key] = nil
else
operation.relationships[widget.key] = target
if IsCircularRelationship(moduleName, operation, widget.key) then
operation.relationships[widget.key] = prev
end
end
end
end
container:ReloadTab()
end,
tooltip = L["Sets all relationship dropdowns below to the operation selected."],
},
},
},
}
for _, inlineData in ipairs(settingInfo) do
local inlineChildren = {}
for _, dropdownData in ipairs(inlineData) do
local dropdown = {
type = "Dropdown",
label = dropdownData.label,
list = operationList,
order = operationListOrder,
relativeWidth = 0.5,
value = operation.relationships[dropdownData.key] or "",
callback = function(self, _, value)
local previousValue = operation.relationships[dropdownData.key]
if value == "" then
operation.relationships[dropdownData.key] = nil
else
operation.relationships[dropdownData.key] = value
end
if IsCircularRelationship(moduleName, operation, dropdownData.key) then
operation.relationships[dropdownData.key] = previousValue
obj:Print("This relationship cannot be applied because doing so would create a circular relationship.")
self:SetValue(operation.relationships[dropdownData.key] or "")
end
end,
tooltip = L["Creating a relationship for this setting will cause the setting for this operation to be equal to the equivalent setting of another operation."],
}
tinsert(inlineChildren, dropdown)
end
local inlineGroup = {
type = "InlineGroup",
layout = "flow",
title = inlineData.label,
children = inlineChildren,
}
tinsert(children, inlineGroup)
end
local page = {
{
type = "ScrollFrame",
layout = "list",
children = children,
},
}
TSMAPI:BuildPage(container, page)
end
-- operation options
function TSM:LoadOperationOptions(parent)
local tabs = {}
local next = next
for _, info in ipairs(private.operationInfo) do
tinsert(tabs, {text=info.module, value=info.module})
end
if next(tabs) then
sort(tabs, function(a, b)
return a.text < b.text
end)
end
tinsert(tabs, 1, {text=L["Help"], value="Help"})
local tabGroup = AceGUI:Create("TSMTabGroup")
tabGroup:SetLayout("Fill")
tabGroup:SetTabs(tabs)
tabGroup:SetCallback("OnGroupSelected", function(_, _, value)
tabGroup:ReleaseChildren()
if value == "Help" then
private:DrawOperationHelp(tabGroup)
else
for _, info in ipairs(private.operationInfo) do
if info.module == value then
info.callbackOptions(tabGroup, TSM.loadModuleOptionsTab and TSM.loadModuleOptionsTab.operation, TSM.loadModuleOptionsTab and TSM.loadModuleOptionsTab.group)
end
end
end
end)
parent:AddChild(tabGroup)
tabGroup:SelectTab(TSM.loadModuleOptionsTab and TSM.loadModuleOptionsTab.module or "Help")
end
function private:DrawOperationHelp(container)
local page = {
{ -- scroll frame to contain everything
type = "ScrollFrame",
layout = "List",
children = {
{
type = "InlineGroup",
layout = "List",
children = {
{
type = "Label",
relativeWidth = 1,
text = L["Use the tabs above to select the module for which you'd like to configure operations and general options."],
},
},
},
},
},
}
TSMAPI:BuildPage(container, page)
end
-- group options
local treeGroup
function TSM:LoadGroupOptions(parent)
treeGroup = AceGUI:Create("TSMTreeGroup")
treeGroup:SetLayout("Fill")
treeGroup:SetCallback("OnGroupSelected", function(...) private:SelectTree(...) end)
treeGroup:SetStatusTable(TSM.db.profile.groupTreeStatus)
parent:AddChild(treeGroup)
private:UpdateTree()
treeGroup:SelectByPath(1)
end
local function UpdateTreeHelper(currentPath, groupPathList, index, treeGroupChildren, level)
for i=index, #groupPathList do
local groupPath = groupPathList[i]
-- make sure this group is under the current parent we're interested in
local parent, groupName = SplitGroupPath(groupPath)
if parent == currentPath then
if TSM.db.profile.colorGroupName then
groupName = TSMAPI:ColorGroupName(groupName, level)
end
local row = {value=groupPath, text=groupName}
if groupPathList[i+1] and (groupPath == groupPathList[i+1] or strfind(groupPathList[i+1], "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP)) then
row.children = {}
UpdateTreeHelper(groupPath, groupPathList, i+1, row.children, level+1)
end
tinsert(treeGroupChildren, row)
end
end
sort(treeGroupChildren, function(a, b) return strlower(a.text) < strlower(b.text) end)
end
function private:UpdateTree()
if not treeGroup then return end
local groupChildren = {}
local groupPathList = TSM:GetGroupPathList()
UpdateTreeHelper(nil, groupPathList, 1, groupChildren, 1)
local treeGroups = {{value=1, text=L["Groups"], children=groupChildren}}
treeGroup:SetTree(treeGroups)
end
function private:SelectGroup(name)
if not treeGroup then return end
local tmp = {1}
local groupPathParts = {TSM.GROUP_SEP:split(name)}
for i=1, #groupPathParts do
tinsert(tmp, table.concat(groupPathParts, TSM.GROUP_SEP, 1, i))
end
treeGroup:SelectByPath(unpack(tmp))
end
local scrollFrameStatus = {}
function private:SelectTree(treeGroup, _, selection)
treeGroup:ReleaseChildren()
selection = {("\001"):split(selection)}
if #selection == 1 then
private:DrawNewGroup(treeGroup)
else
local group = selection[#selection]
local tabGroup = AceGUI:Create("TSMTabGroup")
tabGroup:SetLayout("Fill")
tabGroup:SetTabs({{text=L["Operations"], value=1}, {text=L["Items"], value=2}, {text=L["Import/Export"], value=3}, {text=L["Management"], value=4}})
tabGroup:SetCallback("OnGroupSelected", function(self, _, value)
tabGroup:ReleaseChildren()
if value == 1 then
-- load operations page
private:DrawGroupOperationsPage(self, group)
self.children[1]:SetStatusTable(scrollFrameStatus)
elseif value == 2 then
-- load items page
private:DrawGroupItemsPage(self, group)
elseif value == 3 then
-- load import/export page
private:DrawGroupImportExportPage(self, group)
elseif value == 4 then
-- load management page
private:DrawGroupManagementPage(self, group)
end
end)
tabGroup:SetCallback("OnRelease", function() scrollFrameStatus = {} end)
treeGroup:AddChild(tabGroup)
tabGroup:SelectTab(TSM.db.profile.defaultGroupTab)
end
end
function private:DrawNewGroup(container)
local page = {
{ -- scroll frame to contain everything
type = "ScrollFrame",
layout = "List",
children = {
{
type = "InlineGroup",
layout = "flow",
title = L["New Group"],
children = {
{
type = "Label",
relativeWidth = 1,
text = L["A group is a collection of items which will be treated in a similar way by TSM's modules."],
},
{
type = "HeadingLine",
},
{
type = "EditBox",
label = L["Group Name"],
relativeWidth = 0.8,
callback = function(self,_,value)
value = (value or ""):trim()
if value == "" then return end
if strfind(value, TSM.GROUP_SEP) then
return TSM:Printf(L["Group names cannot contain %s characters."], TSM.GROUP_SEP)
end
if TSM.db.profile.groups[value] then
return TSM:Printf(L["Error creating group. Group with name '%s' already exists."], value)
end
CreateGroup(value)
private:UpdateTree()
if TSM.db.profile.gotoNewGroup then
private:SelectGroup(value)
else
self:SetText()
self:SetFocus()
end
TSMAPI:FireEvent("TSM:GROUPS:NEWGROUP", value)
end,
tooltip = L["Give the new group a name. A descriptive name will help you find this group later."],
},
{
type = "CheckBox",
label = L["Switch to New Group After Creation"],
relativeWidth = 1,
settingInfo = {TSM.db.profile, "gotoNewGroup"},
},
},
},
{
type = "Spacer"
},
{
type = "InlineGroup",
layout = "flow",
title = L["Settings"],
children = {
{
type = "Dropdown",
label = L["Default Group Tab"],
list = {L["Operations"], L["Items"], L["Import/Export"], L["Management"]},
settingInfo = {TSM.db.profile, "defaultGroupTab"},
tooltip = L["This dropdown determines the default tab when you visit a group."],
},
{
type = "CheckBox",
label = L["Show Ungrouped Items for Adding to Subgroups"],
relativeWidth = 1,
settingInfo = {TSM.db.profile, "directSubgroupAdd"},
tooltip = L["If checked, ungrouped items will be displayed in the left list of selection lists used to add items to subgroups. This allows you to add an ungrouped item directly to a subgroup rather than having to add to the parent group(s) first."],
},
},
},
},
},
}
TSMAPI:BuildPage(container, page)
end
function private:DrawGroupOperationsPage(container, groupPath)
local isSubGroup = strfind(groupPath, TSM.GROUP_SEP)
local moduleInlines = {}
local addRef, deleteRef = {}, {}
for _, info in ipairs(private.operationInfo) do
local moduleName = info.module
local ddList = {}
ddList[""] = L["<No Operation>"]
for name in pairs(TSM.operations[moduleName] or {}) do
ddList[name] = name
end
TSM.db.profile.groups[groupPath][moduleName] = TSM.db.profile.groups[groupPath][moduleName] or {}
local operations = TSM.db.profile.groups[groupPath][moduleName]
for i=#operations, 1, -1 do
if not ddList[operations[i]] then
DeleteOperation(groupPath, moduleName, i)
end
end
operations[1] = operations[1] or ""
if #operations > 1 then
ddList[TSM.GROUP_SEP] = L["<Remove Operation>"]
end
local moduleInline = {
type = "InlineGroup",
layout = "Flow",
title = moduleName,
children = {},
}
local addOperationWidget
if #operations < info.maxOperations then
addOperationWidget = {
type = "Button",
text = L["Add Additional Operation"],
relativeWidth = 1,
disabled = isSubGroup and not operations.override,
callback = function()
AddOperation(groupPath, moduleName)
container:ReloadTab()
end,
}
else
addOperationWidget = {type="Label", relativeWidth=1}
end
if isSubGroup then
tinsert(moduleInline.children, {
type = "CheckBox",
label = L["Override Module Operations"],
value = operations.override,
relativeWidth = 1,
callback = function(_,_,value)
SetOperationOverride(groupPath, moduleName, value)
container:ReloadTab()
end,
tooltip = L["Check this box to override this group's operation(s) for this module."],
})
else
tinsert(moduleInline.children, {type="Label", relativeWidth=1})
end
for i=1, #operations do
tinsert(moduleInline.children, {
type = "Dropdown",
label = format(L["Operation #%d"], i),
list = ddList,
value = operations[i],
relativeWidth = 0.6,
disabled = isSubGroup and not operations.override,
callback = function(_,_,value)
if value == "" then
SetOperation(groupPath, moduleName, nil, i)
elseif value == TSM.GROUP_SEP then
DeleteOperation(groupPath, moduleName, i)
else
SetOperation(groupPath, moduleName, value, i)
end
container:ReloadTab()
end,
tooltip = L["Select an operation to apply to this group."],
})
if operations[i] ~= "" then
tinsert(moduleInline.children, {
type = "Button",
text = L["View Operation Options"],
relativeWidth = 0.39,
callback = function()
TSMAPI:ShowOperationOptions(moduleName, operations[i])
end,
tooltip = L["Click this button to configure the currently selected operation."],
})
elseif not isSubGroup or operations.override then
tinsert(moduleInline.children, {
type = "Button",
text = format(L["Create %s Operation"], moduleName),
relativeWidth = 0.39,
callback = function()
TSMAPI:ShowOperationOptions(moduleName, "", groupPath)
end,
tooltip = L["Click this button to create a new operation for this module."],
})
end
end
tinsert(moduleInline.children, addOperationWidget)
local opStrs = {}
for _, name in ipairs(operations) do
if name ~= "" then
local str = info.callbackInfo(name) or "---"
tinsert(opStrs, TSMAPI.Design:GetInlineColor("link")..name.."|r: "..str)
end
end
tinsert(moduleInline.children, {type="HeadingLine"})
tinsert(moduleInline.children, {
type = "Label",
text = #opStrs > 0 and table.concat(opStrs, "\n") or format(L["Select a %s operation using the dropdown above."], moduleName),
relativeWidth = 1,
})
tinsert(moduleInlines, moduleInline)
end
sort(moduleInlines, function(a, b) return a.title < b.title end)
local children = {}
for i, inline in ipairs(moduleInlines) do
tinsert(children, inline)
if i ~= #moduleInlines then
tinsert(children, {type="Spacer"})
end
end
local page = {
{
type = "ScrollFrame",
layout = "List",
children = children,
},
}
TSMAPI:BuildPage(container, page)
end
local alreadyLoaded = {}
function private:DrawGroupItemsPage(container, groupPath)
if not alreadyLoaded[groupPath] then
alreadyLoaded[groupPath] = true
TSMAPI:CreateTimeDelay("itemsTabLoad", 0.1, function() container:ReloadTab() end)
end
local parentPath, groupName = SplitGroupPath(groupPath)
local function GetItemList(side)
local list = {}
if side == "left" then
if parentPath then
-- this is a subgroup so add all items from parent group
for itemString, path in pairs(TSM.db.profile.items) do
if path == parentPath then
local link = select(2, TSMAPI:GetSafeItemInfo(itemString))
if link then
tinsert(list, link)
end
end
end
end
if not parentPath or TSM.db.profile.directSubgroupAdd then
-- add all items in bags
local usedLinks = {}
for bag, slot, itemString in TSMAPI:GetBagIterator() do
if not usedLinks[itemString] then
local baseItemString = TSMAPI:GetBaseItemString(itemString)
local link = GetContainerItemLink(bag, slot)
if itemString ~= baseItemString and TSM.db.global.ignoreRandomEnchants then -- a random enchant item
itemString = baseItemString
link = select(2, TSMAPI:GetSafeItemInfo(itemString))
end
if link and not TSM.db.profile.items[itemString] then
tinsert(list, link)
usedLinks[itemString] = true
end
end
end
end
elseif side == "right" then
for itemString, path in pairs(TSM.db.profile.items) do
if path == groupPath or strfind(path, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP) then
local link = select(2, TSMAPI:GetSafeItemInfo(itemString))
if link then
tinsert(list, link)
end
end
end
end
return list
end
local leftTitle, rightTitle
if parentPath then
if TSM.db.profile.directSubgroupAdd then
leftTitle = L["Parent/Ungrouped Items:"]
else
leftTitle = L["Parent Group Items:"]
end
rightTitle = L["Subgroup Items:"]
else
leftTitle = L["Ungrouped Items:"]
rightTitle = L["Group Items:"]
end
local page = {
{ -- scroll frame to contain everything
type = "SimpleGroup",
layout = "Fill",
children = {
{
type = "GroupItemList",
leftTitle = leftTitle,
rightTitle = rightTitle,
listCallback = GetItemList,
showIgnore = not parentPath or TSM.db.profile.directSubgroupAdd,
onAdd = function(_,_,selected)
for i=#selected, 1, -1 do
AddItem(selected[i], groupPath)
end
TSMAPI:FireEvent("TSM:GROUPS:ADDITEMS", {num=#selected, group=groupPath})
container:ReloadTab()
end,
onRemove = function(_,_,selected)
if parentPath and not IsShiftKeyDown() then
for i=#selected, 1, -1 do
MoveItem(selected[i], parentPath)
end
TSMAPI:FireEvent("TSM:GROUPS:MOVEITEMS", {num=#selected, group=groupPath})
else
for i=#selected, 1, -1 do
DeleteItem(selected[i])
end
TSMAPI:FireEvent("TSM:GROUPS:REMOVEITEMS", {num=#selected, group=groupPath})
end
container:ReloadTab()
end,
},
},
},
}
TSMAPI:BuildPage(container, page)
end
function TSM:ImportGroup(importStr, groupPath)
if not importStr then return end
importStr = importStr:trim()
if importStr == "" then return end
local parentPath = strfind(groupPath, TSM.GROUP_SEP) and SplitGroupPath(groupPath)
if strfind(importStr, "^|c") then
local itemString = TSMAPI:GetItemString(importStr)
if not itemString then return end
if parentPath and TSM.db.profile.importParentOnly and TSM.db.profile.items[itemString] ~= parentPath then return 0 end
if TSM.db.profile.items[itemString] and TSM.db.profile.moveImportedItems then
MoveItem(itemString, groupPath)
return 1
elseif not TSM.db.profile.items[itemString] then
AddItem(itemString, groupPath)
return 1
end
return 0
end
local items = {}
local currentSubPath = ""
local itemID, randomEnchant = nil, nil
for _, str in ipairs(TSMAPI:SafeStrSplit(importStr, ",")) do
str = str:trim()
local noSpaceStr = gsub(str, " ", "") -- forums like to add spaces
local itemString, subPath
if tonumber(noSpaceStr) then
itemString = "item:"..tonumber(noSpaceStr)..":0:0:0:0:0:0"
elseif strfind(noSpaceStr, "^group:") then
subPath = strsub(str, strfind(str, ":")+1, -1)
subPath = gsub(subPath, TSM.GROUP_SEP.."[ ]*"..TSM.GROUP_SEP, ",")
elseif strfind(noSpaceStr, "p") then
itemString = gsub(noSpaceStr, "p", "battlepet")
elseif strfind(noSpaceStr, ":") then
itemID, randomEnchant = (":"):split(noSpaceStr)
if not tonumber(itemID) or not tonumber(randomEnchant) then return end
itemString = "item:"..tonumber(itemID)..":0:0:0:0:0:"..tonumber(randomEnchant)
end
if subPath then
currentSubPath = subPath
elseif itemString then
items[itemString] = currentSubPath
itemID = itemID or noSpaceStr
if Item then
local item = Item:CreateFromID(tonumber(itemID))
item:Query()
else
TSMAPI:GetSafeItemInfo(tonumber(itemID))
end
else
return
end
end
local num = 0
for itemString, subPath in pairs(items) do
if not (parentPath and TSM.db.profile.moveImportedItems and TSM.db.profile.importParentOnly and TSM.db.profile.items[itemString] ~= parentPath) then
local path = groupPath
if subPath ~= "" then
-- create necessary parent groups
local subParts = {TSM.GROUP_SEP:split(subPath)}
for i=1, #subParts-1 do
CreateGroup(path..TSM.GROUP_SEP..table.concat(subParts, TSM.GROUP_SEP, 1, i))
end
path = path..TSM.GROUP_SEP..subPath
end
CreateGroup(path)
if TSM.db.profile.items[itemString] and TSM.db.profile.moveImportedItems then
MoveItem(itemString, path)
num = num + 1
elseif not TSM.db.profile.items[itemString] then
AddItem(itemString, path)
num = num + 1
end
end
end
return num
end
function TSM:ExportGroup(groupPath)
local temp = {}
for itemString, group in pairs(TSM.db.profile.items) do
if group == groupPath or strfind(group, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP) then
tinsert(temp, itemString)
end
end
sort(temp, function(a, b)
local groupA = strlower(gsub(TSM.db.profile.items[a], TSM.GROUP_SEP, "\001"))
local groupB = strlower(gsub(TSM.db.profile.items[b], TSM.GROUP_SEP, "\001"))
if groupA == groupB then
return a < b
end
return groupA < groupB
end)
local items = {}
local currentPath = ""
for _, itemString in pairs(temp) do
if TSM.db.profile.exportSubGroups then
local path = TSM.db.profile.items[itemString]
if path == groupPath then
path = ""
else
path = gsub(path, "^"..TSMAPI:StrEscape(groupPath)..TSM.GROUP_SEP, "")
end
path = gsub(path, ",", TSM.GROUP_SEP..TSM.GROUP_SEP)
if path ~= currentPath then
tinsert(items, "group:"..path)
currentPath = path
end
end
if strfind(itemString, "^item:") then
local _, itemID, _, _, _, _, _, randomEnchant = (":"):split(itemString)
if tonumber(randomEnchant) and tonumber(randomEnchant) > 0 then
tinsert(items, itemID..":"..randomEnchant)
else
tinsert(items, itemID)
end
elseif strfind(itemString, "^battlepet:") then
itemString = gsub(itemString, "battlepet", "p")
tinsert(items, itemString)
end
end
return table.concat(items, ",")
end
function private:DrawGroupImportExportPage(container, groupPath)
local page = {
{ -- scroll frame to contain everything
type = "ScrollFrame",
layout = "list",
children = {
{
type = "InlineGroup",
layout = "flow",
title = L["Import Items"],
children = {
{
type = "Label",
relativeWidth = 1,
text = L["Paste the list of items into the box below and hit enter or click on the 'Okay' button.\n\nYou can also paste an itemLink into the box below to add a specific item to this group."],
},
{
type = "EditBox",
label = L["Import String"],
relativeWidth = 1,
callback = function(self, _, value)
local num = TSM:ImportGroup(value, groupPath)
if not num then
TSM:Print(L["Invalid import string."])
return self:SetFocus()
end
self:SetText("")
TSM:Printf(L["Successfully imported %d items to %s."], num, TSMAPI:FormatGroupPath(groupPath, true))
private:UpdateTree()
private:SelectGroup(groupPath)
TSMAPI:FireEvent("TSM:GROUPS:ADDITEMS", {num=num, group=groupPath, isImport=true})
end,
tooltip = L["Paste the exported items into this box and hit enter or press the 'Okay' button. The recommended format for the list of items is a comma separated list of itemIDs for general items. For battle pets, the entire battlepet string should be used. For randomly enchanted items, the format is <itemID>:<randomEnchant> (ex: 38472:-29)."],
},
{
type = "CheckBox",
label = L["Move Already Grouped Items"],
relativeWidth = 0.5,
settingInfo = {TSM.db.profile, "moveImportedItems"},
callback = function() container:ReloadTab() end,
tooltip = L["If checked, any items you import that are already in a group will be moved out of their current group and into this group. Otherwise, they will simply be ignored."],
},
{
type = "CheckBox",
disabled = not strfind(groupPath, TSM.GROUP_SEP) or not TSM.db.profile.moveImportedItems,
label = L["Only Import Items from Parent Group"],
relativeWidth = 0.5,
settingInfo = {TSM.db.profile, "importParentOnly"},
tooltip = L["If checked, only items which are in the parent group of this group will be imported."],
},
},
},
{
type = "InlineGroup",
layout = "flow",
title = L["Export Items in Group"],
children = {
{
type = "Label",
relativeWidth = 1,
text = L["Click the button below to open the export frame for this group."],
},
{
type = "Button",
text = L["Export Group Items"],
relativeWidth = 1,
callback = function()
ShowExportFrame(TSM:ExportGroup(groupPath))
end,
tooltip = L["Click this button to show a frame for easily exporting the list of items which are in this group."],
},
{
type = "CheckBox",
label = L["Include Subgroup Structure in Export"],
relativeWidth = 0.5,
settingInfo = {TSM.db.profile, "exportSubGroups"},
tooltip = L["If checked, the structure of the subgroups will be included in the export. Otherwise, the items in this group (and all subgroups) will be exported as a flat list."],
},
},
},
},
},
}
TSMAPI:BuildPage(container, page)
end
function private:DrawGroupManagementPage(container, groupPath)
local page = {
{ -- scroll frame to contain everything
type = "ScrollFrame",
layout = "list",
children = {
{
type = "InlineGroup",
layout = "flow",
title = L["Create New Subgroup"],
children = {
{
type = "Label",
relativeWidth = 1,
text = L["Subgroups contain a subset of the items in their parent groups and can be used to further refine how different items are treated by TSM's modules."],
},
{
type = "EditBox",
label = L["New Subgroup Name"],
relativeWidth = 0.8,
callback = function(self,_,value)
value = (value or ""):trim()
if value == "" then return end
if strfind(value, TSM.GROUP_SEP) then
return TSM:Printf(L["Group names cannot contain %s characters."], TSM.GROUP_SEP)
end
local newPath = groupPath..TSM.GROUP_SEP..value
if TSM.db.profile.groups[newPath] then
return TSM:Printf(L["Error creating subgroup. Subgroup with name '%s' already exists."], value)
end
CreateGroup(newPath)
private:UpdateTree()
if TSM.db.profile.gotoNewGroup then
private:SelectGroup(newPath)
else
self:SetText()
self:SetFocus()
end
end,
tooltip = L["Give the group a new name. A descriptive name will help you find this group later."],
},
{
type = "CheckBox",
label = L["Switch to New Group After Creation"],
relativeWidth = 1,
settingInfo = {TSM.db.profile, "gotoNewGroup"},
},
},
},
{
type = "InlineGroup",
layout = "flow",
title = L["Rename Group"],
children = {
{
type = "Label",
relativeWidth = 1,
text = L["Use the editbox below to give this group a new name."],
},
{
type = "EditBox",
label = L["New Group Name"],
relativeWidth = 0.8,
value = select(2, SplitGroupPath(groupPath)),
callback = function(_,_,value)
value = (value or ""):trim()
if value == "" then return end
if value == select(2, SplitGroupPath(groupPath)) then return end -- same name
if strfind(value, TSM.GROUP_SEP) then
return TSM:Printf(L["Group names cannot contain %s characters."], TSM.GROUP_SEP)
end
local newPath
local parent = SplitGroupPath(groupPath)
if parent then
newPath = parent..TSM.GROUP_SEP..value
else
newPath = value
end
if TSM.db.profile.groups[newPath] then
return TSM:Printf(L["Error renaming group. Group with name '%s' already exists."], value)
end
MoveGroup(groupPath, newPath)
TSMAPI:FireEvent("TSM:GROUPS:MOVEGROUP", {old=groupPath, new=newPath})
private:UpdateTree()
private:SelectGroup(newPath)
end,
tooltip = L["Give the group a new name. A descriptive name will help you find this group later."],
},
},
},
{
type = "InlineGroup",
layout = "flow",
title = L["Move Group"],
children = {
{
type = "Label",
relativeWidth = 1,
text = L["Use the group box below to move this group and all subgroups of this group. Moving a group will cause all items in the group (and its subgroups) to be removed from its current parent group and added to the new parent group."],
},
{
type = "GroupBox",
label = L["New Parent Group"],
relativeWidth = .5,
callback = function(self, _, value)
self:SetText()
if value and value ~= groupPath then
if strfind(value, "^"..groupPath) then
return TSM:Printf(L["Error moving group. You cannot move this group to one of its subgroups."])
end
local _, groupName = SplitGroupPath(groupPath)
local newPath = value..TSM.GROUP_SEP..groupName
if TSM.db.profile.groups[newPath] then
return TSM:Printf(L["Error moving group. Group '%s' already exists."], TSMAPI:FormatGroupPath(newPath, true))
end
TSM:Printf(L["Moved %s to %s."], TSMAPI:FormatGroupPath(groupPath, true), TSMAPI:FormatGroupPath(value, true))
MoveGroup(groupPath, newPath)
TSMAPI:FireEvent("TSM:GROUPS:MOVEGROUP", {old=groupPath, new=newPath})
private:UpdateTree()
private:SelectGroup(newPath)
end
end,
},
{
type = "Button",
text = L["Move to Top Level"],
relativeWidth = 0.49,
disabled = groupPath == select(2, SplitGroupPath(groupPath)),
callback = function()
local _, groupName = SplitGroupPath(groupPath)
local newPath = groupName
if TSM.db.profile.groups[newPath] then
return TSM:Printf(L["Error moving group. Group '%s' already exists."], TSMAPI:FormatGroupPath(newPath, true))
end
TSM:Printf(L["Moved %s to %s."], TSMAPI:FormatGroupPath(groupPath, true), TSMAPI:FormatGroupPath(newPath, true))
MoveGroup(groupPath, newPath)
TSMAPI:FireEvent("TSM:GROUPS:MOVEGROUP", {old=groupPath, new=newPath})
private:UpdateTree()
private:SelectGroup(newPath)
end,
tooltip = L["When clicked, makes this group a top-level group with no parent."],
},
},
},
{
type = "InlineGroup",
layout = "flow",
title = L["Delete Group"],
children = {
{
type = "Label",
relativeWidth = 1,
text = L["Use the button below to delete this group. Any subgroups of this group will also be deleted, with all items being returned to the parent of this group or removed completely if this group has no parent."],
},
{
type = "CheckBox",
label = L["Keep Items in Parent Group"],
relativeWidth = 1,
settingInfo = {TSM.db.profile, "keepInParent"},
},
{
type = "Button",
text = L["Delete Group"],
relativeWidth = 0.8,
callback = function()
DeleteGroup(groupPath)
TSMAPI:FireEvent("TSM:GROUPS:DELETEGROUP", groupPath)
private:UpdateTree()
local parent = SplitGroupPath(groupPath)
if parent then
private:SelectGroup(parent)
else
treeGroup:SelectByPath(1)
end
end,
tooltip = L["Any subgroups of this group will also be deleted, with all items being returned to the parent of this group or removed completely if this group has no parent."],
},
},
},
},
},
}
TSMAPI:BuildPage(container, page)
end