changeset 10:c4d0e5d47e10

Ok, please don?t crash again you silly Ace3 multiselect dropdown box. I know you?re itchy, but there?s nothing I can do for you. Cleaned up group management layout, added a duplicate group button. Track at character data is erased when exporting/importing groups. Duplicate items are erased when importing groups. Bug fixes and speed increases in Summary. Added a button to refresh the cache. Added a slider to increase caching speed. Auction value will no longer be cached if the threshold was set to 0.
author Zerotorescue
date Tue, 12 Oct 2010 02:08:37 +0200
parents 3bac0bdd59e2
children 10a2244f7ff0
files Core.lua Inventorium.toc Inventory.toc Summary.lua
diffstat 4 files changed, 198 insertions(+), 99 deletions(-) [+]
line wrap: on
line diff
--- a/Core.lua	Sun Oct 10 04:37:21 2010 +0200
+++ b/Core.lua	Tue Oct 12 02:08:37 2010 +0200
@@ -527,6 +527,7 @@
 								end
 							end
 						end,
+						confirm = true,
 						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.
 					},
 				},
@@ -1017,6 +1018,7 @@
 								return temp;
 							end,
 							get = GetMultiOption,
+							confirm = true,
 							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.
 							arg = "overrideTrackAtCharacters",
 						},
@@ -1143,16 +1145,16 @@
 			name = "Group Management",
 			desc = "Rename, delete or export this group.",
 			args = {
-				rename = {
+				actions = {
 					order = 10,
 					type = "group",
-					name = "Rename",
+					name = "Actions",
 					inline = true,
 					args = {
 						rename = {
 							order = 10,
 							type = "input",
-							name = "New group name",
+							name = "Rename group - New name",
 							desc = "Change the name of this group to something else. You can also use item links here as you wish.",
 							validate = ValidateGroupName,
 							set = function(info, value)
@@ -1170,18 +1172,27 @@
 							get = function(info)
 								return groupIdToName[info[2]];
 							end,
-							width = "double",
 						},
-					},
-				},
-				delete = {
-					order = 20,
-					type = "group",
-					name = "Delete",
-					inline = true,
-					args = {
+						duplicate = {
+							order = 20,
+							type = "input",
+							name = "Duplicate group - New name",
+							desc = "Duplicate this group. You can also use item links here as you wish.\n\nAll item data will be erased.",
+							validate = ValidateGroupName,
+							set = function(info, value)
+								local oldGroupName = groupIdToName[info[2]];
+								
+								addon.db.global.groups[value] = CopyTable(addon.db.global.groups[oldGroupName]);
+								
+								-- Reset item data (duplicate items me no want)
+								addon.db.global.groups[value].items = nil;
+								
+								addon:FillGroupOptions();
+							end,
+							get = false,
+						},
 						delete = {
-							order = 10,
+							order = 30,
 							type = "execute",
 							name = "Delete group",
 							desc = "Delete the currently selected group.",
@@ -1198,7 +1209,7 @@
 					},
 				},
 				export = {
-					order = 30,
+					order = 40,
 					type = "group",
 					name = "Export",
 					inline = true,
@@ -1455,51 +1466,42 @@
 								end
 								
 								local result, temp = AceSerializer:Deserialize(current);
-								local name;
 								
 								if not temp.name then
 									print("|cffff0000The provided data is not supported.|r");
-									return;
+								elseif ValidateGroupName(nil, temp.name) ~= true then
+									print(("|cffff0000Aborting: A group named \"%s\" already exists.|r"):format(temp.name));
 								else
-									name = temp.name;
+									local name = temp.name;
 									temp.name = nil;
 									print(("Importing %s..."):format(name));
+									
+									-- Remove items that are already in another group
+									for value, _ in pairs(temp.items) do
+										local itemId = tonumber(itemid);
+										
+										if not itemId then
+											print(("\"%s\" is not a number."):format(value));
+											temp.items[value] = nil;
+										elseif InGroup(itemId) then
+											print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId)));
+											temp.items[value] = nil;
+										else
+											-- Ensure the keys are numeric
+											temp.items[value] = nil;
+											temp.items[itemId] = true;
+										end
+									end
+									
+									-- Ensure this data isn't received (this would be buggy as exports from other accounts won't know what to do with this)
+									temp.trackAtCharacters = nil;
+									temp.overrideTrackAtCharacters = nil;
+									
+									self.db.global.groups[name] = temp;
 								end
-								
-								local newGroupName = string.trim(string.lower(name or ""));
-								
-								for name in pairs(self.db.global.groups) do
-									if string.lower(name) == newGroupName then
-										print(("|cffff0000Aborting: A group named \"%s\" already exists.|r"):format(name));
-										return;
-									end
-								end
-								
-								-- Remove items that are already in another group
-								for value, _ in pairs(temp.items) do
-									local itemId = tonumber(itemid);
-									
-									if not itemId then
-										print(("\"%s\" is not a number."):format(value));
-										temp.items[value] = nil;
-									elseif InGroup(itemId) then
-										print(("Skipping %s (#%d) as it is already in the group |cfffed000%s|r."):format(select(2, GetItemInfo(itemId)) or "Unknown", itemId, InGroup(itemId)));
-										temp.items[value] = nil;
-									else
-										-- Ensure the keys are numeric
-										temp.items[value] = nil;
-										temp.items[itemId] = true;
-									end
-								end
-								
-								-- Ensure this data isn't received (this would be buggy as exports from other accounts won't know what to do with this)
-								temp.trackAtCharacters = nil;
-								temp.overrideTrackAtCharacters = nil;
-								
-								self.db.global.groups[name] = temp;
-								
-								self:FillGroupOptions();
 							end
+							
+							self:FillGroupOptions();
 						end,
 						get = false,
 						width = "full",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Inventorium.toc	Tue Oct 12 02:08:37 2010 +0200
@@ -0,0 +1,13 @@
+## Interface: 30300
+## Title: Inventorium
+## Notes: Keep track of items you wish to keep enough stock on, and refill.
+## Author: Zerotorescue
+## Version: @project-version@
+## SavedVariables: InventoryDB
+## Dependencies: Altoholic
+## OptionalDeps: Auc-Advanced, Auc-ScanData, AdvancedTradeSkillWindow, Skillet, GnomeWorks, Auctionator
+
+embeds.xml
+
+Core.lua
+Summary.lua
--- a/Inventory.toc	Sun Oct 10 04:37:21 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-## Interface: 30300
-## Title: Inventory
-## Notes: Keep track of items you wish to keep enough stock on, and refill.
-## Author: Zerotorescue
-## Version: @project-version@
-## SavedVariables: InventoryDB
-## Dependencies: Altoholic
-## OptionalDeps: Auc-Advanced, Auc-ScanData, AdvancedTradeSkillWindow, Skillet, GnomeWorks, Auctionator
-
-embeds.xml
-
-Core.lua
-Summary.lua
--- a/Summary.lua	Sun Oct 10 04:37:21 2010 +0200
+++ b/Summary.lua	Tue Oct 12 02:08:37 2010 +0200
@@ -67,6 +67,8 @@
 function mod:BuildMain()
 	LibStub("AceConfigDialog-3.0"):Close("InventoryOptions");
 	
+	self:CloseFrame();
+	
 	-- Main Window
 	mod.frame = AceGUI:Create("Frame");
 	mod.frame:SetTitle("Inventory Summary");
@@ -90,6 +92,15 @@
 	if mod.frame then
 		mod.frame:Release();
 		mod.frame = nil;
+		
+		-- Stop caching
+		
+		-- Stop timer
+		self:CancelTimer(self.tmrUpdater, true);
+		
+		-- Reset trackers
+		CACHE_ITEMS_TOTAL = 0;
+		CACHE_ITEMS_CURRENT = 0;
 	end
 end
 
@@ -105,30 +116,82 @@
 	
 	mod:Build();
 end
+	
+-- From http://www.wowwiki.com/API_sort
+local function pairsByKeys (t, f)
+	local a = {}
+	for n in pairs(t) do table.insert(a, n) end
+		table.sort(a, f)
+	local i = 0      -- iterator variable
+	local iter = function ()   -- iterator function
+		i = i + 1
+		if a[i] == nil then return nil
+		else return a[i], t[a[i]]
+		end
+	end
+	return iter
+end
 
 function mod:Build()
-	local start = GetTime();
-	
-	mod.scrollFrame:ReleaseChildren();
+	local buildStartTime, times = GetTime(), {};
 	
 	-- We are going to add hunderds of widgets to this container, but don't want it to also cause hunderds of reflows, thus pause reflowing and just do it once when everything is prepared
 	-- This appears to be required for each container we wish to pause, so also do this for the contents
 	mod.scrollFrame:PauseLayout();
 	
+	mod.scrollFrame:ReleaseChildren();
+	
+	-- Refresh button
+	local btnRefresh = AceGUI:Create("Button");
+	btnRefresh:SetText("Refresh");
+	-- SetTooltip: Reload all item counts and auction values.
+	btnRefresh:SetRelativeWidth(.2);
+	btnRefresh:SetCallback("OnClick", function()
+		-- Reset items cache
+		table.wipe(itemsCache);
+		
+		-- Rebuild itemlist and start caching
+		mod:Build();
+	end);
+	
+	mod.scrollFrame:AddChild(btnRefresh);
+	
+	-- Speed slider
+	local btnRefresh = AceGUI:Create("Slider");
+	btnRefresh:SetLabel("Processing speed");
+	btnRefresh:SetSliderValues(0.01, 1, 0.01);
+	btnRefresh:SetIsPercent(true);
+	-- SetTooltip: Change the speed at which item counts and auction values are being cached. Higher is faster but may drastically reduce your FPS while caching.
+	btnRefresh:SetRelativeWidth(.3);
+	btnRefresh:SetCallback("OnMouseUp", function(self, event, value)
+		CACHE_ITEMS_PER_UPDATE = ceil( value * 100 / 5 ); -- max = 20, min = 1
+	end);
+	btnRefresh:SetValue( CACHE_ITEMS_PER_UPDATE * 5 / 100 );
+	
+	mod.scrollFrame:AddChild(btnRefresh);
+	
+	times.init = ceil( ( GetTime() - buildStartTime ) * 1000 );
+	addon:Debug("Time spent legend: (init / sorting / preparing / building / all).");
+	
 	local playerName = UnitName("player");
 	
 	-- Go through all our stored groups
-	for groupName, values in pairs(addon.db.global.groups) do
+	for groupName, values in pairsByKeys(addon.db.global.groups, function(a, b) return a:lower() < b:lower(); end) do
+		local groupStartTime, groupTimes = GetTime(), {};
+		
 		local trackAt = (values.trackAtCharacters or (values.trackAtCharacters == nil and addon.db.global.defaults.trackAtCharacters));
 		
 		-- Does this group have any items and do we want to track it at this char?
 		if values.items and trackAt[playerName] then
+		
+			
 			-- Get group settings
 			local minimumStock = (values.minimumStock or (values.minimumStock == nil and addon.db.global.defaults.minimumStock));
 			local showWhenBelow = (values.summaryThresholdShow or (values.summaryThresholdShow == nil and addon.db.global.defaults.summaryThresholdShow));
 			local priceThreshold = (values.priceThreshold or (values.priceThreshold == nil and addon.db.global.defaults.priceThreshold));
 			local hideWhenBelowPriceThreshold = (values.hideFromSummaryWhenBelowPriceThreshold or (values.hideFromSummaryWhenBelowPriceThreshold == nil and addon.db.global.defaults.hideFromSummaryWhenBelowPriceThreshold));
 			
+			
 			-- Make group container
 			local iGroup = AceGUI:Create("InlineGroupWithButton");
 			iGroup:PauseLayout();
@@ -143,13 +206,15 @@
 				end,
 			});
 			
+			
+			
 			-- Headers
 			
 			-- Itemlink
 			local lblItem = AceGUI:Create("InteractiveLabel");
 			lblItem:SetText("|cfffed000Item|r");
 			lblItem:SetFontObject(GameFontHighlight);
-			lblItem:SetRelativeWidth(0.7);
+			lblItem:SetRelativeWidth(.7);
 			lblItem:SetCallback("OnClick", function() ReSort("item"); end);
 			
 			iGroup:AddChild(lblItem);
@@ -158,7 +223,7 @@
 			local lblQuantity = AceGUI:Create("InteractiveLabel");
 			lblQuantity:SetText("|cfffed000Cur.|r");
 			lblQuantity:SetFontObject(GameFontHighlight);
-			lblQuantity:SetRelativeWidth(0.099);
+			lblQuantity:SetRelativeWidth(.099);
 			lblQuantity:SetCallback("OnClick", function() ReSort("current"); end);
 			
 			iGroup:AddChild(lblQuantity);
@@ -167,7 +232,7 @@
 			local lblMinimumStock = AceGUI:Create("InteractiveLabel");
 			lblMinimumStock:SetText("|cfffed000Req.|r");
 			lblMinimumStock:SetFontObject(GameFontHighlight);
-			lblMinimumStock:SetRelativeWidth(0.099);
+			lblMinimumStock:SetRelativeWidth(.099);
 			lblMinimumStock:SetCallback("OnClick", function() ReSort("percentage"); end);
 			
 			iGroup:AddChild(lblMinimumStock);
@@ -176,11 +241,13 @@
 			local lblValue = AceGUI:Create("InteractiveLabel");
 			lblValue:SetText("|cfffed000Value|r");
 			lblValue:SetFontObject(GameFontHighlight);
-			lblValue:SetRelativeWidth(0.099);
+			lblValue:SetRelativeWidth(.099);
 			lblValue:SetCallback("OnClick", function() ReSort("value"); end);
 			
 			iGroup:AddChild(lblValue);
 			
+			
+			-- Retrieve items list
 			if not itemsCache[groupName] then
 				itemsCache[groupName] = {};
 				
@@ -192,7 +259,7 @@
 						id = itemId,
 						name = itemName,
 						link = itemLink,
-						value = -3,--addon:GetAuctionValue(itemLink),
+						value = ((priceThreshold == 0) and 0) or -3,-- if no price threshold is set for this item, then don't look it up either --addon:GetAuctionValue(itemLink),
 						rarity = itemRarity,
 						count = -3,--addon:GetItemCount(itemId),
 						set = {},
@@ -201,6 +268,11 @@
 				end
 			end
 			
+			groupTimes.init = ceil( ( GetTime() - groupStartTime ) * 1000 );
+			
+			
+			
+			-- Sort items
 			table.sort(itemsCache[groupName], function(a, b)
 				if sortMethod == "item" and a.rarity == b.rarity then
 					-- Do a name-compare for items of the same rarity
@@ -224,9 +296,9 @@
 					end
 				elseif sortMethod == "percentage" then
 					if sortDirectory == "ASC" then
-						return ( a.count / lblMinimumStock ) < ( b.count / lblMinimumStock );
+						return ( a.count / minimumStock ) < ( b.count / minimumStock );
 					else
-						return ( a.count / lblMinimumStock ) > ( b.count / lblMinimumStock );
+						return ( a.count / minimumStock ) > ( b.count / minimumStock );
 					end
 				elseif sortMethod == "value" then
 					if sortDirectory == "ASC" then
@@ -237,14 +309,19 @@
 				end
 			end);
 			
-			-- Show stuff
+			groupTimes.sorting = ceil( ( GetTime() - groupStartTime ) * 1000 );
+			
+			
+			
+			
+			-- Show itemslist
 			for i, item in pairs(itemsCache[groupName]) do
 				if ( item.count / minimumStock ) < showWhenBelow and not (hideWhenBelowPriceThreshold and item.value < priceThreshold) then
 					local btnItemLink = AceGUI:Create("ItemLinkButton");
-					btnItemLink:SetUserData("exec", function()
-						print("Win.");
-					end);
-					btnItemLink:SetRelativeWidth(0.7);
+					--btnItemLink:SetUserData("exec", function()
+					--	print("Nothing happening yet.");
+					--end);
+					btnItemLink:SetRelativeWidth(.7);
 					btnItemLink:SetItemId(item.id);
 					
 					iGroup:AddChild(btnItemLink);
@@ -252,40 +329,58 @@
 					-- Current quantity
 					local lblQuantity = AceGUI:Create("Label");
 					lblQuantity:SetText(self:DisplayItemCount(item.count, minimumStock));
-					lblQuantity:SetRelativeWidth(0.099);
+					lblQuantity:SetRelativeWidth(.099);
 					
 					iGroup:AddChild(lblQuantity);
 					
 					-- Required stock
 					local lblMinimumStock = AceGUI:Create("Label");
 					lblMinimumStock:SetText(minimumStock);
-					lblMinimumStock:SetRelativeWidth(0.099);
+					lblMinimumStock:SetRelativeWidth(.099);
 					
 					iGroup:AddChild(lblMinimumStock);
 					
 					-- Value
 					local lblValue = AceGUI:Create("Label");
 					lblValue:SetText(self:DisplayMoney(item.value, priceThreshold));
-					lblValue:SetRelativeWidth(0.099);
+					lblValue:SetRelativeWidth(.099);
 					
 					iGroup:AddChild(lblValue);
 					
 					-- Remember references to the value and current fields so we can fill them later
 					if item.set then
-						item.set.value = lblValue;
-						item.set.current = lblQuantity;
+						-- -3 means the price is unknown, queue look up
+						if item.value == -3 then
+							item.set.value = lblValue;
+						end
+						if item.count == -3 then
+							item.set.current = lblQuantity;
+						end
+						
+						-- Don't queue if we already know everything we want to know
+						if item.value ~= -3 and item.count ~= -3 then
+							item.set = nil;
+						end
 					end
 				end
 			end
 			
+			groupTimes.preparing = ceil( ( GetTime() - groupStartTime ) * 1000 );
+			
 			iGroup:ResumeLayout();
 			mod.scrollFrame:AddChild(iGroup); -- this can take up to .5 seconds, might need to look into again at a later time
+			
+			groupTimes.building = ceil( ( GetTime() - groupStartTime ) * 1000 );
 		end
+		
+		addon:Debug(("Building of %s took %d ms (%d / %d / %d / %d / %d)."):format(groupName, ceil( ( GetTime() - groupStartTime ) * 1000 ), groupTimes.init, groupTimes.sorting, groupTimes.preparing, groupTimes.building, ceil( ( GetTime() - buildStartTime ) * 1000 )));
 	end
 	
 	mod.scrollFrame:ResumeLayout();
 	mod.scrollFrame:DoLayout();
 	
+	addon:Debug(("Done building summary after %d ms."):format(ceil( ( GetTime() - buildStartTime ) * 1000 )));
+	
 	if CACHE_ITEMS_TOTAL > 0 then
 		cacheStart = GetTime();
 		self:CancelTimer(self.tmrUpdater, true);
@@ -299,25 +394,29 @@
 	for groupName, items in pairs(itemsCache) do
 		local minimumStock = addon:GetOptionByKey(groupName, "minimumStock");
 		local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold");
-		local groupUpdated;
 		
 		for _, item in pairs(items) do
 			if item.set then
-				item.count = addon:GetItemCount(item.id);
-				if item.set.current and item.set.current.SetText then
-					item.set.current:SetText(self:DisplayItemCount(item.count, minimumStock));
+				if item.count == -3 then
+					-- Only if item count was queued, update it
+					item.count = addon:GetItemCount(item.id);
+					if item.set.current and item.set.current.SetText then
+						item.set.current:SetText(self:DisplayItemCount(item.count, minimumStock));
+					end
 				end
 				
-				item.value = addon:GetAuctionValue(item.link);
-				if item.set.value and item.set.value.SetText then
-					item.set.value:SetText(self:DisplayMoney(item.value, priceThreshold));
+				if item.value == -3 then
+					-- Only if item value was queued, update it
+					item.value = addon:GetAuctionValue(item.link);
+					if item.set.value and item.set.value.SetText then
+						item.set.value:SetText(self:DisplayMoney(item.value, priceThreshold));
+					end
 				end
 				
 				item.set = nil;
 				
 				i = i + 1;
 				CACHE_ITEMS_CURRENT = CACHE_ITEMS_CURRENT + 1;
-				groupUpdated = true;
 				
 				if mod.frame then
 					mod.frame:SetStatusText(("Caching auction values and item-counts... %d%% has already been processed."):format(floor(CACHE_ITEMS_CURRENT / CACHE_ITEMS_TOTAL * 100)));
@@ -328,11 +427,6 @@
 				end
 			end
 		end
-		
-		if groupUpdated then
-			-- Rebuild list so hidden items due to too low prices get added
-			self:Build();
-		end
 	end
 	
 	-- Reset trackers
@@ -341,9 +435,12 @@
 	
 	-- Stop timer
 	self:CancelTimer(self.tmrUpdater, true);
+		
+	-- Rebuild list so hidden items due to too low prices get added
+	self:Build();
 	
 	-- Announce
-	mod.frame:SetStatusText("All prices and itemcounts have been cached. This process took " .. ceil(GetTime() - cacheStart) .. " seconds.");
+	mod.frame:SetStatusText("All required prices and itemcounts have been cached. This process took " .. ceil(GetTime() - cacheStart) .. " seconds.");
 	
 	-- Forget time
 	cacheStart = nil;