WoWInterface SVN Broker_GarrisonReport

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

trunk/Broker_GarrisonReport/LibDataBroker-1.1.lua New file
0,0 → 1,66
 
assert(LibStub, "LibDataBroker-1.1 requires LibStub")
assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
 
local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 3)
if not lib then return end
oldminor = oldminor or 0
 
 
lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
 
if oldminor < 2 then
lib.domt = {
__metatable = "access denied",
__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
}
end
 
if oldminor < 3 then
lib.domt.__newindex = function(self, key, value)
if not attributestorage[self] then attributestorage[self] = {} end
if attributestorage[self][key] == value then return end
attributestorage[self][key] = value
local name = namestorage[self]
if not name then return end
callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
end
end
 
if oldminor < 2 then
function lib:NewDataObject(name, dataobj)
if self.proxystorage[name] then return end
 
if dataobj then
assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
self.attributestorage[dataobj] = {}
for i,v in pairs(dataobj) do
self.attributestorage[dataobj][i] = v
dataobj[i] = nil
end
end
dataobj = setmetatable(dataobj or {}, self.domt)
self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
return dataobj
end
end
 
if oldminor < 1 then
function lib:DataObjectIterator()
return pairs(self.proxystorage)
end
 
function lib:GetDataObjectByName(dataobjectname)
return self.proxystorage[dataobjectname]
end
 
function lib:GetNameByDataObject(dataobject)
return self.namestorage[dataobject]
end
end
trunk/Broker_GarrisonReport/LibStub/LibStub.lua New file
0,0 → 1,30
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local LibStub = _G[LIBSTUB_MAJOR]
 
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
 
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
 
local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
return self.libs[major], oldminor
end
 
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
 
function LibStub:IterateLibraries() return pairs(self.libs) end
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end
trunk/Broker_GarrisonReport/CallbackHandler-1.0/CallbackHandler-1.0.xml New file
0,0 → 1,4
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="CallbackHandler-1.0.lua"/>
</Ui>
\ No newline at end of file
trunk/Broker_GarrisonReport/CallbackHandler-1.0/CallbackHandler-1.0.lua New file
0,0 → 1,240
--[[ $Id: CallbackHandler-1.0.lua 965 2010-08-09 00:47:52Z mikk $ ]]
local MAJOR, MINOR = "CallbackHandler-1.0", 6
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
 
if not CallbackHandler then return end -- No upgrade needed
 
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
 
-- Lua APIs
local tconcat = table.concat
local assert, error, loadstring = assert, error, loadstring
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
local next, select, pairs, type, tostring = next, select, pairs, type, tostring
 
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: geterrorhandler
 
local xpcall = xpcall
 
local function errorhandler(err)
return geterrorhandler()(err)
end
 
local function CreateDispatcher(argCount)
local code = [[
local next, xpcall, eh = ...
 
local method, ARGS
local function call() method(ARGS) end
 
local function dispatch(handlers, ...)
local index
index, method = next(handlers)
if not method then return end
local OLD_ARGS = ARGS
ARGS = ...
repeat
xpcall(call, eh)
index, method = next(handlers, index)
until not method
ARGS = OLD_ARGS
end
 
return dispatch
]]
 
local ARGS, OLD_ARGS = {}, {}
for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
end
 
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
 
--------------------------------------------------------------------------
-- CallbackHandler:New
--
-- target - target object to embed public APIs in
-- RegisterName - name of the callback registration API, default "RegisterCallback"
-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
 
function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
-- TODO: Remove this after beta has gone out
assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
 
RegisterName = RegisterName or "RegisterCallback"
UnregisterName = UnregisterName or "UnregisterCallback"
if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
UnregisterAllName = "UnregisterAllCallbacks"
end
 
-- we declare all objects and exported APIs inside this closure to quickly gain access
-- to e.g. function names, the "target" parameter, etc
 
 
-- Create the registry object
local events = setmetatable({}, meta)
local registry = { recurse=0, events=events }
 
-- registry:Fire() - fires the given event/message into the registry
function registry:Fire(eventname, ...)
if not rawget(events, eventname) or not next(events[eventname]) then return end
local oldrecurse = registry.recurse
registry.recurse = oldrecurse + 1
 
Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
 
registry.recurse = oldrecurse
 
if registry.insertQueue and oldrecurse==0 then
-- Something in one of our callbacks wanted to register more callbacks; they got queued
for eventname,callbacks in pairs(registry.insertQueue) do
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
for self,func in pairs(callbacks) do
events[eventname][self] = func
-- fire OnUsed callback?
if first and registry.OnUsed then
registry.OnUsed(registry, target, eventname)
first = nil
end
end
end
registry.insertQueue = nil
end
end
 
-- Registration of a callback, handles:
-- self["method"], leads to self["method"](self, ...)
-- self with function ref, leads to functionref(...)
-- "addonId" (instead of self) with function ref, leads to functionref(...)
-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
if type(eventname) ~= "string" then
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
end
 
method = method or eventname
 
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
 
if type(method) ~= "string" and type(method) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
end
 
local regfunc
 
if type(method) == "string" then
-- self["method"] calling style
if type(self) ~= "table" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
elseif self==target then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
elseif type(self[method]) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
end
 
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) self[method](self,arg,...) end
else
regfunc = function(...) self[method](self,...) end
end
else
-- function ref with self=object or self="addonId" or self=thread
if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
end
 
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) method(arg,...) end
else
regfunc = method
end
end
 
 
if events[eventname][self] or registry.recurse<1 then
-- if registry.recurse<1 then
-- we're overwriting an existing entry, or not currently recursing. just set it.
events[eventname][self] = regfunc
-- fire OnUsed callback?
if registry.OnUsed and first then
registry.OnUsed(registry, target, eventname)
end
else
-- we're currently processing a callback in this registry, so delay the registration of this new entry!
-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
registry.insertQueue = registry.insertQueue or setmetatable({},meta)
registry.insertQueue[eventname][self] = regfunc
end
end
 
-- Unregister a callback
target[UnregisterName] = function(self, eventname)
if not self or self==target then
error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
end
if type(eventname) ~= "string" then
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
end
if rawget(events, eventname) and events[eventname][self] then
events[eventname][self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(events[eventname]) then
registry.OnUnused(registry, target, eventname)
end
end
if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
registry.insertQueue[eventname][self] = nil
end
end
 
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
if UnregisterAllName then
target[UnregisterAllName] = function(...)
if select("#",...)<1 then
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
end
if select("#",...)==1 and ...==target then
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
end
 
 
for i=1,select("#",...) do
local self = select(i,...)
if registry.insertQueue then
for eventname, callbacks in pairs(registry.insertQueue) do
if callbacks[self] then
callbacks[self] = nil
end
end
end
for eventname, callbacks in pairs(events) do
if callbacks[self] then
callbacks[self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(callbacks) then
registry.OnUnused(registry, target, eventname)
end
end
end
end
end
end
 
return registry
end
 
 
-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
-- try to upgrade old implicit embeds since the system is selfcontained and
-- relies on closures to work.
 
trunk/Broker_GarrisonReport/Broker_GarrisonReport.toc New file
0,0 → 1,10
## Interface: 60000
## Name: Broker_GarrisonReport
## Notes: An LDB plugin to replace the Garrison Report button on your minimap.
## Author: Seerah
## Version: 1.0
 
LibStub\LibStub.lua
CallBackHandler-1.0\CallbackHandler-1.0.xml
LibDataBroker-1.1.lua
report.lua
\ No newline at end of file
trunk/Broker_GarrisonReport/report.lua New file
0,0 → 1,183
local f = CreateFrame("Frame")
local strformat = string.format
local strgsub = string.gsub
local tinsert = table.insert
local hasGarrison, _ = C_Garrison.GetGarrisonInfo()
local NEW_IN_PROGRESS = "%d "..strgsub(GARRISON_LANDING_IN_PROGRESS, " %- %%d", "")
local NEW_AVAILABLE = "%d "..strgsub(GARRISON_LANDING_AVAILABLE, " %- %%d", "")
local NEW_WORK_COMPLETE = " "..CAPACITANCE_WORK_COMPLETE_TOOLTIP_TITLE
local NEW_COMPLETE = " "..GARRISON_LANDING_COMPLETED
local NEW_NEXT = " "..GARRISON_LANDING_SHIPMENT_READY_TO_START
local NEW_MISSION_COMPLETE = GARRISON_MISSION_COMPLETE.."!"
local workOrderBuildings = {}
local missionData = {}
local underConstruction = {}
 
local GR = LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject("Broker_GarrisonReport", {
type = "data source",
label = GARRISON_LANDING_PAGE_TITLE,
icon = "Interface\\Icons\\Ability_Garrison_OrangeBird",
text = "No Garrison",
OnClick = GarrisonLandingPageMinimapButton_OnClick,
})
 
local function ScanBuildings()
local buildings = C_Garrison.GetBuildings()
for i = 1, #buildings do
local bldg = buildings[i]
local buildingID = bldg.buildingID
workOrderBuildings[buildingID] = workOrderBuildings[buildingID] or {}
workOrderBuildings[buildingID].plotID = bldg.plotID
if C_Garrison.GetLandingPageShipmentInfo(buildingID) then
workOrderBuildings[buildingID].canWork = true
end
 
local _, name, _, _, _, isBuilding, buildStart, buildDur, canActivate, _, _ = C_Garrison.GetOwnedBuildingInfoAbbrev(bldg.plotID)
if isBuilding or canActivate then
underConstruction[buildingID] = underConstruction[buildingID] or {}
local newOrUpgrade = underConstruction[buildingID]
newOrUpgrade.name = name
newOrUpgrade.isBuilding = isBuilding
newOrUpgrade.buildStart = buildStart
newOrUpgrade.buildDur = buildDur
newOrUpgrade.canActivate = canActivate
end
end
end
 
local function ShowConstruction(tt)
if next(underConstruction) then --if there are buildings under construction
tt:AddLine(" ")
tt:AddLine(GARRISON_LANDING_STATUS_BUILDING)
for building, data in pairs(underConstruction) do
tt:AddLine(data.name, 1, 1, 1)
if data.isBuilding then
tt:AddLine(strformat(" %s", GARRISON_BUILDING_IN_PROGRESS), 1, 1, 1)
elseif data.canActivate then
tt:AddLine(strformat(" %s", GARRISON_LANDING_BUILDING_COMPLEATE), 0, .95, 0)
end
end
end
end
 
local function GetWorkOrders()
C_Garrison.RequestLandingPageShipmentInfo() --make sure we have the latest information
 
for buildingID, data in pairs(workOrderBuildings) do
if data.canWork then
local name, texture, maxShipments, shipmentsReady, shipmentsTotal,
_, _, timeLeft, _, itemIcon = C_Garrison.GetLandingPageShipmentInfo(buildingID)
 
data.name = name
data.texture = texture
data.max = maxShipments
data.ready = shipmentsReady
data.total = shipmentsTotal
data.icon = itemIcon
data.time = timeLeft
end
end
 
--let's update our work order data once per minute
C_Timer.After(60, GetWorkOrders)
end
 
local function ShowWorkOrders(tt)
tt:AddLine(CAPACITANCE_WORK_ORDERS)
for building, data in pairs(workOrderBuildings) do
if data.canWork then
tt:AddLine(data.name, 1, 1, 1)
if data.total then --if waiting on work orders
if data.ready == data.total then --all done!
tt:AddLine(NEW_WORK_COMPLETE, 0, .95, 0)
else
if data.ready > 0 then --if some are done
tt:AddLine(strformat(NEW_COMPLETE, data.ready, data.total), .88, .84, .36)
else --if none are done yet
tt:AddLine(strformat(NEW_COMPLETE, data.ready, data.total), 1, 1, 1)
end
end
else --no work orders made
tt:AddLine(strformat(NEW_NEXT, data.max), 1, 1, 1)
end
end
end
end
 
local function GetMissions()
missionData.complete = #C_Garrison.GetCompleteMissions()
missionData.onMission = #C_Garrison.GetInProgressMissions() --all the missions we're working on
missionData.inProgress = missionData.onMission - missionData.complete --let's not include the complete # in our in progress #
missionData.available = #C_Garrison.GetAvailableMissions()
 
local textColor
if missionData.onMission == 0 then
textColor = "ffff0000"
elseif missionData.complete == missionData.onMission then
textColor = "ff00f200"
else
textColor = "ffffffff"
end
GR.text = strformat("|c%s%d/%d|r", textColor, missionData.complete, missionData.onMission)
end
 
local function ShowMissions(tt)
tt:AddLine(GARRISON_MISSIONS)
if missionData.inProgress == 0 then
if missionData.onMission == 0 then
tt:AddLine(GARRISON_EMPTY_IN_PROGRESS_LIST, 1, 0, 0)
elseif missionData.complete == missionData.onMission then
tt:AddLine(NEW_MISSION_COMPLETE, 0, .95, 0)
end
tt:AddLine(strformat(NEW_AVAILABLE, missionData.available), 1, 1, 1)
else
if missionData.complete > 0 then
tt:AddLine(strformat(GARRISON_NUM_COMPLETED_MISSIONS, missionData.complete), 0, .95, 0)
else
tt:AddLine(strformat(GARRISON_NUM_COMPLETED_MISSIONS, missionData.complete), 1, 1, 1)
end
tt:AddLine(strformat(NEW_IN_PROGRESS, missionData.inProgress), 1, 1, 1)
end
end
 
function GR.OnTooltipShow(self)
self:AddLine("Broker_GarrisonReport",1,1,1)
self:AddLine(" ")
if hasGarrison then
ShowMissions(self)
self:AddLine(" ")
ShowWorkOrders(self)
ShowConstruction(self)
self:AddLine(" ")
end
self:AddLine(MINIMAP_GARRISON_LANDING_PAGE_TOOLTIP)
end
 
f:RegisterEvent("PLAYER_LOGIN")
f:RegisterEvent("GARRISON_MISSION_FINISHED")
f:RegisterEvent("GARRISON_MISSION_LIST_UPDATE")
f:RegisterEvent("GARRISON_MISSION_NPC_OPENED")
f:RegisterEvent("GARRISON_BUILDING_PLACED")
f:RegisterEvent("GARRISON_BUILDING_REMOVED")
f:RegisterEvent("GARRISON_BUILDING_ACTIVATABLE")
f:RegisterEvent("GARRISON_BUILDING_ACTIVATED")
f:RegisterEvent("GARRISON_UPDATE")
f:SetScript("OnEvent", function(self, event, ...)
if event == "PLAYER_LOGIN" then
--initialize any sv's?
GarrisonLandingPageMinimapButton:Hide()
hooksecurefunc(GarrisonLandingPageMinimapButton, "Show", GarrisonLandingPageMinimapButton.Hide)
elseif event == "GARRISON_UPDATE" then
hasGarrison = C_Garrison.GetGarrisonInfo()
GetMissions()
ScanBuildings()
GetWorkOrders()
elseif event == "GARRISON_BUILDING_ACTIVATED" then
local plotID, buildingID = ...
underConstruction[buildingID] = nil
elseif event == "GARRISON_MISSION_FINISHED" or event == "GARRISON_MISSION_LIST_UPDATE" or event == "GARRISON_MISSION_NPC_OPENED" then
GetMissions()
else
ScanBuildings()
end
end)
\ No newline at end of file