annotate Modules/Alerts.lua @ 176:26c750a10b14

Renamed Inventorium debug channel to IMDebug (so it?s easier to recognize only IM changes, not from other addons), write /im d to register this new channel. Implemented stock alerts. Added ?don?t alert at characters? option which allows you to track groups at characters without being bothered about low stock. You can change the speed of the stock alert at the extra config tab.
author Zerotorescue
date Sun, 30 Jan 2011 15:39:18 +0100
parents
children 679d3664849d
rev   line source
Zerotorescue@176 1 local addon = select(2, ...);
Zerotorescue@176 2 local mod = addon:NewModule("Alerts", "AceEvent-3.0", "AceTimer-3.0");
Zerotorescue@176 3
Zerotorescue@176 4 local queue, cache = {}, {};
Zerotorescue@176 5
Zerotorescue@176 6 function mod:OnEnable()
Zerotorescue@176 7 addon:Debug("Alerts:OnEnable");
Zerotorescue@176 8
Zerotorescue@176 9 -- Register our alert slash command
Zerotorescue@176 10 -- /im alert
Zerotorescue@176 11 addon:RegisterSlash(function(this)
Zerotorescue@176 12 mod:Scan(true);
Zerotorescue@176 13 end, { "a", "alert" }, "|Hfunction:InventoriumCommandHandler:alert|h|cff00fff7/im alert|r|h (or /im a) - Rescan the items within all tracked groups and show item alerts for those items missing.");
Zerotorescue@176 14
Zerotorescue@176 15 self:RegisterEvent("PLAYER_LOGIN", function()
Zerotorescue@176 16 mod:Scan(false);
Zerotorescue@176 17 end);
Zerotorescue@176 18
Zerotorescue@176 19 --[[if addon.db.profile.defaults.scanInterval["00Login"] then
Zerotorescue@176 20 self:RegisterEvent("PLAYER_LOGIN", "Scan");
Zerotorescue@176 21 end
Zerotorescue@176 22
Zerotorescue@176 23 if addon.db.profile.defaults.scanInterval["01Repeat5"] then
Zerotorescue@176 24 self:ScheduleTimer("Scan", 5 * 60);
Zerotorescue@176 25 elseif addon.db.profile.defaults.scanInterval["01Repeat10"] then
Zerotorescue@176 26 self:ScheduleTimer("Scan", 10 * 60);
Zerotorescue@176 27 elseif addon.db.profile.defaults.scanInterval["01Repeat15"] then
Zerotorescue@176 28 self:ScheduleTimer("Scan", 15 * 60);
Zerotorescue@176 29 elseif addon.db.profile.defaults.scanInterval["01Repeat30"] then
Zerotorescue@176 30 self:ScheduleTimer("Scan", 30 * 60);
Zerotorescue@176 31 elseif addon.db.profile.defaults.scanInterval["01Repeat60"] then
Zerotorescue@176 32 self:ScheduleTimer("Scan", 60 * 60);
Zerotorescue@176 33 elseif addon.db.profile.defaults.scanInterval["01Repeat120"] then
Zerotorescue@176 34 self:ScheduleTimer("Scan", 120 * 60);
Zerotorescue@176 35 end]]
Zerotorescue@176 36 end
Zerotorescue@176 37
Zerotorescue@176 38 local scanTypes = {
Zerotorescue@176 39 Local = "local",
Zerotorescue@176 40 Global = "global",
Zerotorescue@176 41 };
Zerotorescue@176 42
Zerotorescue@176 43 function mod:Scan(verbal)
Zerotorescue@176 44 addon:Debug("Alerts:Scan");
Zerotorescue@176 45
Zerotorescue@176 46 if verbal then
Zerotorescue@176 47 addon:Print("Scanning items, the results will be presented to you in a moment. Please be patient.");
Zerotorescue@176 48 end
Zerotorescue@176 49
Zerotorescue@176 50 local playerName = UnitName("player");
Zerotorescue@176 51
Zerotorescue@176 52 table.wipe(queue);
Zerotorescue@176 53 table.wipe(cache);
Zerotorescue@176 54
Zerotorescue@176 55 -- Go through all groups
Zerotorescue@176 56 for groupName, values in pairs(addon.db.profile.groups) do
Zerotorescue@176 57 -- Settings
Zerotorescue@176 58 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters");
Zerotorescue@176 59 local dontAlertAt = addon:GetOptionByKey(groupName, "dontAlertAtCharacters");
Zerotorescue@176 60
Zerotorescue@176 61 local alertBelowLocalMinimum = addon:GetOptionByKey(groupName, "alertBelowLocalMinimum");
Zerotorescue@176 62 local minLocalStock = alertBelowLocalMinimum and addon:GetOptionByKey(groupName, "minLocalStock");
Zerotorescue@176 63
Zerotorescue@176 64 local alertBelowGlobalMinimum = addon:GetOptionByKey(groupName, "alertBelowGlobalMinimum");
Zerotorescue@176 65 local minGlobalStock = alertBelowGlobalMinimum and addon:GetOptionByKey(groupName, "minGlobalStock");
Zerotorescue@176 66
Zerotorescue@176 67 local isTracked = (trackAt and trackAt[playerName] and (not dontAlertAt or not dontAlertAt[playerName])); -- Is this character interested in this data and does it want alerts?
Zerotorescue@176 68
Zerotorescue@176 69 if values.items and isTracked and (alertBelowLocalMinimum or alertBelowGlobalMinimum) then
Zerotorescue@176 70 addon:Debug("Scanning |cff00ff00%s|r", groupName);
Zerotorescue@176 71
Zerotorescue@176 72 local groupSettings = {
Zerotorescue@176 73 ["name"] = groupName,
Zerotorescue@176 74 ["minLocalStock"] = minLocalStock,
Zerotorescue@176 75 ["minGlobalStock"] = minGlobalStock,
Zerotorescue@176 76 };
Zerotorescue@176 77
Zerotorescue@176 78 for itemId, _ in pairs(values.items) do
Zerotorescue@176 79 if alertBelowLocalMinimum then
Zerotorescue@176 80 self:QeueueScan(groupSettings, itemId, scanTypes.Local);
Zerotorescue@176 81 end
Zerotorescue@176 82
Zerotorescue@176 83 if alertBelowGlobalMinimum then
Zerotorescue@176 84 self:QeueueScan(groupSettings, itemId, scanTypes.Global);
Zerotorescue@176 85 end
Zerotorescue@176 86 end
Zerotorescue@176 87 end
Zerotorescue@176 88 end
Zerotorescue@176 89
Zerotorescue@176 90 if self:HasQueue() then
Zerotorescue@176 91 addon:Debug("Alerts:HasQueue, processing");
Zerotorescue@176 92 --addon:Debug(queue);
Zerotorescue@176 93
Zerotorescue@176 94 self:ProcessScan(verbal);
Zerotorescue@176 95 end
Zerotorescue@176 96 end
Zerotorescue@176 97
Zerotorescue@176 98 function mod:QeueueScan(groupSettings, itemId, scanType)
Zerotorescue@176 99 table.insert(queue, {
Zerotorescue@176 100 ["group"] = groupSettings,
Zerotorescue@176 101 ["itemId"] = itemId,
Zerotorescue@176 102 ["type"] = scanType,
Zerotorescue@176 103 });
Zerotorescue@176 104 end
Zerotorescue@176 105
Zerotorescue@176 106 function mod:HasQueue()
Zerotorescue@176 107 return (#queue > 0);
Zerotorescue@176 108 end
Zerotorescue@176 109
Zerotorescue@176 110 function mod:ProcessScan(verbal)
Zerotorescue@176 111 local thisItem = table.remove(queue, 1);
Zerotorescue@176 112
Zerotorescue@176 113 if not thisItem then
Zerotorescue@176 114 self:ScanFinished();
Zerotorescue@176 115 return;
Zerotorescue@176 116 end
Zerotorescue@176 117
Zerotorescue@176 118 if thisItem.type == scanTypes.Global then
Zerotorescue@176 119 local globalCount = addon:GetItemCount(thisItem.itemId, thisItem.group.name);
Zerotorescue@176 120
Zerotorescue@176 121 if not cache[thisItem.itemId] then
Zerotorescue@176 122 cache[thisItem.itemId] = {
Zerotorescue@176 123 ["itemId"] = thisItem.itemId, -- needed later for displaying
Zerotorescue@176 124 ["group"] = thisItem.group,
Zerotorescue@176 125 ["globalCount"] = globalCount,
Zerotorescue@176 126 };
Zerotorescue@176 127 else
Zerotorescue@176 128 cache[thisItem.itemId].globalCount = globalCount;
Zerotorescue@176 129 end
Zerotorescue@176 130 elseif thisItem.type == scanTypes.Local then
Zerotorescue@176 131 local localCount = addon:GetLocalItemCount(thisItem.itemId, thisItem.group.name);
Zerotorescue@176 132
Zerotorescue@176 133 if not cache[thisItem.itemId] then
Zerotorescue@176 134 cache[thisItem.itemId] = {
Zerotorescue@176 135 ["itemId"] = thisItem.itemId, -- needed later for displaying
Zerotorescue@176 136 ["group"] = thisItem.group,
Zerotorescue@176 137 ["localCount"] = localCount,
Zerotorescue@176 138 };
Zerotorescue@176 139 else
Zerotorescue@176 140 cache[thisItem.itemId].globalCount = localCount;
Zerotorescue@176 141 end
Zerotorescue@176 142 end
Zerotorescue@176 143
Zerotorescue@176 144 local nextScanDelay = (tonumber(addon.db.profile.defaults.scanInterval) or .1);
Zerotorescue@176 145
Zerotorescue@176 146 if nextScanDelay == 0 then
Zerotorescue@176 147 mod:ProcessScan(verbal);
Zerotorescue@176 148 else
Zerotorescue@176 149 self:ScheduleTimer(function()
Zerotorescue@176 150 mod:ProcessScan(verbal);
Zerotorescue@176 151 end, nextScanDelay); -- scan next item in nextScanDelay seconds
Zerotorescue@176 152 end
Zerotorescue@176 153 end
Zerotorescue@176 154
Zerotorescue@176 155 local function OnProceed()
Zerotorescue@176 156 InventoriumCommandHandler("summary");
Zerotorescue@176 157
Zerotorescue@176 158 if InventoriumItemMover then
Zerotorescue@176 159 InventoriumItemMover:Hide();
Zerotorescue@176 160 end
Zerotorescue@176 161 end
Zerotorescue@176 162
Zerotorescue@176 163 local function OnCancel()
Zerotorescue@176 164 if InventoriumItemMover then
Zerotorescue@176 165 InventoriumItemMover:Hide();
Zerotorescue@176 166 end
Zerotorescue@176 167 end
Zerotorescue@176 168
Zerotorescue@176 169 local function UseScanST()
Zerotorescue@176 170 if not InventoriumItemMover then
Zerotorescue@176 171 addon:CreateMoverFrame();
Zerotorescue@176 172 end
Zerotorescue@176 173
Zerotorescue@176 174 local frame = InventoriumItemMover; -- both for speed as code-consistency
Zerotorescue@176 175
Zerotorescue@176 176 -- Scrolling table with a list of items to be moved
Zerotorescue@176 177 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size
Zerotorescue@176 178 local headers = {
Zerotorescue@176 179 {
Zerotorescue@176 180 ["name"] = "Item",
Zerotorescue@176 181 ["width"] = (scrollTableWidth * .6),
Zerotorescue@176 182 ["defaultsort"] = "asc",
Zerotorescue@176 183 ["comparesort"] = function(this, aRow, bRow, column)
Zerotorescue@176 184 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId);
Zerotorescue@176 185 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId);
Zerotorescue@176 186 local template = "%d%s";
Zerotorescue@176 187 aName = template:format((10 - (aRarity or 10)), (aName or ""):lower());
Zerotorescue@176 188 bName = template:format((10 - (bRarity or 10)), (bName or ""):lower());
Zerotorescue@176 189
Zerotorescue@176 190 if this.cols[column].sort == "dsc" then
Zerotorescue@176 191 return aName > bName;
Zerotorescue@176 192 else
Zerotorescue@176 193 return aName < bName;
Zerotorescue@176 194 end
Zerotorescue@176 195 end,
Zerotorescue@176 196 ["sort"] = "asc", -- when the data is set, use this column so sort the default data
Zerotorescue@176 197 ["tooltipTitle"] = "Item",
Zerotorescue@176 198 ["tooltip"] = "Click to sort the list by item quality then item name.",
Zerotorescue@176 199 },
Zerotorescue@176 200 {
Zerotorescue@176 201 ["name"] = "Local",
Zerotorescue@176 202 ["width"] = (scrollTableWidth * .2),
Zerotorescue@176 203 ["align"] = "RIGHT",
Zerotorescue@176 204 ["defaultsort"] = "dsc",
Zerotorescue@176 205 ["sortnext"] = 1,
Zerotorescue@176 206 ["comparesort"] = function(this, aRow, bRow, column)
Zerotorescue@176 207 local aAvailablePercent = (this:GetRow(aRow).rowData.localCount / this:GetRow(aRow).rowData.group.minLocalStock);
Zerotorescue@176 208 local bAvailablePercent = (this:GetRow(bRow).rowData.localCount / this:GetRow(bRow).rowData.group.minLocalStock);
Zerotorescue@176 209
Zerotorescue@176 210 if this.cols[column].sort == "dsc" then
Zerotorescue@176 211 return aAvailablePercent > bAvailablePercent;
Zerotorescue@176 212 else
Zerotorescue@176 213 return aAvailablePercent < bAvailablePercent;
Zerotorescue@176 214 end
Zerotorescue@176 215 end,
Zerotorescue@176 216 ["tooltipTitle"] = "Local Stock",
Zerotorescue@176 217 ["tooltip"] = "Click to sort the list by the local stock percentage.",
Zerotorescue@176 218 },
Zerotorescue@176 219 {
Zerotorescue@176 220 ["name"] = "Global",
Zerotorescue@176 221 ["width"] = (scrollTableWidth * .2),
Zerotorescue@176 222 ["align"] = "RIGHT",
Zerotorescue@176 223 ["defaultsort"] = "dsc",
Zerotorescue@176 224 ["sortnext"] = 1,
Zerotorescue@176 225 ["comparesort"] = function(this, aRow, bRow, column)
Zerotorescue@176 226 local aAvailablePercent = (this:GetRow(aRow).rowData.globalCount / this:GetRow(aRow).rowData.group.minGlobalStock);
Zerotorescue@176 227 local bAvailablePercent = (this:GetRow(bRow).rowData.globalCount / this:GetRow(bRow).rowData.group.minGlobalStock);
Zerotorescue@176 228
Zerotorescue@176 229 if this.cols[column].sort == "dsc" then
Zerotorescue@176 230 return aAvailablePercent > bAvailablePercent;
Zerotorescue@176 231 else
Zerotorescue@176 232 return aAvailablePercent < bAvailablePercent;
Zerotorescue@176 233 end
Zerotorescue@176 234 end,
Zerotorescue@176 235 ["tooltipTitle"] = "Global Stock",
Zerotorescue@176 236 ["tooltip"] = "Click to sort the list by the global stock percentage.",
Zerotorescue@176 237 },
Zerotorescue@176 238 };
Zerotorescue@176 239
Zerotorescue@176 240 local proceedButton = {
Zerotorescue@176 241 text = "Show in summary",
Zerotorescue@176 242 tooltipTitle = "Show in Summary",
Zerotorescue@176 243 tooltip = "Show the summary giving a more detailed list of missing items.",
Zerotorescue@176 244 onClick = OnProceed,
Zerotorescue@176 245 };
Zerotorescue@176 246 local cancelButton = {
Zerotorescue@176 247 text = "Cancel",
Zerotorescue@176 248 tooltipTitle = "Cancel",
Zerotorescue@176 249 tooltip = "Close the window.",
Zerotorescue@176 250 onClick = OnCancel,
Zerotorescue@176 251 };
Zerotorescue@176 252
Zerotorescue@176 253 addon:SetMoverFrameSettings("Inventorium Stock Alert", "You have elected to receive an alert when the following items are under your minimum stock requirement:", proceedButton, cancelButton, headers);
Zerotorescue@176 254 end
Zerotorescue@176 255
Zerotorescue@176 256 function mod:ScanFinished()
Zerotorescue@176 257 table.wipe(queue);
Zerotorescue@176 258
Zerotorescue@176 259 --addon:Debug(cache);
Zerotorescue@176 260
Zerotorescue@176 261 -- This table is never copied, just referenced. It is the same for every row.
Zerotorescue@176 262 local missingRow = {
Zerotorescue@176 263 {
Zerotorescue@176 264 ["value"] = function(data, cols, realrow, column, table)
Zerotorescue@176 265 return IdToItemLink(data[realrow].rowData.itemId);
Zerotorescue@176 266 end,
Zerotorescue@176 267 }, -- item
Zerotorescue@176 268 {
Zerotorescue@176 269 ["value"] = function(data, cols, realrow, column, table)
Zerotorescue@176 270 return addon:DisplayItemCount(data[realrow].rowData.localCount or -4, data[realrow].rowData.group.minLocalStock);
Zerotorescue@176 271 end,
Zerotorescue@176 272 }, -- local
Zerotorescue@176 273 {
Zerotorescue@176 274 ["value"] = function(data, cols, realrow, column, table)
Zerotorescue@176 275 return addon:DisplayItemCount(data[realrow].rowData.globalCount or -4, data[realrow].rowData.group.minGlobalStock);
Zerotorescue@176 276 end,
Zerotorescue@176 277 }, -- global
Zerotorescue@176 278 };
Zerotorescue@176 279
Zerotorescue@176 280 -- Store the list with rows in this
Zerotorescue@176 281 local missingList = {};
Zerotorescue@176 282
Zerotorescue@176 283 for itemId, info in pairs(cache) do
Zerotorescue@176 284 if (info.globalCount and info.globalCount < info.group.minGlobalStock) or (info.localCount and info.localCount < info.group.minLocalStock) then
Zerotorescue@176 285 -- Not enough global or not enough local
Zerotorescue@176 286
Zerotorescue@176 287 tinsert(missingList, {
Zerotorescue@176 288 ["rowData"] = info, -- this is not a key usually found in a row item and ignored by the library
Zerotorescue@176 289 ["cols"] = missingRow,
Zerotorescue@176 290 });
Zerotorescue@176 291 end
Zerotorescue@176 292 end
Zerotorescue@176 293
Zerotorescue@176 294 table.wipe(cache); -- no longer needed, all missing items are now stored in the missingList
Zerotorescue@176 295
Zerotorescue@176 296 if #missingList > 0 then
Zerotorescue@176 297 UseScanST();
Zerotorescue@176 298
Zerotorescue@176 299 addon:SetMoverFrameData(missingList);
Zerotorescue@176 300
Zerotorescue@176 301 if verbal then
Zerotorescue@176 302 addon:Print("Presenting the data...");
Zerotorescue@176 303 end
Zerotorescue@176 304 elseif verbal then
Zerotorescue@176 305 addon:Print("No items that you elected to be alerted about are below the selected stock thresholds.");
Zerotorescue@176 306 end
Zerotorescue@176 307 end