WoWInterface SVN QualityID

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 8 to Rev 7
    Reverse comparison

Rev 8 → Rev 7

libs/AceLibrary/AceLibrary.lua New file
0,0 → 1,799
--[[
Name: AceLibrary
Revision: $Rev: 58127 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Iriel (iriel@vigilance-committee.org)
Tekkub (tekkub@gmail.com)
Revision: $Rev: 58127 $
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceLibrary
SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
Description: Versioning library to handle other library instances, upgrading,
and proper access.
It also provides a base for libraries to work off of, providing
proper error tools. It is handy because all the errors occur in the
file that called it, not in the library file itself.
Dependencies: None
License: LGPL v2.1
]]
 
local ACELIBRARY_MAJOR = "AceLibrary"
local ACELIBRARY_MINOR = "$Revision: 58127 $"
 
local _G = getfenv(0)
local previous = _G[ACELIBRARY_MAJOR]
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
 
do
-- 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
end
local LibStub = _G.LibStub
 
-- If you don't want AceLibrary to enable libraries that are LoadOnDemand but
-- disabled in the addon screen, set this to true.
local DONT_ENABLE_LIBRARIES = nil
 
local function safecall(func,...)
local success, err = pcall(func,...)
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
end
 
-- @table AceLibrary
-- @brief System to handle all versioning of libraries.
local AceLibrary = {}
local AceLibrary_mt = {}
setmetatable(AceLibrary, AceLibrary_mt)
 
local function error(self, message, ...)
if type(self) ~= "table" then
return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2)
end
 
local stack = debugstack()
if not message then
local second = stack:match("\n(.-)\n")
message = "error raised! " .. second
else
local arg = { ... } -- not worried about table creation, as errors don't happen often
 
for i = 1, #arg do
arg[i] = tostring(arg[i])
end
for i = 1, 10 do
table.insert(arg, "nil")
end
message = message:format(unpack(arg))
end
 
if getmetatable(self) and getmetatable(self).__tostring then
message = ("%s: %s"):format(tostring(self), message)
elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
message = ("%s: %s"):format(self:GetLibraryVersion(), message)
elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
message = ("%s: %s"):format(self.class:GetLibraryVersion(), message)
end
 
local first = stack:gsub("\n.*", "")
local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1")
file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
 
 
local i = 0
for s in stack:gmatch("\n([^\n]*)") do
i = i + 1
if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1")
file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
break
end
end
local j = 0
for s in stack:gmatch("\n([^\n]*)") do
j = j + 1
if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
return _G.error(message, j+1)
end
end
return _G.error(message, 2)
end
 
local type = type
local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
if type(num) ~= "number" then
return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
elseif type(kind) ~= "string" then
return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
end
arg = type(arg)
if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
local stack = debugstack()
local func = stack:match("`argCheck'.-([`<].-['>])")
if not func then
func = stack:match("([`<].-['>])")
end
if kind5 then
return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
elseif kind4 then
return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
elseif kind3 then
return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
elseif kind2 then
return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
else
return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
end
end
end
 
local pcall
do
local function check(self, ret, ...)
if not ret then
local s = ...
return error(self, (s:gsub(".-%.lua:%d-: ", "")))
else
return ...
end
end
 
function pcall(self, func, ...)
return check(self, _G.pcall(func, ...))
end
end
 
local recurse = {}
local function addToPositions(t, major)
if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
rawset(t, recurse, true)
AceLibrary.positions[t] = major
for k,v in pairs(t) do
if type(v) == "table" and not rawget(v, recurse) then
addToPositions(v, major)
end
if type(k) == "table" and not rawget(k, recurse) then
addToPositions(k, major)
end
end
local mt = getmetatable(t)
if mt and not rawget(mt, recurse) then
addToPositions(mt, major)
end
rawset(t, recurse, nil)
end
end
 
local function svnRevisionToNumber(text)
local kind = type(text)
if kind == "number" or tonumber(text) then
return tonumber(text)
elseif kind == "string" then
if text:find("^%$Revision: (%d+) %$$") then
return tonumber((text:match("^%$Revision: (%d+) %$$")))
elseif text:find("^%$Rev: (%d+) %$$") then
return tonumber((text:match("^%$Rev: (%d+) %$$")))
elseif text:find("^%$LastChangedRevision: (%d+) %$$") then
return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$")))
end
end
return nil
end
 
local crawlReplace
do
local recurse = {}
local function func(t, to, from)
if recurse[t] then
return
end
recurse[t] = true
local mt = getmetatable(t)
setmetatable(t, nil)
rawset(t, to, rawget(t, from))
rawset(t, from, nil)
for k,v in pairs(t) do
if v == from then
t[k] = to
elseif type(v) == "table" then
if not recurse[v] then
func(v, to, from)
end
end
 
if type(k) == "table" then
if not recurse[k] then
func(k, to, from)
end
end
end
setmetatable(t, mt)
if mt then
if mt == from then
setmetatable(t, to)
elseif not recurse[mt] then
func(mt, to, from)
end
end
end
function crawlReplace(t, to, from)
func(t, to, from)
for k in pairs(recurse) do
recurse[k] = nil
end
end
end
 
-- @function destroyTable
-- @brief remove all the contents of a table
-- @param t table to destroy
local function destroyTable(t)
setmetatable(t, nil)
for k,v in pairs(t) do
t[k] = nil
end
end
 
local function isFrame(frame)
return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
end
 
-- @function copyTable
-- @brief Create a shallow copy of a table and return it.
-- @param from The table to copy from
-- @return A shallow copy of the table
local function copyTable(from, to)
if not to then
to = {}
end
for k,v in pairs(from) do
to[k] = v
end
setmetatable(to, getmetatable(from))
return to
end
 
-- @function deepTransfer
-- @brief Fully transfer all data, keeping proper previous table
-- backreferences stable.
-- @param to The table with which data is to be injected into
-- @param from The table whose data will be injected into the first
-- @param saveFields If available, a shallow copy of the basic data is saved
-- in here.
-- @param list The account of table references
-- @param list2 The current status on which tables have been traversed.
local deepTransfer
do
-- @function examine
-- @brief Take account of all the table references to be shared
-- between the to and from tables.
-- @param to The table with which data is to be injected into
-- @param from The table whose data will be injected into the first
-- @param list An account of the table references
local function examine(to, from, list, major)
list[from] = to
for k,v in pairs(from) do
if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
if from[k] == to[k] then
list[from[k]] = to[k]
elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
list[from[k]] = from[k]
elseif not list[from[k]] then
examine(to[k], from[k], list, major)
end
end
end
return list
end
 
function deepTransfer(to, from, saveFields, major, list, list2)
setmetatable(to, nil)
if not list then
list = {}
list2 = {}
examine(to, from, list, major)
end
list2[to] = to
for k,v in pairs(to) do
if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
if saveFields then
saveFields[k] = v
end
to[k] = nil
elseif v ~= _G then
if saveFields then
saveFields[k] = copyTable(v)
end
end
end
for k in pairs(from) do
if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
if not list2[to[k]] then
deepTransfer(to[k], from[k], nil, major, list, list2)
end
to[k] = list[to[k]] or list2[to[k]]
else
rawset(to, k, from[k])
end
end
setmetatable(to, getmetatable(from))
local mt = getmetatable(to)
if mt then
if list[mt] then
setmetatable(to, list[mt])
elseif mt.__index and list[mt.__index] then
mt.__index = list[mt.__index]
end
end
destroyTable(from)
end
end
 
local function TryToEnable(addon)
if DONT_ENABLE_LIBRARIES then return end
local isondemand = IsAddOnLoadOnDemand(addon)
if isondemand then
local _, _, _, enabled = GetAddOnInfo(addon)
EnableAddOn(addon)
local _, _, _, _, loadable = GetAddOnInfo(addon)
if not loadable and not enabled then
DisableAddOn(addon)
end
 
return loadable
end
end
 
-- @method TryToLoadStandalone
-- @brief Attempt to find and load a standalone version of the requested library
-- @param major A string representing the major version
-- @return If library is found and loaded, true is return. If not loadable, false is returned.
-- If the library has been requested previously, nil is returned.
local function TryToLoadStandalone(major)
if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
if AceLibrary.scannedlibs[major] then return end
 
AceLibrary.scannedlibs[major] = true
 
local name, _, _, enabled, loadable = GetAddOnInfo(major)
 
loadable = (enabled and loadable) or TryToEnable(name)
 
local loaded = false
if loadable then
loaded = true
LoadAddOn(name)
end
 
local field = "X-AceLibrary-" .. major
for i = 1, GetNumAddOns() do
if GetAddOnMetadata(i, field) then
name, _, _, enabled, loadable = GetAddOnInfo(i)
 
loadable = (enabled and loadable) or TryToEnable(name)
if loadable then
loaded = true
LoadAddOn(name)
end
end
end
return loaded
end
 
-- @method IsNewVersion
-- @brief Obtain whether the supplied version would be an upgrade to the
-- current version. This allows for bypass code in library
-- declaration.
-- @param major A string representing the major version
-- @param minor An integer or an svn revision string representing the minor version
-- @return whether the supplied version would be newer than what is
-- currently available.
function AceLibrary:IsNewVersion(major, minor)
argCheck(self, major, 2, "string")
TryToLoadStandalone(major)
 
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
end
end
argCheck(self, minor, 3, "number")
local lib, oldMinor = LibStub:GetLibrary(major, true)
if lib then
return oldMinor < minor
end
local data = self.libs[major]
if not data then
return true
end
return data.minor < minor
end
 
-- @method HasInstance
-- @brief Returns whether an instance exists. This allows for optional support of a library.
-- @param major A string representing the major version.
-- @param minor (optional) An integer or an svn revision string representing the minor version.
-- @return Whether an instance exists.
function AceLibrary:HasInstance(major, minor)
argCheck(self, major, 2, "string")
if minor ~= false then
TryToLoadStandalone(major)
end
 
local lib, ver = LibStub:GetLibrary(major, true)
if not lib and self.libs[major] then
lib, ver = self.libs[major].instance, self.libs[major].minor
end
if minor then
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
end
end
argCheck(self, minor, 3, "number")
if not lib then
return false
end
return ver == minor
end
return not not lib
end
 
-- @method GetInstance
-- @brief Returns the library with the given major/minor version.
-- @param major A string representing the major version.
-- @param minor (optional) An integer or an svn revision string representing the minor version.
-- @return The library with the given major/minor version.
function AceLibrary:GetInstance(major, minor)
argCheck(self, major, 2, "string")
if minor ~= false then
TryToLoadStandalone(major)
end
 
local data, ver = LibStub:GetLibrary(major, true)
if not data then
if self.libs[major] then
data, ver = self.libs[major].instance, self.libs[major].minor
else
_G.error(("Cannot find a library instance of %s."):format(major), 2)
return
end
end
if minor then
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
end
end
argCheck(self, minor, 2, "number")
if ver ~= minor then
_G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2)
end
end
return data
end
 
-- Syntax sugar. AceLibrary("FooBar-1.0")
AceLibrary_mt.__call = AceLibrary.GetInstance
 
local donothing = function() end
 
local AceEvent
 
local tmp = {}
 
-- @method Register
-- @brief Registers a new version of a given library.
-- @param newInstance the library to register
-- @param major the major version of the library
-- @param minor the minor version of the library
-- @param activateFunc (optional) A function to be called when the library is
-- fully activated. Takes the arguments
-- (newInstance [, oldInstance, oldDeactivateFunc]). If
-- oldInstance is given, you should probably call
-- oldDeactivateFunc(oldInstance).
-- @param deactivateFunc (optional) A function to be called by a newer library's
-- activateFunc.
-- @param externalFunc (optional) A function to be called whenever a new
-- library is registered.
function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
argCheck(self, newInstance, 2, "table")
argCheck(self, major, 3, "string")
if major ~= ACELIBRARY_MAJOR then
for k,v in pairs(_G) do
if v == newInstance then
geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
end
end
end
if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then
_G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2)
end
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
end
end
argCheck(self, minor, 4, "number")
if math.floor(minor) ~= minor or minor < 0 then
error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
end
argCheck(self, activateFunc, 5, "function", "nil")
argCheck(self, deactivateFunc, 6, "function", "nil")
argCheck(self, externalFunc, 7, "function", "nil")
if not deactivateFunc then
deactivateFunc = donothing
end
local data = self.libs[major]
if not data then
-- This is new
if LibStub:GetLibrary(major, true) then
error(self, "Cannot register library %q. It is already registered with LibStub.", major)
end
local instance = LibStub:NewLibrary(major, minor)
copyTable(newInstance, instance)
crawlReplace(instance, instance, newInstance)
destroyTable(newInstance)
if AceLibrary == newInstance then
self = instance
AceLibrary = instance
end
self.libs[major] = {
instance = instance,
minor = minor,
deactivateFunc = deactivateFunc,
externalFunc = externalFunc,
}
rawset(instance, 'GetLibraryVersion', function(self)
return major, minor
end)
if not rawget(instance, 'error') then
rawset(instance, 'error', error)
end
if not rawget(instance, 'argCheck') then
rawset(instance, 'argCheck', argCheck)
end
if not rawget(instance, 'pcall') then
rawset(instance, 'pcall', pcall)
end
addToPositions(instance, major)
if activateFunc then
safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
end
 
if externalFunc then
for k, data_instance in LibStub:IterateLibraries() do -- all libraries
tmp[k] = data_instance
end
for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
tmp[k] = data.instance
end
for k, data_instance in pairs(tmp) do
if k ~= major then
safecall(externalFunc, instance, k, data_instance)
end
tmp[k] = nil
end
end
 
for k,data in pairs(self.libs) do -- only Ace libraries
if k ~= major and data.externalFunc then
safecall(data.externalFunc, data.instance, major, instance)
end
end
if major == "AceEvent-2.0" then
AceEvent = instance
end
if AceEvent then
AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
end
 
return instance
end
if minor <= data.minor then
-- This one is already obsolete, raise an error.
_G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2)
return
end
local instance = data.instance
-- This is an update
local oldInstance = {}
 
local libStubInstance = LibStub:GetLibrary(major, true)
if not libStubInstance then -- non-LibStub AceLibrary registered the library
-- pass
elseif libStubInstance ~= instance then
error(self, "Cannot register library %q. It is already registered with LibStub.", major)
else
LibStub:NewLibrary(major, minor) -- upgrade the minor version
end
 
addToPositions(newInstance, major)
local isAceLibrary = (AceLibrary == newInstance)
local old_error, old_argCheck, old_pcall
if isAceLibrary then
self = instance
AceLibrary = instance
 
old_error = instance.error
old_argCheck = instance.argCheck
old_pcall = instance.pcall
 
self.error = error
self.argCheck = argCheck
self.pcall = pcall
end
deepTransfer(instance, newInstance, oldInstance, major)
crawlReplace(instance, instance, newInstance)
local oldDeactivateFunc = data.deactivateFunc
data.minor = minor
data.deactivateFunc = deactivateFunc
data.externalFunc = externalFunc
rawset(instance, 'GetLibraryVersion', function()
return major, minor
end)
if not rawget(instance, 'error') then
rawset(instance, 'error', error)
end
if not rawget(instance, 'argCheck') then
rawset(instance, 'argCheck', argCheck)
end
if not rawget(instance, 'pcall') then
rawset(instance, 'pcall', pcall)
end
if isAceLibrary then
for _,v in pairs(self.libs) do
local i = type(v) == "table" and v.instance
if type(i) == "table" then
if not rawget(i, 'error') or i.error == old_error then
rawset(i, 'error', error)
end
if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
rawset(i, 'argCheck', argCheck)
end
if not rawget(i, 'pcall') or i.pcall == old_pcall then
rawset(i, 'pcall', pcall)
end
end
end
end
if activateFunc then
safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)
else
safecall(oldDeactivateFunc, oldInstance)
end
oldInstance = nil
 
if externalFunc then
for k, data_instance in LibStub:IterateLibraries() do -- all libraries
tmp[k] = data_instance
end
for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
tmp[k] = data.instance
end
for k, data_instance in pairs(tmp) do
if k ~= major then
safecall(externalFunc, instance, k, data_instance)
end
tmp[k] = nil
end
end
 
return instance
end
 
function AceLibrary:IterateLibraries()
local t = {}
for major, instance in LibStub:IterateLibraries() do
t[major] = instance
end
for major, data in pairs(self.libs) do
t[major] = data.instance
end
return pairs(t)
end
 
local function manuallyFinalize(major, instance)
if AceLibrary.libs[major] then
-- don't work on Ace libraries
return
end
local finalizedExternalLibs = AceLibrary.finalizedExternalLibs
if finalizedExternalLibs[major] then
return
end
finalizedExternalLibs[major] = true
 
for k,data in pairs(AceLibrary.libs) do -- only Ace libraries
if k ~= major and data.externalFunc then
safecall(data.externalFunc, data.instance, major, instance)
end
end
end
 
-- @function Activate
-- @brief The activateFunc for AceLibrary itself. Called when
-- AceLibrary properly registers.
-- @param self Reference to AceLibrary
-- @param oldLib (optional) Reference to an old version of AceLibrary
-- @param oldDeactivate (optional) Function to deactivate the old lib
local function activate(self, oldLib, oldDeactivate)
AceLibrary = self
if not self.libs then
self.libs = oldLib and oldLib.libs or {}
self.scannedlibs = oldLib and oldLib.scannedlibs or {}
end
if not self.positions then
self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" })
end
self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {}
self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
self.frame:UnregisterAllEvents()
self.frame:RegisterEvent("ADDON_LOADED")
self.frame:SetScript("OnEvent", function()
for major, instance in LibStub:IterateLibraries() do
manuallyFinalize(major, instance)
end
end)
for major, instance in LibStub:IterateLibraries() do
manuallyFinalize(major, instance)
end
 
-- Expose the library in the global environment
_G[ACELIBRARY_MAJOR] = self
 
if oldDeactivate then
oldDeactivate(oldLib)
end
end
 
if not previous then
previous = AceLibrary
end
if not previous.libs then
previous.libs = {}
end
AceLibrary.libs = previous.libs
if not previous.positions then
previous.positions = setmetatable({}, { __mode = "k" })
end
AceLibrary.positions = previous.positions
AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
libs/TipHooker-1.0/TipHooker-1.0.lua New file
0,0 → 1,415
--[[
Name: TipHooker-1.0
Description: A Library for hooking tooltips.
Revision: $Revision: 61157 $
Author: Whitetooth@Cenarius (hotdogee@bahamut.twbbs.org)
LastUpdate: $Date: 2008-02-13 12:59:08 -0500 (Wed, 13 Feb 2008) $
Website:
Documentation:
SVN: $URL: svn://dev.wowace.com/wowace/trunk/TipHookerLib/TipHooker-1.0/TipHooker-1.0.lua $
Dependencies: AceLibrary
License: LGPL v2.1
]]
 
-- This library is still in early development
 
--[[ Tips for using TipHooker
{
This library provides tooltip hooks, mainly for use with tooltip modification, you can eazily append or modify text in a tooltip with TipHookerLib.
If you need to not only modify the tooltip but also need to scan the tooltip for information, you should use other libraries with TipHookerLib.
Bedcause TipHookerLib passes the real tooltip frame to your handler function,
which may already be modifided by other addons and may not be suited for scanning.
For simple custom scaning you can use GratuityLib, it creates a custom tooltip and scan that for patterns.
For a complete item scanning solution to stat scanning you can use ItemBonusLib, or my more light weight version: StatLogicLib.
}
--]]
 
 
local MAJOR_VERSION = "TipHooker-1.0"
local MINOR_VERSION = tonumber(("$Revision: 61157 $"):sub(12, -3))
 
if not AceLibrary then error(MAJOR_VERSION.." requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
 
local TipHooker = {}
local VariablesLoaded
 
-----------
-- Tools --
-----------
local DEBUG = false
 
-- Localize globals
local _G = getfenv(0)
local select = select
local pairs = pairs
local ipairs = ipairs
local IsAddOnLoaded = IsAddOnLoaded
 
local function print(text)
if DEBUG then
DEFAULT_CHAT_FRAME:AddMessage(text)
end
end
 
-- copyTable
local function copyTable(to, from)
if not to then
to = {}
end
for k,v in pairs(from) do
if type(k) == "table" then
k = copyTable({}, k)
end
if type(v) == "table" then
v = copyTable({}, v)
end
to[k] = v
end
setmetatable(to, getmetatable(from))
return to
end
 
-----------------------
-- Hook Tooltip Core --
-----------------------
local TooltipList = {
item = {
"GameTooltip",
"ItemRefTooltip",
"ShoppingTooltip",
-- EquipCompare support
"ComparisonTooltip",
-- EQCompare support
"EQCompareTooltip",
-- takKompare support
"tekKompareTooltip",
-- LinkWrangler support
"IRR_",
"LinkWrangler",
-- MultiTips support
-- Links support
"LinksTooltip",
-- AtlasLoot support
"AtlasLootTooltip",
-- ItemMagic support
"ItemMagicTooltip",
-- Sniff support
"SniffTooltip",
-- LinkHeaven support
"LH_",
-- Mirror support
"MirrorTooltip",
-- TooltipExchange support
"TooltipExchange_TooltipShow",
},
buff = {
"GameTooltip",
},
spell = {
"GameTooltip",
},
talant = {
"GameTooltip",
},
unit = {
"GameTooltip",
},
action = {
"GameTooltip",
},
}
 
local MethodList = {
item = {
"SetHyperlink",
"SetBagItem",
"SetInventoryItem",
-- auction
"SetAuctionItem",
"SetAuctionSellItem",
-- loot
"SetLootItem",
"SetLootRollItem",
-- crafting
"SetCraftSpell",
"SetCraftItem",
"SetTradeSkillItem",
"SetTrainerService",
-- mail
"SetInboxItem",
"SetSendMailItem",
-- quest log
"SetQuestItem",
"SetQuestLogItem",
-- trade
"SetTradePlayerItem",
"SetTradeTargetItem",
-- vendor tooltip
"SetMerchantItem",
"SetBuybackItem",
"SetMerchantCostItem",
-- socketing interface
"SetSocketGem",
"SetExistingSocketGem",
-- 2.1.0
"SetHyperlinkCompareItem",
-- 2.3.0
"SetGuildBankItem",
},
buff = {
"SetPlayerBuff",
"SetUnitBuff",
"SetUnitDebuff",
},
spell = {
"SetSpell",
"SetTrackingSpell",
"SetShapeshift",
},
talant = {
"SetTalent",
},
unit = {
"SetUnit",
},
action = {
"SetAction",
"SetPetAction",
},
}
 
local HandlerList = {}
 
local Set = {
item = function(tooltip)
if not tooltip.GetItem then return end
local name, link = tooltip:GetItem()
-- Check for empty slots
if not name then return end
for handler in pairs(HandlerList.item) do
handler(tooltip, name, link)
end
end,
buff = function(tooltip, unitId, buffIndex, raidFilter)
if not unitId then
unitId = "player"
end
for handler in pairs(HandlerList.buff) do
handler(tooltip, unitId, buffIndex, raidFilter)
end
end,
spell = function(tooltip, spellId, bookType)
for handler in pairs(HandlerList.spell) do
handler(tooltip, spellId, bookType)
end
end,
talant = function(tooltip, tabIndex, talentIndex)
for handler in pairs(HandlerList.talant) do
handler(tooltip, tabIndex, talentIndex)
end
end,
unit = function(tooltip, unit)
if not tooltip.GetUnit then return end
local name = tooltip:GetUnit()
for handler in pairs(HandlerList.unit) do
handler(tooltip, unit)
end
end,
action = function(tooltip, slot)
for handler in pairs(HandlerList.action) do
handler(tooltip, slot)
end
end,
}
 
 
-- This gets called during VARIABLES_LOADED and :Hook()
-- InitializeHook will hook all methods in MethodList[tipType]
-- from tooltips in TooltipList[tipType] to the Set[tipType] function
local Initialized = {}
TipHooker.SupportedTooltips = {}
TipHooker.HookedFrames = {}
local function InitializeHook(tipType)
if Initialized[tipType] then return end
-- Walk through all frames
local tooltip = EnumerateFrames()
while tooltip do
if tooltip:GetObjectType() == "GameTooltip" then
local name = tooltip:GetName()
if name then
for _, v in ipairs(TooltipList[tipType]) do
if strfind(name, v) then
print("InitializeHook("..tipType..") = "..name)
for _, methodName in ipairs(MethodList[tipType]) do
if type(tooltip[methodName]) == "function" then
hooksecurefunc(tooltip, methodName, Set[tipType])
end
end
tinsert(_G.TipHooker.SupportedTooltips, tooltip)
break
end
end
end
end
tooltip = EnumerateFrames(tooltip)
end
-- Destroy tooltip list so we don't have double hooking accidents
Initialized[tipType] = true
end
 
local function CreateFrameHook(frameType, name, parent, inheritFrame)
if name and frameType == "GameTooltip" then
for tipType in pairs(HandlerList) do
for _, v in ipairs(TooltipList[tipType]) do
if strfind(name, v) then
print("CreateFrameHook("..tipType..") = "..name)
local tooltip = _G[name]
for _, methodName in ipairs(MethodList[tipType]) do
-- prevent double hooking by checking HookedFrames table
if (type(tooltip[methodName]) == "function") and (not _G.TipHooker.HookedFrames[name]) then
_G.TipHooker.HookedFrames[name] = true
hooksecurefunc(tooltip, methodName, Set[tipType])
end
end
tinsert(_G.TipHooker.SupportedTooltips, tooltip)
break
end
end
end
end
end
 
 
------------------
-- OnEventFrame --
------------------
local OnEventFrame = CreateFrame("Frame")
 
OnEventFrame:RegisterEvent("VARIABLES_LOADED")
--OnEventFrame:RegisterEvent("PLAYER_LOGIN")
 
OnEventFrame:SetScript("OnEvent", function(self, event, ...)
print(event)
VariablesLoaded = true
print("VariablesLoaded = true")
-- Check for exsiting hooks
for tipType in pairs(HandlerList) do
InitializeHook(tipType)
end
hooksecurefunc("CreateFrame", CreateFrameHook)
end)
 
TipHooker.OnEventFrame = OnEventFrame
 
 
----------------
-- Activation --
----------------
-- Called when a newer version is registered
local function activate(self, oldLib)
if not oldLib then
print("not oldLib")
-- HandlerList
self.HandlerList = HandlerList
else
print("oldLib")
oldLib.OnEventFrame:UnregisterAllEvents()
oldLib.OnEventFrame:SetScript("OnEvent", nil)
if oldLib.HandlerList then
HandlerList = oldLib.HandlerList
end
self.HandlerList = HandlerList
end
end
 
 
--[[---------------------------------
{ :Hook(handler, ...)
-------------------------------------
-- Description
Hooks tooltip SetX methods with handler
-- Args
handler
func - handler func
...
string - list of tooltips that you want to hook:
"item": Items
"buff": Buff/Debuff
"spell": Spells
"talant": Talants
"unit": Units
"action": Action button
-- Examples
}
-----------------------------------]]
function TipHooker:Hook(handler, ...)
for i = 1, select('#', ...) do
local tipType = select(i, ...)
print("TipHooker:Hook("..tipType..")")
if VariablesLoaded then
InitializeHook(tipType)
end
if not HandlerList[tipType] then
HandlerList[tipType] = {}
end
HandlerList[tipType][handler] = true
end
end
 
--[[---------------------------------
{ :Unhook(handler, ...)
-------------------------------------
-- Description
Unhooks handler from tooltip SetX methods
-- Args
handler
func - handler func
...
string - list of tooltips that you want to hook:
"item": Items
"buff": Buff/Debuff
"spell": Spells
"talant": Talants
"unit": Units
"action": Action button
-- Examples
}
-----------------------------------]]
function TipHooker:Unhook(handler, ...)
for i = 1, select('#', ...) do
local tipType = select(i, ...)
if HandlerList[tipType] then
HandlerList[tipType][handler] = nil
end
end
end
 
--[[---------------------------------
{ :IsHooked(handler, tipType)
-------------------------------------
-- Description
Unhooks handler from tooltip SetX methods
-- Args
handler
func - handler func
tipType
string - tooltip that you want to hook:
"item": Items
"buff": Buff/Debuff
"spell": Spells
"talant": Talants
"unit": Units
"action": Action button
-- Examples
}
-----------------------------------]]
function TipHooker:IsHooked(handler, tipType)
if HandlerList[tipType] then
return HandlerList[tipType][handler]
end
end
 
AceLibrary:Register(TipHooker, MAJOR_VERSION, MINOR_VERSION, activate)
 
_G.TipHooker = AceLibrary("TipHooker-1.0")
\ No newline at end of file
WoWScrnShot_073008_143632.jpg Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
trunk/QualityID/QualityID.xml New file
0,0 → 1,20
<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="QualityID.lua"/>
<Frame name="QualityID_Frame">
<Scripts>
<OnLoad>
this:RegisterEvent("ADDON_LOADED");
</OnLoad>
<OnEvent>
QualityID:OnEvent(event);
</OnEvent>
</Scripts>
</Frame>
<GameTooltip name="QualityID_Tooltip" inherits="GameTooltipTemplate">
<Scripts>
<Onload>
this:SetOwner(QualityID_Frame, "ANCHOR_NONE");
</Onload>
</Scripts>
</GameTooltip>
</Ui>
\ No newline at end of file