comparison Core.lua @ 62:fee06221176f

Seperated the config from Core.lua. Many other code cleaning up for readability. Added local references for much used globals. Moved widgets to a different file for readability. Re-added global function for slash command handling since we do need it for our chat-hyperlinks. Fixed queueing to properly use the track at property of virtual groups. Fixed queueing to display the item id instead of the item link if the item link could not be loaded. Speed slider at the summary now has an interval of 1% down from 5% and rounds rather than ceils it?s value so 101% will become 100% rather than 105%. Now using the right stock properties at the summary. Added a help group to the config.
author Zerotorescue
date Wed, 22 Dec 2010 19:56:55 +0100
parents d903b0a151d3
children ac1189599769
comparison
equal deleted inserted replaced
61:d903b0a151d3 62:fee06221176f
1 -- You can access this addon's object through: LibStub("AceAddon-3.0"):GetAddon("Inventorium") 1 -- You can access this addon's object through: LibStub("AceAddon-3.0"):GetAddon("Inventorium")
2 local addon = select(2, ...); 2 local addon = select(2, ...);
3 addon = LibStub("AceAddon-3.0"):NewAddon(addon, "Inventorium", "AceEvent-3.0"); 3 addon = LibStub("AceAddon-3.0"):NewAddon(addon, "Inventorium", "AceEvent-3.0");
4
5 local AceGUI = LibStub("AceGUI-3.0");
6 4
7 --@debug@ 5 --@debug@
8 local addonRevision = 1; 6 local addonRevision = 1;
9 --@end-debug@ 7 --@end-debug@
10 --[===[@non-debug@ 8 --[===[@non-debug@
11 local addonRevision = @project-revision@; 9 local addonRevision = @project-revision@;
12 --@end-non-debug@]===] 10 --@end-non-debug@]===]
13 11
14 local AceConfigDialog, AceConfigRegistry, AceSerializer; 12 local _G = _G;
15 local groupIdToName, groupIsVirtual, options = {}, {}, {}; 13 local print, pairs, tonumber = _G.print, _G.pairs, _G.tonumber;
16 local includeTradeSkillItems = 500; 14
17 15 -- All modules must be able to retrieve our supported addons database, thus keep it a part of the addon object rather than local
18 local slashArgs = {};
19 local slashError = "Wrong argument, the following arguments are available:";
20
21 -- All modules must be able to retrieve our supported addons database, thus keep it public
22 addon.supportedAddons = {}; 16 addon.supportedAddons = {};
23 addon.supportedAddons.auctionPricing = {}; 17 addon.supportedAddons.auctionPricing = {};
24 addon.supportedAddons.itemCount = {}; 18 addon.supportedAddons.itemCount = {};
25 addon.supportedAddons.crafting = {}; 19 addon.supportedAddons.crafting = {};
26
27 local function CommandHandler(message)
28 local cmd, arg = string.split(" ", (message or ""), 2);
29 cmd = string.lower(cmd);
30
31 if slashArgs[cmd] then
32 slashArgs[cmd](addon, arg);
33 else
34 print(slashError);
35 end
36 end
37 20
38 function addon:OnInitialize() 21 function addon:OnInitialize()
39 self:Debug("OnInitialize"); 22 self:Debug("OnInitialize");
40 23
41 -- SAVED VARIABLES 24 -- SAVED VARIABLES
86 }, 69 },
87 }; 70 };
88 71
89 -- Register our saved variables database 72 -- Register our saved variables database
90 self.db = LibStub("AceDB-3.0"):New("InventoriumDB", defaults, true); 73 self.db = LibStub("AceDB-3.0"):New("InventoriumDB", defaults, true);
91 self.db.RegisterCallback(self, "OnProfileChanged", "RefreshConfig") 74
92 self.db.RegisterCallback(self, "OnProfileCopied", "RefreshConfig") 75 -- SLASH COMMANDS
93 self.db.RegisterCallback(self, "OnProfileReset", "RefreshConfig") 76
94 77 -- Disable the AddonLoader slash commands
78 SLASH_INVENTORIUM1 = nil;
79 SLASH_IM1 = nil;
80
81 -- Register our own slash commands
82 SLASH_INVENTORIUM1 = "/inventorium";
83 SLASH_INVENTORIUM2 = "/im";
84 SlashCmdList["INVENTORIUM"] = function(msg)
85 addon:CommandHandler(msg);
86 end;
87
88 -- Debug command handling
89 self:RegisterSlash(function(this)
90 this.debugChannel = false;
91 for i = 1, NUM_CHAT_WINDOWS do
92 local name = GetChatWindowInfo(i);
93
94 if name:upper() == "DEBUG" then
95 this.debugChannel = _G["ChatFrame" .. i];
96
97 print("A debug channel already exists, used the old one. (" .. i .. ")");
98 return;
99 end
100 end
101
102 if not this.debugChannel then
103 -- Create a new debug channel
104 local chatFrame = FCF_OpenNewWindow('Debug');
105 ChatFrame_RemoveAllMessageGroups(chatFrame);
106 this.debugChannel = chatFrame;
107
108 print("New debug channel created.");
109 end
110 end, { "d", "debug" });
111
112 -- Remember this character is on this account
113 local playerName = UnitName("player");
114 if not self.db.factionrealm.characters[playerName] then
115 self.db.factionrealm.characters[playerName] = true;
116
117 -- Default to tracking on all chars, untracking is a convenience, not tracking by default would probably get multiple issue reports.
118 self.db.profile.defaults.trackAtCharacters[playerName] = true;
119 end
120
121 self:PremadeGroupsCheck();
122 end
123
124 function addon:UpdateDatabase()
95 if not self.db.global.version or self.db.global.version < addonRevision then 125 if not self.db.global.version or self.db.global.version < addonRevision then
96 -- Is our database outdated? Then patch it. 126 -- Is our database outdated? Then patch it.
97 127
98 if not self.db.global.version then 128 if not self.db.global.version then
99 -- Old version was before version was saved, many changes were done in that revision 129 -- Old version was before version was saved, many changes were done in that revision
108 self.db.profile.groups = CopyTable(self.db.global.groups); 138 self.db.profile.groups = CopyTable(self.db.global.groups);
109 139
110 self.db.global.defaults = nil; 140 self.db.global.defaults = nil;
111 self.db.global.groups = nil; 141 self.db.global.groups = nil;
112 142
113 CommandHandler = function() 143 self.CommandHandler = function()
114 print("You must /reload once to finalize the database updates."); 144 message("You must /reload once to finalize the Inventorium database updates. This will only be required once during the BETA.");
115 end; 145 end;
116 CommandHandler(); 146 self:CommandHandler();
117 end 147 end
118 148
119 if self.db.profile.defaults.minimumStock then 149 if self.db.profile.defaults.minimumStock then
120 print("Copying the minimum stock value into the minimum global stock..."); 150 print("Copying the minimum stock value into the minimum global stock...");
121 151
150 end 180 end
151 181
152 -- Remember the version of our database 182 -- Remember the version of our database
153 self.db.global.version = addonRevision; 183 self.db.global.version = addonRevision;
154 end 184 end
155
156 -- SLASH COMMANDS
157
158 -- Disable the AddonLoader slash commands
159 SLASH_INVENTORIUM1 = nil;
160 SLASH_IY1 = nil;
161
162 -- Register our own slash commands
163 SLASH_INVENTORIUM1 = "/inventorium";
164 SLASH_INVENTORIUM2 = "/im";
165 SlashCmdList["INVENTORIUM"] = CommandHandler;
166
167 -- Config command handling
168 self:RegisterSlash(function(this)
169 -- We don't want any other windows open at this time.
170 for name, module in this:IterateModules() do
171 if module.CloseFrame then
172 module:CloseFrame();
173 end
174 end
175
176 this:Show();
177 end, { "c", "config", "conf", "option", "options", "opt", "setting", "settings" }, "|Hfunction:InventoriumCommandHandler:config|h|cff00fff7/im config|r|h (or /im c) - Open the config window to change the settings and manage groups.");
178
179 -- Debug command handling
180 self:RegisterSlash(function(this)
181 this.debugChannel = false;
182 for i = 1, NUM_CHAT_WINDOWS do
183 local name = GetChatWindowInfo(i);
184
185 if name:upper() == "DEBUG" then
186 this.debugChannel = _G["ChatFrame" .. i];
187
188 print("A debug channel already exists, used the old one. (" .. i .. ")");
189 return;
190 end
191 end
192
193 if not this.debugChannel then
194 -- Create a new debug channel
195 local chatFrame = FCF_OpenNewWindow('Debug');
196 ChatFrame_RemoveAllMessageGroups(chatFrame);
197 this.debugChannel = chatFrame;
198
199 print("New debug channel created.");
200 end
201 end, { "d", "debug" });
202
203 -- INTERFACE OPTIONS
204
205 -- Attempt to remove the interface options added by AddonLoader (if enabled)
206 if AddonLoader and AddonLoader.RemoveInterfaceOptions then
207 AddonLoader:RemoveInterfaceOptions("Inventorium");
208 end
209
210 -- Now create our own options frame
211 local frame = CreateFrame("Frame", nil, UIParent);
212 frame:Hide();
213 frame.name = "Inventorium";
214 frame:HookScript("OnShow", function(self)
215 -- Refresh the frame to instantly show the right options
216 InterfaceOptionsFrame_OpenToCategory(self.name)
217 end);
218 -- And add it to the interface options
219 InterfaceOptions_AddCategory(frame);
220
221 self:MakeItemLinkButtonWidget();
222 self:MakeConfigItemLinkButtonWidget();
223
224 -- Remember this character is on this account
225 local playerName = UnitName("player");
226 if not self.db.factionrealm.characters[playerName] then
227 self.db.factionrealm.characters[playerName] = true;
228
229 -- Default to tracking on all chars, untracking is a convenience, not tracking by default would probably get multiple issue reports.
230 self.db.profile.defaults.trackAtCharacters[playerName] = true;
231 end
232
233 self:PremadeGroupsCheck();
234 end
235
236 function addon:RefreshConfig()
237 self:FillGroupOptions();
238 end
239
240 local function InGroup(itemId)
241 -- Go through all groups to see if this item is already somewhere
242 for groupName, values in pairs(addon.db.profile.groups) do
243 if values.items and values.items[itemId] then
244 return groupName;
245 end
246 end
247
248 return;
249 end
250
251 local function AddToGroup(groupName, itemId)
252 if InGroup(itemId) then
253 return false;
254 end
255
256 if not addon.db.profile.groups[groupName].items then
257 addon.db.profile.groups[groupName].items = {};
258 end
259
260 -- Set this item
261 addon.db.profile.groups[groupName].items[itemId] = true;
262
263 if AceConfigRegistry then
264 -- Now rebuild the list
265 AceConfigRegistry:NotifyChange("InventoriumOptions");
266 end
267
268 return true;
269 end
270
271 local function RemoveFromGroup(groupName, itemId)
272 if InGroup(itemId) ~= groupName then
273 return false;
274 end
275
276 -- Unset this item
277 addon.db.profile.groups[groupName].items[itemId] = nil;
278
279 return true;
280 end 185 end
281 186
282 function addon:PremadeGroupsCheck(updateGroupName, updateKey, accept) 187 function addon:PremadeGroupsCheck(updateGroupName, updateKey, accept)
283 -- Compare the current premade groups with those used, notify about changes 188 -- Compare the current premade groups with those used, notify about changes
284 if addon.defaultGroups then 189 if addon.defaultGroups then
301 -- Go through all items in this premade group 206 -- Go through all items in this premade group
302 207
303 if version > values.premadeGroups[premadeGroupName] then 208 if version > values.premadeGroups[premadeGroupName] then
304 -- This item was added in a more recent version than this group: Add item 209 -- This item was added in a more recent version than this group: Add item
305 210
306 if InGroup(itemId) then 211 if self:InGroup(itemId) then
307 print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); 212 print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, self:InGroup(itemId)));
308 elseif AddToGroup(groupName, itemId) then 213 elseif self:AddItemToGroup(groupName, itemId) then
309 print(("|cff00ff00Added|r %s (#%d) found in the premade group |cfffed000%s|r to the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, premadeGroupName, InGroup(itemId))); 214 print(("|cff00ff00Added|r %s (#%d) found in the premade group |cfffed000%s|r to the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, premadeGroupName, self:InGroup(itemId)));
310 end 215 end
311 elseif ( version * -1 ) > values.premadeGroups[premadeGroupName] then 216 elseif ( version * -1 ) > values.premadeGroups[premadeGroupName] then
312 if InGroup(itemId) == groupName then 217 if self:InGroup(itemId) == groupName then
313 print(("|cffff0000Removed|r %s (#%d) from the group |cfffed000%s|r as it was removed from the premade group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId), premadeGroupName)); 218 print(("|cffff0000Removed|r %s (#%d) from the group |cfffed000%s|r as it was removed from the premade group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, self:InGroup(itemId), premadeGroupName));
314 RemoveFromGroup(groupName, itemId); 219 self:RemoveItemFromGroup(groupName, itemId);
315 else 220 else
316 print(("Skipping the removal of %s (#%d) as it isn't in this group."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); 221 print(("Skipping the removal of %s (#%d) as it isn't in this group."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, self:InGroup(itemId)));
317 end 222 end
318 end 223 end
319 end 224 end
320 225
321 -- Remember the new version 226 -- Remember the new version
328 -- Go through all items in this premade group 233 -- Go through all items in this premade group
329 234
330 if version > values.premadeGroups[premadeGroupName] then 235 if version > values.premadeGroups[premadeGroupName] then
331 -- This item was added in a more recent version than this group: don't add (since we clicked no), but announce it 236 -- This item was added in a more recent version than this group: don't add (since we clicked no), but announce it
332 237
333 print(("Skipping %s (#%d) found in the premade group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId))); 238 print(("Skipping %s (#%d) found in the premade group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, self:InGroup(itemId)));
334 end 239 end
335 end 240 end
336 241
337 -- Remember the new version 242 -- Remember the new version
338 values.premadeGroups[premadeGroupName] = groupInfo.version; 243 values.premadeGroups[premadeGroupName] = groupInfo.version;
362 end 267 end
363 end 268 end
364 end 269 end
365 end 270 end
366 271
367 272 function addon:GetItemId(itemLink)
368 273 itemLink = itemLink and itemLink:match("|Hitem:([-0-9]+):"); -- if itemLink is nil, it won't execute the second part
369 function addon:MakeItemLinkButtonWidget() 274 itemLink = itemLink and tonumber(itemLink);
370 --[[ 275
371 [ ItemLinkButton ] 276 return itemLink;
372 This custom widget has to show an icon with the item link next to it. 277 end
373 Upon hover it must show the item tooltip. 278
374 Upon click it must execute the function provided through user data. 279 function addon:GetOptionByKey(groupName, optionName, noDefault)
375 280 if groupName and addon.db.profile.groups[groupName] and addon.db.profile.groups[groupName][optionName] ~= nil then
376 UserData: itemId, onClickEvent 281 -- If this option exists within the settings of this group
377 282
378 OnEnter: tooltip show 283 return addon.db.profile.groups[groupName][optionName];
379 OnLeave: tooltip hide 284 elseif groupName and addon.db.profile.groups[groupName] and addon.db.profile.groups[groupName].virtualGroup ~= "" and not noDefault then
380 OnClick: UserData.onClickEvent 285 -- If a virtual group was selected
381 ]] 286
382 287 return self:GetOptionByKey(addon.db.profile.groups[groupName].virtualGroup, optionName, noDefault);
383 local widgetType = "ItemLinkButton"; 288 elseif addon.db.profile.defaults[optionName] and not noDefault then
384 local widgetVersion = 1; 289 return addon.db.profile.defaults[optionName];
385 290 else
386 local function Constructor() 291 return nil;
387 local widget = AceGUI:Create("InteractiveLabel"); 292 end
388 widget.type = widgetType; 293 end
389 294
390 -- We overwrite the OnAcquire as we want to set our callbacks even 295 function addon:GetItemCountAddon(group)
391 -- when the widget is re-used from the widget pool 296 local selectedExternalAddon = self:GetOptionByKey(group, "itemCountAddon");
392 widget.originalOnAcquire = widget.OnAcquire; 297
393 widget.OnAcquire = function(self, ...) 298 if self.supportedAddons.itemCount[selectedExternalAddon] and self.supportedAddons.itemCount[selectedExternalAddon].IsEnabled() then
394 299 -- Try to use the default item count addon
395 300
396 -- We overwrite the setcallback because we don't want anything else 301 return self.supportedAddons.itemCount[selectedExternalAddon], selectedExternalAddon;
397 -- to overwrite our OnEnter, OnLeave and OnClick events 302 else
398 -- which would be done by the AceConfigDialog after a widget gets re-used 303 -- Default not available, get the first one then
399 if not self.originalSetCallBack then 304
400 self.originalSetCallBack = self.SetCallback; 305 for name, value in pairs(self.supportedAddons.itemCount) do
401 self.SetCallback = function(this, event, func, ...) 306 if value.IsEnabled() then
402 if event == "OnEnter" or event == "OnLeave" or event == "OnClick" then 307 return value, name;
403 -- Don't allow overwriting of these events 308 end
404 return; 309 end
405 elseif event == "CustomOnEnter" then 310 end
406 return this.originalSetCallBack(this, "OnEnter", func, ...); 311
407 elseif event == "CustomOnLeave" then 312 return;
408 return this.originalSetCallBack(this, "OnLeave", func, ...); 313 end
409 elseif event == "CustomOnClick" then 314
410 return this.originalSetCallBack(this, "OnClick", func, ...); 315 function addon:GetItemCount(itemId, group)
411 else 316 itemId = tonumber(itemId);
412 return this.originalSetCallBack(this, event, func, ...); 317
413 end 318 if not itemId then return; end
414 end; 319
415 end 320 local itemCountAddon = self:GetItemCountAddon(group);
416 321
417 322 return (itemCountAddon and itemCountAddon.GetTotalCount(itemId)) or -1;
418 323 end
419 -- Set our own events, since we disabled the normal event-names, we'll call them our custom versions 324
420 self:SetCallback("CustomOnEnter", function(this) 325 function addon:GetLocalItemCount(itemId, group)
421 local itemId = this:GetUserData("itemId"); 326 itemId = tonumber(itemId);
422 327
423 if itemId then 328 if not itemId then return; end
424 GameTooltip:SetOwner(this.frame, "ANCHOR_TOPRIGHT"); 329
425 GameTooltip:SetHyperlink(("item:%d"):format(itemId)); 330 local itemCountAddon = self:GetItemCountAddon(group);
426 GameTooltip:Show(); 331
427 end 332 local currentItemCount;
428 end); 333
429 self:SetCallback("CustomOnLeave", function(this) 334 if itemCountAddon and itemCountAddon.GetCharacterCount then
430 GameTooltip:Hide(); 335 local bag, bank, auctionHouse, mail = itemCountAddon.GetCharacterCount(itemId);
431 end); 336
432 self:SetCallback("CustomOnClick", function(this, ...) 337 local selectedLocalItemCountSources = self:GetOptionByKey(group, "localItemData");
433 -- Below is used in child widgets to prepare for onclick 338
434 if this.OnClick then 339 currentItemCount = 0;
435 this.OnClick(this, ...); 340 if selectedLocalItemCountSources["Bag"] then
436 end 341 currentItemCount = currentItemCount + bag;
437 342 end
438 local func = this:GetUserData("exec"); 343 if selectedLocalItemCountSources["Bank"] then
439 local itemId = this:GetUserData("itemId"); 344 currentItemCount = currentItemCount + bank;
440 345 end
441 if func then 346 if selectedLocalItemCountSources["Auction House"] then
442 -- If this is a config option we will need the group id 347 currentItemCount = currentItemCount + auctionHouse;
443 local path = this:GetUserData("path"); 348 end
444 local groupId = (path and path[2]) or nil; 349 if selectedLocalItemCountSources["Mailbox"] then
445 350 currentItemCount = currentItemCount + mail;
446 func(groupId, itemId, ...); 351 end
447 end 352 end
448 end); 353
449 354 return currentItemCount or -1;
450 355 end
451 356
452 -- Then also do whatever it wanted to do 357 function addon:GetAuctionValue(itemLink, group)
453 self.originalOnAcquire(self, ...); 358 if not itemLink then return -5; end
454 end; 359
455 360 local selectedExternalAddon = self:GetOptionByKey(group, "auctionPricingAddon");
456 -- Remember the original SetText as this might get overwritten by the config-widget 361
457 widget.originalSetText = widget.SetText; 362 if self.supportedAddons.auctionPricing[selectedExternalAddon] and self.supportedAddons.auctionPricing[selectedExternalAddon].IsEnabled() then
458 363 -- Try to use the default auction pricing addon
459 widget.SetItemId = function(self, itemId) 364
460 self:SetUserData("itemId", itemId); 365 return self.supportedAddons.auctionPricing[selectedExternalAddon].GetValue(itemLink);
461 366 else
462 -- Put the icon in front of it 367 -- Default not available, get the first one then
463 self:SetImage(GetItemIcon(itemId)); 368
464 -- Standardize the size 369 for name, value in pairs(self.supportedAddons.auctionPricing) do
465 self:SetImageSize(16, 16); 370 if value.IsEnabled() then
466 371 return value.GetValue(itemLink);
467 -- Make readable font 372 end
468 self:SetFontObject(GameFontHighlight); 373 end
469 374 end
470 -- We don't want to set the itemId as text, but rather the item link, so get that. 375
471 local itemLink = select(2, GetItemInfo(itemId)) or ("Unknown (#%d)"):format(itemId); 376 return -2;
472 377 end
473 self:originalSetText(itemLink); 378
474 end; 379 -- Slash commands
475 380
476 return widget; 381 local slashArgs = {};
477 end 382 local slashError = "Wrong argument, the following arguments are available:";
478 383
479 AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion); 384 function addon:CommandHandler(message)
480 end 385 local cmd, arg = string.split(" ", (message or ""), 2);
481 386 cmd = string.lower(cmd);
482 function addon:MakeConfigItemLinkButtonWidget() 387
483 -- Define out custom item link button widget 388 if slashArgs[cmd] then
484 -- This will be called as if it's an input element, we overwrite some of the related functions which are called for default input fields 389 -- Pass a reference to the addon (to be used as "self") and the provided arg
485 390 slashArgs[cmd](addon, arg);
486 local widgetType = "ConfigItemLinkButton"; 391 else
487 local widgetVersion = 1; 392 print(slashError);
488 393 end
489 -- Empty function for disabling functions
490 local function Dummy() end
491
492 -- Makes an instance of our ItemLinkButton widget
493 local function GetItemLinkButton()
494 local widget = AceGUI:Create("ItemLinkButton");
495 widget.type = widgetType;
496
497 -- We can only provide custom widgets for input, select and multiselect fields
498 -- Input being the simplest, we use that - however, it provides two parameters: label and text. We only need one, disable the other.
499 widget.SetLabel = Dummy;
500
501 -- SetText is called when this button is being created and contains the itemId
502 -- Forward that itemId to the ItemLinkButton
503 widget.SetText = function(self, value, ...)
504 if value and tonumber(value) then
505 self:SetItemId(tonumber(value));
506 end
507 end;
508
509 widget.OnClick = function(self, ...)
510 local option = self:GetUserData("option");
511
512 if option and option.set then
513 self:SetUserData("exec", option.set);
514 end
515 end;
516
517 return widget;
518 end
519
520 AceGUI:RegisterWidgetType(widgetType, GetItemLinkButton, widgetVersion);
521 end 394 end
522 395
523 function addon:RegisterSlash(func, args, description) 396 function addon:RegisterSlash(func, args, description)
524 for _, arg in pairs(args) do 397 for _, arg in pairs(args) do
525 slashArgs[arg] = func; 398 slashArgs[arg] = func;
528 if description then 401 if description then
529 slashError = slashError .. "\n" .. description; 402 slashError = slashError .. "\n" .. description;
530 end 403 end
531 end 404 end
532 405
533 function addon:Load() 406 -- Group functions
534 if not AceConfigDialog and not AceConfigRegistry then 407
535 self:FillOptions(); 408 function addon:InGroup(itemId)
536 409 -- Go through all groups to see if this item is already somewhere
537 -- Build options dialog 410 for groupName, values in pairs(addon.db.profile.groups) do
538 AceConfigDialog = LibStub("AceConfigDialog-3.0"); 411 if values.items and values.items[itemId] then
539 AceConfigRegistry = LibStub("AceConfigRegistry-3.0"); 412 return groupName;
540 -- Register options table 413 end
541 LibStub("AceConfig-3.0"):RegisterOptionsTable("InventoriumOptions", options); 414 end
542 -- Set a nice default size (so that 4 normal sized elements fit next to eachother) 415
543 AceConfigDialog:SetDefaultSize("InventoriumOptions", 975, 600); 416 return;
544 417 end
545 -- In case the addon is loaded from another condition, always call the remove interface options 418
546 if AddonLoader and AddonLoader.RemoveInterfaceOptions then 419 function addon:AddItemToGroup(groupName, itemId)
547 AddonLoader:RemoveInterfaceOptions("Inventorium"); 420 if self:InGroup(itemId) then
548 end 421 return false;
549 422 end
550 -- Add to the blizzard addons options thing 423
551 --AceConfigDialog:AddToBlizOptions("InventoriumOptions"); 424 if not addon.db.profile.groups[groupName].items then
552 end 425 addon.db.profile.groups[groupName].items = {};
553 end 426 end
554 427
555 function addon:Show() 428 -- Set this item
556 self:Load(); 429 addon.db.profile.groups[groupName].items[itemId] = true;
557 430
558 AceConfigDialog:Open("InventoriumOptions"); 431 if AceConfigRegistry then
559 end 432 -- Now rebuild the list
560 433 AceConfigRegistry:NotifyChange("InventoriumOptions");
561 function addon:FillOptions() 434 end
562 options = { 435
563 type = "group", 436 return true;
564 name = "Inventorium", 437 end
565 childGroups = "tree", 438
566 args = { 439 function addon:RemoveItemFromGroup(groupName, itemId)
567 }, 440 if self:InGroup(itemId) ~= groupName then
568 }; 441 return false;
569 442 end
570 self:FillGeneralOptions(); 443
571 444 -- Unset this item
572 options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db, true); 445 addon.db.profile.groups[groupName].items[itemId] = nil;
573 options.args.profiles.order = 200; 446
574 447 return true;
575 self:MakeGroupOptions(); 448 end
576 449
577 self:FillGroupOptions(); 450 -- Readable money
578 end
579 451
580 local goldText = "%s%d|cffffd700g|r "; 452 local goldText = "%s%d|cffffd700g|r ";
581 local silverText = "%s%d|cffc7c7cfs|r "; 453 local silverText = "%s%d|cffc7c7cfs|r ";
582 local copperText = "%s%d|cffeda55fc|r"; 454 local copperText = "%s%d|cffeda55fc|r";
583 455
631 else 503 else
632 return true; 504 return true;
633 end 505 end
634 end 506 end
635 507
636 function addon:FillGeneralOptions()
637 options.args.general = {
638 order = 100,
639 type = "group",
640 name = "General",
641 desc = "Change general Inventorium settings.",
642 args = {
643 info = {
644 order = 1,
645 type = "group",
646 inline = true,
647 name = "BETA Information",
648 args = {
649 description = {
650 order = 5,
651 type = "description",
652 name = "Please note that all multi-select |cfffed000dropdown|r boxes were turned into multi-select |cfffed000toggle|r boxes. I do not intend to keep it this way, however it can not yet be reverted due to a major bug in one of the libraries used by Inventorium. The layout of this config may look terribly organized in it's current state.\n\n" ..
653 "Since this is a beta some functionality might not be implemented yet while the options are available (usually - but not always - tagged as \"NYI\"). These options are used to indicate a feature is on the way and will be implemented before Inventorium is tagged as a release.\n\n" ..
654 "Please request things you want and report anything that's clunky, weird, vague or otherwise buggy at |cfffed000the Inventorium development addon page|r. You can find this by searching for \"|cfffed000Inventorium|r\" at |cfffed000CurseForge.com|r.\n\n" ..
655 "Tutorials for Inventorium will be created after the first stable release. If you require any help before that you can always contact me in the |cfffed000#JMTC|r IRC channel at |cfffed000QuakeNet.org|r. You may also report issues and request things there if you wish.\n\n" ..
656 "You might notice the summary window currently gets very slow when refreshed once you get over 100-200 items in the list, this is a known issue and will be fixed in |cfffed000version 1.1|r (which is after the initial release).",
657 },
658 },
659 },
660 general = {
661 order = 1,
662 type = "group",
663 inline = true,
664 name = "General",
665 args = {
666 description = {
667 order = 0,
668 type = "description",
669 name = function()
670 local t = "Here you can set general settings. The settings entered here will be used when you choose not to override the settings within an individual group.\n\n";
671
672 local currentAddon, selectedAddonName = addon:GetItemCountAddon();
673 local preferedAddon = self.db.profile.defaults.itemCountAddon;
674
675 if currentAddon then
676 --GetCharacterCount
677 --self.supportedAddons.itemCount[selectedExternalAddon]
678 t = t .. "Currently using |cfffed000" .. selectedAddonName .. "|r as your item count addon. This addon is " .. ((currentAddon.IsEnabled() and "|cff00ff00enabled|r") or "|cffff0000disabled|r") .. ".";
679
680 if currentAddon.GetTotalCount and currentAddon.GetCharacterCount then
681 t = t .. " This addon supports |cfffed000both total as local|r item counts.";
682 elseif currentAddon.GetTotalCount then
683 t = t .. " This addon supports |cfffed000only total|r item counts.";
684 elseif currentAddon.GetCharacterCount then
685 t = t .. " This addon supports |cfffed000only local|r item counts.";
686 end
687
688 if preferedAddon ~= selectedAddonName then
689 t = t .. "\n\n|cffff0000You have selected |cfffed000" .. preferedAddon .. "|r|cffff0000 as your item count addon, but this appears to be disabled and thus a random alternative was selected.|r";
690 end
691 end
692
693 return t;
694 end,
695 },
696 header = {
697 order = 5,
698 type = "header",
699 name = "",
700 },
701 auctionPricingAddon = {
702 order = 10,
703 type = "select",
704 name = "Prefered pricing addon",
705 desc = "Select the addon you prefer data to be retrieved from. A random supported addon will be used if the selected addon can not be found.",
706 values = function()
707 local temp = {};
708 for name, value in pairs(self.supportedAddons.auctionPricing) do
709 temp[name] = name;
710 end
711
712 return temp;
713 end,
714 get = function() return self.db.profile.defaults.auctionPricingAddon; end,
715 set = function(i, v)
716 self.db.profile.defaults.auctionPricingAddon = v;
717
718 if self.supportedAddons.auctionPricing[v].OnSelect then
719 self.supportedAddons.auctionPricing[v].OnSelect();
720 end
721 end,
722 },
723 itemCountAddon = {
724 order = 20,
725 type = "select",
726 name = "Prefered item count addon",
727 desc = "Select the addon you prefer data to be retrieved from. A random supported addon will be used if the selected addon can not be found.",
728 values = function()
729 local temp = {};
730 for name, value in pairs(self.supportedAddons.itemCount) do
731 temp[name] = name;
732 end
733
734 return temp;
735 end,
736 get = function() return self.db.profile.defaults.itemCountAddon; end,
737 set = function(i, v)
738 self.db.profile.defaults.itemCountAddon = v;
739
740 if self.supportedAddons.itemCount[v].OnSelect then
741 self.supportedAddons.itemCount[v].OnSelect();
742 end
743 end,
744 },
745 craftingAddon = {
746 order = 30,
747 type = "select",
748 name = "Prefered crafting addon",
749 desc = "Select the addon you prefer data to be queued into. A random supported addon will be used if the selected addon can not be found.",
750 values = function()
751 local temp = {};
752 for name, value in pairs(self.supportedAddons.crafting) do
753 temp[name] = name;
754 end
755
756 return temp;
757 end,
758 get = function() return self.db.profile.defaults.craftingAddon; end,
759 set = function(i, v)
760 self.db.profile.defaults.craftingAddon = v;
761
762 if self.supportedAddons.crafting[v].OnSelect then
763 self.supportedAddons.crafting[v].OnSelect();
764 end
765 end,
766 },
767 localItemData = {
768 order = 40,
769 type = "multiselect",
770 name = "Include in local item data",
771 desc = "Select which data should be included in the local item data.",
772 values = {
773 ["Bag"] = "Bag",
774 ["Bank"] = "Bank",
775 ["Auction House"] = "Auction House",
776 ["Mailbox"] = "Mailbox",
777 },
778 get = function(i, v) return self.db.profile.defaults.localItemData and self.db.profile.defaults.localItemData[v]; end,
779 set = function(i, v, e) self.db.profile.defaults.localItemData[v] = e or nil; end,
780 --dialogControl = "Dropdown", -- this is not standard, normal multiselect control gives us a list of all chars with toggle-boxes. UGLY! We want a multiselect-box instead.
781 },
782 },
783 },
784 minimumStock = {
785 order = 10,
786 type = "group",
787 inline = true,
788 name = "Minimum stock",
789 args = {
790 description = {
791 order = 0,
792 type = "description",
793 name = "Here you can specify the default minimum amount of items you wish to keep in stock and related settings. The settings entered here will be used when you choose not to override the settings within an individual group.",
794 },
795 header = {
796 order = 5,
797 type = "header",
798 name = "",
799 },
800 minLocalStock = {
801 order = 10,
802 type = "range",
803 min = 0,
804 max = 100000,
805 softMax = 100,
806 step = 1,
807 name = "Minimum local stock",
808 desc = "You can manually enter a value between 100 and 100.000 in the text box below if the provided range is insufficient.",
809 get = function() return self.db.profile.defaults.minLocalStock; end,
810 set = function(i, v) self.db.profile.defaults.minLocalStock = v; end,
811 },
812 alertBelowLocalMinimum = {
813 order = 11,
814 type = "toggle",
815 name = "Alert when below local minimum (NYI)",
816 desc = "Show an alert when this item gets below this threshold.",
817 get = function() return self.db.profile.defaults.alertBelowLocalMinimum; end,
818 set = function(i, v) self.db.profile.defaults.alertBelowLocalMinimum = v; end,
819 },
820 minGlobalStock = {
821 order = 20,
822 type = "range",
823 min = 0,
824 max = 100000,
825 softMax = 100,
826 step = 1,
827 name = "Minimum global stock",
828 desc = "You can manually enter a value between 100 and 100.000 in the text box below if the provided range is insufficient.",
829 get = function() return self.db.profile.defaults.minGlobalStock; end,
830 set = function(i, v) self.db.profile.defaults.minGlobalStock = v; end,
831 },
832 alertBelowGlobalMinimum = {
833 order = 21,
834 type = "toggle",
835 name = "Alert when below global minimum (NYI)",
836 desc = "Show an alert when this item gets below this threshold.",
837 get = function() return self.db.profile.defaults.alertBelowGlobalMinimum; end,
838 set = function(i, v) self.db.profile.defaults.alertBelowGlobalMinimum = v; end,
839 },
840 summaryThresholdShow = {
841 order = 30,
842 type = "range",
843 min = 0,
844 max = 10,
845 softMax = 100,
846 step = 0.05,
847 isPercent = true,
848 name = "Show in summary when below",
849 desc = "Show items in the summary when below this percentage of the minimum stock. This can be either below the minimum or the global stock.\n\nYou can manually enter a value between 1.000% and 10.000% in the edit box if the provided range is insufficient.",
850 get = function() return self.db.profile.defaults.summaryThresholdShow; end,
851 set = function(i, v) self.db.profile.defaults.summaryThresholdShow = v; end,
852 },
853 trackAtCharacters = {
854 order = 40,
855 type = "multiselect",
856 name = "Track at",
857 desc = "Select at which characters this should appear in the summary and generate alerts.",
858 values = function()
859 local temp = {};
860 for charName in pairs(self.db.factionrealm.characters) do
861 temp[charName] = charName;
862 end
863
864 return temp;
865 end,
866 get = function(i, v) return self.db.profile.defaults.trackAtCharacters[v]; end,
867 set = function(i, v, e) self.db.profile.defaults.trackAtCharacters[v] = e or nil; end,
868 --dialogControl = "Dropdown", -- this is not standard, normal multiselect control gives us a list of all chars with toggle-boxes. UGLY! We want a multiselect-box instead.
869 },
870 },
871 },
872 refill = {
873 order = 20,
874 type = "group",
875 inline = true,
876 name = "Replenishing stock",
877 args = {
878 description = {
879 order = 0,
880 type = "description",
881 name = function()
882 local r = "Here you can specify the default amount of items to which you wish to restock when you are collecting new items. This may be higher than the minimum stock. The settings entered here will be used when you choose not to override the settings within an individual group.\n\n";
883
884 r = r .. "When restocking the target amount is |cfffed000" .. self.db.profile.defaults.restockTarget .. "|r of every item. Not queueing craftable items when only missing |cfffed000" .. floor( self.db.profile.defaults.minCraftingQueue * self.db.profile.defaults.restockTarget ) .. "|r (|cfffed000" .. ( self.db.profile.defaults.minCraftingQueue * 100 ) .. "%|r) of the restock target.";
885
886 return r;
887 end,
888 },
889 header = {
890 order = 5,
891 type = "header",
892 name = "",
893 },
894 restockTarget = {
895 order = 10,
896 type = "range",
897 min = 0,
898 max = 100000,
899 softMax = 100,
900 step = 1,
901 name = "Restock target",
902 desc = "You can manually enter a value between 100 and 100.000 in the edit box if the provided range is insufficient.",
903 get = function() return self.db.profile.defaults.restockTarget; end,
904 set = function(i, v) self.db.profile.defaults.restockTarget = v; end,
905 },
906 minCraftingQueue = {
907 order = 20,
908 type = "range",
909 min = 0,
910 max = 1,
911 step = 0.01, -- 1%
912 isPercent = true,
913 name = "Don't queue if I only miss",
914 desc = "Don't add a craftable item to the queue if I only miss this much or less of the restock target.\n\nExample: if your restock target is set to 60 and this is set to 5%, an item won't be queued unless you are missing more than 3 of it.",
915 get = function() return self.db.profile.defaults.minCraftingQueue; end,
916 set = function(i, v) self.db.profile.defaults.minCraftingQueue = v; end,
917 },
918 bonusQueue = {
919 order = 30,
920 type = "range",
921 min = 0,
922 max = 10, -- 1000%
923 step = 0.01, -- 1%
924 isPercent = true,
925 name = "Bonus queue",
926 desc = "Get additional items when there are none left.\n\nExample: if your restock target is set to 60 and this is set to 10%, you will get 66 items instead of just 60 if you end up with none left while queueing.",
927 get = function() return self.db.profile.defaults.bonusQueue; end,
928 set = function(i, v) self.db.profile.defaults.bonusQueue = v; end,
929 },
930 priceThreshold = {
931 order = 40,
932 type = "input",
933 name = "Price threshold",
934 desc = "Only queue craftable items when they are worth at least this much according to your auction house addon.\n\nSet to 0 to ignore auction prices.",
935 validate = function(info, value) return self:ValidateReadableMoney(info, value); end,
936 get = function() return self:ReadableMoney(self.db.profile.defaults.priceThreshold); end,
937 set = function(i, v) self.db.profile.defaults.priceThreshold = self:ReadableMoneyToCopper(v); end,
938 },
939 summaryHidePriceThreshold = {
940 order = 50,
941 type = "toggle",
942 name = "Hide when below threshold",
943 desc = "Hide items from the summary when their value is below the set price threshold.",
944 get = function() return self.db.profile.defaults.summaryHidePriceThreshold; end,
945 set = function(i, v) self.db.profile.defaults.summaryHidePriceThreshold = v; end,
946 },
947 alwaysGetAuctionValue = {
948 order = 60,
949 type = "toggle",
950 name = "Always show auction value",
951 desc = "Always cache and show the auction value of items, even if the price threshold is set to 0|cffeda55fc|r.",
952 get = function() return self.db.profile.defaults.alwaysGetAuctionValue; end,
953 set = function(i, v) self.db.profile.defaults.alwaysGetAuctionValue = v; end,
954 },
955 },
956 },
957 colorCodes = {
958 order = 30,
959 type = "group",
960 inline = true,
961 name = "Color codes",
962 args = {
963 description = {
964 order = 0,
965 type = "description",
966 name = "Change the color code thresholds based on the current stock remaining of the required minimum stock.",
967 },
968 header = {
969 order = 5,
970 type = "header",
971 name = "",
972 },
973 green = {
974 order = 10,
975 type = "range",
976 min = 0,
977 max = 1,
978 step = 0.01,
979 isPercent = true,
980 name = "|cff00ff00Green|r",
981 desc = "Show quantity in green when at least this much of the minimum stock is available.",
982 get = function() return self.db.profile.defaults.colors.green; end,
983 set = function(i, v) self.db.profile.defaults.colors.green = v; end,
984 },
985 yellow = {
986 order = 20,
987 type = "range",
988 min = 0,
989 max = 1,
990 step = 0.01,
991 isPercent = true,
992 name = "|cffffff00Yellow|r",
993 desc = "Show quantity in yellow when at least this much of the minimum stock is available.",
994 get = function() return self.db.profile.defaults.colors.yellow; end,
995 set = function(i, v) self.db.profile.defaults.colors.yellow = v; end,
996 },
997 orange = {
998 order = 30,
999 type = "range",
1000 min = 0,
1001 max = 1,
1002 step = 0.01,
1003 isPercent = true,
1004 name = "|cffff9933Orange|r",
1005 desc = "Show quantity in orange when at least this much of the minimum stock is available.",
1006 get = function() return self.db.profile.defaults.colors.orange; end,
1007 set = function(i, v) self.db.profile.defaults.colors.orange = v; end,
1008 },
1009 red = {
1010 order = 40,
1011 type = "range",
1012 min = 0,
1013 max = 1,
1014 step = 0.01,
1015 isPercent = true,
1016 name = "|cffff0000Red|r",
1017 desc = "Show quantity in red when at least this much of the minimum stock is available.",
1018 get = function() return self.db.profile.defaults.colors.red; end,
1019 set = function(i, v) self.db.profile.defaults.colors.red = v; end,
1020 },
1021 },
1022 },
1023 },
1024 };
1025 end
1026
1027 local count = 0;
1028 local temp = {};
1029
1030 local function SetOption(info, value, multiSelectEnabled)
1031 local groupName = groupIdToName[info[2]];
1032 local optionName = info[#info];
1033
1034 -- Special treatment for override toggle boxes
1035 if optionName:find("override") then
1036 if not value and info.arg then
1037 -- If this override was disabled and a saved variable name was provided, set it to nil rather than false
1038
1039 value = nil;
1040
1041 -- If this is an override toggler then also set the related field to nil
1042 addon.db.profile.groups[groupName][info.arg] = nil;
1043 elseif value and info.arg then
1044 -- If this override is now enabled, we need to copy the default into this field (unless it is not nil (which is supposed to be impossible), in which case we'll use the already selected value)
1045
1046 addon.db.profile.groups[groupName][info.arg] = addon:GetOptionByKey(groupName, info.arg);
1047 end
1048 end
1049
1050 if multiSelectEnabled ~= nil then
1051 -- The saved vars for a multiselect will always be an array, it may not yet exist in which case it must be created.
1052 if not addon.db.profile.groups[groupName][optionName] then
1053 addon.db.profile.groups[groupName][optionName] = {};
1054 end
1055
1056 addon.db.profile.groups[groupName][optionName][value] = multiSelectEnabled or nil;
1057 else
1058 addon.db.profile.groups[groupName][optionName] = value;
1059 end
1060 end
1061
1062 function addon:GetOptionByKey(groupName, optionName, noDefault)
1063 if groupName and self.db.profile.groups[groupName] and self.db.profile.groups[groupName][optionName] ~= nil then
1064 -- If this option exists within the settings of this group
1065
1066 return self.db.profile.groups[groupName][optionName];
1067 elseif groupName and self.db.profile.groups[groupName] and self.db.profile.groups[groupName].virtualGroup ~= "" and not noDefault then
1068 -- If a virtual group was selected
1069
1070 return self:GetOptionByKey(self.db.profile.groups[groupName].virtualGroup, optionName, noDefault);
1071 elseif self.db.profile.defaults[optionName] and not noDefault then
1072 return self.db.profile.defaults[optionName];
1073 else
1074 return nil;
1075 end
1076 end
1077
1078 local function GetOption(info)
1079 local groupName = groupIdToName[info[2]];
1080 local optionName = info[#info];
1081
1082 local noDefault;
1083
1084 if optionName:find("override") then
1085 noDefault = true;
1086 end
1087
1088 return addon:GetOptionByKey(groupName, optionName, noDefault);
1089 end
1090
1091 local function GetMultiOption(info, value)
1092 local groupName = groupIdToName[info[2]];
1093 local optionName = info[#info];
1094
1095 if addon.db.profile.groups[groupName][optionName] ~= nil then
1096 return addon.db.profile.groups[groupName][optionName][value];
1097 elseif addon.db.profile.defaults[optionName] then
1098 return addon.db.profile.defaults[optionName][value];
1099 else
1100 return nil;
1101 end
1102 end
1103
1104 local function GetDisabled(info)
1105 local groupName = groupIdToName[info[2]];
1106 local optionName = info[#info];
1107
1108 if optionName:find("override") or not info.arg then
1109 return false;
1110 end
1111
1112 return (addon:GetOptionByKey(groupName, info.arg, true) == nil);
1113 end
1114
1115 local function ValidateGroupName(_, value)
1116 value = string.lower(string.trim(value or ""));
1117
1118 for name, _ in pairs(addon.db.profile.groups) do
1119 if string.lower(name) == value then
1120 return ("A group named \"%s\" already exists."):format(name);
1121 end
1122 end
1123
1124 return true;
1125 end
1126
1127 local tblAddItemTemplate = {
1128 order = 0,
1129 type = "input",
1130 name = function(info)
1131 local itemName, _, itemRarity = GetItemInfo(info[#info]);
1132 return tostring( 7 - (itemRarity or 0) ) .. (itemName or "");
1133 end,
1134 get = function(info)
1135 return tostring(info[#info]); -- Ace is going to be anal about this if it's a numeric value, so we transmute it into a string here then back to a number on the other side
1136 end,
1137 set = function(groupId, itemId)
1138 -- This is NOT a real "set", we pass the widget reference to this function which contains similar, but not the same, info.
1139
1140 if itemId then
1141 local groupName = groupIdToName[groupId];
1142
1143 if not AddToGroup(groupName, itemId) then
1144 print("|cffff0000Couldn't add the item with itemId (" .. itemId .. ") because it is already in a group.|r");
1145 end
1146 end
1147 end,
1148 width = "double",
1149 dialogControl = "ConfigItemLinkButton",
1150 };
1151
1152 local tblRemoveItemTemplate = {
1153 order = 0,
1154 type = "input",
1155 name = function(info)
1156 local itemName, _, itemRarity = GetItemInfo(info[#info]);
1157 return tostring( 7 - (itemRarity or 0) ) .. (itemName or "");
1158 end,
1159 get = function(info)
1160 return tostring(info[#info]); -- Ace is going to be anal about this if it's a numeric value, so we transmute it into a string here then back to a number on the other side
1161 end,
1162 set = function(groupId, itemId)
1163 -- This is NOT a real "set", we pass the widget reference to this function which contains similar, but not the same, info.
1164
1165 if itemId then
1166 local groupName = groupIdToName[groupId];
1167
1168 RemoveFromGroup(groupName, itemId);
1169
1170 -- Now rebuild the list
1171 AceConfigRegistry:NotifyChange("InventoriumOptions");
1172 end
1173 end,
1174 width = "double",
1175 dialogControl = "ConfigItemLinkButton",
1176 };
1177
1178 local function UpdateAddItemList(info)
1179 local groupName = groupIdToName[info[2]];
1180
1181 if not addon.db.profile.groups[groupName].items then
1182 addon.db.profile.groups[groupName].items = {};
1183 end
1184
1185 -- Merge all items from all groups together
1186 local items = {};
1187 for groupName, values in pairs(addon.db.profile.groups) do
1188 if values.items then
1189 for itemId, _ in pairs(values.items) do
1190 items[itemId] = true;
1191 end
1192 end
1193 end
1194
1195 local ref = options.args.groups.args[info[2]].args.add.args.list.args;
1196
1197 -- Remaking the list, so out with the old, in with the new
1198 table.wipe(ref);
1199
1200 -- Parse bags and show these
1201 for bagID = 4, 0, -1 do
1202 for slot = 1, GetContainerNumSlots(bagID) do
1203 local itemId = addon:GetItemId(GetContainerItemLink(bagID, slot));
1204
1205 if itemId then
1206 if not items[itemId] then
1207 -- If this item isn't used in any group yet
1208 ref[itemId] = tblAddItemTemplate;
1209 else
1210 -- It's already used in a group, don't show it
1211 ref[itemId] = nil;
1212 end
1213 end
1214 end
1215 end
1216
1217 if includeTradeSkillItems ~= 500 then
1218 -- Include tradeskill items
1219
1220 -- Go through all trade skills for the profession
1221 for i = 1, GetNumTradeSkills() do
1222 -- Try to retrieve the itemlink, this will be nil if current item is a group instead
1223 local itemLink = GetTradeSkillItemLink(i);
1224
1225 if itemLink then
1226 local itemId = addon:GetItemId(itemLink);
1227 if not itemId then
1228 -- If this isn't an item, it can only be an enchant instead
1229 itemId = tonumber(itemLink:match("|Henchant:([-0-9]+)|h"));
1230
1231 itemId = addon.scrollIds[itemId]; -- change enchantIds into scrollIds
1232 end
1233
1234 if itemId then
1235 local itemLevel = select(4, GetItemInfo(itemId)) or 0;
1236
1237 if includeTradeSkillItems == 0 or itemLevel >= includeTradeSkillItems then
1238 if not items[itemId] then
1239 -- If this item isn't used in any group yet
1240 ref[itemId] = tblAddItemTemplate;
1241 else
1242 -- It's already used in a group, don't show it
1243 ref[itemId] = nil;
1244 end
1245 end
1246 else
1247 addon:Debug("|cffff0000ERROR|r: Couldn't find proper item id for " .. itemLink);
1248 end
1249 end
1250 end
1251 end
1252 end
1253
1254 local function UpdateRemoveItemList(info)
1255 local groupName = groupIdToName[info[2]];
1256
1257 if not addon.db.profile.groups[groupName].items then
1258 addon.db.profile.groups[groupName].items = {};
1259 end
1260
1261 local ref = options.args.groups.args[info[2]].args.remove.args.list.args;
1262
1263 -- Unset all
1264 for itemId, _ in pairs(ref) do
1265 ref[itemId] = nil;
1266 end
1267
1268 -- Parse items in group and show these
1269 for itemId, _ in pairs(addon.db.profile.groups[groupName].items) do
1270 ref[itemId] = tblRemoveItemTemplate;
1271 end
1272 end
1273
1274 function addon:GetItemId(itemLink)
1275 itemLink = itemLink and itemLink:match("|Hitem:([-0-9]+):"); -- if itemLink is nil, it won't execute the second part
1276 itemLink = itemLink and tonumber(itemLink);
1277
1278 return itemLink;
1279 end
1280
1281 -- Default group
1282 local defaultGroup = {
1283 order = 0,
1284 type = "group",
1285 childGroups = "tab",
1286 name = function(info)
1287 local groupId = info[#info];
1288 if groupIsVirtual[groupId] then
1289 return ("%s |cfffed000Virtual|r"):format(groupIdToName[groupId]);
1290 else
1291 return groupIdToName[groupId];
1292 end
1293 end,
1294 desc = function(info)
1295 local groupId = info[#info];
1296 if groupIsVirtual[groupId] then
1297 return "This is a virtual group, you can use it to override the defaults for other groups.";
1298 end
1299 end,
1300 args = {
1301 general = {
1302 order = 10,
1303 type = "group",
1304 name = "General",
1305 desc = "Change the general settings for just this group.",
1306 args = {
1307 general = {
1308 order = 0,
1309 type = "group",
1310 inline = true,
1311 name = "General",
1312 set = SetOption,
1313 get = GetOption,
1314 disabled = GetDisabled,
1315 args = {
1316 description = {
1317 order = 0,
1318 type = "description",
1319 name = function(info)
1320 local groupName = groupIdToName[info[2]];
1321
1322 local t = "Here you can set general settings for the currently selected group. If you do not wish to override a setting, the default setting specified in the general group will be used.\n\n";
1323
1324 local currentAddon, selectedAddonName = addon:GetItemCountAddon(groupName);
1325 local preferedAddon = addon:GetOptionByKey(groupName, "itemCountAddon");
1326
1327 if currentAddon then
1328 --GetCharacterCount
1329 --self.supportedAddons.itemCount[selectedExternalAddon]
1330 t = t .. "Currently using |cfffed000" .. selectedAddonName .. "|r as your item count addon. This addon is " .. ((currentAddon.IsEnabled() and "|cff00ff00enabled|r") or "|cffff0000disabled|r") .. ".";
1331
1332 if currentAddon.GetTotalCount and currentAddon.GetCharacterCount then
1333 t = t .. " This addon supports |cfffed000both total as local|r item counts.";
1334 elseif currentAddon.GetTotalCount then
1335 t = t .. " This addon supports |cfffed000only total|r item counts.";
1336 elseif currentAddon.GetCharacterCount then
1337 t = t .. " This addon supports |cfffed000only local|r item counts.";
1338 end
1339
1340 if preferedAddon ~= selectedAddonName then
1341 t = t .. "\n\n|cffff0000You have selected |cfffed000" .. preferedAddon .. "|r|cffff0000 as your item count addon, but this appears to be disabled and thus a random alternative was selected.|r";
1342 end
1343 end
1344
1345 return t;
1346 end,
1347 },
1348 header = {
1349 order = 5,
1350 type = "header",
1351 name = "",
1352 },
1353 overrideAuctionPricingAddon = {
1354 order = 9,
1355 type = "toggle",
1356 name = "Override pricing addon",
1357 desc = "Allows you to override the pricing addon setting for this group.",
1358 arg = "auctionPricingAddon",
1359 },
1360 auctionPricingAddon = {
1361 order = 10,
1362 type = "select",
1363 name = "Prefered pricing addon",
1364 desc = "Select the addon you prefer data for this group to be retrieved from. A random supported addon will be used if the selected addon can not be found.",
1365 values = function()
1366 local temp = {};
1367 for name, value in pairs(addon.supportedAddons.auctionPricing) do
1368 temp[name] = name;
1369 end
1370
1371 return temp;
1372 end,
1373 set = function(info, value)
1374 local groupName = groupIdToName[info[2]];
1375 local optionName = info[#info];
1376
1377 addon.db.profile.groups[groupName][optionName] = value ~= "" and value;
1378
1379 if addon.supportedAddons.auctionPricing[value].OnSelect then
1380 addon.supportedAddons.auctionPricing[value].OnSelect();
1381 end
1382 end,
1383 arg = "overrideAuctionPricingAddon",
1384 },
1385 overrideItemCountAddon = {
1386 order = 19,
1387 type = "toggle",
1388 name = "Override item count addon",
1389 desc = "Allows you to override the item count addon setting for this group.",
1390 arg = "itemCountAddon",
1391 },
1392 itemCountAddon = {
1393 order = 20,
1394 type = "select",
1395 name = "Prefered item count addon",
1396 desc = "Select the addon you prefer data for this group to be retrieved from. A random supported addon will be used if the selected addon can not be found.",
1397 values = function()
1398 local temp = {};
1399 for name, value in pairs(addon.supportedAddons.itemCount) do
1400 temp[name] = name;
1401 end
1402
1403 return temp;
1404 end,
1405 set = function(info, value)
1406 local groupName = groupIdToName[info[2]];
1407 local optionName = info[#info];
1408
1409 addon.db.profile.groups[groupName][optionName] = value ~= "" and value;
1410
1411 if addon.supportedAddons.itemCount[value].OnSelect then
1412 addon.supportedAddons.itemCount[value].OnSelect();
1413 end
1414 end,
1415 arg = "overrideItemCountAddon",
1416 },
1417 overrideCraftingAddon = {
1418 order = 29,
1419 type = "toggle",
1420 name = "Override crafting addon",
1421 desc = "Allows you to override the crafting addon setting for this group.",
1422 arg = "craftingAddon",
1423 },
1424 craftingAddon = {
1425 order = 30,
1426 type = "select",
1427 name = "Prefered crafting addon",
1428 desc = "Select the addon you prefer data from this group to be queued into. A random supported addon will be used if the selected addon can not be found.",
1429 values = function()
1430 local temp = {};
1431 for name, value in pairs(addon.supportedAddons.crafting) do
1432 temp[name] = name;
1433 end
1434
1435 return temp;
1436 end,
1437 set = function(info, value)
1438 local groupName = groupIdToName[info[2]];
1439 local optionName = info[#info];
1440
1441 addon.db.profile.groups[groupName][optionName] = value ~= "" and value;
1442
1443 if addon.supportedAddons.crafting[value].OnSelect then
1444 addon.supportedAddons.crafting[value].OnSelect();
1445 end
1446 end,
1447 arg = "overrideCraftingAddon",
1448 },
1449 overrideLocalItemData = {
1450 order = 39,
1451 type = "toggle",
1452 name = "Override local item data",
1453 desc = "Allows you to override the local item data setting for this group.",
1454 arg = "localItemData",
1455 },
1456 localItemData = {
1457 order = 40,
1458 type = "multiselect",
1459 name = "Include in local item data",
1460 desc = "Select which data should be included in the local item data.",
1461 values = {
1462 ["Bag"] = "Bag",
1463 ["Bank"] = "Bank",
1464 ["Auction House"] = "Auction House",
1465 ["Mailbox"] = "Mailbox",
1466 },
1467 get = GetMultiOption,
1468 --dialogControl = "Dropdown", -- this is not standard, normal multiselect control gives us a list of all chars with toggle-boxes. UGLY! We want a multiselect-box instead.
1469 arg = "overrideLocalItemData",
1470 },
1471 virtualGroup = {
1472 order = 50,
1473 type = "select",
1474 name = "Use virtual group settings",
1475 desc = "Use the settings from a virtual group before using the general defaults.\n\n|cffff9933This is an advanced option, you will probably not need it unless you manage a lot of groups.|r\n\n|cfffed000Off|r: Use the overridden options in this group and then the defaults.\n\n|cfffed000On|r: Use the overridden options in this group, then the ones in the selected virtual group and then the defaults.",
1476 values = function(info)
1477 local groupName = groupIdToName[info[2]];
1478
1479 local temp = {};
1480
1481 temp[""] = "";
1482 for name, values in pairs(addon.db.profile.groups) do
1483 if values.isVirtual and name ~= groupName then
1484 temp[name] = name;
1485 end
1486 end
1487
1488 return temp;
1489 end,
1490 set = function(info, value)
1491 local groupName = groupIdToName[info[2]];
1492 local optionName = info[#info];
1493
1494 addon.db.profile.groups[groupName][optionName] = value ~= "" and value;
1495 end,
1496 disabled = false,
1497 },
1498 },
1499 },
1500 minimumStock = {
1501 order = 10,
1502 type = "group",
1503 inline = true,
1504 name = "Minimum stock",
1505 set = SetOption,
1506 get = GetOption,
1507 disabled = GetDisabled,
1508 args = {
1509 description = {
1510 order = 0,
1511 type = "description",
1512 name = "Here you can specify the minimum amount of items you wish to keep in stock and related settings for the currently selected group. Please note the values entered here do not affect the queued quantities, you must set settings for that in the area below.",
1513 },
1514 header = {
1515 order = 5,
1516 type = "header",
1517 name = "",
1518 },
1519
1520 overrideMinLocalStock = {
1521 order = 10,
1522 type = "toggle",
1523 name = "Override min local stock",
1524 desc = "Allows you to override the minimum local stock setting for this group.",
1525 arg = "minLocalStock",
1526 },
1527 minLocalStock = {
1528 order = 11,
1529 type = "range",
1530 min = 0,
1531 max = 100000,
1532 softMax = 100,
1533 step = 1,
1534 name = "Minimum local stock",
1535 desc = "You can manually enter a value between 100 and 100.000 in the text box below if the provided range is insufficient.",
1536 arg = "overrideMinLocalStock",
1537 },
1538 overrideAlertBelowLocalMinimum = {
1539 order = 15,
1540 type = "toggle",
1541 name = "Override local minimum alert",
1542 desc = "Allows you to override wether an alert should be shown when an item in this group gets below the local minimum stock threshold.",
1543 arg = "alertBelowLocalMinimum",
1544 },
1545 alertBelowLocalMinimum = {
1546 order = 16,
1547 type = "toggle",
1548 name = "Alert when below local minimum (NYI)",
1549 desc = "Show an alert when an item in this group gets below the local minimum stock threshold.",
1550 arg = "overrideAlertBelowLocalMinimum",
1551 },
1552
1553 overrideMinGlobalStock = {
1554 order = 20,
1555 type = "toggle",
1556 name = "Override min global stock",
1557 desc = "Allows you to override the minimum global stock setting for this group.",
1558 arg = "minGlobalStock",
1559 },
1560 minGlobalStock = {
1561 order = 21,
1562 type = "range",
1563 min = 0,
1564 max = 100000,
1565 softMax = 100,
1566 step = 1,
1567 name = "Minimum global stock",
1568 desc = "You can manually enter a value between 100 and 100.000 in the text box below if the provided range is insufficient.",
1569 arg = "overrideMinGlobalStock",
1570 },
1571 overrideAlertBelowGlobalMinimum = {
1572 order = 25,
1573 type = "toggle",
1574 name = "Override global minimum alert",
1575 desc = "Allows you to override wether an alert should be shown when an item in this group gets below the global minimum stock threshold.",
1576 arg = "alertBelowGlobalMinimum",
1577 },
1578 alertBelowGlobalMinimum = {
1579 order = 26,
1580 type = "toggle",
1581 name = "Alert when below global minimum (NYI)",
1582 desc = "Show an alert when an item in this group gets below the global minimum stock threshold.",
1583 arg = "overrideAlertBelowGlobalMinimum",
1584 },
1585
1586 overrideSummaryThresholdShow = {
1587 order = 34,
1588 type = "toggle",
1589 name = "Override summary showing",
1590 desc = "Allows you to override when this group should appear in the summary.",
1591 arg = "summaryThresholdShow",
1592 },
1593 summaryThresholdShow = {
1594 order = 35,
1595 type = "range",
1596 min = 0,
1597 max = 10,
1598 softMax = 100,
1599 step = 0.05,
1600 isPercent = true,
1601 name = "Show in summary when below",
1602 desc = "Show items in the summary when below the specified percentage of the minimum stock.\n\nYou can manually enter a value between 1.000% and 10.000% in the edit box if the provided range is insufficient.",
1603 arg = "overrideSummaryThresholdShow",
1604 },
1605 overrideTrackAtCharacters = {
1606 order = 39,
1607 type = "toggle",
1608 name = "Override track at",
1609 desc = "Allows you to override at which characters items in this group should appear in the summary and generate alerts.",
1610 arg = "trackAtCharacters",
1611 },
1612 trackAtCharacters = {
1613 order = 40,
1614 type = "multiselect",
1615 name = "Track at",
1616 desc = "Select at which characters this should appear in the summary and generate alerts.",
1617 values = function()
1618 local temp = {};
1619 for charName in pairs(addon.db.factionrealm.characters) do
1620 temp[charName] = charName;
1621 end
1622
1623 return temp;
1624 end,
1625 get = GetMultiOption,
1626 --dialogControl = "Dropdown", -- this is not standard, normal multiselect control gives us a list of all chars with toggle-boxes. UGLY! We want a multiselect-box instead.
1627 arg = "overrideTrackAtCharacters",
1628 },
1629 },
1630 },
1631 refill = {
1632 order = 20,
1633 type = "group",
1634 inline = true,
1635 name = "Replenishing stock",
1636 set = SetOption,
1637 get = GetOption,
1638 disabled = GetDisabled,
1639 args = {
1640 description = {
1641 order = 0,
1642 type = "description",
1643 name = function(info)
1644 local groupName = groupIdToName[info[2]];
1645 local r = "Here you can specify the amount of items to which you wish to restock when you are collecting new items for the currently selected group. This may be higher than the minimum stock.\n\n";
1646
1647 r = r .. "When restocking the target amount is |cfffed000" .. addon:GetOptionByKey(groupName, "restockTarget") .. "|r of every item. Not queueing craftable items when only missing |cfffed000" .. floor( addon:GetOptionByKey(groupName, "minCraftingQueue") * addon:GetOptionByKey(groupName, "restockTarget") ) .. "|r (|cfffed000" .. ( addon:GetOptionByKey(groupName, "minCraftingQueue") * 100 ) .. "%|r) of the restock target and making |cfffed000" .. floor( ( addon:GetOptionByKey(groupName, "bonusQueue") * addon:GetOptionByKey(groupName, "restockTarget") ) + .5 ) .. "|r (|cfffed000" .. ( addon:GetOptionByKey(groupName, "bonusQueue") * 100 ) .. "%|r) extra items when you completely ran out. ";
1648
1649 if addon:GetOptionByKey(groupName, "priceThreshold") == 0 then
1650 r = r .. "Queueing items at |cfffed000any|r auction value.";
1651 else
1652 r = r .. "Queueing items worth |cfffed000" .. addon:ReadableMoney(addon:GetOptionByKey(groupName, "priceThreshold")) .. "|r or more.";
1653 end
1654
1655 return r;
1656 end,
1657 },
1658 header = {
1659 order = 5,
1660 type = "header",
1661 name = "",
1662 },
1663 overrideRestockTarget = {
1664 order = 9,
1665 type = "toggle",
1666 name = "Override restock target",
1667 desc = "Allows you to override the restock target setting for this group.",
1668 arg = "restockTarget",
1669 },
1670 restockTarget = {
1671 order = 10,
1672 type = "range",
1673 min = 0,
1674 max = 100000,
1675 softMax = 100,
1676 step = 1,
1677 name = "Restock target",
1678 desc = "You can manually enter a value between 100 and 100.000 in the edit box if the provided range is insufficient.",
1679 arg = "overrideRestockTarget",
1680 },
1681 overrideMinCraftingQueue = {
1682 order = 19,
1683 type = "toggle",
1684 name = "Override min queue",
1685 desc = "Allows you to override the minimum craftable items queue setting for this group.",
1686 arg = "minCraftingQueue",
1687 },
1688 minCraftingQueue = {
1689 order = 20,
1690 type = "range",
1691 min = 0,
1692 max = 1,
1693 step = 0.01,
1694 isPercent = true,
1695 name = "Don't queue if I only miss",
1696 desc = "Don't add a craftable item to the queue if I only miss this much or less of the restock target.\n\nExample: if your restock target is set to 60 and this is set to 5%, an item won't be queued unless you are missing more than 3 of it.",
1697 arg = "overrideMinCraftingQueue",
1698 },
1699 overrideBonusQueue = {
1700 order = 29,
1701 type = "toggle",
1702 name = "Override bonus queue",
1703 desc = "Allows you to override the bonus craftable items queue setting for this group.",
1704 arg = "bonusQueue",
1705 },
1706 bonusQueue = {
1707 order = 30,
1708 type = "range",
1709 min = 0,
1710 max = 10, -- 1000%
1711 step = 0.01, -- 1%
1712 isPercent = true,
1713 name = "Bonus queue",
1714 desc = "Get additional items when there are none left.\n\nExample: if your restock target is set to 60 and this is set to 10%, you will get 66 items instead of just 60 if you end up with none left while queueing.",
1715 arg = "overrideBonusQueue",
1716 },
1717 overridePriceThreshold = {
1718 order = 39,
1719 type = "toggle",
1720 name = "Override price threshold",
1721 desc = "Allows you to override the price threshold setting for this group.",
1722 arg = "priceThreshold",
1723 },
1724 priceThreshold = {
1725 order = 40,
1726 type = "input",
1727 name = "Price threshold",
1728 desc = "Only queue craftable items when they are worth at least this much according to your auction house addon.\n\nSet to 0 to ignore auction prices.",
1729 validate = function(info, value) return addon:ValidateReadableMoney(info, value); end,
1730 get = function(i) return addon:ReadableMoney(GetOption(i)); end,
1731 set = function(i, v) SetOption(i, addon:ReadableMoneyToCopper(v)); end,
1732 arg = "overridePriceThreshold",
1733 },
1734 overrideSummaryHidePriceThreshold = {
1735 order = 49,
1736 type = "toggle",
1737 name = "Override summary showing",
1738 desc = "Allows you to override if items in this group should be hidden from the summary while their value is below the price threshold.",
1739 arg = "summaryHidePriceThreshold",
1740 },
1741 summaryHidePriceThreshold = {
1742 order = 50,
1743 type = "toggle",
1744 name = "Hide when below threshold",
1745 desc = "Hide items from the summary when their value is below the set price threshold.",
1746 arg = "overrideSummaryHidePriceThreshold",
1747 },
1748 overrideAlwaysGetAuctionValue = {
1749 order = 59,
1750 type = "toggle",
1751 name = "Override auction value showing",
1752 desc = "Allows you to override if the auction value of items in this group should be cached and displayed even when the price threshold is set to 0|cffeda55fc|r.",
1753 arg = "alwaysGetAuctionValue",
1754 },
1755 alwaysGetAuctionValue = {
1756 order = 60,
1757 type = "toggle",
1758 name = "Always show auction value",
1759 desc = "Always cache and show the auction value of items in this group, even if the price threshold is set to 0|cffeda55fc|r.",
1760 arg = "overrideAlwaysGetAuctionValue",
1761 },
1762 },
1763 },
1764 },
1765 },
1766 group = {
1767 order = 20,
1768 type = "group",
1769 name = "Management",
1770 desc = "Rename, delete, duplicate or export this group.",
1771 args = {
1772 actions = {
1773 order = 10,
1774 type = "group",
1775 name = "Actions",
1776 inline = true,
1777 args = {
1778 rename = {
1779 order = 10,
1780 type = "input",
1781 name = "Rename group - New name",
1782 desc = "Change the name of this group to something else. You can also use item links here as you wish.",
1783 validate = ValidateGroupName,
1784 set = function(info, value)
1785 local oldGroupName = groupIdToName[info[2]];
1786
1787 addon.db.profile.groups[value] = CopyTable(addon.db.profile.groups[oldGroupName]);
1788 addon.db.profile.groups[oldGroupName] = nil;
1789
1790 groupIdToName[info[2]] = value;
1791 groupIdToName[value] = true;
1792 groupIdToName[oldGroupName] = nil;
1793
1794 addon:FillGroupOptions();
1795 end,
1796 get = function(info)
1797 return groupIdToName[info[2]];
1798 end,
1799 },
1800 duplicate = {
1801 order = 20,
1802 type = "input",
1803 name = "Duplicate group - New name",
1804 desc = "Duplicate this group. You can also use item links here as you wish.\n\nAll item data will be erased.",
1805 validate = ValidateGroupName,
1806 set = function(info, value)
1807 local oldGroupName = groupIdToName[info[2]];
1808
1809 addon.db.profile.groups[value] = CopyTable(addon.db.profile.groups[oldGroupName]);
1810
1811 -- Reset item data (duplicate items me no want)
1812 addon.db.profile.groups[value].items = nil;
1813
1814 addon:FillGroupOptions();
1815 end,
1816 get = false,
1817 },
1818 delete = {
1819 order = 30,
1820 type = "execute",
1821 name = "Delete group",
1822 desc = "Delete the currently selected group.",
1823 confirm = true,
1824 confirmText = "Are you sure you wish to |cffff0000DELETE|r this group? This action is not reversable!",
1825 func = function(info)
1826 local groupName = groupIdToName[info[2]];
1827
1828 addon.db.profile.groups[groupName] = nil;
1829
1830 addon:FillGroupOptions();
1831 end,
1832 },
1833 },
1834 },
1835 export = {
1836 order = 40,
1837 type = "group",
1838 name = "Export",
1839 inline = true,
1840 args = {
1841 input = {
1842 order = 10,
1843 type = "input",
1844 multiline = true,
1845 name = "Group data",
1846 width = "full",
1847 desc = "Export the group data for the currently selected group. Press CTRL-A to select all and CTRL-C to copy the text.",
1848 set = false,
1849 get = function(info)
1850 local groupName = groupIdToName[info[2]];
1851
1852 -- We want to include the group name, so we copy the table then set another value
1853 local temp = CopyTable(addon.db.profile.groups[groupName]);
1854 temp.name = groupName;
1855 temp.trackAtCharacters = nil;
1856 temp.overrideTrackAtCharacters = nil;
1857
1858 if not AceSerializer then
1859 AceSerializer = LibStub("AceSerializer-3.0");
1860 end
1861
1862 return AceSerializer:Serialize(temp);
1863 end,
1864 },
1865 },
1866 },
1867 },
1868 },
1869 add = {
1870 order = 30,
1871 type = "group",
1872 name = "Add items",
1873 desc = "Add new items to this group.",
1874 hidden = function(info) return groupIsVirtual[info[2]]; end,
1875 args = {
1876 singleAdd = {
1877 order = 10,
1878 type = "group",
1879 inline = true,
1880 name = "Add items",
1881 args = {
1882 help = {
1883 order = 10,
1884 type = "description",
1885 name = "You can add a single item to this group at a time by pasting the item-id or an item-link in the field to the left or you can also import multiple items at once by pasting exported item data in the field to the right. Scroll further down to add items based on your inventory contents.",
1886 },
1887 itemLink = {
1888 order = 20,
1889 type = "input",
1890 name = "Single item add (item-link or item-id)",
1891 desc = "Shift-click an item-link or enter an item-id to add the related item to this group. You can only add one item link or item id at a time.",
1892 validate = function(info, value)
1893 -- If the value is empty we'll allow passing to clear the carret
1894 if value == "" then return true; end
1895
1896 local groupName = groupIdToName[info[2]];
1897
1898 local itemId = addon:GetItemId(string.trim(value or "")) or tonumber(string.trim(value or ""));
1899
1900 if not itemId then
1901 return "This is not a valid item link.";
1902 elseif InGroup(itemId) then
1903 return ("This item is already in the group \"%s\"."):format(InGroup(itemId));
1904 end
1905
1906 return true;
1907 end,
1908 set = function(info, value)
1909 if value and value ~= "" then
1910 local groupName = groupIdToName[info[2]];
1911
1912 local itemId = addon:GetItemId(string.trim(value or "")) or tonumber(string.trim(value or ""));
1913
1914 AddToGroup(groupName, itemId);
1915
1916 print(("Added %s"):format(select(2, GetItemInfo(itemId)) or ("Unknown (#%d)"):format(itemId)));
1917 end
1918 end,
1919 get = false,
1920 },
1921 importItemData = {
1922 order = 30,
1923 type = "input",
1924 name = "Import item data",
1925 desc = "Import item data from an exported item data-string. Any items already grouped will be skipped.",
1926 set = function(info, value)
1927 local groupName = groupIdToName[info[2]];
1928
1929 local allItemIds = { string.split(";", value or "") };
1930
1931 for _, value in pairs(allItemIds) do
1932 local itemId = tonumber(value);
1933
1934 if not itemId then
1935 print(("\"%s\" is not a number."):format(value));
1936 elseif InGroup(itemId) then
1937 print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId)));
1938 else
1939 AddToGroup(groupName, itemId);
1940 end
1941 end
1942 end,
1943 get = false,
1944 },
1945 importPremadeData = {
1946 order = 40,
1947 type = "select",
1948 name = "Import premade data",
1949 desc = "Import item data from a premade item-group. Any items already grouped will be skipped.",
1950 values = function()
1951 local temp = {};
1952 for key, group in pairs(addon.defaultGroups) do
1953 temp[key] = key;
1954 end
1955
1956 return temp;
1957 end,
1958 set = function(info, value)
1959 local groupName = groupIdToName[info[2]];
1960
1961 print(("Importing items from the premade group \"|cfffed000%s|r\"."):format(value));
1962
1963 -- Remember we imported this group and it's version so if it is ever changed, people can be notified
1964 if not addon.db.profile.groups[groupName].premadeGroups then
1965 addon.db.profile.groups[groupName].premadeGroups = {};
1966 end
1967 addon.db.profile.groups[groupName].premadeGroups[value] = addon.defaultGroups[value].version;
1968
1969 for itemId, version in pairs(addon.defaultGroups[value].items) do
1970 if version > 0 then
1971 itemId = itemId and tonumber(itemId);
1972
1973 if not itemId then
1974 print(("\"|cfffed000%s|r\" is not a number."):format(value));
1975 elseif InGroup(itemId) then
1976 print(("|cffff0000Skipping|r |cfffed000%s|r (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId)));
1977 else
1978 AddToGroup(groupName, itemId);
1979 print(("|cff00ff00Added|r |cfffed000%s|r (#%d) to the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, groupName));
1980 end
1981 end
1982 end
1983 end,
1984 get = false,
1985 },
1986 },
1987 },
1988 massAdd = {
1989 order = 20,
1990 type = "group",
1991 inline = true,
1992 name = "Mass add",
1993 args = {
1994 help = {
1995 order = 10,
1996 type = "description",
1997 name = "Click the items you wish to add to this group or add multiple of these items at once by providing a name filter in the field below.",
1998 },
1999 massAdd = {
2000 order = 20,
2001 type = "input",
2002 name = "Add all items matching...",
2003 desc = "Add every item in your inventory matching the name entered in this field. If you enter \"Glyph\" as a filter, any items in your inventory containing this in their name will be added to this group.",
2004 set = function(info, value)
2005 local groupName = groupIdToName[info[2]];
2006
2007 if not value then return; end
2008
2009 value = value:lower();
2010
2011 local ref = options.args.groups.args[info[2]].args.add.args.list.args;
2012
2013 for itemId, test in pairs(ref) do
2014 if test then
2015 local itemName = GetItemInfo(itemId);
2016
2017 if itemName:lower():find(value) then
2018 if not AddToGroup(groupName, itemId) then
2019 print("|cffff0000Couldn't add the item with itemId (" .. itemId .. ") because it is already in a group.|r");
2020 end
2021 end
2022 end
2023 end
2024 end,
2025 get = false,
2026 },
2027 minItemLevel = {
2028 order = 40,
2029 type = "select",
2030 values = function()
2031 local temp = {};
2032
2033 temp[0] = "Include everything";
2034
2035 local itemLevelTemplate = "Itemlevel >= %d";
2036
2037 for i = 1, 49 do
2038 temp[( i * 10 )] = itemLevelTemplate:format(( i * 10 ));
2039 end
2040
2041 temp[500] = "Include nothing";
2042
2043 return temp;
2044 end,
2045 name = "Include tradeskill items",
2046 desc = "Include all items above this item level from the currently opened tradeskill window in the below item list.\n\nSetting this very low this might considerably slow down this config window.\n\nSet to 500 to disable showing of items completely.",
2047 set = function(i, v) includeTradeSkillItems = v; end,
2048 get = function() return includeTradeSkillItems; end,
2049 disabled = function()
2050 if GetTradeSkillLine() == "UNKNOWN" then
2051 includeTradeSkillItems = 500;
2052 return true; -- disabled
2053 else
2054 return false;
2055 end
2056 end,
2057 },
2058 },
2059 },
2060 list = {
2061 order = 30,
2062 type = "group",
2063 inline = true,
2064 name = "Item list",
2065 hidden = UpdateAddItemList,
2066 args = {
2067
2068 },
2069 },
2070 },
2071 },
2072 remove = {
2073 order = 40,
2074 type = "group",
2075 name = "Current items",
2076 desc = "View, export or remove items from this group.",
2077 hidden = function(info) return groupIsVirtual[info[2]]; end,
2078 args = {
2079 help = {
2080 order = 10,
2081 type = "group",
2082 inline = true,
2083 name = "Help",
2084 hidden = false,
2085 args = {
2086 help = {
2087 order = 10,
2088 type = "description",
2089 name = "Click the items you wish to remove from this group.",
2090 },
2091 massRemove = {
2092 order = 20,
2093 type = "input",
2094 name = "Remove all items matching...",
2095 desc = "Remove every item in this group matching the name entered in this field. If you enter \"Glyph\" as a filter, any items in this group containing this in their name will be removed from this group.",
2096 set = function(info, value)
2097 local groupName = groupIdToName[info[2]];
2098
2099 if not value then return; end
2100
2101 value = value:lower();
2102
2103 local ref = options.args.groups.args[info[2]].args.remove.args.list.args;
2104
2105 for itemId, test in pairs(ref) do
2106 if test then
2107 local itemName = GetItemInfo(itemId);
2108
2109 if itemName:lower():find(value) then
2110 RemoveFromGroup(groupName, itemId);
2111 print(("|cffff0000Removed|r %s (#%d)."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId));
2112 end
2113 end
2114 end
2115
2116 -- Now rebuild the list
2117 AceConfigRegistry:NotifyChange("InventoriumOptions");
2118 end,
2119 get = false,
2120 },
2121 premadeGroups = {
2122 order = 30,
2123 type = "select",
2124 name = "Imported premade groups",
2125 desc = "This is a list of all premade groups that were imported into this group. You will be notified when any of these premade groups have changed and you will be able to import these changes.\n\nSelect a group to stop reminding you of changes to the premade group (the item list will be unaffected). Doing so will require you to manually update this when new items are added to the game.",
2126 values = function(info)
2127 local groupName = groupIdToName[info[2]];
2128
2129 local temp = {};
2130 if addon.db.profile.groups[groupName].premadeGroups then
2131 for name, version in pairs(addon.db.profile.groups[groupName].premadeGroups) do
2132 temp[name] = name;
2133 end
2134 end
2135
2136 return temp;
2137 end,
2138 set = function(info, value)
2139 -- Remove premade group from this group
2140 local groupName = groupIdToName[info[2]];
2141
2142 addon.db.profile.groups[groupName].premadeGroups[value] = nil;
2143
2144 print(("No longer notifying you about changes made to the premade group named \"|cfffed000%s|r\"."):format(value));
2145 end,
2146 get = false,
2147 disabled = function(info)
2148 local groupName = groupIdToName[info[2]];
2149
2150 return (not addon.db.profile.groups[groupName].premadeGroups);
2151 end,
2152 },
2153 },
2154 },
2155 list = {
2156 order = 20,
2157 type = "group",
2158 inline = true,
2159 name = "Item list",
2160 hidden = UpdateRemoveItemList,
2161 args = {
2162
2163 },
2164 },
2165 export = {
2166 order = 30,
2167 type = "group",
2168 name = "Export",
2169 inline = true,
2170 args = {
2171 input = {
2172 order = 10,
2173 type = "input",
2174 name = "Item data",
2175 width = "full",
2176 desc = "Export the item data for the currently selected group. Press CTRL-A to select all and CTRL-C to copy the text.",
2177 set = false,
2178 get = function(info)
2179 local groupName = groupIdToName[info[2]];
2180
2181 local combinedItemIds;
2182 -- Parse items in group and show these
2183 for itemId, _ in pairs(addon.db.profile.groups[groupName].items) do
2184 if not combinedItemIds then
2185 combinedItemIds = tostring(itemId);
2186 else
2187 combinedItemIds = combinedItemIds .. (";%d"):format(itemId);
2188 end
2189 end
2190
2191 return combinedItemIds; -- We don't serialize this because we actually DO want people to be able to manually modify it - besides, parsing it isn't going to be hard
2192 end,
2193 },
2194 },
2195 },
2196 },
2197 },
2198 },
2199 };
2200
2201 local currentGroupType = "Normal";
2202 function addon:MakeGroupOptions()
2203 options.args.groups = {
2204 order = 1100,
2205 type = "group",
2206 name = "Groups",
2207 desc = "Change a group.",
2208 args = {
2209 create = {
2210 order = 10,
2211 type = "group",
2212 inline = true,
2213 name = "Create a brand new group",
2214 args = {
2215 name = {
2216 order = 10,
2217 type = "input",
2218 name = "Group name",
2219 desc = "The name of the group. You can also use item links as you wish.",
2220 validate = ValidateGroupName,
2221 set = function(_, value)
2222 self.db.profile.groups[value] = {};
2223 if currentGroupType == "Virtual" then
2224 self.db.profile.groups[value].isVirtual = true;
2225 end
2226
2227 addon:FillGroupOptions();
2228 end,
2229 get = false,
2230 width = "double",
2231 },
2232 type = {
2233 order = 20,
2234 type = "select",
2235 name = "Type (advanced)",
2236 desc = "The type of the new group. This can not be changed at a later time.\n\n|cffff9933This is an advanced option, you will probably not need it unless you manage a lot of groups.|r\n\n|cfffed000Normal|r: A normal group with complete functionality.\n\n|cfffed000Virtual|r: A virtual group which you can use to override the defaults for a set of groups. You can not add items to virtual groups.",
2237 values = {
2238 ["Normal"] = "Normal",
2239 ["Virtual"] = "Virtual",
2240 },
2241 set = function(_, value) currentGroupType = value; end,
2242 get = function() return currentGroupType; end,
2243 },
2244 },
2245 },
2246 import = {
2247 order = 20,
2248 type = "group",
2249 inline = true,
2250 name = "Import a group",
2251 args = {
2252 input = {
2253 order = 10,
2254 type = "input",
2255 multiline = true,
2256 name = "Group data",
2257 desc = "Paste the group data as provided by a group export. If you are trying to import multiple groups at the same time, make sure to use newlines to seperate them.",
2258 set = function(info, value)
2259 local data = { string.split("\n", value or "") };
2260
2261 for _, current in pairs(data) do
2262 if not AceSerializer then
2263 AceSerializer = LibStub("AceSerializer-3.0");
2264 end
2265
2266 local result, temp = AceSerializer:Deserialize(current);
2267
2268 if not temp.name then
2269 print("|cffff0000The provided data is not supported.|r");
2270 elseif ValidateGroupName(nil, temp.name) ~= true then
2271 print(("|cffff0000Aborting: A group named \"%s\" already exists.|r"):format(temp.name));
2272 else
2273 local name = temp.name;
2274 temp.name = nil;
2275 print(("Importing %s..."):format(name));
2276
2277 if temp.items then
2278 -- Remove items that are already in another group
2279 for value, _ in pairs(temp.items) do
2280 local itemId = tonumber(value);
2281
2282 if not itemId then
2283 print(("\"%s\" is not a number."):format(value));
2284 temp.items[value] = nil;
2285 elseif InGroup(itemId) then
2286 print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId)));
2287 temp.items[value] = nil;
2288 else
2289 -- Ensure the keys are numeric
2290 temp.items[value] = nil;
2291 temp.items[itemId] = true;
2292 end
2293 end
2294 end
2295
2296 -- Ensure this data isn't received (this would be silly/buggy as exports from other accounts - with different characters - won't know what to do with this)
2297 temp.trackAtCharacters = nil;
2298 temp.overrideTrackAtCharacters = nil;
2299
2300 self.db.profile.groups[name] = temp;
2301 end
2302 end
2303
2304 self:FillGroupOptions();
2305 end,
2306 get = false,
2307 width = "full",
2308 },
2309 },
2310 },
2311 },
2312 };
2313 end
2314
2315 function addon:FillGroupOptions()
2316 for id, name in pairs(groupIdToName) do
2317 if type(name) == "string" and not self.db.profile.groups[name] then
2318 options.args.groups.args[id] = nil;
2319 groupIdToName[id] = nil;
2320 groupIdToName[name] = nil;
2321 groupIsVirtual[id] = nil;
2322 end
2323 end
2324
2325 for name, values in pairs(self.db.profile.groups) do
2326 if not groupIdToName[name] then
2327 options.args.groups.args[tostring(count)] = defaultGroup;
2328
2329 groupIdToName[tostring(count)] = name;
2330 groupIdToName[name] = true;
2331 if values.isVirtual then
2332 groupIsVirtual[tostring(count)] = true;
2333 end
2334
2335 count = ( count + 1 );
2336 end
2337 end
2338 end
2339
2340
2341
2342 -- General functions used addon-wide
2343
2344 function addon:GetItemCountAddon(group)
2345 local selectedExternalAddon = self:GetOptionByKey(group, "itemCountAddon");
2346
2347 if self.supportedAddons.itemCount[selectedExternalAddon] and self.supportedAddons.itemCount[selectedExternalAddon].IsEnabled() then
2348 -- Try to use the default item count addon
2349
2350 return self.supportedAddons.itemCount[selectedExternalAddon], selectedExternalAddon;
2351 else
2352 -- Default not available, get the first one then
2353
2354 for name, value in pairs(self.supportedAddons.itemCount) do
2355 if value.IsEnabled() then
2356 return value, name;
2357 end
2358 end
2359 end
2360
2361 return;
2362 end
2363
2364 function addon:GetItemCount(itemId, group)
2365 itemId = tonumber(itemId);
2366
2367 if not itemId then return; end
2368
2369 local itemCountAddon = self:GetItemCountAddon(group);
2370
2371 return (itemCountAddon and itemCountAddon.GetTotalCount(itemId)) or -1;
2372 end
2373
2374 function addon:GetLocalItemCount(itemId, group)
2375 itemId = tonumber(itemId);
2376
2377 if not itemId then return; end
2378
2379 local itemCountAddon = self:GetItemCountAddon(group);
2380
2381 local currentItemCount;
2382
2383 if itemCountAddon and itemCountAddon.GetCharacterCount then
2384 local bag, bank, auctionHouse, mail = itemCountAddon.GetCharacterCount(itemId);
2385
2386 local selectedLocalItemCountSources = self:GetOptionByKey(group, "localItemData");
2387
2388 currentItemCount = 0;
2389 if selectedLocalItemCountSources["Bag"] then
2390 currentItemCount = currentItemCount + bag;
2391 end
2392 if selectedLocalItemCountSources["Bank"] then
2393 currentItemCount = currentItemCount + bank;
2394 end
2395 if selectedLocalItemCountSources["Auction House"] then
2396 currentItemCount = currentItemCount + auctionHouse;
2397 end
2398 if selectedLocalItemCountSources["Mailbox"] then
2399 currentItemCount = currentItemCount + mail;
2400 end
2401 end
2402
2403 return currentItemCount or -1;
2404 end
2405
2406 function addon:GetAuctionValue(itemLink, group)
2407 if not itemLink then return -5; end
2408
2409 local selectedExternalAddon = self:GetOptionByKey(group, "auctionPricingAddon");
2410
2411 if self.supportedAddons.auctionPricing[selectedExternalAddon] and self.supportedAddons.auctionPricing[selectedExternalAddon].IsEnabled() then
2412 -- Try to use the default auction pricing addon
2413
2414 return self.supportedAddons.auctionPricing[selectedExternalAddon].GetValue(itemLink);
2415 else
2416 -- Default not available, get the first one then
2417
2418 for name, value in pairs(self.supportedAddons.auctionPricing) do
2419 if value.IsEnabled() then
2420 return value.GetValue(itemLink);
2421 end
2422 end
2423 end
2424
2425 return -2;
2426 end
2427
2428 508
2429 509
2430 -- Public 510 -- Public
2431 511
2432 function IMRegisterPricingAddon(name, get, enabled, onSelect) 512 function IMRegisterPricingAddon(name, get, enabled, onSelect)
2452 IsEnabled = enabled, 532 IsEnabled = enabled,
2453 OnSelect = onSelect, 533 OnSelect = onSelect,
2454 }; 534 };
2455 end 535 end
2456 536
537 -- We need a global command handler for our chat-links
538 function InventoriumCommandHandler(msg)
539 addon:CommandHandler(msg);
540 end
541
2457 542
2458 543
2459 -- Debug 544 -- Debug
2460 545
2461 function addon:Debug(t) 546 function addon:Debug(t)